compote-ui 0.55.4 → 0.56.1
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-v9/column-helper.d.ts +12 -0
- package/dist/components/data-table-v9/column-helper.js +42 -0
- package/dist/components/data-table-v9/create-table.svelte.d.ts +42 -0
- package/dist/components/data-table-v9/create-table.svelte.js +251 -0
- package/dist/components/data-table-v9/data-table-cell-content.svelte +66 -0
- package/dist/components/data-table-v9/data-table-cell-content.svelte.d.ts +28 -0
- package/dist/components/data-table-v9/data-table-foot.svelte +111 -0
- package/dist/components/data-table-v9/data-table-foot.svelte.d.ts +32 -0
- package/dist/components/{data-table/data-table-head.svelte.md → data-table-v9/data-table-head.svelte} +47 -39
- package/dist/components/data-table-v9/data-table-head.svelte.d.ts +32 -0
- package/dist/components/data-table-v9/data-table-title.svelte.d.ts +10 -0
- package/dist/components/data-table-v9/data-table-utils.d.ts +53 -0
- package/dist/components/data-table-v9/data-table-utils.js +181 -0
- package/dist/components/data-table-v9/data-table.svelte +151 -0
- package/dist/components/data-table-v9/data-table.svelte.d.ts +41 -0
- package/dist/components/data-table-v9/features.d.ts +12 -0
- package/dist/components/data-table-v9/features.js +14 -0
- package/dist/components/data-table-v9/index.d.ts +11 -0
- package/dist/components/data-table-v9/index.js +9 -0
- package/dist/components/data-table-v9/table-view-state.svelte.d.ts +74 -0
- package/dist/components/data-table-v9/table-view-state.svelte.js +182 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +380 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte.d.ts +29 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-visibility.svelte +73 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-visibility.svelte.d.ts +29 -0
- package/dist/components/data-table-v9/toolbar/data-table-search.svelte +58 -0
- package/dist/components/data-table-v9/toolbar/data-table-search.svelte.d.ts +32 -0
- package/dist/components/{data-table/data-table-toolbar.svelte.md → data-table-v9/toolbar/data-table-toolbar.svelte} +14 -15
- package/dist/components/data-table-v9/toolbar/data-table-toolbar.svelte.d.ts +12 -0
- package/dist/components/data-table-v9/types.d.ts +74 -0
- package/dist/components/data-table-v9/types.js +1 -0
- package/dist/components/data-table-v9/virtual/data-table-virtual-rows.svelte +131 -0
- package/dist/components/data-table-v9/virtual/data-table-virtual-rows.svelte.d.ts +40 -0
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +79 -0
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte.d.ts +41 -0
- package/dist/components/data-table-v9/virtual/index.d.ts +3 -0
- package/dist/components/data-table-v9/virtual/index.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/package.json +12 -2
- package/dist/components/data-table/column-helper.ts.md +0 -96
- package/dist/components/data-table/create-table.ts.md +0 -386
- package/dist/components/data-table/data-table-column-filter.svelte.md +0 -249
- package/dist/components/data-table/data-table-column-visibility.svelte.md +0 -74
- package/dist/components/data-table/data-table-new.svelte.md +0 -245
- package/dist/components/data-table/data-table-utils.ts.md +0 -179
- package/dist/components/data-table/data-table-virtual-rows.svelte.md +0 -171
- package/dist/components/data-table/data-table-virtualized.svelte.md +0 -108
- package/dist/components/data-table/data-table.svelte.md +0 -214
- package/dist/components/data-table/index.ts.md +0 -22
- package/dist/components/data-table/types.ts.md +0 -101
- package/dist/components/data-table/virtual/index.ts.md +0 -26
- /package/dist/components/{data-table/data-table-title.svelte.md → data-table-v9/data-table-title.svelte} +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends RowData">
|
|
2
|
-
import { FlexRender } from '@tanstack/svelte-table';
|
|
3
2
|
import type { HeaderGroup, RowData } from '@tanstack/svelte-table';
|
|
3
|
+
import { FlexRender } from '@tanstack/svelte-table';
|
|
4
4
|
import { cn } from 'tailwind-variants';
|
|
5
|
-
import { PhCaretDown, PhCaretUp } from '
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
5
|
+
import { PhCaretDown, PhCaretUp } from '../../icons';
|
|
6
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
7
|
+
import type { DataTableViewState } from './table-view-state.svelte';
|
|
8
|
+
import type { DataTableFeatures } from './features';
|
|
8
9
|
import {
|
|
9
10
|
alignClass,
|
|
10
11
|
getColumnMeta,
|
|
12
|
+
getGroupPinningStyle,
|
|
11
13
|
getHeaderAriaSort,
|
|
12
|
-
getHeaderSortDirection,
|
|
13
14
|
getHeaderSortLabel,
|
|
14
15
|
getPinningStyle,
|
|
15
16
|
joinStyles,
|
|
@@ -25,25 +26,12 @@
|
|
|
25
26
|
|
|
26
27
|
type Props = {
|
|
27
28
|
table: DataTableInstance<T>;
|
|
28
|
-
|
|
29
|
-
headerGroupCount: number;
|
|
30
|
-
isRowSelectionEnabled: boolean;
|
|
31
|
-
isMultiRowSelectionEnabled: boolean;
|
|
32
|
-
allRowsSelectionState: boolean | 'indeterminate';
|
|
29
|
+
view: DataTableViewState<T>;
|
|
33
30
|
isVirtual?: boolean;
|
|
34
31
|
hasGrowColumn?: boolean;
|
|
35
32
|
};
|
|
36
33
|
|
|
37
|
-
let {
|
|
38
|
-
table,
|
|
39
|
-
headerGroups,
|
|
40
|
-
headerGroupCount,
|
|
41
|
-
isRowSelectionEnabled,
|
|
42
|
-
isMultiRowSelectionEnabled,
|
|
43
|
-
allRowsSelectionState,
|
|
44
|
-
isVirtual = false,
|
|
45
|
-
hasGrowColumn = false
|
|
46
|
-
}: Props = $props();
|
|
34
|
+
let { table, view, isVirtual = false, hasGrowColumn = false }: Props = $props();
|
|
47
35
|
|
|
48
36
|
type Header = HeaderGroup<DataTableFeatures, T>['headers'][number];
|
|
49
37
|
|
|
@@ -58,11 +46,17 @@
|
|
|
58
46
|
return undefined;
|
|
59
47
|
}
|
|
60
48
|
|
|
49
|
+
function headerSortDirection(header: Header) {
|
|
50
|
+
void view.sorting;
|
|
51
|
+
return header.column.getIsSorted();
|
|
52
|
+
}
|
|
53
|
+
|
|
61
54
|
function headerCellStyle(header: Header) {
|
|
62
55
|
const canPinHeader = header.subHeaders.length === 0;
|
|
63
56
|
|
|
64
57
|
let virtualSizeStyle: string | undefined;
|
|
65
58
|
if (isVirtual) {
|
|
59
|
+
void view.columnSizing;
|
|
66
60
|
const isGrowLeaf = canPinHeader && getColumnMeta(header.column.columnDef)?.grow;
|
|
67
61
|
if (isGrowLeaf) {
|
|
68
62
|
virtualSizeStyle = virtualGrowColumnSizeStyle();
|
|
@@ -76,7 +70,14 @@
|
|
|
76
70
|
|
|
77
71
|
return joinStyles(
|
|
78
72
|
virtualSizeStyle,
|
|
79
|
-
canPinHeader
|
|
73
|
+
canPinHeader
|
|
74
|
+
? getPinningStyle(header.column, table, view, true, view.isRowSelectionEnabled)
|
|
75
|
+
: getGroupPinningStyle(
|
|
76
|
+
header,
|
|
77
|
+
view.getHeaderSection(header),
|
|
78
|
+
view,
|
|
79
|
+
view.isRowSelectionEnabled
|
|
80
|
+
)
|
|
80
81
|
);
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -99,8 +100,8 @@
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
function shouldRenderSelectionCheckbox(headerGroupIndex: number) {
|
|
102
|
-
if (!isMultiRowSelectionEnabled) return false;
|
|
103
|
-
return headerGroupIndex ===
|
|
103
|
+
if (!view.isMultiRowSelectionEnabled) return false;
|
|
104
|
+
return headerGroupIndex === view.headerGroups.length - 1;
|
|
104
105
|
}
|
|
105
106
|
</script>
|
|
106
107
|
|
|
@@ -108,11 +109,12 @@
|
|
|
108
109
|
class="sticky top-0 z-20 bg-surface-2 text-left text-ink-dim"
|
|
109
110
|
style={isVirtual ? 'display: grid; position: sticky; top: 0; z-index: 20' : undefined}
|
|
110
111
|
>
|
|
111
|
-
{#each headerGroups as headerGroup, headerGroupIndex (headerGroup.id)}
|
|
112
|
+
{#each view.headerGroups as headerGroup, headerGroupIndex (`${headerGroup.id}:${headerGroup.headers.map((header) => `${header.id}:${header.colSpan}`).join('|')}`)}
|
|
112
113
|
{@const visibleHeaders = headerGroup.headers.filter((header) => header.colSpan > 0)}
|
|
113
114
|
<tr class="h-9" style={headerRowStyle()}>
|
|
114
|
-
{#if isRowSelectionEnabled}
|
|
115
|
+
{#if view.isRowSelectionEnabled}
|
|
115
116
|
<th
|
|
117
|
+
scope="col"
|
|
116
118
|
class={cn(
|
|
117
119
|
'h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 text-center align-middle leading-5 font-medium',
|
|
118
120
|
isVirtual && 'items-center justify-center'
|
|
@@ -120,25 +122,29 @@
|
|
|
120
122
|
style={selectionHeaderStyle()}
|
|
121
123
|
>
|
|
122
124
|
{#if shouldRenderSelectionCheckbox(headerGroupIndex)}
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
+
<input
|
|
126
|
+
type="checkbox"
|
|
125
127
|
aria-label="Select all rows"
|
|
126
|
-
class="mx-auto size-4"
|
|
127
|
-
checked={allRowsSelectionState}
|
|
128
|
-
|
|
128
|
+
class="table-checkbox mx-auto block size-4"
|
|
129
|
+
checked={view.allRowsSelectionState === true}
|
|
130
|
+
indeterminate={view.allRowsSelectionState === 'indeterminate'}
|
|
131
|
+
onchange={(e) => table.toggleAllRowsSelected(e.currentTarget.checked)}
|
|
129
132
|
/>
|
|
130
133
|
{/if}
|
|
131
134
|
</th>
|
|
132
135
|
{/if}
|
|
133
|
-
{#each visibleHeaders as header, headerIndex (header.id)}
|
|
134
|
-
{@const
|
|
135
|
-
{@const sortDirection =
|
|
136
|
+
{#each visibleHeaders as header, headerIndex (`${header.id}:${view.getHeaderSection(header) ?? ''}:${header.colSpan}:${header.column.getIsVisible()}`)}
|
|
137
|
+
{@const meta = getColumnMeta(header.column.columnDef)}
|
|
138
|
+
{@const sortDirection = headerSortDirection(header)}
|
|
139
|
+
{@const continuesInNextFragment =
|
|
140
|
+
visibleHeaders[headerIndex + 1]?.column.id === header.column.id}
|
|
136
141
|
<th
|
|
142
|
+
scope="col"
|
|
137
143
|
class={cn(
|
|
138
144
|
'relative h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 align-middle leading-5 font-medium',
|
|
139
145
|
isVirtual && 'items-center',
|
|
140
|
-
isVirtual && justifyClass(
|
|
141
|
-
alignClass(
|
|
146
|
+
isVirtual && justifyClass(meta?.align),
|
|
147
|
+
alignClass(meta?.align)
|
|
142
148
|
)}
|
|
143
149
|
colspan={header.colSpan}
|
|
144
150
|
aria-sort={header.column.getCanSort() ? getHeaderAriaSort(sortDirection) : undefined}
|
|
@@ -150,8 +156,8 @@
|
|
|
150
156
|
type="button"
|
|
151
157
|
class={cn(
|
|
152
158
|
'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(
|
|
154
|
-
sortButtonDirectionClass(
|
|
159
|
+
justifyClass(meta?.align),
|
|
160
|
+
sortButtonDirectionClass(meta?.align)
|
|
155
161
|
)}
|
|
156
162
|
aria-label={`${getHeaderSortLabel(sortDirection)}. Toggle sorting.`}
|
|
157
163
|
onclick={header.column.getToggleSortingHandler()}
|
|
@@ -173,11 +179,13 @@
|
|
|
173
179
|
<FlexRender {header} />
|
|
174
180
|
{/if}
|
|
175
181
|
{/if}
|
|
176
|
-
|
|
182
|
+
<!-- A group split by pinning renders as adjacent fragments; skip the
|
|
183
|
+
divider between them so the group reads as one continuous header. -->
|
|
184
|
+
{#if header.column.getCanResize() && !continuesInNextFragment}
|
|
177
185
|
<div
|
|
178
186
|
aria-hidden="true"
|
|
179
187
|
class={resizeHandleClass(headerIndex, visibleHeaders.length)}
|
|
180
|
-
style={resizeHandleStyle(table, header)}
|
|
188
|
+
style={resizeHandleStyle(table, header, view.columnResizing)}
|
|
181
189
|
ondblclick={() => header.column.resetSize()}
|
|
182
190
|
onmousedown={header.getResizeHandler()}
|
|
183
191
|
ontouchstart={header.getResizeHandler()}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { RowData } from '@tanstack/svelte-table';
|
|
2
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
3
|
+
import type { DataTableViewState } from './table-view-state.svelte';
|
|
4
|
+
declare function $$render<T extends RowData>(): {
|
|
5
|
+
props: {
|
|
6
|
+
table: DataTableInstance<T>;
|
|
7
|
+
view: DataTableViewState<T>;
|
|
8
|
+
isVirtual?: boolean;
|
|
9
|
+
hasGrowColumn?: boolean;
|
|
10
|
+
};
|
|
11
|
+
exports: {};
|
|
12
|
+
bindings: "";
|
|
13
|
+
slots: {};
|
|
14
|
+
events: {};
|
|
15
|
+
};
|
|
16
|
+
declare class __sveltets_Render<T extends RowData> {
|
|
17
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
18
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
19
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
20
|
+
bindings(): "";
|
|
21
|
+
exports(): {};
|
|
22
|
+
}
|
|
23
|
+
interface $$IsomorphicComponent {
|
|
24
|
+
new <T extends RowData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
25
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
26
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
27
|
+
<T extends RowData>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
28
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
29
|
+
}
|
|
30
|
+
declare const DataTableHead: $$IsomorphicComponent;
|
|
31
|
+
type DataTableHead<T extends RowData> = InstanceType<typeof DataTableHead<T>>;
|
|
32
|
+
export default DataTableHead;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { type ClassValue } from 'tailwind-variants';
|
|
4
|
+
type Props = Omit<HTMLAttributes<HTMLHeadingElement>, 'class'> & {
|
|
5
|
+
class?: ClassValue;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
};
|
|
8
|
+
declare const DataTableTitle: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type DataTableTitle = ReturnType<typeof DataTableTitle>;
|
|
10
|
+
export default DataTableTitle;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Column, ColumnPinningState, ColumnSizingState, ColumnVisibilityState, Header, Row, RowData, SvelteTable, TableState } from '@tanstack/svelte-table';
|
|
2
|
+
import type { DataTableColumnMeta } from './types';
|
|
3
|
+
import type { DataTableFeatures } from './features';
|
|
4
|
+
export type DataTableInstance<T extends RowData> = SvelteTable<DataTableFeatures, T>;
|
|
5
|
+
export type DataTableTrackedState = {
|
|
6
|
+
columnPinning: ColumnPinningState;
|
|
7
|
+
columnResizing: TableState<DataTableFeatures>['columnResizing'];
|
|
8
|
+
columnSizing: ColumnSizingState;
|
|
9
|
+
columnVisibility: ColumnVisibilityState;
|
|
10
|
+
};
|
|
11
|
+
export declare function alignClass(align: DataTableColumnMeta['align']): "text-right" | "text-center" | "text-left";
|
|
12
|
+
export declare function justifyClass(align: DataTableColumnMeta['align']): "justify-end" | "justify-center" | "justify-start";
|
|
13
|
+
export declare function sortButtonDirectionClass(align: DataTableColumnMeta['align']): "flex-row-reverse" | "flex-row";
|
|
14
|
+
export declare function columnSizeStyle(size: number): string;
|
|
15
|
+
export declare function selectionColumnSizeStyle(): string;
|
|
16
|
+
export declare function virtualColumnSizeStyle(size: number): string;
|
|
17
|
+
export declare function virtualSelectionColumnSizeStyle(): string;
|
|
18
|
+
export declare function tableSizeStyle<T extends RowData>(table: DataTableInstance<T>, isRowSelectionEnabled: boolean, state: DataTableTrackedState): string;
|
|
19
|
+
export declare function virtualGrowColumnSizeStyle(): string;
|
|
20
|
+
export declare function virtualGroupWithGrowSizeStyle(fixedPortion: number): string;
|
|
21
|
+
export declare function resizeHandleStyle<T extends RowData>(table: DataTableInstance<T>, header: Header<DataTableFeatures, T, unknown>, columnResizing: TableState<DataTableFeatures>['columnResizing']): string | undefined;
|
|
22
|
+
export declare function resizeHandleClass(headerIndex: number, headerCount: number): import("tailwind-variants").CnReturn;
|
|
23
|
+
export declare function getHeaderSortLabel(sortDirection: false | 'asc' | 'desc'): "Sorted ascending" | "Sorted descending" | "Not sorted";
|
|
24
|
+
export declare function getHeaderAriaSort(sortDirection: false | 'asc' | 'desc'): "none" | "ascending" | "descending";
|
|
25
|
+
export declare function getRowCells<T extends RowData>(row: Row<DataTableFeatures, T>, state: DataTableTrackedState): import("@tanstack/svelte-table").Cell_Core<{
|
|
26
|
+
rowSortingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
27
|
+
rowSelectionFeature: import("@tanstack/svelte-table").TableFeature;
|
|
28
|
+
columnFilteringFeature: import("@tanstack/svelte-table").TableFeature;
|
|
29
|
+
columnFacetingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
30
|
+
globalFilteringFeature: import("@tanstack/svelte-table").TableFeature;
|
|
31
|
+
columnVisibilityFeature: import("@tanstack/svelte-table").TableFeature;
|
|
32
|
+
columnPinningFeature: import("@tanstack/svelte-table").TableFeature;
|
|
33
|
+
columnSizingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
34
|
+
columnResizingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
35
|
+
}, T, unknown>[];
|
|
36
|
+
export declare function getBooleanCellValue(value: unknown): boolean | undefined;
|
|
37
|
+
export declare function getPinningStyle<T extends RowData>(column: Column<DataTableFeatures, T, unknown>, table: DataTableInstance<T>, state: DataTableTrackedState, isHeader?: boolean, isRowSelectionEnabled?: boolean): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Sticky positioning for a group header whose leaf columns are pinned.
|
|
40
|
+
*
|
|
41
|
+
* A split fragment's subHeaders contain only its own section's children, so the
|
|
42
|
+
* fragment over the pinned columns sticks at the first/last pinned leaf's offset
|
|
43
|
+
* while the fragment over the scrolling columns gets no style.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getGroupPinningStyle<T extends RowData>(header: Header<DataTableFeatures, T, unknown>, section: 'left' | 'center' | 'right' | undefined, state: DataTableTrackedState, isRowSelectionEnabled?: boolean): string | undefined;
|
|
46
|
+
export declare function getUrlCellValue(value: unknown): string | undefined;
|
|
47
|
+
export declare function openUrlCell(value: string): void;
|
|
48
|
+
export declare function getColumnMeta(columnDef: {
|
|
49
|
+
meta?: unknown;
|
|
50
|
+
}): DataTableColumnMeta | undefined;
|
|
51
|
+
export declare function joinStyles(...styles: Array<string | undefined>): string;
|
|
52
|
+
export declare const TYPE_NUMBER_FORMAT_DEFAULTS: Partial<Record<string, Intl.NumberFormatOptions>>;
|
|
53
|
+
export declare function formatColumnFooter(meta: DataTableColumnMeta, values: unknown[], locale: string): string | undefined;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { cn } from 'tailwind-variants';
|
|
2
|
+
export function alignClass(align) {
|
|
3
|
+
return align === 'right' ? 'text-right' : align === 'center' ? 'text-center' : 'text-left';
|
|
4
|
+
}
|
|
5
|
+
export function justifyClass(align) {
|
|
6
|
+
return align === 'right'
|
|
7
|
+
? 'justify-end'
|
|
8
|
+
: align === 'center'
|
|
9
|
+
? 'justify-center'
|
|
10
|
+
: 'justify-start';
|
|
11
|
+
}
|
|
12
|
+
export function sortButtonDirectionClass(align) {
|
|
13
|
+
return align === 'right' ? 'flex-row-reverse' : 'flex-row';
|
|
14
|
+
}
|
|
15
|
+
export function columnSizeStyle(size) {
|
|
16
|
+
return `width: ${size}px`;
|
|
17
|
+
}
|
|
18
|
+
export function selectionColumnSizeStyle() {
|
|
19
|
+
return 'width: 40px';
|
|
20
|
+
}
|
|
21
|
+
export function virtualColumnSizeStyle(size) {
|
|
22
|
+
return `display: flex; flex: 0 0 ${size}px; width: ${size}px`;
|
|
23
|
+
}
|
|
24
|
+
export function virtualSelectionColumnSizeStyle() {
|
|
25
|
+
return 'display: flex; flex: 0 0 40px; width: 40px';
|
|
26
|
+
}
|
|
27
|
+
export function tableSizeStyle(table, isRowSelectionEnabled, state) {
|
|
28
|
+
void state.columnSizing;
|
|
29
|
+
void state.columnVisibility;
|
|
30
|
+
return `width: max(100%, ${table.getTotalSize() + (isRowSelectionEnabled ? 40 : 0)}px)`;
|
|
31
|
+
}
|
|
32
|
+
export function virtualGrowColumnSizeStyle() {
|
|
33
|
+
return 'display: flex; flex: 1; min-width: 0';
|
|
34
|
+
}
|
|
35
|
+
export function virtualGroupWithGrowSizeStyle(fixedPortion) {
|
|
36
|
+
return `display: flex; flex: 1 0 ${fixedPortion}px; width: ${fixedPortion}px`;
|
|
37
|
+
}
|
|
38
|
+
export function resizeHandleStyle(table, header, columnResizing) {
|
|
39
|
+
if (table.options.columnResizeMode !== 'onEnd')
|
|
40
|
+
return undefined;
|
|
41
|
+
const deltaOffset = columnResizing.deltaOffset;
|
|
42
|
+
if (!header.column.getIsResizing() || deltaOffset === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
return `transform: translateX(${deltaOffset}px)`;
|
|
45
|
+
}
|
|
46
|
+
export function resizeHandleClass(headerIndex, headerCount) {
|
|
47
|
+
return cn('absolute top-0 z-10 flex h-full w-2 cursor-col-resize touch-none items-center justify-center select-none before:h-4 before:w-px before:bg-border before:content-[""]', headerIndex === headerCount - 1 ? 'right-0' : '-right-1');
|
|
48
|
+
}
|
|
49
|
+
export function getHeaderSortLabel(sortDirection) {
|
|
50
|
+
if (sortDirection === 'asc')
|
|
51
|
+
return 'Sorted ascending';
|
|
52
|
+
if (sortDirection === 'desc')
|
|
53
|
+
return 'Sorted descending';
|
|
54
|
+
return 'Not sorted';
|
|
55
|
+
}
|
|
56
|
+
export function getHeaderAriaSort(sortDirection) {
|
|
57
|
+
if (sortDirection === 'asc')
|
|
58
|
+
return 'ascending';
|
|
59
|
+
if (sortDirection === 'desc')
|
|
60
|
+
return 'descending';
|
|
61
|
+
return 'none';
|
|
62
|
+
}
|
|
63
|
+
export function getRowCells(row, state) {
|
|
64
|
+
void state.columnVisibility;
|
|
65
|
+
void state.columnPinning;
|
|
66
|
+
void state.columnSizing;
|
|
67
|
+
return [
|
|
68
|
+
...row.getLeftVisibleCells(),
|
|
69
|
+
...row.getCenterVisibleCells(),
|
|
70
|
+
...row.getRightVisibleCells()
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
export function getBooleanCellValue(value) {
|
|
74
|
+
if (value === true)
|
|
75
|
+
return true;
|
|
76
|
+
if (value === false)
|
|
77
|
+
return false;
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
export function getPinningStyle(column, table, state, isHeader = false, isRowSelectionEnabled = false) {
|
|
81
|
+
void state.columnPinning;
|
|
82
|
+
void state.columnSizing;
|
|
83
|
+
const isPinned = column.getIsPinned();
|
|
84
|
+
if (!isPinned)
|
|
85
|
+
return undefined;
|
|
86
|
+
const zIndex = isHeader ? 15 : 1;
|
|
87
|
+
const selectionOffset = isRowSelectionEnabled ? 40 : 0;
|
|
88
|
+
if (isPinned === 'left') {
|
|
89
|
+
const left = column.getStart('left') + selectionOffset;
|
|
90
|
+
const leftCols = table.getLeftLeafColumns();
|
|
91
|
+
const isLastLeft = leftCols[leftCols.length - 1]?.id === column.id;
|
|
92
|
+
const shadow = !isHeader && isLastLeft
|
|
93
|
+
? 'box-shadow: -4px 0 4px -4px var(--compote-border) inset'
|
|
94
|
+
: undefined;
|
|
95
|
+
return ['position: sticky', `z-index: ${zIndex}`, `left: ${left}px`, shadow]
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.join('; ');
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const right = column.getAfter('right');
|
|
101
|
+
const rightCols = table.getRightLeafColumns();
|
|
102
|
+
const isFirstRight = rightCols[0]?.id === column.id;
|
|
103
|
+
const shadow = !isHeader && isFirstRight
|
|
104
|
+
? 'box-shadow: 4px 0 4px -4px var(--compote-border) inset'
|
|
105
|
+
: undefined;
|
|
106
|
+
return ['position: sticky', `z-index: ${zIndex}`, `right: ${right}px`, shadow]
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join('; ');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function collectLeafHeaders(header) {
|
|
112
|
+
if (header.subHeaders.length === 0)
|
|
113
|
+
return [header];
|
|
114
|
+
return header.subHeaders.flatMap((sub) => collectLeafHeaders(sub));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Sticky positioning for a group header whose leaf columns are pinned.
|
|
118
|
+
*
|
|
119
|
+
* A split fragment's subHeaders contain only its own section's children, so the
|
|
120
|
+
* fragment over the pinned columns sticks at the first/last pinned leaf's offset
|
|
121
|
+
* while the fragment over the scrolling columns gets no style.
|
|
122
|
+
*/
|
|
123
|
+
export function getGroupPinningStyle(header, section, state, isRowSelectionEnabled = false) {
|
|
124
|
+
void state.columnPinning;
|
|
125
|
+
void state.columnSizing;
|
|
126
|
+
if (section !== 'left' && section !== 'right')
|
|
127
|
+
return undefined;
|
|
128
|
+
const leafHeaders = collectLeafHeaders(header);
|
|
129
|
+
if (section === 'left') {
|
|
130
|
+
const first = leafHeaders[0];
|
|
131
|
+
if (first?.column.getIsPinned() !== 'left')
|
|
132
|
+
return undefined;
|
|
133
|
+
const left = first.column.getStart('left') + (isRowSelectionEnabled ? 40 : 0);
|
|
134
|
+
return `position: sticky; z-index: 15; left: ${left}px`;
|
|
135
|
+
}
|
|
136
|
+
const last = leafHeaders[leafHeaders.length - 1];
|
|
137
|
+
if (last?.column.getIsPinned() !== 'right')
|
|
138
|
+
return undefined;
|
|
139
|
+
return `position: sticky; z-index: 15; right: ${last.column.getAfter('right')}px`;
|
|
140
|
+
}
|
|
141
|
+
export function getUrlCellValue(value) {
|
|
142
|
+
if (typeof value !== 'string' || value.trim() === '')
|
|
143
|
+
return undefined;
|
|
144
|
+
return value;
|
|
145
|
+
}
|
|
146
|
+
export function openUrlCell(value) {
|
|
147
|
+
window.open(value, '_blank', 'noopener,noreferrer');
|
|
148
|
+
}
|
|
149
|
+
export function getColumnMeta(columnDef) {
|
|
150
|
+
return columnDef.meta;
|
|
151
|
+
}
|
|
152
|
+
export function joinStyles(...styles) {
|
|
153
|
+
return styles.filter(Boolean).join('; ');
|
|
154
|
+
}
|
|
155
|
+
// Shared with the cell formatter in create-table.svelte.ts — keep number-typed
|
|
156
|
+
// columns and their footer sums formatted identically.
|
|
157
|
+
export const TYPE_NUMBER_FORMAT_DEFAULTS = {
|
|
158
|
+
currency: { style: 'currency', currency: 'USD' },
|
|
159
|
+
percent: { style: 'percent' },
|
|
160
|
+
number: {}
|
|
161
|
+
};
|
|
162
|
+
export function formatColumnFooter(meta, values, locale) {
|
|
163
|
+
if (meta.footer) {
|
|
164
|
+
const result = meta.footer(values);
|
|
165
|
+
if (result === null || result === undefined)
|
|
166
|
+
return undefined;
|
|
167
|
+
return String(result);
|
|
168
|
+
}
|
|
169
|
+
if (meta.sum) {
|
|
170
|
+
const sum = values.reduce((acc, val) => acc + (typeof val === 'number' ? val : Number(val) || 0), 0);
|
|
171
|
+
const numDefaults = meta.type ? TYPE_NUMBER_FORMAT_DEFAULTS[meta.type] : undefined;
|
|
172
|
+
if (numDefaults !== undefined) {
|
|
173
|
+
return new Intl.NumberFormat(meta.formatLocale ?? locale, {
|
|
174
|
+
...numDefaults,
|
|
175
|
+
...meta.formatOptions
|
|
176
|
+
}).format(sum);
|
|
177
|
+
}
|
|
178
|
+
return String(sum);
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends RowData">
|
|
2
|
+
import type { RowData } from '@tanstack/svelte-table';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { cn, type ClassValue } from 'tailwind-variants';
|
|
5
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
6
|
+
import { createTableViewState } from './table-view-state.svelte';
|
|
7
|
+
import DataTableHead from './data-table-head.svelte';
|
|
8
|
+
import DataTableFoot from './data-table-foot.svelte';
|
|
9
|
+
import DataTableCellContent from './data-table-cell-content.svelte';
|
|
10
|
+
import {
|
|
11
|
+
alignClass,
|
|
12
|
+
columnSizeStyle,
|
|
13
|
+
getColumnMeta,
|
|
14
|
+
getPinningStyle,
|
|
15
|
+
getRowCells,
|
|
16
|
+
selectionColumnSizeStyle,
|
|
17
|
+
tableSizeStyle
|
|
18
|
+
} from './data-table-utils';
|
|
19
|
+
|
|
20
|
+
type Props = Omit<HTMLAttributes<HTMLDivElement>, 'class'> & {
|
|
21
|
+
table: DataTableInstance<T>;
|
|
22
|
+
caption?: string;
|
|
23
|
+
emptyMessage?: string;
|
|
24
|
+
class?: ClassValue;
|
|
25
|
+
onRowClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
26
|
+
onRowDoubleClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
table,
|
|
31
|
+
caption,
|
|
32
|
+
emptyMessage = 'No rows found',
|
|
33
|
+
class: className,
|
|
34
|
+
onRowClick,
|
|
35
|
+
onRowDoubleClick,
|
|
36
|
+
...rest
|
|
37
|
+
}: Props = $props();
|
|
38
|
+
|
|
39
|
+
const view = createTableViewState(() => table);
|
|
40
|
+
|
|
41
|
+
const visibleColumnCount = $derived(view.visibleLeafColumns.length);
|
|
42
|
+
const tableColumnCount = $derived(visibleColumnCount + (view.isRowSelectionEnabled ? 1 : 0));
|
|
43
|
+
const renderedColumnCount = $derived(tableColumnCount + 1);
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<div
|
|
47
|
+
class={cn(
|
|
48
|
+
'flex max-h-full min-h-0 flex-col overflow-hidden rounded-lg border border-surface-3 bg-surface-1',
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...rest}
|
|
52
|
+
>
|
|
53
|
+
{#if view.isColumnResizing}
|
|
54
|
+
<div aria-hidden="true" class="fixed inset-0 z-50 cursor-col-resize select-none"></div>
|
|
55
|
+
{/if}
|
|
56
|
+
|
|
57
|
+
<div class="min-h-0 flex-1 overflow-auto">
|
|
58
|
+
<table
|
|
59
|
+
class="table-fixed border-separate border-spacing-0 text-sm"
|
|
60
|
+
style={tableSizeStyle(table, view.isRowSelectionEnabled, view)}
|
|
61
|
+
>
|
|
62
|
+
<colgroup>
|
|
63
|
+
{#if view.isRowSelectionEnabled}
|
|
64
|
+
<col style={selectionColumnSizeStyle()} />
|
|
65
|
+
{/if}
|
|
66
|
+
{#each view.visibleLeafColumns as column (column.id)}
|
|
67
|
+
<col
|
|
68
|
+
style={getColumnMeta(column.columnDef)?.grow
|
|
69
|
+
? undefined
|
|
70
|
+
: columnSizeStyle(column.getSize())}
|
|
71
|
+
/>
|
|
72
|
+
{/each}
|
|
73
|
+
{#if !view.hasGrowColumn}
|
|
74
|
+
<col />
|
|
75
|
+
{/if}
|
|
76
|
+
</colgroup>
|
|
77
|
+
{#if caption}
|
|
78
|
+
<caption class="sr-only">{caption}</caption>
|
|
79
|
+
{/if}
|
|
80
|
+
<DataTableHead {table} {view} hasGrowColumn={view.hasGrowColumn} />
|
|
81
|
+
<tbody>
|
|
82
|
+
{#each view.rowModel.rows as row (row.id)}
|
|
83
|
+
{@const rowSelected = view.rowSelection[row.id] === true}
|
|
84
|
+
<tr
|
|
85
|
+
class={cn(
|
|
86
|
+
'group/row',
|
|
87
|
+
'[--row-bg:var(--compote-surface-1)]',
|
|
88
|
+
'hover:bg-well/60 hover:[--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]',
|
|
89
|
+
rowSelected &&
|
|
90
|
+
'bg-well/60 [--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]'
|
|
91
|
+
)}
|
|
92
|
+
onclick={(event) => onRowClick?.({ row: row.original, event })}
|
|
93
|
+
ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
|
|
94
|
+
>
|
|
95
|
+
{#if view.isRowSelectionEnabled}
|
|
96
|
+
<td
|
|
97
|
+
class="border-b border-surface-2 bg-(--row-bg) px-3 py-2 text-center align-middle group-last/row:border-b-0"
|
|
98
|
+
style="position: sticky; left: 0; z-index: 1"
|
|
99
|
+
onclick={(event) => event.stopPropagation()}
|
|
100
|
+
ondblclick={(event) => event.stopPropagation()}
|
|
101
|
+
>
|
|
102
|
+
<input
|
|
103
|
+
type="checkbox"
|
|
104
|
+
aria-label="Select row"
|
|
105
|
+
class="table-checkbox mx-auto block size-4"
|
|
106
|
+
checked={rowSelected}
|
|
107
|
+
disabled={!row.getCanSelect()}
|
|
108
|
+
onchange={(e) => row.toggleSelected(e.currentTarget.checked)}
|
|
109
|
+
/>
|
|
110
|
+
</td>
|
|
111
|
+
{/if}
|
|
112
|
+
{#each getRowCells(row, view) as cell (cell.id)}
|
|
113
|
+
{@const meta = getColumnMeta(cell.column.columnDef)}
|
|
114
|
+
<td
|
|
115
|
+
class={cn(
|
|
116
|
+
'truncate border-b border-b-surface-2 px-3 py-2 group-last/row:border-b-0',
|
|
117
|
+
alignClass(meta?.align),
|
|
118
|
+
cell.column.getIsPinned() && 'bg-(--row-bg)'
|
|
119
|
+
)}
|
|
120
|
+
style={getPinningStyle(cell.column, table, view, false, view.isRowSelectionEnabled)}
|
|
121
|
+
>
|
|
122
|
+
<DataTableCellContent {cell} />
|
|
123
|
+
</td>
|
|
124
|
+
{/each}
|
|
125
|
+
{#if !view.hasGrowColumn}
|
|
126
|
+
<td aria-hidden="true" class="border-b border-surface-2 p-0 group-last/row:border-b-0"
|
|
127
|
+
></td>
|
|
128
|
+
{/if}
|
|
129
|
+
</tr>
|
|
130
|
+
{:else}
|
|
131
|
+
<tr>
|
|
132
|
+
<td class="px-3 py-10 text-center text-sm text-ink-dim" colspan={renderedColumnCount}>
|
|
133
|
+
{emptyMessage}
|
|
134
|
+
</td>
|
|
135
|
+
</tr>
|
|
136
|
+
{/each}
|
|
137
|
+
</tbody>
|
|
138
|
+
{#if view.hasFooter}
|
|
139
|
+
<DataTableFoot {table} {view} hasGrowColumn={view.hasGrowColumn} />
|
|
140
|
+
{/if}
|
|
141
|
+
</table>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div class="shrink-0 border-t border-surface-3 bg-surface-2 px-3 py-2 text-sm text-ink-dim">
|
|
145
|
+
{#if view.isRowSelectionEnabled}
|
|
146
|
+
{view.selectedRowCount} of {view.rowModel.rows.length} rows selected
|
|
147
|
+
{:else}
|
|
148
|
+
{view.rowModel.rows.length} rows
|
|
149
|
+
{/if}
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RowData } from '@tanstack/svelte-table';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { type ClassValue } from 'tailwind-variants';
|
|
4
|
+
import type { DataTableInstance } from './data-table-utils';
|
|
5
|
+
declare function $$render<T extends RowData>(): {
|
|
6
|
+
props: Omit<HTMLAttributes<HTMLDivElement>, "class"> & {
|
|
7
|
+
table: DataTableInstance<T>;
|
|
8
|
+
caption?: string;
|
|
9
|
+
emptyMessage?: string;
|
|
10
|
+
class?: ClassValue;
|
|
11
|
+
onRowClick?: (details: {
|
|
12
|
+
row: T;
|
|
13
|
+
event: MouseEvent;
|
|
14
|
+
}) => void;
|
|
15
|
+
onRowDoubleClick?: (details: {
|
|
16
|
+
row: T;
|
|
17
|
+
event: MouseEvent;
|
|
18
|
+
}) => void;
|
|
19
|
+
};
|
|
20
|
+
exports: {};
|
|
21
|
+
bindings: "";
|
|
22
|
+
slots: {};
|
|
23
|
+
events: {};
|
|
24
|
+
};
|
|
25
|
+
declare class __sveltets_Render<T extends RowData> {
|
|
26
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
27
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
28
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
29
|
+
bindings(): "";
|
|
30
|
+
exports(): {};
|
|
31
|
+
}
|
|
32
|
+
interface $$IsomorphicComponent {
|
|
33
|
+
new <T extends RowData>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
34
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
35
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
36
|
+
<T extends RowData>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
37
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
38
|
+
}
|
|
39
|
+
declare const DataTable: $$IsomorphicComponent;
|
|
40
|
+
type DataTable<T extends RowData> = InstanceType<typeof DataTable<T>>;
|
|
41
|
+
export default DataTable;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const dataTableFeatures: {
|
|
2
|
+
rowSortingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
3
|
+
rowSelectionFeature: import("@tanstack/svelte-table").TableFeature;
|
|
4
|
+
columnFilteringFeature: import("@tanstack/svelte-table").TableFeature;
|
|
5
|
+
columnFacetingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
6
|
+
globalFilteringFeature: import("@tanstack/svelte-table").TableFeature;
|
|
7
|
+
columnVisibilityFeature: import("@tanstack/svelte-table").TableFeature;
|
|
8
|
+
columnPinningFeature: import("@tanstack/svelte-table").TableFeature;
|
|
9
|
+
columnSizingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
10
|
+
columnResizingFeature: import("@tanstack/svelte-table").TableFeature;
|
|
11
|
+
};
|
|
12
|
+
export type DataTableFeatures = typeof dataTableFeatures;
|