compote-ui 0.55.3 → 0.56.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 (54) hide show
  1. package/dist/components/data-table-v8/create-table.svelte.js +8 -1
  2. package/dist/components/data-table-v9/column-helper.d.ts +12 -0
  3. package/dist/components/data-table-v9/column-helper.js +42 -0
  4. package/dist/components/data-table-v9/create-table.svelte.d.ts +42 -0
  5. package/dist/components/data-table-v9/create-table.svelte.js +248 -0
  6. package/dist/components/data-table-v9/data-table-cell-content.svelte +66 -0
  7. package/dist/components/data-table-v9/data-table-cell-content.svelte.d.ts +28 -0
  8. package/dist/components/data-table-v9/data-table-foot.svelte +111 -0
  9. package/dist/components/data-table-v9/data-table-foot.svelte.d.ts +32 -0
  10. package/dist/components/{data-table/data-table-head.svelte.md → data-table-v9/data-table-head.svelte} +47 -39
  11. package/dist/components/data-table-v9/data-table-head.svelte.d.ts +32 -0
  12. package/dist/components/data-table-v9/data-table-title.svelte.d.ts +10 -0
  13. package/dist/components/data-table-v9/data-table-utils.d.ts +53 -0
  14. package/dist/components/data-table-v9/data-table-utils.js +181 -0
  15. package/dist/components/data-table-v9/data-table.svelte +151 -0
  16. package/dist/components/data-table-v9/data-table.svelte.d.ts +41 -0
  17. package/dist/components/data-table-v9/features.d.ts +12 -0
  18. package/dist/components/data-table-v9/features.js +14 -0
  19. package/dist/components/data-table-v9/index.d.ts +11 -0
  20. package/dist/components/data-table-v9/index.js +9 -0
  21. package/dist/components/data-table-v9/table-view-state.svelte.d.ts +74 -0
  22. package/dist/components/data-table-v9/table-view-state.svelte.js +182 -0
  23. package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte +380 -0
  24. package/dist/components/data-table-v9/toolbar/data-table-column-filter.svelte.d.ts +29 -0
  25. package/dist/components/data-table-v9/toolbar/data-table-column-visibility.svelte +73 -0
  26. package/dist/components/data-table-v9/toolbar/data-table-column-visibility.svelte.d.ts +29 -0
  27. package/dist/components/data-table-v9/toolbar/data-table-search.svelte +58 -0
  28. package/dist/components/data-table-v9/toolbar/data-table-search.svelte.d.ts +32 -0
  29. package/dist/components/{data-table/data-table-toolbar.svelte.md → data-table-v9/toolbar/data-table-toolbar.svelte} +14 -15
  30. package/dist/components/data-table-v9/toolbar/data-table-toolbar.svelte.d.ts +12 -0
  31. package/dist/components/data-table-v9/types.d.ts +74 -0
  32. package/dist/components/data-table-v9/types.js +1 -0
  33. package/dist/components/data-table-v9/virtual/data-table-virtual-rows.svelte +131 -0
  34. package/dist/components/data-table-v9/virtual/data-table-virtual-rows.svelte.d.ts +40 -0
  35. package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte +79 -0
  36. package/dist/components/data-table-v9/virtual/data-table-virtualized.svelte.d.ts +41 -0
  37. package/dist/components/data-table-v9/virtual/index.d.ts +3 -0
  38. package/dist/components/data-table-v9/virtual/index.js +2 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +4 -0
  41. package/package.json +12 -2
  42. package/dist/components/data-table/column-helper.ts.md +0 -96
  43. package/dist/components/data-table/create-table.ts.md +0 -386
  44. package/dist/components/data-table/data-table-column-filter.svelte.md +0 -249
  45. package/dist/components/data-table/data-table-column-visibility.svelte.md +0 -74
  46. package/dist/components/data-table/data-table-new.svelte.md +0 -245
  47. package/dist/components/data-table/data-table-utils.ts.md +0 -179
  48. package/dist/components/data-table/data-table-virtual-rows.svelte.md +0 -171
  49. package/dist/components/data-table/data-table-virtualized.svelte.md +0 -108
  50. package/dist/components/data-table/data-table.svelte.md +0 -214
  51. package/dist/components/data-table/index.ts.md +0 -22
  52. package/dist/components/data-table/types.ts.md +0 -101
  53. package/dist/components/data-table/virtual/index.ts.md +0 -26
  54. /package/dist/components/{data-table/data-table-title.svelte.md → data-table-v9/data-table-title.svelte} +0 -0
