@vuecs/table 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +59 -0
- package/dist/components/Table.vue.d.ts +511 -0
- package/dist/components/Table.vue.d.ts.map +1 -0
- package/dist/components/TableBody.vue.d.ts +43 -0
- package/dist/components/TableBody.vue.d.ts.map +1 -0
- package/dist/components/TableCell.vue.d.ts +182 -0
- package/dist/components/TableCell.vue.d.ts.map +1 -0
- package/dist/components/TableEmpty.vue.d.ts +104 -0
- package/dist/components/TableEmpty.vue.d.ts.map +1 -0
- package/dist/components/TableFooter.vue.d.ts +40 -0
- package/dist/components/TableFooter.vue.d.ts.map +1 -0
- package/dist/components/TableHeadCell.vue.d.ts +267 -0
- package/dist/components/TableHeadCell.vue.d.ts.map +1 -0
- package/dist/components/TableHeader.vue.d.ts +40 -0
- package/dist/components/TableHeader.vue.d.ts.map +1 -0
- package/dist/components/TableLite.vue.d.ts +250 -0
- package/dist/components/TableLite.vue.d.ts.map +1 -0
- package/dist/components/TableLoading.vue.d.ts +88 -0
- package/dist/components/TableLoading.vue.d.ts.map +1 -0
- package/dist/components/TableRow.vue.d.ts +116 -0
- package/dist/components/TableRow.vue.d.ts.map +1 -0
- package/dist/components/TableSortIndicators.vue.d.ts +335 -0
- package/dist/components/TableSortIndicators.vue.d.ts.map +1 -0
- package/dist/components/index.d.ts +23 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/composables/context.d.ts +104 -0
- package/dist/composables/context.d.ts.map +1 -0
- package/dist/composables/define-table.d.ts +48 -0
- package/dist/composables/define-table.d.ts.map +1 -0
- package/dist/composables/index.d.ts +5 -0
- package/dist/composables/index.d.ts.map +1 -0
- package/dist/composables/selection.d.ts +10 -0
- package/dist/composables/selection.d.ts.map +1 -0
- package/dist/composables/sort.d.ts +61 -0
- package/dist/composables/sort.d.ts.map +1 -0
- package/dist/defaults.d.ts +41 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +2081 -0
- package/dist/index.mjs.map +1 -0
- package/dist/style.css +145 -0
- package/dist/theme.d.ts +13 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/types.d.ts +248 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/auto-render.d.ts +31 -0
- package/dist/utils/auto-render.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/render-utils.d.ts +49 -0
- package/dist/utils/render-utils.d.ts.map +1 -0
- package/dist/utils/sort-rows.d.ts +29 -0
- package/dist/utils/sort-rows.d.ts.map +1 -0
- package/dist/vue.d.ts +27 -0
- package/dist/vue.d.ts.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["VCTableFooter","VCTableHeader","VCTableBody","VCTableRow","VCTableHeadCell","VCTableCell"],"sources":["../src/composables/context.ts","../src/composables/sort.ts","../src/components/TableBody.vue","../src/components/TableBody.vue","../src/utils/render-utils.ts","../src/components/TableCell.vue","../src/components/TableCell.vue","../src/components/TableFooter.vue","../src/components/TableFooter.vue","../src/components/TableHeadCell.vue","../src/components/TableHeadCell.vue","../src/components/TableHeader.vue","../src/components/TableHeader.vue","../src/components/TableRow.vue","../src/components/TableRow.vue","../src/utils/auto-render.ts","../src/utils/sort-rows.ts","../src/components/Table.vue","../src/components/Table.vue","../src/components/TableLite.vue","../src/components/TableLite.vue","../src/components/TableEmpty.vue","../src/components/TableEmpty.vue","../src/components/TableLoading.vue","../src/components/TableLoading.vue","../src/components/TableSortIndicators.vue","../src/components/TableSortIndicators.vue","../src/composables/define-table.ts","../src/theme.ts","../src/index.ts"],"sourcesContent":["import type { InjectionKey, Ref } from 'vue';\nimport { inject, provide } from 'vue';\nimport type {\n SortDirection,\n TableColumn,\n TableSortState,\n} from '../types';\nimport type { RowSelectionKey, RowSelectionState } from './selection';\n\n// ──────────────────────────────────────────────────────────────────────────\n// Table-scope context (provided by <VCTable>, consumed by every descendant)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport type TableContext<Row = unknown> = {\n data: Ref<Row[]>;\n busy: Ref<boolean>;\n columns: Ref<TableColumn<Row>[]>;\n sort: Ref<TableSortState>;\n /**\n * Cycle the sort state for `key`. `opts.append` (Shift-click) adds\n * the key as a secondary/tertiary descriptor instead of replacing.\n * `opts.direction` jumps straight to a given direction.\n */\n setSort: (key: string, opts?: { append?: boolean; direction?: SortDirection }) => void;\n /**\n * Replace the entire sort state directly. Used by\n * `<VCTableSortIndicators>` to remove / reorder / clear descriptors\n * without invoking the per-key cycle logic.\n */\n setSortState: (next: TableSortState) => void;\n /**\n * Cap on the sort-state array length (`<VCTable :max-sort-keys>`).\n * Exposed so descendants like `<VCTableSortIndicators>` can\n * enforce the cap consistently — `setSortState` itself bypasses\n * cycle logic, so the cap is enforced at the call site.\n */\n maxSortKeys: Ref<number>;\n /**\n * Whether the host table can actually mutate sort state.\n * `<VCTable>` sets this to `true`; `<VCTableLite>` sets it to\n * `false` (it ships no sort machine). Descendants like\n * `<VCTableSortIndicators>` check this in their context-fallback\n * path so they refuse to silently no-op when mounted inside Lite.\n */\n supportsSortMutation: boolean;\n /** Whether `<VCTable>` was passed `:rowClickable`. */\n rowClickable: Ref<boolean>;\n /** Currently focused row index (row keyboard nav). `null` when nothing focused. */\n focusedRow: Ref<number | null>;\n setFocusedRow: (index: number | null) => void;\n /** Resolved colspan (Shape A: `columns.length`; Shape B: auto-counted from `<VCTableHeadCell>` siblings). */\n colspan: Ref<number>;\n /** Emit a `row-click` event from inside a body row. */\n emitRowClick: (row: Row, index: number, event: Event) => void;\n /**\n * The positioned wrapper element that wraps the `<table>` in the DOM.\n * `<VCTableLoading :overlay>` teleports here so its `<div>` isn't\n * fostered out of the table by the HTML parser AND so it has a real\n * positioning context for `position: absolute; inset: 0`.\n */\n wrapperEl: Ref<globalThis.HTMLElement | null>;\n /**\n * Row selection state (plan 033 v1.x-A). Always provided; reports\n * mode `undefined` and `isSelected: () => false` when selection is\n * disabled, so descendants don't need to null-check. `<VCTableRow>`\n * calls `selection.toggle()` on activation and reads `isSelected`\n * to render `aria-selected` + the `selected` theme variant.\n */\n selection: RowSelectionState;\n /** Resolve the selection key for a given row (function or index fallback). */\n getRowKey: (row: Row, index: number) => RowSelectionKey;\n /**\n * Set of row indices that are currently interactive (focusable +\n * keyboard-navigable). Each `<VCTableRow>` registers / unregisters\n * itself based on its own `isInteractive` state. Used by:\n *\n * - Roving-tabindex fallback — when `focusedRow` is unset or stale,\n * the FIRST interactive row gets `tabindex=\"0\"` (so a disabled\n * row 0 doesn't lock the grid out of Tab navigation).\n * - Arrow / Home / End nav — skips disabled rows by walking the\n * sorted registry rather than the raw data index.\n */\n interactiveRows: Ref<Set<number>>;\n registerInteractiveRow(index: number): void;\n unregisterInteractiveRow(index: number): void;\n};\n\nconst TABLE_CONTEXT_KEY: InjectionKey<TableContext<unknown>> = Symbol('vcTableContext');\n\nexport function provideTableContext<Row>(ctx: TableContext<Row>): void {\n provide(TABLE_CONTEXT_KEY, ctx as TableContext<unknown>);\n}\n\nexport function useTable<Row = unknown>(): TableContext<Row> | null {\n return inject(TABLE_CONTEXT_KEY, null) as TableContext<Row> | null;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Row-scope context (provided by <VCTableRow> inside <VCTableBody>'s iteration)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport type TableRowContext<Row = unknown> = {\n row: Ref<Row>;\n index: Ref<number>;\n /** Resolved row-level variant from `row._rowVariant`. */\n rowVariant: Ref<string | null>;\n /** Resolved per-cell variants from `row._cellVariants`. */\n cellVariants: Ref<Record<string, string>>;\n /** `true` when `useTable().focusedRow === index`. */\n focused: Ref<boolean>;\n /** Resolved selection key for this row (memoized per render). */\n selectionKey: Ref<RowSelectionKey>;\n /** `true` when the parent table's selection includes this row. */\n selected: Ref<boolean>;\n};\n\nconst TABLE_ROW_CONTEXT_KEY: InjectionKey<TableRowContext<unknown>> = Symbol('vcTableRowContext');\n\nexport function provideTableRowContext<Row>(ctx: TableRowContext<Row>): void {\n provide(TABLE_ROW_CONTEXT_KEY, ctx as TableRowContext<unknown>);\n}\n\nexport function useTableRow<Row = unknown>(): TableRowContext<Row> | null {\n return inject(TABLE_ROW_CONTEXT_KEY, null) as TableRowContext<Row> | null;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Head-cell count context (D3 — auto-count <VCTableHeadCell> siblings in\n// <VCTableHeader>'s first row, used as the Shape B colspan fallback)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport type HeadCellCountContext = {\n register: () => void;\n unregister: () => void;\n};\n\nconst TABLE_HEAD_CELL_COUNT_CONTEXT_KEY: InjectionKey<HeadCellCountContext> = Symbol(\n 'vcTableHeadCellCountContext',\n);\n\nexport function provideHeadCellCountContext(ctx: HeadCellCountContext): void {\n provide(TABLE_HEAD_CELL_COUNT_CONTEXT_KEY, ctx);\n}\n\nexport function useHeadCellCountContext(): HeadCellCountContext | null {\n return inject(TABLE_HEAD_CELL_COUNT_CONTEXT_KEY, null);\n}\n","import { computed, ref, watch } from 'vue';\nimport type { ComputedRef, Ref } from 'vue';\nimport type {\n SortDescriptor,\n SortDirection,\n TableColumn,\n TableSortState,\n} from '../types';\n\nexport type UseSortMachineOptions<Row = unknown> = {\n /** Reactive source-of-truth from the consumer's `v-model:sort`. May be `undefined`. */\n source: Ref<TableSortState | undefined>;\n /** Reactive column list — needed to resolve `initialSortDirection`. */\n columns: Ref<TableColumn<Row>[]>;\n /** When `true`, the cycle skips the `null` step → `null → asc → desc → asc`. */\n mustSort: Ref<boolean>;\n /**\n * Maximum number of sort keys retained in multi-sort mode (plan 033\n * v1.x-B). When adding a key past this cap, the oldest descriptor\n * is dropped. Defaults to `3` in `<VCTable>`.\n */\n maxSortKeys: Ref<number>;\n /** Emit handler that propagates each change back to the consumer. */\n emit: (next: TableSortState) => void;\n};\n\nexport type SortMachine = {\n state: ComputedRef<TableSortState>;\n /**\n * Cycle the sort state for `key`.\n *\n * - Plain call (no opts) — replace state with this key alone. Cycles\n * through `initial → opposite → cleared` (or `→ initial` when\n * `mustSort`).\n * - `opts.append === true` (Shift-click) — add `key` as a secondary\n * descriptor at the end of the array OR cycle its direction if\n * already present. Cycling past clears just that key.\n * - `opts.direction` — jump straight to that direction. Honors\n * `append` for placement.\n */\n setSort: (key: string, opts?: { append?: boolean; direction?: SortDirection }) => void;\n /**\n * Replace the entire sort state directly. Bypasses cycle + multi-sort\n * gating — used by the chip-row indicator UX which mutates the array\n * declaratively (remove, reorder, clear).\n */\n setState: (next: TableSortState) => void;\n /** Direction for a key (regardless of sort position), or `null`. */\n directionFor: (key: string) => SortDirection | null;\n /** 1-based position of a key within the sort array, or `null`. */\n positionFor: (key: string) => number | null;\n};\n\n/**\n * Controlled sort machine. The consumer owns the sort state via\n * `v-model:sort` — the table emits intent only. When `<VCTable\n * :client-sort>` is set, the table additionally sorts data internally\n * via `sortRows()` from `utils/sort-rows.ts`; the controlled v-model\n * still emits, so consumers stay observable.\n *\n * State shape is `SortDescriptor[]` from v1.x-B onward — single-column\n * sort is an array of length 0–1. Multi-key cycling lives entirely\n * here; `<VCTableHeadCell>` reads `directionFor` / `positionFor` to\n * paint the indicator + numeric badge.\n */\nexport function useSortMachine<Row = unknown>(\n options: UseSortMachineOptions<Row>,\n): SortMachine {\n const {\n source,\n columns,\n mustSort,\n maxSortKeys,\n emit,\n } = options;\n\n // Mirror the source into a local ref so we can react to undefined→[],\n // but the source remains the single source of truth.\n const local = ref<TableSortState>(normalize(source.value));\n watch(source, (next) => {\n local.value = normalize(next);\n });\n\n const state = computed<TableSortState>(() => local.value);\n\n function findInitialDirection(key: string): SortDirection {\n const col = columns.value.find((c) => c.key === key);\n return col?.initialSortDirection ?? 'asc';\n }\n\n function setSort(\n key: string,\n opts: { append?: boolean; direction?: SortDirection } = {},\n ): void {\n const current = local.value;\n const idx = current.findIndex((s) => s.key === key);\n const initial = findInitialDirection(key);\n\n // Explicit direction override — same insertion rules as cycling.\n if (opts.direction !== undefined) {\n const next = opts.append ?\n upsertAppend(current, key, opts.direction, maxSortKeys.value) :\n [{\n key,\n direction: opts.direction,\n }];\n local.value = next;\n emit(next);\n return;\n }\n\n if (!opts.append) {\n // Single-sort cycle: replace state entirely.\n // - Key isn't currently sorted → start at initial.\n // - Same key matches initial direction → flip.\n // - Same key on the opposite direction → clear (or back to\n // initial when mustSort).\n const existing = idx >= 0 ? current[idx] : null;\n let next: TableSortState;\n if (!existing) {\n next = [{\n key,\n direction: initial,\n }];\n } else if (existing.direction === initial) {\n next = [{\n key,\n direction: initial === 'asc' ? 'desc' : 'asc',\n }];\n } else {\n next = mustSort.value ?\n [{\n key,\n direction: initial,\n }] :\n [];\n }\n local.value = next;\n emit(next);\n return;\n }\n\n // Append mode — Shift-click semantics. Cycle just this key's\n // direction within the array; respect maxSortKeys when adding.\n if (idx < 0) {\n // Not currently in the sort — append at the end.\n const next = appendCapped(current, {\n key,\n direction: initial,\n }, maxSortKeys.value);\n local.value = next;\n emit(next);\n return;\n }\n\n // Key already present in append mode — cycle direction OR remove.\n const existing = current[idx];\n let next: SortDescriptor[];\n if (existing.direction === initial) {\n next = current.map((s, i) => (i === idx ?\n {\n key,\n direction: initial === 'asc' ? 'desc' : 'asc',\n } :\n s));\n } else {\n // Past the \"second\" direction — drop this key from the\n // sort array (mustSort doesn't apply to secondary keys —\n // a multi-sort consumer can always clear individual keys).\n next = current.filter((_, i) => i !== idx);\n }\n local.value = next;\n emit(next);\n }\n\n function directionFor(key: string): SortDirection | null {\n const cur = local.value.find((s) => s.key === key);\n return cur ? cur.direction : null;\n }\n\n function positionFor(key: string): number | null {\n const i = local.value.findIndex((s) => s.key === key);\n return i < 0 ? null : i + 1;\n }\n\n /**\n * Replace the entire sort state. Bypasses cycle logic + multi-sort\n * gating — for callers that know exactly what they want (e.g. the\n * sort-indicator chip row removes / reorders / clears descriptors\n * directly without going through Shift-click semantics).\n */\n function setState(next: TableSortState): void {\n local.value = next;\n emit(next);\n }\n\n return {\n state,\n setSort,\n setState,\n directionFor,\n positionFor,\n };\n}\n\n/**\n * Coerce v-model input into the canonical array shape. `undefined` /\n * `null` (which Vue may bind through during the v1.x-B migration\n * window when consumers still hold `ref<...>(null)`) become `[]`.\n */\nfunction normalize(v: TableSortState | undefined | null): TableSortState {\n if (v == null) return [];\n return v;\n}\n\n/**\n * Append a new descriptor, evicting the oldest when over the cap.\n * Cap of `<= 0` is treated as \"unlimited\" so consumers can opt out.\n */\nfunction appendCapped(\n state: SortDescriptor[],\n descriptor: SortDescriptor,\n max: number,\n): SortDescriptor[] {\n const next = [...state, descriptor];\n if (max > 0 && next.length > max) {\n return next.slice(next.length - max);\n }\n return next;\n}\n\n/**\n * In-place semantic: if `key` is already in the state, update its\n * direction; else append (capped). Used by the explicit-direction\n * path when `append` is set.\n */\nfunction upsertAppend(\n state: SortDescriptor[],\n key: string,\n direction: SortDirection,\n max: number,\n): SortDescriptor[] {\n const idx = state.findIndex((s) => s.key === key);\n if (idx >= 0) {\n return state.map((s, i) => (i === idx ?\n {\n key,\n direction,\n } :\n s));\n }\n return appendCapped(state, {\n key,\n direction,\n }, max);\n}\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableBodyRowSlotProps, TableBodyThemeClasses } from '../types';\n\nconst tableBodyThemeDefaults = { classes: { root: 'vc-table-body' } };\n\nconst tableBodyProps = { ...themableProps<TableBodyThemeClasses>() };\n\nexport type TableBodyProps = ExtractPublicPropTypes<typeof tableBodyProps>;\n\nexport default defineComponent({\n name: 'VCTableBody',\n inheritAttrs: false,\n props: tableBodyProps,\n slots: Object as SlotsType<{\n row(props: TableBodyRowSlotProps): unknown;\n default(): unknown;\n }>,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableBody',\n useThemeProps(props),\n tableBodyThemeDefaults,\n );\n const ctx = useTable();\n\n return () => {\n const rowSlot = slots.row;\n const data = ctx?.data.value ?? [];\n\n let children: unknown[];\n if (rowSlot) {\n // Driver path — auto-iterate `<VCTable>` data. Suppress\n // the entire `<tbody>` when there's nothing to render so\n // `<VCTableEmpty>` / `<VCTableLoading>` get the spotlight\n // (decoupled render conditions per the compound layout).\n if (data.length === 0) return null;\n children = data.map((row, index) => rowSlot({ row, index } as TableBodyRowSlotProps));\n } else {\n // Manual Shape B markup — consumers writing their own\n // `<VCTableRow>` chain inside the default slot drive the\n // content directly. Render whatever they wrote, even if\n // `ctx.data` is empty (their markup might not depend on\n // it).\n children = [slots.default?.() ?? null];\n }\n\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n children as never,\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableBodyRowSlotProps, TableBodyThemeClasses } from '../types';\n\nconst tableBodyThemeDefaults = { classes: { root: 'vc-table-body' } };\n\nconst tableBodyProps = { ...themableProps<TableBodyThemeClasses>() };\n\nexport type TableBodyProps = ExtractPublicPropTypes<typeof tableBodyProps>;\n\nexport default defineComponent({\n name: 'VCTableBody',\n inheritAttrs: false,\n props: tableBodyProps,\n slots: Object as SlotsType<{\n row(props: TableBodyRowSlotProps): unknown;\n default(): unknown;\n }>,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableBody',\n useThemeProps(props),\n tableBodyThemeDefaults,\n );\n const ctx = useTable();\n\n return () => {\n const rowSlot = slots.row;\n const data = ctx?.data.value ?? [];\n\n let children: unknown[];\n if (rowSlot) {\n // Driver path — auto-iterate `<VCTable>` data. Suppress\n // the entire `<tbody>` when there's nothing to render so\n // `<VCTableEmpty>` / `<VCTableLoading>` get the spotlight\n // (decoupled render conditions per the compound layout).\n if (data.length === 0) return null;\n children = data.map((row, index) => rowSlot({ row, index } as TableBodyRowSlotProps));\n } else {\n // Manual Shape B markup — consumers writing their own\n // `<VCTableRow>` chain inside the default slot drive the\n // content directly. Render whatever they wrote, even if\n // `ctx.data` is empty (their markup might not depend on\n // it).\n children = [slots.default?.() ?? null];\n }\n\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n children as never,\n );\n };\n },\n});\n</script>\n","import { isObject } from '@vuecs/core';\nimport type { TableColumn, TableColumnRaw } from '../types';\n\n/**\n * Convert a key like `'firstName'` / `'first_name'` / `'first-name'` to\n * `'First Name'`. Used by the bare-string column shorthand to derive\n * a label when only the key is given.\n */\nexport function startCase(input: string): string {\n if (!input) return '';\n return input\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .replace(/\\s+/g, ' ')\n .trim()\n .split(' ')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\n/**\n * Normalize the `:columns` prop into a uniform `TableColumn[]`.\n *\n * - **Explicit array** (including empty `[]`): pass through, fill `label`\n * from `startCase(key)`. Treating `[]` as authoritative lets consumers\n * deliberately render a header-less table during loading without the\n * auto-derive kicking in the moment data arrives.\n * - **Bare-string shorthand**: `['id', 'name']` → `[{ key, label }, ...]`.\n * - **Auto-derive**: only when `columns` is `undefined` AND `data[0]` is an\n * object, derive the columns from `Object.keys(data[0])`, skipping\n * underscore-prefixed row-meta keys (`_rowVariant` / `_cellVariants`).\n */\nexport function normalizeColumns<Row>(\n columns: ReadonlyArray<TableColumnRaw<Row>> | undefined,\n data: ReadonlyArray<Row>,\n): TableColumn<Row>[] {\n const fromRaw = (col: TableColumnRaw<Row>): TableColumn<Row> => {\n if (typeof col === 'string') {\n return { key: col, label: startCase(col) };\n }\n // Spread first, then fold in `label` so a consumer-passed\n // `label: undefined` doesn't clobber the computed default.\n return { ...col, label: col.label ?? startCase(col.key) };\n };\n\n if (columns !== undefined) {\n return columns.map(fromRaw);\n }\n\n if (data.length === 0 || !isObject(data[0])) return [];\n\n const first = data[0] as Record<string, unknown>;\n return Object.keys(first)\n .filter((key) => !key.startsWith('_'))\n .map((key) => ({ key, label: startCase(key) }));\n}\n\n/**\n * Resolve a column's value against a row.\n *\n * - String accessor: dot-path lookup (e.g. `'profile.email'` → `row.profile.email`)\n * - Function accessor: invoked with the row\n * - Falls back to `row[column.key]`\n */\nexport function resolveCellValue<Row>(column: TableColumn<Row>, row: Row): unknown {\n const { accessor } = column;\n if (typeof accessor === 'function') {\n return accessor(row);\n }\n if (typeof accessor === 'string') {\n return resolveDotPath(row, accessor);\n }\n if (isObject(row)) {\n return (row as Record<string, unknown>)[column.key];\n }\n return undefined;\n}\n\nfunction resolveDotPath(obj: unknown, path: string): unknown {\n if (!isObject(obj)) return undefined;\n let cur: unknown = obj;\n for (const part of path.split('.')) {\n if (!isObject(cur)) return undefined;\n cur = (cur as Record<string, unknown>)[part];\n }\n return cur;\n}\n\n/**\n * Resolve attribute objects, supporting both static-object and function forms\n * used by `cellAttrs` and `headerAttrs`.\n */\nexport function resolveAttrs<Ctx>(\n attrs: Record<string, unknown> | ((ctx: Ctx) => Record<string, unknown>) | undefined,\n ctx: Ctx,\n): Record<string, unknown> | undefined {\n if (!attrs) return undefined;\n return typeof attrs === 'function' ? attrs(ctx) : attrs;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// filterEvent — ported from bootstrap-vue-next's utils/filterEvent.ts\n// (plan 028 §\"filterEvent — richer interactive-descendant exclusion\")\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Selectors that mark an element (or an ancestor of it) as interactive —\n * row-click handlers should NOT fire when the click originates inside one\n * of these. Plan 028 D5 ships this list; the closest-ancestor matching\n * (vs direct-match) is what catches clicks on text INSIDE a button or\n * anchor.\n */\nconst INTERACTIVE_SELECTOR = [\n 'a',\n 'button',\n 'input',\n 'select',\n 'textarea',\n 'label[for]',\n '[role=\"button\"]',\n '[role=\"link\"]',\n '[contenteditable]:not([contenteditable=\"false\"])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '.vc-overlay-portal-content',\n].join(',');\n\n/**\n * Returns `true` when a row-level click should be suppressed because the\n * event originated inside an interactive descendant — a button, anchor,\n * form input, role=button/link, an explicitly-focusable element, or a\n * portal'd overlay rendered into the document body (e.g. a\n * `<VCDropdownMenu>` action menu inside the row).\n *\n * Pass the `<tr>` element as `rowEl` so the helper can disambiguate\n * legitimate row clicks (where the `closest()` ancestor walk reaches the\n * `<tr>` itself, which carries `tabindex=\"0\"` when the row is clickable)\n * from clicks on a genuine interactive descendant.\n *\n * Use at the row click handler: `if (filterRowClickEvent(event, tr)) return;`.\n */\nexport function filterRowClickEvent(event: Event, rowEl?: Element | null): boolean {\n const { target } = event;\n if (!(target instanceof Element)) return false;\n const hit = target.closest(INTERACTIVE_SELECTOR);\n if (hit === null) return false;\n // If the only match is the row itself (which carries `tabindex=\"0\"`\n // when clickable), this is a real row click, not a click on an\n // interactive descendant — let it through.\n if (rowEl && hit === rowEl) return false;\n return true;\n}\n","<script lang=\"ts\">\nimport {\n Comment,\n Fragment,\n Text,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type {\n ExtractPublicPropTypes,\n PropType,\n VNode,\n VNodeArrayChildren,\n} from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useTable, useTableRow } from '../composables/context';\nimport { resolveCellValue } from '../utils/render-utils';\nimport type { TableCellThemeClasses } from '../types';\n\nconst tableCellThemeDefaults = { classes: { root: 'vc-table-cell' } };\n\nconst tableCellProps = {\n /** Render as `<th scope=\"row\">` instead of `<td>` (mirror of `column.isRowHeader`). */\n isRowHeader: { type: Boolean, default: false },\n /**\n * Column key this cell corresponds to — used to resolve\n * `_cellVariants[key]` from row meta AND to look up the column's\n * `accessor` / `formatter` for the default-render path.\n */\n columnKey: { type: String, default: undefined },\n /** Forward-compat for stacked-mode CSS — emitted as `data-label`. */\n dataLabel: { type: String, default: undefined },\n /** Alignment helper — selects the `align.<value>` theme variant. */\n align: { type: String as PropType<'left' | 'center' | 'right'>, default: undefined },\n /** `position: sticky` on this cell. Forwarded as `themeVariant.stickyColumn`. */\n stickyColumn: { type: Boolean, default: undefined },\n /**\n * Renders a selection checkbox/radio for this row. Pairs with\n * `<VCTableHeadCell isSelector>` to build a selection column.\n * State mirrors `selection.isSelected(rowKey)`; clicking toggles\n * that row independently of any row-click handler. Falls back\n * to the default slot when selection is off.\n */\n isSelector: { type: Boolean, default: false },\n /** `aria-label` for the per-row checkbox (defaults to `'Select row'`). */\n selectorAriaLabel: { type: String, default: 'Select row' },\n ...themableProps<TableCellThemeClasses>(),\n};\n\nexport type TableCellProps = ExtractPublicPropTypes<typeof tableCellProps>;\n\n/**\n * Detect whether the consumer-passed default slot's rendered vnodes\n * contain any meaningful content (vs being an empty / whitespace-only\n * / comment-only render).\n *\n * Vue passes `slots.default` as a render fn that's always present when\n * a `<template>` slot is declared (even if empty), so a naive\n * `slots.default?.()` truthy check would always pick the slot path\n * and skip the auto-render. Walk the rendered vnodes and recurse into\n * `Fragment` children — a `<template v-if>` / `<template v-for>` /\n * multi-child template renders as a Fragment whose `children` is the\n * actual content. Without recursion those would be falsely classified\n * as empty.\n *\n * Takes the pre-rendered vnodes (not the slot fn) so the caller can\n * invoke the slot at most once per render — slot fns can be\n * non-trivial and should not be called twice.\n */\nfunction hasMeaningfulSlotContent(nodes: unknown): boolean {\n if (nodes == null || nodes === false) return false;\n if (typeof nodes === 'string') return nodes.trim().length > 0;\n if (typeof nodes === 'number') return true;\n if (Array.isArray(nodes)) {\n for (const child of nodes) {\n if (hasMeaningfulSlotContent(child)) return true;\n }\n return false;\n }\n if (typeof nodes !== 'object') return false;\n const v = nodes as VNode;\n if (v.type === Comment) return false;\n if (v.type === Text) {\n return typeof v.children === 'string' && v.children.trim().length > 0;\n }\n if (v.type === Fragment) {\n return hasMeaningfulSlotContent(v.children);\n }\n // Element or component vnode (string tag, object component, symbol other than the above).\n return true;\n}\n\nexport default defineComponent({\n name: 'VCTableCell',\n inheritAttrs: false,\n props: tableCellProps,\n setup(props, { attrs, slots }) {\n const tableCtx = useTable();\n const rowCtx = useTableRow();\n const themeProps = useThemeProps(props, 'align', 'stickyColumn');\n\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n const cellVariant = props.columnKey ?\n rowCtx?.cellVariants.value[props.columnKey] ?? undefined :\n undefined;\n return {\n ...(themeProps.themeVariant ?? {}),\n ...(cellVariant ? { cellVariant } : {}),\n };\n },\n };\n const theme = useComponentTheme('tableCell', mergedThemeProps, tableCellThemeDefaults);\n\n return () => {\n // Selector cell — renders a checkbox / radio bound to the\n // current row's selection state. Short-circuits the\n // default-cell rendering entirely so consumers don't need\n // to pass slot content. Falls back to the default render\n // path when selection is off, so consumers can keep\n // `is-selector` cells in place when toggling selection.\n if (props.isSelector && tableCtx?.selection.mode.value !== undefined && rowCtx) {\n const rowKey = rowCtx.selectionKey.value;\n const mode = tableCtx.selection.mode.value;\n const checked = tableCtx.selection.isSelected(rowKey);\n // ARIA grid role is always required here — the outer\n // guard already established `mode !== undefined`, so\n // the parent `<table>` carries `role=\"grid\"`.\n return h(\n props.isRowHeader ? 'th' : 'td',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'data-label': props.dataLabel || undefined,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n scope: props.isRowHeader ? 'row' : undefined,\n role: props.isRowHeader ? 'rowheader' : 'gridcell',\n }),\n [\n h('input', {\n type: mode === 'single' ? 'radio' : 'checkbox',\n class: 'vc-table-selector-checkbox',\n 'aria-label': props.selectorAriaLabel,\n checked,\n onClick: (e: globalThis.MouseEvent) => {\n e.stopPropagation();\n if (rowKey === undefined) return;\n tableCtx.selection.toggle(rowKey);\n },\n }),\n ],\n );\n }\n\n // Default-render path: when the consumer didn't provide slot\n // content AND we have enough context (table column lookup + row\n // value), resolve via `accessor` + `formatter`. Slot content\n // always wins — the consumer keeps full control when they pass\n // anything. Invoke `slots.default` at most once per render.\n const slotVNodes = slots.default?.();\n let content: unknown = slotVNodes;\n if (\n props.columnKey &&\n tableCtx &&\n rowCtx &&\n !hasMeaningfulSlotContent(slotVNodes)\n ) {\n const column = tableCtx.columns.value\n .find((c) => c.key === props.columnKey);\n if (column) {\n const value = resolveCellValue(column, rowCtx.row.value);\n if (column.formatter) {\n content = column.formatter({\n value,\n key: column.key,\n row: rowCtx.row.value,\n });\n } else if (value === undefined || value === null) {\n content = '';\n } else {\n content = String(value);\n }\n }\n }\n\n // ARIA grid pattern: when the parent table has `role=\"grid\"`\n // (selection-mode active), implicit `<td>` / `<th>` roles\n // don't carry through the overridden parent role. Cells\n // need explicit `gridcell` / `rowheader` so assistive tech\n // sees a complete grid structure.\n const inGrid = tableCtx?.selection.mode.value !== undefined;\n let cellRole: 'rowheader' | 'gridcell' | undefined;\n if (inGrid) cellRole = props.isRowHeader ? 'rowheader' : 'gridcell';\n const ariaAttrs: Record<string, unknown> = inGrid ? { role: cellRole } : {};\n\n return h(\n props.isRowHeader ? 'th' : 'td',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'data-label': props.dataLabel || undefined,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n scope: props.isRowHeader ? 'row' : undefined,\n ...ariaAttrs,\n }),\n content as string | VNodeArrayChildren,\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n Comment,\n Fragment,\n Text,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type {\n ExtractPublicPropTypes,\n PropType,\n VNode,\n VNodeArrayChildren,\n} from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useTable, useTableRow } from '../composables/context';\nimport { resolveCellValue } from '../utils/render-utils';\nimport type { TableCellThemeClasses } from '../types';\n\nconst tableCellThemeDefaults = { classes: { root: 'vc-table-cell' } };\n\nconst tableCellProps = {\n /** Render as `<th scope=\"row\">` instead of `<td>` (mirror of `column.isRowHeader`). */\n isRowHeader: { type: Boolean, default: false },\n /**\n * Column key this cell corresponds to — used to resolve\n * `_cellVariants[key]` from row meta AND to look up the column's\n * `accessor` / `formatter` for the default-render path.\n */\n columnKey: { type: String, default: undefined },\n /** Forward-compat for stacked-mode CSS — emitted as `data-label`. */\n dataLabel: { type: String, default: undefined },\n /** Alignment helper — selects the `align.<value>` theme variant. */\n align: { type: String as PropType<'left' | 'center' | 'right'>, default: undefined },\n /** `position: sticky` on this cell. Forwarded as `themeVariant.stickyColumn`. */\n stickyColumn: { type: Boolean, default: undefined },\n /**\n * Renders a selection checkbox/radio for this row. Pairs with\n * `<VCTableHeadCell isSelector>` to build a selection column.\n * State mirrors `selection.isSelected(rowKey)`; clicking toggles\n * that row independently of any row-click handler. Falls back\n * to the default slot when selection is off.\n */\n isSelector: { type: Boolean, default: false },\n /** `aria-label` for the per-row checkbox (defaults to `'Select row'`). */\n selectorAriaLabel: { type: String, default: 'Select row' },\n ...themableProps<TableCellThemeClasses>(),\n};\n\nexport type TableCellProps = ExtractPublicPropTypes<typeof tableCellProps>;\n\n/**\n * Detect whether the consumer-passed default slot's rendered vnodes\n * contain any meaningful content (vs being an empty / whitespace-only\n * / comment-only render).\n *\n * Vue passes `slots.default` as a render fn that's always present when\n * a `<template>` slot is declared (even if empty), so a naive\n * `slots.default?.()` truthy check would always pick the slot path\n * and skip the auto-render. Walk the rendered vnodes and recurse into\n * `Fragment` children — a `<template v-if>` / `<template v-for>` /\n * multi-child template renders as a Fragment whose `children` is the\n * actual content. Without recursion those would be falsely classified\n * as empty.\n *\n * Takes the pre-rendered vnodes (not the slot fn) so the caller can\n * invoke the slot at most once per render — slot fns can be\n * non-trivial and should not be called twice.\n */\nfunction hasMeaningfulSlotContent(nodes: unknown): boolean {\n if (nodes == null || nodes === false) return false;\n if (typeof nodes === 'string') return nodes.trim().length > 0;\n if (typeof nodes === 'number') return true;\n if (Array.isArray(nodes)) {\n for (const child of nodes) {\n if (hasMeaningfulSlotContent(child)) return true;\n }\n return false;\n }\n if (typeof nodes !== 'object') return false;\n const v = nodes as VNode;\n if (v.type === Comment) return false;\n if (v.type === Text) {\n return typeof v.children === 'string' && v.children.trim().length > 0;\n }\n if (v.type === Fragment) {\n return hasMeaningfulSlotContent(v.children);\n }\n // Element or component vnode (string tag, object component, symbol other than the above).\n return true;\n}\n\nexport default defineComponent({\n name: 'VCTableCell',\n inheritAttrs: false,\n props: tableCellProps,\n setup(props, { attrs, slots }) {\n const tableCtx = useTable();\n const rowCtx = useTableRow();\n const themeProps = useThemeProps(props, 'align', 'stickyColumn');\n\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n const cellVariant = props.columnKey ?\n rowCtx?.cellVariants.value[props.columnKey] ?? undefined :\n undefined;\n return {\n ...(themeProps.themeVariant ?? {}),\n ...(cellVariant ? { cellVariant } : {}),\n };\n },\n };\n const theme = useComponentTheme('tableCell', mergedThemeProps, tableCellThemeDefaults);\n\n return () => {\n // Selector cell — renders a checkbox / radio bound to the\n // current row's selection state. Short-circuits the\n // default-cell rendering entirely so consumers don't need\n // to pass slot content. Falls back to the default render\n // path when selection is off, so consumers can keep\n // `is-selector` cells in place when toggling selection.\n if (props.isSelector && tableCtx?.selection.mode.value !== undefined && rowCtx) {\n const rowKey = rowCtx.selectionKey.value;\n const mode = tableCtx.selection.mode.value;\n const checked = tableCtx.selection.isSelected(rowKey);\n // ARIA grid role is always required here — the outer\n // guard already established `mode !== undefined`, so\n // the parent `<table>` carries `role=\"grid\"`.\n return h(\n props.isRowHeader ? 'th' : 'td',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'data-label': props.dataLabel || undefined,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n scope: props.isRowHeader ? 'row' : undefined,\n role: props.isRowHeader ? 'rowheader' : 'gridcell',\n }),\n [\n h('input', {\n type: mode === 'single' ? 'radio' : 'checkbox',\n class: 'vc-table-selector-checkbox',\n 'aria-label': props.selectorAriaLabel,\n checked,\n onClick: (e: globalThis.MouseEvent) => {\n e.stopPropagation();\n if (rowKey === undefined) return;\n tableCtx.selection.toggle(rowKey);\n },\n }),\n ],\n );\n }\n\n // Default-render path: when the consumer didn't provide slot\n // content AND we have enough context (table column lookup + row\n // value), resolve via `accessor` + `formatter`. Slot content\n // always wins — the consumer keeps full control when they pass\n // anything. Invoke `slots.default` at most once per render.\n const slotVNodes = slots.default?.();\n let content: unknown = slotVNodes;\n if (\n props.columnKey &&\n tableCtx &&\n rowCtx &&\n !hasMeaningfulSlotContent(slotVNodes)\n ) {\n const column = tableCtx.columns.value\n .find((c) => c.key === props.columnKey);\n if (column) {\n const value = resolveCellValue(column, rowCtx.row.value);\n if (column.formatter) {\n content = column.formatter({\n value,\n key: column.key,\n row: rowCtx.row.value,\n });\n } else if (value === undefined || value === null) {\n content = '';\n } else {\n content = String(value);\n }\n }\n }\n\n // ARIA grid pattern: when the parent table has `role=\"grid\"`\n // (selection-mode active), implicit `<td>` / `<th>` roles\n // don't carry through the overridden parent role. Cells\n // need explicit `gridcell` / `rowheader` so assistive tech\n // sees a complete grid structure.\n const inGrid = tableCtx?.selection.mode.value !== undefined;\n let cellRole: 'rowheader' | 'gridcell' | undefined;\n if (inGrid) cellRole = props.isRowHeader ? 'rowheader' : 'gridcell';\n const ariaAttrs: Record<string, unknown> = inGrid ? { role: cellRole } : {};\n\n return h(\n props.isRowHeader ? 'th' : 'td',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'data-label': props.dataLabel || undefined,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n scope: props.isRowHeader ? 'row' : undefined,\n ...ariaAttrs,\n }),\n content as string | VNodeArrayChildren,\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { provideHeadCellCountContext } from '../composables/context';\nimport type { TableFooterThemeClasses } from '../types';\n\nconst tableFooterThemeDefaults = { classes: { root: 'vc-table-footer' } };\n\nconst tableFooterProps = { ...themableProps<TableFooterThemeClasses>() };\n\nexport type TableFooterProps = ExtractPublicPropTypes<typeof tableFooterProps>;\n\nexport default defineComponent({\n name: 'VCTableFooter',\n inheritAttrs: false,\n props: tableFooterProps,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableFooter',\n useThemeProps(props),\n tableFooterThemeDefaults,\n );\n\n // Provide a no-op head-cell-count context so `<VCTableHeadCell>`s\n // inside `<tfoot>` don't double-register against the colspan auto-count\n // (which is meant to reflect the header band, not the footer band).\n provideHeadCellCountContext({ register: () => {}, unregister: () => {} });\n\n return () => h(\n 'tfoot',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n slots.default?.(),\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { provideHeadCellCountContext } from '../composables/context';\nimport type { TableFooterThemeClasses } from '../types';\n\nconst tableFooterThemeDefaults = { classes: { root: 'vc-table-footer' } };\n\nconst tableFooterProps = { ...themableProps<TableFooterThemeClasses>() };\n\nexport type TableFooterProps = ExtractPublicPropTypes<typeof tableFooterProps>;\n\nexport default defineComponent({\n name: 'VCTableFooter',\n inheritAttrs: false,\n props: tableFooterProps,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableFooter',\n useThemeProps(props),\n tableFooterThemeDefaults,\n );\n\n // Provide a no-op head-cell-count context so `<VCTableHeadCell>`s\n // inside `<tfoot>` don't double-register against the colspan auto-count\n // (which is meant to reflect the header band, not the footer band).\n provideHeadCellCountContext({ register: () => {}, unregister: () => {} });\n\n return () => h(\n 'tfoot',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n slots.default?.(),\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { \n computed, \n defineComponent, \n h, \n mergeProps, \n onBeforeUnmount, \n onMounted, \n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useHeadCellCountContext, useTable } from '../composables/context';\nimport type { SortDirection, TableHeadCellThemeClasses } from '../types';\n\nconst tableHeadCellThemeDefaults = {\n classes: {\n root: 'vc-table-head-cell',\n sortIcon: 'vc-table-head-cell-sort-icon',\n },\n};\n\nfunction renderHeadContent(args: {\n isSelector: boolean;\n selectionMode: 'single' | 'multi' | undefined;\n selectAllState: 'all' | 'some' | 'none';\n selectorAriaLabel: string;\n onSelectorClick: () => void;\n defaultSlot: (() => unknown) | undefined;\n}): unknown {\n if (!args.isSelector) return args.defaultSlot?.();\n // Empty in single mode — \"select-all\" doesn't apply.\n if (args.selectionMode === 'single') return null;\n // No selection mode at all → fall back to whatever the consumer\n // put in the slot so the column doesn't visually collapse.\n if (args.selectionMode === undefined) return args.defaultSlot?.();\n return h('input', {\n type: 'checkbox',\n class: 'vc-table-selector-checkbox',\n 'aria-label': args.selectorAriaLabel,\n checked: args.selectAllState === 'all',\n // jsdom + real browsers both require setting `indeterminate`\n // as a property (no attribute form). Vue's runtime forwards\n // prop-style bindings via `el.indeterminate = …`.\n indeterminate: args.selectAllState === 'some',\n onClick: (e: globalThis.MouseEvent) => {\n e.stopPropagation();\n args.onSelectorClick();\n },\n });\n}\n\nconst tableHeadCellProps = {\n /** Column key — required for sort wiring (omit for purely presentational heads). */\n columnKey: { type: String, default: undefined },\n /** Mark this header sortable. When set, click + Enter/Space cycle sort state. */\n sortable: { type: Boolean, default: false },\n /** Override scope (\"col\" / \"colgroup\" / \"row\" / \"rowgroup\"). Smart default: colspan→colgroup, rowspan→rowgroup, else col. */\n scope: { type: String as PropType<'col' | 'colgroup' | 'row' | 'rowgroup'>, default: undefined },\n /** Native `<th colspan>` (forwarded; also drives the smart scope default). */\n colspan: { type: Number, default: undefined },\n /** Native `<th rowspan>` (forwarded; also drives the smart scope default). */\n rowspan: { type: Number, default: undefined },\n /** Native `<th title>`. */\n title: { type: String, default: undefined },\n /** Native `<th abbr>`. */\n abbr: { type: String, default: undefined },\n /** Alignment helper — selects the `align.<value>` theme variant. */\n align: { type: String as PropType<'left' | 'center' | 'right'>, default: undefined },\n /** `position: sticky` on this header cell. Forwarded as `themeVariant.stickyColumn`. */\n stickyColumn: { type: Boolean, default: undefined },\n /**\n * Renders a select-all checkbox when the parent table has\n * `:selection-mode=\"multi\"`. State is derived from the current\n * selection against the visible data set: checked = all visible\n * rows selected; indeterminate = some visible rows selected;\n * unchecked = none.\n *\n * Click semantics — Gmail / GitHub style: when state is `none`\n * or `some`, ADDS every visible row's key to the selection\n * (preserving any off-screen / paginated selection); when state\n * is `all`, REMOVES every visible row's key (also preserving\n * off-screen selection). Cross-page selection persists across\n * pagination flips.\n *\n * In `single` mode the header renders empty (only one row can\n * be selected); when selection is off, the slot's default\n * content renders so the column collapses gracefully.\n */\n isSelector: { type: Boolean, default: false },\n /** `aria-label` for the select-all checkbox (defaults to `'Select all rows'`). */\n selectorAriaLabel: { type: String, default: 'Select all rows' },\n ...themableProps<TableHeadCellThemeClasses>(),\n};\n\nexport type TableHeadCellProps = ExtractPublicPropTypes<typeof tableHeadCellProps>;\n\nexport default defineComponent({\n name: 'VCTableHeadCell',\n inheritAttrs: false,\n props: tableHeadCellProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n\n // Register against the head-cell-count context so Shape B\n // (manual <VCTableHeader>) can auto-resolve the empty / loading\n // colspan. The `<VCTableFooter>` provides a no-op variant, so\n // cells in the footer skip this.\n const countCtx = useHeadCellCountContext();\n onMounted(() => countCtx?.register());\n onBeforeUnmount(() => countCtx?.unregister());\n\n // Theme — fold sorted state + stickyColumn into themeVariant\n const themeProps = useThemeProps(props, 'align', 'stickyColumn');\n // Sort state is `SortDescriptor[]` since v1.x-B. Find THIS\n // column's entry to drive the indicator arrow + numeric badge.\n const sortDirection = computed<SortDirection | null>(() => {\n if (!props.sortable || !props.columnKey || !ctx) return null;\n const found = ctx.sort.value.find((s) => s.key === props.columnKey);\n return found ? found.direction : null;\n });\n const sortIndex = computed<number | null>(() => {\n if (!props.sortable || !props.columnKey || !ctx) return null;\n const i = ctx.sort.value.findIndex((s) => s.key === props.columnKey);\n return i < 0 ? null : i + 1;\n });\n\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n sorted: sortDirection.value ?? 'none',\n };\n },\n };\n const theme = useComponentTheme('tableHeadCell', mergedThemeProps, tableHeadCellThemeDefaults);\n\n // Smart scope default — col / colgroup / rowgroup per the multi-axis\n // span hints. Consumers can still override via `:scope`.\n const resolvedScope = computed(() => {\n if (props.scope) return props.scope;\n if (props.colspan && props.colspan > 1) return 'colgroup';\n if (props.rowspan && props.rowspan > 1) return 'rowgroup';\n return 'col';\n });\n\n const ariaSort = computed(() => {\n if (!props.sortable) return undefined;\n const d = sortDirection.value;\n if (d === 'asc') return 'ascending';\n if (d === 'desc') return 'descending';\n return 'none';\n });\n\n function onClick(event: globalThis.MouseEvent) {\n if (!props.sortable || !props.columnKey) return;\n event.preventDefault();\n ctx?.setSort(props.columnKey, { append: event.shiftKey });\n }\n\n // Select-all state — derived from the visible data set and\n // the current selection. Visible-data check matches the\n // documented \"select-all\" mental model: if the user has\n // filtered rows out, select-all only affects the visible\n // subset.\n //\n // Defensive fallback to the row index when `getRowKey` returns\n // `null` / `undefined` mirrors the `<VCTableRow>` resolution\n // (`getRowKey(row, i) ?? props.index`) so a misbehaving\n // resolver can't push invalid keys into the select-all set.\n const allRowKeys = computed<(string | number)[]>(() => {\n if (!ctx) return [];\n const data = ctx.data.value;\n return data.map((row, i) => ctx.getRowKey(row, i) ?? i);\n });\n const selectAllState = computed<'all' | 'some' | 'none'>(() => {\n if (!ctx || ctx.selection.mode.value !== 'multi') return 'none';\n const keys = allRowKeys.value;\n if (keys.length === 0) return 'none';\n // Pre-build a Set from the current selection so membership\n // checks are O(1) per row — `isSelected` falls back to\n // `Array.includes`, making the worst case O(visible *\n // selected) for large tables.\n const sel = ctx.selection.value.value;\n const selectedSet = new Set<string | number>(\n Array.isArray(sel) ? sel : [],\n );\n if (selectedSet.size === 0) return 'none';\n let selectedCount = 0;\n for (const k of keys) if (selectedSet.has(k)) selectedCount += 1;\n if (selectedCount === 0) return 'none';\n if (selectedCount === keys.length) return 'all';\n return 'some';\n });\n function onSelectorClick() {\n if (!ctx || ctx.selection.mode.value !== 'multi') return;\n // Cross-page-safe semantics: union with the current\n // selection rather than overwriting. This way, a row\n // selected on page 1 doesn't get clobbered when the user\n // navigates to page 2 and clicks select-all (matches\n // Gmail / GitHub).\n const current = ctx.selection.value.value;\n const existing = new Set<string | number>(\n Array.isArray(current) ? current : [],\n );\n if (selectAllState.value === 'all') {\n // Clear every VISIBLE row's key from the existing set;\n // off-screen selections are preserved.\n for (const k of allRowKeys.value) existing.delete(k);\n } else {\n // Add every visible row's key to the existing set.\n for (const k of allRowKeys.value) existing.add(k);\n }\n ctx.selection.setValue(Array.from(existing));\n }\n\n function onKeydown(event: globalThis.KeyboardEvent) {\n if (!props.sortable || !props.columnKey) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n ctx?.setSort(props.columnKey, { append: event.shiftKey });\n }\n }\n\n return () => h(\n 'th',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n scope: resolvedScope.value,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n colspan: props.colspan,\n rowspan: props.rowspan,\n title: props.title,\n abbr: props.abbr,\n 'aria-sort': ariaSort.value,\n // Numeric multi-sort badge index. `null` (or 1 — the\n // primary key) doesn't emit the attribute, so the\n // structural CSS `::after` badge only shows for\n // secondary/tertiary keys; primary key still gets the\n // up/down arrow span below.\n 'data-sort-index': sortIndex.value !== null && sortIndex.value > 1 ?\n String(sortIndex.value) :\n undefined,\n tabindex: props.sortable ? 0 : undefined,\n // Explicit `role=\"columnheader\"` is required whenever the\n // parent table has `role=\"grid\"` (selection-mode active)\n // OR the header is sortable (vuecs's tabindex pattern).\n // Outside both cases, `<th>` inside `<thead>` carries the\n // implicit `columnheader` role.\n role: (props.sortable || ctx?.selection.mode.value !== undefined) ?\n 'columnheader' :\n undefined,\n onClick: props.sortable ? onClick : undefined,\n onKeydown: props.sortable ? onKeydown : undefined,\n }),\n ([\n // Selector head — checkbox in multi mode; empty in\n // single mode (only one row can be selected so a\n // \"select-all\" doesn't apply). Falls through to the\n // default slot when selection is off entirely so the\n // column collapses gracefully if a consumer keeps\n // `is-selector` cells in place when toggling\n // selection off.\n renderHeadContent({\n isSelector: props.isSelector,\n selectionMode: ctx?.selection.mode.value,\n selectAllState: selectAllState.value,\n selectorAriaLabel: props.selectorAriaLabel,\n onSelectorClick,\n defaultSlot: slots.default,\n }),\n props.sortable && sortDirection.value ?\n h('span', {\n class: theme.value.sortIcon || undefined,\n 'aria-hidden': 'true',\n 'data-sort': sortDirection.value,\n }, sortDirection.value === 'asc' ? '↑' : '↓') :\n null,\n ]) as never,\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { \n computed, \n defineComponent, \n h, \n mergeProps, \n onBeforeUnmount, \n onMounted, \n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport { useHeadCellCountContext, useTable } from '../composables/context';\nimport type { SortDirection, TableHeadCellThemeClasses } from '../types';\n\nconst tableHeadCellThemeDefaults = {\n classes: {\n root: 'vc-table-head-cell',\n sortIcon: 'vc-table-head-cell-sort-icon',\n },\n};\n\nfunction renderHeadContent(args: {\n isSelector: boolean;\n selectionMode: 'single' | 'multi' | undefined;\n selectAllState: 'all' | 'some' | 'none';\n selectorAriaLabel: string;\n onSelectorClick: () => void;\n defaultSlot: (() => unknown) | undefined;\n}): unknown {\n if (!args.isSelector) return args.defaultSlot?.();\n // Empty in single mode — \"select-all\" doesn't apply.\n if (args.selectionMode === 'single') return null;\n // No selection mode at all → fall back to whatever the consumer\n // put in the slot so the column doesn't visually collapse.\n if (args.selectionMode === undefined) return args.defaultSlot?.();\n return h('input', {\n type: 'checkbox',\n class: 'vc-table-selector-checkbox',\n 'aria-label': args.selectorAriaLabel,\n checked: args.selectAllState === 'all',\n // jsdom + real browsers both require setting `indeterminate`\n // as a property (no attribute form). Vue's runtime forwards\n // prop-style bindings via `el.indeterminate = …`.\n indeterminate: args.selectAllState === 'some',\n onClick: (e: globalThis.MouseEvent) => {\n e.stopPropagation();\n args.onSelectorClick();\n },\n });\n}\n\nconst tableHeadCellProps = {\n /** Column key — required for sort wiring (omit for purely presentational heads). */\n columnKey: { type: String, default: undefined },\n /** Mark this header sortable. When set, click + Enter/Space cycle sort state. */\n sortable: { type: Boolean, default: false },\n /** Override scope (\"col\" / \"colgroup\" / \"row\" / \"rowgroup\"). Smart default: colspan→colgroup, rowspan→rowgroup, else col. */\n scope: { type: String as PropType<'col' | 'colgroup' | 'row' | 'rowgroup'>, default: undefined },\n /** Native `<th colspan>` (forwarded; also drives the smart scope default). */\n colspan: { type: Number, default: undefined },\n /** Native `<th rowspan>` (forwarded; also drives the smart scope default). */\n rowspan: { type: Number, default: undefined },\n /** Native `<th title>`. */\n title: { type: String, default: undefined },\n /** Native `<th abbr>`. */\n abbr: { type: String, default: undefined },\n /** Alignment helper — selects the `align.<value>` theme variant. */\n align: { type: String as PropType<'left' | 'center' | 'right'>, default: undefined },\n /** `position: sticky` on this header cell. Forwarded as `themeVariant.stickyColumn`. */\n stickyColumn: { type: Boolean, default: undefined },\n /**\n * Renders a select-all checkbox when the parent table has\n * `:selection-mode=\"multi\"`. State is derived from the current\n * selection against the visible data set: checked = all visible\n * rows selected; indeterminate = some visible rows selected;\n * unchecked = none.\n *\n * Click semantics — Gmail / GitHub style: when state is `none`\n * or `some`, ADDS every visible row's key to the selection\n * (preserving any off-screen / paginated selection); when state\n * is `all`, REMOVES every visible row's key (also preserving\n * off-screen selection). Cross-page selection persists across\n * pagination flips.\n *\n * In `single` mode the header renders empty (only one row can\n * be selected); when selection is off, the slot's default\n * content renders so the column collapses gracefully.\n */\n isSelector: { type: Boolean, default: false },\n /** `aria-label` for the select-all checkbox (defaults to `'Select all rows'`). */\n selectorAriaLabel: { type: String, default: 'Select all rows' },\n ...themableProps<TableHeadCellThemeClasses>(),\n};\n\nexport type TableHeadCellProps = ExtractPublicPropTypes<typeof tableHeadCellProps>;\n\nexport default defineComponent({\n name: 'VCTableHeadCell',\n inheritAttrs: false,\n props: tableHeadCellProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n\n // Register against the head-cell-count context so Shape B\n // (manual <VCTableHeader>) can auto-resolve the empty / loading\n // colspan. The `<VCTableFooter>` provides a no-op variant, so\n // cells in the footer skip this.\n const countCtx = useHeadCellCountContext();\n onMounted(() => countCtx?.register());\n onBeforeUnmount(() => countCtx?.unregister());\n\n // Theme — fold sorted state + stickyColumn into themeVariant\n const themeProps = useThemeProps(props, 'align', 'stickyColumn');\n // Sort state is `SortDescriptor[]` since v1.x-B. Find THIS\n // column's entry to drive the indicator arrow + numeric badge.\n const sortDirection = computed<SortDirection | null>(() => {\n if (!props.sortable || !props.columnKey || !ctx) return null;\n const found = ctx.sort.value.find((s) => s.key === props.columnKey);\n return found ? found.direction : null;\n });\n const sortIndex = computed<number | null>(() => {\n if (!props.sortable || !props.columnKey || !ctx) return null;\n const i = ctx.sort.value.findIndex((s) => s.key === props.columnKey);\n return i < 0 ? null : i + 1;\n });\n\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n sorted: sortDirection.value ?? 'none',\n };\n },\n };\n const theme = useComponentTheme('tableHeadCell', mergedThemeProps, tableHeadCellThemeDefaults);\n\n // Smart scope default — col / colgroup / rowgroup per the multi-axis\n // span hints. Consumers can still override via `:scope`.\n const resolvedScope = computed(() => {\n if (props.scope) return props.scope;\n if (props.colspan && props.colspan > 1) return 'colgroup';\n if (props.rowspan && props.rowspan > 1) return 'rowgroup';\n return 'col';\n });\n\n const ariaSort = computed(() => {\n if (!props.sortable) return undefined;\n const d = sortDirection.value;\n if (d === 'asc') return 'ascending';\n if (d === 'desc') return 'descending';\n return 'none';\n });\n\n function onClick(event: globalThis.MouseEvent) {\n if (!props.sortable || !props.columnKey) return;\n event.preventDefault();\n ctx?.setSort(props.columnKey, { append: event.shiftKey });\n }\n\n // Select-all state — derived from the visible data set and\n // the current selection. Visible-data check matches the\n // documented \"select-all\" mental model: if the user has\n // filtered rows out, select-all only affects the visible\n // subset.\n //\n // Defensive fallback to the row index when `getRowKey` returns\n // `null` / `undefined` mirrors the `<VCTableRow>` resolution\n // (`getRowKey(row, i) ?? props.index`) so a misbehaving\n // resolver can't push invalid keys into the select-all set.\n const allRowKeys = computed<(string | number)[]>(() => {\n if (!ctx) return [];\n const data = ctx.data.value;\n return data.map((row, i) => ctx.getRowKey(row, i) ?? i);\n });\n const selectAllState = computed<'all' | 'some' | 'none'>(() => {\n if (!ctx || ctx.selection.mode.value !== 'multi') return 'none';\n const keys = allRowKeys.value;\n if (keys.length === 0) return 'none';\n // Pre-build a Set from the current selection so membership\n // checks are O(1) per row — `isSelected` falls back to\n // `Array.includes`, making the worst case O(visible *\n // selected) for large tables.\n const sel = ctx.selection.value.value;\n const selectedSet = new Set<string | number>(\n Array.isArray(sel) ? sel : [],\n );\n if (selectedSet.size === 0) return 'none';\n let selectedCount = 0;\n for (const k of keys) if (selectedSet.has(k)) selectedCount += 1;\n if (selectedCount === 0) return 'none';\n if (selectedCount === keys.length) return 'all';\n return 'some';\n });\n function onSelectorClick() {\n if (!ctx || ctx.selection.mode.value !== 'multi') return;\n // Cross-page-safe semantics: union with the current\n // selection rather than overwriting. This way, a row\n // selected on page 1 doesn't get clobbered when the user\n // navigates to page 2 and clicks select-all (matches\n // Gmail / GitHub).\n const current = ctx.selection.value.value;\n const existing = new Set<string | number>(\n Array.isArray(current) ? current : [],\n );\n if (selectAllState.value === 'all') {\n // Clear every VISIBLE row's key from the existing set;\n // off-screen selections are preserved.\n for (const k of allRowKeys.value) existing.delete(k);\n } else {\n // Add every visible row's key to the existing set.\n for (const k of allRowKeys.value) existing.add(k);\n }\n ctx.selection.setValue(Array.from(existing));\n }\n\n function onKeydown(event: globalThis.KeyboardEvent) {\n if (!props.sortable || !props.columnKey) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n ctx?.setSort(props.columnKey, { append: event.shiftKey });\n }\n }\n\n return () => h(\n 'th',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n scope: resolvedScope.value,\n 'data-sticky-column': props.stickyColumn ? '' : undefined,\n colspan: props.colspan,\n rowspan: props.rowspan,\n title: props.title,\n abbr: props.abbr,\n 'aria-sort': ariaSort.value,\n // Numeric multi-sort badge index. `null` (or 1 — the\n // primary key) doesn't emit the attribute, so the\n // structural CSS `::after` badge only shows for\n // secondary/tertiary keys; primary key still gets the\n // up/down arrow span below.\n 'data-sort-index': sortIndex.value !== null && sortIndex.value > 1 ?\n String(sortIndex.value) :\n undefined,\n tabindex: props.sortable ? 0 : undefined,\n // Explicit `role=\"columnheader\"` is required whenever the\n // parent table has `role=\"grid\"` (selection-mode active)\n // OR the header is sortable (vuecs's tabindex pattern).\n // Outside both cases, `<th>` inside `<thead>` carries the\n // implicit `columnheader` role.\n role: (props.sortable || ctx?.selection.mode.value !== undefined) ?\n 'columnheader' :\n undefined,\n onClick: props.sortable ? onClick : undefined,\n onKeydown: props.sortable ? onKeydown : undefined,\n }),\n ([\n // Selector head — checkbox in multi mode; empty in\n // single mode (only one row can be selected so a\n // \"select-all\" doesn't apply). Falls through to the\n // default slot when selection is off entirely so the\n // column collapses gracefully if a consumer keeps\n // `is-selector` cells in place when toggling\n // selection off.\n renderHeadContent({\n isSelector: props.isSelector,\n selectionMode: ctx?.selection.mode.value,\n selectAllState: selectAllState.value,\n selectorAriaLabel: props.selectorAriaLabel,\n onSelectorClick,\n defaultSlot: slots.default,\n }),\n props.sortable && sortDirection.value ?\n h('span', {\n class: theme.value.sortIcon || undefined,\n 'aria-hidden': 'true',\n 'data-sort': sortDirection.value,\n }, sortDirection.value === 'asc' ? '↑' : '↓') :\n null,\n ]) as never,\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport type { TableHeaderThemeClasses } from '../types';\n\nconst tableHeaderThemeDefaults = { classes: { root: 'vc-table-header' } };\n\nconst tableHeaderProps = { ...themableProps<TableHeaderThemeClasses>() };\n\nexport type TableHeaderProps = ExtractPublicPropTypes<typeof tableHeaderProps>;\n\nexport default defineComponent({\n name: 'VCTableHeader',\n inheritAttrs: false,\n props: tableHeaderProps,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableHeader',\n useThemeProps(props),\n tableHeaderThemeDefaults,\n );\n return () => h(\n 'thead',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n slots.default?.(),\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { defineComponent, h, mergeProps } from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport type { TableHeaderThemeClasses } from '../types';\n\nconst tableHeaderThemeDefaults = { classes: { root: 'vc-table-header' } };\n\nconst tableHeaderProps = { ...themableProps<TableHeaderThemeClasses>() };\n\nexport type TableHeaderProps = ExtractPublicPropTypes<typeof tableHeaderProps>;\n\nexport default defineComponent({\n name: 'VCTableHeader',\n inheritAttrs: false,\n props: tableHeaderProps,\n setup(props, { attrs, slots }) {\n const theme = useComponentTheme(\n 'tableHeader',\n useThemeProps(props),\n tableHeaderThemeDefaults,\n );\n return () => h(\n 'thead',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n slots.default?.(),\n );\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n nextTick,\n onBeforeUnmount,\n toRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType } from 'vue';\nimport {\n isObject,\n themableProps,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { provideTableRowContext, useTable } from '../composables/context';\nimport type { RowSelectionKey } from '../composables/selection';\nimport type { TableRowThemeClasses } from '../types';\nimport { filterRowClickEvent } from '../utils/render-utils';\n\nconst tableRowThemeDefaults = { classes: { root: 'vc-table-row' } };\n\nconst tableRowProps = {\n /** Current row data — used to resolve `_rowVariant` / `_cellVariants` and to emit `@row-click`. */\n row: { type: null as unknown as PropType<unknown>, default: undefined },\n /** Row index — used by row keyboard navigation + focused-row tracking. */\n index: { type: Number, default: undefined },\n /** Mark the row disabled — forwarded to `themeVariant.disabled`. */\n disabled: { type: Boolean, default: undefined },\n /**\n * Manual override for the row's selected state. When set, wins over\n * the auto-resolved selection from `useTable().selection`. Leave\n * undefined to let `<VCTable :selection>` drive selection state.\n */\n selected: { type: Boolean, default: undefined },\n ...themableProps<TableRowThemeClasses>(),\n};\n\nexport type TableRowProps = ExtractPublicPropTypes<typeof tableRowProps>;\n\nexport default defineComponent({\n name: 'VCTableRow',\n inheritAttrs: false,\n props: tableRowProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n\n // Resolve row-meta variants from the row payload.\n const rowVariant = computed<string | null>(() => {\n if (!isObject(props.row)) return null;\n const v = (props.row as Record<string, unknown>)._rowVariant;\n return typeof v === 'string' ? v : null;\n });\n const cellVariants = computed<Record<string, string>>(() => {\n if (!isObject(props.row)) return {};\n const v = (props.row as Record<string, unknown>)._cellVariants;\n return isObject(v) ? (v as Record<string, string>) : {};\n });\n const focused = computed(() => {\n if (props.index === undefined) return false;\n return ctx?.focusedRow.value === props.index;\n });\n\n // Selection (plan 033 v1.x-A). When the parent table has a\n // selection mode set, derive `selected` from the selection\n // state. Manual `:selected` on the row wins for declarative\n // marking (the v0.1 escape hatch).\n const selectionKey = computed<RowSelectionKey>(() => {\n if (props.index === undefined) return -1;\n return ctx?.getRowKey(props.row, props.index) ?? props.index;\n });\n const selectionMode = computed(() => ctx?.selection.mode.value);\n const autoSelected = computed<boolean>(() => {\n if (props.selected !== undefined) return props.selected;\n // Short-circuit when this row has no index — the selection\n // key falls back to `-1`, which could phantom-match if a\n // consumer's selection array literally contains `-1`.\n if (props.index === undefined) return false;\n return ctx?.selection.isSelected(selectionKey.value) ?? false;\n });\n\n // Theme — fold row-meta variant + per-row flags into themeVariant\n const themeProps = useThemeProps(props, 'disabled');\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n ...(rowVariant.value ? { rowVariant: rowVariant.value } : {}),\n focused: focused.value,\n selected: autoSelected.value,\n };\n },\n };\n const theme = useComponentTheme('tableRow', mergedThemeProps, tableRowThemeDefaults);\n\n // Provide row context for child cells (needed for cellVariants resolution).\n if (props.index !== undefined) {\n provideTableRowContext({\n row: toRef(props, 'row'),\n index: toRef(props, 'index') as unknown as import('vue').Ref<number>,\n rowVariant,\n cellVariants,\n focused,\n selectionKey,\n selected: autoSelected,\n });\n }\n\n // Row interactivity gating. Selection mode enables row-level\n // keyboard nav even without `:row-clickable` (per the v1.x-A\n // ARIA grid pattern). The two opt-ins compose: a selectable\n // row IS focusable; a `:row-clickable` row also emits the\n // public `@row-click` event.\n const selectionActive = computed(() => selectionMode.value !== undefined);\n const isInteractive = computed(() => (\n (ctx?.rowClickable.value || selectionActive.value) &&\n props.index !== undefined &&\n !props.disabled\n ));\n\n // Register with the table's interactive-row registry so the\n // roving-tabindex fallback can pick the first INTERACTIVE row\n // (not just row 0, which might be disabled) and arrow nav can\n // skip non-interactive rows. Wired via `watch` (not\n // `watchEffect`) so the registry mutations don't recursively\n // re-trigger this effect — the watcher reads `isInteractive`\n // + `props.index` explicitly and only re-fires when those\n // values change.\n watch(\n [isInteractive, () => props.index],\n ([active, idx], [, prevIdx]) => {\n if (!ctx) return;\n // Unregister the previous index whenever it changes\n // (rare, but covers re-keyed rows).\n if (prevIdx !== undefined && prevIdx !== idx) {\n ctx.unregisterInteractiveRow(prevIdx);\n }\n if (active && idx !== undefined) {\n ctx.registerInteractiveRow(idx);\n } else if (idx !== undefined) {\n ctx.unregisterInteractiveRow(idx);\n }\n },\n { immediate: true },\n );\n onBeforeUnmount(() => {\n if (ctx && props.index !== undefined) {\n ctx.unregisterInteractiveRow(props.index);\n }\n });\n\n // Roving tabindex when grid-mode is active: only the focused\n // row carries tabindex=0; others get -1, so Tab exits the grid\n // instead of cycling row-by-row (W3C grid pattern). Outside\n // selection mode, every clickable row stays tabindex=0 — the\n // v0.1 behavior.\n const tabindex = computed<number | undefined>(() => {\n if (!isInteractive.value) return undefined;\n if (!selectionActive.value) return 0;\n // Grid mode: roving tabindex. Fall back to the FIRST\n // interactive row (read from the registry) when\n // `focusedRow` is unset OR points at a row that is no\n // longer interactive (e.g. disabled now, or data shrunk\n // past it). Picking the first interactive row — not\n // blindly row 0 — keeps Tab navigation working when row 0\n // happens to be disabled.\n const focusIdx = ctx?.focusedRow.value;\n const interactives = ctx?.interactiveRows.value;\n const focusActive = focusIdx !== null &&\n focusIdx !== undefined &&\n interactives !== undefined &&\n interactives.has(focusIdx);\n if (focusActive) {\n return props.index === focusIdx ? 0 : -1;\n }\n if (!interactives || interactives.size === 0) return -1;\n let firstInteractive: number | null = null;\n for (const idx of interactives) {\n if (firstInteractive === null || idx < firstInteractive) firstInteractive = idx;\n }\n return props.index === firstInteractive ? 0 : -1;\n });\n\n function activateSelection(event: globalThis.MouseEvent | globalThis.KeyboardEvent) {\n if (!selectionActive.value || props.index === undefined) return;\n ctx?.selection.toggle(selectionKey.value, {\n range: event.shiftKey,\n toggle: event.metaKey || event.ctrlKey,\n });\n ctx?.setFocusedRow(props.index);\n }\n\n function onClick(event: globalThis.MouseEvent) {\n if (!isInteractive.value) return;\n const rowEl = event.currentTarget as globalThis.Element | null;\n if (filterRowClickEvent(event, rowEl)) return;\n if (props.index === undefined) return;\n ctx?.setFocusedRow(props.index);\n activateSelection(event);\n if (ctx?.rowClickable.value) {\n ctx?.emitRowClick(props.row, props.index, event);\n }\n }\n\n function onKeydown(event: globalThis.KeyboardEvent) {\n if (!isInteractive.value || props.index === undefined) return;\n const i = props.index;\n\n // Build a sorted snapshot of currently interactive row\n // indices. Arrow / Home / End walk THIS list rather than\n // the raw data range, so disabled rows are skipped instead\n // of becoming dead spots in keyboard navigation.\n const interactives = ctx?.interactiveRows.value;\n const sorted = interactives && interactives.size > 0 ?\n Array.from(interactives).sort((a, b) => a - b) :\n [];\n const posInSorted = sorted.indexOf(i);\n\n const moveTo = (target: number) => {\n event.preventDefault();\n if (sorted.length === 0) return;\n const clamped = Math.max(0, Math.min(sorted.length - 1, target));\n const nextIdx = sorted[clamped];\n ctx?.setFocusedRow(nextIdx);\n const tr = event.currentTarget as globalThis.HTMLElement | null;\n if (!tr) return;\n // Defer the DOM .focus() until after Vue re-renders\n // with the updated tabindex. The roving-tabindex\n // pattern only ever has ONE row carrying `tabindex=\"0\"`\n // at a time; walking siblings before the re-render\n // would never find the new target (all other rows\n // still carry `tabindex=\"-1\"`). After the tick, only\n // the new target row carries `tabindex=\"0\"`, so the\n // walker latches on it cleanly and disabled rows\n // (carrying `tabindex=\"-1\"`) are correctly skipped.\n nextTick(() => {\n const direction = nextIdx > i ? 'nextElementSibling' : 'previousElementSibling';\n let sibling: globalThis.Element | null = tr[direction];\n while (sibling) {\n if (\n sibling instanceof globalThis.HTMLElement &&\n sibling.tagName === 'TR' &&\n sibling.getAttribute('tabindex') === '0'\n ) {\n sibling.focus();\n break;\n }\n sibling = sibling[direction];\n }\n });\n // Shift+arrow extends selection from the range anchor\n // to the new focused row (multi mode only). Seed the\n // anchor to the CURRENT row when none exists yet, so\n // the first Shift+arrow press includes the starting\n // row in the range.\n if (event.shiftKey && selectionActive.value && selectionMode.value === 'multi' && ctx) {\n if (ctx.selection.rangeAnchor.value === null) {\n const currentRow = ctx.data.value[i];\n if (currentRow !== undefined) {\n ctx.selection.rangeAnchor.value = ctx.getRowKey(currentRow, i);\n }\n }\n const targetRow = ctx.data.value[nextIdx];\n if (targetRow !== undefined) {\n const targetKey = ctx.getRowKey(targetRow, nextIdx);\n ctx.selection.toggle(targetKey, { range: true });\n }\n }\n };\n\n if (event.key === 'ArrowDown') {\n moveTo(posInSorted + 1);\n } else if (event.key === 'ArrowUp') {\n moveTo(posInSorted - 1);\n } else if (event.key === 'Home') {\n moveTo(0);\n } else if (event.key === 'End') {\n moveTo(sorted.length - 1);\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n activateSelection(event);\n if (ctx?.rowClickable.value) {\n ctx?.emitRowClick(props.row, i, event);\n }\n }\n }\n\n function onFocus() {\n if (!isInteractive.value || props.index === undefined) return;\n ctx?.setFocusedRow(props.index);\n }\n\n return () => {\n // Conditional ARIA spread — only paint role/aria-selected\n // when selection is active. Painting `role: undefined`\n // shadows consumer-provided attrs through mergeProps and\n // breaks the plain-table escape hatch for manual rows.\n const selectionAttrs: Record<string, unknown> = selectionActive.value ?\n {\n role: 'row',\n 'aria-selected': autoSelected.value ? 'true' : 'false',\n } :\n {};\n return h(\n 'tr',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n tabindex: tabindex.value,\n 'data-row-variant': rowVariant.value || undefined,\n ...selectionAttrs,\n onClick: isInteractive.value ? onClick : undefined,\n onKeydown: isInteractive.value ? onKeydown : undefined,\n onFocus: isInteractive.value ? onFocus : undefined,\n }),\n slots.default?.(),\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n nextTick,\n onBeforeUnmount,\n toRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType } from 'vue';\nimport {\n isObject,\n themableProps,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { provideTableRowContext, useTable } from '../composables/context';\nimport type { RowSelectionKey } from '../composables/selection';\nimport type { TableRowThemeClasses } from '../types';\nimport { filterRowClickEvent } from '../utils/render-utils';\n\nconst tableRowThemeDefaults = { classes: { root: 'vc-table-row' } };\n\nconst tableRowProps = {\n /** Current row data — used to resolve `_rowVariant` / `_cellVariants` and to emit `@row-click`. */\n row: { type: null as unknown as PropType<unknown>, default: undefined },\n /** Row index — used by row keyboard navigation + focused-row tracking. */\n index: { type: Number, default: undefined },\n /** Mark the row disabled — forwarded to `themeVariant.disabled`. */\n disabled: { type: Boolean, default: undefined },\n /**\n * Manual override for the row's selected state. When set, wins over\n * the auto-resolved selection from `useTable().selection`. Leave\n * undefined to let `<VCTable :selection>` drive selection state.\n */\n selected: { type: Boolean, default: undefined },\n ...themableProps<TableRowThemeClasses>(),\n};\n\nexport type TableRowProps = ExtractPublicPropTypes<typeof tableRowProps>;\n\nexport default defineComponent({\n name: 'VCTableRow',\n inheritAttrs: false,\n props: tableRowProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n\n // Resolve row-meta variants from the row payload.\n const rowVariant = computed<string | null>(() => {\n if (!isObject(props.row)) return null;\n const v = (props.row as Record<string, unknown>)._rowVariant;\n return typeof v === 'string' ? v : null;\n });\n const cellVariants = computed<Record<string, string>>(() => {\n if (!isObject(props.row)) return {};\n const v = (props.row as Record<string, unknown>)._cellVariants;\n return isObject(v) ? (v as Record<string, string>) : {};\n });\n const focused = computed(() => {\n if (props.index === undefined) return false;\n return ctx?.focusedRow.value === props.index;\n });\n\n // Selection (plan 033 v1.x-A). When the parent table has a\n // selection mode set, derive `selected` from the selection\n // state. Manual `:selected` on the row wins for declarative\n // marking (the v0.1 escape hatch).\n const selectionKey = computed<RowSelectionKey>(() => {\n if (props.index === undefined) return -1;\n return ctx?.getRowKey(props.row, props.index) ?? props.index;\n });\n const selectionMode = computed(() => ctx?.selection.mode.value);\n const autoSelected = computed<boolean>(() => {\n if (props.selected !== undefined) return props.selected;\n // Short-circuit when this row has no index — the selection\n // key falls back to `-1`, which could phantom-match if a\n // consumer's selection array literally contains `-1`.\n if (props.index === undefined) return false;\n return ctx?.selection.isSelected(selectionKey.value) ?? false;\n });\n\n // Theme — fold row-meta variant + per-row flags into themeVariant\n const themeProps = useThemeProps(props, 'disabled');\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n ...(rowVariant.value ? { rowVariant: rowVariant.value } : {}),\n focused: focused.value,\n selected: autoSelected.value,\n };\n },\n };\n const theme = useComponentTheme('tableRow', mergedThemeProps, tableRowThemeDefaults);\n\n // Provide row context for child cells (needed for cellVariants resolution).\n if (props.index !== undefined) {\n provideTableRowContext({\n row: toRef(props, 'row'),\n index: toRef(props, 'index') as unknown as import('vue').Ref<number>,\n rowVariant,\n cellVariants,\n focused,\n selectionKey,\n selected: autoSelected,\n });\n }\n\n // Row interactivity gating. Selection mode enables row-level\n // keyboard nav even without `:row-clickable` (per the v1.x-A\n // ARIA grid pattern). The two opt-ins compose: a selectable\n // row IS focusable; a `:row-clickable` row also emits the\n // public `@row-click` event.\n const selectionActive = computed(() => selectionMode.value !== undefined);\n const isInteractive = computed(() => (\n (ctx?.rowClickable.value || selectionActive.value) &&\n props.index !== undefined &&\n !props.disabled\n ));\n\n // Register with the table's interactive-row registry so the\n // roving-tabindex fallback can pick the first INTERACTIVE row\n // (not just row 0, which might be disabled) and arrow nav can\n // skip non-interactive rows. Wired via `watch` (not\n // `watchEffect`) so the registry mutations don't recursively\n // re-trigger this effect — the watcher reads `isInteractive`\n // + `props.index` explicitly and only re-fires when those\n // values change.\n watch(\n [isInteractive, () => props.index],\n ([active, idx], [, prevIdx]) => {\n if (!ctx) return;\n // Unregister the previous index whenever it changes\n // (rare, but covers re-keyed rows).\n if (prevIdx !== undefined && prevIdx !== idx) {\n ctx.unregisterInteractiveRow(prevIdx);\n }\n if (active && idx !== undefined) {\n ctx.registerInteractiveRow(idx);\n } else if (idx !== undefined) {\n ctx.unregisterInteractiveRow(idx);\n }\n },\n { immediate: true },\n );\n onBeforeUnmount(() => {\n if (ctx && props.index !== undefined) {\n ctx.unregisterInteractiveRow(props.index);\n }\n });\n\n // Roving tabindex when grid-mode is active: only the focused\n // row carries tabindex=0; others get -1, so Tab exits the grid\n // instead of cycling row-by-row (W3C grid pattern). Outside\n // selection mode, every clickable row stays tabindex=0 — the\n // v0.1 behavior.\n const tabindex = computed<number | undefined>(() => {\n if (!isInteractive.value) return undefined;\n if (!selectionActive.value) return 0;\n // Grid mode: roving tabindex. Fall back to the FIRST\n // interactive row (read from the registry) when\n // `focusedRow` is unset OR points at a row that is no\n // longer interactive (e.g. disabled now, or data shrunk\n // past it). Picking the first interactive row — not\n // blindly row 0 — keeps Tab navigation working when row 0\n // happens to be disabled.\n const focusIdx = ctx?.focusedRow.value;\n const interactives = ctx?.interactiveRows.value;\n const focusActive = focusIdx !== null &&\n focusIdx !== undefined &&\n interactives !== undefined &&\n interactives.has(focusIdx);\n if (focusActive) {\n return props.index === focusIdx ? 0 : -1;\n }\n if (!interactives || interactives.size === 0) return -1;\n let firstInteractive: number | null = null;\n for (const idx of interactives) {\n if (firstInteractive === null || idx < firstInteractive) firstInteractive = idx;\n }\n return props.index === firstInteractive ? 0 : -1;\n });\n\n function activateSelection(event: globalThis.MouseEvent | globalThis.KeyboardEvent) {\n if (!selectionActive.value || props.index === undefined) return;\n ctx?.selection.toggle(selectionKey.value, {\n range: event.shiftKey,\n toggle: event.metaKey || event.ctrlKey,\n });\n ctx?.setFocusedRow(props.index);\n }\n\n function onClick(event: globalThis.MouseEvent) {\n if (!isInteractive.value) return;\n const rowEl = event.currentTarget as globalThis.Element | null;\n if (filterRowClickEvent(event, rowEl)) return;\n if (props.index === undefined) return;\n ctx?.setFocusedRow(props.index);\n activateSelection(event);\n if (ctx?.rowClickable.value) {\n ctx?.emitRowClick(props.row, props.index, event);\n }\n }\n\n function onKeydown(event: globalThis.KeyboardEvent) {\n if (!isInteractive.value || props.index === undefined) return;\n const i = props.index;\n\n // Build a sorted snapshot of currently interactive row\n // indices. Arrow / Home / End walk THIS list rather than\n // the raw data range, so disabled rows are skipped instead\n // of becoming dead spots in keyboard navigation.\n const interactives = ctx?.interactiveRows.value;\n const sorted = interactives && interactives.size > 0 ?\n Array.from(interactives).sort((a, b) => a - b) :\n [];\n const posInSorted = sorted.indexOf(i);\n\n const moveTo = (target: number) => {\n event.preventDefault();\n if (sorted.length === 0) return;\n const clamped = Math.max(0, Math.min(sorted.length - 1, target));\n const nextIdx = sorted[clamped];\n ctx?.setFocusedRow(nextIdx);\n const tr = event.currentTarget as globalThis.HTMLElement | null;\n if (!tr) return;\n // Defer the DOM .focus() until after Vue re-renders\n // with the updated tabindex. The roving-tabindex\n // pattern only ever has ONE row carrying `tabindex=\"0\"`\n // at a time; walking siblings before the re-render\n // would never find the new target (all other rows\n // still carry `tabindex=\"-1\"`). After the tick, only\n // the new target row carries `tabindex=\"0\"`, so the\n // walker latches on it cleanly and disabled rows\n // (carrying `tabindex=\"-1\"`) are correctly skipped.\n nextTick(() => {\n const direction = nextIdx > i ? 'nextElementSibling' : 'previousElementSibling';\n let sibling: globalThis.Element | null = tr[direction];\n while (sibling) {\n if (\n sibling instanceof globalThis.HTMLElement &&\n sibling.tagName === 'TR' &&\n sibling.getAttribute('tabindex') === '0'\n ) {\n sibling.focus();\n break;\n }\n sibling = sibling[direction];\n }\n });\n // Shift+arrow extends selection from the range anchor\n // to the new focused row (multi mode only). Seed the\n // anchor to the CURRENT row when none exists yet, so\n // the first Shift+arrow press includes the starting\n // row in the range.\n if (event.shiftKey && selectionActive.value && selectionMode.value === 'multi' && ctx) {\n if (ctx.selection.rangeAnchor.value === null) {\n const currentRow = ctx.data.value[i];\n if (currentRow !== undefined) {\n ctx.selection.rangeAnchor.value = ctx.getRowKey(currentRow, i);\n }\n }\n const targetRow = ctx.data.value[nextIdx];\n if (targetRow !== undefined) {\n const targetKey = ctx.getRowKey(targetRow, nextIdx);\n ctx.selection.toggle(targetKey, { range: true });\n }\n }\n };\n\n if (event.key === 'ArrowDown') {\n moveTo(posInSorted + 1);\n } else if (event.key === 'ArrowUp') {\n moveTo(posInSorted - 1);\n } else if (event.key === 'Home') {\n moveTo(0);\n } else if (event.key === 'End') {\n moveTo(sorted.length - 1);\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n activateSelection(event);\n if (ctx?.rowClickable.value) {\n ctx?.emitRowClick(props.row, i, event);\n }\n }\n }\n\n function onFocus() {\n if (!isInteractive.value || props.index === undefined) return;\n ctx?.setFocusedRow(props.index);\n }\n\n return () => {\n // Conditional ARIA spread — only paint role/aria-selected\n // when selection is active. Painting `role: undefined`\n // shadows consumer-provided attrs through mergeProps and\n // breaks the plain-table escape hatch for manual rows.\n const selectionAttrs: Record<string, unknown> = selectionActive.value ?\n {\n role: 'row',\n 'aria-selected': autoSelected.value ? 'true' : 'false',\n } :\n {};\n return h(\n 'tr',\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n tabindex: tabindex.value,\n 'data-row-variant': rowVariant.value || undefined,\n ...selectionAttrs,\n onClick: isInteractive.value ? onClick : undefined,\n onKeydown: isInteractive.value ? onKeydown : undefined,\n onFocus: isInteractive.value ? onFocus : undefined,\n }),\n slots.default?.(),\n );\n };\n },\n});\n</script>\n","import { Fragment, h } from 'vue';\nimport type { VNode } from 'vue';\nimport VCTableBody from '../components/TableBody.vue';\nimport VCTableCell from '../components/TableCell.vue';\nimport VCTableFooter from '../components/TableFooter.vue';\nimport VCTableHeadCell from '../components/TableHeadCell.vue';\nimport VCTableHeader from '../components/TableHeader.vue';\nimport VCTableRow from '../components/TableRow.vue';\nimport type { TableColumn } from '../types';\n\n/**\n * Recursively check whether `nodes` (a slot return) contains a vnode\n * whose `type` equals `target`. Recurses into Vue `Fragment` vnodes so\n * `<template v-if>` / `<template v-for>` wrapping around a part\n * doesn't hide it from the auto-render check.\n *\n * Used by `<VCTable>` and `<VCTableLite>` to detect whether the\n * consumer wrote a manual `<VCTableHeader>` / `<VCTableBody>` in the\n * default slot — if not, and `:columns` is set, the table renders the\n * missing band itself.\n */\nexport function containsComponent(nodes: unknown, target: unknown): boolean {\n if (nodes == null || nodes === false) return false;\n if (Array.isArray(nodes)) {\n for (const child of nodes) {\n if (containsComponent(child, target)) return true;\n }\n return false;\n }\n if (typeof nodes !== 'object') return false;\n const v = nodes as VNode;\n if (v.type === target) return true;\n if (v.type === Fragment) return containsComponent(v.children, target);\n return false;\n}\n\n/**\n * Flatten a slot return into a single-level array, unwrapping\n * `Fragment` vnodes so partition logic operates on a flat sequence.\n * Fragments only serve as grouping markers and lose no DOM semantics\n * when flattened.\n */\nfunction flattenSlot(nodes: unknown): unknown[] {\n if (nodes == null || nodes === false) return [];\n if (Array.isArray(nodes)) return nodes.flatMap(flattenSlot);\n if (typeof nodes !== 'object') return [nodes];\n const v = nodes as VNode;\n if (v.type === Fragment) return flattenSlot(v.children);\n return [nodes];\n}\n\n/**\n * Partition slot children into vnodes that should render BEFORE the\n * auto-body and vnodes that should render AFTER it. Body precedence\n * rules:\n *\n * <thead> ← always first\n * <tbody> ← auto-rendered band\n * <VCTableEmpty> ← own <tbody>, gated on empty data\n * <VCTableLoading> ← own <tbody>, gated on busy\n * <tfoot> ← must come last (HTML5 says SHOULD; matches\n * browser visual placement so the source order\n * lines up with the rendered order)\n *\n * Only `<VCTableFooter>` is partitioned to \"after\"; everything else\n * keeps source order in \"before\".\n */\nfunction partitionBeforeAfterBody(nodes: unknown): { before: unknown[]; after: unknown[] } {\n const flat = flattenSlot(nodes);\n const before: unknown[] = [];\n const after: unknown[] = [];\n for (const n of flat) {\n if (n && typeof n === 'object' && (n as VNode).type === VCTableFooter) {\n after.push(n);\n } else {\n before.push(n);\n }\n }\n return {\n before,\n after,\n };\n}\n\n/**\n * Compose the inner children of a `<table>` for the driver auto-render\n * path (plan 033 v0.2-B). Returns the array of vnodes in the order\n * the table should render them:\n *\n * caption? · colgroup? · autoHeader? · slotChildren · autoBody?\n *\n * Header / body auto-render fires when `columns.length > 0` AND the\n * matching part isn't already present in `slotChildren` (Fragment-\n * aware via `containsComponent`).\n */\nexport function composeTableInner(opts: {\n cols: TableColumn<unknown>[];\n slotChildren: unknown;\n captionSlot?: (() => unknown) | undefined;\n colgroupSlot?: (() => unknown) | undefined;\n}): unknown[] {\n const {\n cols, \n slotChildren, \n captionSlot, \n colgroupSlot,\n } = opts;\n\n const inner: unknown[] = [];\n if (captionSlot) inner.push(h('caption', null, captionSlot() as never));\n if (colgroupSlot) inner.push(h('colgroup', null, colgroupSlot() as never));\n\n const autoRender = cols.length > 0;\n const hasHeader = autoRender && containsComponent(slotChildren, VCTableHeader);\n const hasBody = autoRender && containsComponent(slotChildren, VCTableBody);\n\n if (autoRender && !hasHeader) {\n inner.push(h(VCTableHeader, null, () => h(VCTableRow, null, () => cols.map((col) => h(\n VCTableHeadCell,\n {\n key: col.key,\n columnKey: col.key,\n sortable: col.sortable,\n stickyColumn: col.stickyColumn,\n title: col.headerTitle,\n abbr: col.headerAbbr,\n // `column.class` applies to BOTH <th> and <td>; `headerClass`\n // is the header-only additive. Vue normalizes the array.\n class: [col.class, col.headerClass],\n },\n () => col.label,\n )))));\n }\n\n // Partition slot children so `<VCTableFooter>` always lands AFTER\n // the auto-body. Without this, the common terse form\n // `<VCTable :columns :data><VCTableFooter>…</VCTableFooter></VCTable>`\n // would source-order as `thead → tfoot → tbody`, which violates\n // the HTML5 SHOULD-be-last rule for `<tfoot>` and de-syncs source\n // order from visual placement (browsers render `<tfoot>` last\n // anyway). Everything else (`<VCTableEmpty>`, `<VCTableLoading>`,\n // ad-hoc consumer nodes) keeps source order in `before`.\n const { before, after } = partitionBeforeAfterBody(slotChildren);\n if (before.length > 0) inner.push(before);\n\n if (autoRender && !hasBody) {\n inner.push(h(VCTableBody, null, {\n row: ({ row, index }: { row: unknown; index: number }) => h(\n VCTableRow,\n { row, index },\n () => cols.map((col) => h(VCTableCell, {\n key: col.key,\n columnKey: col.key,\n isRowHeader: col.isRowHeader,\n stickyColumn: col.stickyColumn,\n dataLabel: col.label,\n class: [col.class, col.cellClass],\n })),\n ),\n }));\n }\n\n if (after.length > 0) inner.push(after);\n\n return inner;\n}\n","import type {\n SortDescriptor,\n SortDirection,\n TableColumn,\n} from '../types';\nimport { resolveCellValue } from './render-utils';\n\nexport type SortRowsOptions<Row = unknown> = {\n columns: ReadonlyArray<TableColumn<Row>>;\n sorts: ReadonlyArray<SortDescriptor>;\n};\n\n/**\n * Client-side row sort (plan 033 v1.x-B).\n *\n * Returns a new array — the input is untouched. Honors:\n *\n * - **Sort key**: `column.sortByFormatted` → use `formatter` output;\n * else → use `accessor` resolved value (default, matches v0.1\n * `resolveCellValue`).\n * - **Comparator**: `column.sortFn(a, b) => number` when present;\n * else a built-in compare that handles numbers, Dates, booleans,\n * and uses `localeCompare` (with `numeric: true`) for everything\n * else — so `'item 2'` sorts before `'item 10'`.\n * - **Null handling**: `null` / `undefined` sort LAST regardless of\n * direction. Per-column `nullsFirst: true` floats them to the top.\n * - **Multi-key tie-break**: descriptors are applied in order. The\n * first non-zero comparison wins.\n * - **Stability**: relies on `Array.prototype.sort`'s stable\n * guarantee (ES2019+, every supported runtime).\n *\n * Empty `sorts` returns a shallow copy — never the input reference\n * itself, so callers can safely mutate the result.\n */\nexport function sortRows<Row>(\n rows: ReadonlyArray<Row>,\n options: SortRowsOptions<Row>,\n): Row[] {\n if (options.sorts.length === 0) return rows.slice();\n const columnByKey = new Map<string, TableColumn<Row>>();\n for (const col of options.columns) columnByKey.set(col.key, col);\n\n return rows.slice().sort((a, b) => {\n for (const sort of options.sorts) {\n const column = columnByKey.get(sort.key);\n if (!column) continue;\n const cmp = compareWithColumn(a, b, column, sort.direction);\n if (cmp !== 0) return cmp;\n }\n return 0;\n });\n}\n\nfunction compareWithColumn<Row>(\n a: Row,\n b: Row,\n column: TableColumn<Row>,\n direction: SortDirection,\n): number {\n const av = resolveSortValue(column, a);\n const bv = resolveSortValue(column, b);\n\n // Null handling — always before the comparator runs. `nullsFirst`\n // is per-column; default is \"nulls last regardless of direction\".\n const aMissing = av === null || av === undefined;\n const bMissing = bv === null || bv === undefined;\n if (aMissing && bMissing) return 0;\n if (aMissing) return column.nullsFirst ? -1 : 1;\n if (bMissing) return column.nullsFirst ? 1 : -1;\n\n const cmp = column.sortFn ?\n column.sortFn(av, bv) :\n defaultCompare(av, bv);\n return direction === 'asc' ? cmp : -cmp;\n}\n\nfunction resolveSortValue<Row>(column: TableColumn<Row>, row: Row): unknown {\n const value = resolveCellValue(column, row);\n if (!column.sortByFormatted || !column.formatter) return value;\n return column.formatter({\n value,\n key: column.key,\n row,\n });\n}\n\n/**\n * Default comparator. Locale-aware for strings, numeric for numbers,\n * chronological for Dates. Falls back to coerced-string compare so\n * mixed-type columns don't throw.\n */\nfunction defaultCompare(a: unknown, b: unknown): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n if (a === b) return 0;\n return a ? 1 : -1;\n }\n const as = typeof a === 'string' ? a : String(a);\n const bs = typeof b === 'string' ? b : String(b);\n return as.localeCompare(bs, undefined, { numeric: true });\n}\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n ref,\n shallowRef,\n toRef,\n triggerRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport {\n provideHeadCellCountContext,\n provideTableContext,\n} from '../composables/context';\nimport { useRowSelectionMachine } from '../composables/selection';\nimport type {\n RowSelectionKey,\n RowSelectionMode,\n RowSelectionValue,\n} from '../composables/selection';\nimport { useSortMachine } from '../composables/sort';\nimport type {\n SortDirection,\n TableColumn,\n TableColumnRaw,\n TableSlotProps,\n TableSortState,\n TableThemeClasses,\n} from '../types';\nimport { composeTableInner } from '../utils/auto-render';\nimport { normalizeColumns } from '../utils/render-utils';\nimport { sortRows } from '../utils/sort-rows';\n\nconst tableThemeDefaults = {\n classes: {\n root: 'vc-table',\n scrollContainer: 'vc-table-scroll-container',\n },\n};\n\nconst tableProps = {\n /** Row data array. */\n data: { type: Array as PropType<unknown[]>, default: () => [] },\n /** Column definitions (TableColumn or bare-string shorthand). When omitted, columns are derived from `Object.keys(data[0])`. */\n columns: { type: Array as PropType<TableColumnRaw<unknown>[]>, default: undefined },\n /** Busy flag — drives `aria-busy` on the `<table>` and gates the loading-band render. */\n busy: { type: Boolean, default: false },\n /**\n * Controlled sort state as `SortDescriptor[]`. Use `v-model:sort`.\n * Empty array means \"no sort\". Since v1.x-B this is always an\n * array (BREAKING change from v0.1's `{ key, direction } | null`).\n * Single-column sort is just an array of length 0 or 1.\n */\n sort: { type: Array as PropType<TableSortState>, default: () => [] },\n /** When `true`, the cycle skips the `null` step: `null → asc → desc → asc`. */\n mustSort: { type: Boolean, default: false },\n /**\n * Enable multi-column sort. When `true`, Shift-click on a\n * sortable header adds it as a secondary descriptor (or cycles\n * its direction if already present). Plain click without Shift\n * replaces multi-sort with single-sort of the clicked column.\n * Default `false` — Shift-click behaves identically to plain\n * click and the sort array stays length 0–1.\n */\n multiSort: { type: Boolean, default: false },\n /**\n * Maximum number of sort keys retained when `:multi-sort` is on.\n * Adding a key past the cap drops the oldest descriptor. `0`\n * means unlimited. Default `3` (matches Excel / bvnext / TanStack\n * convention).\n */\n maxSortKeys: { type: Number, default: 3 },\n /**\n * When `true`, the table reorders `:data` internally using\n * `accessor` (or `formatter` output if `column.sortByFormatted`),\n * honoring `column.sortFn` / `nullsFirst` if set. `v-model:sort`\n * still emits intent so consumers stay observable. Default\n * `false` — v0.1 controlled-sort behaviour preserved.\n */\n clientSort: { type: Boolean, default: false },\n /** Wrap the `<table>` in an overflow scroll container. */\n scrollable: { type: Boolean, default: false },\n /** When `:scrollable`, sticks the `<thead>` to the top of the scroll container. */\n stickyHeader: { type: Boolean, default: false },\n /** When `:scrollable`, applied as `max-height` on the scroll container (any CSS length, e.g. `'24rem'`). */\n maxHeight: { type: String, default: undefined },\n /** Opt-in row-click affordance — adds `tabindex` + cursor-pointer on every row and emits `@row-click`. */\n rowClickable: { type: Boolean, default: false },\n /**\n * Row selection mode (plan 033 v1.x-A). When set, the table flips\n * to ARIA `role=\"grid\"` (+ `aria-multiselectable` for multi) and\n * rows render with `aria-selected`. `undefined` keeps the v0.1\n * plain-table semantics.\n */\n selectionMode: { type: String as PropType<RowSelectionMode>, default: undefined },\n /**\n * Controlled selection state. Use `v-model:selection`. Type is\n * `string|number` for single mode, `(string|number)[]` for multi.\n * `null` clears the selection.\n */\n selection: {\n type: [String, Number, Array, null] as PropType<RowSelectionValue<RowSelectionMode> | null>,\n default: null,\n },\n /**\n * Resolve a row's selection key. Defaults to `row.id` (falling\n * back to the row index when absent). Pass a function for richer\n * mappings (e.g. `(row) => row.uuid`).\n */\n getRowKey: {\n type: Function as PropType<(row: unknown, index: number) => RowSelectionKey>,\n default: undefined,\n },\n /**\n * Stacked responsive mode (v0.2-D). When `true`, sets\n * `data-responsive=\"true\"` on the `<table>` so the structural CSS\n * (and any theme-specific overrides) can collapse the table into\n * per-row cards at narrow viewports. Uses each cell's `data-label`\n * as the per-row column label.\n */\n responsive: { type: Boolean, default: false },\n /** Density shorthand for `themeVariant.density`. */\n density: { type: String as PropType<'compact' | 'normal' | 'spacious'>, default: undefined },\n /** Alternating row backgrounds — shorthand for `themeVariant.striped`. */\n striped: { type: Boolean, default: undefined },\n /** Cell borders — shorthand for `themeVariant.bordered`. */\n bordered: { type: Boolean, default: undefined },\n /** Row hover highlight — shorthand for `themeVariant.hover`. */\n hover: { type: Boolean, default: undefined },\n /** HTML tag to render. */\n tag: { type: String, default: 'table' },\n ...themableProps<TableThemeClasses>(),\n};\n\nexport type TableProps = ExtractPublicPropTypes<typeof tableProps>;\n\nexport default defineComponent({\n name: 'VCTable',\n inheritAttrs: false,\n props: tableProps,\n emits: ['update:sort', 'update:selection', 'row-click'],\n slots: Object as SlotsType<{\n default(props: TableSlotProps): unknown;\n caption(): unknown;\n colgroup(): unknown;\n }>,\n setup(props, {\n attrs, \n slots, \n emit, \n }) {\n const themeProps = useThemeProps(\n props,\n 'density',\n 'striped',\n 'bordered',\n 'hover',\n 'stickyHeader',\n );\n const theme = useComponentTheme('table', themeProps, tableThemeDefaults);\n\n const dataRef = toRef(props, 'data');\n const rawColumns = toRef(props, 'columns');\n const columns = computed<TableColumn<unknown>[]>(\n () => normalizeColumns(rawColumns.value, dataRef.value),\n );\n\n const sortSource = toRef(props, 'sort');\n const mustSortRef = toRef(props, 'mustSort');\n const maxSortKeysRef = toRef(props, 'maxSortKeys');\n const sortMachine = useSortMachine({\n source: sortSource,\n columns,\n mustSort: mustSortRef,\n maxSortKeys: maxSortKeysRef,\n emit: (next) => emit('update:sort', next),\n });\n\n // Client-side sort (plan 033 v1.x-B). When `:client-sort` is\n // set, the table reorders `:data` itself using the resolved\n // sort descriptors. Always emits `update:sort` so consumers\n // still observe the state changes.\n const visibleData = computed<unknown[]>(() => {\n if (!props.clientSort || sortMachine.state.value.length === 0) {\n return dataRef.value;\n }\n return sortRows(dataRef.value, {\n columns: columns.value,\n sorts: sortMachine.state.value,\n });\n });\n\n // D3 — Shape B colspan auto-counting from <VCTableHeadCell> siblings\n // that register via context. Shape A overrides via `columns.length`.\n const childCellCount = ref(0);\n provideHeadCellCountContext({\n register: () => { childCellCount.value += 1; },\n unregister: () => { childCellCount.value = Math.max(0, childCellCount.value - 1); },\n });\n const colspan = computed(() => {\n if (columns.value.length > 0) return columns.value.length;\n return Math.max(1, childCellCount.value);\n });\n watch(\n () => columns.value.length > 0,\n (hasColumns) => {\n if (hasColumns) childCellCount.value = 0;\n },\n );\n\n const focusedRow = ref<number | null>(null);\n const setFocusedRow = (index: number | null) => { focusedRow.value = index; };\n\n const emitRowClick = (row: unknown, index: number, event: Event) => {\n emit('row-click', row, index, event);\n };\n\n const wrapperEl = ref<globalThis.HTMLElement | null>(null);\n\n // Interactive-row registry. Each `<VCTableRow>` registers\n // itself when `isInteractive` flips on, unregisters when off.\n // Drives the roving-tabindex fallback (first-interactive gets\n // the tab stop, not blindly row 0) and the arrow-nav skip\n // semantics (next/prev interactive, not next/prev data index).\n // Set mutations aren't reactivity-tracked, so we hold the\n // Set in a shallow ref and call `triggerRef` after each\n // in-place `add`/`delete`. Previously the code allocated a\n // FRESH Set on every register/unregister — during mount of a\n // table with N interactive rows that was O(N²) allocations\n // (each new row copies the prior Set).\n const interactiveRows = shallowRef<Set<number>>(new Set());\n const registerInteractiveRow = (index: number) => {\n if (interactiveRows.value.has(index)) return;\n interactiveRows.value.add(index);\n triggerRef(interactiveRows);\n };\n const unregisterInteractiveRow = (index: number) => {\n if (!interactiveRows.value.has(index)) return;\n interactiveRows.value.delete(index);\n triggerRef(interactiveRows);\n };\n\n // Selection wiring (plan 033 v1.x-A). Always construct the\n // machine; when `selectionMode` is undefined it reports a\n // no-op (isSelected → false; toggle → no-op) so descendants\n // don't need to null-check before calling.\n const selectionMode = computed(() => props.selectionMode);\n const selectionValue = computed(() => props.selection);\n const getRowKey = (row: unknown, index: number): RowSelectionKey => {\n const custom = props.getRowKey;\n if (typeof custom === 'function') return custom(row, index);\n if (row && typeof row === 'object') {\n const { id } = (row as { id?: unknown });\n if (typeof id === 'string' || typeof id === 'number') return id;\n }\n return index;\n };\n const selection = useRowSelectionMachine({\n mode: selectionMode,\n value: selectionValue,\n emit: (next) => emit('update:selection', next),\n keyAt: (index) => {\n // Look up against the VISIBLE data view, not the raw\n // source — when `:client-sort` reorders rows, the\n // index seen in selection events matches the rendered\n // position, so range-select spans the rendered order.\n const view = visibleData.value;\n if (index < 0 || index >= view.length) return undefined;\n return getRowKey(view[index], index);\n },\n });\n\n provideTableContext({\n // When `:client-sort` is on, descendants see the sorted view\n // — `<VCTableBody>` iterates `ctx.data`, so threading the\n // sorted view here is what reorders rendered rows. When\n // off, this is the unsorted source array (v0.1 behaviour).\n data: visibleData,\n busy: toRef(props, 'busy'),\n columns,\n sort: sortMachine.state,\n setSort: (\n key: string,\n opts?: { append?: boolean; direction?: SortDirection },\n ) => sortMachine.setSort(key, {\n ...opts,\n // Shift-click only appends when `<VCTable :multi-sort>`\n // is on — otherwise the prop would be advisory only\n // and headers would always grow the array.\n append: props.multiSort ? opts?.append : false,\n }),\n setSortState: sortMachine.setState,\n maxSortKeys: maxSortKeysRef,\n supportsSortMutation: true,\n rowClickable: toRef(props, 'rowClickable'),\n focusedRow,\n setFocusedRow,\n selection,\n getRowKey,\n interactiveRows,\n registerInteractiveRow,\n unregisterInteractiveRow,\n colspan,\n emitRowClick,\n wrapperEl,\n });\n\n const slotProps = computed<TableSlotProps>(() => ({\n data: visibleData.value,\n busy: props.busy,\n columns: columns.value,\n sort: sortMachine.state.value,\n setSort: sortMachine.setSort,\n }));\n\n const setWrapperRef = (el: unknown) => {\n wrapperEl.value = (el as globalThis.HTMLElement | null) ?? null;\n };\n\n return () => {\n // Driver auto-render (plan 033 v0.2-B): when `:columns` is set\n // and the consumer's default slot doesn't already contain a\n // `<VCTableHeader>` / `<VCTableBody>`, render the missing\n // band(s) automatically. Consumer-provided slot content\n // (e.g. `<VCTableEmpty>`, `<VCTableLoading>`) flows as\n // siblings so the band-rendering precedence is unaffected.\n const inner = composeTableInner({\n cols: columns.value,\n slotChildren: slots.default?.(slotProps.value),\n captionSlot: slots.caption,\n colgroupSlot: slots.colgroup,\n });\n\n // `attrs` always forward to the `<table>` itself — consumers'\n // `:class` / `@click` / etc target the same element regardless\n // of whether `:scrollable` is set.\n const mode = selectionMode.value;\n // Build the merge props conditionally so a disabled\n // selection mode doesn't paint `role: undefined` /\n // `aria-multiselectable: undefined` over consumer-supplied\n // attribute fallthrough. `mergeProps` keeps explicit\n // `undefined` keys on the merged result, which would\n // shadow attrs.\n const selectionAttrs: Record<string, unknown> = mode === undefined ?\n {} :\n {\n role: 'grid',\n ...(mode === 'multi' ? { 'aria-multiselectable': 'true' } : {}),\n };\n const tableNode = h(\n props.tag,\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'aria-busy': props.busy ? 'true' : undefined,\n 'data-responsive': props.responsive ? 'true' : undefined,\n ...selectionAttrs,\n }),\n inner as never,\n );\n\n // Always wrap the `<table>` in a positioned wrapper. This is\n // the teleport target for `<VCTableLoading :overlay>` — a\n // `<div>` inside a `<table>` is foster-parented out by the\n // HTML parser, breaking the overlay; rendering it as a\n // sibling of the `<table>` (inside this wrapper) keeps the\n // overlay correctly sized against the table area.\n const wrapper = h(\n 'div',\n {\n ref: setWrapperRef,\n class: 'vc-table-wrapper',\n style: { position: 'relative' },\n },\n [tableNode],\n );\n\n if (!props.scrollable) return wrapper;\n\n return h(\n 'div',\n {\n class: theme.value.scrollContainer || undefined,\n style: props.maxHeight ?\n { maxHeight: props.maxHeight, overflow: 'auto' } :\n { overflow: 'auto' },\n },\n [wrapper],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n ref,\n shallowRef,\n toRef,\n triggerRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport {\n provideHeadCellCountContext,\n provideTableContext,\n} from '../composables/context';\nimport { useRowSelectionMachine } from '../composables/selection';\nimport type {\n RowSelectionKey,\n RowSelectionMode,\n RowSelectionValue,\n} from '../composables/selection';\nimport { useSortMachine } from '../composables/sort';\nimport type {\n SortDirection,\n TableColumn,\n TableColumnRaw,\n TableSlotProps,\n TableSortState,\n TableThemeClasses,\n} from '../types';\nimport { composeTableInner } from '../utils/auto-render';\nimport { normalizeColumns } from '../utils/render-utils';\nimport { sortRows } from '../utils/sort-rows';\n\nconst tableThemeDefaults = {\n classes: {\n root: 'vc-table',\n scrollContainer: 'vc-table-scroll-container',\n },\n};\n\nconst tableProps = {\n /** Row data array. */\n data: { type: Array as PropType<unknown[]>, default: () => [] },\n /** Column definitions (TableColumn or bare-string shorthand). When omitted, columns are derived from `Object.keys(data[0])`. */\n columns: { type: Array as PropType<TableColumnRaw<unknown>[]>, default: undefined },\n /** Busy flag — drives `aria-busy` on the `<table>` and gates the loading-band render. */\n busy: { type: Boolean, default: false },\n /**\n * Controlled sort state as `SortDescriptor[]`. Use `v-model:sort`.\n * Empty array means \"no sort\". Since v1.x-B this is always an\n * array (BREAKING change from v0.1's `{ key, direction } | null`).\n * Single-column sort is just an array of length 0 or 1.\n */\n sort: { type: Array as PropType<TableSortState>, default: () => [] },\n /** When `true`, the cycle skips the `null` step: `null → asc → desc → asc`. */\n mustSort: { type: Boolean, default: false },\n /**\n * Enable multi-column sort. When `true`, Shift-click on a\n * sortable header adds it as a secondary descriptor (or cycles\n * its direction if already present). Plain click without Shift\n * replaces multi-sort with single-sort of the clicked column.\n * Default `false` — Shift-click behaves identically to plain\n * click and the sort array stays length 0–1.\n */\n multiSort: { type: Boolean, default: false },\n /**\n * Maximum number of sort keys retained when `:multi-sort` is on.\n * Adding a key past the cap drops the oldest descriptor. `0`\n * means unlimited. Default `3` (matches Excel / bvnext / TanStack\n * convention).\n */\n maxSortKeys: { type: Number, default: 3 },\n /**\n * When `true`, the table reorders `:data` internally using\n * `accessor` (or `formatter` output if `column.sortByFormatted`),\n * honoring `column.sortFn` / `nullsFirst` if set. `v-model:sort`\n * still emits intent so consumers stay observable. Default\n * `false` — v0.1 controlled-sort behaviour preserved.\n */\n clientSort: { type: Boolean, default: false },\n /** Wrap the `<table>` in an overflow scroll container. */\n scrollable: { type: Boolean, default: false },\n /** When `:scrollable`, sticks the `<thead>` to the top of the scroll container. */\n stickyHeader: { type: Boolean, default: false },\n /** When `:scrollable`, applied as `max-height` on the scroll container (any CSS length, e.g. `'24rem'`). */\n maxHeight: { type: String, default: undefined },\n /** Opt-in row-click affordance — adds `tabindex` + cursor-pointer on every row and emits `@row-click`. */\n rowClickable: { type: Boolean, default: false },\n /**\n * Row selection mode (plan 033 v1.x-A). When set, the table flips\n * to ARIA `role=\"grid\"` (+ `aria-multiselectable` for multi) and\n * rows render with `aria-selected`. `undefined` keeps the v0.1\n * plain-table semantics.\n */\n selectionMode: { type: String as PropType<RowSelectionMode>, default: undefined },\n /**\n * Controlled selection state. Use `v-model:selection`. Type is\n * `string|number` for single mode, `(string|number)[]` for multi.\n * `null` clears the selection.\n */\n selection: {\n type: [String, Number, Array, null] as PropType<RowSelectionValue<RowSelectionMode> | null>,\n default: null,\n },\n /**\n * Resolve a row's selection key. Defaults to `row.id` (falling\n * back to the row index when absent). Pass a function for richer\n * mappings (e.g. `(row) => row.uuid`).\n */\n getRowKey: {\n type: Function as PropType<(row: unknown, index: number) => RowSelectionKey>,\n default: undefined,\n },\n /**\n * Stacked responsive mode (v0.2-D). When `true`, sets\n * `data-responsive=\"true\"` on the `<table>` so the structural CSS\n * (and any theme-specific overrides) can collapse the table into\n * per-row cards at narrow viewports. Uses each cell's `data-label`\n * as the per-row column label.\n */\n responsive: { type: Boolean, default: false },\n /** Density shorthand for `themeVariant.density`. */\n density: { type: String as PropType<'compact' | 'normal' | 'spacious'>, default: undefined },\n /** Alternating row backgrounds — shorthand for `themeVariant.striped`. */\n striped: { type: Boolean, default: undefined },\n /** Cell borders — shorthand for `themeVariant.bordered`. */\n bordered: { type: Boolean, default: undefined },\n /** Row hover highlight — shorthand for `themeVariant.hover`. */\n hover: { type: Boolean, default: undefined },\n /** HTML tag to render. */\n tag: { type: String, default: 'table' },\n ...themableProps<TableThemeClasses>(),\n};\n\nexport type TableProps = ExtractPublicPropTypes<typeof tableProps>;\n\nexport default defineComponent({\n name: 'VCTable',\n inheritAttrs: false,\n props: tableProps,\n emits: ['update:sort', 'update:selection', 'row-click'],\n slots: Object as SlotsType<{\n default(props: TableSlotProps): unknown;\n caption(): unknown;\n colgroup(): unknown;\n }>,\n setup(props, {\n attrs, \n slots, \n emit, \n }) {\n const themeProps = useThemeProps(\n props,\n 'density',\n 'striped',\n 'bordered',\n 'hover',\n 'stickyHeader',\n );\n const theme = useComponentTheme('table', themeProps, tableThemeDefaults);\n\n const dataRef = toRef(props, 'data');\n const rawColumns = toRef(props, 'columns');\n const columns = computed<TableColumn<unknown>[]>(\n () => normalizeColumns(rawColumns.value, dataRef.value),\n );\n\n const sortSource = toRef(props, 'sort');\n const mustSortRef = toRef(props, 'mustSort');\n const maxSortKeysRef = toRef(props, 'maxSortKeys');\n const sortMachine = useSortMachine({\n source: sortSource,\n columns,\n mustSort: mustSortRef,\n maxSortKeys: maxSortKeysRef,\n emit: (next) => emit('update:sort', next),\n });\n\n // Client-side sort (plan 033 v1.x-B). When `:client-sort` is\n // set, the table reorders `:data` itself using the resolved\n // sort descriptors. Always emits `update:sort` so consumers\n // still observe the state changes.\n const visibleData = computed<unknown[]>(() => {\n if (!props.clientSort || sortMachine.state.value.length === 0) {\n return dataRef.value;\n }\n return sortRows(dataRef.value, {\n columns: columns.value,\n sorts: sortMachine.state.value,\n });\n });\n\n // D3 — Shape B colspan auto-counting from <VCTableHeadCell> siblings\n // that register via context. Shape A overrides via `columns.length`.\n const childCellCount = ref(0);\n provideHeadCellCountContext({\n register: () => { childCellCount.value += 1; },\n unregister: () => { childCellCount.value = Math.max(0, childCellCount.value - 1); },\n });\n const colspan = computed(() => {\n if (columns.value.length > 0) return columns.value.length;\n return Math.max(1, childCellCount.value);\n });\n watch(\n () => columns.value.length > 0,\n (hasColumns) => {\n if (hasColumns) childCellCount.value = 0;\n },\n );\n\n const focusedRow = ref<number | null>(null);\n const setFocusedRow = (index: number | null) => { focusedRow.value = index; };\n\n const emitRowClick = (row: unknown, index: number, event: Event) => {\n emit('row-click', row, index, event);\n };\n\n const wrapperEl = ref<globalThis.HTMLElement | null>(null);\n\n // Interactive-row registry. Each `<VCTableRow>` registers\n // itself when `isInteractive` flips on, unregisters when off.\n // Drives the roving-tabindex fallback (first-interactive gets\n // the tab stop, not blindly row 0) and the arrow-nav skip\n // semantics (next/prev interactive, not next/prev data index).\n // Set mutations aren't reactivity-tracked, so we hold the\n // Set in a shallow ref and call `triggerRef` after each\n // in-place `add`/`delete`. Previously the code allocated a\n // FRESH Set on every register/unregister — during mount of a\n // table with N interactive rows that was O(N²) allocations\n // (each new row copies the prior Set).\n const interactiveRows = shallowRef<Set<number>>(new Set());\n const registerInteractiveRow = (index: number) => {\n if (interactiveRows.value.has(index)) return;\n interactiveRows.value.add(index);\n triggerRef(interactiveRows);\n };\n const unregisterInteractiveRow = (index: number) => {\n if (!interactiveRows.value.has(index)) return;\n interactiveRows.value.delete(index);\n triggerRef(interactiveRows);\n };\n\n // Selection wiring (plan 033 v1.x-A). Always construct the\n // machine; when `selectionMode` is undefined it reports a\n // no-op (isSelected → false; toggle → no-op) so descendants\n // don't need to null-check before calling.\n const selectionMode = computed(() => props.selectionMode);\n const selectionValue = computed(() => props.selection);\n const getRowKey = (row: unknown, index: number): RowSelectionKey => {\n const custom = props.getRowKey;\n if (typeof custom === 'function') return custom(row, index);\n if (row && typeof row === 'object') {\n const { id } = (row as { id?: unknown });\n if (typeof id === 'string' || typeof id === 'number') return id;\n }\n return index;\n };\n const selection = useRowSelectionMachine({\n mode: selectionMode,\n value: selectionValue,\n emit: (next) => emit('update:selection', next),\n keyAt: (index) => {\n // Look up against the VISIBLE data view, not the raw\n // source — when `:client-sort` reorders rows, the\n // index seen in selection events matches the rendered\n // position, so range-select spans the rendered order.\n const view = visibleData.value;\n if (index < 0 || index >= view.length) return undefined;\n return getRowKey(view[index], index);\n },\n });\n\n provideTableContext({\n // When `:client-sort` is on, descendants see the sorted view\n // — `<VCTableBody>` iterates `ctx.data`, so threading the\n // sorted view here is what reorders rendered rows. When\n // off, this is the unsorted source array (v0.1 behaviour).\n data: visibleData,\n busy: toRef(props, 'busy'),\n columns,\n sort: sortMachine.state,\n setSort: (\n key: string,\n opts?: { append?: boolean; direction?: SortDirection },\n ) => sortMachine.setSort(key, {\n ...opts,\n // Shift-click only appends when `<VCTable :multi-sort>`\n // is on — otherwise the prop would be advisory only\n // and headers would always grow the array.\n append: props.multiSort ? opts?.append : false,\n }),\n setSortState: sortMachine.setState,\n maxSortKeys: maxSortKeysRef,\n supportsSortMutation: true,\n rowClickable: toRef(props, 'rowClickable'),\n focusedRow,\n setFocusedRow,\n selection,\n getRowKey,\n interactiveRows,\n registerInteractiveRow,\n unregisterInteractiveRow,\n colspan,\n emitRowClick,\n wrapperEl,\n });\n\n const slotProps = computed<TableSlotProps>(() => ({\n data: visibleData.value,\n busy: props.busy,\n columns: columns.value,\n sort: sortMachine.state.value,\n setSort: sortMachine.setSort,\n }));\n\n const setWrapperRef = (el: unknown) => {\n wrapperEl.value = (el as globalThis.HTMLElement | null) ?? null;\n };\n\n return () => {\n // Driver auto-render (plan 033 v0.2-B): when `:columns` is set\n // and the consumer's default slot doesn't already contain a\n // `<VCTableHeader>` / `<VCTableBody>`, render the missing\n // band(s) automatically. Consumer-provided slot content\n // (e.g. `<VCTableEmpty>`, `<VCTableLoading>`) flows as\n // siblings so the band-rendering precedence is unaffected.\n const inner = composeTableInner({\n cols: columns.value,\n slotChildren: slots.default?.(slotProps.value),\n captionSlot: slots.caption,\n colgroupSlot: slots.colgroup,\n });\n\n // `attrs` always forward to the `<table>` itself — consumers'\n // `:class` / `@click` / etc target the same element regardless\n // of whether `:scrollable` is set.\n const mode = selectionMode.value;\n // Build the merge props conditionally so a disabled\n // selection mode doesn't paint `role: undefined` /\n // `aria-multiselectable: undefined` over consumer-supplied\n // attribute fallthrough. `mergeProps` keeps explicit\n // `undefined` keys on the merged result, which would\n // shadow attrs.\n const selectionAttrs: Record<string, unknown> = mode === undefined ?\n {} :\n {\n role: 'grid',\n ...(mode === 'multi' ? { 'aria-multiselectable': 'true' } : {}),\n };\n const tableNode = h(\n props.tag,\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'aria-busy': props.busy ? 'true' : undefined,\n 'data-responsive': props.responsive ? 'true' : undefined,\n ...selectionAttrs,\n }),\n inner as never,\n );\n\n // Always wrap the `<table>` in a positioned wrapper. This is\n // the teleport target for `<VCTableLoading :overlay>` — a\n // `<div>` inside a `<table>` is foster-parented out by the\n // HTML parser, breaking the overlay; rendering it as a\n // sibling of the `<table>` (inside this wrapper) keeps the\n // overlay correctly sized against the table area.\n const wrapper = h(\n 'div',\n {\n ref: setWrapperRef,\n class: 'vc-table-wrapper',\n style: { position: 'relative' },\n },\n [tableNode],\n );\n\n if (!props.scrollable) return wrapper;\n\n return h(\n 'div',\n {\n class: theme.value.scrollContainer || undefined,\n style: props.maxHeight ?\n { maxHeight: props.maxHeight, overflow: 'auto' } :\n { overflow: 'auto' },\n },\n [wrapper],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n ref,\n toRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport {\n provideHeadCellCountContext,\n provideTableContext,\n} from '../composables/context';\nimport { useRowSelectionMachine } from '../composables/selection';\nimport type { RowSelectionKey } from '../composables/selection';\nimport type {\n TableColumn,\n TableColumnRaw,\n TableSlotProps,\n TableThemeClasses,\n} from '../types';\nimport { composeTableInner } from '../utils/auto-render';\nimport { normalizeColumns } from '../utils/render-utils';\n\nconst tableLiteThemeDefaults = {\n classes: {\n root: 'vc-table',\n scrollContainer: 'vc-table-scroll-container',\n },\n};\n\n/**\n * Slim sibling of `<VCTable>` — same columns driver + theme system +\n * auto-render, but with the sort + row-click + keyboard-nav machinery\n * stripped out (plan 033 v0.2-C). Consumers who want their own state\n * plumbing (e.g. tanstack-table on top) import this instead of the\n * full `<VCTable>`. Lite-only consumers tree-shake `useSortMachine`\n * out of their bundle.\n *\n * Provides the same `TableContext` shape so child components\n * (`<VCTableRow>`, `<VCTableHeadCell>`, …) work identically — the\n * sort / row-click hooks are wired to no-ops, so sortable headers and\n * `:row-clickable` rows visually behave as if the consumer hadn't\n * opted in.\n */\nconst tableLiteProps = {\n /** Row data array. */\n data: { type: Array as PropType<unknown[]>, default: () => [] },\n /** Column definitions (TableColumn or bare-string shorthand). When omitted, columns are derived from `Object.keys(data[0])`. */\n columns: { type: Array as PropType<TableColumnRaw<unknown>[]>, default: undefined },\n /** Busy flag — drives `aria-busy` on the `<table>` and gates the loading-band render. */\n busy: { type: Boolean, default: false },\n /** Wrap the `<table>` in an overflow scroll container. */\n scrollable: { type: Boolean, default: false },\n /** When `:scrollable`, sticks the `<thead>` to the top of the scroll container. */\n stickyHeader: { type: Boolean, default: false },\n /** When `:scrollable`, applied as `max-height` on the scroll container. */\n maxHeight: { type: String, default: undefined },\n /** Stacked responsive mode opt-in. Same shape as `<VCTable :responsive>`. */\n responsive: { type: Boolean, default: false },\n /** Density shorthand for `themeVariant.density`. */\n density: { type: String as PropType<'compact' | 'normal' | 'spacious'>, default: undefined },\n /** Alternating row backgrounds — shorthand for `themeVariant.striped`. */\n striped: { type: Boolean, default: undefined },\n /** Cell borders — shorthand for `themeVariant.bordered`. */\n bordered: { type: Boolean, default: undefined },\n /** Row hover highlight — shorthand for `themeVariant.hover`. */\n hover: { type: Boolean, default: undefined },\n /** HTML tag to render. */\n tag: { type: String, default: 'table' },\n ...themableProps<TableThemeClasses>(),\n};\n\nexport type TableLiteProps = ExtractPublicPropTypes<typeof tableLiteProps>;\n\n// Sort state is `SortDescriptor[]` since v1.x-B — empty array means\n// \"no sort\", which is the permanent state for Lite.\nconst NOOP_SORT_STATE = ref([]);\n\n// Lite-shared, perma-disabled selection mode + value refs. Module-level\n// singletons are safe here because the values are intentionally\n// read-only at the context contract level (selection is a no-op in\n// Lite). Sharing avoids allocating one ref pair per VCTableLite mount.\nconst NOOP_SELECTION_MODE = computed<undefined>(() => undefined);\nconst NOOP_SELECTION_VALUE = computed<null>(() => null);\n\nexport default defineComponent({\n name: 'VCTableLite',\n inheritAttrs: false,\n props: tableLiteProps,\n slots: Object as SlotsType<{\n default(props: TableSlotProps): unknown;\n caption(): unknown;\n colgroup(): unknown;\n }>,\n setup(props, { attrs, slots }) {\n const themeProps = useThemeProps(\n props,\n 'density',\n 'striped',\n 'bordered',\n 'hover',\n 'stickyHeader',\n );\n const theme = useComponentTheme('table', themeProps, tableLiteThemeDefaults);\n\n const dataRef = toRef(props, 'data');\n const rawColumns = toRef(props, 'columns');\n const columns = computed<TableColumn<unknown>[]>(\n () => normalizeColumns(rawColumns.value, dataRef.value),\n );\n\n // Same headcell-count provider as `<VCTable>` so Shape B\n // (`<VCTableHeader>` written manually) keeps auto-resolving\n // colspan for `<VCTableEmpty>` / `<VCTableLoading>`.\n const childCellCount = ref(0);\n provideHeadCellCountContext({\n register: () => { childCellCount.value += 1; },\n unregister: () => { childCellCount.value = Math.max(0, childCellCount.value - 1); },\n });\n const colspan = computed(() => {\n if (columns.value.length > 0) return columns.value.length;\n return Math.max(1, childCellCount.value);\n });\n watch(\n () => columns.value.length > 0,\n (hasColumns) => {\n if (hasColumns) childCellCount.value = 0;\n },\n );\n\n const wrapperEl = ref<globalThis.HTMLElement | null>(null);\n\n // Build a no-op selection machine. With mode permanently\n // undefined, `isSelected: () => false` and `toggle` is a\n // no-op — child rows behave as if the consumer hadn't opted\n // in to selection.\n const liteSelection = useRowSelectionMachine({\n mode: NOOP_SELECTION_MODE,\n value: NOOP_SELECTION_VALUE,\n emit: () => {},\n keyAt: () => undefined,\n });\n const liteGetRowKey = (row: unknown, index: number): RowSelectionKey => {\n if (row && typeof row === 'object') {\n const { id } = (row as { id?: unknown });\n if (typeof id === 'string' || typeof id === 'number') return id;\n }\n return index;\n };\n\n // No-op sort + row-click hooks. `<VCTableHeadCell :sortable>`\n // and `<VCTableRow>` read these from context; with rowClickable\n // permanently false and `sort` permanently null, the\n // descendants visually behave as if the consumer hadn't opted\n // in to either feature.\n provideTableContext({\n data: dataRef,\n busy: toRef(props, 'busy'),\n columns,\n sort: NOOP_SORT_STATE,\n setSort: () => {},\n setSortState: () => {},\n maxSortKeys: ref(0),\n supportsSortMutation: false,\n rowClickable: computed(() => false),\n focusedRow: ref(null),\n setFocusedRow: () => {},\n colspan,\n emitRowClick: () => {},\n wrapperEl,\n selection: liteSelection,\n getRowKey: liteGetRowKey,\n interactiveRows: ref(new Set()),\n registerInteractiveRow: () => {},\n unregisterInteractiveRow: () => {},\n });\n\n const slotProps = computed<TableSlotProps>(() => ({\n data: dataRef.value as unknown[],\n busy: props.busy,\n columns: columns.value,\n sort: NOOP_SORT_STATE.value,\n setSort: () => {},\n }));\n\n const setWrapperRef = (el: unknown) => {\n wrapperEl.value = (el as globalThis.HTMLElement | null) ?? null;\n };\n\n return () => {\n const inner = composeTableInner({\n cols: columns.value,\n slotChildren: slots.default?.(slotProps.value),\n captionSlot: slots.caption,\n colgroupSlot: slots.colgroup,\n });\n\n const tableNode = h(\n props.tag,\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'aria-busy': props.busy ? 'true' : undefined,\n 'data-responsive': props.responsive ? 'true' : undefined,\n }),\n inner as never,\n );\n\n const wrapper = h(\n 'div',\n {\n ref: setWrapperRef,\n class: 'vc-table-wrapper',\n style: { position: 'relative' },\n },\n [tableNode],\n );\n\n if (!props.scrollable) return wrapper;\n\n return h(\n 'div',\n {\n class: theme.value.scrollContainer || undefined,\n style: props.maxHeight ?\n { maxHeight: props.maxHeight, overflow: 'auto' } :\n { overflow: 'auto' },\n },\n [wrapper],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n ref,\n toRef,\n watch,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport { themableProps, useComponentTheme, useThemeProps } from '@vuecs/core';\nimport {\n provideHeadCellCountContext,\n provideTableContext,\n} from '../composables/context';\nimport { useRowSelectionMachine } from '../composables/selection';\nimport type { RowSelectionKey } from '../composables/selection';\nimport type {\n TableColumn,\n TableColumnRaw,\n TableSlotProps,\n TableThemeClasses,\n} from '../types';\nimport { composeTableInner } from '../utils/auto-render';\nimport { normalizeColumns } from '../utils/render-utils';\n\nconst tableLiteThemeDefaults = {\n classes: {\n root: 'vc-table',\n scrollContainer: 'vc-table-scroll-container',\n },\n};\n\n/**\n * Slim sibling of `<VCTable>` — same columns driver + theme system +\n * auto-render, but with the sort + row-click + keyboard-nav machinery\n * stripped out (plan 033 v0.2-C). Consumers who want their own state\n * plumbing (e.g. tanstack-table on top) import this instead of the\n * full `<VCTable>`. Lite-only consumers tree-shake `useSortMachine`\n * out of their bundle.\n *\n * Provides the same `TableContext` shape so child components\n * (`<VCTableRow>`, `<VCTableHeadCell>`, …) work identically — the\n * sort / row-click hooks are wired to no-ops, so sortable headers and\n * `:row-clickable` rows visually behave as if the consumer hadn't\n * opted in.\n */\nconst tableLiteProps = {\n /** Row data array. */\n data: { type: Array as PropType<unknown[]>, default: () => [] },\n /** Column definitions (TableColumn or bare-string shorthand). When omitted, columns are derived from `Object.keys(data[0])`. */\n columns: { type: Array as PropType<TableColumnRaw<unknown>[]>, default: undefined },\n /** Busy flag — drives `aria-busy` on the `<table>` and gates the loading-band render. */\n busy: { type: Boolean, default: false },\n /** Wrap the `<table>` in an overflow scroll container. */\n scrollable: { type: Boolean, default: false },\n /** When `:scrollable`, sticks the `<thead>` to the top of the scroll container. */\n stickyHeader: { type: Boolean, default: false },\n /** When `:scrollable`, applied as `max-height` on the scroll container. */\n maxHeight: { type: String, default: undefined },\n /** Stacked responsive mode opt-in. Same shape as `<VCTable :responsive>`. */\n responsive: { type: Boolean, default: false },\n /** Density shorthand for `themeVariant.density`. */\n density: { type: String as PropType<'compact' | 'normal' | 'spacious'>, default: undefined },\n /** Alternating row backgrounds — shorthand for `themeVariant.striped`. */\n striped: { type: Boolean, default: undefined },\n /** Cell borders — shorthand for `themeVariant.bordered`. */\n bordered: { type: Boolean, default: undefined },\n /** Row hover highlight — shorthand for `themeVariant.hover`. */\n hover: { type: Boolean, default: undefined },\n /** HTML tag to render. */\n tag: { type: String, default: 'table' },\n ...themableProps<TableThemeClasses>(),\n};\n\nexport type TableLiteProps = ExtractPublicPropTypes<typeof tableLiteProps>;\n\n// Sort state is `SortDescriptor[]` since v1.x-B — empty array means\n// \"no sort\", which is the permanent state for Lite.\nconst NOOP_SORT_STATE = ref([]);\n\n// Lite-shared, perma-disabled selection mode + value refs. Module-level\n// singletons are safe here because the values are intentionally\n// read-only at the context contract level (selection is a no-op in\n// Lite). Sharing avoids allocating one ref pair per VCTableLite mount.\nconst NOOP_SELECTION_MODE = computed<undefined>(() => undefined);\nconst NOOP_SELECTION_VALUE = computed<null>(() => null);\n\nexport default defineComponent({\n name: 'VCTableLite',\n inheritAttrs: false,\n props: tableLiteProps,\n slots: Object as SlotsType<{\n default(props: TableSlotProps): unknown;\n caption(): unknown;\n colgroup(): unknown;\n }>,\n setup(props, { attrs, slots }) {\n const themeProps = useThemeProps(\n props,\n 'density',\n 'striped',\n 'bordered',\n 'hover',\n 'stickyHeader',\n );\n const theme = useComponentTheme('table', themeProps, tableLiteThemeDefaults);\n\n const dataRef = toRef(props, 'data');\n const rawColumns = toRef(props, 'columns');\n const columns = computed<TableColumn<unknown>[]>(\n () => normalizeColumns(rawColumns.value, dataRef.value),\n );\n\n // Same headcell-count provider as `<VCTable>` so Shape B\n // (`<VCTableHeader>` written manually) keeps auto-resolving\n // colspan for `<VCTableEmpty>` / `<VCTableLoading>`.\n const childCellCount = ref(0);\n provideHeadCellCountContext({\n register: () => { childCellCount.value += 1; },\n unregister: () => { childCellCount.value = Math.max(0, childCellCount.value - 1); },\n });\n const colspan = computed(() => {\n if (columns.value.length > 0) return columns.value.length;\n return Math.max(1, childCellCount.value);\n });\n watch(\n () => columns.value.length > 0,\n (hasColumns) => {\n if (hasColumns) childCellCount.value = 0;\n },\n );\n\n const wrapperEl = ref<globalThis.HTMLElement | null>(null);\n\n // Build a no-op selection machine. With mode permanently\n // undefined, `isSelected: () => false` and `toggle` is a\n // no-op — child rows behave as if the consumer hadn't opted\n // in to selection.\n const liteSelection = useRowSelectionMachine({\n mode: NOOP_SELECTION_MODE,\n value: NOOP_SELECTION_VALUE,\n emit: () => {},\n keyAt: () => undefined,\n });\n const liteGetRowKey = (row: unknown, index: number): RowSelectionKey => {\n if (row && typeof row === 'object') {\n const { id } = (row as { id?: unknown });\n if (typeof id === 'string' || typeof id === 'number') return id;\n }\n return index;\n };\n\n // No-op sort + row-click hooks. `<VCTableHeadCell :sortable>`\n // and `<VCTableRow>` read these from context; with rowClickable\n // permanently false and `sort` permanently null, the\n // descendants visually behave as if the consumer hadn't opted\n // in to either feature.\n provideTableContext({\n data: dataRef,\n busy: toRef(props, 'busy'),\n columns,\n sort: NOOP_SORT_STATE,\n setSort: () => {},\n setSortState: () => {},\n maxSortKeys: ref(0),\n supportsSortMutation: false,\n rowClickable: computed(() => false),\n focusedRow: ref(null),\n setFocusedRow: () => {},\n colspan,\n emitRowClick: () => {},\n wrapperEl,\n selection: liteSelection,\n getRowKey: liteGetRowKey,\n interactiveRows: ref(new Set()),\n registerInteractiveRow: () => {},\n unregisterInteractiveRow: () => {},\n });\n\n const slotProps = computed<TableSlotProps>(() => ({\n data: dataRef.value as unknown[],\n busy: props.busy,\n columns: columns.value,\n sort: NOOP_SORT_STATE.value,\n setSort: () => {},\n }));\n\n const setWrapperRef = (el: unknown) => {\n wrapperEl.value = (el as globalThis.HTMLElement | null) ?? null;\n };\n\n return () => {\n const inner = composeTableInner({\n cols: columns.value,\n slotChildren: slots.default?.(slotProps.value),\n captionSlot: slots.caption,\n colgroupSlot: slots.colgroup,\n });\n\n const tableNode = h(\n props.tag,\n mergeProps(attrs, {\n class: theme.value.root || undefined,\n 'aria-busy': props.busy ? 'true' : undefined,\n 'data-responsive': props.responsive ? 'true' : undefined,\n }),\n inner as never,\n );\n\n const wrapper = h(\n 'div',\n {\n ref: setWrapperRef,\n class: 'vc-table-wrapper',\n style: { position: 'relative' },\n },\n [tableNode],\n );\n\n if (!props.scrollable) return wrapper;\n\n return h(\n 'div',\n {\n class: theme.value.scrollContainer || undefined,\n style: props.maxHeight ?\n { maxHeight: props.maxHeight, overflow: 'auto' } :\n { overflow: 'auto' },\n },\n [wrapper],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { \n computed, \n defineComponent, \n h, \n mergeProps, \n} from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableEmptyThemeClasses } from '../types';\n\nconst tableEmptyThemeDefaults = { classes: { root: 'vc-table-empty' } };\n\nconst behavioralDefaults = {\n content: 'No results.',\n filteredContent: 'No matches.',\n};\n\nconst tableEmptyProps = {\n /** Override the auto-derived `colspan`. When omitted, uses the table's resolved colspan. */\n colspan: { type: Number, default: undefined },\n /** Mark this as the empty-after-filter case (distinct copy / icon vs empty-no-data). */\n filtered: { type: Boolean, default: false },\n /** Override the rendered text. Falls back to global defaults / hardcoded. */\n content: { type: String, default: undefined },\n /** Override the rendered text for the filtered case. */\n filteredContent: { type: String, default: undefined },\n ...themableProps<TableEmptyThemeClasses>(),\n};\n\nexport type TableEmptyProps = ExtractPublicPropTypes<typeof tableEmptyProps>;\n\nexport default defineComponent({\n name: 'VCTableEmpty',\n inheritAttrs: false,\n props: tableEmptyProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableEmpty', props, behavioralDefaults);\n\n const themeProps = useThemeProps(props);\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n filtered: props.filtered,\n };\n },\n };\n const theme = useComponentTheme('tableEmpty', mergedThemeProps, tableEmptyThemeDefaults);\n\n const shouldRender = computed(() => {\n // Empty band renders only when there's no data AND we're not busy\n // (busy + no-data is the loading-band's first-load case).\n if (!ctx) return true;\n return ctx.data.value.length === 0 && !ctx.busy.value;\n });\n\n const resolvedColspan = computed(() => props.colspan ?? ctx?.colspan.value ?? 1);\n\n return () => {\n if (!shouldRender.value) return null;\n const cellContent = slots.default?.() ??\n (props.filtered ? defaults.value.filteredContent : defaults.value.content);\n // ARIA live-region attributes (`role`, `aria-live`) do NOT\n // belong on `<tbody>` — they override the native `rowgroup`\n // semantics and break table-structure recognition for\n // assistive tech. The live region lives inside the `<td>`\n // as a wrapper `<div>` instead, where it announces the\n // empty-state message without corrupting the table's\n // accessibility tree.\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n [\n h('tr', null, [\n h('td', { colspan: resolvedColspan.value }, [\n h('div', { role: 'status', 'aria-live': 'polite' }, cellContent as never),\n ]),\n ]),\n ],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport { \n computed, \n defineComponent, \n h, \n mergeProps, \n} from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableEmptyThemeClasses } from '../types';\n\nconst tableEmptyThemeDefaults = { classes: { root: 'vc-table-empty' } };\n\nconst behavioralDefaults = {\n content: 'No results.',\n filteredContent: 'No matches.',\n};\n\nconst tableEmptyProps = {\n /** Override the auto-derived `colspan`. When omitted, uses the table's resolved colspan. */\n colspan: { type: Number, default: undefined },\n /** Mark this as the empty-after-filter case (distinct copy / icon vs empty-no-data). */\n filtered: { type: Boolean, default: false },\n /** Override the rendered text. Falls back to global defaults / hardcoded. */\n content: { type: String, default: undefined },\n /** Override the rendered text for the filtered case. */\n filteredContent: { type: String, default: undefined },\n ...themableProps<TableEmptyThemeClasses>(),\n};\n\nexport type TableEmptyProps = ExtractPublicPropTypes<typeof tableEmptyProps>;\n\nexport default defineComponent({\n name: 'VCTableEmpty',\n inheritAttrs: false,\n props: tableEmptyProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableEmpty', props, behavioralDefaults);\n\n const themeProps = useThemeProps(props);\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n filtered: props.filtered,\n };\n },\n };\n const theme = useComponentTheme('tableEmpty', mergedThemeProps, tableEmptyThemeDefaults);\n\n const shouldRender = computed(() => {\n // Empty band renders only when there's no data AND we're not busy\n // (busy + no-data is the loading-band's first-load case).\n if (!ctx) return true;\n return ctx.data.value.length === 0 && !ctx.busy.value;\n });\n\n const resolvedColspan = computed(() => props.colspan ?? ctx?.colspan.value ?? 1);\n\n return () => {\n if (!shouldRender.value) return null;\n const cellContent = slots.default?.() ??\n (props.filtered ? defaults.value.filteredContent : defaults.value.content);\n // ARIA live-region attributes (`role`, `aria-live`) do NOT\n // belong on `<tbody>` — they override the native `rowgroup`\n // semantics and break table-structure recognition for\n // assistive tech. The live region lives inside the `<td>`\n // as a wrapper `<div>` instead, where it announces the\n // empty-state message without corrupting the table's\n // accessibility tree.\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n [\n h('tr', null, [\n h('td', { colspan: resolvedColspan.value }, [\n h('div', { role: 'status', 'aria-live': 'polite' }, cellContent as never),\n ]),\n ]),\n ],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n Teleport,\n computed,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableLoadingThemeClasses } from '../types';\n\nconst tableLoadingThemeDefaults = { classes: { root: 'vc-table-loading', overlay: 'vc-table-loading-overlay' } };\n\nconst behavioralDefaults = { content: 'Loading…' };\n\nconst tableLoadingProps = {\n /** Override the auto-derived `colspan` (default mode only — ignored in overlay mode). */\n colspan: { type: Number, default: undefined },\n /** Render as a positioned overlay on top of the existing `<tbody>` (refresh feedback). Default mode is a centered tbody/tr/td placeholder. */\n overlay: { type: Boolean, default: false },\n /** Override the rendered text. Falls back to global defaults. */\n content: { type: String, default: undefined },\n ...themableProps<TableLoadingThemeClasses>(),\n};\n\nexport type TableLoadingProps = ExtractPublicPropTypes<typeof tableLoadingProps>;\n\nexport default defineComponent({\n name: 'VCTableLoading',\n inheritAttrs: false,\n props: tableLoadingProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableLoading', props, behavioralDefaults);\n\n const themeProps = useThemeProps(props);\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n overlay: props.overlay,\n };\n },\n };\n const theme = useComponentTheme('tableLoading', mergedThemeProps, tableLoadingThemeDefaults);\n\n const shouldRender = computed(() => {\n if (!ctx) return true;\n const busy = ctx.busy.value;\n const hasData = ctx.data.value.length > 0;\n // Default mode: render on first load (busy + no data).\n // Overlay mode: render whenever busy (refresh-on-existing-data pattern).\n return props.overlay ? busy : busy && !hasData;\n });\n\n const resolvedColspan = computed(() => props.colspan ?? ctx?.colspan.value ?? 1);\n\n return () => {\n if (!shouldRender.value) return null;\n const cellContent = slots.default?.() ?? defaults.value.content;\n\n if (props.overlay) {\n // Teleport the overlay into `<VCTable>`'s positioned\n // wrapper. Rendering a `<div>` directly as a child of the\n // `<table>` is invalid HTML — the parser foster-parents\n // it OUT of the table, breaking the intended absolute\n // positioning. The wrapper is a sibling-of-`<table>`\n // `<div style=\"position:relative\">` provided by\n // `<VCTable>`. If we're rendered outside `<VCTable>` (no\n // ctx, no wrapper), fall back to rendering inline.\n const overlayNode = h(\n 'div',\n mergeProps(attrs, {\n class: [theme.value.root || undefined, theme.value.overlay || undefined],\n role: 'status',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n }),\n cellContent as never,\n );\n if (ctx?.wrapperEl.value) {\n return h(Teleport, { to: ctx.wrapperEl.value }, [overlayNode]);\n }\n return overlayNode;\n }\n\n // ARIA live-region attributes (`role`, `aria-live`,\n // `aria-busy`) do NOT belong on `<tbody>` — they override\n // the native `rowgroup` semantics and break table-structure\n // recognition for AT. Wrap the cell content in a `<div>`\n // that carries the live region instead.\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n [\n h('tr', null, [\n h('td', { colspan: resolvedColspan.value }, [\n h(\n 'div',\n {\n role: 'status',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n },\n cellContent as never,\n ),\n ]),\n ]),\n ],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n Teleport,\n computed,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type { ExtractPublicPropTypes } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type { TableLoadingThemeClasses } from '../types';\n\nconst tableLoadingThemeDefaults = { classes: { root: 'vc-table-loading', overlay: 'vc-table-loading-overlay' } };\n\nconst behavioralDefaults = { content: 'Loading…' };\n\nconst tableLoadingProps = {\n /** Override the auto-derived `colspan` (default mode only — ignored in overlay mode). */\n colspan: { type: Number, default: undefined },\n /** Render as a positioned overlay on top of the existing `<tbody>` (refresh feedback). Default mode is a centered tbody/tr/td placeholder. */\n overlay: { type: Boolean, default: false },\n /** Override the rendered text. Falls back to global defaults. */\n content: { type: String, default: undefined },\n ...themableProps<TableLoadingThemeClasses>(),\n};\n\nexport type TableLoadingProps = ExtractPublicPropTypes<typeof tableLoadingProps>;\n\nexport default defineComponent({\n name: 'VCTableLoading',\n inheritAttrs: false,\n props: tableLoadingProps,\n setup(props, { attrs, slots }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableLoading', props, behavioralDefaults);\n\n const themeProps = useThemeProps(props);\n const mergedThemeProps = {\n get themeClass() { return themeProps.themeClass; },\n get themeVariant() {\n return {\n ...(themeProps.themeVariant ?? {}),\n overlay: props.overlay,\n };\n },\n };\n const theme = useComponentTheme('tableLoading', mergedThemeProps, tableLoadingThemeDefaults);\n\n const shouldRender = computed(() => {\n if (!ctx) return true;\n const busy = ctx.busy.value;\n const hasData = ctx.data.value.length > 0;\n // Default mode: render on first load (busy + no data).\n // Overlay mode: render whenever busy (refresh-on-existing-data pattern).\n return props.overlay ? busy : busy && !hasData;\n });\n\n const resolvedColspan = computed(() => props.colspan ?? ctx?.colspan.value ?? 1);\n\n return () => {\n if (!shouldRender.value) return null;\n const cellContent = slots.default?.() ?? defaults.value.content;\n\n if (props.overlay) {\n // Teleport the overlay into `<VCTable>`'s positioned\n // wrapper. Rendering a `<div>` directly as a child of the\n // `<table>` is invalid HTML — the parser foster-parents\n // it OUT of the table, breaking the intended absolute\n // positioning. The wrapper is a sibling-of-`<table>`\n // `<div style=\"position:relative\">` provided by\n // `<VCTable>`. If we're rendered outside `<VCTable>` (no\n // ctx, no wrapper), fall back to rendering inline.\n const overlayNode = h(\n 'div',\n mergeProps(attrs, {\n class: [theme.value.root || undefined, theme.value.overlay || undefined],\n role: 'status',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n }),\n cellContent as never,\n );\n if (ctx?.wrapperEl.value) {\n return h(Teleport, { to: ctx.wrapperEl.value }, [overlayNode]);\n }\n return overlayNode;\n }\n\n // ARIA live-region attributes (`role`, `aria-live`,\n // `aria-busy`) do NOT belong on `<tbody>` — they override\n // the native `rowgroup` semantics and break table-structure\n // recognition for AT. Wrap the cell content in a `<div>`\n // that carries the live region instead.\n return h(\n 'tbody',\n mergeProps(attrs, { class: theme.value.root || undefined }),\n [\n h('tr', null, [\n h('td', { colspan: resolvedColspan.value }, [\n h(\n 'div',\n {\n role: 'status',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n },\n cellContent as never,\n ),\n ]),\n ]),\n ],\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type {\n SortDescriptor,\n TableColumn,\n TableSortIndicatorsThemeClasses,\n TableSortState,\n} from '../types';\nimport type {} from '../defaults';\n\nconst tableSortIndicatorsThemeDefaults = {\n classes: {\n root: 'vc-table-sort-indicators',\n label: 'vc-table-sort-indicators-label',\n empty: 'vc-table-sort-indicators-empty',\n chip: 'vc-table-sort-indicators-chip',\n chipToggle: 'vc-table-sort-indicators-chip-toggle',\n chipPosition: 'vc-table-sort-indicators-chip-position',\n chipLabel: 'vc-table-sort-indicators-chip-label',\n chipArrow: 'vc-table-sort-indicators-chip-arrow',\n chipRemove: 'vc-table-sort-indicators-chip-remove',\n addWrapper: '',\n add: 'vc-table-sort-indicators-add',\n clear: 'vc-table-sort-indicators-clear',\n },\n};\n\nconst behavioralDefaults = {\n label: 'Sort:',\n emptyContent: 'no columns sorted yet',\n addLabel: '+ Add column',\n clearLabel: 'Clear all',\n removeAriaLabel: 'Remove sort key',\n toggleAscTitle: 'Click to toggle descending',\n toggleDescTitle: 'Click to toggle ascending',\n arrowAsc: '↑',\n arrowDesc: '↓',\n removeGlyph: '×',\n};\n\nconst tableSortIndicatorsProps = {\n /**\n * Sort state to render. Use `v-model:sort` for two-way binding.\n * `null` is treated as \"empty array\" so consumers carrying\n * migration-era `ref<TableSortState | null>(null)` don't crash.\n * When BOTH `:sort` and `:columns` are omitted, the component\n * falls back to `useTable()` context — note that with the\n * default `<table>` rendering, slot children render INSIDE the\n * `<table>`, so the v-model path is the recommended placement\n * for chip rows above / below the table.\n */\n sort: { type: Array as PropType<TableSortState | null>, default: undefined },\n /**\n * Columns the sort can reference. Required when using v-model\n * mode (to look up labels + filter the add-column dropdown).\n * Falls back to `useTable()` context when omitted.\n */\n columns: { type: Array as PropType<TableColumn[]>, default: undefined },\n /**\n * Cap on the sort-state array length (mirrors `<VCTable\n * :max-sort-keys>`). `0` = unlimited. When the cap is hit,\n * adding via this component evicts the oldest descriptor.\n * Falls back to `useTable().maxSortKeys` when omitted; defaults\n * to `0` (unlimited) in stand-alone v-model mode without a\n * context.\n */\n maxSortKeys: { type: Number, default: undefined },\n /** Override the leading label text. Falls back to global defaults. */\n label: { type: String, default: undefined },\n /** Override the empty-state copy. Falls back to global defaults. */\n emptyContent: { type: String, default: undefined },\n /** Override the add-column trigger text. Falls back to global defaults. */\n addLabel: { type: String, default: undefined },\n /** Override the clear-all trigger text. Falls back to global defaults. */\n clearLabel: { type: String, default: undefined },\n /** Override the aria-label applied to per-chip remove buttons. */\n removeAriaLabel: { type: String, default: undefined },\n /** Hide the add-column dropdown (consumer brings their own affordance). */\n hideAdd: { type: Boolean, default: false },\n /** Hide the clear-all button. */\n hideClear: { type: Boolean, default: false },\n ...themableProps<TableSortIndicatorsThemeClasses>(),\n};\n\nexport type TableSortIndicatorsProps = ExtractPublicPropTypes<typeof tableSortIndicatorsProps>;\n\nexport type TableSortIndicatorsChipSlotProps = {\n descriptor: SortDescriptor;\n /** 0-based index in the sort array. */\n index: number;\n /** 1-based position (`index + 1`). */\n position: number;\n column: TableColumn | undefined;\n /** Toggle this descriptor's direction (asc ↔ desc). */\n toggle: () => void;\n /** Remove this descriptor from the sort. */\n remove: () => void;\n};\n\nexport type TableSortIndicatorsAddSlotProps = {\n /** Columns that are `:sortable` but not currently in the sort array. */\n options: TableColumn[];\n /** Append a column to the sort with `asc` direction. */\n add: (key: string) => void;\n};\n\nexport type TableSortIndicatorsClearSlotProps = {\n /** Clear the entire sort. */\n clear: () => void;\n};\n\n/**\n * Discoverable, modifier-key-free alternative to Shift-click for\n * managing multi-column sort state. Renders a chip per active\n * `SortDescriptor`, an add-column dropdown for unsorted sortable\n * columns, and a clear-all action.\n *\n * Two wiring modes:\n *\n * 1. **v-model (recommended)** — pass `:sort` + `:columns` and bind\n * `v-model:sort`. Place the chip row anywhere (above or below\n * the table). This is the only mode that supports the natural\n * \"chip row above table\" layout because `<VCTable>`'s default\n * slot children render inside `<table>` and a `<div>` there is\n * invalid HTML.\n *\n * ```vue\n * <VCTableSortIndicators v-model:sort=\"sort\" :columns=\"columns\" />\n * <VCTable v-model:sort=\"sort\" :columns :data ... />\n * ```\n *\n * 2. **Context fallback** — mount inside a `<VCTable>` and omit\n * `:sort` / `:columns`. The component reads from `useTable()`\n * and calls `setSortState`. Only safe in custom layouts where\n * a `<div>` is legal at the mount point.\n *\n * Slot customization:\n * - `default` — replace the whole layout (slot props include all\n * chip handlers + add + clear)\n * - `#label` — replace the leading \"Sort:\" label\n * - `#empty` — replace the empty-state hint\n * - `#chip=\"{ descriptor, index, position, toggle, remove }\"` —\n * replace per-chip rendering\n * - `#add=\"{ options, add }\"` — replace the add-column trigger\n * - `#clear=\"{ clear }\"` — replace the clear-all trigger\n *\n * Text strings flow through `useComponentDefaults('tableSortIndicators', …)`\n * so consumers can localize via\n * `app.use(vuecs, { defaults: { tableSortIndicators: { … } } })`.\n */\nexport default defineComponent({\n name: 'VCTableSortIndicators',\n inheritAttrs: false,\n props: tableSortIndicatorsProps,\n emits: ['update:sort'] as ['update:sort'],\n slots: Object as SlotsType<{\n default(props: {\n sort: SortDescriptor[];\n chips: TableSortIndicatorsChipSlotProps[];\n add: TableSortIndicatorsAddSlotProps;\n clear: TableSortIndicatorsClearSlotProps;\n }): unknown;\n label(): unknown;\n empty(): unknown;\n chip(props: TableSortIndicatorsChipSlotProps): unknown;\n add(props: TableSortIndicatorsAddSlotProps): unknown;\n clear(props: TableSortIndicatorsClearSlotProps): unknown;\n }>,\n setup(props, {\n attrs, \n emit, \n slots, \n }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableSortIndicators', props, behavioralDefaults);\n const theme = useComponentTheme(\n 'tableSortIndicators',\n useThemeProps(props),\n tableSortIndicatorsThemeDefaults,\n );\n\n // Resolved sources. The explicit `:sort` / `:columns` props\n // win over the context — this lets the chip row be placed\n // outside the `<VCTable>` (the recommended path) while\n // still working as a compound child in custom layouts.\n // `null` is treated as \"v-model is wired, currently empty\" —\n // a consumer holding `ref<TableSortState | null>(null)` keeps\n // the writeback path active. Only `undefined` (= prop not\n // bound at all) falls back to the table context. The `?? []`\n // floor makes `.map` etc safe.\n const sortPropProvided = computed<boolean>(() => props.sort !== undefined);\n const resolvedSort = computed<TableSortState>(() => {\n if (sortPropProvided.value) return (props.sort ?? []) as TableSortState;\n return (ctx?.sort.value ?? []) as TableSortState;\n });\n const resolvedColumns = computed<TableColumn[]>(() => {\n if (props.columns !== undefined) return props.columns;\n return (ctx?.columns.value ?? []) as TableColumn[];\n });\n\n function commitSort(next: TableSortState): void {\n if (sortPropProvided.value) {\n // v-model mode — emit only; consumer's binding owns\n // the writeback path.\n emit('update:sort', next);\n return;\n }\n // Context-fallback mode — push into the table's machine.\n // No `update:sort` emit here (the table emits its own\n // `update:sort` once the machine state lands), so a\n // double-emit doesn't fire for consumers who happen to\n // listen on the chip row.\n if (ctx) {\n // `globalThis.process` is the safe lookup in browser\n // ESM builds where `process` isn't a global; raw\n // `process.env.NODE_ENV` would throw ReferenceError.\n if (\n (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV !== 'production' &&\n !ctx.supportsSortMutation\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VCTableSortIndicators] mounted inside a table context that does not support sort mutation (likely <VCTableLite>). Clicks will be swallowed. Either bind :sort + :columns directly for v-model mode, or use <VCTable> instead of Lite.',\n );\n }\n ctx.setSortState(next);\n }\n }\n\n const columnByKey = computed(() => {\n const map = new Map<string, TableColumn>();\n for (const col of resolvedColumns.value) map.set(col.key, col);\n return map;\n });\n\n const unsortedSortable = computed<TableColumn[]>(() => {\n const inSort = new Set(resolvedSort.value.map((s) => s.key));\n return resolvedColumns.value.filter((c) => c.sortable && !inSort.has(c.key));\n });\n\n function toggleDirection(key: string) {\n commitSort(resolvedSort.value.map((s) => (s.key === key ?\n { ...s, direction: s.direction === 'asc' ? 'desc' : 'asc' as const } :\n s)));\n }\n\n function removeKey(key: string) {\n commitSort(resolvedSort.value.filter((s) => s.key !== key));\n }\n\n const resolvedMaxSortKeys = computed<number>(() => {\n if (props.maxSortKeys !== undefined) return props.maxSortKeys;\n return ctx?.maxSortKeys.value ?? 0;\n });\n\n function appendKey(key: string) {\n if (!key) return;\n // Defense-in-depth: the native `<select>` is already\n // filtered to sortable columns, but slot-prop callers\n // (custom `#add` UIs) may pass any string. Reject:\n // - unknown keys (no matching column → unrenderable\n // descriptor; the table can't map it)\n // - known but non-sortable columns (`sortable` defaults\n // to `undefined` (= not sortable); only an explicit\n // `true` opts in)\n const col = columnByKey.value.get(key);\n if (!col || !col.sortable) return;\n // Don't re-add a key that's already in the sort.\n if (resolvedSort.value.some((s) => s.key === key)) return;\n const next: TableSortState = [...resolvedSort.value, { key, direction: 'asc' }];\n const cap = resolvedMaxSortKeys.value;\n // Evict from the front (oldest first) to match the\n // sort machine's `appendCapped` semantic. `cap <= 0`\n // means unlimited.\n const capped = cap > 0 && next.length > cap ? next.slice(next.length - cap) : next;\n commitSort(capped);\n }\n\n function clearAll() {\n commitSort([]);\n }\n\n const chipSlotProps = computed<TableSortIndicatorsChipSlotProps[]>(() => resolvedSort.value\n .map((descriptor, index) => ({\n descriptor,\n index,\n position: index + 1,\n column: columnByKey.value.get(descriptor.key),\n toggle: () => toggleDirection(descriptor.key),\n remove: () => removeKey(descriptor.key),\n })));\n\n return () => {\n // Render nothing when we have neither v-model state nor a\n // table context — there's no useful interaction to expose.\n if (!sortPropProvided.value && !ctx) return null;\n\n const sortState = resolvedSort.value;\n const t = theme.value;\n const d = defaults.value;\n\n const addSlotProps: TableSortIndicatorsAddSlotProps = {\n options: unsortedSortable.value,\n add: appendKey,\n };\n const clearSlotProps: TableSortIndicatorsClearSlotProps = { clear: clearAll };\n\n const renderChip = (chip: TableSortIndicatorsChipSlotProps) => {\n if (slots.chip) return slots.chip(chip);\n const isAsc = chip.descriptor.direction === 'asc';\n // Two real `<button>`s wrapped in a non-interactive\n // `<div>`. Putting a `<button>` inside another\n // `<button>` is invalid HTML (browsers hoist the\n // inner button) and a screen-reader trap (nested\n // role=button announcements). The wrapper carries\n // the chip's visual styling; the two buttons inherit\n // a borderless `chipToggle` / `chipRemove` look.\n return h('div', {\n key: chip.descriptor.key,\n class: t.chip || undefined,\n 'data-sort-key': chip.descriptor.key,\n 'data-direction': chip.descriptor.direction,\n }, [\n h('button', {\n type: 'button',\n class: t.chipToggle || undefined,\n title: isAsc ? d.toggleAscTitle : d.toggleDescTitle,\n onClick: chip.toggle,\n }, [\n h('span', { class: t.chipPosition || undefined }, `${chip.position}.`),\n h('span', { class: t.chipLabel || undefined }, chip.column?.label ?? chip.descriptor.key),\n h('span', { class: t.chipArrow || undefined }, isAsc ? d.arrowAsc : d.arrowDesc),\n ]),\n h('button', {\n type: 'button',\n class: t.chipRemove || undefined,\n 'aria-label': d.removeAriaLabel,\n onClick: chip.remove,\n }, d.removeGlyph),\n ]);\n };\n\n const renderLabel = () => (slots.label ? slots.label() : h(\n 'span',\n { class: t.label || undefined },\n d.label,\n ));\n\n const renderEmpty = () => (slots.empty ? slots.empty() : h(\n 'span',\n { class: t.empty || undefined },\n d.emptyContent,\n ));\n\n const renderAdd = () => {\n if (props.hideAdd || addSlotProps.options.length === 0) return null;\n if (slots.add) return slots.add(addSlotProps);\n const selectNode = h('select', {\n class: t.add || undefined,\n 'aria-label': d.addLabel,\n onChange: (e: Event) => {\n const target = e.target as globalThis.HTMLSelectElement;\n appendKey(target.value);\n target.value = '';\n },\n }, [\n h('option', { value: '' }, d.addLabel),\n ...addSlotProps.options.map((col) => h(\n 'option',\n { key: col.key, value: col.key },\n col.label ?? col.key,\n )),\n ]);\n // Some themes (Bulma) style a wrapper element rather\n // than the `<select>` itself — `.select` in Bulma 1.x\n // is a wrapper pattern, not a direct-on-select class.\n // Themes that style the select directly (Tailwind,\n // Bootstrap) leave `addWrapper` empty and we render\n // the bare select.\n if (!t.addWrapper) return selectNode;\n return h('div', { class: t.addWrapper }, [selectNode]);\n };\n\n const renderClear = () => {\n if (props.hideClear || sortState.length === 0) return null;\n if (slots.clear) return slots.clear(clearSlotProps);\n return h('button', {\n type: 'button',\n class: t.clear || undefined,\n onClick: clearAll,\n }, d.clearLabel);\n };\n\n // Root attrs are identical across both render paths so\n // `#default` overrides keep the toolbar a11y semantics.\n const rootAttrs = {\n class: t.root || undefined,\n role: 'toolbar',\n 'aria-label': 'Active sort columns',\n };\n\n if (slots.default) {\n return h(\n 'div',\n mergeProps(attrs, rootAttrs),\n slots.default({\n sort: sortState,\n chips: chipSlotProps.value,\n add: addSlotProps,\n clear: clearSlotProps,\n }) as never,\n );\n }\n\n const chipsContent = sortState.length === 0 ?\n [renderEmpty()] :\n chipSlotProps.value.map(renderChip);\n\n return h(\n 'div',\n mergeProps(attrs, rootAttrs),\n ([\n renderLabel(),\n ...chipsContent,\n renderAdd(),\n renderClear(),\n ]) as never,\n );\n };\n },\n});\n</script>\n","<script lang=\"ts\">\nimport {\n computed,\n defineComponent,\n h,\n mergeProps,\n} from 'vue';\nimport type { ExtractPublicPropTypes, PropType, SlotsType } from 'vue';\nimport {\n themableProps,\n useComponentDefaults,\n useComponentTheme,\n useThemeProps,\n} from '@vuecs/core';\nimport { useTable } from '../composables/context';\nimport type {\n SortDescriptor,\n TableColumn,\n TableSortIndicatorsThemeClasses,\n TableSortState,\n} from '../types';\nimport type {} from '../defaults';\n\nconst tableSortIndicatorsThemeDefaults = {\n classes: {\n root: 'vc-table-sort-indicators',\n label: 'vc-table-sort-indicators-label',\n empty: 'vc-table-sort-indicators-empty',\n chip: 'vc-table-sort-indicators-chip',\n chipToggle: 'vc-table-sort-indicators-chip-toggle',\n chipPosition: 'vc-table-sort-indicators-chip-position',\n chipLabel: 'vc-table-sort-indicators-chip-label',\n chipArrow: 'vc-table-sort-indicators-chip-arrow',\n chipRemove: 'vc-table-sort-indicators-chip-remove',\n addWrapper: '',\n add: 'vc-table-sort-indicators-add',\n clear: 'vc-table-sort-indicators-clear',\n },\n};\n\nconst behavioralDefaults = {\n label: 'Sort:',\n emptyContent: 'no columns sorted yet',\n addLabel: '+ Add column',\n clearLabel: 'Clear all',\n removeAriaLabel: 'Remove sort key',\n toggleAscTitle: 'Click to toggle descending',\n toggleDescTitle: 'Click to toggle ascending',\n arrowAsc: '↑',\n arrowDesc: '↓',\n removeGlyph: '×',\n};\n\nconst tableSortIndicatorsProps = {\n /**\n * Sort state to render. Use `v-model:sort` for two-way binding.\n * `null` is treated as \"empty array\" so consumers carrying\n * migration-era `ref<TableSortState | null>(null)` don't crash.\n * When BOTH `:sort` and `:columns` are omitted, the component\n * falls back to `useTable()` context — note that with the\n * default `<table>` rendering, slot children render INSIDE the\n * `<table>`, so the v-model path is the recommended placement\n * for chip rows above / below the table.\n */\n sort: { type: Array as PropType<TableSortState | null>, default: undefined },\n /**\n * Columns the sort can reference. Required when using v-model\n * mode (to look up labels + filter the add-column dropdown).\n * Falls back to `useTable()` context when omitted.\n */\n columns: { type: Array as PropType<TableColumn[]>, default: undefined },\n /**\n * Cap on the sort-state array length (mirrors `<VCTable\n * :max-sort-keys>`). `0` = unlimited. When the cap is hit,\n * adding via this component evicts the oldest descriptor.\n * Falls back to `useTable().maxSortKeys` when omitted; defaults\n * to `0` (unlimited) in stand-alone v-model mode without a\n * context.\n */\n maxSortKeys: { type: Number, default: undefined },\n /** Override the leading label text. Falls back to global defaults. */\n label: { type: String, default: undefined },\n /** Override the empty-state copy. Falls back to global defaults. */\n emptyContent: { type: String, default: undefined },\n /** Override the add-column trigger text. Falls back to global defaults. */\n addLabel: { type: String, default: undefined },\n /** Override the clear-all trigger text. Falls back to global defaults. */\n clearLabel: { type: String, default: undefined },\n /** Override the aria-label applied to per-chip remove buttons. */\n removeAriaLabel: { type: String, default: undefined },\n /** Hide the add-column dropdown (consumer brings their own affordance). */\n hideAdd: { type: Boolean, default: false },\n /** Hide the clear-all button. */\n hideClear: { type: Boolean, default: false },\n ...themableProps<TableSortIndicatorsThemeClasses>(),\n};\n\nexport type TableSortIndicatorsProps = ExtractPublicPropTypes<typeof tableSortIndicatorsProps>;\n\nexport type TableSortIndicatorsChipSlotProps = {\n descriptor: SortDescriptor;\n /** 0-based index in the sort array. */\n index: number;\n /** 1-based position (`index + 1`). */\n position: number;\n column: TableColumn | undefined;\n /** Toggle this descriptor's direction (asc ↔ desc). */\n toggle: () => void;\n /** Remove this descriptor from the sort. */\n remove: () => void;\n};\n\nexport type TableSortIndicatorsAddSlotProps = {\n /** Columns that are `:sortable` but not currently in the sort array. */\n options: TableColumn[];\n /** Append a column to the sort with `asc` direction. */\n add: (key: string) => void;\n};\n\nexport type TableSortIndicatorsClearSlotProps = {\n /** Clear the entire sort. */\n clear: () => void;\n};\n\n/**\n * Discoverable, modifier-key-free alternative to Shift-click for\n * managing multi-column sort state. Renders a chip per active\n * `SortDescriptor`, an add-column dropdown for unsorted sortable\n * columns, and a clear-all action.\n *\n * Two wiring modes:\n *\n * 1. **v-model (recommended)** — pass `:sort` + `:columns` and bind\n * `v-model:sort`. Place the chip row anywhere (above or below\n * the table). This is the only mode that supports the natural\n * \"chip row above table\" layout because `<VCTable>`'s default\n * slot children render inside `<table>` and a `<div>` there is\n * invalid HTML.\n *\n * ```vue\n * <VCTableSortIndicators v-model:sort=\"sort\" :columns=\"columns\" />\n * <VCTable v-model:sort=\"sort\" :columns :data ... />\n * ```\n *\n * 2. **Context fallback** — mount inside a `<VCTable>` and omit\n * `:sort` / `:columns`. The component reads from `useTable()`\n * and calls `setSortState`. Only safe in custom layouts where\n * a `<div>` is legal at the mount point.\n *\n * Slot customization:\n * - `default` — replace the whole layout (slot props include all\n * chip handlers + add + clear)\n * - `#label` — replace the leading \"Sort:\" label\n * - `#empty` — replace the empty-state hint\n * - `#chip=\"{ descriptor, index, position, toggle, remove }\"` —\n * replace per-chip rendering\n * - `#add=\"{ options, add }\"` — replace the add-column trigger\n * - `#clear=\"{ clear }\"` — replace the clear-all trigger\n *\n * Text strings flow through `useComponentDefaults('tableSortIndicators', …)`\n * so consumers can localize via\n * `app.use(vuecs, { defaults: { tableSortIndicators: { … } } })`.\n */\nexport default defineComponent({\n name: 'VCTableSortIndicators',\n inheritAttrs: false,\n props: tableSortIndicatorsProps,\n emits: ['update:sort'] as ['update:sort'],\n slots: Object as SlotsType<{\n default(props: {\n sort: SortDescriptor[];\n chips: TableSortIndicatorsChipSlotProps[];\n add: TableSortIndicatorsAddSlotProps;\n clear: TableSortIndicatorsClearSlotProps;\n }): unknown;\n label(): unknown;\n empty(): unknown;\n chip(props: TableSortIndicatorsChipSlotProps): unknown;\n add(props: TableSortIndicatorsAddSlotProps): unknown;\n clear(props: TableSortIndicatorsClearSlotProps): unknown;\n }>,\n setup(props, {\n attrs, \n emit, \n slots, \n }) {\n const ctx = useTable();\n const defaults = useComponentDefaults('tableSortIndicators', props, behavioralDefaults);\n const theme = useComponentTheme(\n 'tableSortIndicators',\n useThemeProps(props),\n tableSortIndicatorsThemeDefaults,\n );\n\n // Resolved sources. The explicit `:sort` / `:columns` props\n // win over the context — this lets the chip row be placed\n // outside the `<VCTable>` (the recommended path) while\n // still working as a compound child in custom layouts.\n // `null` is treated as \"v-model is wired, currently empty\" —\n // a consumer holding `ref<TableSortState | null>(null)` keeps\n // the writeback path active. Only `undefined` (= prop not\n // bound at all) falls back to the table context. The `?? []`\n // floor makes `.map` etc safe.\n const sortPropProvided = computed<boolean>(() => props.sort !== undefined);\n const resolvedSort = computed<TableSortState>(() => {\n if (sortPropProvided.value) return (props.sort ?? []) as TableSortState;\n return (ctx?.sort.value ?? []) as TableSortState;\n });\n const resolvedColumns = computed<TableColumn[]>(() => {\n if (props.columns !== undefined) return props.columns;\n return (ctx?.columns.value ?? []) as TableColumn[];\n });\n\n function commitSort(next: TableSortState): void {\n if (sortPropProvided.value) {\n // v-model mode — emit only; consumer's binding owns\n // the writeback path.\n emit('update:sort', next);\n return;\n }\n // Context-fallback mode — push into the table's machine.\n // No `update:sort` emit here (the table emits its own\n // `update:sort` once the machine state lands), so a\n // double-emit doesn't fire for consumers who happen to\n // listen on the chip row.\n if (ctx) {\n // `globalThis.process` is the safe lookup in browser\n // ESM builds where `process` isn't a global; raw\n // `process.env.NODE_ENV` would throw ReferenceError.\n if (\n (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV !== 'production' &&\n !ctx.supportsSortMutation\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VCTableSortIndicators] mounted inside a table context that does not support sort mutation (likely <VCTableLite>). Clicks will be swallowed. Either bind :sort + :columns directly for v-model mode, or use <VCTable> instead of Lite.',\n );\n }\n ctx.setSortState(next);\n }\n }\n\n const columnByKey = computed(() => {\n const map = new Map<string, TableColumn>();\n for (const col of resolvedColumns.value) map.set(col.key, col);\n return map;\n });\n\n const unsortedSortable = computed<TableColumn[]>(() => {\n const inSort = new Set(resolvedSort.value.map((s) => s.key));\n return resolvedColumns.value.filter((c) => c.sortable && !inSort.has(c.key));\n });\n\n function toggleDirection(key: string) {\n commitSort(resolvedSort.value.map((s) => (s.key === key ?\n { ...s, direction: s.direction === 'asc' ? 'desc' : 'asc' as const } :\n s)));\n }\n\n function removeKey(key: string) {\n commitSort(resolvedSort.value.filter((s) => s.key !== key));\n }\n\n const resolvedMaxSortKeys = computed<number>(() => {\n if (props.maxSortKeys !== undefined) return props.maxSortKeys;\n return ctx?.maxSortKeys.value ?? 0;\n });\n\n function appendKey(key: string) {\n if (!key) return;\n // Defense-in-depth: the native `<select>` is already\n // filtered to sortable columns, but slot-prop callers\n // (custom `#add` UIs) may pass any string. Reject:\n // - unknown keys (no matching column → unrenderable\n // descriptor; the table can't map it)\n // - known but non-sortable columns (`sortable` defaults\n // to `undefined` (= not sortable); only an explicit\n // `true` opts in)\n const col = columnByKey.value.get(key);\n if (!col || !col.sortable) return;\n // Don't re-add a key that's already in the sort.\n if (resolvedSort.value.some((s) => s.key === key)) return;\n const next: TableSortState = [...resolvedSort.value, { key, direction: 'asc' }];\n const cap = resolvedMaxSortKeys.value;\n // Evict from the front (oldest first) to match the\n // sort machine's `appendCapped` semantic. `cap <= 0`\n // means unlimited.\n const capped = cap > 0 && next.length > cap ? next.slice(next.length - cap) : next;\n commitSort(capped);\n }\n\n function clearAll() {\n commitSort([]);\n }\n\n const chipSlotProps = computed<TableSortIndicatorsChipSlotProps[]>(() => resolvedSort.value\n .map((descriptor, index) => ({\n descriptor,\n index,\n position: index + 1,\n column: columnByKey.value.get(descriptor.key),\n toggle: () => toggleDirection(descriptor.key),\n remove: () => removeKey(descriptor.key),\n })));\n\n return () => {\n // Render nothing when we have neither v-model state nor a\n // table context — there's no useful interaction to expose.\n if (!sortPropProvided.value && !ctx) return null;\n\n const sortState = resolvedSort.value;\n const t = theme.value;\n const d = defaults.value;\n\n const addSlotProps: TableSortIndicatorsAddSlotProps = {\n options: unsortedSortable.value,\n add: appendKey,\n };\n const clearSlotProps: TableSortIndicatorsClearSlotProps = { clear: clearAll };\n\n const renderChip = (chip: TableSortIndicatorsChipSlotProps) => {\n if (slots.chip) return slots.chip(chip);\n const isAsc = chip.descriptor.direction === 'asc';\n // Two real `<button>`s wrapped in a non-interactive\n // `<div>`. Putting a `<button>` inside another\n // `<button>` is invalid HTML (browsers hoist the\n // inner button) and a screen-reader trap (nested\n // role=button announcements). The wrapper carries\n // the chip's visual styling; the two buttons inherit\n // a borderless `chipToggle` / `chipRemove` look.\n return h('div', {\n key: chip.descriptor.key,\n class: t.chip || undefined,\n 'data-sort-key': chip.descriptor.key,\n 'data-direction': chip.descriptor.direction,\n }, [\n h('button', {\n type: 'button',\n class: t.chipToggle || undefined,\n title: isAsc ? d.toggleAscTitle : d.toggleDescTitle,\n onClick: chip.toggle,\n }, [\n h('span', { class: t.chipPosition || undefined }, `${chip.position}.`),\n h('span', { class: t.chipLabel || undefined }, chip.column?.label ?? chip.descriptor.key),\n h('span', { class: t.chipArrow || undefined }, isAsc ? d.arrowAsc : d.arrowDesc),\n ]),\n h('button', {\n type: 'button',\n class: t.chipRemove || undefined,\n 'aria-label': d.removeAriaLabel,\n onClick: chip.remove,\n }, d.removeGlyph),\n ]);\n };\n\n const renderLabel = () => (slots.label ? slots.label() : h(\n 'span',\n { class: t.label || undefined },\n d.label,\n ));\n\n const renderEmpty = () => (slots.empty ? slots.empty() : h(\n 'span',\n { class: t.empty || undefined },\n d.emptyContent,\n ));\n\n const renderAdd = () => {\n if (props.hideAdd || addSlotProps.options.length === 0) return null;\n if (slots.add) return slots.add(addSlotProps);\n const selectNode = h('select', {\n class: t.add || undefined,\n 'aria-label': d.addLabel,\n onChange: (e: Event) => {\n const target = e.target as globalThis.HTMLSelectElement;\n appendKey(target.value);\n target.value = '';\n },\n }, [\n h('option', { value: '' }, d.addLabel),\n ...addSlotProps.options.map((col) => h(\n 'option',\n { key: col.key, value: col.key },\n col.label ?? col.key,\n )),\n ]);\n // Some themes (Bulma) style a wrapper element rather\n // than the `<select>` itself — `.select` in Bulma 1.x\n // is a wrapper pattern, not a direct-on-select class.\n // Themes that style the select directly (Tailwind,\n // Bootstrap) leave `addWrapper` empty and we render\n // the bare select.\n if (!t.addWrapper) return selectNode;\n return h('div', { class: t.addWrapper }, [selectNode]);\n };\n\n const renderClear = () => {\n if (props.hideClear || sortState.length === 0) return null;\n if (slots.clear) return slots.clear(clearSlotProps);\n return h('button', {\n type: 'button',\n class: t.clear || undefined,\n onClick: clearAll,\n }, d.clearLabel);\n };\n\n // Root attrs are identical across both render paths so\n // `#default` overrides keep the toolbar a11y semantics.\n const rootAttrs = {\n class: t.root || undefined,\n role: 'toolbar',\n 'aria-label': 'Active sort columns',\n };\n\n if (slots.default) {\n return h(\n 'div',\n mergeProps(attrs, rootAttrs),\n slots.default({\n sort: sortState,\n chips: chipSlotProps.value,\n add: addSlotProps,\n clear: clearSlotProps,\n }) as never,\n );\n }\n\n const chipsContent = sortState.length === 0 ?\n [renderEmpty()] :\n chipSlotProps.value.map(renderChip);\n\n return h(\n 'div',\n mergeProps(attrs, rootAttrs),\n ([\n renderLabel(),\n ...chipsContent,\n renderAdd(),\n renderClear(),\n ]) as never,\n );\n };\n },\n});\n</script>\n","import { computed, ref } from 'vue';\nimport type { ComputedRef, Ref } from 'vue';\nimport type {\n SortDirection,\n TableColumn,\n TableColumnRaw,\n TableSortState,\n} from '../types';\nimport { useSortMachine } from './sort';\nimport { normalizeColumns } from '../utils/render-utils';\n\nexport type DefineTableOptions<Row> = {\n /** Initial data array. */\n data?: Row[];\n /** Initial column definitions (TableColumn or bare-string shorthand). */\n columns?: TableColumnRaw<Row>[];\n /** Initial busy flag. */\n busy?: boolean;\n /** Initial sort state (array of descriptors). Empty array means no sort. */\n sort?: TableSortState;\n /** Max sort keys retained in multi-sort mode. `0` = unlimited. Default `3`. */\n maxSortKeys?: number;\n /** When `true`, the sort cycle skips the `null` step. Mirrors `<VCTable :must-sort>`. */\n mustSort?: boolean;\n};\n\nexport type TableState<Row> = {\n data: Ref<Row[]>;\n columns: ComputedRef<TableColumn<Row>[]>;\n rawColumns: Ref<TableColumnRaw<Row>[]>;\n busy: Ref<boolean>;\n mustSort: Ref<boolean>;\n sort: Ref<TableSortState>;\n setSort: (key: string, opts?: { append?: boolean; direction?: SortDirection }) => void;\n};\n\n/**\n * Pinia-style factory mirroring `defineList()`. Returns reactive state\n * containers + a `setSort` mutator. Useful when a consumer wants to share\n * a table's state across multiple components without prop drilling, or\n * when wiring a controlled table outside the SFC.\n *\n * const usersTable = defineTable<User>({\n * columns: ['id', 'name', 'email'],\n * data: [],\n * busy: false,\n * });\n *\n * <VCTable :data=\"usersTable.data\" :columns=\"usersTable.columns\" ... />\n *\n * The sort cycle composes `useSortMachine` internally — same semantics\n * as the `<VCTable>` SFC path (honors per-column `initialSortDirection`\n * + `mustSort`).\n */\nexport function defineTable<Row = unknown>(\n options: DefineTableOptions<Row> = {},\n): TableState<Row> {\n // Deep `ref` (not `shallowRef`) for `data` + `rawColumns` so\n // in-place array mutations (`.push`, `.splice`, item-property\n // updates) flow through to dependent computeds. `shallowRef` would\n // silently swallow these in normal state-store usage.\n const data = ref(options.data ?? []) as Ref<Row[]>;\n const rawColumns = ref(options.columns ?? []) as Ref<TableColumnRaw<Row>[]>;\n const busy = ref(options.busy ?? false);\n const mustSort = ref(options.mustSort ?? false);\n const sort = ref<TableSortState>(options.sort ?? []);\n const maxSortKeys = ref(options.maxSortKeys ?? 3);\n\n const columns = computed(() => normalizeColumns(rawColumns.value, data.value));\n\n // Compose `useSortMachine` so the cycle (initialSortDirection +\n // mustSort handling) matches the SFC path bit-for-bit. The local\n // `sort` ref serves as both source-of-truth and emit-target.\n const sortMachine = useSortMachine<Row>({\n source: sort as unknown as Ref<TableSortState | undefined>,\n columns,\n mustSort,\n maxSortKeys,\n emit: (next) => { sort.value = next; },\n });\n\n return {\n data,\n columns,\n rawColumns,\n busy,\n mustSort,\n sort,\n setSort: sortMachine.setSort,\n };\n}\n","import type { ComponentThemeDefinition } from '@vuecs/core';\nimport type {\n TableBodyThemeClasses,\n TableCellThemeClasses,\n TableEmptyThemeClasses,\n TableFooterThemeClasses,\n TableHeadCellThemeClasses,\n TableHeaderThemeClasses,\n TableLoadingThemeClasses,\n TableRowThemeClasses,\n TableSortIndicatorsThemeClasses,\n TableThemeClasses,\n} from './types';\n\nexport const tableThemeDefaults: ComponentThemeDefinition<TableThemeClasses> = {\n classes: {\n root: 'vc-table',\n scrollContainer: 'vc-table-scroll-container',\n },\n};\n\nexport const tableHeaderThemeDefaults: ComponentThemeDefinition<TableHeaderThemeClasses> = { classes: { root: 'vc-table-header' } };\n\nexport const tableBodyThemeDefaults: ComponentThemeDefinition<TableBodyThemeClasses> = { classes: { root: 'vc-table-body' } };\n\nexport const tableFooterThemeDefaults: ComponentThemeDefinition<TableFooterThemeClasses> = { classes: { root: 'vc-table-footer' } };\n\nexport const tableRowThemeDefaults: ComponentThemeDefinition<TableRowThemeClasses> = { classes: { root: 'vc-table-row' } };\n\nexport const tableCellThemeDefaults: ComponentThemeDefinition<TableCellThemeClasses> = { classes: { root: 'vc-table-cell' } };\n\nexport const tableHeadCellThemeDefaults: ComponentThemeDefinition<TableHeadCellThemeClasses> = {\n classes: {\n root: 'vc-table-head-cell',\n sortIcon: 'vc-table-head-cell-sort-icon',\n },\n};\n\nexport const tableEmptyThemeDefaults: ComponentThemeDefinition<TableEmptyThemeClasses> = { classes: { root: 'vc-table-empty' } };\n\nexport const tableLoadingThemeDefaults: ComponentThemeDefinition<TableLoadingThemeClasses> = {\n classes: {\n root: 'vc-table-loading',\n overlay: 'vc-table-loading-overlay',\n },\n};\n\nexport const tableSortIndicatorsThemeDefaults: ComponentThemeDefinition<TableSortIndicatorsThemeClasses> = {\n classes: {\n root: 'vc-table-sort-indicators',\n label: 'vc-table-sort-indicators-label',\n empty: 'vc-table-sort-indicators-empty',\n chip: 'vc-table-sort-indicators-chip',\n chipToggle: 'vc-table-sort-indicators-chip-toggle',\n chipPosition: 'vc-table-sort-indicators-chip-position',\n chipLabel: 'vc-table-sort-indicators-chip-label',\n chipArrow: 'vc-table-sort-indicators-chip-arrow',\n chipRemove: 'vc-table-sort-indicators-chip-remove',\n addWrapper: '',\n add: 'vc-table-sort-indicators-add',\n clear: 'vc-table-sort-indicators-clear',\n },\n};\n","import type { App, Plugin } from 'vue';\nimport { installDefaultsManager, installThemeManager } from '@vuecs/core';\nimport type { CoreOptions } from '@vuecs/core';\n\nimport '../assets/index.css';\nimport './defaults';\nimport './vue';\n\nimport {\n VCTable,\n VCTableBody,\n VCTableCell,\n VCTableEmpty,\n VCTableFooter,\n VCTableHeadCell,\n VCTableHeader,\n VCTableLite,\n VCTableLoading,\n VCTableRow,\n VCTableSortIndicators,\n} from './components';\n\nexport * from './components';\nexport * from './composables';\nexport * from './theme';\nexport * from './types';\nexport * from './utils';\nexport type * from './defaults';\n\nexport type Options = CoreOptions;\n\nexport function install(app: App, options: Options = {}): void {\n installThemeManager(app, options);\n installDefaultsManager(app, options);\n\n Object.entries({\n VCTable,\n VCTableLite,\n VCTableHeader,\n VCTableBody,\n VCTableFooter,\n VCTableRow,\n VCTableCell,\n VCTableHeadCell,\n VCTableEmpty,\n VCTableLoading,\n VCTableSortIndicators,\n }).forEach(([name, component]) => {\n app.component(name, component);\n });\n}\n\nexport default { install } satisfies Plugin<[Options?]>;\n"],"mappings":"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"}
|