sv5ui 1.8.0 → 2.1.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 (92) hide show
  1. package/dist/Accordion/Accordion.svelte +11 -0
  2. package/dist/Alert/alert.types.d.ts +1 -1
  3. package/dist/AvatarGroup/AvatarGroup.svelte +5 -3
  4. package/dist/Badge/badge.types.d.ts +1 -1
  5. package/dist/Button/Button.svelte +7 -6
  6. package/dist/Button/button.types.d.ts +3 -3
  7. package/dist/Calendar/Calendar.svelte +14 -1
  8. package/dist/Collapsible/collapsible.types.d.ts +4 -2
  9. package/dist/Command/command.types.d.ts +4 -2
  10. package/dist/Command/index.d.ts +1 -1
  11. package/dist/ContextMenu/ContextMenu.svelte +1 -1
  12. package/dist/Drawer/Drawer.svelte +7 -3
  13. package/dist/Drawer/DrawerTriggerTestWrapper.svelte +10 -0
  14. package/dist/Drawer/DrawerTriggerTestWrapper.svelte.d.ts +18 -0
  15. package/dist/Drawer/drawer.types.d.ts +13 -2
  16. package/dist/DropdownMenu/DropdownMenu.svelte +1 -3
  17. package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte +12 -0
  18. package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte.d.ts +7 -0
  19. package/dist/DropdownMenu/dropdown-menu.types.d.ts +17 -9
  20. package/dist/Editor/Editor.svelte +85 -61
  21. package/dist/Editor/SlashPopup.svelte +8 -1
  22. package/dist/Editor/SlashPopup.svelte.d.ts +2 -0
  23. package/dist/Editor/editor.extensions.d.ts +1 -1
  24. package/dist/Editor/editor.extensions.js +25 -16
  25. package/dist/Editor/editor.schemas.d.ts +1 -0
  26. package/dist/Editor/editor.schemas.js +24 -0
  27. package/dist/Editor/editor.slash.svelte.d.ts +0 -9
  28. package/dist/Editor/editor.slash.svelte.js +33 -7
  29. package/dist/Editor/editor.suggestion.js +23 -0
  30. package/dist/Editor/editor.toolbar.js +0 -8
  31. package/dist/Editor/editor.types.d.ts +20 -0
  32. package/dist/Editor/editor.variants.d.ts +0 -5
  33. package/dist/Editor/editor.variants.js +0 -15
  34. package/dist/Editor/index.d.ts +6 -4
  35. package/dist/Editor/index.js +6 -4
  36. package/dist/FileUpload/FileUpload.svelte +7 -0
  37. package/dist/Icon/icon.types.d.ts +4 -1
  38. package/dist/Input/Input.svelte +22 -16
  39. package/dist/Input/index.d.ts +1 -1
  40. package/dist/Input/input.variants.d.ts +0 -15
  41. package/dist/Input/input.variants.js +1 -20
  42. package/dist/Link/Link.svelte +4 -3
  43. package/dist/Link/link.types.d.ts +2 -2
  44. package/dist/Modal/Modal.svelte +4 -2
  45. package/dist/Modal/ModalTriggerTestWrapper.svelte +10 -0
  46. package/dist/Modal/ModalTriggerTestWrapper.svelte.d.ts +18 -0
  47. package/dist/Modal/modal.types.d.ts +13 -3
  48. package/dist/Pagination/Pagination.svelte +7 -1
  49. package/dist/Pagination/pagination.types.d.ts +4 -1
  50. package/dist/Pagination/pagination.variants.d.ts +0 -72
  51. package/dist/Pagination/pagination.variants.js +6 -30
  52. package/dist/Popover/Popover.svelte +1 -1
  53. package/dist/Popover/popover.types.d.ts +2 -0
  54. package/dist/Progress/Progress.svelte +14 -6
  55. package/dist/RadioGroup/RadioGroup.svelte +3 -1
  56. package/dist/Select/Select.svelte +3 -1
  57. package/dist/Select/select.types.d.ts +5 -9
  58. package/dist/SelectMenu/SelectMenu.svelte +27 -10
  59. package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte +11 -0
  60. package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte.d.ts +7 -0
  61. package/dist/SelectMenu/select-menu.types.d.ts +5 -2
  62. package/dist/SelectMenu/select-menu.variants.d.ts +12 -2
  63. package/dist/SelectMenu/select-menu.variants.js +10 -1
  64. package/dist/Separator/Separator.svelte +9 -2
  65. package/dist/Separator/separator.types.d.ts +6 -1
  66. package/dist/Separator/separator.variants.d.ts +25 -0
  67. package/dist/Separator/separator.variants.js +7 -1
  68. package/dist/Skeleton/Skeleton.svelte +3 -5
  69. package/dist/Slideover/Slideover.svelte +4 -2
  70. package/dist/Slideover/SlideoverTriggerTestWrapper.svelte +10 -0
  71. package/dist/Slideover/SlideoverTriggerTestWrapper.svelte.d.ts +18 -0
  72. package/dist/Slideover/slideover.types.d.ts +13 -3
  73. package/dist/Stepper/Stepper.svelte +1 -3
  74. package/dist/Switch/Switch.svelte +12 -17
  75. package/dist/Table/table.utils.d.ts +7 -4
  76. package/dist/Table/table.utils.js +26 -25
  77. package/dist/Tabs/Tabs.svelte +4 -2
  78. package/dist/Tabs/tabs.types.d.ts +4 -6
  79. package/dist/ThemeModeButton/ThemeModeButton.svelte +4 -3
  80. package/dist/Tooltip/Tooltip.svelte +1 -1
  81. package/dist/Tooltip/tooltip.types.d.ts +2 -0
  82. package/dist/hooks/HookContextProbe.svelte +7 -0
  83. package/dist/hooks/HookContextProbe.svelte.d.ts +18 -0
  84. package/dist/hooks/HookContextProvider.svelte +9 -0
  85. package/dist/hooks/HookContextProvider.svelte.d.ts +18 -0
  86. package/dist/hooks/HookEmitProbe.svelte +14 -0
  87. package/dist/hooks/HookEmitProbe.svelte.d.ts +18 -0
  88. package/dist/hooks/index.d.ts +1 -1
  89. package/dist/hooks/index.js +1 -1
  90. package/dist/hooks/useFormField.svelte.d.ts +0 -31
  91. package/dist/hooks/useFormField.svelte.js +0 -21
  92. package/package.json +1 -1
