Worker 可排序表格
这个示例由哪些部分组成
Section titled “这个示例由哪些部分组成”这个页面展示的是完整的 Worker sortable table 场景,而不是模拟预览。docs 页面负责 host DOM 和指针命中测试,remote Vue app 与行顺序状态则运行在专用 Web Worker 中。
这个示例包含三部分:
- 把
HostedTree挂到预览区域中的 host runtime; - 渲染表格行并处理
RemoteSortableEvent的 remote Worker 应用; - 位于表格下方的实时 snapshot,用来显示每次 drop 之后的当前 remote order。
- 只能通过第一列里的
Draghandle 抓取行。 - 把一行移动到另一行的上方或下方来改变顺序。
- 需要回到初始状态时,使用
重置表格。
运行在专用 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, }}import type { MessageEndpoint } from '@remote-ui/rpc'import type { Channel } from '@omnicajs/vue-remote/host'import type { RemoteSortableEvent } from '@omnicajs/vue-remote/remote'
import { createEndpoint, release, retain,} from '@remote-ui/rpc'import { RemoteDragHandle, RemoteSortableContainer, RemoteSortableItem, createRemoteRenderer, createRemoteRoot,} from '@omnicajs/vue-remote/remote'import { defineComponent, h, ref,} from 'vue'
interface RoadmapRow { accent: 'amber' | 'blue' | 'mint'; eta: string; id: string; owner: string; status: 'Blocked' | 'In review' | 'Ready'; task: string;}
interface TableSnapshot { lastAction: string; rowIds: string[];}
interface SandboxWorkerApi { release (): void; run (channel: Channel, labels: SandboxUiLabels): Promise<void>;}
interface SandboxUiLabels { booting: string; failed: string; ready: string; resetLabel: string; snapshotLabel: string; snapshotUnavailable?: string; unsupported: string;}
const endpoint = createEndpoint<SandboxWorkerApi>(self as unknown as MessageEndpoint)
const initialRows = (): RoadmapRow[] => ([ { accent: 'mint', eta: 'Today', id: 'row-1', owner: 'Dina', status: 'Ready', task: 'Publish the sortable DnD API guide', }, { accent: 'amber', eta: 'Tomorrow', id: 'row-2', owner: 'Marco', status: 'Blocked', task: 'Validate overlay geometry for table rows', }, { accent: 'blue', eta: 'Mon', id: 'row-3', owner: 'Aya', status: 'In review', task: 'Document worker sandbox behavior end to end', }, { accent: 'mint', eta: 'Wed', id: 'row-4', owner: 'Nora', status: 'Ready', task: 'Wire live examples into the docs navigation', },])
const cloneSnapshot = (rows: RoadmapRow[], lastAction: string): TableSnapshot => ({ lastAction, rowIds: rows.map(row => row.id),})
const rows = ref<RoadmapRow[]>(initialRows())const lastAction = ref('Drag rows by their handle to reorder the release queue.')let uiLabels: SandboxUiLabels = { booting: '', failed: '', ready: '', resetLabel: 'Reset table', snapshotLabel: 'Snapshot', unsupported: '',}
let releaseRemote = () => {}
const moveRow = (event: RemoteSortableEvent) => { if (!event.accepted || event.targetIndex == null) { lastAction.value = `Drop ignored for ${event.itemId}.` return }
const sourceIndex = rows.value.findIndex(row => row.id === event.itemId)
if (sourceIndex < 0) { lastAction.value = `Row ${event.itemId} was not found.` return }
const [row] = rows.value.splice(sourceIndex, 1) const nextIndex = Math.min(Math.max(event.targetIndex, 0), rows.value.length)
rows.value.splice(nextIndex, 0, row) lastAction.value = `"${row.task}" moved to position ${nextIndex + 1}.`}
const setDragStart = (row: RoadmapRow) => { lastAction.value = `Dragging "${row.task}".`}
const setDragCancel = (row: RoadmapRow) => { lastAction.value = `Drag canceled for "${row.task}".`}
const resetTable = () => { rows.value = initialRows() lastAction.value = 'Drag rows by their handle to reorder the release queue.'}
const statusClassName = (status: RoadmapRow['status']) => { switch (status) { case 'Blocked': return 'sandbox-table__status sandbox-table__status--blocked' case 'In review': return 'sandbox-table__status sandbox-table__status--review' default: return 'sandbox-table__status sandbox-table__status--ready' }}
const TableApp = defineComponent({ name: 'WorkerSortableTableSandbox',
setup () { const renderGrip = () => h('svg', { 'aria-hidden': 'true', class: 'sandbox-table__grip', fill: 'none', viewBox: '0 0 8 12', }, [ h('circle', { cx: '1.5', cy: '1.5', fill: 'currentColor', r: '1' }), h('circle', { cx: '6.5', cy: '1.5', fill: 'currentColor', r: '1' }), h('circle', { cx: '1.5', cy: '6', fill: 'currentColor', r: '1' }), h('circle', { cx: '6.5', cy: '6', fill: 'currentColor', r: '1' }), h('circle', { cx: '1.5', cy: '10.5', fill: 'currentColor', r: '1' }), h('circle', { cx: '6.5', cy: '10.5', fill: 'currentColor', r: '1' }), ])
const renderRow = (row: RoadmapRow, index: number) => { return h(RemoteSortableItem, { as: 'tr', class: `sandbox-table__row sandbox-table__row--${row.accent}`, containerId: 'release-table', 'data-testid': `sandbox-row-${row.id}`, index, itemId: row.id, onDragcancel: () => setDragCancel(row), onDragstart: () => setDragStart(row), type: 'release-row', }, { default: () => [ h('td', { class: 'sandbox-table__cell sandbox-table__cell--rank' }, [ h('div', { class: 'sandbox-table__rank-slot' }, [ h('span', { class: 'sandbox-table__rank', 'data-testid': `sandbox-rank-${row.id}`, }, `#${String(index + 1).padStart(2, '0')}`), h(RemoteDragHandle, { as: 'button', 'aria-label': `Drag ${row.task}`, class: 'sandbox-table__handle', 'data-testid': `sandbox-handle-${row.id}`, type: 'button', }, { default: renderGrip, }), ]), ]), h('td', { class: 'sandbox-table__cell' }, [ h('div', { class: 'sandbox-table__task' }, [ h('p', { class: 'sandbox-table__task-title' }, row.task), h('span', { class: 'sandbox-table__task-meta' }, row.id), ]), ]), h('td', { class: 'sandbox-table__cell' }, [ h('span', { class: 'sandbox-table__owner' }, row.owner), ]), h('td', { class: 'sandbox-table__cell' }, [ h('span', { class: 'sandbox-table__eta' }, row.eta), ]), h('td', { class: 'sandbox-table__cell' }, [ h('span', { class: statusClassName(row.status) }, row.status), ]), ], }) }
return () => h('div', { class: 'worker-table-sandbox__runtime' }, [ h('div', { class: 'worker-table-sandbox__toolbar' }, [ h('span', { class: 'worker-table-sandbox__status', 'data-sandbox-status': '', }, uiLabels.ready), h('button', { class: 'worker-table-sandbox__reset', 'data-sandbox-reset': '', onClick: resetTable, type: 'button', }, uiLabels.resetLabel), ]), h('div', { class: 'worker-table-sandbox__preview' }, [ h('div', { class: 'sandbox-table-demo' }, [ h('div', { class: 'sandbox-table-demo__toolbar' }, [ h('p', { class: 'sandbox-table-demo__eyebrow' }, 'Release queue'), h('p', { class: 'sandbox-table-demo__caption' }, lastAction.value), ]), h('div', { class: 'sandbox-table-shell' }, [ h('table', { class: 'sandbox-table', 'data-testid': 'sandbox-table', }, [ h('thead', { class: 'sandbox-table__head' }, [ h('tr', [ h('th', 'Rank'), h('th', 'Task'), h('th', 'Owner'), h('th', 'ETA'), h('th', 'Status'), ]), ]), h(RemoteSortableContainer, { as: 'tbody', accepts: ['release-row'], class: 'sandbox-table__body', containerId: 'release-table', 'data-testid': 'sandbox-table-body', onDrop: moveRow, orientation: 'vertical', }, { default: () => rows.value.map((row, index) => renderRow(row, index)), }), ]), ]), ]), ]), h('div', { class: 'worker-table-sandbox__snapshot', 'data-sandbox-snapshot-wrap': '', }, [ h('div', { class: 'worker-table-sandbox__snapshot-title' }, uiLabels.snapshotLabel), h('pre', { class: 'worker-table-sandbox__snapshot-code', 'data-sandbox-snapshot': '', }, JSON.stringify(cloneSnapshot(rows.value, lastAction.value), null, 2)), ]), ]) },})
endpoint.expose({ async run (channel: Channel, labels: SandboxUiLabels) { uiLabels = labels retain(channel)
const root = createRemoteRoot(channel) await root.mount()
const app = createRemoteRenderer(root).createApp(TableApp) app.mount(root)
releaseRemote = () => { app.unmount() release(channel) } },
release () { releaseRemote() releaseRemote = () => {} },}).worker-table-sandbox { --worker-sandbox-border: color-mix(in srgb, var(--sl-color-hairline-light) 78%, transparent); --worker-sandbox-surface: color-mix(in srgb, var(--sl-color-bg) 92%, var(--sl-color-accent-low)); margin-block: 2rem; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__layout { display: grid; gap: 1.5rem; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__surface { display: grid; gap: 1rem; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__heading { display: grid; gap: 0.45rem; margin-bottom: 1rem;}
.worker-table-sandbox__heading h2 { margin: 0; font-size: clamp(1.3rem, 1.15rem + 0.5vw, 1.7rem);}
.worker-table-sandbox__heading p,.worker-table-sandbox__note { margin: 0; color: var(--sl-color-gray-2);}
.worker-table-sandbox__toolbar { display: flex; gap: 0.75rem; align-items: center; justify-content: space-between; margin-bottom: 1rem;}
.worker-table-sandbox__status { color: var(--sl-color-gray-2); font-size: 0.92rem; font-weight: 600;}
.worker-table-sandbox__reset { border: 1px solid var(--worker-sandbox-border); border-radius: 999px; background: color-mix(in srgb, var(--sl-color-white) 7%, transparent); color: var(--sl-color-text); padding: 0.55rem 0.95rem; font: inherit; font-weight: 700; cursor: pointer; transition: transform 140ms ease, border-color 140ms ease;}
.worker-table-sandbox__reset:hover,.worker-table-sandbox__reset:focus-visible { transform: translateY(-1px); border-color: color-mix(in srgb, var(--sl-color-accent-high) 50%, var(--worker-sandbox-border));}
.worker-table-sandbox__reset:disabled { opacity: 0.55; cursor: progress; transform: none;}
.worker-table-sandbox__runtime-host { min-height: 25rem; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__runtime { display: grid; gap: 1rem; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__preview { min-height: 25rem; padding: 0; width: 100%; max-width: 100%; min-width: 0;}
.worker-table-sandbox__note { margin-top: 0.85rem; width: min(100%, var(--sl-content-width)); max-width: var(--sl-content-width); justify-self: start;}
.worker-table-sandbox__snapshot { margin-top: 1rem; width: min(100%, var(--sl-content-width)); max-width: var(--sl-content-width); min-width: 0; justify-self: start;}
.worker-table-sandbox__snapshot-title { margin-bottom: 0.45rem; font-size: 0.82rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--sl-color-gray-2);}
.worker-table-sandbox__snapshot-code,.worker-table-sandbox__code .expressive-code { margin: 0;}
.worker-table-sandbox__code { display: grid; gap: 1rem; width: min(100%, var(--sl-content-width)); max-width: var(--sl-content-width); min-width: 0; justify-self: start;}
.worker-table-sandbox__snapshot-code { overflow: auto; padding: 1rem; border-radius: 0.5rem; background: color-mix(in srgb, var(--sl-color-black) 12%, var(--sl-color-bg)); color: var(--sl-color-white); font-size: 0.82rem; line-height: 1.55;}
.worker-table-sandbox__code .tablist-wrapper { margin-bottom: 1rem; max-width: 100%; min-width: 0; overflow-x: auto;}
.worker-table-sandbox__code starlight-tabs,.worker-table-sandbox__code [role='tablist'],.worker-table-sandbox__code [role='tabpanel'] { min-width: 0; max-width: 100%;}
.worker-table-sandbox__code starlight-tabs { display: grid; min-width: 0;}
.worker-table-sandbox__code [role='tabpanel'] { margin-top: 0;}
.worker-table-sandbox__code .expressive-code,.worker-table-sandbox__code .expressive-code pre { max-width: 100%; min-width: 0;}
.worker-table-sandbox .sandbox-table-demo { display: grid; gap: 1rem; padding: 1rem; border: 1px solid var(--worker-sandbox-border); border-radius: 0.5rem; background: radial-gradient(circle at top right, color-mix(in srgb, #0ea5e9 12%, transparent), transparent 32%), linear-gradient(180deg, color-mix(in srgb, var(--worker-sandbox-surface) 96%, transparent), var(--sl-color-bg)); box-shadow: 0 1rem 2rem -1.5rem color-mix(in srgb, var(--sl-color-black) 25%, transparent);}
.worker-table-sandbox .sandbox-table-demo__toolbar { display: grid; gap: 0.4rem;}
.worker-table-sandbox .sandbox-table-demo__eyebrow { margin: 0; color: var(--sl-color-text-accent); font-size: 0.76rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;}
.worker-table-sandbox .sandbox-table-demo__caption { margin: 0; color: var(--sl-color-gray-2); font-size: 0.95rem; font-weight: 600;}
.worker-table-sandbox .sandbox-table-shell { overflow-x: auto; padding-bottom: 0.25rem; border: 1px solid color-mix(in srgb, var(--sl-color-hairline-light) 72%, transparent); border-radius: 0.5rem; background: color-mix(in srgb, var(--sl-color-bg) 96%, var(--sl-color-white)); box-shadow: inset 0 1px 0 color-mix(in srgb, var(--sl-color-white) 20%, transparent);}
.worker-table-sandbox .sandbox-table { width: 100%; min-width: 48rem; border-collapse: collapse; border-spacing: 0; table-layout: fixed;}
.worker-table-sandbox .sandbox-table__head th { padding: 0.85rem; text-align: left; font-size: 0.74rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--sl-color-gray-2); background: color-mix(in srgb, var(--sl-color-accent-high) 4%, var(--sl-color-bg)); border-bottom: 1px solid color-mix(in srgb, var(--sl-color-hairline-light) 72%, transparent);}
.worker-table-sandbox .sandbox-table__head th:first-child { width: 5.5rem;}
.worker-table-sandbox .sandbox-table__head th:nth-child(2) { width: 20rem;}
.worker-table-sandbox .sandbox-table__head th:nth-child(3),.worker-table-sandbox .sandbox-table__head th:nth-child(4) { width: 9rem;}
.worker-table-sandbox .sandbox-table__body { margin: 0;}
.worker-table-sandbox .sandbox-table__row,[data-dnd-overlay='true'] .sandbox-table__row { margin: 0;}
.worker-table-sandbox .sandbox-table__row--mint,[data-dnd-overlay='true'] .sandbox-table__row--mint { --sandbox-row-accent: color-mix(in srgb, #41b883 55%, transparent);}
.worker-table-sandbox .sandbox-table__row--amber,[data-dnd-overlay='true'] .sandbox-table__row--amber { --sandbox-row-accent: color-mix(in srgb, #f59e0b 55%, transparent);}
.worker-table-sandbox .sandbox-table__row--blue,[data-dnd-overlay='true'] .sandbox-table__row--blue { --sandbox-row-accent: color-mix(in srgb, #38bdf8 55%, transparent);}
.worker-table-sandbox .sandbox-table__cell,[data-dnd-overlay='true'] .sandbox-table__cell { margin: 0; padding: 0.82rem 0.85rem; vertical-align: middle; background: color-mix(in srgb, var(--sl-color-bg) 94%, var(--sl-color-white)); border-bottom: 1px solid color-mix(in srgb, var(--sl-color-hairline-light) 72%, transparent); transition: background-color 160ms ease, border-color 160ms ease, opacity 160ms ease, box-shadow 160ms ease;}
.worker-table-sandbox .sandbox-table__row td:first-child,[data-dnd-overlay='true'] .sandbox-table__row td:first-child { box-shadow: inset 3px 0 0 var(--sandbox-row-accent, transparent);}
.worker-table-sandbox .sandbox-table__body tr:last-child td { border-bottom: 0;}
.worker-table-sandbox .sandbox-table__body tr:hover td { background: color-mix(in srgb, var(--sl-color-accent-high) 3%, var(--sl-color-bg));}
.worker-table-sandbox .sandbox-table__cell--rank,[data-dnd-overlay='true'] .sandbox-table__cell--rank { padding-inline: 0.65rem;}
.worker-table-sandbox .sandbox-table__rank-slot,[data-dnd-overlay='true'] .sandbox-table__rank-slot { position: relative; display: grid; place-items: center; min-height: 2.2rem;}
.worker-table-sandbox .sandbox-table__rank,[data-dnd-overlay='true'] .sandbox-table__rank { display: inline-flex; align-items: center; justify-content: center; min-width: 2.75rem; padding: 0.35rem 0.55rem; border-radius: 999px; background: color-mix(in srgb, var(--sl-color-accent-high) 10%, transparent); color: var(--sl-color-text-accent); font-size: 0.8rem; font-weight: 800; transition: opacity 140ms ease, transform 140ms ease;}
.worker-table-sandbox .sandbox-table__handle,[data-dnd-overlay='true'] .sandbox-table__handle { display: inline-grid; place-items: center; width: 2rem; height: 2rem; padding: 0; border: 0; border-radius: 0.65rem; background: transparent; color: inherit; cursor: grab; transition: background-color 140ms ease, opacity 140ms ease, transform 140ms ease;}
.worker-table-sandbox .sandbox-table__cell--rank .sandbox-table__handle,[data-dnd-overlay='true'] .sandbox-table__cell--rank .sandbox-table__handle { position: absolute; inset: 50% auto auto 50%; opacity: 0; transform: translate(-50%, -50%) scale(0.92);}
.worker-table-sandbox .sandbox-table__row:hover .sandbox-table__rank,.worker-table-sandbox .sandbox-table__row:focus-within .sandbox-table__rank,[data-dnd-overlay='true'] .sandbox-table__rank { opacity: 0; transform: scale(0.92);}
.worker-table-sandbox .sandbox-table__row:hover .sandbox-table__cell--rank .sandbox-table__handle,.worker-table-sandbox .sandbox-table__row:focus-within .sandbox-table__cell--rank .sandbox-table__handle,[data-dnd-overlay='true'] .sandbox-table__cell--rank .sandbox-table__handle { opacity: 1; transform: translate(-50%, -50%) scale(1);}
.worker-table-sandbox .sandbox-table__handle:hover,.worker-table-sandbox .sandbox-table__handle:focus-visible,[data-dnd-overlay='true'] .sandbox-table__handle { background: color-mix(in srgb, var(--sl-color-accent-high) 8%, transparent);}
.worker-table-sandbox .sandbox-table__grip,[data-dnd-overlay='true'] .sandbox-table__grip { display: block; width: 0.72rem; height: 1.08rem; color: color-mix(in srgb, var(--sl-color-gray-3) 88%, var(--sl-color-text)); overflow: visible;}
.worker-table-sandbox .sandbox-table__task,[data-dnd-overlay='true'] .sandbox-table__task { display: grid; gap: 0.35rem;}
.worker-table-sandbox .sandbox-table__task-title,[data-dnd-overlay='true'] .sandbox-table__task-title { margin: 0; font-size: 0.98rem; font-weight: 700; line-height: 1.4;}
.worker-table-sandbox .sandbox-table__task-meta,[data-dnd-overlay='true'] .sandbox-table__task-meta { color: var(--sl-color-gray-2); font-size: 0.82rem;}
.worker-table-sandbox .sandbox-table__owner,.worker-table-sandbox .sandbox-table__eta,[data-dnd-overlay='true'] .sandbox-table__owner,[data-dnd-overlay='true'] .sandbox-table__eta { display: inline-block; color: var(--sl-color-text); font-weight: 600;}
.worker-table-sandbox .sandbox-table__status,[data-dnd-overlay='true'] .sandbox-table__status { display: inline-flex; align-items: center; padding: 0.3rem 0.65rem; border-radius: 999px; white-space: nowrap; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.03em;}
.worker-table-sandbox .sandbox-table__status--blocked,[data-dnd-overlay='true'] .sandbox-table__status--blocked { background: color-mix(in srgb, #f59e0b 16%, transparent); color: color-mix(in srgb, #f59e0b 78%, var(--sl-color-text));}
.worker-table-sandbox .sandbox-table__status--ready,[data-dnd-overlay='true'] .sandbox-table__status--ready { background: color-mix(in srgb, #41b883 16%, transparent); color: color-mix(in srgb, #41b883 78%, var(--sl-color-text));}
.worker-table-sandbox .sandbox-table__status--review,[data-dnd-overlay='true'] .sandbox-table__status--review { background: color-mix(in srgb, #38bdf8 16%, transparent); color: color-mix(in srgb, #0ea5e9 82%, var(--sl-color-text));}
.worker-table-sandbox [data-dnd-dragging='true'] { visibility: hidden; opacity: 0; pointer-events: none;}
[data-dnd-overlay='true'] { --worker-sandbox-border: color-mix(in srgb, var(--sl-color-hairline-light) 78%, transparent); position: fixed; top: 0; left: 0; z-index: 9999; width: var(--dnd-overlay-width); pointer-events: none; transform: translate3d(-9999px, -9999px, 0); color: var(--sl-color-text); font: inherit;}
[data-dnd-overlay='true']::after { content: var(--worker-dragging-label); position: absolute; top: -0.65rem; right: 0; display: inline-flex; align-items: center; padding: 0.18rem 0.55rem; border-radius: 999px; background: color-mix(in srgb, var(--sl-color-accent-high) 20%, var(--sl-color-bg)); border: 1px solid color-mix(in srgb, var(--sl-color-accent-high) 42%, var(--worker-sandbox-border)); color: var(--sl-color-text-accent); font-size: 0.68rem; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase; box-shadow: 0 0.6rem 1.2rem -0.9rem color-mix(in srgb, var(--sl-color-accent-high) 60%, transparent);}
[data-dnd-overlay='true'] table { width: 100%; border-collapse: collapse; border-spacing: 0; table-layout: fixed; background: color-mix(in srgb, var(--sl-color-bg) 96%, var(--sl-color-white)); border: 1px solid color-mix(in srgb, var(--sl-color-hairline-light) 72%, transparent); border-radius: 0.5rem; overflow: hidden; box-shadow: 0 1.25rem 2.4rem -1.3rem color-mix(in srgb, var(--sl-color-black) 40%, transparent);}
[data-dnd-overlay='true'] .sandbox-table__cell { background: color-mix(in srgb, var(--sl-color-bg) 97%, var(--sl-color-white));}
[data-dnd-overlay='true'] .sandbox-table__task-title,[data-dnd-overlay='true'] .sandbox-table__task-meta,[data-dnd-overlay='true'] .sandbox-table__owner,[data-dnd-overlay='true'] .sandbox-table__eta { color: inherit;}
[data-dnd-overlay='true'] .sandbox-table__handle { cursor: grabbing;}
.worker-table-sandbox [data-dnd-placeholder='true'] td { background: linear-gradient(180deg, color-mix(in srgb, var(--sl-color-accent-low) 20%, transparent), transparent), color-mix(in srgb, var(--sl-color-accent-high) 7%, var(--sl-color-bg)); border-top: 2px dashed color-mix(in srgb, var(--sl-color-accent-high) 45%, var(--worker-sandbox-border)); border-bottom: 2px dashed color-mix(in srgb, var(--sl-color-accent-high) 45%, var(--worker-sandbox-border)); box-shadow: none;}
.worker-table-sandbox [data-dnd-placeholder='true'] td > * { visibility: hidden;}
@media (max-width: 52rem) { .worker-table-sandbox .sandbox-table { min-width: 42rem; }}