@loidolt/theme-svelte 0.4.0 → 0.6.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/README.md +11 -0
- package/dist/announcer.svelte.d.ts +36 -0
- package/dist/announcer.svelte.js +73 -0
- package/dist/attachments.d.ts +83 -0
- package/dist/attachments.js +211 -0
- package/dist/components/ActiveFilterChips.svelte +80 -0
- package/dist/components/ActiveFilterChips.svelte.d.ts +41 -0
- package/dist/components/AlertDialog.svelte +4 -4
- package/dist/components/AppShell.svelte +9 -2
- package/dist/components/AppShell.svelte.d.ts +3 -1
- package/dist/components/AspectRatio.svelte +32 -0
- package/dist/components/AspectRatio.svelte.d.ts +13 -0
- package/dist/components/AudioPlayer.svelte +94 -0
- package/dist/components/AudioPlayer.svelte.d.ts +24 -0
- package/dist/components/Avatar.svelte +85 -0
- package/dist/components/Avatar.svelte.d.ts +31 -0
- package/dist/components/Badge.svelte +28 -2
- package/dist/components/Badge.svelte.d.ts +13 -1
- package/dist/components/Combobox.svelte +180 -0
- package/dist/components/Combobox.svelte.d.ts +77 -0
- package/dist/components/DataTable.svelte +228 -0
- package/dist/components/DataTable.svelte.d.ts +62 -0
- package/dist/components/DataTableColumnVisibility.svelte +46 -0
- package/dist/components/DataTableColumnVisibility.svelte.d.ts +31 -0
- package/dist/components/DataTableFacetedFilter.svelte +87 -0
- package/dist/components/DataTableFacetedFilter.svelte.d.ts +40 -0
- package/dist/components/DataTablePagination.svelte +68 -0
- package/dist/components/DataTablePagination.svelte.d.ts +42 -0
- package/dist/components/DataTableSearch.svelte +67 -0
- package/dist/components/DataTableSearch.svelte.d.ts +37 -0
- package/dist/components/Dialog.svelte +35 -14
- package/dist/components/Dialog.svelte.d.ts +7 -0
- package/dist/components/Drawer.svelte +3 -3
- package/dist/components/DropdownMenu.svelte +95 -28
- package/dist/components/DropdownMenu.svelte.d.ts +12 -3
- package/dist/components/Field.svelte +2 -3
- package/dist/components/Fieldset.svelte +2 -3
- package/dist/components/Filmstrip.svelte +10 -3
- package/dist/components/FilterPanel.svelte +62 -0
- package/dist/components/FilterPanel.svelte.d.ts +22 -0
- package/dist/components/Lightbox.svelte +239 -0
- package/dist/components/Lightbox.svelte.d.ts +40 -0
- package/dist/components/LiveRegion.svelte +48 -0
- package/dist/components/LiveRegion.svelte.d.ts +20 -0
- package/dist/components/MediaCarousel.svelte +177 -0
- package/dist/components/MediaCarousel.svelte.d.ts +32 -0
- package/dist/components/MediaEmbed.svelte +116 -0
- package/dist/components/MediaEmbed.svelte.d.ts +34 -0
- package/dist/components/MediaGrid.svelte +91 -0
- package/dist/components/MediaGrid.svelte.d.ts +24 -0
- package/dist/components/MultiSelect.svelte +232 -0
- package/dist/components/MultiSelect.svelte.d.ts +67 -0
- package/dist/components/NumberField.svelte +53 -25
- package/dist/components/NumberField.svelte.d.ts +47 -18
- package/dist/components/OTPInput.svelte +94 -0
- package/dist/components/OTPInput.svelte.d.ts +26 -0
- package/dist/components/PasswordInput.svelte +93 -0
- package/dist/components/PasswordInput.svelte.d.ts +24 -0
- package/dist/components/Progress.svelte +57 -14
- package/dist/components/Progress.svelte.d.ts +13 -0
- package/dist/components/RadioGroup.svelte +19 -5
- package/dist/components/RadioGroup.svelte.d.ts +3 -2
- package/dist/components/Select.svelte +15 -5
- package/dist/components/Select.svelte.d.ts +3 -2
- package/dist/components/SignaturePad.svelte +317 -0
- package/dist/components/SignaturePad.svelte.d.ts +48 -0
- package/dist/components/Skeleton.svelte +40 -9
- package/dist/components/Skeleton.svelte.d.ts +8 -0
- package/dist/components/SkipLink.svelte +48 -0
- package/dist/components/SkipLink.svelte.d.ts +14 -0
- package/dist/components/Slider.svelte +148 -0
- package/dist/components/Slider.svelte.d.ts +55 -0
- package/dist/components/Spinner.svelte +11 -2
- package/dist/components/Spinner.svelte.d.ts +3 -0
- package/dist/components/Tabs.svelte.d.ts +1 -1
- package/dist/components/Thumbnail.svelte +52 -6
- package/dist/components/Thumbnail.svelte.d.ts +14 -2
- package/dist/components/Toast.svelte +24 -0
- package/dist/components/Toast.svelte.d.ts +10 -0
- package/dist/components/ToastViewport.svelte +10 -1
- package/dist/components/ToastViewport.svelte.d.ts +2 -0
- package/dist/components/Toolbar.svelte +49 -0
- package/dist/components/Toolbar.svelte.d.ts +23 -0
- package/dist/components/Tooltip.svelte +9 -1
- package/dist/components/Tooltip.svelte.d.ts +2 -0
- package/dist/components/VideoPlayer.svelte +136 -0
- package/dist/components/VideoPlayer.svelte.d.ts +38 -0
- package/dist/data-table-utils.d.ts +62 -0
- package/dist/data-table-utils.js +91 -0
- package/dist/data-table.svelte.d.ts +132 -0
- package/dist/data-table.svelte.js +292 -0
- package/dist/hls.d.ts +35 -0
- package/dist/hls.js +37 -0
- package/dist/hls.svelte.d.ts +22 -0
- package/dist/hls.svelte.js +66 -0
- package/dist/index.d.ts +47 -4
- package/dist/index.js +35 -2
- package/dist/internal/EditableCell.svelte +58 -0
- package/dist/internal/EditableCell.svelte.d.ts +8 -0
- package/dist/internal/ListboxEntries.svelte +49 -0
- package/dist/internal/ListboxEntries.svelte.d.ts +35 -0
- package/dist/internal/media/MediaControls.svelte +163 -0
- package/dist/internal/media/MediaControls.svelte.d.ts +12 -0
- package/dist/internal/media/MediaStage.svelte +49 -0
- package/dist/internal/media/MediaStage.svelte.d.ts +11 -0
- package/dist/internal/media/MediaTile.svelte +36 -0
- package/dist/internal/media/MediaTile.svelte.d.ts +11 -0
- package/dist/internal/media/keys.d.ts +7 -0
- package/dist/internal/media/keys.js +51 -0
- package/dist/internal/media/labels.d.ts +19 -0
- package/dist/internal/media/labels.js +15 -0
- package/dist/internal/options.d.ts +9 -0
- package/dist/internal/options.js +20 -0
- package/dist/media-player.svelte.d.ts +61 -0
- package/dist/media-player.svelte.js +246 -0
- package/dist/media-utils.d.ts +112 -0
- package/dist/media-utils.js +205 -0
- package/dist/media-zoom.svelte.d.ts +33 -0
- package/dist/media-zoom.svelte.js +126 -0
- package/dist/signature.d.ts +55 -0
- package/dist/signature.js +52 -0
- package/dist/toaster.svelte.d.ts +31 -2
- package/dist/toaster.svelte.js +30 -2
- package/dist/types.d.ts +62 -3
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +11 -0
- package/package.json +10 -4
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLTableAttributes } from 'svelte/elements';
|
|
4
|
+
import type { DataTableRow, DataTableState } from '../data-table.svelte.js';
|
|
5
|
+
import EditableCell from '../internal/EditableCell.svelte';
|
|
6
|
+
import Checkbox from './Checkbox.svelte';
|
|
7
|
+
import EmptyState from './EmptyState.svelte';
|
|
8
|
+
import Skeleton from './Skeleton.svelte';
|
|
9
|
+
import Table from './Table.svelte';
|
|
10
|
+
import TableHeader from './TableHeader.svelte';
|
|
11
|
+
|
|
12
|
+
interface Props extends Omit<HTMLTableAttributes, 'children'> {
|
|
13
|
+
/** The state from `createDataTable()`. */
|
|
14
|
+
table: DataTableState<T>;
|
|
15
|
+
caption?: string;
|
|
16
|
+
regionLabel?: string;
|
|
17
|
+
/** Pin the header row. Needs `--ldt-table-height` on the wrapper. */
|
|
18
|
+
sticky?: boolean;
|
|
19
|
+
/** Show placeholder rows while data is on its way. */
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
loadingRows?: number;
|
|
22
|
+
/** Shown when no rows remain. Defaults to an `EmptyState` from `emptyTitle`. */
|
|
23
|
+
empty?: Snippet;
|
|
24
|
+
emptyTitle?: string;
|
|
25
|
+
emptyDescription?: string;
|
|
26
|
+
/** Render each row yourself. Receives the row; output a whole `<tr>`. */
|
|
27
|
+
row?: Snippet<[DataTableRow<T>]>;
|
|
28
|
+
/** Accessible name of a row's selection control. */
|
|
29
|
+
selectLabel?: (row: T) => string;
|
|
30
|
+
selectAllLabel?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Render only the rows scrolled into view — for thousands of rows on one page. Every row must
|
|
33
|
+
* be `rowHeight` pixels tall, and the wrapper needs `--ldt-table-height` (with `sticky`).
|
|
34
|
+
*/
|
|
35
|
+
virtual?: { rowHeight: number; overscan?: number };
|
|
36
|
+
/** Called when an `editable` cell is saved. Update your data in response. */
|
|
37
|
+
onCellEdit?: (row: T, columnId: string, value: string) => void;
|
|
38
|
+
editLabel?: (header: string) => string;
|
|
39
|
+
/** `class` lands on the `<table>`; `wrapperClass` on the scroll container. */
|
|
40
|
+
class?: string;
|
|
41
|
+
wrapperClass?: string;
|
|
42
|
+
ref?: HTMLTableElement | null;
|
|
43
|
+
wrapperRef?: HTMLDivElement | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
table,
|
|
48
|
+
caption,
|
|
49
|
+
regionLabel,
|
|
50
|
+
sticky = false,
|
|
51
|
+
loading = false,
|
|
52
|
+
loadingRows = 5,
|
|
53
|
+
empty,
|
|
54
|
+
emptyTitle = 'No results',
|
|
55
|
+
emptyDescription,
|
|
56
|
+
row: rowSnippet,
|
|
57
|
+
selectLabel = () => 'Select row',
|
|
58
|
+
selectAllLabel = 'Select all rows on this page',
|
|
59
|
+
virtual,
|
|
60
|
+
onCellEdit,
|
|
61
|
+
editLabel = (header) => `Edit ${header}`,
|
|
62
|
+
class: className,
|
|
63
|
+
wrapperClass,
|
|
64
|
+
ref = $bindable(null),
|
|
65
|
+
wrapperRef = $bindable(null),
|
|
66
|
+
...rest
|
|
67
|
+
}: Props = $props();
|
|
68
|
+
|
|
69
|
+
const generatedName = $props.id();
|
|
70
|
+
const selectable = $derived(table.selection !== 'none');
|
|
71
|
+
const columnCount = $derived(table.columns.length + (selectable ? 1 : 0));
|
|
72
|
+
// Rows before this page, so aria-rowindex counts from the top of the whole result.
|
|
73
|
+
const offset = $derived(
|
|
74
|
+
table.rows.length === table.rowCount ? 0 : (table.page - 1) * table.pageSize
|
|
75
|
+
);
|
|
76
|
+
const described = $derived(table.rows.length < table.rowCount);
|
|
77
|
+
|
|
78
|
+
// Virtual window: which slice of the page's rows is in view, plus padding rows above and below.
|
|
79
|
+
let scrollTop = $state(0);
|
|
80
|
+
let viewport = $state(0);
|
|
81
|
+
$effect(() => {
|
|
82
|
+
if (!virtual || !wrapperRef) return;
|
|
83
|
+
const node = wrapperRef;
|
|
84
|
+
const measure = () => {
|
|
85
|
+
scrollTop = node.scrollTop;
|
|
86
|
+
viewport = node.clientHeight;
|
|
87
|
+
};
|
|
88
|
+
measure();
|
|
89
|
+
node.addEventListener('scroll', measure, { passive: true });
|
|
90
|
+
const observer = new ResizeObserver(measure);
|
|
91
|
+
observer.observe(node);
|
|
92
|
+
return () => {
|
|
93
|
+
node.removeEventListener('scroll', measure);
|
|
94
|
+
observer.disconnect();
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
const windowed = $derived.by(() => {
|
|
98
|
+
const all = table.rows;
|
|
99
|
+
if (!virtual) return { rows: all, start: 0, before: 0, after: 0 };
|
|
100
|
+
const { rowHeight, overscan = 6 } = virtual;
|
|
101
|
+
const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
|
|
102
|
+
// Before the wrapper has been measured (and on the server) render one screenful.
|
|
103
|
+
const visible = Math.ceil((viewport || rowHeight * 20) / rowHeight) + overscan * 2;
|
|
104
|
+
const end = Math.min(all.length, start + visible);
|
|
105
|
+
return {
|
|
106
|
+
rows: all.slice(start, end),
|
|
107
|
+
start,
|
|
108
|
+
before: start * rowHeight,
|
|
109
|
+
after: (all.length - end) * rowHeight,
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
{#snippet nothing()}
|
|
115
|
+
{#if empty}{@render empty()}{:else}<EmptyState
|
|
116
|
+
title={emptyTitle}
|
|
117
|
+
description={emptyDescription}
|
|
118
|
+
/>{/if}
|
|
119
|
+
{/snippet}
|
|
120
|
+
|
|
121
|
+
{#snippet selectCell(item: DataTableRow<T>)}
|
|
122
|
+
<td class="ldt-data-table__select">
|
|
123
|
+
{#if table.selection === 'multiple'}
|
|
124
|
+
<Checkbox
|
|
125
|
+
checked={item.selected}
|
|
126
|
+
disabled={!table.isSelectable(item)}
|
|
127
|
+
aria-label={selectLabel(item.original)}
|
|
128
|
+
onCheckedChange={(checked) => table.select(item.id, checked)}
|
|
129
|
+
/>
|
|
130
|
+
{:else}
|
|
131
|
+
<input
|
|
132
|
+
type="radio"
|
|
133
|
+
class="ldt-data-table__radio"
|
|
134
|
+
name={generatedName}
|
|
135
|
+
checked={item.selected}
|
|
136
|
+
disabled={!table.isSelectable(item)}
|
|
137
|
+
aria-label={selectLabel(item.original)}
|
|
138
|
+
onchange={() => table.select(item.id, true)}
|
|
139
|
+
/>
|
|
140
|
+
{/if}
|
|
141
|
+
</td>
|
|
142
|
+
{/snippet}
|
|
143
|
+
|
|
144
|
+
<Table
|
|
145
|
+
bind:ref
|
|
146
|
+
bind:wrapperRef
|
|
147
|
+
{caption}
|
|
148
|
+
{regionLabel}
|
|
149
|
+
{sticky}
|
|
150
|
+
columns={columnCount}
|
|
151
|
+
empty={!loading && table.rows.length === 0 ? nothing : undefined}
|
|
152
|
+
class={className}
|
|
153
|
+
wrapperClass={['ldt-data-table', wrapperClass].filter(Boolean).join(' ')}
|
|
154
|
+
aria-busy={loading || undefined}
|
|
155
|
+
aria-rowcount={described ? table.rowCount + 1 : undefined}
|
|
156
|
+
{...rest}
|
|
157
|
+
>
|
|
158
|
+
<thead>
|
|
159
|
+
<tr aria-rowindex={described ? 1 : undefined}>
|
|
160
|
+
{#if selectable}
|
|
161
|
+
<th scope="col" class="ldt-data-table__select">
|
|
162
|
+
{#if table.selection === 'multiple'}
|
|
163
|
+
<Checkbox
|
|
164
|
+
checked={table.allSelected}
|
|
165
|
+
indeterminate={table.someSelected}
|
|
166
|
+
aria-label={selectAllLabel}
|
|
167
|
+
onCheckedChange={(checked) => table.toggleAll(checked)}
|
|
168
|
+
/>
|
|
169
|
+
{:else}<span class="ldt-sr-only">{selectAllLabel}</span>{/if}
|
|
170
|
+
</th>
|
|
171
|
+
{/if}
|
|
172
|
+
{#each table.columns as column (column.id)}
|
|
173
|
+
<TableHeader
|
|
174
|
+
sort={column.sortable ? table.sortOf(column.id) : undefined}
|
|
175
|
+
onSort={column.sortable
|
|
176
|
+
? (direction) =>
|
|
177
|
+
table.sortBy(column.id, direction === 'descending' ? 'descending' : 'ascending')
|
|
178
|
+
: undefined}
|
|
179
|
+
align={column.align}
|
|
180
|
+
style={column.width ? `width: ${column.width}` : undefined}
|
|
181
|
+
data-hide-below={column.hideBelow}>{column.header}</TableHeader
|
|
182
|
+
>
|
|
183
|
+
{/each}
|
|
184
|
+
</tr>
|
|
185
|
+
</thead>
|
|
186
|
+
{#if loading}
|
|
187
|
+
<tbody>
|
|
188
|
+
{#each { length: loadingRows }, index (index)}
|
|
189
|
+
<tr>
|
|
190
|
+
{#each { length: columnCount }, cell (cell)}<td><Skeleton variant="text" /></td>{/each}
|
|
191
|
+
</tr>
|
|
192
|
+
{/each}
|
|
193
|
+
</tbody>
|
|
194
|
+
{:else if table.rows.length}
|
|
195
|
+
<tbody>
|
|
196
|
+
{#if windowed.before}<tr class="ldt-data-table__spacer" aria-hidden="true"
|
|
197
|
+
><td colspan={columnCount} style:height="{windowed.before}px"></td></tr
|
|
198
|
+
>{/if}
|
|
199
|
+
{#each windowed.rows as item, index (item.id)}
|
|
200
|
+
{#if rowSnippet}
|
|
201
|
+
{@render rowSnippet(item)}
|
|
202
|
+
{:else}
|
|
203
|
+
<tr
|
|
204
|
+
data-selected={item.selected ? '' : undefined}
|
|
205
|
+
aria-rowindex={described ? offset + windowed.start + index + 2 : undefined}
|
|
206
|
+
style:height={virtual ? `${virtual.rowHeight}px` : undefined}
|
|
207
|
+
>
|
|
208
|
+
{#if selectable}{@render selectCell(item)}{/if}
|
|
209
|
+
{#each table.columns as column (column.id)}
|
|
210
|
+
<td data-align={column.align} data-hide-below={column.hideBelow}>
|
|
211
|
+
{#if column.cell}{@render column.cell(
|
|
212
|
+
item.original
|
|
213
|
+
)}{:else if column.editable && onCellEdit}<EditableCell
|
|
214
|
+
value={table.format(item.original, column)}
|
|
215
|
+
label={editLabel(column.header)}
|
|
216
|
+
onCommit={(value) => onCellEdit(item.original, column.id, value)}
|
|
217
|
+
/>{:else}{table.format(item.original, column)}{/if}
|
|
218
|
+
</td>
|
|
219
|
+
{/each}
|
|
220
|
+
</tr>
|
|
221
|
+
{/if}
|
|
222
|
+
{/each}
|
|
223
|
+
{#if windowed.after}<tr class="ldt-data-table__spacer" aria-hidden="true"
|
|
224
|
+
><td colspan={columnCount} style:height="{windowed.after}px"></td></tr
|
|
225
|
+
>{/if}
|
|
226
|
+
</tbody>
|
|
227
|
+
{/if}
|
|
228
|
+
</Table>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLTableAttributes } from 'svelte/elements';
|
|
3
|
+
import type { DataTableRow, DataTableState } from '../data-table.svelte.js';
|
|
4
|
+
declare function $$render<T>(): {
|
|
5
|
+
props: Omit<HTMLTableAttributes, "children"> & {
|
|
6
|
+
/** The state from `createDataTable()`. */
|
|
7
|
+
table: DataTableState<T>;
|
|
8
|
+
caption?: string;
|
|
9
|
+
regionLabel?: string;
|
|
10
|
+
/** Pin the header row. Needs `--ldt-table-height` on the wrapper. */
|
|
11
|
+
sticky?: boolean;
|
|
12
|
+
/** Show placeholder rows while data is on its way. */
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
loadingRows?: number;
|
|
15
|
+
/** Shown when no rows remain. Defaults to an `EmptyState` from `emptyTitle`. */
|
|
16
|
+
empty?: Snippet;
|
|
17
|
+
emptyTitle?: string;
|
|
18
|
+
emptyDescription?: string;
|
|
19
|
+
/** Render each row yourself. Receives the row; output a whole `<tr>`. */
|
|
20
|
+
row?: Snippet<[DataTableRow<T>]>;
|
|
21
|
+
/** Accessible name of a row's selection control. */
|
|
22
|
+
selectLabel?: (row: T) => string;
|
|
23
|
+
selectAllLabel?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Render only the rows scrolled into view — for thousands of rows on one page. Every row must
|
|
26
|
+
* be `rowHeight` pixels tall, and the wrapper needs `--ldt-table-height` (with `sticky`).
|
|
27
|
+
*/
|
|
28
|
+
virtual?: {
|
|
29
|
+
rowHeight: number;
|
|
30
|
+
overscan?: number;
|
|
31
|
+
};
|
|
32
|
+
/** Called when an `editable` cell is saved. Update your data in response. */
|
|
33
|
+
onCellEdit?: (row: T, columnId: string, value: string) => void;
|
|
34
|
+
editLabel?: (header: string) => string;
|
|
35
|
+
/** `class` lands on the `<table>`; `wrapperClass` on the scroll container. */
|
|
36
|
+
class?: string;
|
|
37
|
+
wrapperClass?: string;
|
|
38
|
+
ref?: HTMLTableElement | null;
|
|
39
|
+
wrapperRef?: HTMLDivElement | null;
|
|
40
|
+
};
|
|
41
|
+
exports: {};
|
|
42
|
+
bindings: "ref" | "wrapperRef";
|
|
43
|
+
slots: {};
|
|
44
|
+
events: {};
|
|
45
|
+
};
|
|
46
|
+
declare class __sveltets_Render<T> {
|
|
47
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
48
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
49
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
50
|
+
bindings(): "ref" | "wrapperRef";
|
|
51
|
+
exports(): {};
|
|
52
|
+
}
|
|
53
|
+
interface $$IsomorphicComponent {
|
|
54
|
+
new <T>(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']>> & {
|
|
55
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
56
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
57
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
58
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
59
|
+
}
|
|
60
|
+
declare const DataTable: $$IsomorphicComponent;
|
|
61
|
+
type DataTable<T> = InstanceType<typeof DataTable<T>>;
|
|
62
|
+
export default DataTable;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
3
|
+
import type { MenuEntry } from '../types.js';
|
|
4
|
+
import { cx } from '../utils.js';
|
|
5
|
+
import DropdownMenu from './DropdownMenu.svelte';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
table: DataTableState<T>;
|
|
9
|
+
/** Trigger text. */
|
|
10
|
+
label?: string;
|
|
11
|
+
resetLabel?: string;
|
|
12
|
+
class?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { table, label = 'Columns', resetLabel = 'Show all', class: className }: Props = $props();
|
|
16
|
+
|
|
17
|
+
const RESET = '\u0000reset';
|
|
18
|
+
|
|
19
|
+
const items = $derived<MenuEntry[]>([
|
|
20
|
+
{
|
|
21
|
+
type: 'group',
|
|
22
|
+
label,
|
|
23
|
+
items: table.allColumns
|
|
24
|
+
.filter((column) => column.hideable !== false)
|
|
25
|
+
.map((column) => ({
|
|
26
|
+
type: 'checkbox' as const,
|
|
27
|
+
value: column.id,
|
|
28
|
+
label: column.header,
|
|
29
|
+
checked: table.isVisible(column.id),
|
|
30
|
+
})),
|
|
31
|
+
},
|
|
32
|
+
...(table.hidden.length
|
|
33
|
+
? [{ value: RESET, label: resetLabel, separatorBefore: true } satisfies MenuEntry]
|
|
34
|
+
: []),
|
|
35
|
+
]);
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<DropdownMenu
|
|
39
|
+
{items}
|
|
40
|
+
align="end"
|
|
41
|
+
triggerClass={cx('ldt-button ldt-button--quiet ldt-button--sm', className)}
|
|
42
|
+
onCheckedChange={(id, checked) => table.setColumnVisible(id, checked)}
|
|
43
|
+
onSelect={(value) => value === RESET && table.showAllColumns()}
|
|
44
|
+
>
|
|
45
|
+
{#snippet trigger()}{label}{/snippet}
|
|
46
|
+
</DropdownMenu>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
2
|
+
declare function $$render<T>(): {
|
|
3
|
+
props: {
|
|
4
|
+
table: DataTableState<T>;
|
|
5
|
+
/** Trigger text. */
|
|
6
|
+
label?: string;
|
|
7
|
+
resetLabel?: string;
|
|
8
|
+
class?: string;
|
|
9
|
+
};
|
|
10
|
+
exports: {};
|
|
11
|
+
bindings: "";
|
|
12
|
+
slots: {};
|
|
13
|
+
events: {};
|
|
14
|
+
};
|
|
15
|
+
declare class __sveltets_Render<T> {
|
|
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>(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>(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 DataTableColumnVisibility: $$IsomorphicComponent;
|
|
30
|
+
type DataTableColumnVisibility<T> = InstanceType<typeof DataTableColumnVisibility<T>>;
|
|
31
|
+
export default DataTableColumnVisibility;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
3
|
+
import type { MenuEntry, Option } from '../types.js';
|
|
4
|
+
import { cx } from '../utils.js';
|
|
5
|
+
import DropdownMenu from './DropdownMenu.svelte';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
table: DataTableState<T>;
|
|
9
|
+
/** The column to filter. */
|
|
10
|
+
column: string;
|
|
11
|
+
/** Trigger text and menu heading. Defaults to the column header. */
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Choices. Defaults to the column's `filterOptions`, else the values present in the data. */
|
|
14
|
+
options?: Option[];
|
|
15
|
+
/** Show how many rows hold each value. */
|
|
16
|
+
showCounts?: boolean;
|
|
17
|
+
clearLabel?: string;
|
|
18
|
+
/** How the trigger reports a selection, e.g. "Stock, 2 selected". */
|
|
19
|
+
selectedText?: (count: number) => string;
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let {
|
|
24
|
+
table,
|
|
25
|
+
column,
|
|
26
|
+
title,
|
|
27
|
+
options,
|
|
28
|
+
showCounts = true,
|
|
29
|
+
clearLabel = 'Clear filter',
|
|
30
|
+
selectedText = (count) => `${count} selected`,
|
|
31
|
+
class: className,
|
|
32
|
+
}: Props = $props();
|
|
33
|
+
|
|
34
|
+
// Not a value any real option can hold, so the clear row never collides with data.
|
|
35
|
+
const CLEAR = '\u0000clear';
|
|
36
|
+
|
|
37
|
+
const header = $derived(
|
|
38
|
+
title ?? table.allColumns.find((one) => one.id === column)?.header ?? column
|
|
39
|
+
);
|
|
40
|
+
const counts = $derived(table.facets(column));
|
|
41
|
+
const choices = $derived<Option[]>(
|
|
42
|
+
options ??
|
|
43
|
+
table.allColumns.find((one) => one.id === column)?.filterOptions ??
|
|
44
|
+
[...counts.keys()].sort().map((value) => ({ value, label: value }))
|
|
45
|
+
);
|
|
46
|
+
const chosen = $derived.by(() => {
|
|
47
|
+
const value = table.filters[column];
|
|
48
|
+
return Array.isArray(value) ? value : [];
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const items = $derived<MenuEntry[]>([
|
|
52
|
+
{
|
|
53
|
+
type: 'group',
|
|
54
|
+
label: header,
|
|
55
|
+
items: choices.map((choice) => ({
|
|
56
|
+
type: 'checkbox' as const,
|
|
57
|
+
value: choice.value,
|
|
58
|
+
label: choice.label,
|
|
59
|
+
checked: chosen.includes(choice.value),
|
|
60
|
+
disabled: choice.disabled,
|
|
61
|
+
hint: showCounts ? String(counts.get(choice.value) ?? 0) : undefined,
|
|
62
|
+
})),
|
|
63
|
+
},
|
|
64
|
+
...(chosen.length
|
|
65
|
+
? [{ value: CLEAR, label: clearLabel, separatorBefore: true } satisfies MenuEntry]
|
|
66
|
+
: []),
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
function toggle(value: string, checked: boolean) {
|
|
70
|
+
table.setFilter(column, checked ? [...chosen, value] : chosen.filter((one) => one !== value));
|
|
71
|
+
}
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<DropdownMenu
|
|
75
|
+
{items}
|
|
76
|
+
triggerClass={cx('ldt-button ldt-button--quiet ldt-button--sm ldt-facet', className)}
|
|
77
|
+
onCheckedChange={toggle}
|
|
78
|
+
onSelect={(value) => value === CLEAR && table.setFilter(column, null)}
|
|
79
|
+
>
|
|
80
|
+
{#snippet trigger()}
|
|
81
|
+
<span>{header}</span>{#if chosen.length}<span class="ldt-facet__count"
|
|
82
|
+
><span aria-hidden="true">{chosen.length}</span><span class="ldt-sr-only"
|
|
83
|
+
>, {selectedText(chosen.length)}</span
|
|
84
|
+
></span
|
|
85
|
+
>{/if}
|
|
86
|
+
{/snippet}
|
|
87
|
+
</DropdownMenu>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
2
|
+
import type { Option } from '../types.js';
|
|
3
|
+
declare function $$render<T>(): {
|
|
4
|
+
props: {
|
|
5
|
+
table: DataTableState<T>;
|
|
6
|
+
/** The column to filter. */
|
|
7
|
+
column: string;
|
|
8
|
+
/** Trigger text and menu heading. Defaults to the column header. */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Choices. Defaults to the column's `filterOptions`, else the values present in the data. */
|
|
11
|
+
options?: Option[];
|
|
12
|
+
/** Show how many rows hold each value. */
|
|
13
|
+
showCounts?: boolean;
|
|
14
|
+
clearLabel?: string;
|
|
15
|
+
/** How the trigger reports a selection, e.g. "Stock, 2 selected". */
|
|
16
|
+
selectedText?: (count: number) => string;
|
|
17
|
+
class?: string;
|
|
18
|
+
};
|
|
19
|
+
exports: {};
|
|
20
|
+
bindings: "";
|
|
21
|
+
slots: {};
|
|
22
|
+
events: {};
|
|
23
|
+
};
|
|
24
|
+
declare class __sveltets_Render<T> {
|
|
25
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
26
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
27
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
28
|
+
bindings(): "";
|
|
29
|
+
exports(): {};
|
|
30
|
+
}
|
|
31
|
+
interface $$IsomorphicComponent {
|
|
32
|
+
new <T>(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']>> & {
|
|
33
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
34
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
35
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
36
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
37
|
+
}
|
|
38
|
+
declare const DataTableFacetedFilter: $$IsomorphicComponent;
|
|
39
|
+
type DataTableFacetedFilter<T> = InstanceType<typeof DataTableFacetedFilter<T>>;
|
|
40
|
+
export default DataTableFacetedFilter;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
4
|
+
import { cx } from '../utils.js';
|
|
5
|
+
import Pagination from './Pagination.svelte';
|
|
6
|
+
import Select from './Select.svelte';
|
|
7
|
+
|
|
8
|
+
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
9
|
+
table: DataTableState<T>;
|
|
10
|
+
/** Choices for rows per page. An empty list hides the picker. */
|
|
11
|
+
pageSizes?: number[];
|
|
12
|
+
pageSizeLabel?: string;
|
|
13
|
+
/** The status line, e.g. "11–20 of 48 · 3 selected". */
|
|
14
|
+
summary?: (range: { from: number; to: number; total: number; selected: number }) => string;
|
|
15
|
+
/** Accessible name of the page navigation. */
|
|
16
|
+
label?: string;
|
|
17
|
+
class?: string;
|
|
18
|
+
ref?: HTMLDivElement | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
table,
|
|
23
|
+
pageSizes = [10, 25, 50, 100],
|
|
24
|
+
pageSizeLabel = 'Rows per page',
|
|
25
|
+
summary = ({ from, to, total, selected }) =>
|
|
26
|
+
`${total === 0 ? 0 : `${from}–${to}`} of ${total}${selected ? ` · ${selected} selected` : ''}`,
|
|
27
|
+
label = 'Table pages',
|
|
28
|
+
class: className,
|
|
29
|
+
ref = $bindable(null),
|
|
30
|
+
...rest
|
|
31
|
+
}: Props = $props();
|
|
32
|
+
|
|
33
|
+
const pageId = $props.id();
|
|
34
|
+
const from = $derived(table.rowCount === 0 ? 0 : (table.page - 1) * table.pageSize + 1);
|
|
35
|
+
const to = $derived(Math.min(table.rowCount, table.page * table.pageSize));
|
|
36
|
+
const sizes = $derived(
|
|
37
|
+
[...new Set([...pageSizes, ...(Number.isFinite(table.pageSize) ? [table.pageSize] : [])])].sort(
|
|
38
|
+
(a, b) => a - b
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<div bind:this={ref} class={cx('ldt-data-table-pagination', className)} {...rest}>
|
|
44
|
+
<!-- Polite, so a screen reader hears the new range after paging or filtering. -->
|
|
45
|
+
<p class="ldt-data-table-pagination__summary" role="status">
|
|
46
|
+
{summary({ from, to, total: table.rowCount, selected: table.selectedCount })}
|
|
47
|
+
</p>
|
|
48
|
+
{#if sizes.length && Number.isFinite(table.pageSize)}
|
|
49
|
+
<div class="ldt-data-table-pagination__size">
|
|
50
|
+
<label for={pageId}>{pageSizeLabel}</label>
|
|
51
|
+
<Select
|
|
52
|
+
id={pageId}
|
|
53
|
+
value={String(table.pageSize)}
|
|
54
|
+
options={sizes.map((size) => ({ value: String(size), label: String(size) }))}
|
|
55
|
+
onValueChange={(value) => table.setPageSize(Number(value))}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
{/if}
|
|
59
|
+
{#if table.pageCount > 1}
|
|
60
|
+
<Pagination
|
|
61
|
+
{label}
|
|
62
|
+
count={table.rowCount}
|
|
63
|
+
perPage={table.pageSize}
|
|
64
|
+
page={table.page}
|
|
65
|
+
onPageChange={(page) => table.setPage(page)}
|
|
66
|
+
/>
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
3
|
+
declare function $$render<T>(): {
|
|
4
|
+
props: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
5
|
+
table: DataTableState<T>;
|
|
6
|
+
/** Choices for rows per page. An empty list hides the picker. */
|
|
7
|
+
pageSizes?: number[];
|
|
8
|
+
pageSizeLabel?: string;
|
|
9
|
+
/** The status line, e.g. "11–20 of 48 · 3 selected". */
|
|
10
|
+
summary?: (range: {
|
|
11
|
+
from: number;
|
|
12
|
+
to: number;
|
|
13
|
+
total: number;
|
|
14
|
+
selected: number;
|
|
15
|
+
}) => string;
|
|
16
|
+
/** Accessible name of the page navigation. */
|
|
17
|
+
label?: string;
|
|
18
|
+
class?: string;
|
|
19
|
+
ref?: HTMLDivElement | null;
|
|
20
|
+
};
|
|
21
|
+
exports: {};
|
|
22
|
+
bindings: "ref";
|
|
23
|
+
slots: {};
|
|
24
|
+
events: {};
|
|
25
|
+
};
|
|
26
|
+
declare class __sveltets_Render<T> {
|
|
27
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
28
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
29
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
30
|
+
bindings(): "ref";
|
|
31
|
+
exports(): {};
|
|
32
|
+
}
|
|
33
|
+
interface $$IsomorphicComponent {
|
|
34
|
+
new <T>(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']>> & {
|
|
35
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
36
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
37
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
38
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
39
|
+
}
|
|
40
|
+
declare const DataTablePagination: $$IsomorphicComponent;
|
|
41
|
+
type DataTablePagination<T> = InstanceType<typeof DataTablePagination<T>>;
|
|
42
|
+
export default DataTablePagination;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
import type { DataTableState } from '../data-table.svelte.js';
|
|
4
|
+
import Input from './Input.svelte';
|
|
5
|
+
|
|
6
|
+
interface Props extends Omit<HTMLInputAttributes, 'value' | 'type'> {
|
|
7
|
+
table: DataTableState<T>;
|
|
8
|
+
/** Filter one column instead of searching them all. */
|
|
9
|
+
column?: string;
|
|
10
|
+
/** Accessible name, when not wrapped in a `Field`. */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Milliseconds to wait after the last keystroke — worth raising for a server search. */
|
|
13
|
+
debounce?: number;
|
|
14
|
+
boxed?: boolean;
|
|
15
|
+
class?: string;
|
|
16
|
+
ref?: HTMLInputElement | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
table,
|
|
21
|
+
column,
|
|
22
|
+
label = 'Search',
|
|
23
|
+
debounce = 200,
|
|
24
|
+
boxed = true,
|
|
25
|
+
placeholder = 'Search',
|
|
26
|
+
class: className,
|
|
27
|
+
ref = $bindable(null),
|
|
28
|
+
...rest
|
|
29
|
+
}: Props = $props();
|
|
30
|
+
|
|
31
|
+
const current = $derived.by(() => {
|
|
32
|
+
if (!column) return table.search;
|
|
33
|
+
const value = table.filters[column];
|
|
34
|
+
return typeof value === 'string' ? value : '';
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// The field keeps its own text while the user types; it re-syncs when the table's value
|
|
38
|
+
// changes from elsewhere (a Clear all, a reset).
|
|
39
|
+
let text = $derived(current);
|
|
40
|
+
|
|
41
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
42
|
+
$effect(() => () => clearTimeout(timer));
|
|
43
|
+
|
|
44
|
+
function apply(value: string) {
|
|
45
|
+
if (column) table.setFilter(column, value);
|
|
46
|
+
else table.setSearch(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function handleInput(event: Event & { currentTarget: HTMLInputElement }) {
|
|
50
|
+
const value = event.currentTarget.value;
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
if (debounce > 0) timer = setTimeout(() => apply(value), debounce);
|
|
53
|
+
else apply(value);
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<Input
|
|
58
|
+
bind:ref
|
|
59
|
+
bind:value={text}
|
|
60
|
+
type="search"
|
|
61
|
+
aria-label={label}
|
|
62
|
+
{placeholder}
|
|
63
|
+
{boxed}
|
|
64
|
+
class={className}
|
|
65
|
+
{...rest}
|
|
66
|
+
oninput={handleInput}
|
|
67
|
+
/>
|