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
@@ -11,11 +11,13 @@
11
11
  import { getContext } from 'svelte'
12
12
  import Icon from '../Icon/Icon.svelte'
13
13
  import type { FormFieldProps } from '../FormField/form-field.types.js'
14
+ import type { RadioGroupItem } from './radio-group.types.js'
14
15
 
15
16
  const config = getComponentConfig('radioGroup', radioGroupDefaults)
16
17
  const icons = getComponentConfig('icons', iconsDefaults)
17
18
 
18
19
  let {
20
+ ref = $bindable(null),
19
21
  value = $bindable(''),
20
22
  onValueChange,
21
23
  items = [],
@@ -24,9 +26,12 @@
24
26
  name,
25
27
  color = config.defaultVariants.color,
26
28
  size,
29
+ variant = config.defaultVariants.variant,
30
+ indicator = config.defaultVariants.indicator,
27
31
  orientation = config.defaultVariants.orientation,
28
32
  disabled = false,
29
33
  required = false,
34
+ readonly = false,
30
35
  loop = true,
31
36
  loading = false,
32
37
  loadingIcon = icons.loading,
@@ -34,7 +39,8 @@
34
39
  legendSlot,
35
40
  labelSlot,
36
41
  descriptionSlot,
37
- class: className
42
+ class: className,
43
+ ...restProps
38
44
  }: Props = $props()
39
45
 
40
46
  const formFieldContext = getContext<
@@ -57,16 +63,20 @@
57
63
  const resolvedName = $derived(name ?? formFieldContext?.name)
58
64
  const isDisabled = $derived(disabled || loading)
59
65
 
60
- const ariaDescribedBy = $derived.by(() => {
61
- if (!formFieldContext) return undefined
62
- const fid = formFieldContext.ariaId
63
- return hasError ? `${fid}-error` : `${fid}-description ${fid}-help`
64
- })
66
+ const ariaDescribedBy = $derived(
67
+ !formFieldContext
68
+ ? undefined
69
+ : hasError
70
+ ? `${formFieldContext.ariaId}-error`
71
+ : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
72
+ )
65
73
 
66
74
  const slots = $derived(
67
75
  radioGroupVariants({
68
76
  color: resolvedColor,
69
77
  size: resolvedSize,
78
+ variant,
79
+ indicator,
70
80
  orientation,
71
81
  loading,
72
82
  required,
@@ -90,9 +100,75 @@
90
100
  label: slots.label({ class: [config.slots.label, ui?.label] }),
91
101
  description: slots.description({ class: [config.slots.description, ui?.description] })
92
102
  }))
103
+
104
+ function handleCardItemClick(e: MouseEvent, btnId: string, itemDisabled: boolean) {
105
+ if (itemDisabled) return
106
+ if ((e.target as Element).closest('button')) return
107
+ document.getElementById(btnId)?.click()
108
+ }
93
109
  </script>
94
110
 
