compote-ui 0.43.15 → 0.44.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.
@@ -111,8 +111,10 @@
111
111
  <Popover.Trigger
112
112
  class="flex h-9 cursor-pointer items-center rounded-md border border-surface-3 bg-surface-1 px-3 text-sm font-medium text-ink shadow-sm outline-none hover:bg-surface-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
113
113
  >
114
- {triggerLabel}{#if activeCount > 0}
115
- ({activeCount}){/if}
114
+ {triggerLabel}
115
+ {#if activeCount > 0}
116
+ ({activeCount})
117
+ {/if}
116
118
  </Popover.Trigger>
117
119
 
118
120
  <Popover.Content class="w-72 px-0" showArrow={false}>
@@ -0,0 +1,57 @@
1
+ <script lang="ts" generics="T extends RowData">
2
+ import { onDestroy } from 'svelte';
3
+ import type { RowData } from '@tanstack/table-core';
4
+ import { cn, type ClassValue } from 'tailwind-variants';
5
+ import { PhMagnifyingGlass, PhX } from '../../icons';
6
+ import * as Field from '../field';
7
+ import { getReactiveTableState, type DataTableInstance } from './data-table-utils';
8
+
9
+ type Props = {
10
+ table: DataTableInstance<T>;
11
+ placeholder?: string;
12
+ class?: ClassValue;
13
+ };
14
+
15
+ let { table, placeholder = 'Search...', class: className }: Props = $props();
16
+
17
+ const globalFilter = $derived(
18
+ (getReactiveTableState(table).globalFilter as string | undefined) ?? ''
19
+ );
20
+
21
+ let timer: ReturnType<typeof setTimeout> | undefined;
22
+
23
+ onDestroy(() => clearTimeout(timer));
24
+
25
+ function handleInput(e: Event) {
26
+ const value = (e.currentTarget as HTMLInputElement).value;
27
+ clearTimeout(timer);
28
+ timer = setTimeout(() => {
29
+ table.setGlobalFilter(value || undefined);
30
+ }, 300);
31
+ }
32
+
33
+ function clearFilter() {
34
+ clearTimeout(timer);
35
+ table.setGlobalFilter(undefined);
36
+ }
37
+ </script>
38
+
39
+ <Field.Root class={cn(className)}>
40
+ <Field.Input {placeholder} value={globalFilter} oninput={handleInput}>
41
+ {#snippet startIcon()}
42
+ <PhMagnifyingGlass class="size-4" />
43
+ {/snippet}
44
+ {#snippet endIcon()}
45
+ {#if globalFilter}
46
+ <button
47
+ type="button"
48
+ onclick={clearFilter}
49
+ aria-label="Clear search"
50
+ class="flex size-5 items-center justify-center rounded text-ink-dim hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring"
51
+ >
52
+ <PhX class="size-3.5" />
53
+ </button>
54
+ {/if}
55
+ {/snippet}
56
+ </Field.Input>
57
+ </Field.Root>
@@ -0,0 +1,31 @@
1
+ import type { RowData } from '@tanstack/table-core';
2
+ import { type ClassValue } from 'tailwind-variants';
3
+ import { type DataTableInstance } from './data-table-utils';
4
+ declare function $$render<T extends RowData>(): {
5
+ props: {
6
+ table: DataTableInstance<T>;
7
+ placeholder?: string;
8
+ class?: ClassValue;
9
+ };
10
+ exports: {};
11
+ bindings: "";
12
+ slots: {};
13
+ events: {};
14
+ };
15
+ declare class __sveltets_Render<T extends RowData> {
16
+ props(): ReturnType<typeof $$render<T>>['props'];
17
+ events(): ReturnType<typeof $$render<T>>['events'];
18
+ slots(): ReturnType<typeof $$render<T>>['slots'];
19
+ bindings(): "";
20
+ exports(): {};
21
+ }
22
+ interface $$IsomorphicComponent {
23
+ 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']>> & {
24
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
25
+ } & ReturnType<__sveltets_Render<T>['exports']>;
26
+ <T extends RowData>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
27
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
28
+ }
29
+ declare const DataTableSearch: $$IsomorphicComponent;
30
+ type DataTableSearch<T extends RowData> = InstanceType<typeof DataTableSearch<T>>;
31
+ export default DataTableSearch;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" generics="T extends RowData">
2
2
  import type { Row, RowData } from '@tanstack/table-core';
3
3
  import { createVirtualizer } from '@tanstack/svelte-virtual';
4
+ import { untrack } from 'svelte';
4
5
  import { cn } from 'tailwind-variants';
5
6
  import { PhArrowSquareOut, PhCheck, PhX } from '../../icons';
6
7
  import type { DataTableInstance } from './data-table-utils';
@@ -57,6 +58,13 @@
57
58
  function measureRowElement(node: HTMLTableRowElement) {
58
59
  $rowVirtualizer.measureElement(node);
59
60
  }
61
+
62
+ $effect(() => {
63
+ const count = rows.length;
64
+ untrack(() => {
65
+ $rowVirtualizer.setOptions({ ...$rowVirtualizer.options, count });
66
+ });
67
+ });
60
68
  </script>
61
69
 
62
70
  <tbody style="display: grid; height: {$rowVirtualizer.getTotalSize()}px; position: relative">
@@ -69,98 +77,100 @@
69
77
  {:else}
70
78
  {#each $rowVirtualizer.getVirtualItems() as virtualRow (virtualRow.index)}
71
79
  {@const row = rows[virtualRow.index]}
72
- {@const rowSelected = getReactiveTableState(table).rowSelection[row.id] === true}
73
- <tr
74
- data-index={virtualRow.index}
75
- use:measureRowElement
76
- class={cn(
77
- 'group/row border-b border-surface-2 last:border-b-0',
78
- '[--row-bg:var(--compote-surface-1)]',
79
- 'hover:bg-well/60 hover:[--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]',
80
- rowSelected &&
81
- 'bg-well/60 [--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]'
82
- )}
83
- style="display: flex; position: absolute; transform: translateY({virtualRow.start}px); width: 100%"
84
- onclick={(event) => onRowClick?.({ row: row.original, event })}
85
- ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
86
- >
87
- {#if isRowSelectionEnabled}
88
- <td
89
- class="items-center justify-center bg-(--row-bg) px-3 py-2 text-center align-middle"
90
- style={joinStyles(
91
- virtualSelectionColumnSizeStyle(),
92
- 'position: sticky; left: 0; z-index: 1'
93
- )}
94
- >
95
- <input
96
- type="checkbox"
97
- aria-label="Select row"
98
- class="table-checkbox mx-auto block size-4"
99
- checked={rowSelected}
100
- disabled={!row.getCanSelect()}
101
- onchange={(e) => row.toggleSelected(e.currentTarget.checked)}
102
- />
103
- </td>
104
- {/if}
105
- {#each getReactiveCells(row, getReactiveTableState(table).columnVisibility) as cell (cell.id)}
106
- {@const columnDef = getColumnMeta(cell.column.columnDef)}
107
- <td
108
- class={cn(
109
- 'items-center truncate px-3 py-2',
110
- alignClass(columnDef?.align),
111
- justifyClass(columnDef?.align),
112
- cell.column.getIsPinned() && 'bg-(--row-bg)'
113
- )}
114
- style={joinStyles(
115
- getColumnMeta(cell.column.columnDef)?.grow
116
- ? virtualGrowColumnSizeStyle()
117
- : virtualColumnSizeStyle(cell.column.getSize()),
118
- getPinningStyle(cell.column, table, false, isRowSelectionEnabled)
119
- )}
120
- >
121
- {#if columnDef?.type === 'boolean'}
122
- {@const value = getBooleanCellValue(cell.getValue())}
123
- {#if value === true}
124
- <span
125
- class="inline-flex size-5 items-center justify-center text-success"
126
- role="img"
127
- aria-label="Yes"
128
- >
129
- <PhCheck class="size-4" />
130
- </span>
131
- {:else if value === false}
132
- <span
133
- class="inline-flex size-5 items-center justify-center text-danger"
134
- role="img"
135
- aria-label="No"
136
- >
137
- <PhX class="size-4" />
138
- </span>
139
- {:else}
140
- -
141
- {/if}
142
- {:else if columnDef?.type === 'url'}
143
- {@const value = getUrlCellValue(cell.getValue())}
144
- {#if value}
145
- <button
146
- type="button"
147
- class={cn(
148
- 'inline-flex max-w-full appearance-none items-center gap-1.5 rounded-sm border-0 bg-transparent p-0 align-middle leading-5 font-medium text-ink underline decoration-border decoration-dotted underline-offset-4 outline-none hover:text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',
149
- justifyClass(columnDef.align)
150
- )}
151
- onclick={() => openUrlCell(value)}
152
- >
153
- <PhArrowSquareOut class="size-3.5 shrink-0" />
154
- </button>
80
+ {#if row}
81
+ {@const rowSelected = getReactiveTableState(table).rowSelection[row.id] === true}
82
+ <tr
83
+ data-index={virtualRow.index}
84
+ use:measureRowElement
85
+ class={cn(
86
+ 'group/row border-b border-surface-2 last:border-b-0',
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
+ style="display: flex; position: absolute; transform: translateY({virtualRow.start}px); width: 100%"
93
+ onclick={(event) => onRowClick?.({ row: row.original, event })}
94
+ ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
95
+ >
96
+ {#if isRowSelectionEnabled}
97
+ <td
98
+ class="items-center justify-center bg-(--row-bg) px-3 py-2 text-center align-middle"
99
+ style={joinStyles(
100
+ virtualSelectionColumnSizeStyle(),
101
+ 'position: sticky; left: 0; z-index: 1'
102
+ )}
103
+ >
104
+ <input
105
+ type="checkbox"
106
+ aria-label="Select row"
107
+ class="table-checkbox mx-auto block size-4"
108
+ checked={rowSelected}
109
+ disabled={!row.getCanSelect()}
110
+ onchange={(e) => row.toggleSelected(e.currentTarget.checked)}
111
+ />
112
+ </td>
113
+ {/if}
114
+ {#each getReactiveCells(row, getReactiveTableState(table).columnVisibility) as cell (cell.id)}
115
+ {@const columnDef = getColumnMeta(cell.column.columnDef)}
116
+ <td
117
+ class={cn(
118
+ 'items-center truncate px-3 py-2',
119
+ alignClass(columnDef?.align),
120
+ justifyClass(columnDef?.align),
121
+ cell.column.getIsPinned() && 'bg-(--row-bg)'
122
+ )}
123
+ style={joinStyles(
124
+ getColumnMeta(cell.column.columnDef)?.grow
125
+ ? virtualGrowColumnSizeStyle()
126
+ : virtualColumnSizeStyle(cell.column.getSize()),
127
+ getPinningStyle(cell.column, table, false, isRowSelectionEnabled)
128
+ )}
129
+ >
130
+ {#if columnDef?.type === 'boolean'}
131
+ {@const value = getBooleanCellValue(cell.getValue())}
132
+ {#if value === true}
133
+ <span
134
+ class="inline-flex size-5 items-center justify-center text-success"
135
+ role="img"
136
+ aria-label="Yes"
137
+ >
138
+ <PhCheck class="size-4" />
139
+ </span>
140
+ {:else if value === false}
141
+ <span
142
+ class="inline-flex size-5 items-center justify-center text-danger"
143
+ role="img"
144
+ aria-label="No"
145
+ >
146
+ <PhX class="size-4" />
147
+ </span>
148
+ {:else}
149
+ -
150
+ {/if}
151
+ {:else if columnDef?.type === 'url'}
152
+ {@const value = getUrlCellValue(cell.getValue())}
153
+ {#if value}
154
+ <button
155
+ type="button"
156
+ class={cn(
157
+ 'inline-flex max-w-full appearance-none items-center gap-1.5 rounded-sm border-0 bg-transparent p-0 align-middle leading-5 font-medium text-ink underline decoration-border decoration-dotted underline-offset-4 outline-none hover:text-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',
158
+ justifyClass(columnDef.align)
159
+ )}
160
+ onclick={() => openUrlCell(value)}
161
+ >
162
+ <PhArrowSquareOut class="size-3.5 shrink-0" />
163
+ </button>
164
+ {:else}
165
+ -
166
+ {/if}
155
167
  {:else}
156
- -
168
+ <FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
157
169
  {/if}
158
- {:else}
159
- <FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
160
- {/if}
161
- </td>
162
- {/each}
163
- </tr>
170
+ </td>
171
+ {/each}
172
+ </tr>
173
+ {/if}
164
174
  {/each}
165
175
  {/if}
166
176
  </tbody>
@@ -7,5 +7,6 @@ export { default as Toolbar } from './data-table-toolbar.svelte';
7
7
  export { default as Title } from './data-table-title.svelte';
8
8
  export { default as ColumnVisibility } from './data-table-column-visibility.svelte';
9
9
  export { default as ColumnFilter } from './data-table-column-filter.svelte';
10
+ export { default as Search } from './data-table-search.svelte';
10
11
  export type { CreateDataTableOptions, DataTableInstance } from './create-table.svelte';
11
12
  export type { DataTableAlign, DataTableAccessorFnColumn, DataTableAccessorKeyColumn, DataTableColumn, DataTableColumnBase, DataTableColumnOptions, DataTableColumnType, DataTableCellPropsResolver, DataTableCellRenderProps, DataTableGroupColumn, DataTableLeafColumnBase, DataTableLeafColumn } from './types';
@@ -7,3 +7,4 @@ export { default as Toolbar } from './data-table-toolbar.svelte';
7
7
  export { default as Title } from './data-table-title.svelte';
8
8
  export { default as ColumnVisibility } from './data-table-column-visibility.svelte';
9
9
  export { default as ColumnFilter } from './data-table-column-filter.svelte';
10
+ export { default as Search } from './data-table-search.svelte';
@@ -1,3 +1,3 @@
1
1
  export { default as Root } from '../data-table-virtualized.svelte';
2
- export { ColumnFilter, ColumnVisibility, FlexRender, Title, Toolbar, createDataTableColumnHelper, createTable, renderComponent, renderSnippet } from '../index';
2
+ export { ColumnFilter, ColumnVisibility, FlexRender, Search, Title, Toolbar, createDataTableColumnHelper, createTable, renderComponent, renderSnippet } from '../index';
3
3
  export type { CreateDataTableOptions, DataTableAccessorFnColumn, DataTableAccessorKeyColumn, DataTableAlign, DataTableCellPropsResolver, DataTableCellRenderProps, DataTableColumn, DataTableColumnBase, DataTableColumnOptions, DataTableColumnType, DataTableGroupColumn, DataTableInstance, DataTableLeafColumn, DataTableLeafColumnBase } from '../index';
@@ -1,2 +1,2 @@
1
1
  export { default as Root } from '../data-table-virtualized.svelte';
2
- export { ColumnFilter, ColumnVisibility, FlexRender, Title, Toolbar, createDataTableColumnHelper, createTable, renderComponent, renderSnippet } from '../index';
2
+ export { ColumnFilter, ColumnVisibility, FlexRender, Search, Title, Toolbar, createDataTableColumnHelper, createTable, renderComponent, renderSnippet } from '../index';
@@ -47,7 +47,7 @@
47
47
  <Select.Control>
48
48
  <Select.Trigger
49
49
  class={cn(
50
- 'flex w-full cursor-pointer items-center justify-between rounded-md border bg-transparent px-3 text-sm shadow-sm focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none active:bg-surface-2 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:border-danger data-invalid:focus-visible:ring-danger',
50
+ 'flex w-full cursor-pointer items-center justify-between rounded-md border bg-surface-1 px-3 text-sm shadow-sm focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none active:bg-surface-2 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:border-danger data-invalid:focus-visible:ring-danger',
51
51
  size === 'sm' ? 'h-8' : 'h-9'
52
52
  )}
53
53
  >
@@ -37,13 +37,15 @@
37
37
  aria-label={`Resize ${panelConfig.id} and ${panels[i + 1].id}`}
38
38
  class={cn(
39
39
  'group relative flex shrink-0 items-center justify-center border-none bg-transparent p-0 outline-none',
40
- isHorizontal ? 'w-1.5 cursor-col-resize' : 'h-1.5 cursor-row-resize'
40
+ isHorizontal
41
+ ? 'w-1.5 cursor-col-resize data-disabled:cursor-default'
42
+ : 'h-1.5 cursor-row-resize data-disabled:cursor-default'
41
43
  )}
42
44
  >
43
45
  <!-- Divider line -->
44
46
  <div
45
47
  class={cn(
46
- 'absolute bg-surface-3 transition-colors group-focus-within:bg-primary group-hover:bg-primary/40 group-data-dragging:bg-primary',
48
+ 'absolute bg-surface-3 transition-colors group-focus-within:bg-primary group-hover:bg-primary/40 group-data-dragging:bg-primary group-data-disabled:bg-border',
47
49
  isHorizontal
48
50
  ? 'inset-y-0 left-1/2 w-px -translate-x-1/2'
49
51
  : 'inset-x-0 top-1/2 h-px -translate-y-1/2'
@@ -52,7 +54,7 @@
52
54
  <!-- Handle pill -->
53
55
  <div
54
56
  class={cn(
55
- 'relative z-10 rounded-full bg-surface-3 shadow-sm transition-colors group-hover:bg-primary/40 group-data-dragging:bg-primary',
57
+ 'relative z-10 rounded-full bg-surface-3 shadow-sm transition-colors group-hover:bg-primary/40 group-data-dragging:bg-primary group-data-disabled:invisible',
56
58
  isHorizontal ? 'h-6 w-1' : 'h-1 w-6'
57
59
  )}
58
60
  ></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compote-ui",
3
- "version": "0.43.15",
3
+ "version": "0.44.1",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev --open",