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.
Files changed (69) hide show
  1. package/dist/components/data-table-v9/column-filter-editing.svelte.d.ts +41 -0
  2. package/dist/components/data-table-v9/column-filter-editing.svelte.js +88 -0
  3. package/dist/components/data-table-v9/column-filter-kind.d.ts +10 -0
  4. package/dist/components/data-table-v9/column-filter-kind.js +25 -0
  5. package/dist/components/data-table-v9/create-table.svelte.js +49 -26
  6. package/dist/components/data-table-v9/data-table-head.svelte +230 -201
  7. package/dist/components/data-table-v9/data-table-head.svelte.d.ts +2 -0
  8. package/dist/components/data-table-v9/data-table-utils.d.ts +7 -0
  9. package/dist/components/data-table-v9/data-table-utils.js +4 -0
  10. package/dist/components/data-table-v9/data-table.svelte +154 -151
  11. package/dist/components/data-table-v9/data-table.svelte.d.ts +2 -0
  12. package/dist/components/data-table-v9/date-cell.d.ts +13 -0
  13. package/dist/components/data-table-v9/date-cell.js +38 -0
  14. package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte +45 -0
  15. package/dist/components/data-table-v9/filter-editors/boolean-filter-editor.svelte.d.ts +7 -0
  16. package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte +33 -0
  17. package/dist/components/data-table-v9/filter-editors/column-filter-editor.svelte.d.ts +30 -0
  18. package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte +52 -0
  19. package/dist/components/data-table-v9/filter-editors/date-range-filter-editor.svelte.d.ts +28 -0
  20. package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte +51 -0
  21. package/dist/components/data-table-v9/filter-editors/range-filter-editor.svelte.d.ts +30 -0
  22. package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte +59 -0
  23. package/dist/components/data-table-v9/filter-editors/select-filter-editor.svelte.d.ts +28 -0
  24. package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte +20 -0
  25. package/dist/components/data-table-v9/filter-editors/text-filter-editor.svelte.d.ts +8 -0
  26. package/dist/components/data-table-v9/filter-revisions.svelte.d.ts +17 -0
  27. package/dist/components/data-table-v9/filter-revisions.svelte.js +42 -0
  28. package/dist/components/data-table-v9/header/column-header-filter.svelte +66 -0
  29. package/dist/components/data-table-v9/header/column-header-filter.svelte.d.ts +30 -0
  30. package/dist/components/data-table-v9/table-view-state.svelte.d.ts +1 -0
  31. package/dist/components/data-table-v9/table-view-state.svelte.js +3 -0
  32. package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +203 -433
  33. package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte.d.ts +1 -1
  34. package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +82 -79
  35. package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte.d.ts +2 -0
  36. package/dist/components/dialog/alert-dialog.svelte +73 -71
  37. package/dist/components/dialog/dialog-root.svelte +45 -43
  38. package/dist/components/drawer/drawer-content.svelte +213 -211
  39. package/dist/components/number-input/number-input.svelte +2 -6
  40. package/dist/components/popover/popover-content.svelte +97 -71
  41. package/dist/components/popover/popover-content.svelte.d.ts +2 -1
  42. package/dist/components/popover/popover-description.svelte +19 -15
  43. package/dist/components/popover/popover-labels.svelte.d.ts +18 -0
  44. package/dist/components/popover/popover-labels.svelte.js +35 -0
  45. package/dist/components/popover/popover-root.svelte +27 -24
  46. package/dist/components/popover/popover-title.svelte +19 -15
  47. package/dist/icons/PhFunnelFill.svelte +19 -0
  48. package/dist/icons/PhFunnelFill.svelte.d.ts +5 -0
  49. package/dist/icons/index.d.ts +1 -0
  50. package/dist/icons/index.js +1 -0
  51. package/dist/utils/date-filter.d.ts +31 -0
  52. package/dist/utils/date-filter.js +58 -0
  53. package/dist/utils/date.d.ts +19 -1
  54. package/dist/utils/date.js +48 -1
  55. package/dist/utils/debounced-filter-edit.svelte.d.ts +16 -0
  56. package/dist/utils/debounced-filter-edit.svelte.js +56 -0
  57. package/dist/utils/number-input-value.d.ts +10 -0
  58. package/dist/utils/number-input-value.js +15 -0
  59. package/dist/utils/range-filter.d.ts +19 -0
  60. package/dist/utils/range-filter.js +23 -0
  61. package/dist/utils/release-focus-on-exit.d.ts +22 -0
  62. package/dist/utils/release-focus-on-exit.js +26 -0
  63. package/package.json +1 -1
  64. package/skills/component-usage/SKILL.md +1 -1
  65. package/skills/component-usage/references/forms-and-inputs.md +3 -0
  66. package/skills/component-usage/references/overlays-and-floating-ui.md +278 -273
  67. package/skills/data-table/SKILL.md +314 -283
  68. package/skills/data-table/references/column-options.md +175 -150
  69. package/skills/data-table/references/table-state-and-reactivity.md +65 -45
