sv5ui 1.1.3 → 1.3.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 (187) hide show
  1. package/README.md +6 -0
  2. package/dist/Alert/Alert.svelte +33 -22
  3. package/dist/Alert/Alert.svelte.d.ts +1 -1
  4. package/dist/Alert/alert.types.d.ts +4 -0
  5. package/dist/Avatar/Avatar.svelte +72 -46
  6. package/dist/Avatar/avatar.types.d.ts +36 -3
  7. package/dist/Avatar/avatar.variants.d.ts +138 -0
  8. package/dist/Avatar/avatar.variants.js +23 -12
  9. package/dist/Avatar/index.d.ts +1 -1
  10. package/dist/AvatarGroup/AvatarGroup.svelte +11 -6
  11. package/dist/AvatarGroup/AvatarGroup.svelte.d.ts +1 -1
  12. package/dist/AvatarGroup/avatar-group.types.d.ts +18 -3
  13. package/dist/AvatarGroup/avatar-group.variants.d.ts +85 -0
  14. package/dist/AvatarGroup/avatar-group.variants.js +19 -29
  15. package/dist/Badge/Badge.svelte +4 -3
  16. package/dist/Badge/Badge.svelte.d.ts +1 -1
  17. package/dist/Badge/badge.types.d.ts +9 -0
  18. package/dist/Breadcrumb/Breadcrumb.svelte +20 -7
  19. package/dist/Breadcrumb/Breadcrumb.svelte.d.ts +1 -1
  20. package/dist/Breadcrumb/breadcrumb.types.d.ts +5 -1
  21. package/dist/Breadcrumb/breadcrumb.variants.d.ts +15 -5
  22. package/dist/Breadcrumb/breadcrumb.variants.js +7 -3
  23. package/dist/Button/Button.svelte +71 -16
  24. package/dist/Button/Button.svelte.d.ts +0 -1
  25. package/dist/Button/button.types.d.ts +61 -2
  26. package/dist/Calendar/Calendar.svelte +4 -0
  27. package/dist/Calendar/Calendar.svelte.d.ts +1 -1
  28. package/dist/Calendar/calendar.types.d.ts +4 -0
  29. package/dist/Card/Card.svelte +5 -4
  30. package/dist/Card/Card.svelte.d.ts +1 -1
  31. package/dist/Card/card.types.d.ts +5 -1
  32. package/dist/Checkbox/Checkbox.svelte +37 -11
  33. package/dist/Checkbox/Checkbox.svelte.d.ts +1 -1
  34. package/dist/Checkbox/checkbox.types.d.ts +16 -1
  35. package/dist/Checkbox/checkbox.variants.d.ts +90 -0
  36. package/dist/Checkbox/checkbox.variants.js +73 -4
  37. package/dist/CheckboxGroup/CheckboxGroup.svelte +215 -0
  38. package/dist/CheckboxGroup/CheckboxGroup.svelte.d.ts +5 -0
  39. package/dist/CheckboxGroup/checkbox-group.types.d.ts +130 -0
  40. package/dist/CheckboxGroup/checkbox-group.types.js +1 -0
  41. package/dist/CheckboxGroup/checkbox-group.variants.d.ts +553 -0
  42. package/dist/CheckboxGroup/checkbox-group.variants.js +231 -0
  43. package/dist/CheckboxGroup/index.d.ts +2 -0
  44. package/dist/CheckboxGroup/index.js +1 -0
  45. package/dist/Chip/Chip.svelte +3 -2
  46. package/dist/Chip/Chip.svelte.d.ts +1 -1
  47. package/dist/Chip/chip.types.d.ts +5 -1
  48. package/dist/Chip/chip.variants.d.ts +135 -45
  49. package/dist/Chip/chip.variants.js +9 -9
  50. package/dist/ContextMenu/ContextMenu.svelte +87 -77
  51. package/dist/ContextMenu/ContextMenu.svelte.d.ts +1 -1
  52. package/dist/ContextMenu/context-menu.types.d.ts +9 -3
  53. package/dist/ContextMenu/context-menu.types.js +1 -1
  54. package/dist/ContextMenu/context-menu.variants.d.ts +74 -160
  55. package/dist/ContextMenu/context-menu.variants.js +63 -95
  56. package/dist/DropdownMenu/DropdownMenu.svelte +37 -43
  57. package/dist/DropdownMenu/DropdownMenu.svelte.d.ts +1 -1
  58. package/dist/DropdownMenu/dropdown-menu.types.d.ts +9 -3
  59. package/dist/DropdownMenu/dropdown-menu.types.js +1 -1
  60. package/dist/DropdownMenu/dropdown-menu.variants.d.ts +79 -230
  61. package/dist/DropdownMenu/dropdown-menu.variants.js +68 -111
  62. package/dist/DropdownMenu/index.d.ts +1 -1
  63. package/dist/Empty/Empty.svelte +68 -33
  64. package/dist/Empty/Empty.svelte.d.ts +1 -1
  65. package/dist/Empty/empty.types.d.ts +26 -9
  66. package/dist/Empty/empty.variants.d.ts +150 -130
  67. package/dist/Empty/empty.variants.js +33 -324
  68. package/dist/FieldGroup/FieldGroup.svelte +11 -6
  69. package/dist/FieldGroup/FieldGroup.svelte.d.ts +1 -1
  70. package/dist/FieldGroup/field-group.types.d.ts +4 -0
  71. package/dist/FileUpload/FileUpload.svelte +561 -0
  72. package/dist/FileUpload/FileUpload.svelte.d.ts +8 -0
  73. package/dist/FileUpload/file-upload.types.d.ts +164 -0
  74. package/dist/FileUpload/file-upload.types.js +1 -0
  75. package/dist/FileUpload/file-upload.variants.d.ts +397 -0
  76. package/dist/FileUpload/file-upload.variants.js +224 -0
  77. package/dist/FileUpload/index.d.ts +2 -0
  78. package/dist/FileUpload/index.js +1 -0
  79. package/dist/FormField/FormField.svelte +17 -18
  80. package/dist/FormField/FormField.svelte.d.ts +1 -1
  81. package/dist/FormField/form-field.types.d.ts +4 -0
  82. package/dist/Icon/Icon.svelte +13 -7
  83. package/dist/Icon/icon.types.d.ts +18 -9
  84. package/dist/Input/Input.svelte +30 -29
  85. package/dist/Kbd/Kbd.svelte +13 -3
  86. package/dist/Kbd/Kbd.svelte.d.ts +1 -1
  87. package/dist/Kbd/index.d.ts +1 -1
  88. package/dist/Kbd/kbd.types.d.ts +15 -1
  89. package/dist/Kbd/kbd.variants.d.ts +92 -30
  90. package/dist/Kbd/kbd.variants.js +55 -35
  91. package/dist/Kbd/useKbd.svelte.d.ts +2 -2
  92. package/dist/Kbd/useKbd.svelte.js +34 -41
  93. package/dist/Link/Link.svelte +69 -24
  94. package/dist/Link/Link.svelte.d.ts +1 -1
  95. package/dist/Link/link.types.d.ts +26 -8
  96. package/dist/Link/link.variants.d.ts +35 -60
  97. package/dist/Link/link.variants.js +8 -110
  98. package/dist/Modal/Modal.svelte +9 -1
  99. package/dist/Modal/modal.types.d.ts +5 -0
  100. package/dist/Modal/modal.variants.d.ts +5 -0
  101. package/dist/Modal/modal.variants.js +1 -0
  102. package/dist/Pagination/Pagination.svelte +143 -94
  103. package/dist/Pagination/Pagination.svelte.d.ts +1 -1
  104. package/dist/Pagination/index.d.ts +1 -1
  105. package/dist/Pagination/pagination.types.d.ts +21 -2
  106. package/dist/Pagination/pagination.variants.d.ts +21 -387
  107. package/dist/Pagination/pagination.variants.js +63 -59
  108. package/dist/PinInput/PinInput.svelte +150 -0
  109. package/dist/PinInput/PinInput.svelte.d.ts +6 -0
  110. package/dist/PinInput/index.d.ts +2 -0
  111. package/dist/PinInput/index.js +1 -0
  112. package/dist/PinInput/pin-input.types.d.ts +99 -0
  113. package/dist/PinInput/pin-input.types.js +1 -0
  114. package/dist/PinInput/pin-input.variants.d.ts +303 -0
  115. package/dist/PinInput/pin-input.variants.js +196 -0
  116. package/dist/Popover/Popover.svelte +9 -12
  117. package/dist/Popover/Popover.svelte.d.ts +1 -1
  118. package/dist/Popover/popover.types.d.ts +4 -0
  119. package/dist/Popover/popover.variants.d.ts +5 -75
  120. package/dist/Popover/popover.variants.js +6 -16
  121. package/dist/Progress/Progress.svelte +58 -30
  122. package/dist/Progress/progress.types.d.ts +9 -1
  123. package/dist/Progress/progress.variants.d.ts +55 -25
  124. package/dist/Progress/progress.variants.js +34 -28
  125. package/dist/RadioGroup/RadioGroup.svelte +105 -61
  126. package/dist/RadioGroup/RadioGroup.svelte.d.ts +1 -1
  127. package/dist/RadioGroup/radio-group.types.d.ts +16 -1
  128. package/dist/RadioGroup/radio-group.variants.d.ts +90 -0
  129. package/dist/RadioGroup/radio-group.variants.js +73 -4
  130. package/dist/Select/Select.svelte +9 -6
  131. package/dist/Select/Select.svelte.d.ts +1 -1
  132. package/dist/Select/select.types.d.ts +4 -0
  133. package/dist/SelectMenu/SelectMenu.svelte +436 -0
  134. package/dist/SelectMenu/SelectMenu.svelte.d.ts +5 -0
  135. package/dist/SelectMenu/index.d.ts +2 -0
  136. package/dist/SelectMenu/index.js +1 -0
  137. package/dist/SelectMenu/select-menu.types.d.ts +262 -0
  138. package/dist/SelectMenu/select-menu.types.js +1 -0
  139. package/dist/SelectMenu/select-menu.variants.d.ts +759 -0
  140. package/dist/SelectMenu/select-menu.variants.js +33 -0
  141. package/dist/Separator/Separator.svelte +1 -2
  142. package/dist/Separator/separator.variants.d.ts +1 -5
  143. package/dist/Separator/separator.variants.js +2 -2
  144. package/dist/Skeleton/Skeleton.svelte +18 -2
  145. package/dist/Skeleton/Skeleton.svelte.d.ts +1 -1
  146. package/dist/Skeleton/skeleton.types.d.ts +10 -1
  147. package/dist/Slideover/Slideover.svelte +9 -1
  148. package/dist/Slideover/slideover.types.d.ts +5 -0
  149. package/dist/Slideover/slideover.variants.d.ts +20 -5
  150. package/dist/Slideover/slideover.variants.js +4 -29
  151. package/dist/Slider/Slider.svelte +135 -0
  152. package/dist/Slider/Slider.svelte.d.ts +6 -0
  153. package/dist/Slider/index.d.ts +2 -0
  154. package/dist/Slider/index.js +1 -0
  155. package/dist/Slider/slider.types.d.ts +55 -0
  156. package/dist/Slider/slider.types.js +1 -0
  157. package/dist/Slider/slider.variants.d.ts +383 -0
  158. package/dist/Slider/slider.variants.js +102 -0
  159. package/dist/Switch/Switch.svelte +32 -31
  160. package/dist/Switch/Switch.svelte.d.ts +1 -1
  161. package/dist/Switch/switch.types.d.ts +6 -1
  162. package/dist/Switch/switch.variants.js +6 -6
  163. package/dist/Tabs/Tabs.svelte +6 -9
  164. package/dist/Tabs/Tabs.svelte.d.ts +1 -1
  165. package/dist/Tabs/tabs.types.d.ts +4 -0
  166. package/dist/Tabs/tabs.variants.js +2 -0
  167. package/dist/Textarea/Textarea.svelte +26 -25
  168. package/dist/ThemeModeButton/theme-mode-button.types.d.ts +7 -2
  169. package/dist/Timeline/Timeline.svelte +62 -19
  170. package/dist/Timeline/Timeline.svelte.d.ts +1 -1
  171. package/dist/Timeline/index.d.ts +1 -1
  172. package/dist/Timeline/timeline.types.d.ts +8 -0
  173. package/dist/Tooltip/Tooltip.svelte +12 -10
  174. package/dist/Tooltip/Tooltip.svelte.d.ts +1 -1
  175. package/dist/Tooltip/tooltip.types.d.ts +8 -4
  176. package/dist/Tooltip/tooltip.variants.d.ts +10 -75
  177. package/dist/Tooltip/tooltip.variants.js +8 -17
  178. package/dist/User/User.svelte +13 -9
  179. package/dist/User/User.svelte.d.ts +1 -1
  180. package/dist/User/user.types.d.ts +4 -0
  181. package/dist/User/user.variants.d.ts +60 -0
  182. package/dist/User/user.variants.js +13 -1
  183. package/dist/config.d.ts +8 -0
  184. package/dist/config.js +9 -1
  185. package/dist/index.d.ts +5 -0
  186. package/dist/index.js +5 -0
  187. package/package.json +2 -2
