@sveltier/ui 0.0.0-stage → 0.1.0-alpha.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 (276) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -2
  3. package/dist/components/Alert/Alert.svelte +88 -0
  4. package/dist/components/Alert/Alert.svelte.d.ts +4 -0
  5. package/dist/components/Alert/alert.css +78 -0
  6. package/dist/components/Alert/index.d.ts +2 -0
  7. package/dist/components/Alert/index.js +1 -0
  8. package/dist/components/Alert/types.d.ts +67 -0
  9. package/dist/components/Alert/types.js +1 -0
  10. package/dist/components/Avatar/Avatar.svelte +47 -0
  11. package/dist/components/Avatar/Avatar.svelte.d.ts +4 -0
  12. package/dist/components/Avatar/avatar.css +34 -0
  13. package/dist/components/Avatar/index.d.ts +2 -0
  14. package/dist/components/Avatar/index.js +1 -0
  15. package/dist/components/Avatar/types.d.ts +47 -0
  16. package/dist/components/Avatar/types.js +1 -0
  17. package/dist/components/Badge/Badge.svelte +53 -0
  18. package/dist/components/Badge/Badge.svelte.d.ts +4 -0
  19. package/dist/components/Badge/badge.css +57 -0
  20. package/dist/components/Badge/index.d.ts +2 -0
  21. package/dist/components/Badge/index.js +1 -0
  22. package/dist/components/Badge/types.d.ts +43 -0
  23. package/dist/components/Badge/types.js +1 -0
  24. package/dist/components/Button/Button.svelte +85 -0
  25. package/dist/components/Button/Button.svelte.d.ts +4 -0
  26. package/dist/components/Button/button.css +132 -0
  27. package/dist/components/Button/index.d.ts +2 -0
  28. package/dist/components/Button/index.js +1 -0
  29. package/dist/components/Button/types.d.ts +76 -0
  30. package/dist/components/Button/types.js +1 -0
  31. package/dist/components/ButtonGroup/ButtonGroup.svelte +61 -0
  32. package/dist/components/ButtonGroup/ButtonGroup.svelte.d.ts +4 -0
  33. package/dist/components/ButtonGroup/button-group.css +39 -0
  34. package/dist/components/ButtonGroup/index.d.ts +2 -0
  35. package/dist/components/ButtonGroup/index.js +1 -0
  36. package/dist/components/ButtonGroup/types.d.ts +48 -0
  37. package/dist/components/ButtonGroup/types.js +1 -0
  38. package/dist/components/Card/Card.svelte +53 -0
  39. package/dist/components/Card/Card.svelte.d.ts +4 -0
  40. package/dist/components/Card/card.css +62 -0
  41. package/dist/components/Card/index.d.ts +2 -0
  42. package/dist/components/Card/index.js +1 -0
  43. package/dist/components/Card/types.d.ts +56 -0
  44. package/dist/components/Card/types.js +1 -0
  45. package/dist/components/Checkbox/Checkbox.svelte +105 -0
  46. package/dist/components/Checkbox/Checkbox.svelte.d.ts +4 -0
  47. package/dist/components/Checkbox/checkbox.css +138 -0
  48. package/dist/components/Checkbox/index.d.ts +2 -0
  49. package/dist/components/Checkbox/index.js +1 -0
  50. package/dist/components/Checkbox/types.d.ts +76 -0
  51. package/dist/components/Checkbox/types.js +1 -0
  52. package/dist/components/Chip/Chip.svelte +109 -0
  53. package/dist/components/Chip/Chip.svelte.d.ts +4 -0
  54. package/dist/components/Chip/chip.css +101 -0
  55. package/dist/components/Chip/index.d.ts +2 -0
  56. package/dist/components/Chip/index.js +1 -0
  57. package/dist/components/Chip/types.d.ts +69 -0
  58. package/dist/components/Chip/types.js +1 -0
  59. package/dist/components/Choice/Choice.svelte +60 -0
  60. package/dist/components/Choice/Choice.svelte.d.ts +4 -0
  61. package/dist/components/Choice/choice.css +75 -0
  62. package/dist/components/Choice/types.d.ts +43 -0
  63. package/dist/components/Choice/types.js +1 -0
  64. package/dist/components/Divider/Divider.svelte +19 -0
  65. package/dist/components/Divider/Divider.svelte.d.ts +4 -0
  66. package/dist/components/Divider/divider.css +23 -0
  67. package/dist/components/Divider/index.d.ts +2 -0
  68. package/dist/components/Divider/index.js +1 -0
  69. package/dist/components/Divider/types.d.ts +10 -0
  70. package/dist/components/Divider/types.js +1 -0
  71. package/dist/components/Field/Field.svelte +95 -0
  72. package/dist/components/Field/Field.svelte.d.ts +4 -0
  73. package/dist/components/Field/field.css +210 -0
  74. package/dist/components/Field/index.d.ts +3 -0
  75. package/dist/components/Field/index.js +2 -0
  76. package/dist/components/Field/types.d.ts +109 -0
  77. package/dist/components/Field/types.js +2 -0
  78. package/dist/components/Form/Form.svelte +93 -0
  79. package/dist/components/Form/Form.svelte.d.ts +8 -0
  80. package/dist/components/Form/form.css +16 -0
  81. package/dist/components/Form/index.d.ts +2 -0
  82. package/dist/components/Form/index.js +1 -0
  83. package/dist/components/Form/types.d.ts +38 -0
  84. package/dist/components/Form/types.js +1 -0
  85. package/dist/components/Icon/Icon.svelte +38 -0
  86. package/dist/components/Icon/Icon.svelte.d.ts +4 -0
  87. package/dist/components/Icon/icon.css +33 -0
  88. package/dist/components/Icon/index.d.ts +2 -0
  89. package/dist/components/Icon/index.js +1 -0
  90. package/dist/components/Icon/types.d.ts +34 -0
  91. package/dist/components/Icon/types.js +1 -0
  92. package/dist/components/List/List.svelte +39 -0
  93. package/dist/components/List/List.svelte.d.ts +4 -0
  94. package/dist/components/List/ListItem.svelte +57 -0
  95. package/dist/components/List/ListItem.svelte.d.ts +4 -0
  96. package/dist/components/List/index.d.ts +3 -0
  97. package/dist/components/List/index.js +2 -0
  98. package/dist/components/List/list.css +127 -0
  99. package/dist/components/List/types.d.ts +67 -0
  100. package/dist/components/List/types.js +1 -0
  101. package/dist/components/NativeSelect/NativeSelect.svelte +110 -0
  102. package/dist/components/NativeSelect/NativeSelect.svelte.d.ts +25 -0
  103. package/dist/components/NativeSelect/index.d.ts +2 -0
  104. package/dist/components/NativeSelect/index.js +1 -0
  105. package/dist/components/NativeSelect/native-select.css +45 -0
  106. package/dist/components/NativeSelect/types.d.ts +58 -0
  107. package/dist/components/NativeSelect/types.js +1 -0
  108. package/dist/components/NumberField/NumberField.svelte +246 -0
  109. package/dist/components/NumberField/NumberField.svelte.d.ts +4 -0
  110. package/dist/components/NumberField/index.d.ts +2 -0
  111. package/dist/components/NumberField/index.js +1 -0
  112. package/dist/components/NumberField/number-field.css +74 -0
  113. package/dist/components/NumberField/types.d.ts +73 -0
  114. package/dist/components/NumberField/types.js +1 -0
  115. package/dist/components/Progress/ProgressCircular.svelte +61 -0
  116. package/dist/components/Progress/ProgressCircular.svelte.d.ts +4 -0
  117. package/dist/components/Progress/ProgressLinear.svelte +44 -0
  118. package/dist/components/Progress/ProgressLinear.svelte.d.ts +4 -0
  119. package/dist/components/Progress/index.d.ts +3 -0
  120. package/dist/components/Progress/index.js +2 -0
  121. package/dist/components/Progress/progress-circular.css +61 -0
  122. package/dist/components/Progress/progress-linear.css +67 -0
  123. package/dist/components/Progress/types.d.ts +53 -0
  124. package/dist/components/Progress/types.js +1 -0
  125. package/dist/components/RadioGroup/RadioGroup.svelte +149 -0
  126. package/dist/components/RadioGroup/RadioGroup.svelte.d.ts +25 -0
  127. package/dist/components/RadioGroup/index.d.ts +2 -0
  128. package/dist/components/RadioGroup/index.js +1 -0
  129. package/dist/components/RadioGroup/radio-group.css +139 -0
  130. package/dist/components/RadioGroup/types.d.ts +93 -0
  131. package/dist/components/RadioGroup/types.js +1 -0
  132. package/dist/components/SegmentedControl/SegmentedControl.svelte +70 -0
  133. package/dist/components/SegmentedControl/SegmentedControl.svelte.d.ts +25 -0
  134. package/dist/components/SegmentedControl/index.d.ts +2 -0
  135. package/dist/components/SegmentedControl/index.js +1 -0
  136. package/dist/components/SegmentedControl/segmented-control.css +68 -0
  137. package/dist/components/SegmentedControl/types.d.ts +60 -0
  138. package/dist/components/SegmentedControl/types.js +1 -0
  139. package/dist/components/Skeleton/Skeleton.svelte +33 -0
  140. package/dist/components/Skeleton/Skeleton.svelte.d.ts +4 -0
  141. package/dist/components/Skeleton/index.d.ts +2 -0
  142. package/dist/components/Skeleton/index.js +1 -0
  143. package/dist/components/Skeleton/skeleton.css +70 -0
  144. package/dist/components/Skeleton/types.d.ts +25 -0
  145. package/dist/components/Skeleton/types.js +1 -0
  146. package/dist/components/Slider/Slider.svelte +153 -0
  147. package/dist/components/Slider/Slider.svelte.d.ts +4 -0
  148. package/dist/components/Slider/index.d.ts +2 -0
  149. package/dist/components/Slider/index.js +1 -0
  150. package/dist/components/Slider/slider.css +206 -0
  151. package/dist/components/Slider/types.d.ts +102 -0
  152. package/dist/components/Slider/types.js +1 -0
  153. package/dist/components/Switch/Switch.svelte +94 -0
  154. package/dist/components/Switch/Switch.svelte.d.ts +4 -0
  155. package/dist/components/Switch/index.d.ts +2 -0
  156. package/dist/components/Switch/index.js +1 -0
  157. package/dist/components/Switch/switch.css +118 -0
  158. package/dist/components/Switch/types.d.ts +67 -0
  159. package/dist/components/Switch/types.js +1 -0
  160. package/dist/components/Tabs/Tabs.svelte +93 -0
  161. package/dist/components/Tabs/Tabs.svelte.d.ts +25 -0
  162. package/dist/components/Tabs/index.d.ts +2 -0
  163. package/dist/components/Tabs/index.js +1 -0
  164. package/dist/components/Tabs/tabs.css +73 -0
  165. package/dist/components/Tabs/types.d.ts +59 -0
  166. package/dist/components/Tabs/types.js +1 -0
  167. package/dist/components/TextField/TextField.svelte +115 -0
  168. package/dist/components/TextField/TextField.svelte.d.ts +4 -0
  169. package/dist/components/TextField/index.d.ts +2 -0
  170. package/dist/components/TextField/index.js +1 -0
  171. package/dist/components/TextField/types.d.ts +57 -0
  172. package/dist/components/TextField/types.js +1 -0
  173. package/dist/components/Textarea/Textarea.svelte +116 -0
  174. package/dist/components/Textarea/Textarea.svelte.d.ts +4 -0
  175. package/dist/components/Textarea/index.d.ts +2 -0
  176. package/dist/components/Textarea/index.js +1 -0
  177. package/dist/components/Textarea/textarea.css +35 -0
  178. package/dist/components/Textarea/types.d.ts +60 -0
  179. package/dist/components/Textarea/types.js +1 -0
  180. package/dist/core/defaults/DefaultsProvider.svelte +30 -0
  181. package/dist/core/defaults/DefaultsProvider.svelte.d.ts +13 -0
  182. package/dist/core/defaults/context.d.ts +45 -0
  183. package/dist/core/defaults/context.js +38 -0
  184. package/dist/core/display/display.d.ts +39 -0
  185. package/dist/core/display/display.js +53 -0
  186. package/dist/core/errors/codes.d.ts +112 -0
  187. package/dist/core/errors/codes.js +96 -0
  188. package/dist/core/errors/errors.d.ts +8 -0
  189. package/dist/core/errors/errors.js +7 -0
  190. package/dist/core/form/constraints.d.ts +15 -0
  191. package/dist/core/form/constraints.js +42 -0
  192. package/dist/core/form/context.d.ts +19 -0
  193. package/dist/core/form/context.js +4 -0
  194. package/dist/core/form/field.svelte.d.ts +34 -0
  195. package/dist/core/form/field.svelte.js +66 -0
  196. package/dist/core/form/number.d.ts +24 -0
  197. package/dist/core/form/number.js +71 -0
  198. package/dist/core/form/types.d.ts +22 -0
  199. package/dist/core/form/types.js +1 -0
  200. package/dist/core/locale/locale.d.ts +55 -0
  201. package/dist/core/locale/locale.js +80 -0
  202. package/dist/core/props/classes.d.ts +21 -0
  203. package/dist/core/props/classes.js +44 -0
  204. package/dist/core/props/element.d.ts +18 -0
  205. package/dist/core/props/element.js +1 -0
  206. package/dist/core/props/types.d.ts +47 -0
  207. package/dist/core/props/types.js +16 -0
  208. package/dist/core/provider/UIProvider.svelte +60 -0
  209. package/dist/core/provider/UIProvider.svelte.d.ts +29 -0
  210. package/dist/core/theme/ThemeProvider.svelte +178 -0
  211. package/dist/core/theme/ThemeProvider.svelte.d.ts +25 -0
  212. package/dist/core/theme/color.d.ts +23 -0
  213. package/dist/core/theme/color.js +54 -0
  214. package/dist/core/theme/context.d.ts +25 -0
  215. package/dist/core/theme/context.js +14 -0
  216. package/dist/core/theme/css.d.ts +25 -0
  217. package/dist/core/theme/css.js +69 -0
  218. package/dist/core/theme/define.d.ts +11 -0
  219. package/dist/core/theme/define.js +21 -0
  220. package/dist/core/theme/resolve.d.ts +6 -0
  221. package/dist/core/theme/resolve.js +18 -0
  222. package/dist/core/theme/theme-provider.css +13 -0
  223. package/dist/core/theme/types.d.ts +35 -0
  224. package/dist/core/theme/types.js +61 -0
  225. package/dist/dev/off.d.ts +4 -0
  226. package/dist/dev/off.js +3 -0
  227. package/dist/dev/on.d.ts +8 -0
  228. package/dist/dev/on.js +33 -0
  229. package/dist/index.d.ts +58 -0
  230. package/dist/index.js +72 -0
  231. package/dist/primitives/anchored/anchored.d.ts +39 -0
  232. package/dist/primitives/anchored/anchored.js +104 -0
  233. package/dist/primitives/anchored/fallback.d.ts +31 -0
  234. package/dist/primitives/anchored/fallback.js +73 -0
  235. package/dist/primitives/focus/focus-trap.d.ts +25 -0
  236. package/dist/primitives/focus/focus-trap.js +86 -0
  237. package/dist/primitives/focus/roving-focus.d.ts +22 -0
  238. package/dist/primitives/focus/roving-focus.js +86 -0
  239. package/dist/primitives/focus/tabbable.d.ts +9 -0
  240. package/dist/primitives/focus/tabbable.js +75 -0
  241. package/dist/primitives/inert/inert-others.d.ts +12 -0
  242. package/dist/primitives/inert/inert-others.js +44 -0
  243. package/dist/primitives/keyboard/keymap.d.ts +17 -0
  244. package/dist/primitives/keyboard/keymap.js +39 -0
  245. package/dist/primitives/keyboard/typeahead.d.ts +18 -0
  246. package/dist/primitives/keyboard/typeahead.js +50 -0
  247. package/dist/primitives/layer/dismissable.d.ts +26 -0
  248. package/dist/primitives/layer/dismissable.js +84 -0
  249. package/dist/primitives/motion/easing.d.ts +9 -0
  250. package/dist/primitives/motion/easing.js +46 -0
  251. package/dist/primitives/motion/motion.d.ts +59 -0
  252. package/dist/primitives/motion/motion.js +80 -0
  253. package/dist/primitives/portal/Portal.svelte +37 -0
  254. package/dist/primitives/portal/Portal.svelte.d.ts +9 -0
  255. package/dist/primitives/portal/PortalContent.svelte +15 -0
  256. package/dist/primitives/portal/PortalContent.svelte.d.ts +9 -0
  257. package/dist/primitives/portal/portal.css +8 -0
  258. package/dist/primitives/scroll-lock/scroll-lock.d.ts +10 -0
  259. package/dist/primitives/scroll-lock/scroll-lock.js +33 -0
  260. package/dist/primitives/virtual/virtual-list.svelte.d.ts +65 -0
  261. package/dist/primitives/virtual/virtual-list.svelte.js +291 -0
  262. package/dist/styles/base.css +44 -0
  263. package/dist/styles/props.css +137 -0
  264. package/dist/styles/tokens.css +84 -0
  265. package/dist/styles/visually-hidden.css +16 -0
  266. package/dist/themes/aurora.d.ts +13 -0
  267. package/dist/themes/aurora.js +103 -0
  268. package/dist/themes/heritage.d.ts +13 -0
  269. package/dist/themes/heritage.js +102 -0
  270. package/dist/themes/maison.d.ts +13 -0
  271. package/dist/themes/maison.js +99 -0
  272. package/dist/themes/milano.d.ts +13 -0
  273. package/dist/themes/milano.js +101 -0
  274. package/dist/themes/monolith.d.ts +13 -0
  275. package/dist/themes/monolith.js +101 -0
  276. package/package.json +87 -5