95
- <div class={layoutClasses.root}>
111
+ {#snippet itemContent(radioItem: RadioGroupItem)}
112
+ {@const itemId = `${resolvedId}-${radioItem.value}`}
113
+ {@const itemDisabled = isDisabled || !!radioItem.disabled}
114
+ <div class={layoutClasses.container}>
115
+ <RadioGroup.Item
116
+ value={radioItem.value}
117
+ disabled={itemDisabled}
118
+ id={itemId}
119
+ class={elementClasses.base}
120
+ >
121
+ {#snippet children({ checked })}
122
+ {#if checked}
123
+ <span class={elementClasses.indicator}>
124
+ {#if loading}
125
+ <Icon name={loadingIcon} class={elementClasses.loadingIcon} />
126
+ {/if}
127
+ </span>
128
+ {/if}
129
+ {/snippet}
130
+ </RadioGroup.Item>
131
+ </div>
132
+
133
+ {#if radioItem.label || radioItem.description || labelSlot || descriptionSlot}
134
+ <div class={layoutClasses.wrapper}>
135
+ {#if labelSlot}
136
+ {@render labelSlot({ item: radioItem })}
137
+ {:else if radioItem.label}
138
+ {#if variant === 'card'}
139
+ <span
140
+ class={[elementClasses.label, itemDisabled && 'cursor-not-allowed']
141
+ .filter(Boolean)
142
+ .join(' ')}>{radioItem.label}</span
143
+ >
144
+ {:else}
145
+ <Label.Root
146
+ for={itemId}
147
+ class={[elementClasses.label, itemDisabled && 'cursor-not-allowed']
148
+ .filter(Boolean)
149
+ .join(' ')}
150
+ >
151
+ {radioItem.label}
152
+ </Label.Root>
153
+ {/if}
154
+ {/if}
155
+
156
+ {#if descriptionSlot}
157
+ {@render descriptionSlot({ item: radioItem })}
158
+ {:else if radioItem.description}
159
+ <p
160
+ class={[elementClasses.description, itemDisabled && 'cursor-not-allowed']
161
+ .filter(Boolean)
162
+ .join(' ')}
163
+ >
164
+ {radioItem.description}
165
+ </p>
166
+ {/if}
167
+ </div>
168
+ {/if}
169
+ {/snippet}
170
+
171
+ <div {...restProps} bind:this={ref} class={layoutClasses.root}>
96
172
  <RadioGroup.Root
97
173
  bind:value
98
174
  {onValueChange}
@@ -100,6 +176,7 @@
100
176
  name={resolvedName}
101
177
  disabled={isDisabled}
102
178
  {required}
179
+ {readonly}
103
180
  {loop}
104
181
  {orientation}
105
182
  aria-describedby={ariaDescribedBy}
@@ -115,61 +192,28 @@
115
192
  {/if}
116
193
 
117
194
  {#each items as radioItem (radioItem.value)}
118
- {@const itemId = `${resolvedId}-${radioItem.value}`}
119
- {@const itemDisabled = isDisabled || radioItem.disabled}
120
-
121
- <div class="{layoutClasses.item}{itemDisabled && !isDisabled ? ' opacity-75' : ''}">
122
- <div class={layoutClasses.container}>
123
- <RadioGroup.Item
124
- value={radioItem.value}
125
- disabled={itemDisabled}
126
- id={itemId}
127
- class={elementClasses.base}
128
- >
129
- {#snippet children({ checked })}
130
- {#if checked}
131
- <span class={elementClasses.indicator}>
132
- {#if loading}
133
- <Icon
134
- name={loadingIcon}
135
- class={elementClasses.loadingIcon}
136
- />
137
- {/if}
138
- </span>
139
- {/if}
140
- {/snippet}
141
- </RadioGroup.Item>
195
+ {#if variant === 'card'}
196
+ <div
197
+ role="none"
198
+ class={layoutClasses.item}
199
+ class:opacity-75={radioItem.disabled && !isDisabled}
200
+ onclick={(e) =>
201
+ handleCardItemClick(
202
+ e,
203
+ `${resolvedId}-${radioItem.value}`,
204
+ isDisabled || !!radioItem.disabled
205
+ )}
206
+ >
207
+ {@render itemContent(radioItem)}
142
208
  </div>
143
-
144
- {#if radioItem.label || radioItem.description || labelSlot || descriptionSlot}
145
- <div class={layoutClasses.wrapper}>
146
- {#if labelSlot}
147
- {@render labelSlot({ item: radioItem })}
148
- {:else if radioItem.label}
149
- <Label.Root
150
- for={itemId}
151
- class="{elementClasses.label}{itemDisabled
152
- ? ' cursor-not-allowed'
153
- : ''}"
154
- >
155
- {radioItem.label}
156
- </Label.Root>
157
- {/if}
158
-
159
- {#if descriptionSlot}
160
- {@render descriptionSlot({ item: radioItem })}
161
- {:else if radioItem.description}
162
- <p
163
- class="{elementClasses.description}{itemDisabled
164
- ? ' cursor-not-allowed'
165
- : ''}"
166
- >
167
- {radioItem.description}
168
- </p>
169
- {/if}
170
- </div>
171
- {/if}
172
- </div>
209
+ {:else}
210
+ <div
211
+ class={layoutClasses.item}
212
+ class:opacity-75={radioItem.disabled && !isDisabled}
213
+ >
214
+ {@render itemContent(radioItem)}
215
+ </div>
216
+ {/if}
173
217
  {/each}
174
218
  </RadioGroup.Root>
175
219
  </div>
@@ -1,6 +1,6 @@
1
1
  import type { RadioGroupProps } from './radio-group.types.js';
2
2
  export type Props = RadioGroupProps;
3
3
  import { RadioGroup } from 'bits-ui';
4
- declare const RadioGroup: import("svelte").Component<RadioGroupProps, {}, "value">;
4
+ declare const RadioGroup: import("svelte").Component<RadioGroupProps, {}, "ref" | "value">;
5
5
  type RadioGroup = ReturnType<typeof RadioGroup>;
6
6
  export default RadioGroup;
@@ -1,6 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { RadioGroup as RadioGroupPrimitive } from 'bits-ui';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
+ import type { HTMLAttributes } from 'svelte/elements';
4
5
  import type { RadioGroupVariantProps, RadioGroupSlots } from './radio-group.variants.js';
5
6
  export type RadioGroupItem = {
6
7
  /**
@@ -21,7 +22,11 @@ export type RadioGroupItem = {
21
22
  */
22
23
  disabled?: boolean;
23
24
  };
24
- export type RadioGroupProps = Pick<RadioGroupPrimitive.RootProps, 'disabled' | 'name' | 'required' | 'loop'> & {
25
+ export type RadioGroupProps = Pick<RadioGroupPrimitive.RootProps, 'disabled' | 'name' | 'required' | 'loop' | 'readonly'> & Omit<HTMLAttributes<HTMLElement>, 'class'> & {
26
+ /**
27
+ * Bindable reference to the root DOM element.
28
+ */
29
+ ref?: HTMLElement | null;
25
30
  /**
26
31
  * The selected value. Supports two-way binding with `bind:value`.
27
32
  */
@@ -44,6 +49,16 @@ export type RadioGroupProps = Pick<RadioGroupPrimitive.RootProps, 'disabled' | '
44
49
  * @default 'md'
45
50
  */
46
51
  size?: NonNullable<RadioGroupVariantProps['size']>;
52
+ /**
53
+ * Controls the visual style of each radio item.
54
+ * @default 'list'
55
+ */
56
+ variant?: NonNullable<RadioGroupVariantProps['variant']>;
57
+ /**
58
+ * Controls the position of the radio indicator.
59
+ * @default 'start'
60
+ */
61
+ indicator?: NonNullable<RadioGroupVariantProps['indicator']>;
47
62
  /**
48
63
  * Controls the layout direction.
49
64
  * @default 'vertical'
@@ -52,6 +52,24 @@ export declare const radioGroupVariants: import("tailwind-variants").TVReturnTyp
52
52
  wrapper: string;
53
53
  };
54
54
  };
55
+ variant: {
56
+ list: string;
57
+ card: {
58
+ item: string;
59
+ };
60
+ };
61
+ indicator: {
62
+ start: {
63
+ wrapper: string;
64
+ };
65
+ end: {
66
+ item: string;
67
+ wrapper: string;
68
+ };
69
+ hidden: {
70
+ container: string;
71
+ };
72
+ };
55
73
  orientation: {
56
74
  horizontal: {
57
75
  fieldset: string;
@@ -141,6 +159,24 @@ export declare const radioGroupVariants: import("tailwind-variants").TVReturnTyp
141
159
  wrapper: string;
142
160
  };
143
161
  };
162
+ variant: {
163
+ list: string;
164
+ card: {
165
+ item: string;
166
+ };
167
+ };
168
+ indicator: {
169
+ start: {
170
+ wrapper: string;
171
+ };
172
+ end: {
173
+ item: string;
174
+ wrapper: string;
175
+ };
176
+ hidden: {
177
+ container: string;
178
+ };
179
+ };
144
180
  orientation: {
145
181
  horizontal: {
146
182
  fieldset: string;
@@ -230,6 +266,24 @@ export declare const radioGroupVariants: import("tailwind-variants").TVReturnTyp
230
266
  wrapper: string;
231
267
  };
232
268
  };
269
+ variant: {
270
+ list: string;
271
+ card: {
272
+ item: string;
273
+ };
274
+ };
275
+ indicator: {
276
+ start: {
277
+ wrapper: string;
278
+ };
279
+ end: {
280
+ item: string;
281
+ wrapper: string;
282
+ };
283
+ hidden: {
284
+ container: string;
285
+ };
286
+ };
233
287
  orientation: {
234
288
  horizontal: {
235
289
  fieldset: string;
@@ -323,6 +377,24 @@ export declare const radioGroupDefaults: {
323
377
  wrapper: string;
324
378
  };
325
379
  };
380
+ variant: {
381
+ list: string;
382
+ card: {
383
+ item: string;
384
+ };
385
+ };
386
+ indicator: {
387
+ start: {
388
+ wrapper: string;
389
+ };
390
+ end: {
391
+ item: string;
392
+ wrapper: string;
393
+ };
394
+ hidden: {
395
+ container: string;
396
+ };
397
+ };
326
398
  orientation: {
327
399
  horizontal: {
328
400
  fieldset: string;
@@ -412,6 +484,24 @@ export declare const radioGroupDefaults: {
412
484
  wrapper: string;
413
485
  };
414
486
  };
487
+ variant: {
488
+ list: string;
489
+ card: {
490
+ item: string;
491
+ };
492
+ };
493
+ indicator: {
494
+ start: {
495
+ wrapper: string;
496
+ };
497
+ end: {
498
+ item: string;
499
+ wrapper: string;
500
+ };
501
+ hidden: {
502
+ container: string;
503
+ };
504
+ };
415
505
  orientation: {
416
506
  horizontal: {
417
507
  fieldset: string;
@@ -15,10 +15,10 @@ export const radioGroupVariants = tv({
15
15
  ],
16
16
  indicator: [
17
17
  'flex items-center justify-center rounded-full',
18
- 'after:content-[""] after:block after:rounded-full after:bg-white'
18
+ 'after:content-[""] after:block after:rounded-full after:bg-surface'
19
19
  ],
20
- loadingIcon: 'shrink-0 animate-spin text-white',
21
- wrapper: 'ms-2',
20
+ loadingIcon: 'shrink-0 animate-spin text-surface',
21
+ wrapper: '',
22
22
  label: 'block font-medium text-on-surface',
23
23
  description: 'text-on-surface-variant'
24
24
  },
@@ -75,6 +75,24 @@ export const radioGroupVariants = tv({
75
75
  wrapper: 'text-base'
76
76
  }
77
77
  },
78
+ variant: {
79
+ list: '',
80
+ card: {
81
+ item: 'border border-outline-variant rounded-lg cursor-pointer select-none'
82
+ }
83
+ },
84
+ indicator: {
85
+ start: {
86
+ wrapper: 'ms-2'
87
+ },
88
+ end: {
89
+ item: 'flex-row-reverse',
90
+ wrapper: 'me-2'
91
+ },
92
+ hidden: {
93
+ container: 'sr-only'
94
+ }
95
+ },
78
96
  orientation: {
79
97
  horizontal: {
80
98
  fieldset: 'flex-row'
@@ -149,11 +167,62 @@ export const radioGroupVariants = tv({
149
167
  class: {
150
168
  base: 'data-[state=checked]:bg-on-surface data-[state=checked]:border-on-surface focus-visible:outline-outline'
151
169
  }
152
- }
170
+ },
171
+ // ========== CARD × SIZE (padding) ==========
172
+ { variant: 'card', size: 'xs', class: { item: 'p-2' } },
173
+ { variant: 'card', size: 'sm', class: { item: 'p-2.5' } },
174
+ { variant: 'card', size: 'md', class: { item: 'p-3' } },
175
+ { variant: 'card', size: 'lg', class: { item: 'p-3.5' } },
176
+ { variant: 'card', size: 'xl', class: { item: 'p-4' } },
177
+ // ========== CARD × COLOR (checked border) ==========
178
+ {
179
+ variant: 'card',
180
+ color: 'primary',
181
+ class: { item: 'has-[[data-state=checked]]:border-primary' }
182
+ },
183
+ {
184
+ variant: 'card',
185
+ color: 'secondary',
186
+ class: { item: 'has-[[data-state=checked]]:border-secondary' }
187
+ },
188
+ {
189
+ variant: 'card',
190
+ color: 'tertiary',
191
+ class: { item: 'has-[[data-state=checked]]:border-tertiary' }
192
+ },
193
+ {
194
+ variant: 'card',
195
+ color: 'success',
196
+ class: { item: 'has-[[data-state=checked]]:border-success' }
197
+ },
198
+ {
199
+ variant: 'card',
200
+ color: 'warning',
201
+ class: { item: 'has-[[data-state=checked]]:border-warning' }
202
+ },
203
+ {
204
+ variant: 'card',
205
+ color: 'error',
206
+ class: { item: 'has-[[data-state=checked]]:border-error' }
207
+ },
208
+ {
209
+ variant: 'card',
210
+ color: 'info',
211
+ class: { item: 'has-[[data-state=checked]]:border-info' }
212
+ },
213
+ {
214
+ variant: 'card',
215
+ color: 'surface',
216
+ class: { item: 'has-[[data-state=checked]]:border-on-surface' }
217
+ },
218
+ // ========== CARD × DISABLED ==========
219
+ { variant: 'card', disabled: true, class: { item: 'cursor-not-allowed' } }
153
220
  ],
154
221
  defaultVariants: {
155
222
  color: 'primary',
156
223
  size: 'md',
224
+ variant: 'list',
225
+ indicator: 'start',
157
226
  orientation: 'vertical'
158
227
  }
159
228
  });
@@ -22,6 +22,7 @@
22
22
  const icons = getComponentConfig('icons', iconsDefaults)
23
23
 
24
24
  let {
25
+ ref = $bindable(null),
25
26
  value = $bindable(),
26
27
  open = $bindable(false),
27
28
  onOpenChange,
@@ -102,11 +103,13 @@
102
103
  const resolvedName = $derived(name ?? formFieldContext?.name)
103
104
 
104
105
  // ---- ARIA ----
105
- const ariaDescribedBy = $derived.by(() => {
106
- if (!formFieldContext) return undefined
107
- const fid = formFieldContext.ariaId
108
- return hasError ? `${fid}-error` : `${fid}-description ${fid}-help`
109
- })
106
+ const ariaDescribedBy = $derived(
107
+ !formFieldContext
108
+ ? undefined
109
+ : hasError
110
+ ? `${formFieldContext.ariaId}-error`
111
+ : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
112
+ )
110
113
 
111
114
  // ---- Items lookup (O(1) via Map) ----
112
115
  const itemsMap = $derived(
@@ -329,7 +332,7 @@
329
332
  {value}
330
333
  onValueChange={(val) => (value = val)}
331
334
  >
332
- <div class={rootClass}>
335
+ <div bind:this={ref} class={rootClass}>
333
336
  {#if leadingSlot}
334
337
  <span class={leadingClass}>
335
338
  {@render leadingSlot()}
@@ -1,6 +1,6 @@
1
1
  import type { SelectProps } from './select.types.js';
2
2
  export type Props = SelectProps;
3
3
  import { Select } from 'bits-ui';
4
- declare const Select: import("svelte").Component<SelectProps, {}, "value" | "open">;
4
+ declare const Select: import("svelte").Component<SelectProps, {}, "ref" | "value" | "open">;
5
5
  type Select = ReturnType<typeof Select>;
6
6
  export default Select;
@@ -86,6 +86,10 @@ type ContentProps = Pick<SelectContentPropsWithoutHTML, 'side' | 'sideOffset' |
86
86
  * @see https://bits-ui.com/docs/components/select
87
87
  */
88
88
  export interface SelectProps extends RootProps, ContentProps {
89
+ /**
90
+ * Bindable reference to the root DOM element.
91
+ */
92
+ ref?: HTMLElement | null;
89
93
  /**
90
94
  * The currently selected value. Supports two-way binding with `bind:value`.
91
95
  */