runeforge 0.0.54 → 0.0.55

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 (55) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1342 -1324
  3. package/dist/components/Avatar.svelte +31 -31
  4. package/dist/components/IconRenderer.svelte +22 -22
  5. package/dist/components/Modal.svelte +75 -75
  6. package/dist/components/common/Header.svelte +40 -40
  7. package/dist/components/crud/EmbeddedField.svelte +175 -175
  8. package/dist/components/crud/Field.svelte +376 -376
  9. package/dist/components/crud/GenericCRUD.svelte +426 -425
  10. package/dist/components/crud/SearchInput.svelte +53 -53
  11. package/dist/components/crud/columns/Avatar.svelte +15 -15
  12. package/dist/components/crud/columns/Icon.svelte +8 -8
  13. package/dist/components/crud/views/Create.svelte +232 -232
  14. package/dist/components/crud/views/Read.svelte +124 -124
  15. package/dist/components/crud/views/Update.svelte +208 -208
  16. package/dist/components/crud/views/list/List.svelte +291 -291
  17. package/dist/components/crud/views/list/Modals.svelte +56 -56
  18. package/dist/components/crud/views/list/Table.svelte +176 -176
  19. package/dist/components/crud/views/list/Toolbar.svelte +341 -341
  20. package/dist/components/form/Button.svelte +27 -27
  21. package/dist/components/form/Label.svelte +37 -37
  22. package/dist/components/form/MultiSelect.svelte +248 -248
  23. package/dist/components/form/PasswordInput.svelte +68 -68
  24. package/dist/components/form/Required.svelte +1 -1
  25. package/dist/components/form/Select.svelte +209 -209
  26. package/dist/components/form/Tree.svelte +62 -62
  27. package/dist/components/form/TreeNode.svelte +66 -66
  28. package/dist/components/navigation/Breadcrumbs.svelte +111 -111
  29. package/dist/components/table/ColumnFilter.svelte +168 -168
  30. package/dist/components/table/PaginatedTable.svelte +536 -560
  31. package/dist/components/table/Paginator.svelte +113 -113
  32. package/dist/components/table/SortHeader.svelte +43 -43
  33. package/dist/components/table/TableBody.svelte +150 -150
  34. package/dist/components/table/TableHeader.svelte +88 -88
  35. package/dist/components/table/utils.d.ts +9 -0
  36. package/dist/components/table/utils.js +35 -0
  37. package/dist/icons/defaults/Clear.svelte +6 -6
  38. package/dist/icons/defaults/Create.svelte +6 -6
  39. package/dist/icons/defaults/Delete.svelte +6 -6
  40. package/dist/icons/defaults/Download.svelte +7 -7
  41. package/dist/icons/defaults/Edit.svelte +7 -7
  42. package/dist/icons/defaults/Filter.svelte +6 -6
  43. package/dist/icons/defaults/FilterActive.svelte +6 -6
  44. package/dist/icons/defaults/Folder.svelte +6 -6
  45. package/dist/icons/defaults/Grip.svelte +7 -7
  46. package/dist/icons/defaults/Home.svelte +6 -6
  47. package/dist/icons/defaults/PasswordHide.svelte +9 -9
  48. package/dist/icons/defaults/PasswordShow.svelte +7 -7
  49. package/dist/icons/defaults/SortAsc.svelte +6 -6
  50. package/dist/icons/defaults/SortDesc.svelte +6 -6
  51. package/dist/icons/defaults/SortNone.svelte +6 -6
  52. package/dist/icons/defaults/View.svelte +7 -7
  53. package/dist/types/attribute.d.ts +9 -0
  54. package/dist/types/crud.d.ts +2 -0
  55. package/package.json +1 -1
