compote-ui 0.79.1 → 0.80.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-editing.svelte.d.ts +41 -0
- package/dist/components/data-table-v9/column-filter-editing.svelte.js +88 -0
- package/dist/components/data-table-v9/column-filter-kind.d.ts +10 -0
- package/dist/components/data-table-v9/column-filter-kind.js +25 -0
- package/dist/components/data-table-v9/create-table.svelte.js +49 -26
- package/dist/components/data-table-v9/data-table-head.svelte +230 -201
- package/dist/components/data-table-v9/data-table-head.svelte.d.ts +2 -0
- package/dist/components/data-table-v9/data-table-utils.d.ts +7 -0
- package/dist/components/data-table-v9/data-table-utils.js +4 -0
- package/dist/components/data-table-v9/data-table.svelte +154 -151
- package/dist/components/data-table-v9/data-table.svelte.d.ts +2 -0
- package/dist/components/data-table-v9/date-cell.d.ts +13 -0
- package/dist/components/data-table-v9/date-cell.js +38 -0
- package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte +45 -0
- package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte.d.ts +7 -0
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte +33 -0
- package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte.d.ts +30 -0
- package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte +52 -0
- package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte.d.ts +28 -0
- package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte +51 -0
- package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte.d.ts +30 -0
- package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte +59 -0
- package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte.d.ts +28 -0
- package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte +20 -0
- package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte.d.ts +8 -0
- package/dist/components/data-table-v9/filter-revisions.svelte.d.ts +17 -0
- package/dist/components/data-table-v9/filter-revisions.svelte.js +42 -0
- package/dist/components/data-table-v9/header/column-header-filter.svelte +66 -0
- package/dist/components/data-table-v9/header/column-header-filter.svelte.d.ts +30 -0
- package/dist/components/data-table-v9/table-view-state.svelte.d.ts +1 -0
- package/dist/components/data-table-v9/table-view-state.svelte.js +3 -0
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +203 -433
- package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte.d.ts +1 -1
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +82 -79
- package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte.d.ts +2 -0
- package/dist/components/dialog/alert-dialog.svelte +73 -71
- package/dist/components/dialog/dialog-root.svelte +45 -43
- package/dist/components/drawer/drawer-content.svelte +213 -211
- package/dist/components/number-input/number-input.svelte +2 -6
- package/dist/components/popover/popover-content.svelte +97 -71
- package/dist/components/popover/popover-content.svelte.d.ts +2 -1
- package/dist/components/popover/popover-description.svelte +19 -15
- package/dist/components/popover/popover-labels.svelte.d.ts +18 -0
- package/dist/components/popover/popover-labels.svelte.js +35 -0
- package/dist/components/popover/popover-root.svelte +27 -24
- package/dist/components/popover/popover-title.svelte +19 -15
- package/dist/icons/PhFunnelFill.svelte +19 -0
- package/dist/icons/PhFunnelFill.svelte.d.ts +5 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/utils/date-filter.d.ts +31 -0
- package/dist/utils/date-filter.js +58 -0
- package/dist/utils/date.d.ts +19 -1
- package/dist/utils/date.js +48 -1
- package/dist/utils/debounced-filter-edit.svelte.d.ts +16 -0
- package/dist/utils/debounced-filter-edit.svelte.js +56 -0
- package/dist/utils/number-input-value.d.ts +10 -0
- package/dist/utils/number-input-value.js +15 -0
- package/dist/utils/range-filter.d.ts +19 -0
- package/dist/utils/range-filter.js +23 -0
- package/dist/utils/release-focus-on-exit.d.ts +22 -0
- package/dist/utils/release-focus-on-exit.js +26 -0
- package/package.json +1 -1
- package/skills/component-usage/SKILL.md +1 -1
- package/skills/component-usage/references/forms-and-inputs.md +3 -0
- package/skills/component-usage/references/overlays-and-floating-ui.md +278 -273
- package/skills/data-table/SKILL.md +314 -283
- package/skills/data-table/references/column-options.md +175 -150
- package/skills/data-table/references/table-state-and-reactivity.md +65 -45
|
@@ -1,151 +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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{#
|
|
67
|
-
<col
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
+
/** 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>
|
|
@@ -8,6 +8,8 @@ declare function $$render<T extends RowData>(): {
|
|
|
8
8
|
caption?: string;
|
|
9
9
|
emptyMessage?: string;
|
|
10
10
|
class?: ClassValue;
|
|
11
|
+
/** Show a filter funnel in the header of every filterable column. */
|
|
12
|
+
headerFilters?: boolean;
|
|
11
13
|
onRowClick?: (details: {
|
|
12
14
|
row: T;
|
|
13
15
|
event: MouseEvent;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DateCellType = 'date' | 'time' | 'date-time';
|
|
2
|
+
export declare const TYPE_DATE_FORMAT_DEFAULTS: Record<DateCellType, Intl.DateTimeFormatOptions>;
|
|
3
|
+
/**
|
|
4
|
+
* The zone a date column is shown — and therefore filtered — in: `formatOptions.timeZone`
|
|
5
|
+
* when the column sets one, otherwise the viewer's local zone.
|
|
6
|
+
*/
|
|
7
|
+
export declare function dateCellTimeZone(formatOptions: Intl.DateTimeFormatOptions | undefined): string;
|
|
8
|
+
/**
|
|
9
|
+
* A date cell value formatted for display, or undefined when it can't be read. Reads the
|
|
10
|
+
* value with `readDateInZone`, exactly as the date range filter does, so a cell always shows
|
|
11
|
+
* the day it is filtered by.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatDateCell(value: unknown, type: DateCellType, locale: string, formatOptions?: Intl.DateTimeFormatOptions): string | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { CalendarDate, getLocalTimeZone } from '@internationalized/date';
|
|
2
|
+
import { readDateInZone } from '../../utils/date';
|
|
3
|
+
export const TYPE_DATE_FORMAT_DEFAULTS = {
|
|
4
|
+
date: { day: '2-digit', month: '2-digit', year: 'numeric' },
|
|
5
|
+
time: { hour: '2-digit', minute: '2-digit' },
|
|
6
|
+
'date-time': {
|
|
7
|
+
day: '2-digit',
|
|
8
|
+
month: '2-digit',
|
|
9
|
+
year: 'numeric',
|
|
10
|
+
hour: '2-digit',
|
|
11
|
+
minute: '2-digit'
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The zone a date column is shown — and therefore filtered — in: `formatOptions.timeZone`
|
|
16
|
+
* when the column sets one, otherwise the viewer's local zone.
|
|
17
|
+
*/
|
|
18
|
+
export function dateCellTimeZone(formatOptions) {
|
|
19
|
+
return formatOptions?.timeZone ?? getLocalTimeZone();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A date cell value formatted for display, or undefined when it can't be read. Reads the
|
|
23
|
+
* value with `readDateInZone`, exactly as the date range filter does, so a cell always shows
|
|
24
|
+
* the day it is filtered by.
|
|
25
|
+
*/
|
|
26
|
+
export function formatDateCell(value, type, locale, formatOptions) {
|
|
27
|
+
const timeZone = dateCellTimeZone(formatOptions);
|
|
28
|
+
const date = readDateInZone(value, timeZone);
|
|
29
|
+
if (!date)
|
|
30
|
+
return undefined;
|
|
31
|
+
const options = { ...TYPE_DATE_FORMAT_DEFAULTS[type], ...formatOptions };
|
|
32
|
+
// A calendar date has no instant: format its own year-month-day as UTC midnight in UTC,
|
|
33
|
+
// so no display zone can move it to another day.
|
|
34
|
+
if (date instanceof CalendarDate) {
|
|
35
|
+
return new Intl.DateTimeFormat(locale, { ...options, timeZone: 'UTC' }).format(date.toDate('UTC'));
|
|
36
|
+
}
|
|
37
|
+
return new Intl.DateTimeFormat(locale, { ...options, timeZone }).format(date.toDate());
|
|
38
|
+
}
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FilterableColumn } from '../column-filter-editing.svelte';
|
|
2
|
+
type Props = {
|
|
3
|
+
column: FilterableColumn;
|
|
4
|
+
};
|
|
5
|
+
declare const BooleanFilterEditor: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type BooleanFilterEditor = ReturnType<typeof BooleanFilterEditor>;
|
|
7
|
+
export default BooleanFilterEditor;
|
|
@@ -0,0 +1,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 { getColumnMeta } from '../data-table-utils';
|
|
5
|
+
import { filterKindFor } from '../column-filter-kind';
|
|
6
|
+
import type { ColumnFilterEditing } from '../column-filter-editing.svelte';
|
|
7
|
+
import TextFilterEditor from './text-filter-editor.svelte';
|
|
8
|
+
import RangeFilterEditor from './range-filter-editor.svelte';
|
|
9
|
+
import BooleanFilterEditor from './boolean-filter-editor.svelte';
|
|
10
|
+
import SelectFilterEditor from './select-filter-editor.svelte';
|
|
11
|
+
import DateRangeFilterEditor from './date-range-filter-editor.svelte';
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
15
|
+
editing: ColumnFilterEditing;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let { column, editing }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const kind = $derived(filterKindFor(getColumnMeta(column.columnDef)?.type));
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
{#if kind === 'range'}
|
|
24
|
+
<RangeFilterEditor {column} {editing} />
|
|
25
|
+
{:else if kind === 'boolean'}
|
|
26
|
+
<BooleanFilterEditor {column} />
|
|
27
|
+
{:else if kind === 'select'}
|
|
28
|
+
<SelectFilterEditor {column} />
|
|
29
|
+
{:else if kind === 'date'}
|
|
30
|
+
<DateRangeFilterEditor {column} />
|
|
31
|
+
{:else if kind === 'text'}
|
|
32
|
+
<TextFilterEditor {column} {editing} />
|
|
33
|
+
{/if}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
2
|
+
import type { DataTableFeatures } from '../features';
|
|
3
|
+
import type { ColumnFilterEditing } from '../column-filter-editing.svelte';
|
|
4
|
+
declare function $$render<T extends RowData>(): {
|
|
5
|
+
props: {
|
|
6
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
7
|
+
editing: ColumnFilterEditing;
|
|
8
|
+
};
|
|
9
|
+
exports: {};
|
|
10
|
+
bindings: "";
|
|
11
|
+
slots: {};
|
|
12
|
+
events: {};
|
|
13
|
+
};
|
|
14
|
+
declare class __sveltets_Render<T extends RowData> {
|
|
15
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
16
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
17
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
18
|
+
bindings(): "";
|
|
19
|
+
exports(): {};
|
|
20
|
+
}
|
|
21
|
+
interface $$IsomorphicComponent {
|
|
22
|
+
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']>> & {
|
|
23
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
24
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
25
|
+
<T extends RowData>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
26
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
27
|
+
}
|
|
28
|
+
declare const ColumnFilterEditor: $$IsomorphicComponent;
|
|
29
|
+
type ColumnFilterEditor<T extends RowData> = InstanceType<typeof ColumnFilterEditor<T>>;
|
|
30
|
+
export default ColumnFilterEditor;
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
2
|
+
import type { DataTableFeatures } from '../features';
|
|
3
|
+
declare function $$render<T extends RowData>(): {
|
|
4
|
+
props: {
|
|
5
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
6
|
+
};
|
|
7
|
+
exports: {};
|
|
8
|
+
bindings: "";
|
|
9
|
+
slots: {};
|
|
10
|
+
events: {};
|
|
11
|
+
};
|
|
12
|
+
declare class __sveltets_Render<T extends RowData> {
|
|
13
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
14
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
15
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
16
|
+
bindings(): "";
|
|
17
|
+
exports(): {};
|
|
18
|
+
}
|
|
19
|
+
interface $$IsomorphicComponent {
|
|
20
|
+
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']>> & {
|
|
21
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
22
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
23
|
+
<T extends RowData>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
24
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
25
|
+
}
|
|
26
|
+
declare const DateRangeFilterEditor: $$IsomorphicComponent;
|
|
27
|
+
type DateRangeFilterEditor<T extends RowData> = InstanceType<typeof DateRangeFilterEditor<T>>;
|
|
28
|
+
export default DateRangeFilterEditor;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends RowData">
|
|
2
|
+
import type { Column, RowData } from '@tanstack/svelte-table';
|
|
3
|
+
import NumberInput from '../../number-input/number-input.svelte';
|
|
4
|
+
import type { DataTableFeatures } from '../features';
|
|
5
|
+
import { getColumnMeta } from '../data-table-utils';
|
|
6
|
+
import type { ColumnFilterEditing } from '../column-filter-editing.svelte';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
column: Column<DataTableFeatures, T, unknown>;
|
|
10
|
+
editing: ColumnFilterEditing;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let { column, editing }: Props = $props();
|
|
14
|
+
|
|
15
|
+
const facetBounds = $derived.by((): [number | undefined, number | undefined] => {
|
|
16
|
+
const vals = column.getFacetedMinMaxValues();
|
|
17
|
+
return vals ? [vals[0] as number, vals[1] as number] : [undefined, undefined];
|
|
18
|
+
});
|
|
19
|
+
const formatOptions = $derived(
|
|
20
|
+
getColumnMeta(column.columnDef)?.formatOptions as Intl.NumberFormatOptions | undefined
|
|
21
|
+
);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div class="flex flex-col gap-1.5">
|
|
25
|
+
<div class="min-w-0 flex-1">
|
|
26
|
+
<NumberInput
|
|
27
|
+
layout="horizontal"
|
|
28
|
+
label="From"
|
|
29
|
+
bind:value={
|
|
30
|
+
() => editing.rangeBound(column, 'min'),
|
|
31
|
+
(bound) => editing.editRange(column, 'min', bound ?? null)
|
|
32
|
+
}
|
|
33
|
+
min={facetBounds[0]}
|
|
34
|
+
max={facetBounds[1]}
|
|
35
|
+
{formatOptions}
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="min-w-0 flex-1">
|
|
39
|
+
<NumberInput
|
|
40
|
+
layout="horizontal"
|
|
41
|
+
label="To"
|
|
42
|
+
bind:value={
|
|
43
|
+
() => editing.rangeBound(column, 'max'),
|
|
44
|
+
(bound) => editing.editRange(column, 'max', bound ?? null)
|
|
45
|
+
}
|
|
46
|
+
min={facetBounds[0]}
|
|
47
|
+
max={facetBounds[1]}
|
|
48
|
+
{formatOptions}
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|