@@ -21,9 +21,9 @@
21
21
  } from '../FieldGroup/field-group.variants.js'
22
22
  import Icon from '../Icon/Icon.svelte'
23
23
  import Avatar from '../Avatar/Avatar.svelte'
24
- import Input from '../Input/Input.svelte'
25
24
  import type { AvatarSize } from '../Avatar/avatar.types.js'
26
25
  import { useFormField, useFormFieldEmit } from '../hooks/useFormField.svelte.js'
26
+ import { useDebounce } from '../hooks/useDebounce.svelte.js'
27
27
 
28
28
  const config = getComponentConfig('selectMenu', selectMenuDefaults)
29
29
  const icons = getComponentConfig('icons', iconsDefaults)
@@ -82,7 +82,8 @@
82
82
  itemTrailing,
83
83
  selected: selectedSlot,
84
84
  empty: emptySlot,
85
- content: contentSlot
85
+ content: contentSlot,
86
+ ...restProps
86
87
  }: Props = $props()
87
88
 
88
89
  // ---- Form context ----
@@ -181,13 +182,28 @@
181
182
 
182
183
  // ---- Search & filtering ----
183
184
  let searchTerm = $state('')
185
+ let debouncedSearch = $state('')
186
+ const searchDebounce = useDebounce({ delay: 200 })
187
+
188
+ function setSearch(term: string) {
189
+ searchTerm = term
190
+ searchDebounce.run(() => {
191
+ debouncedSearch = term
192
+ })
193
+ }
194
+
195
+ function resetSearch() {
196
+ searchDebounce.cancel()
197
+ searchTerm = ''
198
+ debouncedSearch = ''
199
+ }
184
200
 
