sv5ui 1.1.3 → 1.2.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 (155) 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/Chip/Chip.svelte +3 -2
  38. package/dist/Chip/Chip.svelte.d.ts +1 -1
  39. package/dist/Chip/chip.types.d.ts +5 -1
  40. package/dist/Chip/chip.variants.d.ts +135 -45
  41. package/dist/Chip/chip.variants.js +9 -9
  42. package/dist/ContextMenu/ContextMenu.svelte +87 -77
  43. package/dist/ContextMenu/ContextMenu.svelte.d.ts +1 -1
  44. package/dist/ContextMenu/context-menu.types.d.ts +9 -3
  45. package/dist/ContextMenu/context-menu.types.js +1 -1
  46. package/dist/ContextMenu/context-menu.variants.d.ts +74 -160
  47. package/dist/ContextMenu/context-menu.variants.js +63 -95
  48. package/dist/DropdownMenu/DropdownMenu.svelte +37 -43
  49. package/dist/DropdownMenu/DropdownMenu.svelte.d.ts +1 -1
  50. package/dist/DropdownMenu/dropdown-menu.types.d.ts +9 -3
  51. package/dist/DropdownMenu/dropdown-menu.types.js +1 -1
  52. package/dist/DropdownMenu/dropdown-menu.variants.d.ts +79 -230
  53. package/dist/DropdownMenu/dropdown-menu.variants.js +68 -111
  54. package/dist/DropdownMenu/index.d.ts +1 -1
  55. package/dist/Empty/Empty.svelte +68 -33
  56. package/dist/Empty/Empty.svelte.d.ts +1 -1
  57. package/dist/Empty/empty.types.d.ts +26 -9
  58. package/dist/Empty/empty.variants.d.ts +150 -130
  59. package/dist/Empty/empty.variants.js +33 -324
  60. package/dist/FieldGroup/FieldGroup.svelte +11 -6
  61. package/dist/FieldGroup/FieldGroup.svelte.d.ts +1 -1
  62. package/dist/FieldGroup/field-group.types.d.ts +4 -0
  63. package/dist/FormField/FormField.svelte +17 -18
  64. package/dist/FormField/FormField.svelte.d.ts +1 -1
  65. package/dist/FormField/form-field.types.d.ts +4 -0
  66. package/dist/Icon/Icon.svelte +13 -7
  67. package/dist/Icon/icon.types.d.ts +18 -9
  68. package/dist/Input/Input.svelte +30 -29
  69. package/dist/Kbd/Kbd.svelte +13 -3
  70. package/dist/Kbd/Kbd.svelte.d.ts +1 -1
  71. package/dist/Kbd/index.d.ts +1 -1
  72. package/dist/Kbd/kbd.types.d.ts +15 -1
  73. package/dist/Kbd/kbd.variants.d.ts +92 -30
  74. package/dist/Kbd/kbd.variants.js +55 -35
  75. package/dist/Kbd/useKbd.svelte.d.ts +2 -2
  76. package/dist/Kbd/useKbd.svelte.js +34 -41
  77. package/dist/Link/Link.svelte +69 -24
  78. package/dist/Link/Link.svelte.d.ts +1 -1
  79. package/dist/Link/link.types.d.ts +26 -8
  80. package/dist/Link/link.variants.d.ts +35 -60
  81. package/dist/Link/link.variants.js +8 -110
  82. package/dist/Modal/Modal.svelte +9 -1
  83. package/dist/Modal/modal.types.d.ts +5 -0
  84. package/dist/Modal/modal.variants.d.ts +5 -0
  85. package/dist/Modal/modal.variants.js +1 -0
  86. package/dist/Pagination/Pagination.svelte +143 -94
  87. package/dist/Pagination/Pagination.svelte.d.ts +1 -1
  88. package/dist/Pagination/index.d.ts +1 -1
  89. package/dist/Pagination/pagination.types.d.ts +21 -2
  90. package/dist/Pagination/pagination.variants.d.ts +21 -387
  91. package/dist/Pagination/pagination.variants.js +63 -59
  92. package/dist/Popover/Popover.svelte +9 -12
  93. package/dist/Popover/Popover.svelte.d.ts +1 -1
  94. package/dist/Popover/popover.types.d.ts +4 -0
  95. package/dist/Popover/popover.variants.d.ts +5 -75
  96. package/dist/Popover/popover.variants.js +6 -16
  97. package/dist/Progress/Progress.svelte +58 -30
  98. package/dist/Progress/progress.types.d.ts +9 -1
  99. package/dist/Progress/progress.variants.d.ts +55 -25
  100. package/dist/Progress/progress.variants.js +34 -28
  101. package/dist/RadioGroup/RadioGroup.svelte +105 -61
  102. package/dist/RadioGroup/RadioGroup.svelte.d.ts +1 -1
  103. package/dist/RadioGroup/radio-group.types.d.ts +16 -1
  104. package/dist/RadioGroup/radio-group.variants.d.ts +90 -0
  105. package/dist/RadioGroup/radio-group.variants.js +73 -4
  106. package/dist/Select/Select.svelte +9 -6
  107. package/dist/Select/Select.svelte.d.ts +1 -1
  108. package/dist/Select/select.types.d.ts +4 -0
  109. package/dist/SelectMenu/SelectMenu.svelte +436 -0
  110. package/dist/SelectMenu/SelectMenu.svelte.d.ts +5 -0
  111. package/dist/SelectMenu/index.d.ts +2 -0
  112. package/dist/SelectMenu/index.js +1 -0
  113. package/dist/SelectMenu/select-menu.types.d.ts +262 -0
  114. package/dist/SelectMenu/select-menu.types.js +1 -0
  115. package/dist/SelectMenu/select-menu.variants.d.ts +759 -0
  116. package/dist/SelectMenu/select-menu.variants.js +33 -0
  117. package/dist/Separator/Separator.svelte +1 -2
  118. package/dist/Separator/separator.variants.d.ts +1 -5
  119. package/dist/Separator/separator.variants.js +2 -2
  120. package/dist/Skeleton/Skeleton.svelte +18 -2
  121. package/dist/Skeleton/Skeleton.svelte.d.ts +1 -1
  122. package/dist/Skeleton/skeleton.types.d.ts +10 -1
  123. package/dist/Slideover/Slideover.svelte +9 -1
  124. package/dist/Slideover/slideover.types.d.ts +5 -0
  125. package/dist/Slideover/slideover.variants.d.ts +20 -5
  126. package/dist/Slideover/slideover.variants.js +4 -29
  127. package/dist/Switch/Switch.svelte +32 -31
  128. package/dist/Switch/Switch.svelte.d.ts +1 -1
  129. package/dist/Switch/switch.types.d.ts +6 -1
  130. package/dist/Switch/switch.variants.js +6 -6
  131. package/dist/Tabs/Tabs.svelte +6 -9
  132. package/dist/Tabs/Tabs.svelte.d.ts +1 -1
  133. package/dist/Tabs/tabs.types.d.ts +4 -0
  134. package/dist/Tabs/tabs.variants.js +2 -0
  135. package/dist/Textarea/Textarea.svelte +26 -25
  136. package/dist/ThemeModeButton/theme-mode-button.types.d.ts +7 -2
  137. package/dist/Timeline/Timeline.svelte +62 -19
  138. package/dist/Timeline/Timeline.svelte.d.ts +1 -1
  139. package/dist/Timeline/index.d.ts +1 -1
  140. package/dist/Timeline/timeline.types.d.ts +8 -0
  141. package/dist/Tooltip/Tooltip.svelte +12 -10
  142. package/dist/Tooltip/Tooltip.svelte.d.ts +1 -1
  143. package/dist/Tooltip/tooltip.types.d.ts +8 -4
  144. package/dist/Tooltip/tooltip.variants.d.ts +10 -75
  145. package/dist/Tooltip/tooltip.variants.js +8 -17
  146. package/dist/User/User.svelte +13 -9
  147. package/dist/User/User.svelte.d.ts +1 -1
  148. package/dist/User/user.types.d.ts +4 -0
  149. package/dist/User/user.variants.d.ts +60 -0
  150. package/dist/User/user.variants.js +13 -1
  151. package/dist/config.d.ts +4 -0
  152. package/dist/config.js +4 -0
  153. package/dist/index.d.ts +1 -0
  154. package/dist/index.js +1 -0
  155. package/package.json +2 -2