@@ -14,6 +14,7 @@
14
14
  const config = getComponentConfig('tabs', tabsDefaults)
15
15
 
16
16
  let {
17
+ ref = $bindable(null),
17
18
  items = [],
18
19
  value = $bindable(),
19
20
  defaultValue,
@@ -46,7 +47,7 @@
46
47
 
47
48
  const variantSlots = $derived(tabsVariants({ variant, color, size, orientation }))
48
49
 
49
- const classes = $derived.by(() => ({
50
+ const classes = $derived({
50
51
  root: variantSlots.root({ class: [config.slots.root, className, ui?.root] }),
51
52
  list: variantSlots.list({ class: [config.slots.list, ui?.list] }),
52
53
  indicator: variantSlots.indicator({
@@ -58,7 +59,7 @@
58
59
  }),
59
60
  label: variantSlots.label({ class: [config.slots.label, ui?.label] }),
60
61
  content: variantSlots.content({ class: [config.slots.content, ui?.content] })
61
- }))
62
+ })
62
63
 
63
64
  let rafId = 0
64
65
 
@@ -107,11 +108,6 @@
107
108
  rafId = requestAnimationFrame(updateIndicator)
108
109
  }
109
110
 
110
- function handleValueChange(newValue: string) {
111
- value = newValue
112
- onValueChange?.(newValue)
113
- }
114
-
115
111
  // Update indicator on mount and when dependencies change
