@sveltier/ui 0.0.0-stage → 0.1.0-alpha.1

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 (331) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -2
  3. package/dist/components/Accordion/Accordion.svelte +74 -0
  4. package/dist/components/Accordion/Accordion.svelte.d.ts +25 -0
  5. package/dist/components/Accordion/accordion.css +88 -0
  6. package/dist/components/Accordion/index.d.ts +2 -0
  7. package/dist/components/Accordion/index.js +1 -0
  8. package/dist/components/Accordion/types.d.ts +64 -0
  9. package/dist/components/Accordion/types.js +1 -0
  10. package/dist/components/Alert/Alert.svelte +88 -0
  11. package/dist/components/Alert/Alert.svelte.d.ts +4 -0
  12. package/dist/components/Alert/alert.css +78 -0
  13. package/dist/components/Alert/index.d.ts +2 -0
  14. package/dist/components/Alert/index.js +1 -0
  15. package/dist/components/Alert/types.d.ts +67 -0
  16. package/dist/components/Alert/types.js +1 -0
  17. package/dist/components/Avatar/Avatar.svelte +47 -0
  18. package/dist/components/Avatar/Avatar.svelte.d.ts +4 -0
  19. package/dist/components/Avatar/avatar.css +34 -0
  20. package/dist/components/Avatar/index.d.ts +2 -0
  21. package/dist/components/Avatar/index.js +1 -0
  22. package/dist/components/Avatar/types.d.ts +47 -0
  23. package/dist/components/Avatar/types.js +1 -0
  24. package/dist/components/Badge/Badge.svelte +53 -0
  25. package/dist/components/Badge/Badge.svelte.d.ts +4 -0
  26. package/dist/components/Badge/badge.css +57 -0
  27. package/dist/components/Badge/index.d.ts +2 -0
  28. package/dist/components/Badge/index.js +1 -0
  29. package/dist/components/Badge/types.d.ts +43 -0
  30. package/dist/components/Badge/types.js +1 -0
  31. package/dist/components/Button/Button.svelte +85 -0
  32. package/dist/components/Button/Button.svelte.d.ts +4 -0
  33. package/dist/components/Button/button.css +132 -0
  34. package/dist/components/Button/index.d.ts +2 -0
  35. package/dist/components/Button/index.js +1 -0
  36. package/dist/components/Button/types.d.ts +76 -0
  37. package/dist/components/Button/types.js +1 -0
  38. package/dist/components/ButtonGroup/ButtonGroup.svelte +61 -0
  39. package/dist/components/ButtonGroup/ButtonGroup.svelte.d.ts +4 -0
  40. package/dist/components/ButtonGroup/button-group.css +39 -0
  41. package/dist/components/ButtonGroup/index.d.ts +2 -0
  42. package/dist/components/ButtonGroup/index.js +1 -0
  43. package/dist/components/ButtonGroup/types.d.ts +48 -0
  44. package/dist/components/ButtonGroup/types.js +1 -0
  45. package/dist/components/Card/Card.svelte +53 -0
  46. package/dist/components/Card/Card.svelte.d.ts +4 -0
  47. package/dist/components/Card/card.css +62 -0
  48. package/dist/components/Card/index.d.ts +2 -0
  49. package/dist/components/Card/index.js +1 -0
  50. package/dist/components/Card/types.d.ts +56 -0
  51. package/dist/components/Card/types.js +1 -0
  52. package/dist/components/Checkbox/Checkbox.svelte +105 -0
  53. package/dist/components/Checkbox/Checkbox.svelte.d.ts +4 -0
  54. package/dist/components/Checkbox/checkbox.css +138 -0
  55. package/dist/components/Checkbox/index.d.ts +2 -0
  56. package/dist/components/Checkbox/index.js +1 -0
  57. package/dist/components/Checkbox/types.d.ts +76 -0
  58. package/dist/components/Checkbox/types.js +1 -0
  59. package/dist/components/Chip/Chip.svelte +109 -0
  60. package/dist/components/Chip/Chip.svelte.d.ts +4 -0
  61. package/dist/components/Chip/chip.css +101 -0
  62. package/dist/components/Chip/index.d.ts +2 -0
  63. package/dist/components/Chip/index.js +1 -0
  64. package/dist/components/Chip/types.d.ts +69 -0
  65. package/dist/components/Chip/types.js +1 -0
  66. package/dist/components/Choice/Choice.svelte +60 -0
  67. package/dist/components/Choice/Choice.svelte.d.ts +4 -0
  68. package/dist/components/Choice/choice.css +75 -0
  69. package/dist/components/Choice/types.d.ts +43 -0
  70. package/dist/components/Choice/types.js +1 -0
  71. package/dist/components/Dialog/Dialog.svelte +36 -0
  72. package/dist/components/Dialog/Dialog.svelte.d.ts +4 -0
  73. package/dist/components/Dialog/index.d.ts +2 -0
  74. package/dist/components/Dialog/index.js +1 -0
  75. package/dist/components/Dialog/types.d.ts +50 -0
  76. package/dist/components/Dialog/types.js +1 -0
  77. package/dist/components/Divider/Divider.svelte +19 -0
  78. package/dist/components/Divider/Divider.svelte.d.ts +4 -0
  79. package/dist/components/Divider/divider.css +23 -0
  80. package/dist/components/Divider/index.d.ts +2 -0
  81. package/dist/components/Divider/index.js +1 -0
  82. package/dist/components/Divider/types.d.ts +10 -0
  83. package/dist/components/Divider/types.js +1 -0
  84. package/dist/components/Field/Field.svelte +95 -0
  85. package/dist/components/Field/Field.svelte.d.ts +4 -0
  86. package/dist/components/Field/field.css +210 -0
  87. package/dist/components/Field/index.d.ts +3 -0
  88. package/dist/components/Field/index.js +2 -0
  89. package/dist/components/Field/types.d.ts +109 -0
  90. package/dist/components/Field/types.js +2 -0
  91. package/dist/components/Form/Form.svelte +93 -0
  92. package/dist/components/Form/Form.svelte.d.ts +8 -0
  93. package/dist/components/Form/form.css +16 -0
  94. package/dist/components/Form/index.d.ts +2 -0
  95. package/dist/components/Form/index.js +1 -0
  96. package/dist/components/Form/types.d.ts +38 -0
  97. package/dist/components/Form/types.js +1 -0
  98. package/dist/components/Icon/Icon.svelte +38 -0
  99. package/dist/components/Icon/Icon.svelte.d.ts +4 -0
  100. package/dist/components/Icon/icon.css +33 -0
  101. package/dist/components/Icon/index.d.ts +2 -0
  102. package/dist/components/Icon/index.js +1 -0
  103. package/dist/components/Icon/types.d.ts +34 -0
  104. package/dist/components/Icon/types.js +1 -0
  105. package/dist/components/List/List.svelte +39 -0
  106. package/dist/components/List/List.svelte.d.ts +4 -0
  107. package/dist/components/List/ListItem.svelte +57 -0
  108. package/dist/components/List/ListItem.svelte.d.ts +4 -0
  109. package/dist/components/List/index.d.ts +3 -0
  110. package/dist/components/List/index.js +2 -0
  111. package/dist/components/List/list.css +127 -0
  112. package/dist/components/List/types.d.ts +67 -0
  113. package/dist/components/List/types.js +1 -0
  114. package/dist/components/Menu/Menu.svelte +195 -0
  115. package/dist/components/Menu/Menu.svelte.d.ts +4 -0
  116. package/dist/components/Menu/index.d.ts +2 -0
  117. package/dist/components/Menu/index.js +1 -0
  118. package/dist/components/Menu/menu.css +103 -0
  119. package/dist/components/Menu/types.d.ts +90 -0
  120. package/dist/components/Menu/types.js +1 -0
  121. package/dist/components/Modal/Modal.svelte +146 -0
  122. package/dist/components/Modal/Modal.svelte.d.ts +4 -0
  123. package/dist/components/Modal/modal.css +150 -0
  124. package/dist/components/Modal/types.d.ts +54 -0
  125. package/dist/components/Modal/types.js +1 -0
  126. package/dist/components/NativeSelect/NativeSelect.svelte +110 -0
  127. package/dist/components/NativeSelect/NativeSelect.svelte.d.ts +25 -0
  128. package/dist/components/NativeSelect/index.d.ts +2 -0
  129. package/dist/components/NativeSelect/index.js +1 -0
  130. package/dist/components/NativeSelect/native-select.css +45 -0
  131. package/dist/components/NativeSelect/types.d.ts +58 -0
  132. package/dist/components/NativeSelect/types.js +1 -0
  133. package/dist/components/NumberField/NumberField.svelte +246 -0
  134. package/dist/components/NumberField/NumberField.svelte.d.ts +4 -0
  135. package/dist/components/NumberField/index.d.ts +2 -0
  136. package/dist/components/NumberField/index.js +1 -0
  137. package/dist/components/NumberField/number-field.css +74 -0
  138. package/dist/components/NumberField/types.d.ts +73 -0
  139. package/dist/components/NumberField/types.js +1 -0
  140. package/dist/components/Popover/Popover.svelte +115 -0
  141. package/dist/components/Popover/Popover.svelte.d.ts +4 -0
  142. package/dist/components/Popover/index.d.ts +2 -0
  143. package/dist/components/Popover/index.js +1 -0
  144. package/dist/components/Popover/popover.css +67 -0
  145. package/dist/components/Popover/types.d.ts +83 -0
  146. package/dist/components/Popover/types.js +1 -0
  147. package/dist/components/Progress/ProgressCircular.svelte +61 -0
  148. package/dist/components/Progress/ProgressCircular.svelte.d.ts +4 -0
  149. package/dist/components/Progress/ProgressLinear.svelte +44 -0
  150. package/dist/components/Progress/ProgressLinear.svelte.d.ts +4 -0
  151. package/dist/components/Progress/index.d.ts +3 -0
  152. package/dist/components/Progress/index.js +2 -0
  153. package/dist/components/Progress/progress-circular.css +61 -0
  154. package/dist/components/Progress/progress-linear.css +67 -0
  155. package/dist/components/Progress/types.d.ts +53 -0
  156. package/dist/components/Progress/types.js +1 -0
  157. package/dist/components/RadioGroup/RadioGroup.svelte +149 -0
  158. package/dist/components/RadioGroup/RadioGroup.svelte.d.ts +25 -0
  159. package/dist/components/RadioGroup/index.d.ts +2 -0
  160. package/dist/components/RadioGroup/index.js +1 -0
  161. package/dist/components/RadioGroup/radio-group.css +139 -0
  162. package/dist/components/RadioGroup/types.d.ts +93 -0
  163. package/dist/components/RadioGroup/types.js +1 -0
  164. package/dist/components/SegmentedControl/SegmentedControl.svelte +70 -0
  165. package/dist/components/SegmentedControl/SegmentedControl.svelte.d.ts +25 -0
  166. package/dist/components/SegmentedControl/index.d.ts +2 -0
  167. package/dist/components/SegmentedControl/index.js +1 -0
  168. package/dist/components/SegmentedControl/segmented-control.css +68 -0
  169. package/dist/components/SegmentedControl/types.d.ts +60 -0
  170. package/dist/components/SegmentedControl/types.js +1 -0
  171. package/dist/components/Sheet/Sheet.svelte +56 -0
  172. package/dist/components/Sheet/Sheet.svelte.d.ts +4 -0
  173. package/dist/components/Sheet/index.d.ts +2 -0
  174. package/dist/components/Sheet/index.js +2 -0
  175. package/dist/components/Sheet/sheet.css +61 -0
  176. package/dist/components/Sheet/types.d.ts +51 -0
  177. package/dist/components/Sheet/types.js +1 -0
  178. package/dist/components/Skeleton/Skeleton.svelte +33 -0
  179. package/dist/components/Skeleton/Skeleton.svelte.d.ts +4 -0
  180. package/dist/components/Skeleton/index.d.ts +2 -0
  181. package/dist/components/Skeleton/index.js +1 -0
  182. package/dist/components/Skeleton/skeleton.css +70 -0
  183. package/dist/components/Skeleton/types.d.ts +25 -0
  184. package/dist/components/Skeleton/types.js +1 -0
  185. package/dist/components/Slider/Slider.svelte +153 -0
  186. package/dist/components/Slider/Slider.svelte.d.ts +4 -0
  187. package/dist/components/Slider/index.d.ts +2 -0
  188. package/dist/components/Slider/index.js +1 -0
  189. package/dist/components/Slider/slider.css +206 -0
  190. package/dist/components/Slider/types.d.ts +102 -0
  191. package/dist/components/Slider/types.js +1 -0
  192. package/dist/components/Switch/Switch.svelte +94 -0
  193. package/dist/components/Switch/Switch.svelte.d.ts +4 -0
  194. package/dist/components/Switch/index.d.ts +2 -0
  195. package/dist/components/Switch/index.js +1 -0
  196. package/dist/components/Switch/switch.css +118 -0
  197. package/dist/components/Switch/types.d.ts +67 -0
  198. package/dist/components/Switch/types.js +1 -0
  199. package/dist/components/Tabs/Tabs.svelte +93 -0
  200. package/dist/components/Tabs/Tabs.svelte.d.ts +25 -0
  201. package/dist/components/Tabs/index.d.ts +2 -0
  202. package/dist/components/Tabs/index.js +1 -0
  203. package/dist/components/Tabs/tabs.css +73 -0
  204. package/dist/components/Tabs/types.d.ts +59 -0
  205. package/dist/components/Tabs/types.js +1 -0
  206. package/dist/components/TextField/TextField.svelte +115 -0
  207. package/dist/components/TextField/TextField.svelte.d.ts +4 -0
  208. package/dist/components/TextField/index.d.ts +2 -0
  209. package/dist/components/TextField/index.js +1 -0
  210. package/dist/components/TextField/types.d.ts +57 -0
  211. package/dist/components/TextField/types.js +1 -0
  212. package/dist/components/Textarea/Textarea.svelte +116 -0
  213. package/dist/components/Textarea/Textarea.svelte.d.ts +4 -0
  214. package/dist/components/Textarea/index.d.ts +2 -0
  215. package/dist/components/Textarea/index.js +1 -0
  216. package/dist/components/Textarea/textarea.css +35 -0
  217. package/dist/components/Textarea/types.d.ts +60 -0
  218. package/dist/components/Textarea/types.js +1 -0
  219. package/dist/components/Tooltip/Tooltip.svelte +161 -0
  220. package/dist/components/Tooltip/Tooltip.svelte.d.ts +4 -0
  221. package/dist/components/Tooltip/index.d.ts +2 -0
  222. package/dist/components/Tooltip/index.js +1 -0
  223. package/dist/components/Tooltip/tooltip.css +44 -0
  224. package/dist/components/Tooltip/types.d.ts +55 -0
  225. package/dist/components/Tooltip/types.js +1 -0
  226. package/dist/core/defaults/DefaultsProvider.svelte +30 -0
  227. package/dist/core/defaults/DefaultsProvider.svelte.d.ts +13 -0
  228. package/dist/core/defaults/context.d.ts +45 -0
  229. package/dist/core/defaults/context.js +38 -0
  230. package/dist/core/display/display.d.ts +39 -0
  231. package/dist/core/display/display.js +53 -0
  232. package/dist/core/errors/codes.d.ts +124 -0
  233. package/dist/core/errors/codes.js +108 -0
  234. package/dist/core/errors/errors.d.ts +8 -0
  235. package/dist/core/errors/errors.js +7 -0
  236. package/dist/core/form/constraints.d.ts +15 -0
  237. package/dist/core/form/constraints.js +42 -0
  238. package/dist/core/form/context.d.ts +19 -0
  239. package/dist/core/form/context.js +4 -0
  240. package/dist/core/form/field.svelte.d.ts +34 -0
  241. package/dist/core/form/field.svelte.js +66 -0
  242. package/dist/core/form/number.d.ts +24 -0
  243. package/dist/core/form/number.js +71 -0
  244. package/dist/core/form/types.d.ts +22 -0
  245. package/dist/core/form/types.js +1 -0
  246. package/dist/core/locale/locale.d.ts +56 -0
  247. package/dist/core/locale/locale.js +82 -0
  248. package/dist/core/overlay/types.d.ts +33 -0
  249. package/dist/core/overlay/types.js +1 -0
  250. package/dist/core/props/classes.d.ts +21 -0
  251. package/dist/core/props/classes.js +44 -0
  252. package/dist/core/props/element.d.ts +18 -0
  253. package/dist/core/props/element.js +1 -0
  254. package/dist/core/props/types.d.ts +47 -0
  255. package/dist/core/props/types.js +16 -0
  256. package/dist/core/provider/UIProvider.svelte +63 -0
  257. package/dist/core/provider/UIProvider.svelte.d.ts +29 -0
  258. package/dist/core/theme/ThemeProvider.svelte +178 -0
  259. package/dist/core/theme/ThemeProvider.svelte.d.ts +25 -0
  260. package/dist/core/theme/color.d.ts +23 -0
  261. package/dist/core/theme/color.js +54 -0
  262. package/dist/core/theme/context.d.ts +25 -0
  263. package/dist/core/theme/context.js +14 -0
  264. package/dist/core/theme/css.d.ts +25 -0
  265. package/dist/core/theme/css.js +73 -0
  266. package/dist/core/theme/define.d.ts +11 -0
  267. package/dist/core/theme/define.js +21 -0
  268. package/dist/core/theme/resolve.d.ts +6 -0
  269. package/dist/core/theme/resolve.js +18 -0
  270. package/dist/core/theme/theme-provider.css +13 -0
  271. package/dist/core/theme/types.d.ts +35 -0
  272. package/dist/core/theme/types.js +61 -0
  273. package/dist/core/toast/ToastOutlet.svelte +192 -0
  274. package/dist/core/toast/ToastOutlet.svelte.d.ts +11 -0
  275. package/dist/core/toast/ToastProvider.svelte +39 -0
  276. package/dist/core/toast/ToastProvider.svelte.d.ts +19 -0
  277. package/dist/core/toast/toast.css +134 -0
  278. package/dist/core/toast/toast.svelte.d.ts +117 -0
  279. package/dist/core/toast/toast.svelte.js +133 -0
  280. package/dist/dev/off.d.ts +5 -0
  281. package/dist/dev/off.js +4 -0
  282. package/dist/dev/on.d.ts +20 -0
  283. package/dist/dev/on.js +49 -0
  284. package/dist/index.d.ts +67 -0
  285. package/dist/index.js +83 -0
  286. package/dist/primitives/anchored/anchored.d.ts +39 -0
  287. package/dist/primitives/anchored/anchored.js +104 -0
  288. package/dist/primitives/anchored/fallback.d.ts +31 -0
  289. package/dist/primitives/anchored/fallback.js +73 -0
  290. package/dist/primitives/focus/focus-trap.d.ts +25 -0
  291. package/dist/primitives/focus/focus-trap.js +86 -0
  292. package/dist/primitives/focus/roving-focus.d.ts +22 -0
  293. package/dist/primitives/focus/roving-focus.js +86 -0
  294. package/dist/primitives/focus/tabbable.d.ts +9 -0
  295. package/dist/primitives/focus/tabbable.js +75 -0
  296. package/dist/primitives/inert/inert-others.d.ts +12 -0
  297. package/dist/primitives/inert/inert-others.js +44 -0
  298. package/dist/primitives/keyboard/keymap.d.ts +17 -0
  299. package/dist/primitives/keyboard/keymap.js +39 -0
  300. package/dist/primitives/keyboard/typeahead.d.ts +18 -0
  301. package/dist/primitives/keyboard/typeahead.js +50 -0
  302. package/dist/primitives/layer/dismissable.d.ts +32 -0
  303. package/dist/primitives/layer/dismissable.js +91 -0
  304. package/dist/primitives/motion/easing.d.ts +9 -0
  305. package/dist/primitives/motion/easing.js +46 -0
  306. package/dist/primitives/motion/motion.d.ts +59 -0
  307. package/dist/primitives/motion/motion.js +80 -0
  308. package/dist/primitives/portal/Portal.svelte +37 -0
  309. package/dist/primitives/portal/Portal.svelte.d.ts +9 -0
  310. package/dist/primitives/portal/PortalContent.svelte +15 -0
  311. package/dist/primitives/portal/PortalContent.svelte.d.ts +9 -0
  312. package/dist/primitives/portal/portal.css +8 -0
  313. package/dist/primitives/scroll-lock/scroll-lock.d.ts +10 -0
  314. package/dist/primitives/scroll-lock/scroll-lock.js +33 -0
  315. package/dist/primitives/virtual/virtual-list.svelte.d.ts +65 -0
  316. package/dist/primitives/virtual/virtual-list.svelte.js +291 -0
  317. package/dist/styles/base.css +44 -0
  318. package/dist/styles/props.css +140 -0
  319. package/dist/styles/tokens.css +84 -0
  320. package/dist/styles/visually-hidden.css +16 -0
  321. package/dist/themes/aurora.d.ts +13 -0
  322. package/dist/themes/aurora.js +103 -0
  323. package/dist/themes/heritage.d.ts +13 -0
  324. package/dist/themes/heritage.js +102 -0
  325. package/dist/themes/maison.d.ts +13 -0
  326. package/dist/themes/maison.js +99 -0
  327. package/dist/themes/milano.d.ts +13 -0
  328. package/dist/themes/milano.js +101 -0
  329. package/dist/themes/monolith.d.ts +13 -0
  330. package/dist/themes/monolith.js +101 -0
  331. package/package.json +87 -5
