メインコンテンツへ移動

Worker 並べ替えテーブル

この例の構成

見出しへのリンク

このページはモックではなく、Worker ベースの sortable table をそのまま見せています。docs ページが host DOM と pointer hit-testing を担当し、remote Vue app と行の並び順は専用 Web Worker の中で動きます。

この例は次の 3 つの要素で構成されています。

  • preview 領域に HostedTree をマウントする host runtime
  • テーブル行を描画し、RemoteSortableEvent を処理する remote Worker app
  • drop のたびに現在の remote order を表示する、テーブル下の live snapshot
  • 行は先頭列の Drag ハンドルからだけつかみます。
  • 別の行の上または下へ移動して順序を変更します。
  • 初期状態に戻したいときは テーブルをリセット を使ってください。

専用 Worker で動く sortable テーブル

行を handle からドラッグして同じテーブル内で順序を入れ替え、必要に応じて例を初期状態に戻してください。

専用 Worker runtime を起動しています...

このテーブルは、ライブラリの公開 runtime API が使うのと同じ host/worker transport モデルで接続されています。

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,
}
}