@@ -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 RangeFilterEditor: $$IsomorphicComponent;
29
+ type RangeFilterEditor<T extends RowData> = InstanceType<typeof RangeFilterEditor<T>>;
30
+ export default RangeFilterEditor;
@@ -0,0 +1,59 @@
1
+ <script lang="ts" generics="T extends RowData">
2
+ import type { Column, RowData } from '@tanstack/svelte-table';
3
+ import * as Field from '../../field';
4
+ import * as ScrollArea from '../../scroll-area';
5
+ import Checkbox from '../../checkbox/checkbox.svelte';
6
+ import type { DataTableFeatures } from '../features';
7
+ import { selectFilterOptions, type SelectFilterValue } from '../../../utils/select-filter';
8
+
9
+ type Props = {
10
+ column: Column<DataTableFeatures, T, unknown>;
11
+ };
12
+
13
+ let { column }: Props = $props();
14
+
15
+ let search = $state('');
16
+
17
+ const allOptions = $derived(selectFilterOptions(column.getFacetedUniqueValues()));
18
+ const options = $derived(
19
+ search
20
+ ? allOptions.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()))
21
+ : allOptions
22
+ );
23
+ const selected = $derived((column.getFilterValue() as SelectFilterValue[] | undefined) ?? []);
24
+
25
+ function toggle(value: SelectFilterValue, checked: boolean) {
26
+ const next = checked ? [...selected, value] : selected.filter((v) => v !== value);
27
+ column.setFilterValue(next.length ? next : undefined);
28
+ }
29
+ </script>
30
+
31
+ <div class="flex flex-col gap-1">
32
+ <Field.Root hideMessageLine>
33
+ <Field.Input placeholder="Search..." bind:value={search} />
34
+ </Field.Root>
35
+ <ScrollArea.Root>
36
+ <ScrollArea.Viewport class="max-h-40">
37
+ <ScrollArea.Content>
38
+ <div class="flex flex-col gap-0.5">
39
+ {#each options as option (option.value)}
40
+ <div class="flex min-h-7 items-center gap-2 rounded-sm pr-2 hover:bg-surface-2">
41
+ <Checkbox
42
+ size="sm"
43
+ label={option.label}
44
+ class="min-h-7 flex-1 px-2"
45
+ checked={selected.includes(option.value)}
46
+ onCheckedChange={({ checked }) => toggle(option.value, checked === true)}
47
+ />
48
+ <span class="text-xs text-ink-dim tabular-nums">{option.count}</span>
49
+ </div>
50
+ {/each}
51
+ </div>
52
+ </ScrollArea.Content>
53
+ </ScrollArea.Viewport>
54
+ <ScrollArea.Scrollbar orientation="vertical">
55
+ <ScrollArea.Thumb />
56
+ </ScrollArea.Scrollbar>
57
+ <ScrollArea.Corner />
58
+ </ScrollArea.Root>
59
+ </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 SelectFilterEditor: $$IsomorphicComponent;
27
+ type SelectFilterEditor<T extends RowData> = InstanceType<typeof SelectFilterEditor<T>>;
28
+ export default SelectFilterEditor;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import * as Field from '../../field';
3
+ import type { ColumnFilterEditing, FilterableColumn } from '../column-filter-editing.svelte';
4
+
5
+ type Props = {
6
+ column: FilterableColumn;
7
+ editing: ColumnFilterEditing;
8
+ };
9
+
10
+ let { column, editing }: Props = $props();
11
+ </script>
12
+
13
+ <Field.Root hideMessageLine>
14
+ <Field.Input
15
+ placeholder="Search..."
16
+ bind:value={
17
+ () => editing.textValue(column), (text) => editing.editText(column, String(text ?? ''))
18
+ }
19
+ />
20
+ </Field.Root>
@@ -0,0 +1,8 @@
1
+ import type { ColumnFilterEditing, FilterableColumn } from '../column-filter-editing.svelte';
2
+ type Props = {
3
+ column: FilterableColumn;
4
+ editing: ColumnFilterEditing;
5
+ };
6
+ declare const TextFilterEditor: import("svelte").Component<Props, {}, "">;
7
+ type TextFilterEditor = ReturnType<typeof TextFilterEditor>;
8
+ export default TextFilterEditor;
@@ -0,0 +1,17 @@
1
+ import type { ColumnFiltersState } from '@tanstack/svelte-table';
2
+ /**
3
+ * A per-column counter that goes up on every change to that column's filter value. Unlike
4
+ * the value itself it never returns to an earlier state, so a filter cleared and then set
5
+ * back to the same value still reads as changed (the ABA case a value comparison misses).
6
+ */
7
+ export declare class FilterRevisions {
8
+ #private;
9
+ get(columnId: string): number;
10
+ bump(columnIds: string[]): void;
11
+ }
12
+ /** Ids of the columns whose filter value differs (by reference) between two filter states. */
13
+ export declare function changedFilterIds(prev: ColumnFiltersState, next: ColumnFiltersState): string[];
14
+ /** Links a table to its filter revisions (done by `createTable`). */
15
+ export declare function registerFilterRevisions(table: object, revisions: FilterRevisions): void;
16
+ /** The filter revisions of a table made by `createTable`; undefined for any other table. */
17
+ export declare function getFilterRevisions(table: object): FilterRevisions | undefined;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A per-column counter that goes up on every change to that column's filter value. Unlike
3
+ * the value itself it never returns to an earlier state, so a filter cleared and then set
4
+ * back to the same value still reads as changed (the ABA case a value comparison misses).
5
+ */
6
+ export class FilterRevisions {
7
+ // Raw record replaced on change: reads in templates/deriveds stay reactive.
8
+ #revisions = $state.raw({});
9
+ get(columnId) {
10
+ return this.#revisions[columnId] ?? 0;
11
+ }
12
+ bump(columnIds) {
13
+ if (columnIds.length === 0)
14
+ return;
15
+ const next = { ...this.#revisions };
16
+ for (const id of columnIds)
17
+ next[id] = (next[id] ?? 0) + 1;
18
+ this.#revisions = next;
19
+ }
20
+ }
21
+ /** Ids of the columns whose filter value differs (by reference) between two filter states. */
22
+ export function changedFilterIds(prev, next) {
23
+ if (prev === next)
24
+ return [];
25
+ const before = Object.create(null);
26
+ const after = Object.create(null);
27
+ for (const filter of prev)
28
+ before[filter.id] = filter.value;
29
+ for (const filter of next)
30
+ after[filter.id] = filter.value;
31
+ const ids = Object.keys({ ...before, ...after });
32
+ return ids.filter((id) => !Object.is(before[id], after[id]));
33
+ }
34
+ const registry = new WeakMap();
35
+ /** Links a table to its filter revisions (done by `createTable`). */
36
+ export function registerFilterRevisions(table, revisions) {
37
+ registry.set(table, revisions);
38
+ }
39
+ /** The filter revisions of a table made by `createTable`; undefined for any other table. */
40
+ export function getFilterRevisions(table) {
41
+ return registry.get(table);
42
+ }
@@ -0,0 +1,66 @@
1
+ <script lang="ts" generics="T extends RowData">
2
+ import type { Column, RowData } from '@tanstack/svelte-table';
3
+ import * as Popover from '../../popover';
4
+ import { PhFunnel, PhFunnelFill } from '../../../icons';
5
+ import type { DataTableFeatures } from '../features';
6
+ import { cn } from 'tailwind-variants';
7
+ import { getColumnLabel, getColumnMeta, type DataTableInstance } from '../data-table-utils';
8
+ import { ColumnFilterEditing } from '../column-filter-editing.svelte';
9
+ import ColumnFilterEditor from '../filter-editors/column-filter-editor.svelte';
10
+
11
+ type Props = {
12
+ table: DataTableInstance<T>;
13
+ column: Column<DataTableFeatures, T, unknown>;
14
+ };
15
+
16
+ let { table, column }: Props = $props();
17
+
18
+ // Pending edits belong to the table: shared with the other filter hosts, and they still
19
+ // commit after this popover closes.
20
+ const editing = new ColumnFilterEditing({ table: () => table });
21
+
22
+ const isFiltered = $derived(
23
+ table.atoms.columnFilters.get().some((filter) => filter.id === column.id)
24
+ );
25
+ const label = $derived(getColumnLabel(column));
26
+ const align = $derived(getColumnMeta(column.columnDef)?.align);
27
+
28
+ function clear() {
29
+ editing.cancel(column.id);
30
+ column.setFilterValue(undefined);
31
+ }
32
+ </script>
33
+
34
+ <Popover.Root positioning={{ placement: 'bottom-start' }}>
35
+ <Popover.Trigger
36
+ aria-label={`Filter ${label}`}
37
+ data-active={isFiltered ? '' : undefined}
38
+ class={cn(
39
+ 'inline-flex size-5 shrink-0 items-center justify-center rounded-sm bg-surface-2 text-ink-dim opacity-0 outline-none group-hover/th:opacity-100 hover:bg-surface-3 hover:text-ink focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:opacity-100 pointer-coarse:opacity-100',
40
+ // Floats over the cell's inner edge, opposite the label, so while inactive it never
41
+ // takes width from a narrow column; its background hides label text running under it.
42
+ // Once a filter is set the header cell pads that edge (see data-table-head).
43
+ 'absolute top-1/2 -translate-y-1/2',
44
+ align === 'right' ? 'left-1' : 'right-1',
45
+ 'data-active:text-primary data-active:opacity-100'
46
+ )}
47
+ >
48
+ {#if isFiltered}
49
+ <PhFunnelFill class="size-3.5" />
50
+ {:else}
51
+ <PhFunnel class="size-3.5" />
52
+ {/if}
53
+ </Popover.Trigger>
54
+
55
+ <Popover.Content class="flex w-64 flex-col gap-3 p-3" showArrow={false}>
56
+ <div class="flex min-h-5 items-center justify-between gap-2">
57
+ <Popover.Title class="truncate text-sm font-medium text-ink">{label}</Popover.Title>
58
+ {#if isFiltered}
59
+ <button type="button" onclick={clear} class="text-xs text-primary hover:underline">
60
+ Clear
61
+ </button>
62
+ {/if}
63
+ </div>
64
+ <ColumnFilterEditor {column} {editing} />
65
+ </Popover.Content>
66
+ </Popover.Root>
@@ -0,0 +1,30 @@
1
+ import type { Column, RowData } from '@tanstack/svelte-table';
2
+ import type { DataTableFeatures } from '../features';
3
+ import { type DataTableInstance } from '../data-table-utils';
4
+ declare function $$render<T extends RowData>(): {
5
+ props: {
6
+ table: DataTableInstance<T>;
7
+ column: Column<DataTableFeatures, T, unknown>;
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 ColumnHeaderFilter: $$IsomorphicComponent;
29
+ type ColumnHeaderFilter<T extends RowData> = InstanceType<typeof ColumnHeaderFilter<T>>;
30
+ export default ColumnHeaderFilter;
@@ -19,6 +19,7 @@ export declare function createTableViewState<T extends RowData>(getTable: () =>
19
19
  readonly columnVisibility: import("@tanstack/table-core").ColumnVisibilityState;
20
20
  readonly rowSelection: import("@tanstack/table-core").RowSelectionState;
21
21
  readonly sorting: import("@tanstack/table-core").SortingState;
22
+ readonly columnFilters: import("@tanstack/table-core").ColumnFiltersState;
22
23
  readonly rowModel: import("@tanstack/table-core").RowModel<{
23
24
  rowSortingFeature: import("@tanstack/table-core").TableFeature;
24
25
  rowSelectionFeature: import("@tanstack/table-core").TableFeature;
@@ -78,6 +78,9 @@ export function createTableViewState(getTable) {
78
78
  get sorting() {
79
79
  return sorting;
80
80
  },
81
+ get columnFilters() {
82
+ return columnFilters;
83
+ },
81
84
  get rowModel() {
82
85
  return rowModel;
83
86
  },