@classic-homes/theme-svelte 0.1.55 → 1.0.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 (47) hide show
  1. package/dist/__tests__/nav-access.test.js +145 -0
  2. package/dist/__tests__/sidebar-expansion.test.js +59 -0
  3. package/dist/lib/components/Button.svelte +17 -1
  4. package/dist/lib/components/Checkbox.svelte +3 -2
  5. package/dist/lib/components/Combobox.svelte +4 -4
  6. package/dist/lib/components/DataPanel.svelte +11 -5
  7. package/dist/lib/components/DateTimePicker.svelte +3 -2
  8. package/dist/lib/components/FileUpload.svelte +4 -3
  9. package/dist/lib/components/HeaderSearch.svelte +5 -0
  10. package/dist/lib/components/RadioGroup.svelte +3 -2
  11. package/dist/lib/components/Select.svelte +3 -2
  12. package/dist/lib/components/Signature.svelte +3 -2
  13. package/dist/lib/components/Tabs.svelte +3 -2
  14. package/dist/lib/components/data-table/DataTableColumnFilter.svelte +2 -2
  15. package/dist/lib/components/data-table/DataTableColumnFilter.svelte.d.ts +33 -13
  16. package/dist/lib/components/data-table/DataTableColumnVisibility.svelte +2 -2
  17. package/dist/lib/components/data-table/DataTableColumnVisibility.svelte.d.ts +27 -7
  18. package/dist/lib/components/data-table/DataTableFacetedFilter.svelte +2 -2
  19. package/dist/lib/components/data-table/DataTableFacetedFilter.svelte.d.ts +36 -17
  20. package/dist/lib/components/data-table/DataTablePagination.svelte +2 -2
  21. package/dist/lib/components/data-table/DataTablePagination.svelte.d.ts +31 -11
  22. package/dist/lib/components/data-table/DataTableSearch.svelte +2 -2
  23. package/dist/lib/components/data-table/DataTableSearch.svelte.d.ts +31 -11
  24. package/dist/lib/components/data-table/DataTableToolbar.svelte +2 -2
  25. package/dist/lib/components/data-table/DataTableToolbar.svelte.d.ts +37 -17
  26. package/dist/lib/components/layout/DashboardLayout.svelte +1 -0
  27. package/dist/lib/components/layout/Sidebar.svelte +22 -17
  28. package/dist/lib/components/layout/Sidebar.svelte.d.ts +10 -1
  29. package/dist/lib/composables/useAnnounce.svelte.js +9 -9
  30. package/dist/lib/composables/useArrowNavigation.svelte.js +5 -4
  31. package/dist/lib/composables/useEscapeKey.svelte.d.ts +4 -2
  32. package/dist/lib/composables/useEscapeKey.svelte.js +3 -2
  33. package/dist/lib/composables/useFocusRef.svelte.js +4 -3
  34. package/dist/lib/composables/useFocusTrap.svelte.d.ts +9 -3
  35. package/dist/lib/composables/useFocusTrap.svelte.js +34 -28
  36. package/dist/lib/composables/useRovingTabindex.svelte.js +4 -3
  37. package/dist/lib/schemas/auth.d.ts +18 -8
  38. package/dist/lib/schemas/auth.js +4 -1
  39. package/dist/lib/schemas/index.d.ts +1 -1
  40. package/dist/lib/stores/sidebar.svelte.d.ts +7 -2
  41. package/dist/lib/stores/sidebar.svelte.js +9 -3
  42. package/dist/lib/types/layout.d.ts +52 -4
  43. package/dist/lib/utils/nav-access.d.ts +61 -0
  44. package/dist/lib/utils/nav-access.js +74 -0
  45. package/dist/lib/utils.d.ts +0 -10
  46. package/dist/lib/utils.js +0 -13
  47. package/package.json +1 -1
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Navigation Access Filtering Tests
3
+ *
4
+ * Covers which navigation items a user sees given the roles and permissions
5
+ * they hold — including the nested case, where a restricted child sits under
6
+ * an unrestricted parent.
7
+ */
8
+ import { describe, it, expect } from 'vitest';
9
+ import { filterNavItems, isNavItemVisible, matchesAccess } from '../lib/utils/nav-access.js';
10
+ function item(partial) {
11
+ return { name: partial.id, ...partial };
12
+ }
13
+ const ids = (items) => items.map((i) => i.id);
14
+ describe('matchesAccess', () => {
15
+ it('matches when nothing is required', () => {
16
+ expect(matchesAccess(undefined, [])).toBe(true);
17
+ expect(matchesAccess([], [])).toBe(true);
18
+ });
19
+ it('does not match a requirement when the user holds nothing', () => {
20
+ expect(matchesAccess(['admin'], undefined)).toBe(false);
21
+ expect(matchesAccess(['admin'], [])).toBe(false);
22
+ });
23
+ it('matches any by default', () => {
24
+ expect(matchesAccess(['admin', 'manager'], ['manager'])).toBe(true);
25
+ expect(matchesAccess(['admin', 'manager'], ['agent'])).toBe(false);
26
+ });
27
+ it('can require all', () => {
28
+ expect(matchesAccess(['admin', 'manager'], ['admin'], true)).toBe(false);
29
+ expect(matchesAccess(['admin', 'manager'], ['admin', 'manager'], true)).toBe(true);
30
+ });
31
+ });
32
+ describe('isNavItemVisible', () => {
33
+ it('shows unrestricted items to anyone', () => {
34
+ expect(isNavItemVisible(item({ id: 'a' }), {})).toBe(true);
35
+ });
36
+ it('matches against every role held, not just one', () => {
37
+ const nav = item({ id: 'a', roles: ['agent'] });
38
+ expect(isNavItemVisible(nav, { userRoles: ['manager', 'agent'] })).toBe(true);
39
+ });
40
+ it('does not imply roles from one another', () => {
41
+ // Mirrors the auth package: holding admin does not imply agent, so the UI
42
+ // cannot offer something the server would reject.
43
+ const nav = item({ id: 'a', roles: ['agent'] });
44
+ expect(isNavItemVisible(nav, { userRoles: ['admin'] })).toBe(false);
45
+ });
46
+ it('combines roles and permissions as AND', () => {
47
+ const nav = item({ id: 'a', roles: ['manager'], permissions: ['users:write'] });
48
+ expect(isNavItemVisible(nav, { userRoles: ['manager'], userPermissions: ['users:write'] })).toBe(true);
49
+ expect(isNavItemVisible(nav, { userRoles: ['manager'], userPermissions: ['users:read'] })).toBe(false);
50
+ expect(isNavItemVisible(nav, { userRoles: ['agent'], userPermissions: ['users:write'] })).toBe(false);
51
+ });
52
+ it('gates on permissions alone', () => {
53
+ const nav = item({ id: 'a', permissions: ['settings:read'] });
54
+ expect(isNavItemVisible(nav, { userPermissions: ['settings:read'] })).toBe(true);
55
+ expect(isNavItemVisible(nav, { userRoles: ['admin'] })).toBe(false);
56
+ });
57
+ });
58
+ describe('filterNavItems', () => {
59
+ it('shows the union across a multi-role user', () => {
60
+ const items = [
61
+ item({ id: 'dashboard' }),
62
+ item({ id: 'users', roles: ['manager'] }),
63
+ item({ id: 'homes', roles: ['agent'] }),
64
+ item({ id: 'system', roles: ['admin'] }),
65
+ ];
66
+ expect(ids(filterNavItems(items, { userRoles: ['manager', 'agent'] }))).toEqual([
67
+ 'dashboard',
68
+ 'users',
69
+ 'homes',
70
+ ]);
71
+ });
72
+ it('filters a restricted child under an unrestricted parent', () => {
73
+ // The parent passes on its own merits; without recursion nothing would ever
74
+ // look inside it and the admin-only child would show to everyone.
75
+ const items = [
76
+ item({
77
+ id: 'main',
78
+ children: [item({ id: 'open' }), item({ id: 'audit', roles: ['admin'] })],
79
+ }),
80
+ ];
81
+ const filtered = filterNavItems(items, { userRoles: ['agent'] });
82
+ expect(ids(filtered[0].children)).toEqual(['open']);
83
+ });
84
+ it('filters arbitrarily deep', () => {
85
+ const items = [
86
+ item({
87
+ id: 'l1',
88
+ children: [
89
+ item({
90
+ id: 'l2',
91
+ children: [item({ id: 'l3', roles: ['admin'] }), item({ id: 'l3-open' })],
92
+ }),
93
+ ],
94
+ }),
95
+ ];
96
+ const filtered = filterNavItems(items, { userRoles: ['agent'] });
97
+ expect(ids(filtered[0].children[0].children)).toEqual(['l3-open']);
98
+ });
99
+ it('drops a container whose children are all filtered away', () => {
100
+ const items = [
101
+ item({ id: 'admin-area', children: [item({ id: 'system', roles: ['admin'] })] }),
102
+ ];
103
+ // Keeping it would render an expandable with nothing behind it.
104
+ expect(ids(filterNavItems(items, { userRoles: ['agent'] }))).toEqual([]);
105
+ });
106
+ it('keeps an emptied parent that is a destination in its own right', () => {
107
+ const items = [
108
+ item({
109
+ id: 'reports',
110
+ href: '/reports',
111
+ children: [item({ id: 'revenue', roles: ['admin'] })],
112
+ }),
113
+ ];
114
+ const filtered = filterNavItems(items, { userRoles: ['agent'] });
115
+ expect(ids(filtered)).toEqual(['reports']);
116
+ expect(filtered[0].children).toEqual([]);
117
+ });
118
+ it('hides everything restricted from a user with no roles', () => {
119
+ const items = [item({ id: 'dashboard' }), item({ id: 'users', roles: ['manager'] })];
120
+ expect(ids(filterNavItems(items, {}))).toEqual(['dashboard']);
121
+ });
122
+ it('honors requireAllRoles', () => {
123
+ const items = [item({ id: 'both', roles: ['admin', 'manager'] })];
124
+ expect(ids(filterNavItems(items, { userRoles: ['admin'], requireAllRoles: true }))).toEqual([]);
125
+ expect(ids(filterNavItems(items, { userRoles: ['admin', 'manager'], requireAllRoles: true }))).toEqual(['both']);
126
+ });
127
+ it('honors requireAllPermissions', () => {
128
+ const items = [item({ id: 'both', permissions: ['a:read', 'b:read'] })];
129
+ expect(ids(filterNavItems(items, { userPermissions: ['a:read'], requireAllPermissions: true }))).toEqual([]);
130
+ expect(ids(filterNavItems(items, {
131
+ userPermissions: ['a:read', 'b:read'],
132
+ requireAllPermissions: true,
133
+ }))).toEqual(['both']);
134
+ });
135
+ it('leaves childless items without a children key', () => {
136
+ const filtered = filterNavItems([item({ id: 'a' })], {});
137
+ expect('children' in filtered[0]).toBe(false);
138
+ });
139
+ it('does not mutate the input', () => {
140
+ const items = [item({ id: 'main', children: [item({ id: 'audit', roles: ['admin'] })] })];
141
+ const before = JSON.stringify(items);
142
+ filterNavItems(items, { userRoles: ['agent'] });
143
+ expect(JSON.stringify(items)).toBe(before);
144
+ });
145
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Sidebar Role-based Expansion Tests
3
+ *
4
+ * Covers which sections start expanded for a given user. This is a UX
5
+ * affordance, not access control — it decides what starts open, not what is
6
+ * visible (that's nav-access).
7
+ */
8
+ import { describe, it, expect } from 'vitest';
9
+ import { sidebarStore } from '../lib/stores/sidebar.svelte.js';
10
+ function section(partial) {
11
+ return { title: partial.id, items: [], ...partial };
12
+ }
13
+ describe('computeInitialExpansions', () => {
14
+ it('expands a section for any matching role', () => {
15
+ const sections = [section({ id: 'admin', expandForRoles: ['admin', 'superuser'] })];
16
+ expect(sidebarStore.computeInitialExpansions(sections, ['admin'])).toEqual(['admin']);
17
+ expect(sidebarStore.computeInitialExpansions(sections, ['superuser'])).toEqual(['admin']);
18
+ });
19
+ it('expands on a secondary role, not just the first held', () => {
20
+ const sections = [section({ id: 'ops', expandForRoles: ['agent'] })];
21
+ expect(sidebarStore.computeInitialExpansions(sections, ['manager', 'agent'])).toEqual(['ops']);
22
+ });
23
+ it('leaves a section collapsed when no role matches', () => {
24
+ const sections = [section({ id: 'admin', expandForRoles: ['admin'] })];
25
+ expect(sidebarStore.computeInitialExpansions(sections, ['agent'])).toEqual([]);
26
+ });
27
+ it('leaves a role-gated section collapsed for a user with no roles', () => {
28
+ const sections = [section({ id: 'admin', expandForRoles: ['admin'] })];
29
+ expect(sidebarStore.computeInitialExpansions(sections, [])).toEqual([]);
30
+ expect(sidebarStore.computeInitialExpansions(sections, undefined)).toEqual([]);
31
+ });
32
+ it('expands non-collapsible sections regardless of roles', () => {
33
+ const sections = [section({ id: 'main', collapsible: false })];
34
+ expect(sidebarStore.computeInitialExpansions(sections, [])).toEqual(['main']);
35
+ });
36
+ it('respects an explicitly collapsed section', () => {
37
+ const sections = [section({ id: 'main', collapsible: true, expanded: false })];
38
+ expect(sidebarStore.computeInitialExpansions(sections, ['admin'])).toEqual([]);
39
+ });
40
+ it('expands a collapsible section that is not explicitly collapsed', () => {
41
+ const sections = [section({ id: 'main', collapsible: true })];
42
+ expect(sidebarStore.computeInitialExpansions(sections, [])).toEqual(['main']);
43
+ });
44
+ it('prefers expandForRoles over the collapsed default', () => {
45
+ // expandForRoles is checked first, so it wins over `expanded: false`.
46
+ const sections = [
47
+ section({ id: 'admin', collapsible: true, expanded: false, expandForRoles: ['admin'] }),
48
+ ];
49
+ expect(sidebarStore.computeInitialExpansions(sections, ['admin'])).toEqual(['admin']);
50
+ });
51
+ it('handles a mixed navigation', () => {
52
+ const sections = [
53
+ section({ id: 'main', collapsible: false }),
54
+ section({ id: 'admin', expandForRoles: ['admin'] }),
55
+ section({ id: 'ops', expandForRoles: ['agent'] }),
56
+ ];
57
+ expect(sidebarStore.computeInitialExpansions(sections, ['agent'])).toEqual(['main', 'ops']);
58
+ });
59
+ });
@@ -110,7 +110,23 @@
110
110
  {/snippet}
111
111
 
112
112
  {#if href}
113
- <a {href} class={classes} {...restProps}>
113
+ <!-- Anchors can't be natively disabled: remove from tab order, expose
114
+ aria-disabled, drop the href, and block clicks when disabled/loading -->
115
+ <a
116
+ href={disabled || loading ? undefined : href}
117
+ class={classes}
118
+ aria-disabled={disabled || loading || undefined}
119
+ aria-busy={loading || undefined}
120
+ tabindex={disabled || loading ? -1 : undefined}
121
+ onclick={(e) => {
122
+ if (disabled || loading) {
123
+ e.preventDefault();
124
+ return;
125
+ }
126
+ onclick?.(e);
127
+ }}
128
+ {...restProps}
129
+ >
114
130
  {@render buttonContent()}
115
131
  </a>
116
132
  {:else}
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import { Checkbox as CheckboxPrimitive } from 'bits-ui';
4
- import { cn, useId } from '../utils.js';
4
+ import { cn } from '../utils.js';
5
5
 
6
6
  interface Props {
7
7
  checked?: boolean;
@@ -32,7 +32,8 @@
32
32
  }: Props = $props();
33
33
 
34
34
  // Generate a stable unique ID if none provided (for accessibility)
35
- const generatedId = useId('checkbox');
35
+ const uid = $props.id();
36
+ const generatedId = `checkbox-${uid}`;
36
37
  const effectiveId = $derived(id ?? generatedId);
37
38
 
38
39
  function handleCheckedChange(newChecked: boolean | 'indeterminate') {
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { Combobox as ComboboxPrimitive } from 'bits-ui';
3
3
  import { cn } from '../utils.js';
4
- import { generateId, computeDescribedBy } from '../utils/form.js';
4
+ import { computeDescribedBy } from '../utils/form.js';
5
5
  import Spinner from './Spinner.svelte';
6
6
  import Label from './Label.svelte';
7
7
  import LiveRegion from './LiveRegion.svelte';
@@ -66,9 +66,9 @@
66
66
  class: className,
67
67
  }: Props = $props();
68
68
 
69
- // Generate unique IDs for accessibility
70
- const randomSuffix = generateId('combobox').split('-').pop();
71
- const componentId = $derived(id || `combobox-${randomSuffix}`);
69
+ // Generate unique IDs for accessibility ($props.id() is SSR-stable)
70
+ const uid = $props.id();
71
+ const componentId = $derived(id || `combobox-${uid}`);
72
72
  const hintId = $derived(`${componentId}-hint`);
73
73
  const errorId = $derived(`${componentId}-error`);
74
74
 
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../utils.js';
3
- import { onMount } from 'svelte';
3
+ import { onMount, onDestroy } from 'svelte';
4
4
  import type { Snippet } from 'svelte';
5
5
  import type {
6
6
  PanelEdge,
@@ -222,11 +222,13 @@
222
222
  }
223
223
 
224
224
  saveTimeout = setTimeout(() => {
225
+ // Persist the resolved values so controlled mode saves what's shown,
226
+ // not the untouched internal defaults
225
227
  savePanelState(persistKey, {
226
- mode: internalMode,
227
- variant: internalVariant,
228
- edge: internalEdge,
229
- isExpanded: internalExpanded,
228
+ mode,
229
+ variant,
230
+ edge,
231
+ isExpanded,
230
232
  detachedPosition,
231
233
  detachedSize,
232
234
  pinnedSize,
@@ -236,6 +238,10 @@
236
238
  }, 300);
237
239
  }
238
240
 
241
+ onDestroy(() => {
242
+ if (saveTimeout) clearTimeout(saveTimeout);
243
+ });
244
+
239
245
  // Initialize from persistence on mount
240
246
  onMount(() => {
241
247
  // Update viewport dimensions
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { Popover, Calendar } from 'bits-ui';
3
3
  import { tick } from 'svelte';
4
- import { cn, useId } from '../utils.js';
4
+ import { cn } from '../utils.js';
5
5
  import { parseDate, toISOString, parseDateInput } from '../utils/date.js';
6
6
  import Label from './Label.svelte';
7
7
 
@@ -69,7 +69,8 @@
69
69
  }: Props = $props();
70
70
 
71
71
  // Generate unique IDs for accessibility using sequential counter
72
- const generatedId = useId('datetimepicker');
72
+ const uid = $props.id();
73
+ const generatedId = `datetimepicker-${uid}`;
73
74
  const componentId = $derived(id || generatedId);
74
75
  const hintId = $derived(`${componentId}-hint`);
75
76
  const errorId = $derived(`${componentId}-error`);
@@ -12,7 +12,7 @@
12
12
  * - Accessible with keyboard navigation
13
13
  */
14
14
  import type { FileMetadata } from '../types/components.js';
15
- import { cn, useId } from '../utils.js';
15
+ import { cn } from '../utils.js';
16
16
  import Button from './Button.svelte';
17
17
 
18
18
  interface Props {
@@ -48,7 +48,8 @@
48
48
  class?: string;
49
49
  }
50
50
 
51
- const generatedId = useId('file-upload');
51
+ const uid = $props.id();
52
+ const generatedId = `file-upload-${uid}`;
52
53
 
53
54
  let {
54
55
  id = generatedId,
@@ -336,7 +337,7 @@
336
337
  for={id}
337
338
  aria-describedby={displayError ? `${id}-error` : undefined}
338
339
  class={cn(
339
- 'relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed p-6 transition-colors',
340
+ 'relative flex flex-col items-center justify-center rounded-lg border-2 border-dashed p-6',
340
341
  'cursor-pointer focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2',
341
342
  isDragging && !disabled && 'border-primary bg-primary/5',
342
343
  disabled && 'cursor-not-allowed opacity-50',
@@ -25,6 +25,7 @@
25
25
  * ```
26
26
  */
27
27
  import { Dialog as DialogPrimitive } from 'bits-ui';
28
+ import { onDestroy } from 'svelte';
28
29
  import { cn } from '../utils.js';
29
30
  import type { Snippet } from 'svelte';
30
31
  import type { SearchResultItem, SearchResultGroup } from '../types/layout.js';
@@ -131,6 +132,10 @@
131
132
  }, 200);
132
133
  }
133
134
 
135
+ onDestroy(() => {
136
+ if (debounceTimer) clearTimeout(debounceTimer);
137
+ });
138
+
134
139
  // Keyboard navigation within results
135
140
  function handleKeydown(e: KeyboardEvent) {
136
141
  switch (e.key) {
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { RadioGroup as RadioGroupPrimitive } from 'bits-ui';
3
- import { cn, useId } from '../utils.js';
3
+ import { cn } from '../utils.js';
4
4
  import { computeDescribedBy } from '../utils/form.js';
5
5
  import { validateNonEmptyArray } from '../validation.js';
6
6
  import Label from './Label.svelte';
@@ -52,7 +52,8 @@
52
52
  }: Props = $props();
53
53
 
54
54
  // Generate unique IDs for accessibility (sequential counter, SSR-safe)
55
- const generatedId = useId('radio-group');
55
+ const uid = $props.id();
56
+ const generatedId = `radio-group-${uid}`;
56
57
  const componentName = $derived(name || generatedId);
57
58
  const labelId = $derived(`${componentName}-label`);
58
59
  const hintId = $derived(`${componentName}-hint`);
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Select as SelectPrimitive } from 'bits-ui';
3
- import { cn, useId } from '../utils.js';
3
+ import { cn } from '../utils.js';
4
4
  import { validateNonEmptyArray } from '../validation.js';
5
5
  import { DEV } from 'esm-env';
6
6
  import Label from './Label.svelte';
@@ -59,7 +59,8 @@
59
59
  }: Props = $props();
60
60
 
61
61
  // Generate unique IDs for accessibility using sequential counter
62
- const generatedId = useId('select');
62
+ const uid = $props.id();
63
+ const generatedId = `select-${uid}`;
63
64
  const componentId = $derived(id || generatedId);
64
65
  const hintId = $derived(`${componentId}-hint`);
65
66
  const errorId = $derived(`${componentId}-error`);
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { untrack } from 'svelte';
3
- import { cn, useId } from '../utils.js';
3
+ import { cn } from '../utils.js';
4
4
  import { tv, type VariantProps } from 'tailwind-variants';
5
5
  import type {
6
6
  SignatureData,
@@ -842,7 +842,8 @@
842
842
  });
843
843
 
844
844
  // Computed IDs (using stable sequential ID generation)
845
- const generatedInputId = useId('signature');
845
+ const uid = $props.id();
846
+ const generatedInputId = `signature-${uid}`;
846
847
  const inputId = $derived(id || generatedInputId);
847
848
  const errorId = $derived(`${inputId}-error`);
848
849
  const hintId = $derived(`${inputId}-hint`);
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import { setContext } from 'svelte';
4
- import { cn, useId } from '../utils.js';
4
+ import { cn } from '../utils.js';
5
5
  import type { Tab } from '../types/components.js';
6
6
 
7
7
  interface Props {
@@ -25,7 +25,8 @@
25
25
  onValueChange?: (value: string) => void;
26
26
  }
27
27
 
28
- const generatedId = useId('tabs');
28
+ const uid = $props.id();
29
+ const generatedId = `tabs-${uid}`;
29
30
 
30
31
  let {
31
32
  tabs,
@@ -1,4 +1,4 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="TData extends object">
2
2
  /**
3
3
  * DataTableColumnFilter - Per-column text filter input
4
4
  *
@@ -12,7 +12,7 @@
12
12
 
13
13
  interface Props {
14
14
  /** The native DataTable instance */
15
- table: DataTableInstance<any>;
15
+ table: DataTableInstance<TData>;
16
16
  /** Column ID to filter */
17
17
  columnId: string;
18
18
  /** Placeholder text */
@@ -5,18 +5,38 @@
5
5
  * Works with the native Svelte 5 DataTable implementation.
6
6
  */
7
7
  import type { DataTableInstance } from './createDataTable.svelte.js';
8
- interface Props {
9
- /** The native DataTable instance */
10
- table: DataTableInstance<any>;
11
- /** Column ID to filter */
12
- columnId: string;
13
- /** Placeholder text */
14
- placeholder?: string;
15
- /** Debounce delay in ms */
16
- debounceMs?: number;
17
- /** Additional classes */
18
- class?: string;
8
+ declare function $$render<TData extends object>(): {
9
+ props: {
10
+ /** The native DataTable instance */
11
+ table: DataTableInstance<TData>;
12
+ /** Column ID to filter */
13
+ columnId: string;
14
+ /** Placeholder text */
15
+ placeholder?: string;
16
+ /** Debounce delay in ms */
17
+ debounceMs?: number;
18
+ /** Additional classes */
19
+ class?: string;
20
+ };
21
+ exports: {};
22
+ bindings: "";
23
+ slots: {};
24
+ events: {};
25
+ };
26
+ declare class __sveltets_Render<TData extends object> {
27
+ props(): ReturnType<typeof $$render<TData>>['props'];
28
+ events(): ReturnType<typeof $$render<TData>>['events'];
29
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
30
+ bindings(): "";
31
+ exports(): {};
19
32
  }
20
- declare const DataTableColumnFilter: import("svelte").Component<Props, {}, "">;
21
- type DataTableColumnFilter = ReturnType<typeof DataTableColumnFilter>;
33
+ interface $$IsomorphicComponent {
34
+ new <TData extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
35
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
36
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
37
+ <TData extends object>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
38
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
39
+ }
40
+ declare const DataTableColumnFilter: $$IsomorphicComponent;
41
+ type DataTableColumnFilter<TData extends object> = InstanceType<typeof DataTableColumnFilter<TData>>;
22
42
  export default DataTableColumnFilter;
@@ -1,4 +1,4 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="TData extends object">
2
2
  /**
3
3
  * DataTableColumnVisibility - Column visibility toggle dropdown
4
4
  *
@@ -12,7 +12,7 @@
12
12
 
13
13
  interface Props {
14
14
  /** The native DataTable instance */
15
- table: DataTableInstance<any>;
15
+ table: DataTableInstance<TData>;
16
16
  /** Additional classes */
17
17
  class?: string;
18
18
  }
@@ -5,12 +5,32 @@
5
5
  * Works with the native Svelte 5 DataTable implementation.
6
6
  */
7
7
  import type { DataTableInstance } from './createDataTable.svelte.js';
8
- interface Props {
9
- /** The native DataTable instance */
10
- table: DataTableInstance<any>;
11
- /** Additional classes */
12
- class?: string;
8
+ declare function $$render<TData extends object>(): {
9
+ props: {
10
+ /** The native DataTable instance */
11
+ table: DataTableInstance<TData>;
12
+ /** Additional classes */
13
+ class?: string;
14
+ };
15
+ exports: {};
16
+ bindings: "";
17
+ slots: {};
18
+ events: {};
19
+ };
20
+ declare class __sveltets_Render<TData extends object> {
21
+ props(): ReturnType<typeof $$render<TData>>['props'];
22
+ events(): ReturnType<typeof $$render<TData>>['events'];
23
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
24
+ bindings(): "";
25
+ exports(): {};
13
26
  }
14
- declare const DataTableColumnVisibility: import("svelte").Component<Props, {}, "">;
15
- type DataTableColumnVisibility = ReturnType<typeof DataTableColumnVisibility>;
27
+ interface $$IsomorphicComponent {
28
+ new <TData extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
29
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
30
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
31
+ <TData extends object>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
32
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
33
+ }
34
+ declare const DataTableColumnVisibility: $$IsomorphicComponent;
35
+ type DataTableColumnVisibility<TData extends object> = InstanceType<typeof DataTableColumnVisibility<TData>>;
16
36
  export default DataTableColumnVisibility;
@@ -1,4 +1,4 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="TData extends object">
2
2
  /**
3
3
  * DataTableFacetedFilter - Multi-select filter for categorical columns
4
4
  *
@@ -23,7 +23,7 @@
23
23
 
24
24
  interface Props {
25
25
  /** The native DataTable instance */
26
- table: DataTableInstance<any>;
26
+ table: DataTableInstance<TData>;
27
27
  /** Column ID to filter */
28
28
  columnId: string;
29
29
  /** Title for the filter */
@@ -9,23 +9,42 @@
9
9
  * from the main table's column filter state.
10
10
  */
11
11
  import type { DataTableInstance } from './createDataTable.svelte.js';
12
- interface FilterOption {
13
- value: string;
14
- label: string;
15
- count?: number;
12
+ declare function $$render<TData extends object>(): {
13
+ props: {
14
+ /** The native DataTable instance */
15
+ table: DataTableInstance<TData>;
16
+ /** Column ID to filter */
17
+ columnId: string;
18
+ /** Title for the filter */
19
+ title: string;
20
+ /** Available filter options */
21
+ options: {
22
+ value: string;
23
+ label: string;
24
+ count?: number;
25
+ }[];
26
+ /** Additional classes */
27
+ class?: string;
28
+ };
29
+ exports: {};
30
+ bindings: "";
31
+ slots: {};
32
+ events: {};
33
+ };
34
+ declare class __sveltets_Render<TData extends object> {
35
+ props(): ReturnType<typeof $$render<TData>>['props'];
36
+ events(): ReturnType<typeof $$render<TData>>['events'];
37
+ slots(): ReturnType<typeof $$render<TData>>['slots'];
38
+ bindings(): "";
39
+ exports(): {};
16
40
  }
17
- interface Props {
18
- /** The native DataTable instance */
19
- table: DataTableInstance<any>;
20
- /** Column ID to filter */
21
- columnId: string;
22
- /** Title for the filter */
23
- title: string;
24
- /** Available filter options */
25
- options: FilterOption[];
26
- /** Additional classes */
27
- class?: string;
41
+ interface $$IsomorphicComponent {
42
+ new <TData extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TData>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TData>['props']>, ReturnType<__sveltets_Render<TData>['events']>, ReturnType<__sveltets_Render<TData>['slots']>> & {
43
+ $$bindings?: ReturnType<__sveltets_Render<TData>['bindings']>;
44
+ } & ReturnType<__sveltets_Render<TData>['exports']>;
45
+ <TData extends object>(internal: unknown, props: ReturnType<__sveltets_Render<TData>['props']> & {}): ReturnType<__sveltets_Render<TData>['exports']>;
46
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
28
47
  }
29
- declare const DataTableFacetedFilter: import("svelte").Component<Props, {}, "">;
30
- type DataTableFacetedFilter = ReturnType<typeof DataTableFacetedFilter>;
48
+ declare const DataTableFacetedFilter: $$IsomorphicComponent;
49
+ type DataTableFacetedFilter<TData extends object> = InstanceType<typeof DataTableFacetedFilter<TData>>;
31
50
  export default DataTableFacetedFilter;