Saltar al contenido principal

Árbol de archivos en Worker

Cómo está construido este ejemplo

Enlace al encabezado

Esta página muestra un árbol de archivos anidado basado en Worker sin mocks. La página de docs conserva el DOM host y el pointer hit-testing, mientras la app Vue remota mantiene la estructura del árbol, la edición inline y la lógica de drag dentro de un Web Worker dedicado.

El ejemplo tiene tres partes:

  • un host runtime que monta HostedTree dentro del área de preview;
  • una app remota en Worker que renderiza carpetas, archivos, acciones inline y procesa RemoteSortableEvent;
  • un snapshot en vivo bajo el árbol que muestra el estado remoto anidado después de cada edición y drop.

Cómo interactuar

Enlace al encabezado
  • Arrastra nodos desde el handle para reordenar hermanos o moverlos a otra carpeta.
  • Renombra elementos inline, agrega archivos o carpetas y elimina nodos del árbol actual.
  • Usa Reiniciar árbol para restaurar la estructura inicial del workspace.

Árbol de archivos sortable y editable en un Worker dedicado

Arrastra archivos y carpetas desde su handle, mueve nodos entre carpetas, renombra elementos inline, crea nuevas entradas y reinicia el workspace cuando quieras volver al estado inicial.

Iniciando runtime dedicado en Worker...

Este árbol está conectado mediante el mismo modelo de transporte host/worker que usan los runtime API públicos de la librería.

import type { Channel } from '@omnicajs/vue-remote/host'
import { createEndpoint, fromWebWorker } from '@remote-ui/rpc'
import {
createApp,
h,
} from 'vue'
import {
HostedTree,
createProvider,
createReceiver,
} from '@omnicajs/vue-remote/host'
interface SandboxWorkerApi {
release (): void;
run (channel: Channel, labels: SortableFileTreeSandboxLabels): Promise<void>;
}
export interface SortableFileTreeSandboxLabels {
addFileLabel: string;
addFolderLabel: string;
booting: string;
cancelLabel: string;
collapseLabel: string;
deleteLabel: string;
dragCanceledAction: string;
draggingAction: string;
emptyFolderLabel: string;
expandLabel: string;
failed: string;
fileAddedAction: string;
fileKindLabel: string;
folderAddedAction: string;
folderKindLabel: string;
initialAction: string;
movedAction: string;
newFileName: string;
newFolderName: string;
ready: string;
removedAction: string;
renameLabel: string;
renamedAction: string;
resetLabel: string;
rootEyebrow: string;
saveLabel: string;
snapshotLabel: string;
snapshotUnavailable?: string;
unsupported: string;
}
export interface SortableFileTreeSandboxElements {
rootElement: HTMLElement;
}
export interface SortableFileTreeSandboxHandle {
destroy (): Promise<void>;
}
export const mountSortableFileTreeSandbox = async (
elements: SortableFileTreeSandboxElements,
labels: SortableFileTreeSandboxLabels
): Promise<SortableFileTreeSandboxHandle> => {
const { rootElement } = elements
if (typeof Worker === 'undefined') {
rootElement.textContent = labels.unsupported
return {
async destroy () {},
}
}
rootElement.textContent = labels.booting
const receiver = createReceiver()
const provider = createProvider()
const host = createApp({
render: () => h(HostedTree, { provider, receiver }),
})
const worker = new Worker(new URL('./remote.worker.ts', import.meta.url), {
type: 'module',
})
const endpoint = createEndpoint<SandboxWorkerApi>(fromWebWorker(worker))
let destroyed = false
const destroy = async () => {
if (destroyed) {
return
}
destroyed = true
try {
await endpoint.call.release()
} catch {
// Worker teardown should not block page cleanup.
} finally {
endpoint.terminate()
worker.terminate()
host.unmount()
rootElement.innerHTML = ''
}
}
try {
host.mount(rootElement)
await endpoint.call.run(receiver.receive, labels)
} catch (error) {
await destroy()
rootElement.textContent = `${labels.failed}: ${error instanceof Error ? error.message : String(error)}`
}
return {
destroy,
}
}

Páginas relacionadas

Enlace al encabezado