@@ -0,0 +1,210 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /*
5
+ * A label above a box above a hint or an error. The box is as tall as a Button of the same
6
+ * size and density. Its border is --sv-field-border; the accent of a focused or invalid
7
+ * field is a layer in --sv-color whose opacity changes.
8
+ */
9
+ .sv-field {
10
+ --sv-field-border: var(--sv-color-border-strong);
11
+ display: flex;
12
+ flex-direction: column;
13
+ min-inline-size: 0;
14
+ font-family: var(--sv-font-ui);
15
+ }
16
+
17
+ /* The theme's label voice: Heritage and Maison set it in tracked capitals. */
18
+ .sv-field__label {
19
+ align-self: flex-start;
20
+ margin-block-end: var(--sv-space-8);
21
+ color: var(--sv-color-text);
22
+ font-size: var(--sv-label-size);
23
+ font-weight: var(--sv-weight-medium);
24
+ line-height: var(--sv-leading-snug);
25
+ letter-spacing: var(--sv-label-tracking);
26
+ text-transform: var(--sv-label-transform);
27
+ }
28
+
29
+ .sv-field__required {
30
+ margin-inline-start: 0.236em;
31
+ color: var(--sv-color-error);
32
+ }
33
+
34
+ .sv-field__box {
35
+ position: relative;
36
+ isolation: isolate;
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 0.618em;
40
+ box-sizing: border-box;
41
+ min-block-size: calc(var(--sv-size-height) * var(--sv-density));
42
+ padding-inline: calc(var(--sv-size-height) * var(--sv-density) * 0.382);
43
+ border: var(--sv-hairline) solid var(--sv-field-border);
44
+ /* A control that grows to several lines sets --sv-field-radius, so it never turns oval. */
45
+ border-radius: var(--sv-rounded, var(--sv-field-radius, var(--sv-radius-md)));
46
+ color: var(--sv-color-text);
47
+ font-size: var(--sv-size-text);
48
+ line-height: var(--sv-leading-snug);
49
+ cursor: text;
50
+ }
51
+
52
+ .sv-field__box::after {
53
+ content: '';
54
+ position: absolute;
55
+ inset: calc(var(--sv-hairline) * -1);
56
+ border: var(--sv-focus-width) solid var(--sv-color);
57
+ border-radius: inherit;
58
+ opacity: 0;
59
+ pointer-events: none;
60
+ transition: opacity var(--sv-duration-fast) var(--sv-ease);
61
+ }
62
+
63
+ .sv-field__box:focus-within::after {
64
+ opacity: 1;
65
+ }
66
+
67
+ @media (hover: hover) {
68
+ .sv-field:where(:not(.sv-field--disabled, .sv-field--readonly)) .sv-field__box:hover {
69
+ --sv-field-border: var(--sv-color-text-muted);
70
+ }
71
+ }
72
+
73
+ .sv-field--invalid,
74
+ .sv-field--invalid .sv-field__box:hover {
75
+ --sv-color: var(--sv-color-error);
76
+ --sv-field-border: var(--sv-color-error);
77
+ }
78
+
79
+ /* Variants. Tonal is a wash of the text colour, not of the accent. */
80
+ .sv-variant-tonal > .sv-field__box {
81
+ border-width: 0 0 var(--sv-hairline);
82
+ border-end-start-radius: 0;
83
+ border-end-end-radius: 0;
84
+ background-color: color-mix(in oklch, var(--sv-color-text) 5%, transparent);
85
+ }
86
+
87
+ .sv-variant-text > .sv-field__box {
88
+ border-width: 0 0 var(--sv-hairline);
89
+ border-radius: 0;
90
+ padding-inline: 0;
91
+ }
92
+
93
+ .sv-variant-tonal > .sv-field__box::after,
94
+ .sv-variant-text > .sv-field__box::after {
95
+ border-width: 0 0 var(--sv-focus-width);
96
+ }
97
+
98
+ .sv-variant-elevated > .sv-field__box {
99
+ border-color: transparent;
100
+ background-color: var(--sv-color-surface);
101
+ box-shadow: var(--sv-shadow);
102
+ }
103
+
104
+ .sv-field--invalid.sv-variant-elevated > .sv-field__box {
105
+ border-color: var(--sv-field-border);
106
+ }
107
+
108
+ .sv-variant-plain > .sv-field__box {
109
+ border-color: transparent;
110
+ padding-inline: 0;
111
+ }
112
+
113
+ /* A plain field draws no box, so its focus is the theme's ring. */
114
+ .sv-variant-plain > .sv-field__box::after {
115
+ content: none;
116
+ }
117
+
118
+ .sv-variant-plain > .sv-field__box:focus-within {
119
+ outline: var(--sv-focus-width) solid var(--sv-color);
120
+ outline-offset: var(--sv-focus-offset);
121
+ }
122
+
123
+ /* Muted at φ⁻², as a disabled Button. */
124
+ .sv-field--disabled {
125
+ opacity: 0.382;
126
+ }
127
+
128
+ .sv-field--disabled .sv-field__box {
129
+ cursor: not-allowed;
130
+ }
131
+
132
+ .sv-field--readonly .sv-field__box {
133
+ cursor: default;
134
+ }
135
+
136
+ .sv-field__prepend,
137
+ .sv-field__append {
138
+ display: inline-flex;
139
+ flex: none;
140
+ align-items: center;
141
+ color: var(--sv-color-text-muted);
142
+ }
143
+
144
+ :where(.sv-field__prepend, .sv-field__append) > svg {
145
+ inline-size: 1.272em;
146
+ block-size: 1.272em;
147
+ }
148
+
149
+ /* Padding, not margin: an app's paragraph reset (p { margin: 0 }) would win over a layer. */
150
+ .sv-field__hint,
151
+ .sv-field__error {
152
+ margin: 0;
153
+ padding-block-start: var(--sv-space-5);
154
+ font-size: var(--sv-text-xs);
155
+ line-height: var(--sv-leading-snug);
156
+ }
157
+
158
+ .sv-field__hint {
159
+ color: var(--sv-color-text-muted);
160
+ }
161
+
162
+ .sv-field__error {
163
+ color: var(--sv-color-error);
164
+ }
165
+
166
+ /*
167
+ * The control fills the box; the box shows focus. Text is at least 16px on touch screens,
168
+ * where smaller text makes iOS zoom into the page on focus.
169
+ */
170
+ .sv-field__control {
171
+ flex: 1;
172
+ align-self: stretch;
173
+ min-inline-size: 0;
174
+ box-sizing: border-box;
175
+ margin: 0;
176
+ padding: 0;
177
+ border: 0;
178
+ background: none;
179
+ color: inherit;
180
+ font: inherit;
181
+ letter-spacing: inherit;
182
+ appearance: none;
183
+ }
184
+
185
+ .sv-field__control:focus-visible {
186
+ outline: none;
187
+ }
188
+
189
+ .sv-field__control::placeholder {
190
+ color: var(--sv-color-text-subtle);
191
+ opacity: 1;
192
+ }
193
+
194
+ .sv-field__control:disabled {
195
+ cursor: not-allowed;
196
+ }
197
+
198
+ /* Autofill keeps the field's colours: the browser's tint is delayed for good. */
199
+ .sv-field__control:autofill {
200
+ transition:
201
+ background-color 0s 600000s,
202
+ color 0s 600000s;
203
+ }
204
+
205
+ @media (pointer: coarse) {
206
+ .sv-field__control {
207
+ font-size: max(1rem, 1em);
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,3 @@
1
+ export { default as Field } from './Field.svelte';
2
+ export { FIELD_VARIANTS } from './types.js';
3
+ export type { FieldContentProps, FieldControlAttributes, FieldDefaults, FieldProps, FieldVariant } from './types.js';
@@ -0,0 +1,2 @@
1
+ export { default as Field } from './Field.svelte';
2
+ export { FIELD_VARIANTS } from './types.js';
@@ -0,0 +1,109 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { FieldError } from '../../core/form/types.js';
4
+ import type { ElementProps } from '../../core/props/element.js';
5
+ import type { Color, Density, Rounded, Size } from '../../core/props/types.js';
6
+ /** The variants a boxed field takes, a subset of the shared `VARIANTS`. */
7
+ export declare const FIELD_VARIANTS: readonly ["outlined", "tonal", "elevated", "text", "plain"];
8
+ /**
9
+ * How a field's box is drawn: `outlined` (a border), `tonal` (a wash with a rule under it),
10
+ * `elevated` (a surface with a shadow), `text` (only the rule) and `plain` (nothing, for a field
11
+ * inside another component).
12
+ */
13
+ export type FieldVariant = (typeof FIELD_VARIANTS)[number];
14
+ /** The Field props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
15
+ export interface FieldDefaults {
16
+ /**
17
+ * How the box is drawn.
18
+ * @default 'outlined'
19
+ */
20
+ variant: FieldVariant;
21
+ /**
22
+ * The accent of the focused field. An invalid field uses `error`.
23
+ * @default 'primary'
24
+ */
25
+ color: Color;
26
+ /**
27
+ * Height and text size, matching a Button of the same size.
28
+ * @default 'md'
29
+ */
30
+ size: Size;
31
+ /**
32
+ * Multiplies the height and padding, never the text.
33
+ * @default 'default'
34
+ */
35
+ density: Density;
36
+ /**
37
+ * Corner rounding. `true` keeps the theme's radius.
38
+ * @default true
39
+ */
40
+ rounded: Rounded;
41
+ /**
42
+ * Mutes the field and disables its control.
43
+ * @default false
44
+ */
45
+ disabled: boolean;
46
+ }
47
+ declare module '../../core/defaults/context.js' {
48
+ interface ComponentDefaults {
49
+ Field: FieldDefaults;
50
+ }
51
+ }
52
+ /** What a Field passes to the control it wraps. Spread it onto the control element. */
53
+ export interface FieldControlAttributes {
54
+ /** The id the label points at. */
55
+ id: string;
56
+ /** `sv-field__control`: fills the box and takes its text style. */
57
+ class: string;
58
+ /** The hint or the error, whichever is shown. */
59
+ 'aria-describedby': string | undefined;
60
+ /** Set while the field shows an error. */
61
+ 'aria-invalid': true | undefined;
62
+ required: boolean;
63
+ disabled: boolean;
64
+ readonly: boolean;
65
+ }
66
+ /** The props of a field's label, help and error, shared by every boxed field. */
67
+ export interface FieldContentProps {
68
+ /** The visible label, linked to the control. Without it, name the control with `aria-label`. */
69
+ label?: string;
70
+ /** Help under the field. An error replaces it. */
71
+ hint?: string;
72
+ /**
73
+ * An error from outside the field, such as the server's answer: a message, a list of which
74
+ * the first is shown, or `true` for an invalid state described elsewhere.
75
+ */
76
+ error?: FieldError;
77
+ /** Content at the start of the box, usually an icon. */
78
+ prepend?: Snippet;
79
+ /** Content at the end of the box: an icon, a unit or a button. */
80
+ append?: Snippet;
81
+ }
82
+ /**
83
+ * A label, a box for a control, and its hint or error. Wrap your own control in it: the
84
+ * children snippet receives the id, ARIA links and state to spread onto the control. Other
85
+ * attributes go to the root element.
86
+ *
87
+ * @example
88
+ * <Field label="Start date" hint="The first payment goes out on this day" required>
89
+ * {#snippet children(attributes)}
90
+ * <input type="date" name="start" {...attributes} bind:value={start} />
91
+ * {/snippet}
92
+ * </Field>
93
+ */
94
+ export type FieldProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<FieldDefaults> & FieldContentProps & {
95
+ /** The id of the control. Generated when not given. */
96
+ id?: string | null;
97
+ /**
98
+ * Adds an asterisk to the label. The control carries `required` itself.
99
+ * @default false
100
+ */
101
+ required?: boolean;
102
+ /**
103
+ * The control can be read and focused but not changed.
104
+ * @default false
105
+ */
106
+ readonly?: boolean;
107
+ /** The control. Spread the attributes it receives onto it. */
108
+ children: Snippet<[FieldControlAttributes]>;
109
+ }>;
@@ -0,0 +1,2 @@
1
+ /** The variants a boxed field takes, a subset of the shared `VARIANTS`. */
2
+ export const FIELD_VARIANTS = ['outlined', 'tonal', 'elevated', 'text', 'plain'];
@@ -0,0 +1,93 @@
1
+ <script lang="ts">
2
+ // A form that checks its fields on submit. See FormProps for the props.
3
+ import { flushSync } from 'svelte';
4
+ import DefaultsProvider from '../../core/defaults/DefaultsProvider.svelte';
5
+ import type { DefaultsConfig } from '../../core/defaults/context.js';
6
+ import { setFormContext, type FormField } from '../../core/form/context.js';
7
+ import './form.css';
8
+ import type { FormProps } from './types.js';
9
+
10
+ let {
11
+ validateOn,
12
+ disabled = false,
13
+ onsubmit,
14
+ onreset,
15
+ children,
16
+ class: className,
17
+ ref = $bindable(null),
18
+ ...rest
19
+ }: FormProps = $props();
20
+
21
+ // A registry, not state: nothing renders from it, so a plain Set rather than a SvelteSet.
22
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- never read reactively
23
+ const fields = new Set<FormField>();
24
+ setFormContext({
25
+ get validateOn() {
26
+ return validateOn;
27
+ },
28
+ register(field) {
29
+ fields.add(field);
30
+ return () => fields.delete(field);
31
+ }
32
+ });
33
+
34
+ // Always rendered, so turning `disabled` on and off never remounts the fields.
35
+ const defaults: DefaultsConfig = $derived(disabled ? { global: { disabled: true } } : {});
36
+
37
+ /** Shows the message of every field. Returns `true` when every field is valid. */
38
+ export function validate(): boolean {
39
+ let valid = true;
40
+ for (const field of fields) if (!field.validate()) valid = false;
41
+ return valid;
42
+ }
43
+
44
+ /** Puts every field back to the value it started with, and hides every message. */
45
+ export function reset(): void {
46
+ ref?.reset();
47
+ }
48
+
49
+ /** Hides every message and keeps the values. */
50
+ export function resetValidation(): void {
51
+ for (const field of fields) field.resetValidation();
52
+ }
53
+
54
+ function submit(event: SubmitEvent & { currentTarget: EventTarget & HTMLFormElement }) {
55
+ const invalid = [...fields].filter((field) => !field.validate());
56
+ if (invalid.length === 0) {
57
+ onsubmit?.(event);
58
+ return;
59
+ }
60
+ // Stop here, including listeners added later such as SvelteKit's enhance, which would
61
+ // otherwise send the form anyway.
62
+ event.preventDefault();
63
+ event.stopImmediatePropagation();
64
+ // Focus the first invalid control in document order, once its message is in the DOM, so
65
+ // its label and error are read out together.
66
+ flushSync();
67
+ const controls = invalid
68
+ .map((field) => field.control())
69
+ .filter((control): control is HTMLElement => control != null);
70
+ controls.sort((a, b) =>
71
+ a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
72
+ );
73
+ controls[0]?.focus();
74
+ }
75
+
76
+ function afterReset(event: Event & { currentTarget: EventTarget & HTMLFormElement }) {
77
+ resetValidation();
78
+ (onreset as ((event: Event) => void) | null | undefined)?.(event);
79
+ }
80
+ </script>
81
+
82
+ <form
83
+ bind:this={ref}
84
+ {...rest}
85
+ novalidate
86
+ class={['sv-form', className]}
87
+ onsubmit={submit}
88
+ onreset={afterReset}
89
+ >
90
+ <DefaultsProvider {defaults}>
91
+ {@render children?.()}
92
+ </DefaultsProvider>
93
+ </form>
@@ -0,0 +1,8 @@
1
+ import type { FormProps } from './types.js';
2
+ declare const Form: import("svelte").Component<FormProps, {
3
+ validate: () => boolean;
4
+ reset: () => void;
5
+ resetValidation: () => void;
6
+ }, "ref">;
7
+ type Form = ReturnType<typeof Form>;
8
+ export default Form;
@@ -0,0 +1,16 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /*
5
+ * Fields stack at one rhythm and take the full width; buttons keep their own width. A class
6
+ * on the form changes the layout, for example to a row for a search bar.
7
+ */
8
+ .sv-form {
9
+ display: grid;
10
+ gap: var(--sv-space-21);
11
+ }
12
+
13
+ .sv-form > :where(.sv-button) {
14
+ justify-self: start;
15
+ }
16
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Form } from './Form.svelte';
2
+ export type { FormProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Form } from './Form.svelte';
@@ -0,0 +1,38 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLFormAttributes } from 'svelte/elements';
3
+ import type { ValidateOn } from '../../core/form/types.js';
4
+ import type { ElementProps } from '../../core/props/element.js';
5
+ /**
6
+ * A `<form>` that checks its fields when it is submitted. An invalid form does not submit: every
7
+ * field shows its message and the first invalid one takes focus. A valid form calls `onsubmit`,
8
+ * or submits as HTML does when there is no `onsubmit`, so SvelteKit form actions work as they
9
+ * are. Other attributes go to the `<form>`. Through `bind:this` it offers `validate()`,
10
+ * `reset()` and `resetValidation()`.
11
+ *
12
+ * @example
13
+ * <Form method="POST" onsubmit={(event) => { event.preventDefault(); save(); }}>
14
+ * <TextField label="Email" name="email" type="email" required />
15
+ * <Button type="submit">Sign up</Button>
16
+ * </Form>
17
+ */
18
+ export type FormProps = ElementProps<HTMLFormElement, HTMLFormAttributes, {
19
+ /**
20
+ * When the fields show their messages, unless a field sets its own.
21
+ * @default 'blur'
22
+ */
23
+ validateOn?: ValidateOn;
24
+ /**
25
+ * Disables every control inside, Buttons included, for example while a submission runs.
26
+ * @default false
27
+ */
28
+ disabled?: boolean;
29
+ /**
30
+ * Called when the form is submitted and every field is valid. Without it, the form submits
31
+ * as HTML does; call `event.preventDefault()` to handle the submission yourself.
32
+ */
33
+ onsubmit?: (event: SubmitEvent & {
34
+ currentTarget: EventTarget & HTMLFormElement;
35
+ }) => void;
36
+ /** The fields and buttons. */
37
+ children?: Snippet;
38
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ // An icon from path data or any SVG of your own. See IconProps for the props.
3
+ import { sharedClasses } from '../../core/props/classes.js';
4
+ import './icon.css';
5
+ import type { IconProps } from './types.js';
6
+
7
+ let {
8
+ path,
9
+ viewBox = '0 0 24 24',
10
+ size,
11
+ color,
12
+ label,
13
+ children,
14
+ class: className,
15
+ ref = $bindable(null),
16
+ ...rest
17
+ }: IconProps = $props();
18
+ </script>
19
+
20
+ <span
21
+ bind:this={ref}
22
+ {...rest}
23
+ role={label ? 'img' : undefined}
24
+ aria-label={label}
25
+ aria-hidden={label ? undefined : 'true'}
26
+ class={[
27
+ 'sv-icon',
28
+ sharedClasses({ size, color }, 'Icon'),
29
+ color && 'sv-icon--colored',
30
+ className
31
+ ]}
32
+ >
33
+ {#if path}
34
+ <svg class="sv-icon__paths" {viewBox} aria-hidden="true"><path d={path} /></svg>
35
+ {:else}
36
+ {@render children?.()}
37
+ {/if}
38
+ </span>
@@ -0,0 +1,4 @@
1
+ import type { IconProps } from './types.js';
2
+ declare const Icon: import("svelte").Component<IconProps, {}, "ref">;
3
+ type Icon = ReturnType<typeof Icon>;
4
+ export default Icon;
@@ -0,0 +1,33 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* φ^½ of the text: the same proportion as icons in buttons. */
5
+ .sv-icon {
6
+ display: inline-flex;
7
+ flex: none;
8
+ align-items: center;
9
+ justify-content: center;
10
+ inline-size: 1.272em;
11
+ block-size: 1.272em;
12
+ line-height: 1;
13
+ vertical-align: -0.236em;
14
+ }
15
+
16
+ /* Only an icon with its own size reads the shared size; otherwise it follows its text. */
17
+ .sv-icon:is(.sv-size-xs, .sv-size-sm, .sv-size-md, .sv-size-lg, .sv-size-xl) {
18
+ font-size: var(--sv-size-text);
19
+ }
20
+
21
+ .sv-icon--colored {
22
+ color: var(--sv-color);
23
+ }
24
+
25
+ .sv-icon > svg {
26
+ inline-size: 100%;
27
+ block-size: 100%;
28
+ }
29
+
30
+ .sv-icon__paths {
31
+ fill: currentColor;
32
+ }
33
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Icon } from './Icon.svelte';
2
+ export type { IconProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Icon } from './Icon.svelte';
@@ -0,0 +1,34 @@
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
+ /**
6
+ * An icon: SVG path data, or any icon of your own as `children`. Decorative unless it has a
7
+ * `label`.
8
+ */
9
+ export type IconProps = ElementProps<HTMLSpanElement, HTMLAttributes<HTMLSpanElement>, {
10
+ /**
11
+ * SVG path data, filled with the current colour: the format of path-based icon sets such
12
+ * as Material Design Icons. Several shapes go in one string (`M… Z M… Z`).
13
+ */
14
+ path?: string;
15
+ /**
16
+ * The coordinate box of `path`.
17
+ * @default '0 0 24 24'
18
+ */
19
+ viewBox?: string;
20
+ /**
21
+ * The text size the icon is drawn at, φ^½ larger. Without it, the icon follows the text
22
+ * around it.
23
+ */
24
+ size?: Size;
25
+ /** The icon's colour. Without it, the icon takes the colour of the text around it. */
26
+ color?: Color;
27
+ /**
28
+ * A name for an icon that means something on its own, for assistive technology. Without
29
+ * it, the icon is decorative and hidden from it.
30
+ */
31
+ label?: string;
32
+ /** Any other icon (an `<svg>`, an icon component), sized and coloured like a path. */
33
+ children?: Snippet;
34
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ // A list of ListItems. See ListProps for the props.
3
+ import { useDefaults } from '../../core/defaults/context.js';
4
+ import { sharedClasses } from '../../core/props/classes.js';
5
+ import './list.css';
6
+ import type { ListDefaults, ListProps } from './types.js';
7
+
8
+ let {
9
+ density,
10
+ color,
11
+ nav,
12
+ children,
13
+ class: className,
14
+ ref = $bindable(null),
15
+ ...rest
16
+ }: ListProps = $props();
17
+
18
+ const resolve = useDefaults<ListDefaults>('List', {
19
+ density: 'default',
20
+ color: 'primary',
21
+ nav: false
22
+ });
23
+ const p = $derived(resolve({ density, color, nav }));
24
+ </script>
25
+
26
+ <!-- role="list": Safari drops the list semantics of a list without bullets. -->
27
+ <ul
28
+ bind:this={ref}
29
+ {...rest}
30
+ role="list"
31
+ class={[
32
+ 'sv-list',
33
+ sharedClasses({ density: p.density, color: p.color }, 'List'),
34
+ p.nav && 'sv-list--nav',
35
+ className
36
+ ]}
37
+ >
38
+ {@render children?.()}
39
+ </ul>
@@ -0,0 +1,4 @@
1
+ import type { ListProps } from './types.js';
2
+ declare const List: import("svelte").Component<ListProps, {}, "ref">;
3
+ type List = ReturnType<typeof List>;
4
+ export default List;