compote-ui 0.42.6 → 0.43.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/dist/components/data-table/column-helper.ts.md +96 -0
- package/dist/components/data-table/create-table.ts.md +386 -0
- package/dist/components/data-table/data-table-column-filter.svelte.md +249 -0
- package/dist/components/data-table/data-table-column-visibility.svelte.md +74 -0
- package/dist/components/data-table/{data-table-head.svelte → data-table-head.svelte.md} +1 -1
- package/dist/components/data-table/data-table-new.svelte.md +245 -0
- package/dist/components/data-table/data-table-title.svelte.md +16 -0
- package/dist/components/data-table/data-table-toolbar.svelte.md +40 -0
- package/dist/components/data-table/data-table-utils.ts.md +179 -0
- package/dist/components/data-table/{data-table-virtual-rows.svelte → data-table-virtual-rows.svelte.md} +1 -1
- package/dist/components/data-table/data-table-virtualized.svelte.md +108 -0
- package/dist/components/data-table/data-table.svelte.md +214 -0
- package/dist/components/data-table/index.ts.md +22 -0
- package/dist/components/data-table/types.ts.md +101 -0
- package/dist/components/data-table/virtual/index.ts.md +26 -0
- package/dist/components/{data-table → data-table-v8}/column-helper.d.ts +1 -1
- package/dist/components/data-table-v8/create-svelte-table.svelte.d.ts +8 -0
- package/dist/components/data-table-v8/create-svelte-table.svelte.js +85 -0
- package/dist/components/data-table-v8/create-table.svelte.d.ts +35 -0
- package/dist/components/{data-table/create-table.js → data-table-v8/create-table.svelte.js} +25 -55
- package/dist/components/data-table-v8/data-table-checkbox.css +44 -0
- package/dist/components/{data-table → data-table-v8}/data-table-column-filter.svelte +16 -19
- package/dist/components/{data-table → data-table-v8}/data-table-column-filter.svelte.d.ts +2 -2
- package/dist/components/{data-table → data-table-v8}/data-table-column-visibility.svelte +15 -14
- package/dist/components/{data-table → data-table-v8}/data-table-column-visibility.svelte.d.ts +2 -2
- package/dist/components/data-table-v8/data-table-head.svelte +200 -0
- package/dist/components/{data-table → data-table-v8}/data-table-head.svelte.d.ts +3 -3
- package/dist/components/{data-table → data-table-v8}/data-table-utils.d.ts +10 -15
- package/dist/components/{data-table → data-table-v8}/data-table-utils.js +18 -12
- package/dist/components/data-table-v8/data-table-virtual-rows.svelte +170 -0
- package/dist/components/{data-table → data-table-v8}/data-table-virtual-rows.svelte.d.ts +3 -3
- package/dist/components/{data-table → data-table-v8}/data-table-virtualized.svelte +15 -14
- package/dist/components/{data-table → data-table-v8}/data-table-virtualized.svelte.d.ts +2 -2
- package/dist/components/{data-table → data-table-v8}/data-table.svelte +40 -22
- package/dist/components/{data-table → data-table-v8}/data-table.svelte.d.ts +2 -2
- package/dist/components/data-table-v8/flex-render.svelte +35 -0
- package/dist/components/data-table-v8/flex-render.svelte.d.ts +28 -0
- package/dist/components/{data-table → data-table-v8}/index.d.ts +4 -2
- package/dist/components/{data-table → data-table-v8}/index.js +3 -1
- package/dist/components/data-table-v8/render-helpers.d.ts +13 -0
- package/dist/components/data-table-v8/render-helpers.js +23 -0
- package/dist/components/{data-table → data-table-v8}/types.d.ts +12 -2
- package/dist/components/data-table-v8/virtual/index.d.ts +3 -0
- package/dist/components/data-table-v8/virtual/index.js +2 -0
- package/package.json +9 -9
- package/dist/components/data-table/create-table.d.ts +0 -41
- package/dist/components/data-table/virtual/index.d.ts +0 -3
- package/dist/components/data-table/virtual/index.js +0 -2
- /package/dist/components/{data-table → data-table-v8}/column-helper.js +0 -0
- /package/dist/components/{data-table → data-table-v8}/data-table-title.svelte +0 -0
- /package/dist/components/{data-table → data-table-v8}/data-table-title.svelte.d.ts +0 -0
- /package/dist/components/{data-table → data-table-v8}/data-table-toolbar.svelte +0 -0
- /package/dist/components/{data-table → data-table-v8}/data-table-toolbar.svelte.d.ts +0 -0
- /package/dist/components/{data-table → data-table-v8}/types.js +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createTable } from '@tanstack/table-core';
|
|
2
|
+
export function createSvelteTable(options) {
|
|
3
|
+
const resolvedOptions = mergeObjects({
|
|
4
|
+
state: {},
|
|
5
|
+
onStateChange() { },
|
|
6
|
+
renderFallbackValue: null,
|
|
7
|
+
mergeOptions: (defaultOptions, options) => {
|
|
8
|
+
return mergeObjects(defaultOptions, options);
|
|
9
|
+
}
|
|
10
|
+
}, options);
|
|
11
|
+
const table = createTable(resolvedOptions);
|
|
12
|
+
let state = $state(table.initialState);
|
|
13
|
+
function updateOptions() {
|
|
14
|
+
table.setOptions(() => {
|
|
15
|
+
return mergeObjects(resolvedOptions, options, {
|
|
16
|
+
state: mergeObjects(state, options.state || {}),
|
|
17
|
+
onStateChange: (updater) => {
|
|
18
|
+
if (updater instanceof Function)
|
|
19
|
+
state = updater(state);
|
|
20
|
+
else
|
|
21
|
+
state = mergeObjects(state, updater);
|
|
22
|
+
options.onStateChange?.(updater);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
updateOptions();
|
|
28
|
+
$effect.pre(() => {
|
|
29
|
+
updateOptions();
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(table, '_svelteState', {
|
|
32
|
+
get() {
|
|
33
|
+
return state;
|
|
34
|
+
},
|
|
35
|
+
enumerable: false,
|
|
36
|
+
configurable: true
|
|
37
|
+
});
|
|
38
|
+
return table;
|
|
39
|
+
}
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
export function mergeObjects(...sources) {
|
|
42
|
+
const resolve = (src) => typeof src === 'function' ? (src() ?? undefined) : src;
|
|
43
|
+
const findSourceWithKey = (key) => {
|
|
44
|
+
for (let i = sources.length - 1; i >= 0; i--) {
|
|
45
|
+
const obj = resolve(sources[i]);
|
|
46
|
+
if (obj && key in obj)
|
|
47
|
+
return obj;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
return new Proxy(Object.create(null), {
|
|
52
|
+
get(_, key) {
|
|
53
|
+
const src = findSourceWithKey(key);
|
|
54
|
+
return src?.[key];
|
|
55
|
+
},
|
|
56
|
+
has(_, key) {
|
|
57
|
+
return !!findSourceWithKey(key);
|
|
58
|
+
},
|
|
59
|
+
ownKeys() {
|
|
60
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
61
|
+
const all = new Set();
|
|
62
|
+
for (const s of sources) {
|
|
63
|
+
const obj = resolve(s);
|
|
64
|
+
if (obj) {
|
|
65
|
+
for (const k of Reflect.ownKeys(obj)) {
|
|
66
|
+
all.add(k);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [...all];
|
|
71
|
+
},
|
|
72
|
+
getOwnPropertyDescriptor(_, key) {
|
|
73
|
+
const src = findSourceWithKey(key);
|
|
74
|
+
if (!src)
|
|
75
|
+
return undefined;
|
|
76
|
+
return {
|
|
77
|
+
configurable: true,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
+
value: src[key],
|
|
81
|
+
writable: true
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ColumnPinningState, type ColumnResizeMode, type ColumnSizingState, type VisibilityState, type FilterFn, type Row, type RowData, type Table } from '@tanstack/table-core';
|
|
2
|
+
import type { DataTableColumn, DataTableLeafColumn } from './types';
|
|
3
|
+
declare module '@tanstack/table-core' {
|
|
4
|
+
interface FilterFns {
|
|
5
|
+
oneOf: FilterFn<unknown>;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export type DataTableInstance<T extends RowData> = Table<T>;
|
|
9
|
+
export type CreateDataTableOptions<T extends RowData> = {
|
|
10
|
+
data: T[];
|
|
11
|
+
columns: DataTableColumn<T>[];
|
|
12
|
+
columnResizeMode?: ColumnResizeMode;
|
|
13
|
+
initialState?: {
|
|
14
|
+
columnVisibility?: VisibilityState;
|
|
15
|
+
columnSizing?: ColumnSizingState;
|
|
16
|
+
columnPinning?: ColumnPinningState;
|
|
17
|
+
rowSelection?: Record<string, boolean>;
|
|
18
|
+
sorting?: {
|
|
19
|
+
id: string;
|
|
20
|
+
desc: boolean;
|
|
21
|
+
}[];
|
|
22
|
+
columnFilters?: {
|
|
23
|
+
id: string;
|
|
24
|
+
value: unknown;
|
|
25
|
+
}[];
|
|
26
|
+
};
|
|
27
|
+
getRowId?: (row: T, index: number, parent?: Row<T>) => string;
|
|
28
|
+
enableRowSelection?: boolean | ((row: Row<T>) => boolean);
|
|
29
|
+
enableMultiRowSelection?: boolean | ((row: Row<T>) => boolean);
|
|
30
|
+
enableSorting?: boolean;
|
|
31
|
+
debugTable?: boolean;
|
|
32
|
+
onColumnVisibilityChange?: (visibility: VisibilityState) => void;
|
|
33
|
+
};
|
|
34
|
+
export declare function createTable<T extends RowData>(options: CreateDataTableOptions<T>): Table<T>;
|
|
35
|
+
export declare function getColumnId<T extends RowData>(column: DataTableLeafColumn<T>): string;
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
// createFacetedRowModel,
|
|
3
|
-
// createFacetedMinMaxValues,
|
|
4
|
-
// createFacetedUniqueValues,
|
|
5
|
-
createTable as createTanStackTable, filterFns, renderComponent, renderSnippet, rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures } from '@tanstack/svelte-table';
|
|
6
|
-
import { createAtom } from '@tanstack/svelte-store';
|
|
1
|
+
import { getCoreRowModel, getSortedRowModel, getFilteredRowModel, getFacetedRowModel, getFacetedUniqueValues, getFacetedMinMaxValues } from '@tanstack/table-core';
|
|
7
2
|
import { useLocaleContext } from '@ark-ui/svelte/locale';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
columnSizingFeature,
|
|
11
|
-
columnResizingFeature,
|
|
12
|
-
columnFilteringFeature,
|
|
13
|
-
columnFacetingFeature,
|
|
14
|
-
columnPinningFeature,
|
|
15
|
-
columnOrderingFeature,
|
|
16
|
-
rowSelectionFeature,
|
|
17
|
-
rowSortingFeature
|
|
18
|
-
});
|
|
3
|
+
import { createSvelteTable } from './create-svelte-table.svelte';
|
|
4
|
+
import { renderComponent, renderSnippet } from './render-helpers';
|
|
19
5
|
function oneOfFilterFn(row, columnId, filterValue) {
|
|
20
6
|
return filterValue.includes(String(row.getValue(columnId)));
|
|
21
7
|
}
|
|
@@ -26,33 +12,35 @@ export function createTable(options) {
|
|
|
26
12
|
...createColumnVisibility(options.columns),
|
|
27
13
|
...options.initialState?.columnVisibility
|
|
28
14
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const table = createTanStackTable({
|
|
33
|
-
_features: dataTableFeatures,
|
|
34
|
-
_rowModels: {
|
|
35
|
-
sortedRowModel: createSortedRowModel(sortFns),
|
|
36
|
-
filteredRowModel: createFilteredRowModel({ ...filterFns, oneOf: oneOfFilterFn })
|
|
37
|
-
// facetedRowModel: createFacetedRowModel(),
|
|
38
|
-
// facetedMinMaxValues: createFacetedMinMaxValues(),
|
|
39
|
-
// facetedUniqueValues: createFacetedUniqueValues()
|
|
15
|
+
const table = createSvelteTable({
|
|
16
|
+
get data() {
|
|
17
|
+
return options.data;
|
|
40
18
|
},
|
|
19
|
+
columns: createColumns(options.columns, localeCtx),
|
|
20
|
+
getCoreRowModel: getCoreRowModel(),
|
|
21
|
+
getSortedRowModel: getSortedRowModel(),
|
|
22
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
23
|
+
getFacetedRowModel: getFacetedRowModel(),
|
|
24
|
+
getFacetedUniqueValues: getFacetedUniqueValues(),
|
|
25
|
+
getFacetedMinMaxValues: getFacetedMinMaxValues(),
|
|
41
26
|
columnResizeMode: options.columnResizeMode,
|
|
42
27
|
getRowId: options.getRowId,
|
|
43
28
|
enableRowSelection: options.enableRowSelection ?? false,
|
|
44
29
|
enableMultiRowSelection: options.enableMultiRowSelection,
|
|
45
30
|
enableSorting: options.enableSorting,
|
|
46
31
|
debugTable: options.debugTable,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
get columns() {
|
|
51
|
-
return createColumns(options.columns, localeCtx);
|
|
32
|
+
filterFns: {
|
|
33
|
+
oneOf: oneOfFilterFn
|
|
52
34
|
},
|
|
53
|
-
...(
|
|
35
|
+
...(options.onColumnVisibilityChange
|
|
36
|
+
? {
|
|
37
|
+
onColumnVisibilityChange: (updater) => {
|
|
38
|
+
const newVis = typeof updater === 'function' ? updater(table.getState().columnVisibility) : updater;
|
|
39
|
+
options.onColumnVisibilityChange(newVis);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
: {}),
|
|
54
43
|
initialState: {
|
|
55
|
-
...options.initialState,
|
|
56
44
|
columnVisibility: initialColumnVisibility,
|
|
57
45
|
columnSizing: {
|
|
58
46
|
...createColumnSizing(options.columns),
|
|
@@ -63,25 +51,7 @@ export function createTable(options) {
|
|
|
63
51
|
sorting: options.initialState?.sorting ?? [],
|
|
64
52
|
columnFilters: options.initialState?.columnFilters ?? []
|
|
65
53
|
}
|
|
66
|
-
}
|
|
67
|
-
columnVisibility: state.columnVisibility,
|
|
68
|
-
columnSizing: state.columnSizing,
|
|
69
|
-
columnResizing: state.columnResizing,
|
|
70
|
-
rowSelection: state.rowSelection,
|
|
71
|
-
sorting: state.sorting,
|
|
72
|
-
columnFilters: state.columnFilters
|
|
73
|
-
}));
|
|
74
|
-
if (columnVisibilityAtom && options.onColumnVisibilityChange) {
|
|
75
|
-
const { onColumnVisibilityChange } = options;
|
|
76
|
-
let initialized = false;
|
|
77
|
-
columnVisibilityAtom.subscribe((value) => {
|
|
78
|
-
if (!initialized) {
|
|
79
|
-
initialized = true;
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
onColumnVisibilityChange(value);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
54
|
+
});
|
|
85
55
|
return table;
|
|
86
56
|
}
|
|
87
57
|
function createColumnVisibility(columns) {
|
|
@@ -128,8 +98,8 @@ function createColumns(columns, localeCtx) {
|
|
|
128
98
|
enableResizing: column.enableResizing,
|
|
129
99
|
enableHiding: getColumnEnableHiding(column, columnId),
|
|
130
100
|
enableSorting: column.enableSorting,
|
|
131
|
-
enableColumnFilter: column.enableColumnFilter,
|
|
132
101
|
sortDescFirst: column.sortDescFirst,
|
|
102
|
+
enableColumnFilter: column.enableColumnFilter,
|
|
133
103
|
...(derivedFilterFn !== undefined ? { filterFn: derivedFilterFn } : {}),
|
|
134
104
|
meta: {
|
|
135
105
|
align: column.align,
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.table-checkbox {
|
|
2
|
+
appearance: none;
|
|
3
|
+
-webkit-appearance: none;
|
|
4
|
+
flex-shrink: 0;
|
|
5
|
+
border-radius: 2px;
|
|
6
|
+
border: 1px solid var(--compote-border);
|
|
7
|
+
background-color: transparent;
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
transition:
|
|
10
|
+
border-color 150ms ease,
|
|
11
|
+
background-color 150ms ease;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.table-checkbox:hover:not(:disabled) {
|
|
15
|
+
border-color: color-mix(in srgb, var(--compote-primary) 50%, transparent);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.table-checkbox:checked {
|
|
19
|
+
border-color: var(--compote-primary);
|
|
20
|
+
background-color: var(--compote-primary);
|
|
21
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3e%3cpolyline points='216 72 104 184 48 128' fill='none' stroke='white' stroke-width='32' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
|
22
|
+
background-repeat: no-repeat;
|
|
23
|
+
background-position: center;
|
|
24
|
+
background-size: 70%;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.table-checkbox:indeterminate {
|
|
28
|
+
border-color: var(--compote-primary);
|
|
29
|
+
background-color: var(--compote-primary);
|
|
30
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3e%3cline x1='40' y1='128' x2='216' y2='128' stroke='white' stroke-width='32' stroke-linecap='round'/%3e%3c/svg%3e");
|
|
31
|
+
background-repeat: no-repeat;
|
|
32
|
+
background-position: center;
|
|
33
|
+
background-size: 70%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.table-checkbox:disabled {
|
|
37
|
+
pointer-events: none;
|
|
38
|
+
opacity: 0.5;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.table-checkbox:focus-visible {
|
|
42
|
+
outline: 2px solid var(--compote-ring);
|
|
43
|
+
outline-offset: 2px;
|
|
44
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends RowData">
|
|
2
2
|
import { onDestroy } from 'svelte';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Column, RowData } from '@tanstack/table-core';
|
|
4
4
|
import * as Popover from '../popover';
|
|
5
5
|
import * as ScrollArea from '../scroll-area';
|
|
6
6
|
import Checkbox from '../checkbox/checkbox.svelte';
|
|
7
7
|
import { cn } from 'tailwind-variants';
|
|
8
|
-
import
|
|
8
|
+
import { getReactiveTableState, type DataTableInstance } from './data-table-utils';
|
|
9
9
|
import NumberInput from '../number-input/number-input.svelte';
|
|
10
10
|
import * as Field from '../field';
|
|
11
11
|
|
|
@@ -21,21 +21,24 @@
|
|
|
21
21
|
let localNumMax: Record<string, number> = $state({});
|
|
22
22
|
const timers: Record<string, ReturnType<typeof setTimeout>> = {};
|
|
23
23
|
|
|
24
|
-
const columnFilters = $derived(table.
|
|
24
|
+
const columnFilters = $derived(getReactiveTableState(table).columnFilters);
|
|
25
25
|
const activeCount = $derived(columnFilters.length);
|
|
26
|
-
const filterableColumns = $derived
|
|
26
|
+
const filterableColumns = $derived.by(() => {
|
|
27
|
+
getReactiveTableState(table);
|
|
28
|
+
return table.getAllLeafColumns().filter((col) => col.getCanFilter());
|
|
29
|
+
});
|
|
27
30
|
|
|
28
31
|
onDestroy(() => {
|
|
29
32
|
Object.values(timers).forEach(clearTimeout);
|
|
30
33
|
});
|
|
31
34
|
|
|
32
|
-
function getColumnType(column: Column<
|
|
35
|
+
function getColumnType(column: Column<T, unknown>): string | undefined {
|
|
33
36
|
return (column.columnDef.meta as Record<string, unknown> | undefined)?.type as
|
|
34
37
|
| string
|
|
35
38
|
| undefined;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
function getColumnLabel(column: Column<
|
|
41
|
+
function getColumnLabel(column: Column<T, unknown>): string {
|
|
39
42
|
return typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id;
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -48,7 +51,7 @@
|
|
|
48
51
|
table.resetColumnFilters();
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
function handleTextInput(column: Column<
|
|
54
|
+
function handleTextInput(column: Column<T, unknown>, value: string) {
|
|
52
55
|
localText[column.id] = value;
|
|
53
56
|
clearTimeout(timers[column.id]);
|
|
54
57
|
timers[column.id] = setTimeout(() => {
|
|
@@ -57,7 +60,7 @@
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
function handleNumericInput(
|
|
60
|
-
column: Column<
|
|
63
|
+
column: Column<T, unknown>,
|
|
61
64
|
which: 'min' | 'max',
|
|
62
65
|
value: number | null
|
|
63
66
|
) {
|
|
@@ -76,33 +79,27 @@
|
|
|
76
79
|
}, 300);
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
function getSelectValues(column: Column<
|
|
82
|
+
function getSelectValues(column: Column<T, unknown>): string[] {
|
|
80
83
|
return (column.getFilterValue() as string[] | undefined) ?? [];
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
function handleSelectChange(
|
|
84
|
-
column: Column<DataTableFeatures, T, CellData>,
|
|
85
|
-
value: string,
|
|
86
|
-
checked: boolean
|
|
87
|
-
) {
|
|
86
|
+
function handleSelectChange(column: Column<T, unknown>, value: string, checked: boolean) {
|
|
88
87
|
const current = getSelectValues(column);
|
|
89
88
|
const next = checked ? [...current, value] : current.filter((v) => v !== value);
|
|
90
89
|
column.setFilterValue(next.length ? next : undefined);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
function getFacetedValues(column: Column<
|
|
92
|
+
function getFacetedValues(column: Column<T, unknown>): string[] {
|
|
94
93
|
return Array.from(column.getFacetedUniqueValues().keys()).map(String).sort();
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
function getFacetedMinMax(
|
|
98
|
-
column: Column<DataTableFeatures, T, CellData>
|
|
99
|
-
): [number | undefined, number | undefined] {
|
|
96
|
+
function getFacetedMinMax(column: Column<T, unknown>): [number | undefined, number | undefined] {
|
|
100
97
|
const vals = column.getFacetedMinMaxValues();
|
|
101
98
|
return vals ? [vals[0] as number, vals[1] as number] : [undefined, undefined];
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
function getColumnFormatOptions(
|
|
105
|
-
column: Column<
|
|
102
|
+
column: Column<T, unknown>
|
|
106
103
|
): Intl.NumberFormatOptions | undefined {
|
|
107
104
|
return (column.columnDef.meta as Record<string, unknown> | undefined)?.formatOptions as
|
|
108
105
|
| Intl.NumberFormatOptions
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RowData } from '@tanstack/
|
|
2
|
-
import type
|
|
1
|
+
import type { RowData } from '@tanstack/table-core';
|
|
2
|
+
import { type DataTableInstance } from './data-table-utils';
|
|
3
3
|
declare function $$render<T extends RowData>(): {
|
|
4
4
|
props: {
|
|
5
5
|
table: DataTableInstance<T>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends RowData">
|
|
2
|
-
import type {
|
|
2
|
+
import type { RowData } from '@tanstack/table-core';
|
|
3
3
|
import * as Popover from '../popover';
|
|
4
4
|
import * as ScrollArea from '../scroll-area';
|
|
5
5
|
import Checkbox from '../checkbox/checkbox.svelte';
|
|
6
|
-
import
|
|
6
|
+
import { getReactiveTableState, type DataTableInstance } from './data-table-utils';
|
|
7
7
|
|
|
8
8
|
type Props = {
|
|
9
9
|
table: DataTableInstance<T>;
|
|
@@ -12,23 +12,24 @@
|
|
|
12
12
|
|
|
13
13
|
let { table, triggerLabel = 'Columns' }: Props = $props();
|
|
14
14
|
|
|
15
|
-
const columnVisibility = $derived(table.
|
|
16
|
-
const
|
|
15
|
+
const columnVisibility = $derived(getReactiveTableState(table).columnVisibility);
|
|
16
|
+
const allLeafColumns = $derived.by(() => {
|
|
17
|
+
getReactiveTableState(table);
|
|
18
|
+
return table.getAllLeafColumns();
|
|
19
|
+
});
|
|
20
|
+
const allColumnsVisible = $derived(
|
|
21
|
+
allLeafColumns.every((c) => !c.getCanHide() || columnVisibility[c.id] !== false)
|
|
22
|
+
);
|
|
17
23
|
const someColumnsVisible = $derived(
|
|
18
|
-
|
|
24
|
+
allLeafColumns.some((c) => c.getCanHide() && columnVisibility[c.id] !== false)
|
|
19
25
|
);
|
|
20
26
|
const allColumnsVisibilityState = $derived(
|
|
21
|
-
allColumnsVisible ? true : someColumnsVisible ? 'indeterminate' : false
|
|
27
|
+
allColumnsVisible ? true : someColumnsVisible ? ('indeterminate' as const) : false
|
|
22
28
|
);
|
|
23
29
|
|
|
24
|
-
function getColumnLabel(column:
|
|
30
|
+
function getColumnLabel(column: { columnDef: { header?: unknown }; id: string }) {
|
|
25
31
|
return typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id;
|
|
26
32
|
}
|
|
27
|
-
|
|
28
|
-
function getColumnIsVisible(column: Column<DataTableFeatures, T, CellData>, state: unknown) {
|
|
29
|
-
void state;
|
|
30
|
-
return column.getIsVisible();
|
|
31
|
-
}
|
|
32
33
|
</script>
|
|
33
34
|
|
|
34
35
|
<Popover.Root positioning={{ placement: 'bottom-end' }}>
|
|
@@ -52,12 +53,12 @@
|
|
|
52
53
|
<ScrollArea.Viewport>
|
|
53
54
|
<ScrollArea.Content class="py-1 pe-3">
|
|
54
55
|
<div class="flex flex-col">
|
|
55
|
-
{#each
|
|
56
|
+
{#each allLeafColumns as column (column.id)}
|
|
56
57
|
<Checkbox
|
|
57
58
|
size="md"
|
|
58
59
|
label={getColumnLabel(column)}
|
|
59
60
|
class="min-h-8 rounded-sm px-2 hover:bg-surface-2"
|
|
60
|
-
checked={
|
|
61
|
+
checked={columnVisibility[column.id] !== false}
|
|
61
62
|
disabled={!column.getCanHide()}
|
|
62
63
|
onCheckedChange={({ checked }) => column.toggleVisibility(checked === true)}
|
|
63
64
|
/>
|
package/dist/components/{data-table → data-table-v8}/data-table-column-visibility.svelte.d.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { RowData } from '@tanstack/
|
|
2
|
-
import type
|
|
1
|
+
import type { RowData } from '@tanstack/table-core';
|
|
2
|
+
import { type DataTableInstance } from './data-table-utils';
|
|
3
3
|
declare function $$render<T extends RowData>(): {
|
|
4
4
|
props: {
|
|
5
5
|
table: DataTableInstance<T>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends RowData">
|
|
2
|
+
import type { HeaderGroup, RowData } from '@tanstack/table-core';
|
|
3
|
+
import { cn } from 'tailwind-variants';
|
|
4
|
+
import { PhCaretDown, PhCaretUp } from '../../icons';
|
|
5
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
6
|
+
import FlexRender from './flex-render.svelte';
|
|
7
|
+
import {
|
|
8
|
+
alignClass,
|
|
9
|
+
getColumnMeta,
|
|
10
|
+
getHeaderAriaSort,
|
|
11
|
+
getHeaderSortDirection,
|
|
12
|
+
getHeaderSortLabel,
|
|
13
|
+
getPinningStyle,
|
|
14
|
+
joinStyles,
|
|
15
|
+
justifyClass,
|
|
16
|
+
resizeHandleClass,
|
|
17
|
+
resizeHandleStyle,
|
|
18
|
+
sortButtonDirectionClass,
|
|
19
|
+
virtualColumnSizeStyle,
|
|
20
|
+
virtualGroupWithGrowSizeStyle,
|
|
21
|
+
virtualGrowColumnSizeStyle,
|
|
22
|
+
virtualSelectionColumnSizeStyle
|
|
23
|
+
} from './data-table-utils';
|
|
24
|
+
|
|
25
|
+
type Props = {
|
|
26
|
+
table: DataTableInstance<T>;
|
|
27
|
+
headerGroups: HeaderGroup<T>[];
|
|
28
|
+
headerGroupCount: number;
|
|
29
|
+
isRowSelectionEnabled: boolean;
|
|
30
|
+
isMultiRowSelectionEnabled: boolean;
|
|
31
|
+
allRowsSelectionState: boolean | 'indeterminate';
|
|
32
|
+
isVirtual?: boolean;
|
|
33
|
+
hasGrowColumn?: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
let {
|
|
37
|
+
table,
|
|
38
|
+
headerGroups,
|
|
39
|
+
headerGroupCount,
|
|
40
|
+
isRowSelectionEnabled,
|
|
41
|
+
isMultiRowSelectionEnabled,
|
|
42
|
+
allRowsSelectionState,
|
|
43
|
+
isVirtual = false,
|
|
44
|
+
hasGrowColumn = false
|
|
45
|
+
}: Props = $props();
|
|
46
|
+
|
|
47
|
+
type Header = HeaderGroup<T>['headers'][number];
|
|
48
|
+
|
|
49
|
+
function findGrowLeafHeader(header: Header): Header | undefined {
|
|
50
|
+
if (header.subHeaders.length === 0) {
|
|
51
|
+
return getColumnMeta(header.column.columnDef)?.grow ? header : undefined;
|
|
52
|
+
}
|
|
53
|
+
for (const sub of header.subHeaders) {
|
|
54
|
+
const found = findGrowLeafHeader(sub);
|
|
55
|
+
if (found) return found;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function headerCellStyle(header: Header) {
|
|
61
|
+
const canPinHeader = header.subHeaders.length === 0;
|
|
62
|
+
|
|
63
|
+
let virtualSizeStyle: string | undefined;
|
|
64
|
+
if (isVirtual) {
|
|
65
|
+
const isGrowLeaf = canPinHeader && getColumnMeta(header.column.columnDef)?.grow;
|
|
66
|
+
if (isGrowLeaf) {
|
|
67
|
+
virtualSizeStyle = virtualGrowColumnSizeStyle();
|
|
68
|
+
} else {
|
|
69
|
+
const growLeaf = findGrowLeafHeader(header);
|
|
70
|
+
virtualSizeStyle = growLeaf
|
|
71
|
+
? virtualGroupWithGrowSizeStyle(header.getSize() - growLeaf.getSize())
|
|
72
|
+
: virtualColumnSizeStyle(header.getSize());
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return joinStyles(
|
|
77
|
+
virtualSizeStyle,
|
|
78
|
+
canPinHeader ? getPinningStyle(header.column, table, true, isRowSelectionEnabled) : undefined
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function selectionHeaderStyle() {
|
|
83
|
+
return isVirtual
|
|
84
|
+
? joinStyles(
|
|
85
|
+
virtualSelectionColumnSizeStyle(),
|
|
86
|
+
'min-width: 40px',
|
|
87
|
+
'max-width: 40px',
|
|
88
|
+
'position: sticky',
|
|
89
|
+
'left: 0',
|
|
90
|
+
'z-index: 30'
|
|
91
|
+
)
|
|
92
|
+
: 'width: 40px; min-width: 40px; max-width: 40px; position: sticky; left: 0; z-index: 15';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function headerRowStyle() {
|
|
96
|
+
if (!isVirtual) return undefined;
|
|
97
|
+
return joinStyles('display: flex', 'width: 100%');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function shouldRenderSelectionCheckbox(headerGroupIndex: number) {
|
|
101
|
+
if (!isMultiRowSelectionEnabled) return false;
|
|
102
|
+
return headerGroupIndex === headerGroupCount - 1;
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<thead
|
|
107
|
+
class="sticky top-0 z-20 bg-surface-2 text-left text-ink-dim"
|
|
108
|
+
style={isVirtual ? 'display: grid; position: sticky; top: 0; z-index: 20' : undefined}
|
|
109
|
+
>
|
|
110
|
+
{#each headerGroups as headerGroup, headerGroupIndex (headerGroup.id)}
|
|
111
|
+
{@const visibleHeaders = headerGroup.headers.filter((header) => header.colSpan > 0)}
|
|
112
|
+
<tr class="h-9" style={headerRowStyle()}>
|
|
113
|
+
{#if isRowSelectionEnabled}
|
|
114
|
+
<th
|
|
115
|
+
class={cn(
|
|
116
|
+
'h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 text-center align-middle leading-5 font-medium',
|
|
117
|
+
isVirtual && 'items-center justify-center'
|
|
118
|
+
)}
|
|
119
|
+
style={selectionHeaderStyle()}
|
|
120
|
+
>
|
|
121
|
+
{#if shouldRenderSelectionCheckbox(headerGroupIndex)}
|
|
122
|
+
<input
|
|
123
|
+
type="checkbox"
|
|
124
|
+
aria-label="Select all rows"
|
|
125
|
+
class="table-checkbox mx-auto block size-4"
|
|
126
|
+
checked={allRowsSelectionState === true}
|
|
127
|
+
indeterminate={allRowsSelectionState === 'indeterminate'}
|
|
128
|
+
onchange={(e) => table.toggleAllRowsSelected(e.currentTarget.checked)}
|
|
129
|
+
/>
|
|
130
|
+
{/if}
|
|
131
|
+
</th>
|
|
132
|
+
{/if}
|
|
133
|
+
{#each visibleHeaders as header, headerIndex (header.id)}
|
|
134
|
+
{@const columnDef = getColumnMeta(header.column.columnDef)}
|
|
135
|
+
{@const sortDirection = getHeaderSortDirection(header)}
|
|
136
|
+
<th
|
|
137
|
+
class={cn(
|
|
138
|
+
'relative h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 align-middle leading-5 font-medium',
|
|
139
|
+
isVirtual && 'items-center',
|
|
140
|
+
isVirtual && justifyClass(columnDef?.align),
|
|
141
|
+
alignClass(columnDef?.align)
|
|
142
|
+
)}
|
|
143
|
+
colspan={header.colSpan}
|
|
144
|
+
aria-sort={header.column.getCanSort() ? getHeaderAriaSort(sortDirection) : undefined}
|
|
145
|
+
style={headerCellStyle(header)}
|
|
146
|
+
>
|
|
147
|
+
{#if !header.isPlaceholder}
|
|
148
|
+
{#if header.column.getCanSort()}
|
|
149
|
+
<button
|
|
150
|
+
type="button"
|
|
151
|
+
class={cn(
|
|
152
|
+
'inline-flex max-w-full appearance-none items-center gap-1 rounded-sm border-0 bg-transparent p-0 align-middle text-sm leading-5 text-inherit outline-none hover:text-ink data-focus-visible:outline-2 data-focus-visible:outline-offset-2 data-focus-visible:outline-ring',
|
|
153
|
+
justifyClass(columnDef?.align),
|
|
154
|
+
sortButtonDirectionClass(columnDef?.align)
|
|
155
|
+
)}
|
|
156
|
+
aria-label={`${getHeaderSortLabel(sortDirection)}. Toggle sorting.`}
|
|
157
|
+
onclick={header.column.getToggleSortingHandler()}
|
|
158
|
+
>
|
|
159
|
+
<span class="min-w-0 truncate">
|
|
160
|
+
<FlexRender
|
|
161
|
+
content={header.column.columnDef.header}
|
|
162
|
+
context={header.getContext()}
|
|
163
|
+
/>
|
|
164
|
+
</span>
|
|
165
|
+
<span
|
|
166
|
+
class="inline-flex size-3.5 shrink-0 items-center justify-center text-ink-dim"
|
|
167
|
+
>
|
|
168
|
+
{#if sortDirection === 'asc'}
|
|
169
|
+
<PhCaretUp class="size-3.5" />
|
|
170
|
+
{:else if sortDirection === 'desc'}
|
|
171
|
+
<PhCaretDown class="size-3.5" />
|
|
172
|
+
{/if}
|
|
173
|
+
</span>
|
|
174
|
+
</button>
|
|
175
|
+
{:else}
|
|
176
|
+
<FlexRender content={header.column.columnDef.header} context={header.getContext()} />
|
|
177
|
+
{/if}
|
|
178
|
+
{/if}
|
|
179
|
+
{#if header.column.getCanResize()}
|
|
180
|
+
<div
|
|
181
|
+
aria-hidden="true"
|
|
182
|
+
class={resizeHandleClass(headerIndex, visibleHeaders.length)}
|
|
183
|
+
style={resizeHandleStyle(table, header)}
|
|
184
|
+
ondblclick={() => header.column.resetSize()}
|
|
185
|
+
onmousedown={header.getResizeHandler()}
|
|
186
|
+
ontouchstart={header.getResizeHandler()}
|
|
187
|
+
></div>
|
|
188
|
+
{/if}
|
|
189
|
+
</th>
|
|
190
|
+
{/each}
|
|
191
|
+
{#if !isVirtual && !hasGrowColumn}
|
|
192
|
+
<th aria-hidden="true" class="h-9 border-b border-surface-3 bg-surface-2 p-0"></th>
|
|
193
|
+
{/if}
|
|
194
|
+
</tr>
|
|
195
|
+
{/each}
|
|
196
|
+
</thead>
|
|
197
|
+
|
|
198
|
+
<style>
|
|
199
|
+
@import './data-table-checkbox.css';
|
|
200
|
+
</style>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { HeaderGroup, RowData } from '@tanstack/
|
|
2
|
-
import type {
|
|
1
|
+
import type { HeaderGroup, RowData } from '@tanstack/table-core';
|
|
2
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
3
3
|
declare function $$render<T extends RowData>(): {
|
|
4
4
|
props: {
|
|
5
5
|
table: DataTableInstance<T>;
|
|
6
|
-
headerGroups: HeaderGroup<
|
|
6
|
+
headerGroups: HeaderGroup<T>[];
|
|
7
7
|
headerGroupCount: number;
|
|
8
8
|
isRowSelectionEnabled: boolean;
|
|
9
9
|
isMultiRowSelectionEnabled: boolean;
|