compote-ui 0.80.0 → 0.81.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-v9/column-filter-kind.d.ts +10 -1
- package/dist/components/data-table-v9/column-filter-kind.js +7 -0
- package/dist/components/data-table-v9/data-table-head.svelte +230 -230
- package/dist/components/data-table-v9/data-table.svelte +154 -154
- package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte +45 -45
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte +39 -33
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte.d.ts +7 -2
- package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte +52 -52
- package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte +51 -51
- package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte +59 -59
- package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte +20 -20
- package/dist/components/data-table-v9/header/column-header-filter.svelte +66 -66
- package/dist/components/data-table-v9/index.d.ts +9 -1
- package/dist/components/data-table-v9/index.js +7 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +203 -203
- package/dist/components/data-table-v9/types.d.ts +3 -1
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +82 -82
- package/dist/components/data-table-v9/virtual/index.d.ts +2 -2
- package/dist/components/data-table-v9/virtual/index.js +1 -1
- package/dist/components/dialog/alert-dialog.svelte +73 -73
- package/dist/components/dialog/dialog-root.svelte +45 -45
- package/dist/components/drawer/drawer-content.svelte +213 -213
- package/dist/components/popover/popover-content.svelte +97 -97
- package/dist/components/popover/popover-description.svelte +19 -19
- package/dist/components/popover/popover-root.svelte +27 -27
- package/dist/components/popover/popover-title.svelte +19 -19
- package/dist/icons/PhFunnelFill.svelte +19 -19
- package/package.json +1 -1
- package/skills/component-usage/references/overlays-and-floating-ui.md +278 -278
- package/skills/data-table/SKILL.md +362 -314
- package/skills/data-table/references/column-options.md +175 -175
- package/skills/data-table/references/table-state-and-reactivity.md +65 -65
|
@@ -1,154 +1,154 @@
|
|
|
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
|
-
/** Show a filter funnel in the header of every filterable column. */
|
|
26
|
-
headerFilters?: boolean;
|
|
27
|
-
onRowClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
28
|
-
onRowDoubleClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
let {
|
|
32
|
-
table,
|
|
33
|
-
caption,
|
|
34
|
-
emptyMessage = 'No rows found',
|
|
35
|
-
class: className,
|
|
36
|
-
headerFilters = false,
|
|
37
|
-
onRowClick,
|
|
38
|
-
onRowDoubleClick,
|
|
39
|
-
...rest
|
|
40
|
-
}: Props = $props();
|
|
41
|
-
|
|
42
|
-
const view = createTableViewState(() => table);
|
|
43
|
-
|
|
44
|
-
const visibleColumnCount = $derived(view.visibleLeafColumns.length);
|
|
45
|
-
const tableColumnCount = $derived(visibleColumnCount + (view.isRowSelectionEnabled ? 1 : 0));
|
|
46
|
-
const renderedColumnCount = $derived(tableColumnCount + 1);
|
|
47
|
-
</script>
|
|
48
|
-
|
|
49
|
-
<div
|
|
50
|
-
class={cn(
|
|
51
|
-
'flex max-h-full min-h-0 flex-col overflow-hidden rounded-lg border border-surface-3 bg-surface-1',
|
|
52
|
-
className
|
|
53
|
-
)}
|
|
54
|
-
{...rest}
|
|
55
|
-
>
|
|
56
|
-
{#if view.isColumnResizing}
|
|
57
|
-
<div aria-hidden="true" class="fixed inset-0 z-50 cursor-col-resize select-none"></div>
|
|
58
|
-
{/if}
|
|
59
|
-
|
|
60
|
-
<div class="min-h-0 flex-1 overflow-auto">
|
|
61
|
-
<table
|
|
62
|
-
class="table-fixed border-separate border-spacing-0 text-sm"
|
|
63
|
-
style={tableSizeStyle(table, view.isRowSelectionEnabled, view)}
|
|
64
|
-
>
|
|
65
|
-
<colgroup>
|
|
66
|
-
{#if view.isRowSelectionEnabled}
|
|
67
|
-
<col style={selectionColumnSizeStyle()} />
|
|
68
|
-
{/if}
|
|
69
|
-
{#each view.visibleLeafColumns as column (column.id)}
|
|
70
|
-
<col
|
|
71
|
-
style={getColumnMeta(column.columnDef)?.grow
|
|
72
|
-
? undefined
|
|
73
|
-
: columnSizeStyle(column.getSize())}
|
|
74
|
-
/>
|
|
75
|
-
{/each}
|
|
76
|
-
{#if !view.hasGrowColumn}
|
|
77
|
-
<col />
|
|
78
|
-
{/if}
|
|
79
|
-
</colgroup>
|
|
80
|
-
{#if caption}
|
|
81
|
-
<caption class="sr-only">{caption}</caption>
|
|
82
|
-
{/if}
|
|
83
|
-
<DataTableHead {table} {view} hasGrowColumn={view.hasGrowColumn} {headerFilters} />
|
|
84
|
-
<tbody>
|
|
85
|
-
{#each view.rowModel.rows as row (row.id)}
|
|
86
|
-
{@const rowSelected = view.rowSelection[row.id] === true}
|
|
87
|
-
<tr
|
|
88
|
-
class={cn(
|
|
89
|
-
'group/row',
|
|
90
|
-
'[--row-bg:var(--compote-surface-1)]',
|
|
91
|
-
'hover:bg-well/60 hover:[--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]',
|
|
92
|
-
rowSelected &&
|
|
93
|
-
'bg-well/60 [--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]'
|
|
94
|
-
)}
|
|
95
|
-
onclick={(event) => onRowClick?.({ row: row.original, event })}
|
|
96
|
-
ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
|
|
97
|
-
>
|
|
98
|
-
{#if view.isRowSelectionEnabled}
|
|
99
|
-
<td
|
|
100
|
-
class="border-b border-surface-2 bg-(--row-bg) px-3 py-2 text-center align-middle group-last/row:border-b-0"
|
|
101
|
-
style="position: sticky; left: 0; z-index: 1"
|
|
102
|
-
onclick={(event) => event.stopPropagation()}
|
|
103
|
-
ondblclick={(event) => event.stopPropagation()}
|
|
104
|
-
>
|
|
105
|
-
<input
|
|
106
|
-
type="checkbox"
|
|
107
|
-
aria-label="Select row"
|
|
108
|
-
class="table-checkbox mx-auto block size-4"
|
|
109
|
-
checked={rowSelected}
|
|
110
|
-
disabled={!row.getCanSelect()}
|
|
111
|
-
onchange={(e) => row.toggleSelected(e.currentTarget.checked)}
|
|
112
|
-
/>
|
|
113
|
-
</td>
|
|
114
|
-
{/if}
|
|
115
|
-
{#each getRowCells(row, view) as cell (cell.id)}
|
|
116
|
-
{@const meta = getColumnMeta(cell.column.columnDef)}
|
|
117
|
-
<td
|
|
118
|
-
class={cn(
|
|
119
|
-
'h-9 truncate border-b border-b-surface-2 px-3 py-0 align-middle group-last/row:border-b-0',
|
|
120
|
-
alignClass(meta?.align),
|
|
121
|
-
cell.column.getIsPinned() && 'bg-(--row-bg)'
|
|
122
|
-
)}
|
|
123
|
-
style={getPinningStyle(cell.column, table, view, false, view.isRowSelectionEnabled)}
|
|
124
|
-
>
|
|
125
|
-
<DataTableCellContent {cell} />
|
|
126
|
-
</td>
|
|
127
|
-
{/each}
|
|
128
|
-
{#if !view.hasGrowColumn}
|
|
129
|
-
<td aria-hidden="true" class="border-b border-surface-2 p-0 group-last/row:border-b-0"
|
|
130
|
-
></td>
|
|
131
|
-
{/if}
|
|
132
|
-
</tr>
|
|
133
|
-
{:else}
|
|
134
|
-
<tr>
|
|
135
|
-
<td class="px-3 py-10 text-center text-sm text-ink-dim" colspan={renderedColumnCount}>
|
|
136
|
-
{emptyMessage}
|
|
137
|
-
</td>
|
|
138
|
-
</tr>
|
|
139
|
-
{/each}
|
|
140
|
-
</tbody>
|
|
141
|
-
{#if view.hasFooter}
|
|
142
|
-
<DataTableFoot {table} {view} hasGrowColumn={view.hasGrowColumn} />
|
|
143
|
-
{/if}
|
|
144
|
-
</table>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div class="shrink-0 border-t border-surface-3 bg-surface-2 px-3 py-2 text-sm text-ink-dim">
|
|
148
|
-
{#if view.isRowSelectionEnabled}
|
|
149
|
-
{view.selectedRowCount} of {view.rowModel.rows.length} rows selected
|
|
150
|
-
{:else}
|
|
151
|
-
{view.rowModel.rows.length} rows
|
|
152
|
-
{/if}
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
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
|
+
/** Show a filter funnel in the header of every filterable column. */
|
|
26
|
+
headerFilters?: boolean;
|
|
27
|
+
onRowClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
28
|
+
onRowDoubleClick?: (details: { row: T; event: MouseEvent }) => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
table,
|
|
33
|
+
caption,
|
|
34
|
+
emptyMessage = 'No rows found',
|
|
35
|
+
class: className,
|
|
36
|
+
headerFilters = false,
|
|
37
|
+
onRowClick,
|
|
38
|
+
onRowDoubleClick,
|
|
39
|
+
...rest
|
|
40
|
+
}: Props = $props();
|
|
41
|
+
|
|
42
|
+
const view = createTableViewState(() => table);
|
|
43
|
+
|
|
44
|
+
const visibleColumnCount = $derived(view.visibleLeafColumns.length);
|
|
45
|
+
const tableColumnCount = $derived(visibleColumnCount + (view.isRowSelectionEnabled ? 1 : 0));
|
|
46
|
+
const renderedColumnCount = $derived(tableColumnCount + 1);
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<div
|
|
50
|
+
class={cn(
|
|
51
|
+
'flex max-h-full min-h-0 flex-col overflow-hidden rounded-lg border border-surface-3 bg-surface-1',
|
|
52
|
+
className
|
|
53
|
+
)}
|
|
54
|
+
{...rest}
|
|
55
|
+
>
|
|
56
|
+
{#if view.isColumnResizing}
|
|
57
|
+
<div aria-hidden="true" class="fixed inset-0 z-50 cursor-col-resize select-none"></div>
|
|
58
|
+
{/if}
|
|
59
|
+
|
|
60
|
+
<div class="min-h-0 flex-1 overflow-auto">
|
|
61
|
+
<table
|
|
62
|
+
class="table-fixed border-separate border-spacing-0 text-sm"
|
|
63
|
+
style={tableSizeStyle(table, view.isRowSelectionEnabled, view)}
|
|
64
|
+
>
|
|
65
|
+
<colgroup>
|
|
66
|
+
{#if view.isRowSelectionEnabled}
|
|
67
|
+
<col style={selectionColumnSizeStyle()} />
|
|
68
|
+
{/if}
|
|
69
|
+
{#each view.visibleLeafColumns as column (column.id)}
|
|
70
|
+
<col
|
|
71
|
+
style={getColumnMeta(column.columnDef)?.grow
|
|
72
|
+
? undefined
|
|
73
|
+
: columnSizeStyle(column.getSize())}
|
|
74
|
+
/>
|
|
75
|
+
{/each}
|
|
76
|
+
{#if !view.hasGrowColumn}
|
|
77
|
+
<col />
|
|
78
|
+
{/if}
|
|
79
|
+
</colgroup>
|
|
80
|
+
{#if caption}
|
|
81
|
+
<caption class="sr-only">{caption}</caption>
|
|
82
|
+
{/if}
|
|
83
|
+
<DataTableHead {table} {view} hasGrowColumn={view.hasGrowColumn} {headerFilters} />
|
|
84
|
+
<tbody>
|
|
85
|
+
{#each view.rowModel.rows as row (row.id)}
|
|
86
|
+
{@const rowSelected = view.rowSelection[row.id] === true}
|
|
87
|
+
<tr
|
|
88
|
+
class={cn(
|
|
89
|
+
'group/row',
|
|
90
|
+
'[--row-bg:var(--compote-surface-1)]',
|
|
91
|
+
'hover:bg-well/60 hover:[--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]',
|
|
92
|
+
rowSelected &&
|
|
93
|
+
'bg-well/60 [--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]'
|
|
94
|
+
)}
|
|
95
|
+
onclick={(event) => onRowClick?.({ row: row.original, event })}
|
|
96
|
+
ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
|
|
97
|
+
>
|
|
98
|
+
{#if view.isRowSelectionEnabled}
|
|
99
|
+
<td
|
|
100
|
+
class="border-b border-surface-2 bg-(--row-bg) px-3 py-2 text-center align-middle group-last/row:border-b-0"
|
|
101
|
+
style="position: sticky; left: 0; z-index: 1"
|
|
102
|
+
onclick={(event) => event.stopPropagation()}
|
|
103
|
+
ondblclick={(event) => event.stopPropagation()}
|
|
104
|
+
>
|
|
105
|
+
<input
|
|
106
|
+
type="checkbox"
|
|
107
|
+
aria-label="Select row"
|
|
108
|
+
class="table-checkbox mx-auto block size-4"
|
|
109
|
+
checked={rowSelected}
|
|
110
|
+
disabled={!row.getCanSelect()}
|
|
111
|
+
onchange={(e) => row.toggleSelected(e.currentTarget.checked)}
|
|
112
|
+
/>
|
|
113
|
+
</td>
|
|
114
|
+
{/if}
|
|
115
|
+
{#each getRowCells(row, view) as cell (cell.id)}
|
|
116
|
+
{@const meta = getColumnMeta(cell.column.columnDef)}
|
|
117
|
+
<td
|
|
118
|
+
class={cn(
|
|
119
|
+
'h-9 truncate border-b border-b-surface-2 px-3 py-0 align-middle group-last/row:border-b-0',
|
|
120
|
+
alignClass(meta?.align),
|
|
121
|
+
cell.column.getIsPinned() && 'bg-(--row-bg)'
|
|
122
|
+
)}
|
|
123
|
+
style={getPinningStyle(cell.column, table, view, false, view.isRowSelectionEnabled)}
|
|
124
|
+
>
|
|
125
|
+
<DataTableCellContent {cell} />
|
|
126
|
+
</td>
|
|
127
|
+
{/each}
|
|
128
|
+
{#if !view.hasGrowColumn}
|
|
129
|
+
<td aria-hidden="true" class="border-b border-surface-2 p-0 group-last/row:border-b-0"
|
|
130
|
+
></td>
|
|
131
|
+
{/if}
|
|
132
|
+
</tr>
|
|
133
|
+
{:else}
|
|
134
|
+
<tr>
|
|
135
|
+
<td class="px-3 py-10 text-center text-sm text-ink-dim" colspan={renderedColumnCount}>
|
|
136
|
+
{emptyMessage}
|
|
137
|
+
</td>
|
|
138
|
+
</tr>
|
|
139
|
+
{/each}
|
|
140
|
+
</tbody>
|
|
141
|
+
{#if view.hasFooter}
|
|
142
|
+
<DataTableFoot {table} {view} hasGrowColumn={view.hasGrowColumn} />
|
|
143
|
+
{/if}
|
|
144
|
+
</table>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="shrink-0 border-t border-surface-3 bg-surface-2 px-3 py-2 text-sm text-ink-dim">
|
|
148
|
+
{#if view.isRowSelectionEnabled}
|
|
149
|
+
{view.selectedRowCount} of {view.rowModel.rows.length} rows selected
|
|
150
|
+
{:else}
|
|
151
|
+
{view.rowModel.rows.length} rows
|
|
152
|
+
{/if}
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { cn } from 'tailwind-variants';
|
|
3
|
-
import type { FilterableColumn } from '../column-filter-editing.svelte';
|
|
4
|
-
|
|
5
|
-
type Props = {
|
|
6
|
-
column: FilterableColumn;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
let { column }: Props = $props();
|
|
10
|
-
|
|
11
|
-
const value = $derived(column.getFilterValue() as boolean | undefined);
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<div class="flex overflow-hidden rounded border border-border text-xs">
|
|
15
|
-
<button
|
|
16
|
-
type="button"
|
|
17
|
-
onclick={() => column.setFilterValue(undefined)}
|
|
18
|
-
class={cn(
|
|
19
|
-
'flex-1 px-2 py-1',
|
|
20
|
-
value === undefined ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
21
|
-
)}
|
|
22
|
-
>
|
|
23
|
-
All
|
|
24
|
-
</button>
|
|
25
|
-
<button
|
|
26
|
-
type="button"
|
|
27
|
-
onclick={() => column.setFilterValue(value === true ? undefined : true)}
|
|
28
|
-
class={cn(
|
|
29
|
-
'flex-1 border-x border-border px-2 py-1',
|
|
30
|
-
value === true ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
31
|
-
)}
|
|
32
|
-
>
|
|
33
|
-
Yes
|
|
34
|
-
</button>
|
|
35
|
-
<button
|
|
36
|
-
type="button"
|
|
37
|
-
onclick={() => column.setFilterValue(value === false ? undefined : false)}
|
|
38
|
-
class={cn(
|
|
39
|
-
'flex-1 px-2 py-1',
|
|
40
|
-
value === false ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
41
|
-
)}
|
|
42
|
-
>
|
|
43
|
-
No
|
|
44
|
-
</button>
|
|
45
|
-
</div>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from 'tailwind-variants';
|
|
3
|
+
import type { FilterableColumn } from '../column-filter-editing.svelte';
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
column: FilterableColumn;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
let { column }: Props = $props();
|
|
10
|
+
|
|
11
|
+
const value = $derived(column.getFilterValue() as boolean | undefined);
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div class="flex overflow-hidden rounded border border-border text-xs">
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
onclick={() => column.setFilterValue(undefined)}
|
|
18
|
+
class={cn(
|
|
19
|
+
'flex-1 px-2 py-1',
|
|
20
|
+
value === undefined ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
All
|
|
24
|
+
</button>
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
onclick={() => column.setFilterValue(value === true ? undefined : true)}
|
|
28
|
+
class={cn(
|
|
29
|
+
'flex-1 border-x border-border px-2 py-1',
|
|
30
|
+
value === true ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
31
|
+
)}
|
|
32
|
+
>
|
|
33
|
+
Yes
|
|
34
|
+
</button>
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
onclick={() => column.setFilterValue(value === false ? undefined : false)}
|
|
38
|
+
class={cn(
|
|
39
|
+
'flex-1 px-2 py-1',
|
|
40
|
+
value === false ? 'bg-surface-3 font-medium text-ink' : 'text-ink-dim hover:bg-surface-2'
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
No
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
@@ -1,33 +1,39 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends RowData">
|
|
2
|
-
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
3
|
-
import type { DataTableFeatures } from '../features';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
<
|
|
31
|
-
{:else if kind === '
|
|
32
|
-
<
|
|
33
|
-
{
|
|
1
|
+
<script lang="ts" generics="T extends RowData">
|
|
2
|
+
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
3
|
+
import type { DataTableFeatures } from '../features';
|
|
4
|
+
import { getColumnFilterKind } from '../column-filter-kind';
|
|
5
|
+
import { ColumnFilterEditing } from '../column-filter-editing.svelte';
|
|
6
|
+
import TextFilterEditor from './text-filter-editor.svelte';
|
|
7
|
+
import RangeFilterEditor from './range-filter-editor.svelte';
|
|
8
|
+
import BooleanFilterEditor from './boolean-filter-editor.svelte';
|
|
9
|
+
import SelectFilterEditor from './select-filter-editor.svelte';
|
|
10
|
+
import DateRangeFilterEditor from './date-range-filter-editor.svelte';
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* Pending (debounced) text and range edits. Hosts that can tear an editor down while
|
|
16
|
+
* it still holds an edit pass their own, with `isActive`; otherwise the editor uses
|
|
17
|
+
* one bound to the column's table.
|
|
18
|
+
*/
|
|
19
|
+
editing?: ColumnFilterEditing;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
let { column, editing: editingProp }: Props = $props();
|
|
23
|
+
|
|
24
|
+
const ownEditing = new ColumnFilterEditing({ table: () => column.table });
|
|
25
|
+
const editing = $derived(editingProp ?? ownEditing);
|
|
26
|
+
const kind = $derived(getColumnFilterKind(column));
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
{#if kind === 'range'}
|
|
30
|
+
<RangeFilterEditor {column} {editing} />
|
|
31
|
+
{:else if kind === 'boolean'}
|
|
32
|
+
<BooleanFilterEditor {column} />
|
|
33
|
+
{:else if kind === 'select'}
|
|
34
|
+
<SelectFilterEditor {column} />
|
|
35
|
+
{:else if kind === 'date'}
|
|
36
|
+
<DateRangeFilterEditor {column} />
|
|
37
|
+
{:else if kind === 'text'}
|
|
38
|
+
<TextFilterEditor {column} {editing} />
|
|
39
|
+
{/if}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
2
2
|
import type { DataTableFeatures } from '../features';
|
|
3
|
-
import
|
|
3
|
+
import { ColumnFilterEditing } from '../column-filter-editing.svelte';
|
|
4
4
|
declare function $$render<T extends RowData>(): {
|
|
5
5
|
props: {
|
|
6
6
|
column: Column<DataTableFeatures, T, unknown>;
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Pending (debounced) text and range edits. Hosts that can tear an editor down while
|
|
9
|
+
* it still holds an edit pass their own, with `isActive`; otherwise the editor uses
|
|
10
|
+
* one bound to the column's table.
|
|
11
|
+
*/
|
|
12
|
+
editing?: ColumnFilterEditing;
|
|
8
13
|
};
|
|
9
14
|
exports: {};
|
|
10
15
|
bindings: "";
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
<script lang="ts" generics="T extends RowData">
|
|
2
|
-
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
3
|
-
import DatePicker from '../../date-picker/date-picker.svelte';
|
|
4
|
-
import type { DataTableFeatures } from '../features';
|
|
5
|
-
import { getColumnMeta } from '../data-table-utils';
|
|
6
|
-
import { dateCellTimeZone } from '../date-cell';
|
|
7
|
-
import type { DateRangeFilterValue } from '../../../utils/date-filter';
|
|
8
|
-
|
|
9
|
-
type Props = {
|
|
10
|
-
column: Column<DataTableFeatures, T, unknown>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
let { column }: Props = $props();
|
|
14
|
-
|
|
15
|
-
const meta = $derived(getColumnMeta(column.columnDef));
|
|
16
|
-
// Pick days in the zone the column is shown and filtered in, so "today" matches the cells.
|
|
17
|
-
const timeZone = $derived(
|
|
18
|
-
dateCellTimeZone(meta?.formatOptions as Intl.DateTimeFormatOptions | undefined)
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
function bound(index: 0 | 1): string | null {
|
|
22
|
-
const value = column.getFilterValue();
|
|
23
|
-
const bound = Array.isArray(value) ? value[index] : undefined;
|
|
24
|
-
return typeof bound === 'string' ? bound : null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Each picked bound applies at once. The picker emits `YYYY-MM-DD` for a day it accepted
|
|
28
|
-
// and null when cleared; a half-typed date never reaches here.
|
|
29
|
-
function setBound(index: 0 | 1, next: unknown) {
|
|
30
|
-
const value = column.getFilterValue();
|
|
31
|
-
const range: DateRangeFilterValue = Array.isArray(value)
|
|
32
|
-
? [value[0] as string | undefined, value[1] as string | undefined]
|
|
33
|
-
: [undefined, undefined];
|
|
34
|
-
range[index] = typeof next === 'string' && next ? next : undefined;
|
|
35
|
-
column.setFilterValue(range[0] || range[1] ? range : undefined);
|
|
36
|
-
}
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
<div class="flex flex-col gap-2">
|
|
40
|
-
<DatePicker
|
|
41
|
-
label="From"
|
|
42
|
-
locale={meta?.formatLocale}
|
|
43
|
-
{timeZone}
|
|
44
|
-
bind:value={() => bound(0), (next) => setBound(0, next)}
|
|
45
|
-
/>
|
|
46
|
-
<DatePicker
|
|
47
|
-
label="To"
|
|
48
|
-
locale={meta?.formatLocale}
|
|
49
|
-
{timeZone}
|
|
50
|
-
bind:value={() => bound(1), (next) => setBound(1, next)}
|
|
51
|
-
/>
|
|
52
|
-
</div>
|
|
1
|
+
<script lang="ts" generics="T extends RowData">
|
|
2
|
+
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
3
|
+
import DatePicker from '../../date-picker/date-picker.svelte';
|
|
4
|
+
import type { DataTableFeatures } from '../features';
|
|
5
|
+
import { getColumnMeta } from '../data-table-utils';
|
|
6
|
+
import { dateCellTimeZone } from '../date-cell';
|
|
7
|
+
import type { DateRangeFilterValue } from '../../../utils/date-filter';
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let { column }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const meta = $derived(getColumnMeta(column.columnDef));
|
|
16
|
+
// Pick days in the zone the column is shown and filtered in, so "today" matches the cells.
|
|
17
|
+
const timeZone = $derived(
|
|
18
|
+
dateCellTimeZone(meta?.formatOptions as Intl.DateTimeFormatOptions | undefined)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
function bound(index: 0 | 1): string | null {
|
|
22
|
+
const value = column.getFilterValue();
|
|
23
|
+
const bound = Array.isArray(value) ? value[index] : undefined;
|
|
24
|
+
return typeof bound === 'string' ? bound : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Each picked bound applies at once. The picker emits `YYYY-MM-DD` for a day it accepted
|
|
28
|
+
// and null when cleared; a half-typed date never reaches here.
|
|
29
|
+
function setBound(index: 0 | 1, next: unknown) {
|
|
30
|
+
const value = column.getFilterValue();
|
|
31
|
+
const range: DateRangeFilterValue = Array.isArray(value)
|
|
32
|
+
? [value[0] as string | undefined, value[1] as string | undefined]
|
|
33
|
+
: [undefined, undefined];
|
|
34
|
+
range[index] = typeof next === 'string' && next ? next : undefined;
|
|
35
|
+
column.setFilterValue(range[0] || range[1] ? range : undefined);
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<div class="flex flex-col gap-2">
|
|
40
|
+
<DatePicker
|
|
41
|
+
label="From"
|
|
42
|
+
locale={meta?.formatLocale}
|
|
43
|
+
{timeZone}
|
|
44
|
+
bind:value={() => bound(0), (next) => setBound(0, next)}
|
|
45
|
+
/>
|
|
46
|
+
<DatePicker
|
|
47
|
+
label="To"
|
|
48
|
+
locale={meta?.formatLocale}
|
|
49
|
+
{timeZone}
|
|
50
|
+
bind:value={() => bound(1), (next) => setBound(1, next)}
|
|
51
|
+
/>
|
|
52
|
+
</div>
|