@@ -5,13 +5,13 @@
5
5
  </script>
6
6
 
7
7
  <script lang="ts">
8
- import { Button } from 'bits-ui'
9
8
  import { buttonVariants, buttonDefaults } from './button.variants.js'
10
9
  import { getComponentConfig, iconsDefaults } from '../config.js'
11
10
  import { getContext } from 'svelte'
12
11
  import { fieldGroupVariant } from '../FieldGroup/field-group.variants.js'
13
12
  import Icon from '../Icon/Icon.svelte'
14
13
  import Avatar from '../Avatar/Avatar.svelte'
14
+ import Link from '../Link/Link.svelte'
15
15
  import type { AvatarSize } from '../Avatar/avatar.types.js'
16
16
  import type { FieldGroupVariantProps } from '../FieldGroup/field-group.variants.js'
17
17
 
@@ -26,6 +26,7 @@
26
26
  size,
27
27
  label,
28
28
  loading = false,
29
+ loadingAuto = false,
29
30
  loadingIcon = icons.loading,
30
31
  disabled = false,
31
32
  block = false,
@@ -35,10 +36,20 @@
35
36
  trailingIcon,
36
37
  trailing = false,
37
38
  avatar,
39
+ href,
40
+ type,
41
+ external,
42
+ active,
43
+ exact = false,
44
+ activeColor,
45
+ activeVariant,
46
+ activeClass,
47
+ inactiveClass,
38
48
  leadingSlot,
