Skip to content

Worker Sortable Table

This page shows a worker-based sortable table without mocks. The docs page owns the host DOM and pointer hit-testing, while the remote Vue app and row order state run inside a dedicated Web Worker.

The example has three parts:

  • a host runtime that mounts HostedTree into the preview area;
  • a remote worker app that renders table rows and handles RemoteSortableEvent;
  • a live snapshot below the table that shows the current remote order after each drop.
  • Grab rows only by the Drag handle in the first column.
  • Move a row above or below another row to change the order.
  • Use Reset table to restore the initial queue.

Sortable table running in a dedicated Worker

Drag rows by their handle, reorder the queue inside the same table, and reset the example whenever you want to start over.

Booting dedicated Worker runtime...

This table is wired through the same host/worker transport model used by the library's public runtime APIs.

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: SortableTableSandboxLabels): Promise<void>;
}
export interface SortableTableSandboxLabels {
booting: string;
failed: string;
ready: string;
resetLabel: string;
snapshotLabel: string;
snapshotUnavailable?: string;
unsupported: string;
}
export interface SortableTableSandboxElements {
rootElement: HTMLElement;
}
export interface SortableTableSandboxHandle {
destroy (): Promise<void>;
}
export const mountSortableTableSandbox = async (
elements: SortableTableSandboxElements,
labels: SortableTableSandboxLabels
): Promise<SortableTableSandboxHandle> => {
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,
}
}