@@ -1,249 +0,0 @@
1
- <script lang="ts" generics="T extends RowData">
2
- import { onDestroy } from 'svelte';
3
- import type { CellData, Column, RowData } from '@tanstack/svelte-table';
4
- import * as Popover from '../popover';
5
- import * as ScrollArea from '../scroll-area';
6
- import Checkbox from '../checkbox/checkbox.svelte';
7
- import { cn } from 'tailwind-variants';
8
- import type { DataTableFeatures, DataTableInstance } from './create-table';
9
- import NumberInput from '../number-input/number-input.svelte';
10
- import * as Field from '../field';
11
-
12
- type Props = {
13
- table: DataTableInstance<T>;
14
- triggerLabel?: string;
15
- };
16
-
17
- let { table, triggerLabel = 'Filters' }: Props = $props();
18
-
19
- let localText: Record<string, string> = $state({});
20
- let localNumMin: Record<string, number> = $state({});
21
- let localNumMax: Record<string, number> = $state({});
22
- const timers: Record<string, ReturnType<typeof setTimeout>> = {};
23
-
24
- const columnFilters = $derived(table.store.state.columnFilters);
25
- const activeCount = $derived(columnFilters.length);
26
- const filterableColumns = $derived(table.getAllLeafColumns().filter((col) => col.getCanFilter()));
27
-
28
- onDestroy(() => {
29
- Object.values(timers).forEach(clearTimeout);
30
- });
31
-
32
- function getColumnType(column: Column<DataTableFeatures, T, CellData>): string | undefined {
33
- return (column.columnDef.meta as Record<string, unknown> | undefined)?.type as
34
- | string
35
- | undefined;
36
- }
37
-
38
- function getColumnLabel(column: Column<DataTableFeatures, T, CellData>): string {
39
- return typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id;
40
- }
41
-
42
- function clearFilters() {
43
- Object.values(timers).forEach(clearTimeout);
44
- for (const key of Object.keys(timers)) delete timers[key];
45
- localText = {};
46
- localNumMin = {};
47
- localNumMax = {};
48
- table.resetColumnFilters();
49
- }
50
-
51
- function handleTextInput(column: Column<DataTableFeatures, T, CellData>, value: string) {
52
- localText[column.id] = value;
53
- clearTimeout(timers[column.id]);
54
- timers[column.id] = setTimeout(() => {
55
- column.setFilterValue(value || undefined);
56
- }, 300);
57
- }
58
-
59
- function handleNumericInput(
60
- column: Column<DataTableFeatures, T, CellData>,
61
- which: 'min' | 'max',
62
- value: number | null
63
- ) {
64
- if (value === null) {
65
- if (which === 'min') delete localNumMin[column.id];
66
- else delete localNumMax[column.id];
67
- } else {
68
- if (which === 'min') localNumMin[column.id] = value;
69
- else localNumMax[column.id] = value;
70
- }
71
- clearTimeout(timers[`${column.id}_${which}`]);
72
- timers[`${column.id}_${which}`] = setTimeout(() => {
73
- const min = localNumMin[column.id];
74
- const max = localNumMax[column.id];
75
- column.setFilterValue(min === undefined && max === undefined ? undefined : [min, max]);
76
- }, 300);
77
- }
78
-
79
- function getSelectValues(column: Column<DataTableFeatures, T, CellData>): string[] {
80
- return (column.getFilterValue() as string[] | undefined) ?? [];
81
- }
82
-
83
- function handleSelectChange(
84
- column: Column<DataTableFeatures, T, CellData>,
85
- value: string,
86
- checked: boolean
87
- ) {
88
- const current = getSelectValues(column);
89
- const next = checked ? [...current, value] : current.filter((v) => v !== value);
90
- column.setFilterValue(next.length ? next : undefined);
91
- }
92
-
93
- function getFacetedValues(column: Column<DataTableFeatures, T, CellData>): string[] {
94
- return Array.from(column.getFacetedUniqueValues().keys()).map(String).sort();
95
- }
96
-
97
- function getFacetedMinMax(
98
- column: Column<DataTableFeatures, T, CellData>
99
- ): [number | undefined, number | undefined] {
100
- const vals = column.getFacetedMinMaxValues();
101
- return vals ? [vals[0] as number, vals[1] as number] : [undefined, undefined];
102
- }
103
-
104
- function getColumnFormatOptions(
105
- column: Column<DataTableFeatures, T, CellData>
106
- ): Intl.NumberFormatOptions | undefined {
107
- return (column.columnDef.meta as Record<string, unknown> | undefined)?.formatOptions as
108
- | Intl.NumberFormatOptions
109
- | undefined;
110
- }
111
- </script>
112
-
113
- <Popover.Root positioning={{ placement: 'bottom-end' }}>
114
- <Popover.Trigger
115
- 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" >
116
- {triggerLabel}{#if activeCount > 0}
117
- ({activeCount}){/if}
118
- </Popover.Trigger>
119
-
120
- <Popover.Content class="w-72 px-0" showArrow={false}>
121
- <div class="mb-2 flex items-center justify-between px-4">
122
- <span class="text-sm font-medium text-ink">Filters</span>
123
- {#if activeCount > 0}
124
- <button type="button" onclick={clearFilters} class="text-xs text-primary hover:underline">
125
- Clear all
126
- </button>
127
- {/if}
128
- </div>
129
- <div class="mb-2 border-b border-surface-3"></div>
130
-
131
- <ScrollArea.Root class="h-80">
132
- <ScrollArea.Viewport>
133
- <ScrollArea.Content>
134
- {#each filterableColumns as column (column.id)}
135
- <div class="mb-3">
136
- <p class="mb-1 text-xs font-medium text-ink">{getColumnLabel(column)}</p>
137
-
138
- {#if getColumnType(column) === 'number' || getColumnType(column) === 'currency' || getColumnType(column) === 'percent'}
139
- {@const [facetMin, facetMax] = getFacetedMinMax(column)}
140
- {@const colFormatOptions = getColumnFormatOptions(column)}
141
- <div class="flex gap-1.5">
142
- <div class="min-w-0 flex-1">
143
- <p class="mb-1 text-xs text-ink-dim">From</p>
144
- <NumberInput
145
- value={localNumMin[column.id] ?? facetMin ?? null}
146
- min={facetMin}
147
- max={facetMax}
148
- formatOptions={colFormatOptions}
149
- onValueChange={({ valueAsNumber }) =>
150
- handleNumericInput(
151
- column,
152
- 'min',
153
- isNaN(valueAsNumber) ? null : valueAsNumber
154
- )}
155
- />
156
- </div>
157
- <div class="min-w-0 flex-1">
158
- <p class="mb-1 text-xs text-ink-dim">To</p>
159
- <NumberInput
160
- value={localNumMax[column.id] ?? facetMax ?? null}
161
- min={facetMin}
162
- max={facetMax}
163
- formatOptions={colFormatOptions}
164
- onValueChange={({ valueAsNumber }) =>
165
- handleNumericInput(
166
- column,
167
- 'max',
168
- isNaN(valueAsNumber) ? null : valueAsNumber
169
- )}
170
- />
171
- </div>
172
- </div>
173
- {:else if getColumnType(column) === 'boolean'}
174
- {@const boolFilter = column.getFilterValue() as boolean | undefined}
175
- <div class="flex overflow-hidden rounded border border-border text-xs">
176
- <button
177
- type="button"
178
- onclick={() => column.setFilterValue(undefined)}
179
- class={cn(
180
- 'flex-1 px-2 py-1',
181
- boolFilter === undefined
182
- ? 'bg-surface-3 font-medium text-ink'
183
- : 'text-ink-dim hover:bg-surface-2'
184
- )}
185
- >
186
- All
187
- </button>
188
- <button
189
- type="button"
190
- onclick={() => column.setFilterValue(boolFilter === true ? undefined : true)}
191
- class={cn(
192
- 'flex-1 border-x border-border px-2 py-1',
193
- boolFilter === true
194
- ? 'bg-surface-3 font-medium text-ink'
195
- : 'text-ink-dim hover:bg-surface-2'
196
- )}
197
- >
198
- Yes
199
- </button>
200
- <button
201
- type="button"
202
- onclick={() => column.setFilterValue(boolFilter === false ? undefined : false)}
203
- class={cn(
204
- 'flex-1 px-2 py-1',
205
- boolFilter === false
206
- ? 'bg-surface-3 font-medium text-ink'
207
- : 'text-ink-dim hover:bg-surface-2'
208
- )}
209
- >
210
- No
211
- </button>
212
- </div>
213
- {:else if getColumnType(column) === 'select'}
214
- {@const options = getFacetedValues(column)}
215
- {@const selected = getSelectValues(column)}
216
- <div class="flex flex-col gap-0.5">
217
- {#each options as option (option)}
218
- <Checkbox
219
- size="sm"
220
- label={option}
221
- class="min-h-7 rounded-sm px-2 hover:bg-surface-2"
222
- checked={selected.includes(option)}
223
- onCheckedChange={({ checked }) =>
224
- handleSelectChange(column, option, checked === true)}
225
- />
226
- {/each}
227
- </div>
228
- {:else}
229
- <Field.Root>
230
- <Field.Input
231
- placeholder="Search..."
232
- value={localText[column.id] ?? ''}
233
- oninput={(e: Event) =>
234
- handleTextInput(column, (e.currentTarget as HTMLInputElement).value)}
235
- />
236
- </Field.Root>
237
- {/if}
238
- </div>
239
- {/each}
240
- </ScrollArea.Content>
241
- </ScrollArea.Viewport>
242
- <ScrollArea.Scrollbar orientation="vertical">
243
- <ScrollArea.Thumb />
244
- </ScrollArea.Scrollbar>
245
- <ScrollArea.Corner />
246
- </ScrollArea.Root>
247
- </Popover.Content>
248
-
249
- </Popover.Root>
@@ -1,74 +0,0 @@
1
- <script lang="ts" generics="T extends RowData">
2
- import type { CellData, Column, RowData } from '@tanstack/svelte-table';
3
- import * as Popover from '../popover';
4
- import * as ScrollArea from '../scroll-area';
5
- import Checkbox from '../checkbox/checkbox.svelte';
6
- import type { DataTableFeatures, DataTableInstance } from './create-table';
7
-
8
- type Props = {
9
- table: DataTableInstance<T>;
10
- triggerLabel?: string;
11
- };
12
-
13
- let { table, triggerLabel = 'Columns' }: Props = $props();
14
-
15
- const columnVisibility = $derived(table.store.state.columnVisibility);
16
- const allColumnsVisible = $derived(table.getIsAllColumnsVisible());
17
- const someColumnsVisible = $derived(
18
- table.getAllLeafColumns().some((column) => column.getCanHide() && column.getIsVisible())
19
- );
20
- const allColumnsVisibilityState = $derived(
21
- allColumnsVisible ? true : someColumnsVisible ? 'indeterminate' : false
22
- );
23
-
24
- function getColumnLabel(column: Column<DataTableFeatures, T, CellData>) {
25
- return typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id;
26
- }
27
-
28
- function getColumnIsVisible(column: Column<DataTableFeatures, T, CellData>, state: unknown) {
29
- void state;
30
- return column.getIsVisible();
31
- }
32
- </script>
33
-
34
- <Popover.Root positioning={{ placement: 'bottom-end' }}>
35
- <Popover.Trigger
36
- 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" >
37
- {triggerLabel}
38
- </Popover.Trigger>
39
-
40
- <Popover.Content class="w-56 p-2" showArrow={false}>
41
- <div class="border-b border-surface-3 px-2 pb-2">
42
- <Checkbox
43
- size="sm"
44
- label="All columns"
45
- checked={allColumnsVisibilityState}
46
- onCheckedChange={({ checked }) => table.toggleAllColumnsVisible(checked === true)}
47
- />
48
- </div>
49
-
50
- <ScrollArea.Root class="h-72">
51
- <ScrollArea.Viewport>
52
- <ScrollArea.Content class="py-1 pe-3">
53
- <div class="flex flex-col">
54
- {#each table.getAllLeafColumns() as column (column.id)}
55
- <Checkbox
56
- size="md"
57
- label={getColumnLabel(column)}
58
- class="min-h-8 rounded-sm px-2 hover:bg-surface-2"
59
- checked={getColumnIsVisible(column, columnVisibility)}
60
- disabled={!column.getCanHide()}
61
- onCheckedChange={({ checked }) => column.toggleVisibility(checked === true)}
62
- />
63
- {/each}
64
- </div>
65
- </ScrollArea.Content>
66
- </ScrollArea.Viewport>
67
- <ScrollArea.Scrollbar orientation="vertical">
68
- <ScrollArea.Thumb />
69
- </ScrollArea.Scrollbar>
70
- <ScrollArea.Corner />
71
- </ScrollArea.Root>
72
- </Popover.Content>
73
-
74
- </Popover.Root>
@@ -1,245 +0,0 @@
1
- <script lang="ts" generics="T extends RowData">
2
- import { FlexRender } from '@tanstack/svelte-table';
3
- import type { RowData } from '@tanstack/svelte-table';
4
- import type { HTMLAttributes } from 'svelte/elements';
5
- import { untrack } from 'svelte';
6
- import { createSubscriber } from 'svelte/reactivity';
7
- import { cn, type ClassValue } from 'tailwind-variants';
8
- import { PhArrowSquareOut, PhCheck, PhX } from '$lib/icons';
9
- import Checkbox from '../checkbox/checkbox.svelte';
10
- import { type DataTableInstance } from './create-table';
11
- import {
12
- alignClass,
13
- getBooleanCellValue,
14
- getColumnMeta,
15
- getUrlCellValue,
16
- justifyClass,
17
- openUrlCell
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 subscribeToTable = createSubscriber((update) => {
40
- const sub = table.store.subscribe(() => update());
41
- return () => sub.unsubscribe();
42
- });
43
-
44
- const rowModel = $derived(table.getRowModel());
45
- const headerGroups = $derived(table.getHeaderGroups());
46
-
47
- const columnSizes = $derived.by(() => {
48
- subscribeToTable();
49
- return untrack(() =>
50
- table.getVisibleLeafColumns().map((col) => ({
51
- id: col.id,
52
- size: col.getSize(),
53
- grow: getColumnMeta(col.columnDef)?.grow ?? false
54
- }))
55
- );
56
- });
57
- const hasGrowColumn = $derived(columnSizes.some((c) => c.grow));
58
- const tableWidth = $derived.by(() => {
59
- subscribeToTable();
60
- return untrack(() => table.getTotalSize());
61
- });
62
- const isRowSelectionEnabled = $derived(Boolean(table.options.enableRowSelection));
63
- const isMultiRowSelectionEnabled = $derived(table.options.enableMultiRowSelection !== false);
64
- // table.state is the public selected state — safe to read directly in template
65
- // table.store.state is the internal TanStack atom — accumulates subscriptions
66
- const rowSelection = $derived(table.state.rowSelection);
67
- const selectedCount = $derived(Object.keys(rowSelection).length);
68
- </script>
69
-
70
- <div
71
- class={cn(
72
- 'flex max-h-full min-h-0 flex-col overflow-hidden rounded-lg border border-surface-3 bg-surface-1',
73
- className
74
- )}
75
- {...rest}
76
- >
77
- <div class="min-h-0 flex-1 overflow-auto">
78
- <table
79
- class="table-fixed border-separate border-spacing-0 text-sm"
80
- style="width: max(100%, {tableWidth + (isRowSelectionEnabled ? 40 : 0)}px)"
81
- >
82
- <colgroup>
83
- {#if isRowSelectionEnabled}
84
- <col style="width: 40px" />
85
- {/if}
86
- {#each columnSizes as col (col.id)}
87
- <col style={col.grow ? undefined : `width: ${col.size}px`} />
88
- {/each}
89
- {#if !hasGrowColumn}
90
- <col />
91
- {/if}
92
- </colgroup>
93
- {#if caption}
94
- <caption class="sr-only">{caption}</caption>
95
- {/if}
96
- <thead class="sticky top-0 z-20 bg-surface-2 text-left text-ink-dim">
97
- {#each headerGroups as headerGroup, headerGroupIndex (headerGroup.id)}
98
- <tr class="h-9">
99
- {#if isRowSelectionEnabled}
100
- <th
101
- class="h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 text-center align-middle"
102
- style="position: sticky; left: 0; z-index: 15; width: 40px; min-width: 40px; max-width: 40px"
103
- >
104
- {#if isMultiRowSelectionEnabled && headerGroupIndex === headerGroups.length - 1}
105
- <Checkbox
106
- size="sm"
107
- aria-label="Select all rows"
108
- class="mx-auto size-4"
109
- checked={table.getIsAllRowsSelected()
110
- ? true
111
- : table.getIsSomeRowsSelected()
112
- ? 'indeterminate'
113
- : false}
114
- onCheckedChange={({ checked }) => table.toggleAllRowsSelected(checked === true)}
115
- />
116
- {/if}
117
- </th>
118
- {/if}
119
- {#each headerGroup.headers as header (header.id)}
120
- {@const columnDef = getColumnMeta(header.column.columnDef)}
121
- <th
122
- class={cn(
123
- 'h-9 border-b border-surface-3 bg-surface-2 px-3 py-0 align-middle leading-5 font-medium',
124
- alignClass(columnDef?.align)
125
- )}
126
- colspan={header.colSpan}
127
- >
128
- {#if !header.isPlaceholder}
129
- <FlexRender {header} />
130
- {/if}
131
- </th>
132
- {/each}
133
- {#if !hasGrowColumn}
134
- <th aria-hidden="true" class="h-9 border-b border-surface-3 bg-surface-2 p-0"></th>
135
- {/if}
136
- </tr>
137
- {/each}
138
- </thead>
139
- <tbody>
140
- {#each rowModel.rows as row (row.id)}
141
- {@const isSelected = Boolean(rowSelection[row.id])}
142
- <tr
143
- class={cn(
144
- 'group/row',
145
- '[--row-bg:var(--compote-surface-1)]',
146
- 'hover:bg-well/60 hover:[--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]',
147
- isSelected &&
148
- 'bg-well/60 [--row-bg:color-mix(in_srgb,var(--compote-well)_60%,var(--compote-surface-1))]'
149
- )}
150
- onclick={(event) => onRowClick?.({ row: row.original, event })}
151
- ondblclick={(event) => onRowDoubleClick?.({ row: row.original, event })}
152
- >
153
- {#if isRowSelectionEnabled}
154
- <td
155
- class="border-b border-surface-2 bg-(--row-bg) px-3 py-2 text-center align-middle group-last/row:border-b-0"
156
- style="position: sticky; left: 0; z-index: 1"
157
- >
158
- <Checkbox
159
- size="sm"
160
- aria-label="Select row"
161
- class="mx-auto size-4"
162
- checked={isSelected}
163
- disabled={!row.getCanSelect()}
164
- onCheckedChange={({ checked }) => row.toggleSelected(checked === true)}
165
- />
166
- </td>
167
- {/if}
168
- {#each row.getVisibleCells() as cell (cell.id)}
169
- {@const columnDef = getColumnMeta(cell.column.columnDef)}
170
- <td
171
- class={cn(
172
- 'truncate border-b border-b-surface-2 px-3 py-2 group-last/row:border-b-0',
173
- alignClass(columnDef?.align)
174
- )}
175
- >
176
- {#if columnDef?.type === 'boolean'}
177
- {@const value = getBooleanCellValue(cell.getValue())}
178
- {#if value === true}
179
- <span
180
- class="inline-flex size-5 items-center justify-center text-success"
181
- role="img"
182
- aria-label="Yes"
183
- >
184
- <PhCheck class="size-4" />
185
- </span>
186
- {:else if value === false}
187
- <span
188
- class="inline-flex size-5 items-center justify-center text-danger"
189
- role="img"
190
- aria-label="No"
191
- >
192
- <PhX class="size-4" />
193
- </span>
194
- {:else}
195
- -
196
- {/if}
197
- {:else if columnDef?.type === 'url'}
198
- {@const value = getUrlCellValue(cell.getValue())}
199
- {#if value}
200
- <button
201
- type="button"
202
- class={cn(
203
- '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',
204
- justifyClass(columnDef.align)
205
- )}
206
- onclick={() => openUrlCell(value)}
207
- >
208
- <PhArrowSquareOut class="size-3.5 shrink-0" />
209
- </button>
210
- {:else}
211
- -
212
- {/if}
213
- {:else}
214
- <FlexRender {cell} />
215
- {/if}
216
- </td>
217
- {/each}
218
- {#if !hasGrowColumn}
219
- <td aria-hidden="true" class="border-b border-surface-2 p-0 group-last/row:border-b-0"
220
- ></td>
221
- {/if}
222
- </tr>
223
- {:else}
224
- <tr>
225
- <td
226
- class="px-3 py-10 text-center text-sm text-ink-dim"
227
- colspan={columnSizes.length + (isRowSelectionEnabled ? 2 : 1)}
228
- >
229
- {emptyMessage}
230
- </td>
231
- </tr>
232
- {/each}
233
- </tbody>
234
- </table>
235
- </div>
236
-
237
- <div class="shrink-0 border-t border-surface-3 bg-surface-2 px-3 py-2 text-sm text-ink-dim">
238
- {#if isRowSelectionEnabled}
239
- {selectedCount} of {rowModel.rows.length} rows selected
240
- {:else}
241
- {rowModel.rows.length} rows
242
- {/if}
243
- </div>
244
-
245
- </div>