39
49
  trailingSlot,
40
50
  children,
41
51
  class: className,
52
+ onclick,
42
53
  ...restProps
43
54
  }: Props = $props()
44
55
 
@@ -57,27 +68,34 @@
57
68
  : undefined
58
69
  )
59
70
 
71
+ let autoLoading = $state(false)
72
+ let pendingPromise: Promise<unknown> | null = null
73
+ const isLoading = $derived(loading || autoLoading)
74
+
60
75
  const isIconOnly = $derived(square || (!label && !children))
61
- const isLeading = $derived((!!icon && !trailing) || (loading && !trailing) || !!leadingIcon)
62
- const isTrailing = $derived((!!icon && trailing) || (loading && trailing) || !!trailingIcon)
76
+ const isLeading = $derived((!!icon && !trailing) || (isLoading && !trailing) || !!leadingIcon)
77
+ const isTrailing = $derived((!!icon && trailing) || (isLoading && trailing) || !!trailingIcon)
63
78
 
64
79
  const leadingIconName = $derived(
65
- loading && isLeading
80
+ isLoading && isLeading
66
81
  ? loadingIcon
67
82
  : leadingIcon || (isLeading && !trailing ? icon : undefined)
68
83
  )
69
84
  const trailingIconName = $derived(
70
- loading && isTrailing ? loadingIcon : trailingIcon || (trailing ? icon : undefined)
85
+ isLoading && isTrailing ? loadingIcon : trailingIcon || (trailing ? icon : undefined)
71
86
  )
72
87
 
88
+ const resolvedColor = $derived(active && activeColor ? activeColor : color)
89
+ const resolvedVariant = $derived(active && activeVariant ? activeVariant : variant)
90
+
73
91
  const classes = $derived.by(() => {
74
92
  const slots = buttonVariants({
75
- variant,
76
- color,
93
+ variant: resolvedVariant,
94
+ color: resolvedColor,
77
95
  size: resolvedSize,
78
96
  block,
79
97
  square: isIconOnly,
80
- loading,
98
+ loading: isLoading,
81
99
  leading: isLeading,
82
100
  trailing: isTrailing
83
101
  })
@@ -94,9 +112,48 @@
94
112
  leadingAvatarSize: slots.leadingAvatarSize() as AvatarSize
95
113
  }
96
114
  })