185
201
  const filteredItems = $derived(
186
- ignoreFilter || !searchTerm.trim()
202
+ ignoreFilter || !debouncedSearch.trim()
187
203
  ? combinedItems
188
204
  : combinedItems.filter((item) => {
189
205
  if ('type' in item) return true
190
- const query = searchTerm.toLowerCase()
206
+ const query = debouncedSearch.toLowerCase()
191
207
  return filterFields.some((field) => {
192
208
  const val = (item as unknown as Record<string, unknown>)[field]
193
209
  return typeof val === 'string' && val.toLowerCase().includes(query)
@@ -256,7 +272,7 @@
256
272
  }
257
273
 
258
274
  emit.onChange()
259
- searchTerm = ''
275
+ resetSearch()
260
276
  }
261
277
 
262
278
  // ---- Leading / trailing ----
@@ -386,7 +402,7 @@
386
402
  // ---- Event handlers (Nuxt UI v4 pattern) ----
387
403
  function onUpdateOpen(val: boolean) {
388
404
  if (!val) {
389
- searchTerm = ''
405
+ resetSearch()
390
406
  emit.onBlur()
391
407
  } else {
392
408
  emit.onFocus()
@@ -444,19 +460,19 @@
444
460
  {forceMount}
445
461
  class={contentClass}
446
462
  >
447
- <Input
463
+ <!-- svelte-ignore a11y_autofocus -->
464
+ <input
465
+ type="text"
448
466
  autofocus
449
467
  placeholder={searchPlaceholder}
450
468
  value={searchTerm}
451
- oninput={(e) => (searchTerm = (e.currentTarget as HTMLInputElement).value)}
469
+ oninput={(e) => setSearch((e.currentTarget as HTMLInputElement).value)}
452
470
  onkeydown={(e: KeyboardEvent) => {
453
471
  if (e.key !== 'Enter') return
454
472
  if (!showCreateItem) return
455
473
  e.preventDefault()
456
474
  handleCreate()
457
475
  }}
458
- variant="none"
459
- size={resolvedSize}
460
476
  class={inputClass}
461
477
  />
462
478
 
@@ -539,6 +555,7 @@
539
555
  />
540
556
 
541
557
  <Combobox.Trigger
558
+ {...restProps}
542
559
  id={resolvedId}
543
560
  aria-describedby={ariaDescribedBy}
544
561
  aria-invalid={resolvedHighlight ? true : undefined}
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import FormField from '../FormField/FormField.svelte'
3
+ import SelectMenu from './SelectMenu.svelte'
4
+ import type { SelectMenuItemType } from './select-menu.types.js'
5
+
6
+ let { items = [] }: { items?: SelectMenuItemType[] } = $props()
7
+ </script>
8
+
9
+ <FormField name="fruit" label="Fruit">
10
+ <SelectMenu open {items} placeholder="Pick" />
11
+ </FormField>
@@ -0,0 +1,7 @@
1
+ import type { SelectMenuItemType } from './select-menu.types.js';
2
+ type $$ComponentProps = {
3
+ items?: SelectMenuItemType[];
4
+ };
5
+ declare const SelectMenuFormFieldTestWrapper: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type SelectMenuFormFieldTestWrapper = ReturnType<typeof SelectMenuFormFieldTestWrapper>;
7
+ export default SelectMenuFormFieldTestWrapper;
@@ -2,7 +2,7 @@ import type { Snippet } from 'svelte';
2
2
  import type { ClassNameValue } from 'tailwind-merge';
3
3
  import type { SelectMenuVariantProps, SelectMenuSlots } from './select-menu.variants.js';
4
4
  import type { AvatarProps } from '../Avatar/avatar.types.js';
5
- import type { ComboboxContentPropsWithoutHTML } from 'bits-ui';
5
+ import type { ComboboxContentPropsWithoutHTML, ComboboxTriggerProps } from 'bits-ui';
6
6
  /**
7
7
  * A single selectable option within the SelectMenu.
8
8
  */
@@ -87,7 +87,10 @@ type ContentProps = Pick<ComboboxContentPropsWithoutHTML, 'side' | 'sideOffset'
87
87
  *
88
88
  * @see https://bits-ui.com/docs/components/combobox
89
89
  */
90
- export interface SelectMenuProps extends ContentProps {
90
+ type TriggerHTMLProps = Pick<ComboboxTriggerProps, 'style' | 'title' | 'role' | 'tabindex' | 'aria-label' | 'aria-labelledby' | 'onclick' | 'onkeydown' | 'onmouseenter' | 'onmouseleave' | 'onfocus' | 'onblur'>;
91
+ export interface SelectMenuProps extends ContentProps, TriggerHTMLProps {
92
+ /** Custom data attributes are forwarded to the trigger element. */
93
+ [key: `data-${string}`]: string | number | boolean | null | undefined;
91
94
  /**
92
95
  * Bindable reference to the root DOM element.
93
96
  */
@@ -2,26 +2,31 @@ import { type VariantProps } from 'tailwind-variants';
2
2
  export declare const selectMenuVariants: import("tailwind-variants").TVReturnType<{
3
3
  size: {
4
4
  xs: {
5
+ input: string;
5
6
  empty: string;
6
7
  createItem: string;
7
8
  createItemIcon: string;
8
9
  };
9
10
  sm: {
11
+ input: string;
10
12
  empty: string;
11
13
  createItem: string;
12
14
  createItemIcon: string;
13
15
  };
14
16
  md: {
17
+ input: string;
15
18
  empty: string;
16
19
  createItem: string;
17
20
  createItemIcon: string;
18
21
  };
19
22
  lg: {
23
+ input: string;
20
24
  empty: string;
21
25
  createItem: string;
22
26
  createItemIcon: string;
23
27
  };
24
28
  xl: {
29
+ input: string;
25
30
  empty: string;
26
31
  createItem: string;
27
32
  createItemIcon: string;
@@ -29,7 +34,7 @@ export declare const selectMenuVariants: import("tailwind-variants").TVReturnTyp
29
34
  };
30
35
  }, {
31
36
  content: string[];
32
- input: string;
37
+ input: string[];
33
38
  viewport: string;
34
39
  empty: string;
35
40
  createItem: string[];
@@ -606,26 +611,31 @@ export declare const selectMenuDefaults: {
606
611
  defaultVariants: import("tailwind-variants").TVDefaultVariants<{
607
612
  size: {
608
613
  xs: {
614
+ input: string;
609
615
  empty: string;
610
616
  createItem: string;
611
617
  createItemIcon: string;
612
618
  };
613
619
  sm: {
620
+ input: string;
614
621
  empty: string;
615
622
  createItem: string;
616
623
  createItemIcon: string;
617
624
  };
618
625
  md: {
626
+ input: string;
619
627
  empty: string;
620
628
  createItem: string;
621
629
  createItemIcon: string;
622
630
  };
623
631
  lg: {
632
+ input: string;
624
633
  empty: string;
625
634
  createItem: string;
626
635
  createItemIcon: string;
627
636
  };
628
637
  xl: {
638
+ input: string;
629
639
  empty: string;
630
640
  createItem: string;
631
641
  createItemIcon: string;
@@ -633,7 +643,7 @@ export declare const selectMenuDefaults: {
633
643
  };
634
644
  }, {
635
645
  content: string[];
636
- input: string;
646
+ input: string[];
637
647
  viewport: string;
638
648
  empty: string;
639
649
  createItem: string[];
@@ -13,7 +13,11 @@ export const selectMenuVariants = tv({
13
13
  'overflow-hidden',
14
14
  'flex flex-col'
15
15
  ],
16
- input: 'border-b border-outline-variant',
16
+ input: [
17
+ 'w-full border-0 border-b border-outline-variant bg-transparent',
18
+ 'text-on-surface placeholder:text-on-surface-variant/50',
19
+ 'focus:outline-none focus:ring-0'
20
+ ],
17
21
  viewport: 'p-1 flex-1 overflow-y-auto scrollbar-thin',
18
22
  empty: 'text-center text-on-surface-variant',
19
23
  createItem: [
@@ -28,26 +32,31 @@ export const selectMenuVariants = tv({
28
32
  variants: {
29
33
  size: {
30
34
  xs: {
35
+ input: 'px-2 py-1 text-xs',
31
36
  empty: 'p-2 text-xs',
32
37
  createItem: 'py-1 text-xs',
33
38
  createItemIcon: 'size-3'
34
39
  },
35
40
  sm: {
41
+ input: 'px-2.5 py-1.5 text-xs',
36
42
  empty: 'p-2.5 text-xs',
37
43
  createItem: 'py-1.5 text-xs',
38
44
  createItemIcon: 'size-3.5'
39
45
  },
40
46
  md: {
47
+ input: 'px-3 py-2 text-sm',
41
48
  empty: 'p-2.5 text-sm',
42
49
  createItem: 'py-1.5 text-sm',
43
50
  createItemIcon: 'size-4'
44
51
  },
45
52
  lg: {
53
+ input: 'px-4 py-2.5 text-sm',
46
54
  empty: 'p-3 text-sm',
47
55
  createItem: 'py-2 text-sm',
48
56
  createItemIcon: 'size-5'
49
57
  },
50
58
  xl: {
59
+ input: 'px-5 py-3 text-base',
51
60
  empty: 'p-3 text-base',
52
61
  createItem: 'py-2.5 text-base',
53
62
  createItemIcon: 'size-5'
@@ -24,6 +24,7 @@
24
24
  size = config.defaultVariants.size,
25
25
  type = config.defaultVariants.type,
26
26
  orientation = config.defaultVariants.orientation,
27
+ position = config.defaultVariants.position,
27
28
  decorative = false,
28
29
  class: className,
29
30
  content,
@@ -46,9 +47,11 @@
46
47
  </script>
47
48
 
48
49
  <Separator.Root bind:ref class={classes.root} {orientation} {decorative} {...restProps}>
49
- <div class={classes.border}></div>
50
-
51
50
  {#if hasContent}
51
+ {#if position !== 'start'}
52
+ <div class={classes.border}></div>
53
+ {/if}
54
+
52
55
  <div class={classes.container}>
53
56
  {#if content}
54
57
  {@render content()}
@@ -65,6 +68,10 @@
65
68
  {/if}
66
69
  </div>
67
70
 
71
+ {#if position !== 'end'}
72
+ <div class={classes.border}></div>
73
+ {/if}
74
+ {:else}
68
75
  <div class={classes.border}></div>
69
76
  {/if}
70
77
  </Separator.Root>
@@ -3,7 +3,7 @@ import type { ClassNameValue } from 'tailwind-merge';
3
3
  import type { Separator } from 'bits-ui';
4
4
  import type { SeparatorVariantProps, SeparatorSlots } from './separator.variants.js';
5
5
  import type { AvatarProps } from '../Avatar/avatar.types.js';
6
- export type SeparatorProps = Separator.RootProps & {
6
+ export type SeparatorProps = Omit<Separator.RootProps, 'class'> & {
7
7
  /**
8
8
  * Sets the color scheme applied to the separator.
9
9
  * @default 'surface'
@@ -19,6 +19,11 @@ export type SeparatorProps = Separator.RootProps & {
19
19
  * @default 'solid'
20
20
  */
21
21
  type?: NonNullable<SeparatorVariantProps['type']>;
22
+ /**
23
+ * Position of the label/icon/avatar/content along the separator.
24
+ * @default 'center'
25
+ */
26
+ position?: NonNullable<SeparatorVariantProps['position']>;
22
27
  /**
23
28
  * Text content displayed in the center of the separator.
24
29
  */
@@ -87,6 +87,11 @@ export declare const separatorVariants: import("tailwind-variants").TVReturnType
87
87
  container: string;
88
88
  };
89
89
  };
90
+ position: {
91
+ start: string;
92
+ center: string;
93
+ end: string;
94
+ };
90
95
  }, {
91
96
  root: string;
92
97
  border: string;
@@ -182,6 +187,11 @@ export declare const separatorVariants: import("tailwind-variants").TVReturnType
182
187
  container: string;
183
188
  };
184
189
  };
190
+ position: {
191
+ start: string;
192
+ center: string;
193
+ end: string;
194
+ };
185
195
  }, {
186
196
  root: string;
187
197
  border: string;
@@ -277,6 +287,11 @@ export declare const separatorVariants: import("tailwind-variants").TVReturnType
277
287
  container: string;
278
288
  };
279
289
  };
290
+ position: {
291
+ start: string;
292
+ center: string;
293
+ end: string;
294
+ };
280
295
  }, {
281
296
  root: string;
282
297
  border: string;
@@ -376,6 +391,11 @@ export declare const separatorDefaults: {
376
391
  container: string;
377
392
  };
378
393
  };
394
+ position: {
395
+ start: string;
396
+ center: string;
397
+ end: string;
398
+ };
379
399
  }, {
380
400
  root: string;
381
401
  border: string;
@@ -471,6 +491,11 @@ export declare const separatorDefaults: {
471
491
  container: string;
472
492
  };
473
493
  };
494
+ position: {
495
+ start: string;
496
+ center: string;
497
+ end: string;
498
+ };
474
499
  }, {
475
500
  root: string;
476
501
  border: string;
@@ -74,6 +74,11 @@ export const separatorVariants = tv({
74
74
  border: 'h-full flex-1',
75
75
  container: 'my-2'
76
76
  }
77
+ },
78
+ position: {
79
+ start: '',
80
+ center: '',
81
+ end: ''
77
82
  }
78
83
  },
79
84
  compoundVariants: [
@@ -94,7 +99,8 @@ export const separatorVariants = tv({
94
99
  color: 'surface',
95
100
  size: 'xs',
96
101
  type: 'solid',
97
- orientation: 'horizontal'
102
+ orientation: 'horizontal',
103
+ position: 'center'
98
104
  }
99
105
  });
100
106
  export const separatorDefaults = {
@@ -19,11 +19,9 @@
19
19
  ...restProps
20
20
  }: Props = $props()
21
21
 
22
- const classes = $derived.by(() => {
23
- const slots = skeletonVariants()
24
- return {
25
- root: slots.root({ class: [config.slots.root, className, ui?.root] })
26
- }
22
+ const slots = skeletonVariants()
23
+ const classes = $derived({
24
+ root: slots.root({ class: [config.slots.root, className, ui?.root] })
27
25
  })
28
26
  </script>
29
27
 
@@ -197,8 +197,10 @@
197
197
 
198
198
  <Dialog.Root bind:open onOpenChange={handleOpenChange} {onOpenChangeComplete}>
199
199
  {#if children}
200
- <Dialog.Trigger class={className as string}>
201
- {@render children()}
200
+ <Dialog.Trigger>
201
+ {#snippet child({ props })}
202
+ {@render children({ props })}
203
+ {/snippet}
202
204
  </Dialog.Trigger>
203
205
  {/if}
204
206
 
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import Slideover from './Slideover.svelte'
3
+ </script>
4
+
5
+ <Slideover title="Trigger test" description="D">
6
+ {#snippet children({ props })}
7
+ <button data-testid="trigger" {...props}>Open</button>
8
+ {/snippet}
9
+ {#snippet body()}<p>Body</p>{/snippet}
10
+ </Slideover>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const SlideoverTriggerTestWrapper: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type SlideoverTriggerTestWrapper = InstanceType<typeof SlideoverTriggerTestWrapper>;
18
+ export default SlideoverTriggerTestWrapper;
@@ -100,10 +100,20 @@ export interface SlideoverProps extends RootProps, ContentProps {
100
100
  */
101
101
  class?: ClassNameValue;
102
102
  /**
103
- * Default slot content used as the trigger element.
104
- * When provided, clicking this element opens the slideover.
103
+ * Trigger content. Spread the provided `props` onto your own focusable
104
+ * element (e.g. a `<Button>`) so the dialog's trigger ARIA and event
105
+ * handlers land on the real control instead of a nested wrapper button.
106
+ *
107
+ * @example
108
+ * ```svelte
109
+ * {#snippet children({ props })}
110
+ * <Button {...props}>Open</Button>
111
+ * {/snippet}
112
+ * ```
105
113
  */
106
- children?: Snippet;
114
+ children?: Snippet<[{
115
+ props: Record<string, unknown>;
116
+ }]>;
107
117
  /**
108
118
  * Custom content slot that replaces the entire default layout
109
119
  * (header, body, footer). Title and description are rendered
@@ -122,9 +122,7 @@
122
122
  }
123
123
  }
124
124
 
125
- $effect.pre(() => {
126
- api = apiInstance
127
- })
125
+ api = apiInstance
128
126
 
129
127
  const variantSlots = $derived(stepperVariants({ orientation, size, color }))
130
128
 
@@ -72,17 +72,16 @@
72
72
  disabled: isDisabled ? true : undefined
73
73
  })
74
74
 
75
- const classes = $derived.by(() => {
76
- const slots = switchVariants(variantOpts)
77
- return {
78
- root: slots.root({ class: [config.slots.root, className, ui?.root] }),
79
- base: slots.base({ class: [config.slots.base, ui?.base] }),
80
- container: slots.container({ class: [config.slots.container, ui?.container] }),
81
- thumb: slots.thumb({ class: [config.slots.thumb, ui?.thumb] }),
82
- wrapper: slots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] }),
83
- label: slots.label({ class: [config.slots.label, ui?.label] }),
84
- description: slots.description({ class: [config.slots.description, ui?.description] })
85
- }
75
+ const slots = $derived(switchVariants(variantOpts))
76
+
77
+ const classes = $derived({
78
+ root: slots.root({ class: [config.slots.root, className, ui?.root] }),
79
+ base: slots.base({ class: [config.slots.base, ui?.base] }),
80
+ container: slots.container({ class: [config.slots.container, ui?.container] }),
81
+ thumb: slots.thumb({ class: [config.slots.thumb, ui?.thumb] }),
82
+ wrapper: slots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] }),
83
+ label: slots.label({ class: [config.slots.label, ui?.label] }),
84
+ description: slots.description({ class: [config.slots.description, ui?.description] })
86
85
  })
87
86
 
88
87
  const iconClasses = $derived.by(() => {
@@ -91,15 +90,11 @@
91
90
  const iconUiClass = [config.slots.icon, ui?.icon]
92
91
  return {
93
92
  checked: hasCheckedIcon
94
- ? switchVariants({ ...variantOpts, checked: true, unchecked: loading }).icon({
95
- class: iconUiClass
96
- })
93
+ ? slots.icon({ class: iconUiClass, checked: true, unchecked: loading })
97
94
  : undefined,
98
95
  unchecked:
99
96
  hasUncheckedIcon && !loading
100
- ? switchVariants({ ...variantOpts, unchecked: true }).icon({
101
- class: iconUiClass
102
- })
97
+ ? slots.icon({ class: iconUiClass, unchecked: true })
103
98
  : undefined
104
99
  }
105
100
  })
@@ -35,17 +35,20 @@ export declare function resolveVisibleColumns<T extends Record<string, any>>(col
35
35
  left?: string[];
36
36
  right?: string[];
37
37
  }): TableColumn<T>[];
38
+ type PinOffset = {
39
+ side: 'left' | 'right';
40
+ offset: number;
41
+ };
42
+ type PinOffsets = Map<string, PinOffset>;
38
43
  /**
39
44
  * Compute cumulative left/right offsets for pinned columns.
40
45
  */
41
46
  export declare function computePinOffsets<T extends Record<string, any>>(columns: TableColumn<T>[], columnSizing: Record<string, number>, columnPinning?: {
42
47
  left?: string[];
43
48
  right?: string[];
44
- }): Map<string, {
45
- side: 'left' | 'right';
46
- offset: number;
47
- }>;
49
+ }): PinOffsets;
48
50
  /**
49
51
  * Format cell value for display — handles null/undefined/empty string.
50
52
  */
51
53
  export declare function formatCellValue(value: unknown): string;
54
+ export {};
@@ -17,20 +17,26 @@ export function getRowKey(row, rowKey, index) {
17
17
  return row[rowKey];
18
18
  return index;
19
19
  }
20
+ function isNullish(v) {
21
+ return v === null || v === undefined;
22
+ }
23
+ function compareBooleans(a, b) {
24
+ return a === b ? 0 : a ? -1 : 1;
25
+ }
20
26
  /**
21
27
  * Default sort comparator — handles string, number, boolean, null/undefined.
22
28
  */
23
29
  function defaultCompare(a, b) {
24
30
  if (a === b)
25
31
  return 0;
26
- if (a === null || a === undefined)
32
+ if (isNullish(a))
27
33
  return 1;
28
- if (b === null || b === undefined)
34
+ if (isNullish(b))
29
35
  return -1;
30
36
  if (typeof a === 'number' && typeof b === 'number')
31
37
  return a - b;
32
38
  if (typeof a === 'boolean' && typeof b === 'boolean')
33
- return a === b ? 0 : a ? -1 : 1;
39
+ return compareBooleans(a, b);
34
40
  return String(a).localeCompare(String(b));
35
41
  }
36
42
  /**
@@ -128,33 +134,28 @@ export function resolveVisibleColumns(columns, columnVisibility, columnPinning)
128
134
  const right = visible.filter((c) => rightKeys.has(c.key));
129
135
  return [...left, ...center, ...right];
130
136
  }
137
+ function pinOffsetsForSide(keys, side, columns, columnSizing) {
138
+ const entries = [];
139
+ let offset = 0;
140
+ for (const key of keys) {
141
+ const col = columns.find((c) => c.key === key);
142
+ if (!col)
143
+ continue;
144
+ entries.push([key, { side, offset }]);
145
+ offset += columnSizing[key] ?? col.width ?? 150;
146
+ }
147
+ return entries;
148
+ }
131
149
  /**
132
150
  * Compute cumulative left/right offsets for pinned columns.
133
151
  */
134
152
  export function computePinOffsets(columns, columnSizing, columnPinning) {
135
- const offsets = new Map();
136
153
  if (!columnPinning)
137
- return offsets;
138
- const leftKeys = columnPinning.left ?? [];
139
- const rightKeys = columnPinning.right ?? [];
140
- let leftOffset = 0;
141
- for (const key of leftKeys) {
142
- const col = columns.find((c) => c.key === key);
143
- if (!col)
144
- continue;
145
- offsets.set(key, { side: 'left', offset: leftOffset });
146
- leftOffset += columnSizing[key] ?? col.width ?? 150;
147
- }
148
- let rightOffset = 0;
149
- for (let i = rightKeys.length - 1; i >= 0; i--) {
150
- const key = rightKeys[i];
151
- const col = columns.find((c) => c.key === key);
152
- if (!col)
153
- continue;
154
- offsets.set(key, { side: 'right', offset: rightOffset });
155
- rightOffset += columnSizing[key] ?? col.width ?? 150;
156
- }
157
- return offsets;
154
+ return new Map();
155
+ return new Map([
156
+ ...pinOffsetsForSide(columnPinning.left ?? [], 'left', columns, columnSizing),
157
+ ...pinOffsetsForSide([...(columnPinning.right ?? [])].reverse(), 'right', columns, columnSizing)
158
+ ]);
158
159
  }
159
160
  /**
160
161
  * Format cell value for display — handles null/undefined/empty string.