@@ -1,88 +1,88 @@
1
- <script lang="ts" generics="T extends object">
2
- import SortHeader from './SortHeader.svelte';
3
- import ColumnFilter from './ColumnFilter.svelte';
4
- import { isSortable, isFilterable } from './utils.js';
5
- import type { DistinctEntry } from '../../types/table.js';
6
- import type { ColumnDefinition } from '../../types/crud.js';
7
- import type { SortState, FilterState } from './state.svelte.js';
8
- import { getStrings } from '../../i18n/context.js';
9
-
10
- const strings = getStrings();
11
-
12
- let {
13
- columns,
14
- selectable,
15
- allChecked,
16
- someChecked,
17
- onToggleAll,
18
- sort,
19
- filter,
20
- distinctValues,
21
- hasRowActions = false,
22
- actionsLabel = strings.actions,
23
- reorderActive = false,
24
- onchange,
25
- }: {
26
- columns: ColumnDefinition<T>[];
27
- selectable: boolean;
28
- allChecked: boolean;
29
- someChecked: boolean;
30
- onToggleAll: () => void;
31
- sort: SortState;
32
- filter: FilterState;
33
- distinctValues: Record<string, DistinctEntry<T>[]>;
34
- hasRowActions?: boolean;
35
- actionsLabel?: string;
36
- reorderActive?: boolean;
37
- onchange?: () => void;
38
- } = $props();
39
-
40
- function sortBy(col: ColumnDefinition<T>) {
41
- if (reorderActive || !isSortable(col)) return;
42
- sort.cycle(col.attribute);
43
- onchange?.();
44
- }
45
- </script>
46
-
47
- <thead class="bg-base-200">
48
- <tr>
49
- {#if reorderActive}
50
- <th class="w-10"></th>
51
- {/if}
52
- {#if selectable}
53
- <th>
54
- <input
55
- type="checkbox"
56
- class="checkbox checkbox-sm"
57
- checked={allChecked}
58
- indeterminate={someChecked && !allChecked}
59
- onchange={onToggleAll}
60
- />
61
- </th>
62
- {/if}
63
- {#each columns as col (col.attribute)}
64
- {@const title = (col.title ?? col.attribute).replace(/_/g, ' ')}
65
- <th>
66
- <div class="flex items-center gap-1">
67
- <SortHeader
68
- {title}
69
- sortable={isSortable(col) && !reorderActive}
70
- direction={reorderActive ? null : sort.directionFor(col.attribute)}
71
- onsort={() => sortBy(col)}
72
- />
73
- {#if isFilterable(col) && !reorderActive}
74
- <ColumnFilter
75
- column={col}
76
- entries={distinctValues[col.attribute] ?? []}
77
- {filter}
78
- {onchange}
79
- />
80
- {/if}
81
- </div>
82
- </th>
83
- {/each}
84
- {#if hasRowActions}
85
- <th class="text-right">{actionsLabel}</th>
86
- {/if}
87
- </tr>
88
- </thead>
1
+ <script lang="ts" generics="T extends object">
2
+ import SortHeader from './SortHeader.svelte';
3
+ import ColumnFilter from './ColumnFilter.svelte';
4
+ import { isSortable, isFilterable } from './utils.js';
5
+ import type { DistinctEntry } from '../../types/table.js';
6
+ import type { ColumnDefinition } from '../../types/crud.js';
7
+ import type { SortState, FilterState } from './state.svelte.js';
8
+ import { getStrings } from '../../i18n/context.js';
9
+
10
+ const strings = getStrings();
11
+
12
+ let {
13
+ columns,
14
+ selectable,
15
+ allChecked,
16
+ someChecked,
17
+ onToggleAll,
18
+ sort,
19
+ filter,
20
+ distinctValues,
21
+ hasRowActions = false,
22
+ actionsLabel = strings.actions,
23
+ reorderActive = false,
24
+ onchange,
25
+ }: {
26
+ columns: ColumnDefinition<T>[];
27
+ selectable: boolean;
28
+ allChecked: boolean;
29
+ someChecked: boolean;
30
+ onToggleAll: () => void;
31
+ sort: SortState;
32
+ filter: FilterState;
33
+ distinctValues: Record<string, DistinctEntry<T>[]>;
34
+ hasRowActions?: boolean;
35
+ actionsLabel?: string;
36
+ reorderActive?: boolean;
37
+ onchange?: () => void;
38
+ } = $props();
39
+
40
+ function sortBy(col: ColumnDefinition<T>) {
41
+ if (reorderActive || !isSortable(col)) return;
42
+ sort.cycle(col.attribute);
43
+ onchange?.();
44
+ }
45
+ </script>
46
+
47
+ <thead class="bg-base-200">
48
+ <tr>
49
+ {#if reorderActive}
50
+ <th class="w-10"></th>
51
+ {/if}
52
+ {#if selectable}
53
+ <th>
54
+ <input
55
+ type="checkbox"
56
+ class="checkbox checkbox-sm"
57
+ checked={allChecked}
58
+ indeterminate={someChecked && !allChecked}
59
+ onchange={onToggleAll}
60
+ />
61
+ </th>
62
+ {/if}
63
+ {#each columns as col (col.attribute)}
64
+ {@const title = (col.title ?? col.attribute).replace(/_/g, ' ')}
65
+ <th>
66
+ <div class="flex items-center gap-1">
67
+ <SortHeader
68
+ {title}
69
+ sortable={isSortable(col) && !reorderActive}
70
+ direction={reorderActive ? null : sort.directionFor(col.attribute)}
71
+ onsort={() => sortBy(col)}
72
+ />
73
+ {#if isFilterable(col) && !reorderActive}
74
+ <ColumnFilter
75
+ column={col}
76
+ entries={distinctValues[col.attribute] ?? []}
77
+ {filter}
78
+ {onchange}
79
+ />
80
+ {/if}
81
+ </div>
82
+ </th>
83
+ {/each}
84
+ {#if hasRowActions}
85
+ <th class="text-right">{actionsLabel}</th>
86
+ {/if}
87
+ </tr>
88
+ </thead>
@@ -5,6 +5,15 @@ export declare function isSortable<T extends object>(col: ColumnDefinition<T>):
5
5
  export declare function isFilterable<T extends object>(col: ColumnDefinition<T>): boolean;
6
6
  export declare function compare(a: unknown, b: unknown): number;
7
7
  export declare function distinctEntries<T extends object>(data: T[], columns: ColumnDefinition<T>[]): Record<string, DistinctEntry<T>[]>;
8
+ /** Resolves the checkbox-list entries for every filterable column: a
9
+ * column's own `filterOptions` wins when present (a static, exhaustive
10
+ * list — see its doc comment); a `boolean` column always gets its two known
11
+ * states; everything else falls back to values actually seen in `data`,
12
+ * truncated to `sampleSize` when given. Sampling off `data` is only ever a
13
+ * hint under server-side pagination, where `data` is just the current
14
+ * page — pass `sampleSize` there; omit it in client mode, where `data` is
15
+ * the complete, already-filtered row set. */
16
+ export declare function resolveDistinctValues<T extends object>(data: T[], columns: ColumnDefinition<T>[], sampleSize?: number): Record<string, DistinctEntry<T>[]>;
8
17
  /** Returns a copy of `rows` with the item at `from` moved to `to` — pure
9
18
  * array surgery, handy for building custom reorder UIs on `PaginatedTable`.
10
19
  * Out-of-range indices are a no-op. */
@@ -42,6 +42,41 @@ export function distinctEntries(data, columns) {
42
42
  }
43
43
  return result;
44
44
  }
45
+ /** Resolves the checkbox-list entries for every filterable column: a
46
+ * column's own `filterOptions` wins when present (a static, exhaustive
47
+ * list — see its doc comment); a `boolean` column always gets its two known
48
+ * states; everything else falls back to values actually seen in `data`,
49
+ * truncated to `sampleSize` when given. Sampling off `data` is only ever a
50
+ * hint under server-side pagination, where `data` is just the current
51
+ * page — pass `sampleSize` there; omit it in client mode, where `data` is
52
+ * the complete, already-filtered row set. */
53
+ export function resolveDistinctValues(data, columns, sampleSize) {
54
+ const result = {};
55
+ for (const col of columns) {
56
+ if (!isFilterable(col))
57
+ continue;
58
+ if (col.filterOptions) {
59
+ result[col.attribute] = col.filterOptions.map((o) => ({
60
+ key: o.value,
61
+ label: o.label,
62
+ row: {},
63
+ }));
64
+ continue;
65
+ }
66
+ if (col.type === 'boolean') {
67
+ result[col.attribute] = [
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ { key: 'true', label: col.formatter?.(true, {}), row: {} },
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ { key: 'false', label: col.formatter?.(false, {}), row: {} },
72
+ ];
73
+ continue;
74
+ }
75
+ const entries = distinctEntries(data, [col])[col.attribute] ?? [];
76
+ result[col.attribute] = sampleSize != null ? entries.slice(0, sampleSize) : entries;
77
+ }
78
+ return result;
79
+ }
45
80
  /** Returns a copy of `rows` with the item at `from` moved to `to` — pure
46
81
  * array surgery, handy for building custom reorder UIs on `PaginatedTable`.
47
82
  * Out-of-range indices are a no-op. */
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M2.146 2.146a.5.5 0 0 1 .708 0L8 7.293l5.146-5.147a.5.5 0 1 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854a.5.5 0 0 1 0-.708z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M2.146 2.146a.5.5 0 0 1 .708 0L8 7.293l5.146-5.147a.5.5 0 1 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854a.5.5 0 0 1 0-.708z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5M11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 0 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47M8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M6.5 1h3a.5.5 0 0 1 .5.5v1H6v-1a.5.5 0 0 1 .5-.5M11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3A1.5 1.5 0 0 0 5 1.5v1H1.5a.5.5 0 0 0 0 1h.538l.853 10.66A2 2 0 0 0 4.885 16h6.23a2 2 0 0 0 1.994-1.84l.853-10.66h.538a.5.5 0 0 0 0-1zm1.958 1-.846 10.58a1 1 0 0 1-.997.92h-6.23a1 1 0 0 1-.997-.92L3.042 3.5zm-7.487 1a.5.5 0 0 1 .528.47l.5 8.5a.5.5 0 0 1-.998.06L5 5.03a.5.5 0 0 1 .47-.53Zm5.058 0a.5.5 0 0 1 .47.53l-.5 8.5a.5.5 0 0 1-.998-.06l.5-8.5a.5.5 0 0 1 .528-.47M8 4.5a.5.5 0 0 1 .5.5v8.5a.5.5 0 0 1-1 0V5a.5.5 0 0 1 .5-.5"/>
6
+ </svg>
@@ -1,7 +1,7 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>
6
- <path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"/>
7
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5"/>
6
+ <path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z"/>
7
+ </svg>
@@ -1,7 +1,7 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12z"/>
6
- <path d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z"/>
7
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12z"/>
6
+ <path d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z"/>
7
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5zm1 .5v1.308l4.372 4.858A.5.5 0 0 1 7 8.5v5.306l2-.666V8.5a.5.5 0 0 1 .128-.334L13.5 3.308V2z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5zm1 .5v1.308l4.372 4.858A.5.5 0 0 1 7 8.5v5.306l2-.666V8.5a.5.5 0 0 1 .128-.334L13.5 3.308V2z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31L.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3m-8.322.12q.322-.119.684-.12h5.396l-.707-.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.826a2 2 0 0 1-1.991-1.819l-.637-7a2 2 0 0 1 .342-1.31L.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3m-8.322.12q.322-.119.684-.12h5.396l-.707-.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981z"/>
6
+ </svg>
@@ -1,7 +1,7 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
-
5
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
6
- <path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
7
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+
5
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
6
+ <path d="M7 2a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0m-3 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0m3 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
7
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5z"/>
6
+ </svg>
@@ -1,9 +1,9 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7 7 0 0 0-2.79.588l.77.771A6 6 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755l.708.709z"/>
6
- <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
7
- <path d="M3.35 5.47c-.18.16-.353.322-.518.487A13 13 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7 7 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238z"/>
8
- <path fill-rule="evenodd" d="M13.646 14.354l-12-12 .708-.708 12 12-.708.708z"/>
9
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7 7 0 0 0-2.79.588l.77.771A6 6 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755l.708.709z"/>
6
+ <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z"/>
7
+ <path d="M3.35 5.47c-.18.16-.353.322-.518.487A13 13 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7 7 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238z"/>
8
+ <path fill-rule="evenodd" d="M13.646 14.354l-12-12 .708-.708 12 12-.708.708z"/>
9
+ </svg>
@@ -1,7 +1,7 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
6
- <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
7
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
6
+ <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
7
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
6
+ </svg>
@@ -1,6 +1,6 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708"/>
6
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708"/>
6
+ </svg>
@@ -1,7 +1,7 @@
1
- <script lang="ts">
2
- let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
- </script>
4
- <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
- <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
6
- <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
7
- </svg>
1
+ <script lang="ts">
2
+ let { size = '1em', class: cls = '' }: { size?: string | number; class?: string } = $props();
3
+ </script>
4
+ <svg xmlns="http://www.w3.org/2000/svg" width={size} height={size} viewBox="0 0 16 16" fill="currentColor" class={cls}>
5
+ <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
6
+ <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>
7
+ </svg>
@@ -75,6 +75,15 @@ export type AttributeMetadata = {
75
75
  excludedFromRead?: boolean;
76
76
  sortable?: boolean;
77
77
  filterable?: boolean;
78
+ /** List column filter only: a static, exhaustive set of choices shown in
79
+ * the column filter's checkbox list, instead of the values sampled off
80
+ * currently loaded rows. For a bounded, known set (e.g. an enum-like text
81
+ * column) that the loaded page might not fully represent — especially
82
+ * under [server-side pagination](#server-side-pagination-sorting--filtering),
83
+ * where the sample is only a handful of values off the current page. `value`
84
+ * is matched against the rendered cell text (and sent server-side as-is);
85
+ * `label` is only what's displayed, falling back to `value`. */
86
+ filterOptions?: SelectOption[];
78
87
  groupedAs?: string;
79
88
  min?: number;
80
89
  max?: number;
@@ -12,6 +12,8 @@ export type ColumnDefinition<T extends object = Record<string, unknown>> = {
12
12
  formatter?: CellFormatter<T, T[K]>;
13
13
  sortable?: boolean;
14
14
  filterable?: boolean;
15
+ /** Static, exhaustive filter choices — see `AttributeMetadata.filterOptions`. */
16
+ filterOptions?: SelectOption[];
15
17
  /** Embedded columns only: sub-field definitions for each item, used to
16
18
  * render a default cell summary and to expand the column into one
17
19
  * sub-column per field on CSV/XLSX export. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runeforge",
3
- "version": "0.0.54",
3
+ "version": "0.0.55",
4
4
  "description": "SvelteKit toolkit for building metadata-driven CRUD interfaces with tables, forms, and actions",
5
5
  "license": "MIT",
6
6
  "author": "Ezequiel Puerta",