@@ -0,0 +1,105 @@
1
+ <script lang="ts">
2
+ // A box that is checked or not, with its label beside it and validation. See CheckboxProps.
3
+ import { untrack } from 'svelte';
4
+ import { DEV, warnUnnamed } from '#dev';
5
+ import { useDefaults } from '../../core/defaults/context.js';
6
+ import { createField } from '../../core/form/field.svelte.js';
7
+ import { useLocale } from '../../core/locale/locale.js';
8
+ import { sharedClasses } from '../../core/props/classes.js';
9
+ import Choice from '../Choice/Choice.svelte';
10
+ import './checkbox.css';
11
+ import type { CheckboxDefaults, CheckboxProps } from './types.js';
12
+
13
+ let {
14
+ color,
15
+ size,
16
+ density,
17
+ disabled,
18
+ checked = $bindable(false),
19
+ indeterminate = $bindable(false),
20
+ label,
21
+ hint,
22
+ error,
23
+ rules,
24
+ validateOn,
25
+ required = false,
26
+ id,
27
+ 'aria-describedby': describedBy,
28
+ class: className,
29
+ style,
30
+ ref = $bindable(null),
31
+ ...rest
32
+ }: CheckboxProps = $props();
33
+
34
+ const resolve = useDefaults<CheckboxDefaults>('Checkbox', {
35
+ color: 'primary',
36
+ size: 'md',
37
+ density: 'default',
38
+ disabled: false
39
+ });
40
+ const p = $derived(resolve({ color, size, density, disabled }));
41
+ const locale = useLocale();
42
+ // A form reset goes back to the state the box started in, as it does for a form rendered on
43
+ // the server.
44
+ const initial = untrack(() => checked ?? false);
45
+
46
+ const field = createField<boolean>({
47
+ value: () => checked ?? false,
48
+ // Rules run on a checked box only, as they run on a filled field only.
49
+ empty: (on) => !on,
50
+ check: (on) => (!on && required ? locale.t('required') : undefined),
51
+ rules: () => rules,
52
+ error: () => error,
53
+ validateOn: () => validateOn,
54
+ control: () => ref
55
+ });
56
+
57
+ if (DEV) $effect(() => warnUnnamed('Checkbox', ref));
58
+
59
+ // A toggle is a whole edit, so it also counts as leaving: the message shows at once, even in
60
+ // Safari, where a click does not focus the checkbox.
61
+ function toggled() {
62
+ field.changed();
63
+ field.left();
64
+ }
65
+ </script>
66
+
67
+ <Choice
68
+ {id}
69
+ {label}
70
+ {hint}
71
+ error={field.error}
72
+ {required}
73
+ disabled={p.disabled}
74
+ class={[
75
+ 'sv-checkbox',
76
+ sharedClasses(p, 'Checkbox'),
77
+ indeterminate && 'sv-checkbox--indeterminate',
78
+ className
79
+ ]}
80
+ {style}
81
+ onchange={toggled}
82
+ >
83
+ {#snippet children(attributes)}
84
+ <span class="sv-checkbox__control">
85
+ <input
86
+ bind:this={ref}
87
+ defaultChecked={initial}
88
+ {...rest}
89
+ {...attributes}
90
+ aria-describedby={[describedBy, attributes['aria-describedby']].filter(Boolean).join(' ') ||
91
+ undefined}
92
+ type="checkbox"
93
+ class="sv-checkbox__input"
94
+ bind:checked
95
+ bind:indeterminate
96
+ />
97
+ <span class="sv-checkbox__box" aria-hidden="true">
98
+ <svg class="sv-checkbox__mark" viewBox="0 0 24 24" focusable="false">
99
+ <path class="sv-checkbox__check" d="M5 12.5l4.5 4.5 9.5-9.5" />
100
+ <path class="sv-checkbox__dash" d="M6.5 12h11" />
101
+ </svg>
102
+ </span>
103
+ </span>
104
+ {/snippet}
105
+ </Choice>
@@ -0,0 +1,4 @@
1
+ import type { CheckboxProps } from './types.js';
2
+ declare const Checkbox: import("svelte").Component<CheckboxProps, {}, "ref" | "checked" | "indeterminate">;
3
+ type Checkbox = ReturnType<typeof Checkbox>;
4
+ export default Checkbox;
@@ -0,0 +1,138 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* The box is as tall as a line of the label, 1.272em with the label's √φ line height. */
5
+ .sv-checkbox {
6
+ --sv-checkbox-size: 1.272em;
7
+ --sv-checkbox-border: calc(var(--sv-hairline) * 1.5);
8
+ --sv-choice-control: var(--sv-checkbox-size);
9
+ }
10
+
11
+ /*
12
+ * The native input lies over the drawn box, invisible, so focus, keys, forms and autofill stay
13
+ * native. The box sits on the first line of the label.
14
+ */
15
+ .sv-checkbox__control {
16
+ position: relative;
17
+ display: inline-flex;
18
+ flex: none;
19
+ margin-block-start: calc((1lh - var(--sv-checkbox-size)) / 2);
20
+ }
21
+
22
+ .sv-checkbox__input {
23
+ position: absolute;
24
+ inset: 0;
25
+ inline-size: 100%;
26
+ block-size: 100%;
27
+ margin: 0;
28
+ opacity: 0;
29
+ cursor: inherit;
30
+ }
31
+
32
+ /* Never rounder than a quarter of its side, so a checkbox does not pass for a radio. */
33
+ .sv-checkbox__box {
34
+ position: relative;
35
+ display: grid;
36
+ place-items: center;
37
+ box-sizing: border-box;
38
+ inline-size: var(--sv-checkbox-size);
39
+ block-size: var(--sv-checkbox-size);
40
+ border: var(--sv-checkbox-border) solid var(--sv-color-border-strong);
41
+ border-radius: min(var(--sv-radius-sm), var(--sv-checkbox-size) * 0.236);
42
+ background-color: var(--sv-color-surface);
43
+ color: var(--sv-on-color);
44
+ pointer-events: none;
45
+ }
46
+
47
+ /* The fill (before) and the state layer (after) cover the border. */
48
+ .sv-checkbox__box::before,
49
+ .sv-checkbox__box::after {
50
+ content: '';
51
+ position: absolute;
52
+ inset: calc(var(--sv-checkbox-border) * -1);
53
+ border-radius: inherit;
54
+ opacity: 0;
55
+ }
56
+
57
+ .sv-checkbox__box::before {
58
+ background-color: var(--sv-color);
59
+ transform: scale(0.618);
60
+ }
61
+
62
+ .sv-checkbox__box::after {
63
+ background-color: var(--sv-color-text);
64
+ }
65
+
66
+ .sv-checkbox__mark {
67
+ position: relative;
68
+ inline-size: 100%;
69
+ block-size: 100%;
70
+ fill: none;
71
+ stroke: currentColor;
72
+ stroke-width: 3;
73
+ stroke-linecap: round;
74
+ stroke-linejoin: round;
75
+ opacity: 0;
76
+ transform: scale(0.618);
77
+ }
78
+
79
+ /* A check scales in with its fill; nothing else moves. */
80
+ .sv-checkbox__box::before,
81
+ .sv-checkbox__mark {
82
+ transition:
83
+ opacity var(--sv-duration-fast) var(--sv-ease),
84
+ transform var(--sv-duration-fast) var(--sv-ease);
85
+ }
86
+
87
+ .sv-checkbox__input:checked + .sv-checkbox__box::before,
88
+ .sv-checkbox__input:checked + .sv-checkbox__box .sv-checkbox__mark,
89
+ .sv-checkbox--indeterminate .sv-checkbox__box::before,
90
+ .sv-checkbox--indeterminate .sv-checkbox__mark {
91
+ opacity: 1;
92
+ transform: none;
93
+ }
94
+
95
+ .sv-checkbox__input:checked + .sv-checkbox__box::after,
96
+ .sv-checkbox--indeterminate .sv-checkbox__box::after {
97
+ background-color: var(--sv-on-color);
98
+ }
99
+
100
+ /* The dash stands in for the check while the state is indeterminate. */
101
+ .sv-checkbox__dash,
102
+ .sv-checkbox--indeterminate .sv-checkbox__check {
103
+ display: none;
104
+ }
105
+
106
+ .sv-checkbox--indeterminate .sv-checkbox__dash {
107
+ display: inline;
108
+ }
109
+
110
+ /*
111
+ * Hover and press mix the mark's colour over the box, as they do over a flat Button. The
112
+ * disabled guard adds no weight, so an invalid box keeps its error border under the pointer.
113
+ */
114
+ @media (hover: hover) {
115
+ :where(.sv-checkbox:not(.sv-choice--disabled)) > .sv-choice__row:hover .sv-checkbox__box {
116
+ border-color: var(--sv-color-text-muted);
117
+ }
118
+
119
+ :where(.sv-checkbox:not(.sv-choice--disabled))
120
+ > .sv-choice__row:hover
121
+ .sv-checkbox__box::after {
122
+ opacity: var(--sv-state-hover);
123
+ }
124
+ }
125
+
126
+ :where(.sv-checkbox:not(.sv-choice--disabled)) > .sv-choice__row:active .sv-checkbox__box::after {
127
+ opacity: var(--sv-state-press);
128
+ }
129
+
130
+ .sv-checkbox__input:focus-visible + .sv-checkbox__box {
131
+ outline: var(--sv-focus-width) solid var(--sv-color);
132
+ outline-offset: var(--sv-focus-offset);
133
+ }
134
+
135
+ .sv-choice--invalid > .sv-choice__row .sv-checkbox__box {
136
+ border-color: var(--sv-color-error);
137
+ }
138
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Checkbox } from './Checkbox.svelte';
2
+ export type { CheckboxDefaults, CheckboxProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Checkbox } from './Checkbox.svelte';
@@ -0,0 +1,76 @@
1
+ import type { HTMLInputAttributes } from 'svelte/elements';
2
+ import type { Rule, ValidateOn } from '../../core/form/types.js';
3
+ import type { ElementProps } from '../../core/props/element.js';
4
+ import type { Color, Density, Size } from '../../core/props/types.js';
5
+ import type { ChoiceContentProps } from '../Choice/types.js';
6
+ /** The Checkbox props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
7
+ export interface CheckboxDefaults {
8
+ /**
9
+ * The colour of the checked box. An invalid checkbox uses `error`.
10
+ * @default 'primary'
11
+ */
12
+ color: Color;
13
+ /**
14
+ * The size of the box and the label text.
15
+ * @default 'md'
16
+ */
17
+ size: Size;
18
+ /**
19
+ * Multiplies the height of the row, never the text.
20
+ * @default 'default'
21
+ */
22
+ density: Density;
23
+ /**
24
+ * Mutes the checkbox and disables its input.
25
+ * @default false
26
+ */
27
+ disabled: boolean;
28
+ }
29
+ declare module '../../core/defaults/context.js' {
30
+ interface ComponentDefaults {
31
+ Checkbox: CheckboxDefaults;
32
+ }
33
+ }
34
+ type CheckboxOwnProps = Partial<CheckboxDefaults> & ChoiceContentProps & {
35
+ /**
36
+ * Whether the box is checked. Bindable.
37
+ * @default false
38
+ */
39
+ checked?: boolean;
40
+ /**
41
+ * Shows a dash for a state that is neither checked nor unchecked, such as a "select all"
42
+ * box over a partly selected list. A press clears it. Bindable.
43
+ * @default false
44
+ */
45
+ indeterminate?: boolean;
46
+ /**
47
+ * What the form submits under `name` while the box is checked.
48
+ * @default 'on'
49
+ */
50
+ value?: string;
51
+ /** Checks run in order after `required`, with the checked state. The first message is shown. */
52
+ rules?: readonly Rule<boolean>[];
53
+ /** When the message shows. Defaults to the form's setting, else `'blur'`. */
54
+ validateOn?: ValidateOn;
55
+ /**
56
+ * The box must be checked, as for accepting terms. Adds an asterisk to the label.
57
+ * @default false
58
+ */
59
+ required?: boolean;
60
+ /** Inline style of the checkbox's root element. */
61
+ style?: string | null;
62
+ };
63
+ /**
64
+ * A box that is checked or not, with its label beside it: the platform's own checkbox, drawn in
65
+ * the theme. `class` and `style` apply to the root; `id`, `ref`, `name` and every other attribute
66
+ * go to the `<input type="checkbox">`. The label is the press target, at least 24px tall.
67
+ *
68
+ * @example
69
+ * <Checkbox label="Email me a receipt" name="receipt" bind:checked={receipt} />
70
+ *
71
+ * <Checkbox name="terms" required bind:checked={accepted}>
72
+ * {#snippet label()}I accept the <a href="/terms">terms of service</a>{/snippet}
73
+ * </Checkbox>
74
+ */
75
+ export type CheckboxProps = ElementProps<HTMLInputElement, Omit<HTMLInputAttributes, 'type' | 'children'>, CheckboxOwnProps>;
76
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,109 @@
1
+ <script lang="ts">
2
+ // A tag, a filter, an action or a link, as a compact pill. See ChipProps for the props.
3
+ import { useDefaults } from '../../core/defaults/context.js';
4
+ import { sveltierError } from '../../core/errors/errors.js';
5
+ import { useLocale } from '../../core/locale/locale.js';
6
+ import { sharedClasses } from '../../core/props/classes.js';
7
+ import './chip.css';
8
+ import type { ChipDefaults, ChipProps } from './types.js';
9
+
10
+ let {
11
+ variant,
12
+ size,
13
+ density,
14
+ color,
15
+ rounded,
16
+ disabled,
17
+ selected = $bindable(),
18
+ closable = false,
19
+ closeLabel,
20
+ onclose,
21
+ href,
22
+ onclick,
23
+ prepend,
24
+ append,
25
+ children,
26
+ class: className,
27
+ ref = $bindable(null),
28
+ ...rest
29
+ }: ChipProps = $props();
30
+
31
+ const resolve = useDefaults<ChipDefaults>('Chip', {
32
+ variant: 'tonal',
33
+ size: 'sm',
34
+ density: 'default',
35
+ color: 'neutral',
36
+ rounded: true,
37
+ disabled: false
38
+ });
39
+ const p = $derived(resolve({ variant, size, density, color, rounded, disabled }));
40
+ const locale = useLocale();
41
+
42
+ const toggle = $derived(selected !== undefined);
43
+ const tag = $derived.by(() => {
44
+ const element = href != null ? 'a' : toggle || onclick ? 'button' : 'span';
45
+ // A close button inside a button or a link would nest one control in another.
46
+ if (closable && element !== 'span') {
47
+ throw sveltierError(
48
+ 'SV4001',
49
+ 'Chip: a closable chip cannot also be a button or a link, since its close button would sit inside it. Put the action in a Button next to the chip.'
50
+ );
51
+ }
52
+ return element;
53
+ });
54
+ const action = $derived(tag !== 'span');
55
+
56
+ function click(event: MouseEvent) {
57
+ if (p.disabled) {
58
+ event.preventDefault();
59
+ return;
60
+ }
61
+ if (toggle) selected = !selected;
62
+ (onclick as ((event: MouseEvent) => void) | null | undefined)?.(event);
63
+ }
64
+
65
+ const CHECK = 'M4 12.5 5.5 11l4 4 9-9L20 7.5 9.5 18z';
66
+ const CLOSE =
67
+ 'M6.4 5 12 10.6 17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6l5.6-5.6L5 6.4z';
68
+ </script>
69
+
70
+ <svelte:element
71
+ this={tag}
72
+ bind:this={ref}
73
+ {...rest}
74
+ href={tag === 'a' && !p.disabled ? href : undefined}
75
+ type={tag === 'button' ? 'button' : undefined}
76
+ role={tag === 'a' && p.disabled ? 'link' : undefined}
77
+ disabled={(tag === 'button' && p.disabled) || undefined}
78
+ aria-disabled={(tag === 'a' && p.disabled) || undefined}
79
+ aria-pressed={toggle ? selected : undefined}
80
+ class={[
81
+ 'sv-chip',
82
+ sharedClasses({ ...p, variant: selected ? 'flat' : p.variant }, 'Chip'),
83
+ action && 'sv-chip--action',
84
+ p.disabled && 'sv-chip--disabled',
85
+ className
86
+ ]}
87
+ onclick={action ? click : undefined}
88
+ >
89
+ {#if selected}
90
+ <span class="sv-chip__prepend">
91
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d={CHECK} /></svg>
92
+ </span>
93
+ {:else if prepend}
94
+ <span class="sv-chip__prepend">{@render prepend()}</span>
95
+ {/if}
96
+ {#if children}<span class="sv-chip__label">{@render children()}</span>{/if}
97
+ {#if append}<span class="sv-chip__append">{@render append()}</span>{/if}
98
+ {#if closable}
99
+ <button
100
+ type="button"
101
+ class="sv-chip__close"
102
+ aria-label={closeLabel ?? locale.t('close')}
103
+ disabled={p.disabled}
104
+ onclick={() => onclose?.()}
105
+ >
106
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d={CLOSE} /></svg>
107
+ </button>
108
+ {/if}
109
+ </svelte:element>
@@ -0,0 +1,4 @@
1
+ import type { ChipProps } from './types.js';
2
+ declare const Chip: import("svelte").Component<ChipProps, {}, "ref" | "selected">;
3
+ type Chip = ReturnType<typeof Chip>;
4
+ export default Chip;
@@ -0,0 +1,101 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* A pill a control tall; text follows size only. */
5
+ .sv-chip {
6
+ position: relative;
7
+ isolation: isolate;
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: 0.382em;
11
+ box-sizing: border-box;
12
+ max-inline-size: 100%;
13
+ block-size: calc(var(--sv-size-height) * var(--sv-density));
14
+ margin: 0;
15
+ padding: 0 calc(var(--sv-size-height) * var(--sv-density) * 0.382);
16
+ border: var(--sv-hairline) solid var(--sv-variant-border);
17
+ border-radius: var(--sv-rounded, var(--sv-radius-full));
18
+ background-color: var(--sv-variant-bg);
19
+ box-shadow: var(--sv-variant-shadow);
20
+ color: var(--sv-variant-fg);
21
+ font: var(--sv-weight-medium) var(--sv-size-text) / 1 var(--sv-font-ui);
22
+ text-decoration: none;
23
+ white-space: nowrap;
24
+ vertical-align: middle;
25
+ -webkit-tap-highlight-color: transparent;
26
+ }
27
+
28
+ /* Pressable chips use the same state layer as Button. */
29
+ .sv-chip--action {
30
+ cursor: pointer;
31
+ user-select: none;
32
+ }
33
+
34
+ .sv-chip--action::before {
35
+ content: '';
36
+ position: absolute;
37
+ inset: calc(var(--sv-hairline) * -1);
38
+ z-index: -1;
39
+ border-radius: inherit;
40
+ background-color: currentColor;
41
+ opacity: 0;
42
+ pointer-events: none;
43
+ transition: opacity var(--sv-duration-fast) var(--sv-ease);
44
+ }
45
+
46
+ @media (hover: hover) {
47
+ .sv-chip--action:where(:not(.sv-chip--disabled)):hover::before {
48
+ opacity: var(--sv-state-hover);
49
+ }
50
+ }
51
+
52
+ .sv-chip--action:where(:not(.sv-chip--disabled)):active::before {
53
+ opacity: var(--sv-state-press);
54
+ }
55
+
56
+ .sv-chip--disabled {
57
+ opacity: 0.382;
58
+ cursor: not-allowed;
59
+ }
60
+
61
+ .sv-chip__label {
62
+ overflow: hidden;
63
+ text-overflow: ellipsis;
64
+ }
65
+
66
+ .sv-chip__prepend,
67
+ .sv-chip__append {
68
+ display: inline-flex;
69
+ }
70
+
71
+ :where(.sv-chip) svg {
72
+ inline-size: 1.272em;
73
+ block-size: 1.272em;
74
+ }
75
+
76
+ /* The close button: a round target at the end, tinted on hover. */
77
+ .sv-chip__close {
78
+ display: inline-grid;
79
+ place-items: center;
80
+ inline-size: 1.618em;
81
+ block-size: 1.618em;
82
+ margin-inline-end: -0.382em;
83
+ padding: 0;
84
+ border: 0;
85
+ border-radius: 50%;
86
+ background: transparent;
87
+ color: inherit;
88
+ cursor: pointer;
89
+ }
90
+
91
+ @media (hover: hover) {
92
+ .sv-chip__close:hover {
93
+ background-color: color-mix(in oklch, currentColor var(--sv-state-hover), transparent);
94
+ }
95
+ }
96
+
97
+ .sv-chip__close svg {
98
+ inline-size: 1em;
99
+ block-size: 1em;
100
+ }
101
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Chip } from './Chip.svelte';
2
+ export type { ChipDefaults, ChipProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Chip } from './Chip.svelte';
@@ -0,0 +1,69 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
3
+ import type { ElementProps } from '../../core/props/element.js';
4
+ import type { Color, Density, Rounded, Size, Variant } from '../../core/props/types.js';
5
+ /** The Chip props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
6
+ export interface ChipDefaults {
7
+ /**
8
+ * Visual weight. A selected chip is `flat`.
9
+ * @default 'tonal'
10
+ */
11
+ variant: Variant;
12
+ /**
13
+ * Height and text size.
14
+ * @default 'sm'
15
+ */
16
+ size: Size;
17
+ /**
18
+ * Multiplies the height and padding, never the text.
19
+ * @default 'default'
20
+ */
21
+ density: Density;
22
+ /**
23
+ * The colour the variant is painted with.
24
+ * @default 'neutral'
25
+ */
26
+ color: Color;
27
+ /**
28
+ * Corner rounding. `true` keeps the pill.
29
+ * @default true
30
+ */
31
+ rounded: Rounded;
32
+ /**
33
+ * A disabled chip cannot be pressed; a disabled link loses its `href`.
34
+ * @default false
35
+ */
36
+ disabled: boolean;
37
+ }
38
+ declare module '../../core/defaults/context.js' {
39
+ interface ComponentDefaults {
40
+ Chip: ChipDefaults;
41
+ }
42
+ }
43
+ /**
44
+ * A compact label: a tag (optionally `closable`), a filter that toggles (`selected`), an
45
+ * action (`onclick`) or a link (`href`).
46
+ */
47
+ export type ChipProps = ElementProps<HTMLSpanElement | HTMLButtonElement | HTMLAnchorElement, HTMLAttributes<HTMLSpanElement> & HTMLButtonAttributes & HTMLAnchorAttributes, Partial<ChipDefaults> & {
48
+ /**
49
+ * Makes the chip a toggle button (`aria-pressed`) that flips it when pressed: a filter.
50
+ * Bindable. Shows a check while selected.
51
+ */
52
+ selected?: boolean;
53
+ /**
54
+ * Adds a button that removes the chip by calling `onclose`. Only for chips that are not
55
+ * themselves buttons or links.
56
+ * @default false
57
+ */
58
+ closable?: boolean;
59
+ /** The name of the close button, such as `Remove Euro`. Defaults to the locale's `close`. */
60
+ closeLabel?: string;
61
+ /** Called by the close button. */
62
+ onclose?: () => void;
63
+ /** Content before the label, usually an icon or an avatar. */
64
+ prepend?: Snippet;
65
+ /** Content after the label. */
66
+ append?: Snippet;
67
+ /** The label. */
68
+ children?: Snippet;
69
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ // A control beside its label, with a hint or an error under them: the layout Checkbox and
3
+ // Switch share. See ChoiceProps.
4
+ import './choice.css';
5
+ import type { ChoiceProps } from './types.js';
6
+
7
+ let {
8
+ id: idProp,
9
+ label,
10
+ hint,
11
+ error = false,
12
+ required = false,
13
+ disabled = false,
14
+ children,
15
+ class: className,
16
+ ref = $bindable(null),
17
+ ...rest
18
+ }: ChoiceProps = $props();
19
+
20
+ const uid = $props.id();
21
+ const id = $derived(idProp ?? uid);
22
+ const message = $derived(typeof error === 'string' ? error : undefined);
23
+ </script>
24
+
25
+ <div
26
+ bind:this={ref}
27
+ {...rest}
28
+ class={[
29
+ 'sv-choice',
30
+ error !== false && 'sv-choice--invalid',
31
+ disabled && 'sv-choice--disabled',
32
+ className
33
+ ]}
34
+ >
35
+ <!-- The label wraps the control, so a press anywhere on it toggles the control. -->
36
+ <label class="sv-choice__row">
37
+ {@render children({
38
+ id,
39
+ 'aria-describedby': message ? `${id}-error` : hint ? `${id}-hint` : undefined,
40
+ 'aria-invalid': error !== false || undefined,
41
+ required,
42
+ disabled
43
+ })}
44
+ {#if label}
45
+ <span class="sv-choice__label"
46
+ >{#if typeof label === 'string'}{label}{:else}{@render label()}{/if}{#if required}<span
47
+ class="sv-choice__required"
48
+ aria-hidden="true">*</span
49
+ >{/if}</span
50
+ >
51
+ {/if}
52
+ </label>
53
+ <div class="sv-choice__messages">
54
+ {#if hint && !message}<p class="sv-choice__hint" id="{id}-hint">{hint}</p>{/if}
55
+ <!-- Announces an error that appears after the user has moved on. -->
56
+ <div aria-live="polite">
57
+ {#if message}<p class="sv-choice__error" id="{id}-error">{message}</p>{/if}
58
+ </div>
59
+ </div>
60
+ </div>