116
112
  $effect(() => {
117
113
  void value
@@ -135,8 +131,9 @@
135
131
  </script>
136
132
 
137
133
  <Tabs.Root
138
- {value}
139
- onValueChange={handleValueChange}
134
+ bind:ref
135
+ bind:value
136
+ {onValueChange}
140
137
  {orientation}
141
138
  {activationMode}
142
139
  {disabled}
@@ -1,6 +1,6 @@
1
1
  import type { TabsProps } from './tabs.types.js';
2
2
  export type Props = TabsProps;
3
3
  import { Tabs } from 'bits-ui';
4
- declare const Tabs: import("svelte").Component<TabsProps, {}, "value">;
4
+ declare const Tabs: import("svelte").Component<TabsProps, {}, "ref" | "value">;
5
5
  type Tabs = ReturnType<typeof Tabs>;
6
6
  export default Tabs;
@@ -87,6 +87,10 @@ export interface TabsSlotProps {
87
87
  * @see https://bits-ui.com/docs/components/tabs
88
88
  */
89
89
  export interface TabsProps {
90
+ /**
91
+ * Bindable reference to the root DOM element.
92
+ */
93
+ ref?: HTMLElement | null;
90
94
  /**
91
95
  * Array of tab items to render.
92
96
  * Each item can have a label, icon, content, and optional styling overrides.
@@ -7,6 +7,8 @@ export const tabsVariants = tv({
7
7
  trigger: [
8
8
  'relative inline-flex items-center justify-center whitespace-nowrap',
9
9
  'font-medium cursor-pointer select-none',
10
+ 'data-[state=inactive]:text-on-surface-variant',
11
+ 'hover:data-[state=inactive]:not-disabled:text-on-surface',
10
12
  'focus-visible:outline-none focus-visible:ring-2',
11
13
  'disabled:cursor-not-allowed disabled:opacity-50',
12
14
  'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',
@@ -91,15 +91,16 @@
91
91
  loading && isTrailing ? loadingIcon : trailingIcon || (trailing ? icon : undefined)
92
92
  )
93
93
 
94
- const ariaDescribedBy = $derived.by(() => {
95
- if (!formFieldContext) return undefined
96
- const id = formFieldContext.ariaId
97
- if (hasError) return `${id}-error`
98
- return `${id}-description ${id}-help`
99
- })
94
+ const ariaDescribedBy = $derived(
95
+ !formFieldContext
96
+ ? undefined
97
+ : hasError
98
+ ? `${formFieldContext.ariaId}-error`
99
+ : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
100
+ )
100
101
 
101
- const classes = $derived.by(() => {
102
- const slots = textareaVariants({
102
+ const variantSlots = $derived(
103
+ textareaVariants({
103
104
  variant,
104
105
  color: resolvedColor,
105
106
  size: resolvedSize,
@@ -109,22 +110,22 @@
109
110
  highlight: resolvedHighlight,
110
111
  autoresize
111
112
  })
112
- return {
113
- root: slots.root({
114
- class: [config.slots.root, fieldGroupClass?.root, className, ui?.root]
115
- }),
116
- base: slots.base({
117
- class: [config.slots.base, fieldGroupClass?.base, ui?.base]
118
- }),
119
- leading: slots.leading({ class: [config.slots.leading, ui?.leading] }),
120
- leadingIcon: slots.leadingIcon({
121
- class: [config.slots.leadingIcon, ui?.leadingIcon]
122
- }),
123
- trailing: slots.trailing({ class: [config.slots.trailing, ui?.trailing] }),
124
- trailingIcon: slots.trailingIcon({
125
- class: [config.slots.trailingIcon, ui?.trailingIcon]
126
- })
127
- }
113
+ )
114
+ const classes = $derived({
115
+ root: variantSlots.root({
116
+ class: [config.slots.root, fieldGroupClass?.root, className, ui?.root]
117
+ }),
118
+ base: variantSlots.base({
119
+ class: [config.slots.base, fieldGroupClass?.base, ui?.base]
120
+ }),
121
+ leading: variantSlots.leading({ class: [config.slots.leading, ui?.leading] }),
122
+ leadingIcon: variantSlots.leadingIcon({
123
+ class: [config.slots.leadingIcon, ui?.leadingIcon]
124
+ }),
125
+ trailing: variantSlots.trailing({ class: [config.slots.trailing, ui?.trailing] }),
126
+ trailingIcon: variantSlots.trailingIcon({
127
+ class: [config.slots.trailingIcon, ui?.trailingIcon]
128
+ })
128
129
  })
129
130
 
130
131
  let cachedMaxHeight = $state(0)
@@ -172,6 +173,7 @@
172
173
  {/if}
173
174
 
174
175
  <textarea
176
+ {...restProps}
175
177
  bind:this={ref}
176
178
  bind:value
177
179
  {rows}
@@ -181,7 +183,6 @@
181
183
  aria-describedby={ariaDescribedBy}
182
184
  aria-invalid={resolvedHighlight ? true : undefined}
183
185
  class={classes.base}
184
- {...restProps}
185
186
  ></textarea>
186
187
 
187
188
  {#if trailingSlot}
@@ -1,9 +1,9 @@
1
1
  import type { Snippet } from 'svelte';
2
- import type { HTMLButtonAttributes } from 'svelte/elements';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
4
  import type { ButtonVariantProps } from '../Button/button.variants.js';
5
5
  import type { ThemeModeButtonSlots } from './theme-mode-button.variants.js';
6
- export type ThemeModeButtonProps = Omit<HTMLButtonAttributes, 'children'> & {
6
+ export type ThemeModeButtonProps = Omit<HTMLAttributes<HTMLElement>, 'class' | 'children'> & {
7
7
  /**
8
8
  * Controls the visual style of the button.
9
9
  * @default 'ghost'
@@ -36,6 +36,11 @@ export type ThemeModeButtonProps = Omit<HTMLButtonAttributes, 'children'> & {
36
36
  * @default false
37
37
  */
38
38
  loading?: boolean;
39
+ /**
40
+ * Disables the button and prevents interaction.
41
+ * @default false
42
+ */
43
+ disabled?: boolean;
39
44
  /**
40
45
  * Forces equal width and height, ideal for icon-only buttons.
41
46
  * @default true
@@ -5,6 +5,7 @@
5
5
  </script>
6
6
 
7
7
  <script lang="ts">
8
+ import type { ClassNameValue } from 'tailwind-merge'
8
9
  import { timelineVariants, timelineDefaults } from './timeline.variants.js'
9
10
  import type { TimelineItemState } from './timeline.types.js'
10
11
  import { getComponentConfig } from '../config.js'
@@ -14,6 +15,7 @@
14
15
  const config = getComponentConfig('timeline', timelineDefaults)
15
16
 
16
17
  let {
18
+ ref = $bindable(null),
17
19
  as = 'div',
18
20
  items = [],
19
21
  size = config.defaultVariants.size,
@@ -31,19 +33,54 @@
31
33
  ...restProps
32
34
  }: Props = $props()
33
35
 
34
- // Pre-compute shared slot classes outside the loop (these don't vary per item)
36
+ type ItemUi = Partial<Record<string, ClassNameValue>>
37
+
35
38
  const classes = $derived.by(() => {
36
39
  const slots = timelineVariants({ orientation, color, size, reverse })
40
+ const c = config.slots
41
+
42
+ // Pre-compute defaults — reused for all items without per-item ui
43
+ const _item = slots.item({ class: [c.item, ui?.item] })
44
+ const _container = slots.container({ class: [c.container, ui?.container] })
45
+ const _indicator = slots.indicator({ class: [c.indicator, ui?.indicator] })
46
+ const _separator = slots.separator({ class: [c.separator, ui?.separator] })
47
+ const _wrapper = slots.wrapper({ class: [c.wrapper, ui?.wrapper] })
48
+ const _date = slots.date({ class: [c.date, ui?.date] })
49
+ const _title = slots.title({ class: [c.title, ui?.title] })
50
+ const _description = slots.description({ class: [c.description, ui?.description] })
51
+
37
52
  return {
38
- root: slots.root({ class: [config.slots.root, className, ui?.root] }),
39
- item: slots.item({ class: [config.slots.item, ui?.item] }),
40
- container: slots.container({ class: [config.slots.container, ui?.container] }),
41
- indicator: slots.indicator({ class: [config.slots.indicator, ui?.indicator] }),
42
- separator: slots.separator({ class: [config.slots.separator, ui?.separator] }),
43
- wrapper: slots.wrapper({ class: [config.slots.wrapper, ui?.wrapper] }),
44
- date: slots.date({ class: [config.slots.date, ui?.date] }),
45
- title: slots.title({ class: [config.slots.title, ui?.title] }),
46
- description: slots.description({ class: [config.slots.description, ui?.description] })
53
+ root: slots.root({ class: [c.root, className, ui?.root] }),
54
+ item: (itemClass?: ClassNameValue, itemUi?: ItemUi) =>
55
+ itemClass || itemUi
56
+ ? slots.item({ class: [c.item, ui?.item, itemUi?.item, itemClass] })
57
+ : _item,
58
+ container: (itemUi?: ItemUi) =>
59
+ itemUi
60
+ ? slots.container({ class: [c.container, ui?.container, itemUi.container] })
61
+ : _container,
62
+ indicator: (itemUi?: ItemUi) =>
63
+ itemUi
64
+ ? slots.indicator({ class: [c.indicator, ui?.indicator, itemUi.indicator] })
65
+ : _indicator,
66
+ separator: (itemUi?: ItemUi) =>
67
+ itemUi
68
+ ? slots.separator({ class: [c.separator, ui?.separator, itemUi.separator] })
69
+ : _separator,
70
+ wrapper: (itemUi?: ItemUi) =>
71
+ itemUi
72
+ ? slots.wrapper({ class: [c.wrapper, ui?.wrapper, itemUi.wrapper] })
73
+ : _wrapper,
74
+ date: (itemUi?: ItemUi) =>
75
+ itemUi?.date ? slots.date({ class: [c.date, ui?.date, itemUi.date] }) : _date,
76
+ title: (itemUi?: ItemUi) =>
77
+ itemUi?.title ? slots.title({ class: [c.title, ui?.title, itemUi.title] }) : _title,
78
+ description: (itemUi?: ItemUi) =>
79
+ itemUi?.description
80
+ ? slots.description({
81
+ class: [c.description, ui?.description, itemUi.description]
82
+ })
83
+ : _description
47
84
  }
48
85
  })
49
86
 
@@ -58,15 +95,21 @@
58
95
  }
59
96
  </script>
60
97
 
61
- <svelte:element this={as} class={classes.root} {...restProps}>
98
+ <svelte:element
99
+ this={as}
100
+ bind:this={ref}
101
+ class={classes.root}
102
+ data-orientation={orientation}
103
+ {...restProps}
104
+ >
62
105
  {#each items as item, index (item.value ?? index)}
63
106
  {@const state = getState(index)}
64
- <div class={item.class ? `${classes.item} ${item.class}` : classes.item} data-state={state}>
65
- <div class={classes.container}>
107
+ <div class={classes.item(item.class, item.ui)} data-state={state}>
108
+ <div class={classes.container(item.ui)}>
66
109
  {#if indicator}
67
110
  {@render indicator({ item, index, state })}
68
111
  {:else}
69
- <div class={classes.indicator}>
112
+ <div class={classes.indicator(item.ui)}>
70
113
  {#if item.avatar}
71
114
  <Avatar {...item.avatar} {size} />
72
115
  {:else if item.icon}
@@ -76,27 +119,27 @@
76
119
  {/if}
77
120
 
78
121
  {#if reverse ? index > 0 : index < items.length - 1}
79
- <div class={classes.separator}></div>
122
+ <div class={classes.separator(item.ui)}></div>
80
123
  {/if}
81
124
  </div>
82
125
 
83
- <div class={classes.wrapper}>
126
+ <div class={classes.wrapper(item.ui)}>
84
127
  {#if dateSlot}
85
128
  {@render dateSlot({ item, index, state })}
86
129
  {:else if item.date}
87
- <div class={classes.date}>{item.date}</div>
130
+ <div class={classes.date(item.ui)}>{item.date}</div>
88
131
  {/if}
89
132
 
90
133
  {#if titleSlot}
91
134
  {@render titleSlot({ item, index, state })}
92
135
  {:else if item.title}
93
- <div class={classes.title}>{item.title}</div>
136
+ <div class={classes.title(item.ui)}>{item.title}</div>
94
137
  {/if}
95
138
 
96
139
  {#if descriptionSlot}
97
140
  {@render descriptionSlot({ item, index, state })}
98
141
  {:else if item.description}
99
- <div class={classes.description}>{item.description}</div>
142
+ <div class={classes.description(item.ui)}>{item.description}</div>
100
143
  {/if}
101
144
 
102
145
  {#if content}
@@ -1,5 +1,5 @@
1
1
  import type { TimelineProps } from './timeline.types.js';
2
2
  export type Props = TimelineProps;
3
- declare const Timeline: import("svelte").Component<TimelineProps, {}, "">;
3
+ declare const Timeline: import("svelte").Component<TimelineProps, {}, "ref">;
4
4
  type Timeline = ReturnType<typeof Timeline>;
5
5
  export default Timeline;
@@ -1,2 +1,2 @@
1
1
  export { default as Timeline } from './Timeline.svelte';
2
- export type { TimelineProps, TimelineItem } from './timeline.types.js';
2
+ export type { TimelineProps, TimelineItem, TimelineItemState } from './timeline.types.js';
@@ -38,8 +38,16 @@ export type TimelineItem = {
38
38
  * Additional CSS classes for this item.
39
39
  */
40
40
  class?: ClassNameValue;
41
+ /**
42
+ * Per-item slot class overrides.
43
+ */
44
+ ui?: Partial<Record<'item' | 'container' | 'indicator' | 'separator' | 'wrapper' | 'date' | 'title' | 'description', ClassNameValue>>;
41
45
  };
42
46
  export type TimelineProps = Omit<HTMLAttributes<HTMLElement>, 'class'> & {
47
+ /**
48
+ * Bindable reference to the root DOM element.
49
+ */
50
+ ref?: HTMLElement | null;
43
51
  /**
44
52
  * The HTML element to render as.
45
53
  * @default 'div'
@@ -13,6 +13,7 @@
13
13
  const config = getComponentConfig('tooltip', tooltipDefaults)
14
14
 
15
15
  let {
16
+ ref = $bindable(null),
16
17
  open = $bindable(false),
17
18
  onOpenChange,
18
19
  delayDuration,
@@ -20,7 +21,7 @@
20
21
  disableCloseOnTriggerClick,
21
22
  ignoreNonKeyboardFocus,
22
23
  disabled = false,
23
- side = config.defaultVariants.side ?? 'bottom',
24
+ side = 'bottom',
24
25
  sideOffset = 8,
25
26
  align = 'center',
26
27
  alignOffset = 0,
@@ -39,17 +40,18 @@
39
40
  ui,
40
41
  class: className,
41
42
  children,
42
- content: contentSlot
43
+ content: contentSlot,
44
+ ...restProps
43
45
  }: Props = $props()
44
46
 
45
47
  // Pre-compute booleans
46
48
  const hasText = $derived(!!text)
47
49
  const hasKbds = $derived(!!kbds?.length)
48
50
  const hasContent = $derived(hasText || hasKbds || !!contentSlot)
49
- const showArrow = $derived(!!arrow)
50
51
 
51
52
  // Compute variant classes
52
- const variantSlots = $derived(tooltipVariants({ side, transition }))
53
+ const variantSlots = $derived(tooltipVariants({ transition }))
54
+ const kbdsSize = (config.slots.kbdsSize ?? 'sm') as 'sm' | 'md' | 'lg'
53
55
  const classes = $derived({
54
56
  content: variantSlots.content({ class: [config.slots.content, ui?.content] }),
55
57
  arrow: variantSlots.arrow({ class: [config.slots.arrow, ui?.arrow] }),
@@ -57,7 +59,7 @@
57
59
  kbds: variantSlots.kbds({ class: [config.slots.kbds, ui?.kbds] })
58
60
  })
59
61
 
60
- // Arrow props - default size matches tooltip height for proper pointing
62
+ // Arrow props
61
63
  const arrowProps = $derived.by(() => {
62
64
  if (typeof arrow === 'object') {
63
65
  return { width: 12, height: 6, ...arrow }
@@ -81,9 +83,9 @@
81
83
  <span class="mx-0.5 text-inverse-on-surface/60">·</span>
82
84
  {/if}
83
85
  {#if typeof kbd === 'string'}
84
- <Kbd value={kbd} size="sm" variant="soft" color="surface" />
86
+ <Kbd value={kbd} size={kbdsSize} variant="soft" color="surface" />
85
87
  {:else}
86
- <Kbd size="sm" variant="soft" color="surface" {...kbd} />
88
+ <Kbd size={kbdsSize} variant="soft" color="surface" {...kbd} />
87
89
  {/if}
88
90
  {/each}
89
91
  </span>
@@ -93,6 +95,7 @@
93
95
 
94
96
  {#snippet tooltipContentEl()}
95
97
  <Tooltip.Content
98
+ bind:ref
96
99
  {side}
97
100
  {sideOffset}
98
101
  {align}
@@ -105,10 +108,11 @@
105
108
  {onEscapeKeydown}
106
109
  {forceMount}
107
110
  class={classes.content}
111
+ {...restProps}
108
112
  >
109
113
  {@render tooltipContent()}
110
114
 
111
- {#if showArrow}
115
+ {#if arrow}
112
116
  <Tooltip.Arrow
113
117
  width={arrowProps.width}
114
118
  height={arrowProps.height}
@@ -122,8 +126,6 @@
122
126
  <Tooltip.Root
123
127
  bind:open
124
128
  {onOpenChange}
125
- {delayDuration}
126
- {disableHoverableContent}
127
129
  {disableCloseOnTriggerClick}
128
130
  {ignoreNonKeyboardFocus}
129
131
  disabled={disabled || !hasContent}
@@ -1,6 +1,6 @@
1
1
  import type { TooltipProps } from './tooltip.types.js';
2
2
  export type Props = TooltipProps;
3
3
  import { Tooltip } from 'bits-ui';
4
- declare const Tooltip: import("svelte").Component<TooltipProps, {}, "open">;
4
+ declare const Tooltip: import("svelte").Component<TooltipProps, {}, "ref" | "open">;
5
5
  type Tooltip = ReturnType<typeof Tooltip>;
6
6
  export default Tooltip;
@@ -1,13 +1,17 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { ClassNameValue } from 'tailwind-merge';
3
3
  import type { TooltipSlots, TooltipVariantProps } from './tooltip.variants.js';
4
- import type { TooltipRootPropsWithoutHTML, TooltipContentPropsWithoutHTML, TooltipArrowPropsWithoutHTML } from 'bits-ui';
4
+ import type { TooltipRootPropsWithoutHTML, TooltipContentPropsWithoutHTML, TooltipArrowPropsWithoutHTML, TooltipProviderPropsWithoutHTML } from 'bits-ui';
5
5
  import type { KbdProps } from '../Kbd/kbd.types.js';
6
- export type TooltipSide = 'top' | 'right' | 'bottom' | 'left';
7
6
  export type TooltipAlign = 'start' | 'center' | 'end';
8
- type RootProps = Pick<TooltipRootPropsWithoutHTML, 'open' | 'onOpenChange' | 'delayDuration' | 'disableHoverableContent' | 'disableCloseOnTriggerClick' | 'ignoreNonKeyboardFocus' | 'disabled'>;
7
+ type ProviderProps = Pick<TooltipProviderPropsWithoutHTML, 'delayDuration' | 'disableHoverableContent'>;
8
+ type RootProps = Pick<TooltipRootPropsWithoutHTML, 'open' | 'onOpenChange' | 'disableCloseOnTriggerClick' | 'ignoreNonKeyboardFocus' | 'disabled'>;
9
9
  type ContentProps = Pick<TooltipContentPropsWithoutHTML, 'side' | 'sideOffset' | 'align' | 'alignOffset' | 'avoidCollisions' | 'collisionBoundary' | 'collisionPadding' | 'sticky' | 'hideWhenDetached' | 'onEscapeKeydown' | 'forceMount'>;
10
- export interface TooltipProps extends RootProps, ContentProps {
10
+ export interface TooltipProps extends ProviderProps, RootProps, ContentProps {
11
+ /**
12
+ * Bindable reference to the content DOM element.
13
+ */
14
+ ref?: HTMLElement | null;
11
15
  /**
12
16
  * The text content of the tooltip.
13
17
  */
@@ -1,22 +1,8 @@
1
1
  import { type VariantProps } from 'tailwind-variants';
2
2
  export declare const tooltipVariants: import("tailwind-variants").TVReturnType<{
3
- side: {
4
- top: {
5
- content: string;
6
- };
7
- right: {
8
- content: string;
9
- };
10
- bottom: {
11
- content: string;
12
- };
13
- left: {
14
- content: string;
15
- };
16
- };
17
3
  transition: {
18
4
  true: {
19
- content: string;
5
+ content: string[];
20
6
  };
21
7
  };
22
8
  }, {
@@ -24,24 +10,11 @@ export declare const tooltipVariants: import("tailwind-variants").TVReturnType<{
24
10
  arrow: string;
25
11
  text: string;
26
12
  kbds: string;
13
+ kbdsSize: string;
27
14
  }, undefined, {
28
- side: {
29
- top: {
30
- content: string;
31
- };
32
- right: {
33
- content: string;
34
- };
35
- bottom: {
36
- content: string;
37
- };
38
- left: {
39
- content: string;
40
- };
41
- };
42
15
  transition: {
43
16
  true: {
44
- content: string;
17
+ content: string[];
45
18
  };
46
19
  };
47
20
  }, {
@@ -49,24 +22,11 @@ export declare const tooltipVariants: import("tailwind-variants").TVReturnType<{
49
22
  arrow: string;
50
23
  text: string;
51
24
  kbds: string;
25
+ kbdsSize: string;
52
26
  }, import("tailwind-variants").TVReturnType<{
53
- side: {
54
- top: {
55
- content: string;
56
- };
57
- right: {
58
- content: string;
59
- };
60
- bottom: {
61
- content: string;
62
- };
63
- left: {
64
- content: string;
65
- };
66
- };
67
27
  transition: {
68
28
  true: {
69
- content: string;
29
+ content: string[];
70
30
  };
71
31
  };
72
32
  }, {
@@ -74,28 +34,15 @@ export declare const tooltipVariants: import("tailwind-variants").TVReturnType<{
74
34
  arrow: string;
75
35
  text: string;
76
36
  kbds: string;
37
+ kbdsSize: string;
77
38
  }, undefined, unknown, unknown, undefined>>;
78
39
  export type TooltipVariantProps = VariantProps<typeof tooltipVariants>;
79
40
  export type TooltipSlots = keyof ReturnType<typeof tooltipVariants>;
80
41
  export declare const tooltipDefaults: {
81
42
  defaultVariants: import("tailwind-variants").TVDefaultVariants<{
82
- side: {
83
- top: {
84
- content: string;
85
- };
86
- right: {
87
- content: string;
88
- };
89
- bottom: {
90
- content: string;
91
- };
92
- left: {
93
- content: string;
94
- };
95
- };
96
43
  transition: {
97
44
  true: {
98
- content: string;
45
+ content: string[];
99
46
  };
100
47
  };
101
48
  }, {
@@ -103,24 +50,11 @@ export declare const tooltipDefaults: {
103
50
  arrow: string;
104
51
  text: string;
105
52
  kbds: string;
53
+ kbdsSize: string;
106
54
  }, {
107
- side: {
108
- top: {
109
- content: string;
110
- };
111
- right: {
112
- content: string;
113
- };
114
- bottom: {
115
- content: string;
116
- };
117
- left: {
118
- content: string;
119
- };
120
- };
121
55
  transition: {
122
56
  true: {
123
- content: string;
57
+ content: string[];
124
58
  };
125
59
  };
126
60
  }, {
@@ -128,6 +62,7 @@ export declare const tooltipDefaults: {
128
62
  arrow: string;
129
63
  text: string;
130
64
  kbds: string;
65
+ kbdsSize: string;
131
66
  }>;
132
67
  slots: Partial<Record<TooltipSlots, string>>;
133
68
  };
@@ -10,31 +10,22 @@ export const tooltipVariants = tv({
10
10
  ],
11
11
  arrow: 'fill-inverse-surface text-inverse-surface',
12
12
  text: 'truncate',
13
- kbds: 'hidden lg:inline-flex items-center shrink-0 gap-0.5'
13
+ kbds: 'hidden lg:inline-flex items-center shrink-0 gap-0.5',
14
+ kbdsSize: 'sm'
14
15
  },
15
16
  variants: {
16
- side: {
17
- top: {
18
- content: 'data-[state=delayed-open]:animate-[slide-in-from-bottom_150ms_ease-out] data-[state=closed]:animate-[slide-in-from-top_100ms_ease-in_reverse]'
19
- },
20
- right: {
21
- content: 'data-[state=delayed-open]:animate-[slide-in-from-left_150ms_ease-out] data-[state=closed]:animate-[slide-in-from-right_100ms_ease-in_reverse]'
22
- },
23
- bottom: {
24
- content: 'data-[state=delayed-open]:animate-[slide-in-from-top_150ms_ease-out] data-[state=closed]:animate-[slide-in-from-bottom_100ms_ease-in_reverse]'
25
- },
26
- left: {
27
- content: 'data-[state=delayed-open]:animate-[slide-in-from-right_150ms_ease-out] data-[state=closed]:animate-[slide-in-from-left_100ms_ease-in_reverse]'
28
- }
29
- },
30
17
  transition: {
31
18
  true: {
32
- content: 'data-[state=delayed-open]:animate-[fade-in_150ms_ease-out,zoom-in_150ms_ease-out] data-[state=closed]:animate-[fade-out_100ms_ease-in,zoom-out_100ms_ease-in]'
19
+ content: [
20
+ 'data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95',
21
+ 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
22
+ 'data-[side=top]:slide-in-from-bottom-2 data-[side=right]:slide-in-from-left-2',
23
+ 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2'
24
+ ]
33
25
  }
34
26
  }
35
27
  },
36
28
  defaultVariants: {
37
- side: 'bottom',
38
29
  transition: true
39
30
  }
40
31
  });