@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,61 @@
1
+ <script lang="ts">
2
+ // A circular progress indicator. See ProgressCircularProps for the props.
3
+ import { useDefaults } from '../../core/defaults/context.js';
4
+ import { useLocale } from '../../core/locale/locale.js';
5
+ import { sharedClasses } from '../../core/props/classes.js';
6
+ import './progress-circular.css';
7
+ import type { ProgressCircularDefaults, ProgressCircularProps } from './types.js';
8
+
9
+ let {
10
+ color,
11
+ size,
12
+ value = 0,
13
+ indeterminate = false,
14
+ label,
15
+ children,
16
+ class: className,
17
+ ref = $bindable(null),
18
+ ...rest
19
+ }: ProgressCircularProps = $props();
20
+
21
+ const resolve = useDefaults<ProgressCircularDefaults>('ProgressCircular', {
22
+ color: 'primary',
23
+ size: 'md'
24
+ });
25
+ const p = $derived(resolve({ color, size }));
26
+ const locale = useLocale();
27
+ const percent = $derived(Math.min(100, Math.max(0, Number(value) || 0)));
28
+
29
+ // A circle of radius 20 in a 44 box, stroke 4: the arc is a dash of the circumference.
30
+ const CIRCUMFERENCE = 2 * Math.PI * 20;
31
+ // Indeterminate, a φ⁻² long arc turns.
32
+ const arc = $derived(CIRCUMFERENCE * (indeterminate ? 0.382 : percent / 100));
33
+ </script>
34
+
35
+ <div
36
+ bind:this={ref}
37
+ {...rest}
38
+ role="progressbar"
39
+ aria-label={label ?? locale.t(indeterminate ? 'loading' : 'progress')}
40
+ aria-valuemin={0}
41
+ aria-valuemax={100}
42
+ aria-valuenow={indeterminate ? undefined : percent}
43
+ class={[
44
+ 'sv-progress-circular',
45
+ sharedClasses(p, 'ProgressCircular'),
46
+ indeterminate && 'sv-progress-circular--indeterminate',
47
+ className
48
+ ]}
49
+ >
50
+ <svg class="sv-progress-circular__svg" viewBox="0 0 44 44" aria-hidden="true">
51
+ <circle class="sv-progress-circular__track" cx="22" cy="22" r="20" />
52
+ <circle
53
+ class="sv-progress-circular__arc"
54
+ cx="22"
55
+ cy="22"
56
+ r="20"
57
+ stroke-dasharray="{arc} {CIRCUMFERENCE}"
58
+ />
59
+ </svg>
60
+ {#if children}<span class="sv-progress-circular__content">{@render children()}</span>{/if}
61
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ProgressCircularProps } from './types.js';
2
+ declare const ProgressCircular: import("svelte").Component<ProgressCircularProps, {}, "ref">;
3
+ type ProgressCircular = ReturnType<typeof ProgressCircular>;
4
+ export default ProgressCircular;
@@ -0,0 +1,44 @@
1
+ <script lang="ts">
2
+ // A horizontal progress bar. See ProgressLinearProps for the props.
3
+ import { useDefaults } from '../../core/defaults/context.js';
4
+ import { useLocale } from '../../core/locale/locale.js';
5
+ import { sharedClasses } from '../../core/props/classes.js';
6
+ import './progress-linear.css';
7
+ import type { ProgressLinearDefaults, ProgressLinearProps } from './types.js';
8
+
9
+ let {
10
+ color,
11
+ value = 0,
12
+ indeterminate = false,
13
+ label,
14
+ class: className,
15
+ ref = $bindable(null),
16
+ ...rest
17
+ }: ProgressLinearProps = $props();
18
+
19
+ const resolve = useDefaults<ProgressLinearDefaults>('ProgressLinear', { color: 'primary' });
20
+ const p = $derived(resolve({ color }));
21
+ const locale = useLocale();
22
+ const percent = $derived(Math.min(100, Math.max(0, Number(value) || 0)));
23
+ </script>
24
+
25
+ <div
26
+ bind:this={ref}
27
+ {...rest}
28
+ role="progressbar"
29
+ aria-label={label ?? locale.t(indeterminate ? 'loading' : 'progress')}
30
+ aria-valuemin={0}
31
+ aria-valuemax={100}
32
+ aria-valuenow={indeterminate ? undefined : percent}
33
+ class={[
34
+ 'sv-progress-linear',
35
+ sharedClasses({ color: p.color }, 'ProgressLinear'),
36
+ indeterminate && 'sv-progress-linear--indeterminate',
37
+ className
38
+ ]}
39
+ >
40
+ <div
41
+ class="sv-progress-linear__bar"
42
+ style:transform={indeterminate ? undefined : `scaleX(${percent / 100})`}
43
+ ></div>
44
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ProgressLinearProps } from './types.js';
2
+ declare const ProgressLinear: import("svelte").Component<ProgressLinearProps, {}, "ref">;
3
+ type ProgressLinear = ReturnType<typeof ProgressLinear>;
4
+ export default ProgressLinear;
@@ -0,0 +1,3 @@
1
+ export { default as ProgressCircular } from './ProgressCircular.svelte';
2
+ export { default as ProgressLinear } from './ProgressLinear.svelte';
3
+ export type { ProgressCircularDefaults, ProgressCircularProps, ProgressLinearDefaults, ProgressLinearProps } from './types.js';
@@ -0,0 +1,2 @@
1
+ export { default as ProgressCircular } from './ProgressCircular.svelte';
2
+ export { default as ProgressLinear } from './ProgressLinear.svelte';
@@ -0,0 +1,61 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* As wide as a control of its size is tall. */
5
+ .sv-progress-circular {
6
+ position: relative;
7
+ display: inline-grid;
8
+ flex: none;
9
+ place-items: center;
10
+ inline-size: var(--sv-size-height);
11
+ block-size: var(--sv-size-height);
12
+ color: var(--sv-color);
13
+ font: var(--sv-weight-medium) calc(var(--sv-size-height) * 0.236) / 1 var(--sv-font-ui);
14
+ font-variant-numeric: tabular-nums;
15
+ vertical-align: middle;
16
+ }
17
+
18
+ .sv-progress-circular__svg {
19
+ position: absolute;
20
+ inset: 0;
21
+ inline-size: 100%;
22
+ block-size: 100%;
23
+ fill: none;
24
+ stroke-width: 4;
25
+ transform: rotate(-90deg);
26
+ }
27
+
28
+ .sv-progress-circular__track {
29
+ stroke: color-mix(in oklch, currentColor var(--sv-tonal-wash), transparent);
30
+ }
31
+
32
+ .sv-progress-circular__arc {
33
+ stroke: currentColor;
34
+ stroke-linecap: round;
35
+ }
36
+
37
+ /* Indeterminate: a fixed arc that turns. A spinner that stops reads as frozen. */
38
+ .sv-progress-circular--indeterminate .sv-progress-circular__svg {
39
+ animation: sv-progress-turn 987ms linear infinite;
40
+ }
41
+
42
+ @media (prefers-reduced-motion: reduce) {
43
+ .sv-progress-circular--indeterminate .sv-progress-circular__svg {
44
+ animation-duration: 2961ms;
45
+ }
46
+ }
47
+
48
+ @keyframes sv-progress-turn {
49
+ from {
50
+ transform: rotate(-90deg);
51
+ }
52
+
53
+ to {
54
+ transform: rotate(270deg);
55
+ }
56
+ }
57
+
58
+ .sv-progress-circular__content {
59
+ position: relative;
60
+ }
61
+ }
@@ -0,0 +1,67 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* A track of the colour's tint, three px tall. */
5
+ .sv-progress-linear {
6
+ position: relative;
7
+ overflow: hidden;
8
+ block-size: var(--sv-space-3);
9
+ border-radius: var(--sv-radius-full);
10
+ background-color: color-mix(in oklch, var(--sv-color) var(--sv-tonal-wash), transparent);
11
+ }
12
+
13
+ /* The bar fills by scaling from the start edge: transform only. */
14
+ .sv-progress-linear__bar {
15
+ position: absolute;
16
+ inset: 0;
17
+ border-radius: inherit;
18
+ background-color: var(--sv-color);
19
+ transform-origin: left;
20
+ transition: transform var(--sv-duration-normal) var(--sv-ease);
21
+ }
22
+
23
+ /* An attribute selector, as minifiers rewrite :dir() into language guesses. */
24
+ :where([dir='rtl']) .sv-progress-linear__bar {
25
+ transform-origin: right;
26
+ }
27
+
28
+ /* Indeterminate: a φ⁻² long bar crosses the track. */
29
+ .sv-progress-linear--indeterminate .sv-progress-linear__bar {
30
+ inset-inline-end: auto;
31
+ inline-size: 38.2%;
32
+ animation: sv-progress-cross 1618ms var(--sv-ease) infinite;
33
+ transition: none;
34
+ }
35
+
36
+ :where([dir='rtl']) .sv-progress-linear--indeterminate .sv-progress-linear__bar {
37
+ animation-direction: reverse;
38
+ }
39
+
40
+ @keyframes sv-progress-cross {
41
+ from {
42
+ transform: translateX(-100%);
43
+ }
44
+
45
+ to {
46
+ transform: translateX(261.8%);
47
+ }
48
+ }
49
+
50
+ /* Under reduced motion it pulses in place instead of moving. */
51
+ @media (prefers-reduced-motion: reduce) {
52
+ .sv-progress-linear--indeterminate .sv-progress-linear__bar {
53
+ inline-size: 100%;
54
+ animation: sv-progress-pulse 1618ms ease-in-out infinite alternate;
55
+ }
56
+ }
57
+
58
+ @keyframes sv-progress-pulse {
59
+ from {
60
+ opacity: 0.382;
61
+ }
62
+
63
+ to {
64
+ opacity: 1;
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,53 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { ElementProps } from '../../core/props/element.js';
4
+ import type { Color, Size } from '../../core/props/types.js';
5
+ interface ProgressOwnProps {
6
+ /** How far along, from 0 to 100. Values outside are clamped. */
7
+ value?: number;
8
+ /**
9
+ * Busy for an unknown time: no value, and moving.
10
+ * @default false
11
+ */
12
+ indeterminate?: boolean;
13
+ /**
14
+ * The name screen readers give the bar, such as `Uploading statement`. Defaults to the
15
+ * locale's `loading` when indeterminate and `progress` otherwise.
16
+ */
17
+ label?: string;
18
+ }
19
+ /** The ProgressLinear props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
20
+ export interface ProgressLinearDefaults {
21
+ /**
22
+ * The colour of the bar; its track is a tint of it.
23
+ * @default 'primary'
24
+ */
25
+ color: Color;
26
+ }
27
+ /** The ProgressCircular props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
28
+ export interface ProgressCircularDefaults {
29
+ /**
30
+ * The colour of the arc; its track is a tint of it.
31
+ * @default 'primary'
32
+ */
33
+ color: Color;
34
+ /**
35
+ * The diameter: the control height of the size.
36
+ * @default 'md'
37
+ */
38
+ size: Size;
39
+ }
40
+ declare module '../../core/defaults/context.js' {
41
+ interface ComponentDefaults {
42
+ ProgressLinear: ProgressLinearDefaults;
43
+ ProgressCircular: ProgressCircularDefaults;
44
+ }
45
+ }
46
+ /** A horizontal progress bar. */
47
+ export type ProgressLinearProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<ProgressLinearDefaults> & ProgressOwnProps>;
48
+ /** A circular progress indicator, with optional content in its centre. */
49
+ export type ProgressCircularProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<ProgressCircularDefaults> & ProgressOwnProps & {
50
+ /** Content in the centre, such as the percentage. */
51
+ children?: Snippet;
52
+ }>;
53
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,149 @@
1
+ <script lang="ts" generics="T extends string | number">
2
+ // One choice among a few options, as native radios in a fieldset. See RadioGroupProps.
3
+ import { untrack } from 'svelte';
4
+ import { useDefaults } from '../../core/defaults/context.js';
5
+ import { createField } from '../../core/form/field.svelte.js';
6
+ import type { Rule } from '../../core/form/types.js';
7
+ import { useLocale } from '../../core/locale/locale.js';
8
+ import { sharedClasses } from '../../core/props/classes.js';
9
+ import '../Choice/choice.css';
10
+ import './radio-group.css';
11
+ import type { RadioGroupDefaults, RadioGroupProps } from './types.js';
12
+
13
+ let {
14
+ color,
15
+ size,
16
+ density,
17
+ disabled,
18
+ options,
19
+ value = $bindable(null),
20
+ label,
21
+ hint,
22
+ error,
23
+ rules,
24
+ validateOn,
25
+ required = false,
26
+ inline = false,
27
+ name,
28
+ 'aria-describedby': describedBy,
29
+ class: className,
30
+ ref = $bindable(null),
31
+ ...rest
32
+ }: RadioGroupProps<T> = $props();
33
+
34
+ const uid = $props.id();
35
+ const resolve = useDefaults<RadioGroupDefaults>('RadioGroup', {
36
+ color: 'primary',
37
+ size: 'md',
38
+ density: 'default',
39
+ disabled: false
40
+ });
41
+ const p = $derived(resolve({ color, size, density, disabled }));
42
+ const locale = useLocale();
43
+ // The choice a form reset goes back to: the one the group started with.
44
+ const initial = untrack(() => value ?? null);
45
+
46
+ const field = createField<T | null>({
47
+ value: () => value ?? null,
48
+ empty: (choice) => choice === null,
49
+ check: (choice) => (choice === null && required ? locale.t('required') : undefined),
50
+ // Rules never see null: an empty choice skips them.
51
+ rules: () => rules as readonly Rule<T | null>[] | undefined,
52
+ error: () => error,
53
+ validateOn: () => validateOn,
54
+ // The first radio that can be chosen carries the group's validity and takes focus.
55
+ control: () => ref?.querySelector<HTMLInputElement>('input:not(:disabled)')
56
+ });
57
+
58
+ const message = $derived(typeof field.error === 'string' ? field.error : undefined);
59
+ const groupDescription = $derived(
60
+ [describedBy, message ? `${uid}-error` : hint ? `${uid}-hint` : undefined]
61
+ .filter(Boolean)
62
+ .join(' ') || undefined
63
+ );
64
+
65
+ // A choice is a whole edit, so it also counts as leaving: the message shows at once.
66
+ function chose() {
67
+ field.changed();
68
+ field.left();
69
+ }
70
+
71
+ // A form reset puts the radios back as they started, which bind:group does not notice, so the
72
+ // bound value follows here.
73
+ $effect(() => {
74
+ const form = ref?.form;
75
+ if (!form) return;
76
+ const reset = () => (value = initial);
77
+ form.addEventListener('reset', reset);
78
+ return () => form.removeEventListener('reset', reset);
79
+ });
80
+ </script>
81
+
82
+ <!-- A radiogroup, so the invalid and required states are announced with the group. -->
83
+ <fieldset
84
+ bind:this={ref}
85
+ aria-labelledby={label ? `${uid}-legend` : undefined}
86
+ {...rest}
87
+ class={[
88
+ 'sv-choice',
89
+ 'sv-radio-group',
90
+ sharedClasses(p, 'RadioGroup'),
91
+ inline && 'sv-radio-group--inline',
92
+ field.error !== false && 'sv-choice--invalid',
93
+ className
94
+ ]}
95
+ role="radiogroup"
96
+ disabled={p.disabled}
97
+ aria-describedby={groupDescription}
98
+ aria-invalid={field.error !== false || undefined}
99
+ aria-required={required || undefined}
100
+ onchange={chose}
101
+ >
102
+ {#if label}
103
+ <legend class="sv-radio-group__legend" id="{uid}-legend"
104
+ >{label}{#if required}<span class="sv-choice__required" aria-hidden="true">*</span
105
+ >{/if}</legend
106
+ >
107
+ {/if}
108
+ <div class="sv-radio-group__options">
109
+ {#each options as option, index (option.value)}
110
+ {@const hintId = option.hint ? `${uid}-${index}-hint` : undefined}
111
+ <div
112
+ class={[
113
+ 'sv-radio-group__option',
114
+ (option.disabled || p.disabled) && 'sv-radio-group__option--disabled'
115
+ ]}
116
+ >
117
+ <label class="sv-choice__row">
118
+ <span class="sv-radio__control">
119
+ <input
120
+ type="radio"
121
+ class="sv-radio__input"
122
+ name={name ?? uid}
123
+ value={option.value}
124
+ defaultChecked={Object.is(option.value, initial)}
125
+ disabled={option.disabled}
126
+ {required}
127
+ aria-describedby={hintId}
128
+ bind:group={value}
129
+ />
130
+ <span class="sv-radio__circle" aria-hidden="true"></span>
131
+ </span>
132
+ <span class="sv-choice__label">{option.label}</span>
133
+ </label>
134
+ {#if option.hint}
135
+ <div class="sv-choice__messages">
136
+ <p class="sv-choice__hint" id={hintId}>{option.hint}</p>
137
+ </div>
138
+ {/if}
139
+ </div>
140
+ {/each}
141
+ </div>
142
+ <div class="sv-radio-group__messages">
143
+ {#if hint && !message}<p class="sv-choice__hint" id="{uid}-hint">{hint}</p>{/if}
144
+ <!-- Announces an error that appears after the user has moved on. -->
145
+ <div aria-live="polite">
146
+ {#if message}<p class="sv-choice__error" id="{uid}-error">{message}</p>{/if}
147
+ </div>
148
+ </div>
149
+ </fieldset>
@@ -0,0 +1,25 @@
1
+ import type { RadioGroupProps } from './types.js';
2
+ declare function $$render<T extends string | number>(): {
3
+ props: RadioGroupProps<T>;
4
+ exports: {};
5
+ bindings: "ref" | "value";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<T extends string | number> {
10
+ props(): ReturnType<typeof $$render<T>>['props'];
11
+ events(): ReturnType<typeof $$render<T>>['events'];
12
+ slots(): ReturnType<typeof $$render<T>>['slots'];
13
+ bindings(): "ref" | "value";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <T extends string | number>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<T>['exports']>;
20
+ <T extends string | number>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const RadioGroup: $$IsomorphicComponent;
24
+ type RadioGroup<T extends string | number> = InstanceType<typeof RadioGroup<T>>;
25
+ export default RadioGroup;
@@ -0,0 +1,2 @@
1
+ export { default as RadioGroup } from './RadioGroup.svelte';
2
+ export type { RadioGroupDefaults, RadioGroupOption, RadioGroupProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as RadioGroup } from './RadioGroup.svelte';
@@ -0,0 +1,139 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* A fieldset without the browser's frame; the rows come from the shared choice styles. */
5
+ .sv-radio-group {
6
+ --sv-radio-size: 1.272em;
7
+ --sv-radio-border: calc(var(--sv-hairline) * 1.5);
8
+ --sv-choice-control: var(--sv-radio-size);
9
+ min-inline-size: 0;
10
+ margin: 0;
11
+ padding: 0;
12
+ border: 0;
13
+ }
14
+
15
+ /* The question, in the theme's label voice, as a field's label. */
16
+ .sv-radio-group__legend {
17
+ margin-block-end: var(--sv-space-5);
18
+ padding: 0;
19
+ font-size: var(--sv-label-size);
20
+ font-weight: var(--sv-weight-medium);
21
+ letter-spacing: var(--sv-label-tracking);
22
+ text-transform: var(--sv-label-transform);
23
+ }
24
+
25
+ .sv-radio-group__options {
26
+ display: flex;
27
+ flex-direction: column;
28
+ align-items: flex-start;
29
+ }
30
+
31
+ .sv-radio-group--inline > .sv-radio-group__options {
32
+ flex-flow: row wrap;
33
+ column-gap: var(--sv-space-21);
34
+ }
35
+
36
+ .sv-radio-group__option--disabled > .sv-choice__row {
37
+ opacity: 0.382;
38
+ cursor: not-allowed;
39
+ }
40
+
41
+ /*
42
+ * A radio is round in every theme, square ones included, so it never passes for a checkbox.
43
+ * The native input lies over the drawn circle, invisible.
44
+ */
45
+ .sv-radio__control {
46
+ position: relative;
47
+ display: inline-flex;
48
+ flex: none;
49
+ margin-block-start: calc((1lh - var(--sv-radio-size)) / 2);
50
+ }
51
+
52
+ .sv-radio__input {
53
+ position: absolute;
54
+ inset: 0;
55
+ inline-size: 100%;
56
+ block-size: 100%;
57
+ margin: 0;
58
+ opacity: 0;
59
+ cursor: inherit;
60
+ }
61
+
62
+ .sv-radio__circle {
63
+ position: relative;
64
+ display: grid;
65
+ place-items: center;
66
+ box-sizing: border-box;
67
+ inline-size: var(--sv-radio-size);
68
+ block-size: var(--sv-radio-size);
69
+ border: var(--sv-radio-border) solid var(--sv-color-border-strong);
70
+ border-radius: 50%;
71
+ background-color: var(--sv-color-surface);
72
+ pointer-events: none;
73
+ }
74
+
75
+ /* The dot (before) scales in; the state layer (after) covers the circle. */
76
+ .sv-radio__circle::before {
77
+ content: '';
78
+ inline-size: 50%;
79
+ block-size: 50%;
80
+ border-radius: 50%;
81
+ background-color: var(--sv-color);
82
+ transform: scale(0);
83
+ transition: transform var(--sv-duration-fast) var(--sv-ease);
84
+ }
85
+
86
+ .sv-radio__circle::after {
87
+ content: '';
88
+ position: absolute;
89
+ inset: calc(var(--sv-radio-border) * -1);
90
+ border-radius: 50%;
91
+ background-color: var(--sv-color-text);
92
+ opacity: 0;
93
+ }
94
+
95
+ .sv-radio__input:checked + .sv-radio__circle {
96
+ border-color: var(--sv-color);
97
+ }
98
+
99
+ .sv-radio__input:checked + .sv-radio__circle::before {
100
+ transform: none;
101
+ }
102
+
103
+ /* Hover and press mix a layer over the circle. The disabled guard adds no weight. */
104
+ @media (hover: hover) {
105
+ :where(.sv-radio-group__option:not(.sv-radio-group__option--disabled))
106
+ > .sv-choice__row:hover
107
+ .sv-radio__circle {
108
+ border-color: var(--sv-color-text-muted);
109
+ }
110
+
111
+ :where(.sv-radio-group__option:not(.sv-radio-group__option--disabled))
112
+ > .sv-choice__row:hover
113
+ .sv-radio__circle::after {
114
+ opacity: var(--sv-state-hover);
115
+ }
116
+
117
+ :where(.sv-radio-group__option:not(.sv-radio-group__option--disabled))
118
+ > .sv-choice__row:hover
119
+ .sv-radio__input:checked
120
+ + .sv-radio__circle {
121
+ border-color: var(--sv-color);
122
+ }
123
+ }
124
+
125
+ :where(.sv-radio-group__option:not(.sv-radio-group__option--disabled))
126
+ > .sv-choice__row:active
127
+ .sv-radio__circle::after {
128
+ opacity: var(--sv-state-press);
129
+ }
130
+
131
+ .sv-radio__input:focus-visible + .sv-radio__circle {
132
+ outline: var(--sv-focus-width) solid var(--sv-color);
133
+ outline-offset: var(--sv-focus-offset);
134
+ }
135
+
136
+ .sv-choice--invalid .sv-choice__row .sv-radio__circle {
137
+ border-color: var(--sv-color-error);
138
+ }
139
+ }