115
+
116
+ function handleClick(e: MouseEvent) {
117
+ if (disabled || isLoading) {
118
+ e.preventDefault()
119
+ e.stopPropagation()
120
+ return
121
+ }
122
+
123
+ if (typeof onclick === 'function') {
124
+ const result = (onclick as (e: MouseEvent) => unknown)(e)
125
+
126
+ if (loadingAuto && result instanceof Promise) {
127
+ autoLoading = true
128
+ pendingPromise = result
129
+ result.then(
130
+ () => {
131
+ if (pendingPromise === result) autoLoading = false
132
+ },
133
+ () => {
134
+ if (pendingPromise === result) autoLoading = false
135
+ }
136
+ )
137
+ }
138
+ }
139
+ }
97
140
  </script>
98
141
 
99
- <Button.Root bind:ref class={classes.base} disabled={disabled || loading} {...restProps}>
142
+ <Link
143
+ {...restProps}
144
+ bind:ref
145
+ {href}
146
+ {type}
147
+ {external}
148
+ {active}
149
+ {exact}
150
+ {activeClass}
151
+ {inactiveClass}
152
+ raw
153
+ disabled={disabled || isLoading}
154
+ class={classes.base}
155
+ onclick={handleClick}
156
+ >
100
157
  {#if leadingSlot}
101
158
  {@render leadingSlot()}
102
159
  {:else if isLeading && leadingIconName}
@@ -105,12 +162,10 @@
105
162
  <Avatar {...avatar} size={classes.leadingAvatarSize} class={classes.leadingAvatar} />
106
163
  {/if}
107
164
 
108
- {#if !isIconOnly}
109
- {#if label}
110
- <span class={classes.label}>{label}</span>
111
- {:else if children}
112
- <span class={classes.label}>{@render children()}</span>
113
- {/if}
165
+ {#if label}
166
+ <span class={classes.label}>{label}</span>
167
+ {:else if children}
168
+ <span class={classes.label}>{@render children()}</span>
114
169
  {/if}
115
170
 
116
171
  {#if trailingSlot}
@@ -118,4 +173,4 @@
118
173
  {:else if isTrailing && trailingIconName}
119
174
  <Icon name={trailingIconName} class={classes.trailingIcon} />
120
175
  {/if}
121
- </Button.Root>
176
+ </Link>
@@ -1,6 +1,5 @@
1
1
  import type { ButtonProps } from './button.types.js';
2
2
  export type Props = ButtonProps;
3
- import { Button } from 'bits-ui';
4
3
  declare const Button: import("svelte").Component<ButtonProps, {}, "ref">;
5
4
  type Button = ReturnType<typeof Button>;
6
5
  export default Button;
@@ -1,9 +1,13 @@
1
1
  import type { Snippet } from 'svelte';
2
- import type { Button } from 'bits-ui';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
4
  import type { ButtonVariantProps, ButtonSlots } from './button.variants.js';
5
5
  import type { AvatarProps } from '../Avatar/avatar.types.js';
6
- export type ButtonProps = Button.RootProps & {
6
+ export type ButtonProps = Omit<HTMLAttributes<HTMLElement>, 'class' | 'color'> & {
7
+ /**
8
+ * Bindable reference to the root DOM element.
9
+ */
10
+ ref?: HTMLElement | null;
7
11
  /**
8
12
  * Controls the visual style of the button.
9
13
  * @default 'solid'
@@ -29,12 +33,22 @@ export type ButtonProps = Button.RootProps & {
29
33
  * @default false
30
34
  */
31
35
  loading?: boolean;
36
+ /**
37
+ * Automatically shows loading state while the onclick handler's Promise is pending.
38
+ * @default false
39
+ */
40
+ loadingAuto?: boolean;
32
41
  /**
33
42
  * Icon displayed as the loading indicator.
34
43
  * Supports any valid Iconify icon name.
35
44
  * @default Uses `icons.loading` from app config
36
45
  */
37
46
  loadingIcon?: string;
47
+ /**
48
+ * Disables the button and prevents interaction.
49
+ * @default false
50
+ */
51
+ disabled?: boolean;
38
52
  /**
39
53
  * Stretches the button to fill the full width of its container.
40
54
  * @default false
@@ -71,6 +85,47 @@ export type ButtonProps = Button.RootProps & {
71
85
  * Takes precedence over `leadingIcon`.
72
86
  */
73
87
  avatar?: AvatarProps;
88
+ /**
89
+ * The destination URL. When provided, renders as an anchor element.
90
+ */
91
+ href?: string;
92
+ /**
93
+ * The button type attribute. Only applies when rendering as `<button>`.
94
+ * @default 'button'
95
+ */
96
+ type?: 'button' | 'submit' | 'reset';
97
+ /**
98
+ * Treats the link as external, adding `rel="noopener noreferrer"` and `target="_blank"`.
99
+ * Auto-detected from the `href` when omitted.
100
+ */
101
+ external?: boolean;
102
+ /**
103
+ * Overrides the auto-detected active state.
104
+ */
105
+ active?: boolean;
106
+ /**
107
+ * Requires an exact pathname match for active state detection.
108
+ * @default false
109
+ */
110
+ exact?: boolean;
111
+ /**
112
+ * Color scheme applied when the button is active.
113
+ * Falls back to the `color` prop when omitted.
114
+ */
115
+ activeColor?: NonNullable<ButtonVariantProps['color']>;
116
+ /**
117
+ * Visual style applied when the button is active.
118
+ * Falls back to the `variant` prop when omitted.
119
+ */
120
+ activeVariant?: NonNullable<ButtonVariantProps['variant']>;
121
+ /**
122
+ * Additional CSS class applied when the button link is active.
123
+ */
124
+ activeClass?: string;
125
+ /**
126
+ * Additional CSS class applied when the button link is inactive.
127
+ */
128
+ inactiveClass?: string;
74
129
  /**
75
130
  * Custom content rendered before the label.
76
131
  * Takes precedence over `avatar` and `leadingIcon`.
@@ -81,6 +136,10 @@ export type ButtonProps = Button.RootProps & {
81
136
  * Takes precedence over `trailingIcon`.
82
137
  */
83
138
  trailingSlot?: Snippet;
139
+ /**
140
+ * Custom content for the button label area.
141
+ */
142
+ children?: Snippet;
84
143
  /**
85
144
  * Additional CSS classes for the root element.
86
145
  */
@@ -20,6 +20,7 @@
20
20
  const config = getComponentConfig('calendar', calendarDefaults)
21
21
 
22
22
  let {
23
+ ref = $bindable(null),
23
24
  value = $bindable(),
24
25
  onValueChange,
25
26
  placeholder = $bindable(),
@@ -245,6 +246,7 @@
245
246
  | 'weekNumbers'
246
247
  >}
247
248
  <RangeCalendar.Root
249
+ bind:ref
248
250
  bind:value={value as CalendarRangeProps['value']}
249
251
  onValueChange={onValueChange as CalendarRangeProps['onValueChange']}
250
252
  {...commonProps}
@@ -264,6 +266,7 @@
264
266
  {@const calInitialFocus = (restProps as { initialFocus?: boolean }).initialFocus}
265
267
  {#if calType === 'multiple'}
266
268
  <Calendar.Root
269
+ bind:ref
267
270
  bind:value={value as CalendarMultipleProps['value']}
268
271
  onValueChange={onValueChange as CalendarMultipleProps['onValueChange']}
269
272
  {...commonProps}
@@ -277,6 +280,7 @@
277
280
  </Calendar.Root>
278
281
  {:else}
279
282
  <Calendar.Root
283
+ bind:ref
280
284
  bind:value={value as CalendarSingleProps['value']}
281
285
  onValueChange={onValueChange as CalendarSingleProps['onValueChange']}
282
286
  {...commonProps}
@@ -1,6 +1,6 @@
1
1
  import type { CalendarProps } from './calendar.types.js';
2
2
  export type Props = CalendarProps;
3
3
  import { Calendar } from 'bits-ui';
4
- declare const Calendar: import("svelte").Component<CalendarProps, {}, "placeholder" | "value">;
4
+ declare const Calendar: import("svelte").Component<CalendarProps, {}, "placeholder" | "ref" | "value">;
5
5
  type Calendar = ReturnType<typeof Calendar>;
6
6
  export default Calendar;
@@ -44,6 +44,10 @@ type SharedCalendarRootProps = {
44
44
  disableDaysOutsideMonth?: boolean;
45
45
  };
46
46
  type BaseCalendarProps = {
47
+ /**
48
+ * Bindable reference to the root DOM element.
49
+ */
50
+ ref?: HTMLElement | null;
47
51
  /** @default 'lucide:chevron-left' */
48
52
  prevMonthIcon?: string;
49
53
  /** @default 'lucide:chevron-right' */
@@ -11,6 +11,7 @@
11
11
  const config = getComponentConfig('card', cardDefaults)
12
12
 
13
13
  let {
14
+ ref = $bindable(null),
14
15
  as = 'div',
15
16
  ui,
16
17
  variant = config.defaultVariants.variant,
@@ -25,14 +26,14 @@
25
26
  const slots = cardVariants({ variant })
26
27
  return {
27
28
  root: slots.root({ class: [config.slots.root, className, ui?.root] }),
28
- header: header ? slots.header({ class: [config.slots.header, ui?.header] }) : '',
29
- body: children ? slots.body({ class: [config.slots.body, ui?.body] }) : '',
30
- footer: footer ? slots.footer({ class: [config.slots.footer, ui?.footer] }) : ''
29
+ header: slots.header({ class: [config.slots.header, ui?.header] }),
30
+ body: slots.body({ class: [config.slots.body, ui?.body] }),
31
+ footer: slots.footer({ class: [config.slots.footer, ui?.footer] })
31
32
  }
32
33
  })
33
34
  </script>
34
35
 
35
- <svelte:element this={as} class={classes.root} {...restProps}>
36
+ <svelte:element this={as} bind:this={ref} class={classes.root} {...restProps}>
36
37
  {#if header}
37
38
  <div class={classes.header}>
38
39
  {@render header()}
@@ -1,5 +1,5 @@
1
1
  import type { CardProps } from './card.types.js';
2
2
  export type Props = CardProps;
3
- declare const Card: import("svelte").Component<CardProps, {}, "">;
3
+ declare const Card: import("svelte").Component<CardProps, {}, "ref">;
4
4
  type Card = ReturnType<typeof Card>;
5
5
  export default Card;
@@ -2,7 +2,11 @@ import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
4
  import type { CardVariantProps, CardSlots } from './card.variants.js';
5
- export type CardProps = HTMLAttributes<HTMLDivElement> & {
5
+ export type CardProps = Omit<HTMLAttributes<HTMLDivElement>, 'class'> & {
6
+ /**
7
+ * Bindable reference to the root DOM element.
8
+ */
9
+ ref?: HTMLElement | null;
6
10
  /**
7
11
  * Renders the card as a different HTML element.
8
12
  * @default 'div'
@@ -16,6 +16,7 @@
16
16
  const icons = getComponentConfig('icons', iconsDefaults)
17
17
 
18
18
  let {
19
+ ref = $bindable(null),
19
20
  checked = $bindable(false),
20
21
  onCheckedChange,
21
22
  indeterminate = $bindable(false),
@@ -26,6 +27,8 @@
26
27
  value,
27
28
  color = config.defaultVariants.color,
28
29
  size,
30
+ variant = config.defaultVariants.variant,
31
+ indicator = config.defaultVariants.indicator,
29
32
  disabled = false,
30
33
  required = false,
31
34
  loading = false,
@@ -36,7 +39,8 @@
36
39
  description,
37
40
  labelSlot,
38
41
  descriptionSlot,
39
- class: className
42
+ class: className,
43
+ ...restProps
40
44
  }: Props = $props()
41
45
 
42
46
  const formFieldContext = getContext<
@@ -59,18 +63,31 @@
59
63
  const resolvedName = $derived(name ?? formFieldContext?.name)
60
64
  const isDisabled = $derived(disabled || loading)
61
65
 
62
- const ariaDescribedBy = $derived.by(() => {
63
- if (!formFieldContext) return undefined
64
- const fid = formFieldContext.ariaId
65
- return hasError ? `${fid}-error` : `${fid}-description ${fid}-help`
66
- })
66
+ const ariaDescribedBy = $derived(
67
+ !formFieldContext
68
+ ? undefined
69
+ : hasError
70
+ ? `${formFieldContext.ariaId}-error`
71
+ : `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
72
+ )
67
73
 
68
74
  const resolvedIcon = $derived(loading ? loadingIcon : indeterminate ? indeterminateIcon : icon)
69
75
 
76
+ let containerRef: HTMLElement | null = null
77
+
78
+ function handleCardClick(e: MouseEvent) {
79
+ if (isDisabled) return
80
+ // Don't re-click when the event originated from the checkbox button itself
81
+ if ((e.target as Element).closest('button')) return
82
+ containerRef?.querySelector('button')?.click()
83
+ }
84
+
70
85
  const classes = $derived.by(() => {
71
86
  const slots = checkboxVariants({
72
87
  color: resolvedColor,
73
88
  size: resolvedSize,
89
+ variant,
90
+ indicator,
74
91
  loading,
75
92
  required,
76
93
  disabled: isDisabled ? true : undefined
@@ -90,8 +107,13 @@
90
107
  })
91
108
  </script>
92
109
 
93
- <div class={classes.root}>
94
- <div class={classes.container}>
110
+ <div
111
+ {...restProps}
112
+ bind:this={ref}
113
+ class={classes.root}
114
+ onclick={variant === 'card' ? handleCardClick : undefined}
115
+ >
116
+ <div bind:this={containerRef} class={classes.container}>
95
117
  <Checkbox.Root
96
118
  bind:checked
97
119
  {onCheckedChange}
@@ -123,9 +145,13 @@
123
145
  {#if labelSlot}
124
146
  {@render labelSlot({ label })}
125
147
  {:else if label}
126
- <Label.Root for={resolvedId} class={classes.label}>
127
- {label}
128
- </Label.Root>
148
+ {#if variant === 'card'}
149
+ <span class={classes.label}>{label}</span>
150
+ {:else}
151
+ <Label.Root for={resolvedId} class={classes.label}>
152
+ {label}
153
+ </Label.Root>
154
+ {/if}
129
155
  {/if}
130
156
 
131
157
  {#if descriptionSlot}
@@ -1,6 +1,6 @@
1
1
  import type { CheckboxProps } from './checkbox.types.js';
2
2
  export type Props = CheckboxProps;
3
3
  import { Checkbox } from 'bits-ui';
4
- declare const Checkbox: import("svelte").Component<CheckboxProps, {}, "indeterminate" | "checked">;
4
+ declare const Checkbox: import("svelte").Component<CheckboxProps, {}, "ref" | "indeterminate" | "checked">;
5
5
  type Checkbox = ReturnType<typeof Checkbox>;
6
6
  export default Checkbox;
@@ -1,8 +1,13 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { Checkbox as CheckboxPrimitive } from 'bits-ui';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
+ import type { HTMLAttributes } from 'svelte/elements';
4
5
  import type { CheckboxVariantProps, CheckboxSlots } from './checkbox.variants.js';
5
- export type CheckboxProps = Pick<CheckboxPrimitive.RootProps, 'disabled' | 'name' | 'value' | 'required'> & {
6
+ export type CheckboxProps = Pick<CheckboxPrimitive.RootProps, 'disabled' | 'name' | 'value' | 'required'> & Omit<HTMLAttributes<HTMLElement>, 'class'> & {
7
+ /**
8
+ * Bindable reference to the root DOM element.
9
+ */
10
+ ref?: HTMLElement | null;
6
11
  /**
7
12
  * The checked state of the checkbox. Supports two-way binding with `bind:checked`.
8
13
  * @default false
@@ -31,6 +36,16 @@ export type CheckboxProps = Pick<CheckboxPrimitive.RootProps, 'disabled' | 'name
31
36
  * @default 'md'
32
37
  */
33
38
  size?: NonNullable<CheckboxVariantProps['size']>;
39
+ /**
40
+ * Controls the visual style of the checkbox.
41
+ * @default 'list'
42
+ */
43
+ variant?: NonNullable<CheckboxVariantProps['variant']>;
44
+ /**
45
+ * Controls the position of the checkbox indicator.
46
+ * @default 'start'
47
+ */
48
+ indicator?: NonNullable<CheckboxVariantProps['indicator']>;
34
49
  /**
35
50
  * Renders a loading spinner inside the checkbox.
36
51
  * @default false
@@ -42,6 +42,24 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
42
42
  wrapper: string;
43
43
  };
44
44
  };
45
+ variant: {
46
+ list: string;
47
+ card: {
48
+ root: string;
49
+ };
50
+ };
51
+ indicator: {
52
+ start: {
53
+ wrapper: string;
54
+ };
55
+ end: {
56
+ root: string;
57
+ wrapper: string;
58
+ };
59
+ hidden: {
60
+ container: string;
61
+ };
62
+ };
45
63
  loading: {
46
64
  true: {
47
65
  icon: string;
@@ -112,6 +130,24 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
112
130
  wrapper: string;
113
131
  };
114
132
  };
133
+ variant: {
134
+ list: string;
135
+ card: {
136
+ root: string;
137
+ };
138
+ };
139
+ indicator: {
140
+ start: {
141
+ wrapper: string;
142
+ };
143
+ end: {
144
+ root: string;
145
+ wrapper: string;
146
+ };
147
+ hidden: {
148
+ container: string;
149
+ };
150
+ };
115
151
  loading: {
116
152
  true: {
117
153
  icon: string;
@@ -182,6 +218,24 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
182
218
  wrapper: string;
183
219
  };
184
220
  };
221
+ variant: {
222
+ list: string;
223
+ card: {
224
+ root: string;
225
+ };
226
+ };
227
+ indicator: {
228
+ start: {
229
+ wrapper: string;
230
+ };
231
+ end: {
232
+ root: string;
233
+ wrapper: string;
234
+ };
235
+ hidden: {
236
+ container: string;
237
+ };
238
+ };
185
239
  loading: {
186
240
  true: {
187
241
  icon: string;
@@ -256,6 +310,24 @@ export declare const checkboxDefaults: {
256
310
  wrapper: string;
257
311
  };
258
312
  };
313
+ variant: {
314
+ list: string;
315
+ card: {
316
+ root: string;
317
+ };
318
+ };
319
+ indicator: {
320
+ start: {
321
+ wrapper: string;
322
+ };
323
+ end: {
324
+ root: string;
325
+ wrapper: string;
326
+ };
327
+ hidden: {
328
+ container: string;
329
+ };
330
+ };
259
331
  loading: {
260
332
  true: {
261
333
  icon: string;
@@ -326,6 +398,24 @@ export declare const checkboxDefaults: {
326
398
  wrapper: string;
327
399
  };
328
400
  };
401
+ variant: {
402
+ list: string;
403
+ card: {
404
+ root: string;
405
+ };
406
+ };
407
+ indicator: {
408
+ start: {
409
+ wrapper: string;
410
+ };
411
+ end: {
412
+ root: string;
413
+ wrapper: string;
414
+ };
415
+ hidden: {
416
+ container: string;
417
+ };
418
+ };
329
419
  loading: {
330
420
  true: {
331
421
  icon: string;