@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,85 @@
1
+ <script lang="ts">
2
+ // A button, or a link styled as one. See ButtonProps 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 '../../styles/visually-hidden.css';
7
+ import './button.css';
8
+ import type { ButtonDefaults, ButtonProps } from './types.js';
9
+
10
+ let {
11
+ variant,
12
+ size,
13
+ density,
14
+ color,
15
+ rounded,
16
+ block,
17
+ disabled,
18
+ as,
19
+ icon = false,
20
+ loading = false,
21
+ href,
22
+ type,
23
+ onclick,
24
+ 'aria-disabled': ariaDisabled,
25
+ prepend,
26
+ append,
27
+ children,
28
+ class: className,
29
+ ref = $bindable(null),
30
+ ...rest
31
+ }: ButtonProps = $props();
32
+
33
+ const resolve = useDefaults<ButtonDefaults>('Button', {
34
+ variant: 'flat',
35
+ size: 'md',
36
+ density: 'default',
37
+ color: 'primary',
38
+ rounded: true,
39
+ block: false,
40
+ disabled: false
41
+ });
42
+ const p = $derived(resolve({ variant, size, density, color, rounded, block, disabled }));
43
+ const locale = useLocale();
44
+
45
+ const link = $derived((as ?? (href == null ? 'button' : 'a')) === 'a');
46
+ // Only a <button> can be disabled natively. A disabled link loses its href; a loading button
47
+ // and one marked aria-disabled stay focusable. None of them takes presses.
48
+ const native = $derived(!link && p.disabled);
49
+ const inert = $derived(p.disabled || loading || ariaDisabled === true || ariaDisabled === 'true');
50
+
51
+ function click(event: MouseEvent) {
52
+ if (inert) event.preventDefault();
53
+ else (onclick as ((event: MouseEvent) => void) | null | undefined)?.(event);
54
+ }
55
+ </script>
56
+
57
+ <svelte:element
58
+ this={link ? 'a' : 'button'}
59
+ bind:this={ref}
60
+ {...rest}
61
+ href={link && !p.disabled ? href : undefined}
62
+ type={link ? undefined : (type ?? 'button')}
63
+ role={link && p.disabled ? 'link' : undefined}
64
+ disabled={native || undefined}
65
+ aria-disabled={(inert && !native) || undefined}
66
+ class={[
67
+ 'sv-button',
68
+ sharedClasses(p, 'Button'),
69
+ inert && 'sv-button--inert',
70
+ p.disabled && 'sv-button--disabled',
71
+ p.block && 'sv-button--block',
72
+ icon && 'sv-button--icon',
73
+ loading && 'sv-button--loading',
74
+ className
75
+ ]}
76
+ onclick={click}
77
+ >
78
+ {#if prepend}<span class="sv-button__prepend">{@render prepend()}</span>{/if}
79
+ {@render children?.()}
80
+ {#if append}<span class="sv-button__append">{@render append()}</span>{/if}
81
+ {#if loading}
82
+ <span class="sv-button__loader" aria-hidden="true"></span>
83
+ <span class="sv-visually-hidden">{locale.t('loading')}</span>
84
+ {/if}
85
+ </svelte:element>
@@ -0,0 +1,4 @@
1
+ import type { ButtonProps } from './types.js';
2
+ declare const Button: import("svelte").Component<ButtonProps, {}, "ref">;
3
+ type Button = ReturnType<typeof Button>;
4
+ export default Button;
@@ -0,0 +1,132 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /*
5
+ * Height and padding follow size and density; text follows size only. Colours come from
6
+ * the variant classes, which read the colour class.
7
+ */
8
+ .sv-button {
9
+ position: relative;
10
+ isolation: isolate;
11
+ display: inline-flex;
12
+ align-items: center;
13
+ justify-content: center;
14
+ gap: 0.618em;
15
+ box-sizing: border-box;
16
+ block-size: calc(var(--sv-size-height) * var(--sv-density));
17
+ margin: 0;
18
+ padding: 0 calc(var(--sv-size-height) * var(--sv-density) * 0.382);
19
+ border: var(--sv-hairline) solid var(--sv-variant-border);
20
+ border-radius: var(--sv-rounded, var(--sv-radius-md));
21
+ background-color: var(--sv-variant-bg);
22
+ box-shadow: var(--sv-variant-shadow);
23
+ color: var(--sv-variant-fg);
24
+ font: var(--sv-weight-medium) var(--sv-size-text) / 1 var(--sv-font-ui);
25
+ letter-spacing: var(--sv-button-tracking);
26
+ text-transform: var(--sv-button-transform);
27
+ text-decoration: none;
28
+ white-space: nowrap;
29
+ vertical-align: middle;
30
+ cursor: pointer;
31
+ user-select: none;
32
+ -webkit-tap-highlight-color: transparent;
33
+ transition: transform var(--sv-duration-fast) var(--sv-ease);
34
+ }
35
+
36
+ /* The theme's bevel: a hairline of light along the top edge of filled buttons. */
37
+ .sv-button.sv-variant-flat {
38
+ box-shadow: inset 0 var(--sv-hairline) 0 var(--sv-bevel);
39
+ }
40
+
41
+ /* State layer: the foreground colour over the background, only its opacity changes. */
42
+ .sv-button::before {
43
+ content: '';
44
+ position: absolute;
45
+ inset: calc(var(--sv-hairline) * -1);
46
+ z-index: -1;
47
+ border-radius: inherit;
48
+ background-color: currentColor;
49
+ opacity: 0;
50
+ pointer-events: none;
51
+ transition: opacity var(--sv-duration-fast) var(--sv-ease);
52
+ }
53
+
54
+ @media (hover: hover) {
55
+ .sv-button:where(:not(.sv-button--inert)):hover::before {
56
+ opacity: var(--sv-state-hover);
57
+ }
58
+ }
59
+
60
+ .sv-button:where(:not(.sv-button--inert)):active::before {
61
+ opacity: var(--sv-state-press);
62
+ }
63
+
64
+ .sv-button:where(:not(.sv-button--inert)):active {
65
+ transform: translateY(var(--sv-press-offset));
66
+ }
67
+
68
+ .sv-button--inert {
69
+ cursor: not-allowed;
70
+ }
71
+
72
+ /* Muted at φ⁻². A loading button keeps its colour: it is busy, not unavailable. */
73
+ .sv-button--disabled {
74
+ opacity: 0.382;
75
+ }
76
+
77
+ .sv-button--block {
78
+ display: flex;
79
+ inline-size: 100%;
80
+ }
81
+
82
+ .sv-button--icon {
83
+ inline-size: calc(var(--sv-size-height) * var(--sv-density));
84
+ padding: 0;
85
+ }
86
+
87
+ .sv-button__prepend,
88
+ .sv-button__append {
89
+ display: inline-flex;
90
+ }
91
+
92
+ /* Icons are φ^½ of the text. */
93
+ :where(.sv-button) svg {
94
+ inline-size: 1.272em;
95
+ block-size: 1.272em;
96
+ }
97
+
98
+ /*
99
+ * Loading: the label and icons turn transparent but keep their width and, for screen
100
+ * readers, the name. The spinner is painted in the foreground colour.
101
+ */
102
+ .sv-button--loading {
103
+ color: transparent;
104
+ cursor: wait;
105
+ }
106
+
107
+ .sv-button__loader {
108
+ position: absolute;
109
+ inset: 0;
110
+ box-sizing: border-box;
111
+ inline-size: 1.272em;
112
+ block-size: 1.272em;
113
+ margin: auto;
114
+ border: 0.146em solid var(--sv-variant-fg);
115
+ border-inline-end-color: transparent;
116
+ border-radius: 50%;
117
+ animation: sv-spin 987ms linear infinite;
118
+ }
119
+
120
+ /* A spinner that stops reads as a frozen interface, so it slows down instead. */
121
+ @media (prefers-reduced-motion: reduce) {
122
+ .sv-button__loader {
123
+ animation-duration: 2961ms;
124
+ }
125
+ }
126
+
127
+ @keyframes sv-spin {
128
+ to {
129
+ transform: rotate(1turn);
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Button } from './Button.svelte';
2
+ export type { ButtonDefaults, ButtonProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Button } from './Button.svelte';
@@ -0,0 +1,76 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAnchorAttributes, 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 Button props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
6
+ export interface ButtonDefaults {
7
+ /**
8
+ * Visual weight.
9
+ * @default 'flat'
10
+ */
11
+ variant: Variant;
12
+ /**
13
+ * Height and text size.
14
+ * @default 'md'
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 'primary'
25
+ */
26
+ color: Color;
27
+ /**
28
+ * Corner rounding. `true` keeps the theme's radius.
29
+ * @default true
30
+ */
31
+ rounded: Rounded;
32
+ /**
33
+ * Takes the full width of its container.
34
+ * @default false
35
+ */
36
+ block: boolean;
37
+ /**
38
+ * A disabled button cannot be focused or pressed; a disabled link loses its `href`.
39
+ * @default false
40
+ */
41
+ disabled: boolean;
42
+ }
43
+ declare module '../../core/defaults/context.js' {
44
+ interface ComponentDefaults {
45
+ Button: ButtonDefaults;
46
+ }
47
+ }
48
+ type ButtonOwnProps = Partial<ButtonDefaults> & {
49
+ /**
50
+ * The element to render. Defaults to `'a'` when `href` is given, otherwise `'button'`.
51
+ */
52
+ as?: 'button' | 'a';
53
+ /**
54
+ * Square, for a single icon as the content. Give it an `aria-label`.
55
+ * @default false
56
+ */
57
+ icon?: boolean;
58
+ /**
59
+ * Shows a spinner and ignores presses, while the button keeps focus and its label for
60
+ * screen readers, which also hear that it is loading.
61
+ * @default false
62
+ */
63
+ loading?: boolean;
64
+ /** Content before the label, usually an icon. */
65
+ prepend?: Snippet;
66
+ /** Content after the label, usually an icon. */
67
+ append?: Snippet;
68
+ /** The label. */
69
+ children?: Snippet;
70
+ };
71
+ /**
72
+ * A button, or a link that looks like one (`href`). Every other attribute of `<button>` and
73
+ * `<a>` passes through to the element.
74
+ */
75
+ export type ButtonProps = ElementProps<HTMLButtonElement | HTMLAnchorElement, HTMLButtonAttributes & HTMLAnchorAttributes, ButtonOwnProps>;
76
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ <script lang="ts">
2
+ // Buttons joined into one control. See ButtonGroupProps for the props.
3
+ import {
4
+ getDefaultsContext,
5
+ mergeDefaults,
6
+ setDefaultsContext,
7
+ useDefaults
8
+ } from '../../core/defaults/context.js';
9
+ import { sharedClasses } from '../../core/props/classes.js';
10
+ import './button-group.css';
11
+ import type { ButtonGroupDefaults, ButtonGroupProps } from './types.js';
12
+
13
+ let {
14
+ variant,
15
+ size,
16
+ density,
17
+ color,
18
+ rounded,
19
+ children,
20
+ class: className,
21
+ ref = $bindable(null),
22
+ ...rest
23
+ }: ButtonGroupProps = $props();
24
+
25
+ const resolve = useDefaults<ButtonGroupDefaults>('ButtonGroup', {
26
+ variant: 'outlined',
27
+ size: 'md',
28
+ density: 'default',
29
+ color: 'primary',
30
+ rounded: true
31
+ });
32
+ const p = $derived(resolve({ variant, size, density, color, rounded }));
33
+
34
+ // The Buttons inside take the group's props as their defaults, so their own props still win.
35
+ const parent = getDefaultsContext();
36
+ const merged = $derived(
37
+ mergeDefaults(parent?.config, {
38
+ Button: {
39
+ variant: p.variant,
40
+ size: p.size,
41
+ density: p.density,
42
+ color: p.color,
43
+ rounded: p.rounded
44
+ }
45
+ })
46
+ );
47
+ setDefaultsContext({
48
+ get config() {
49
+ return merged;
50
+ }
51
+ });
52
+ </script>
53
+
54
+ <div
55
+ bind:this={ref}
56
+ {...rest}
57
+ role="group"
58
+ class={['sv-button-group', sharedClasses({ rounded: p.rounded }, 'ButtonGroup'), className]}
59
+ >
60
+ {@render children?.()}
61
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ButtonGroupProps } from './types.js';
2
+ declare const ButtonGroup: import("svelte").Component<ButtonGroupProps, {}, "ref">;
3
+ type ButtonGroup = ReturnType<typeof ButtonGroup>;
4
+ export default ButtonGroup;
@@ -0,0 +1,39 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ .sv-button-group {
5
+ display: inline-flex;
6
+ isolation: isolate;
7
+ vertical-align: middle;
8
+ border-radius: var(--sv-rounded, var(--sv-radius-md));
9
+ }
10
+
11
+ /* Square inside; the group's own rounding on the outer corners. */
12
+ .sv-button-group > .sv-button {
13
+ border-radius: 0;
14
+ }
15
+
16
+ .sv-button-group > .sv-button:first-child {
17
+ border-start-start-radius: inherit;
18
+ border-end-start-radius: inherit;
19
+ }
20
+
21
+ .sv-button-group > .sv-button:last-child {
22
+ border-start-end-radius: inherit;
23
+ border-end-end-radius: inherit;
24
+ }
25
+
26
+ /* Neighbours share one border; the focused one is drawn on top. */
27
+ .sv-button-group > .sv-button + .sv-button {
28
+ margin-inline-start: calc(var(--sv-hairline) * -1);
29
+ }
30
+
31
+ .sv-button-group > .sv-button:focus-visible {
32
+ z-index: 1;
33
+ }
34
+
35
+ /* Filled and borderless buttons get a faint divider where they meet. */
36
+ .sv-button-group > .sv-button:not(.sv-variant-outlined) + .sv-button:not(.sv-variant-outlined) {
37
+ border-inline-start-color: color-mix(in oklch, var(--sv-variant-fg) 21%, transparent);
38
+ }
39
+ }
@@ -0,0 +1,2 @@
1
+ export { default as ButtonGroup } from './ButtonGroup.svelte';
2
+ export type { ButtonGroupDefaults, ButtonGroupProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as ButtonGroup } from './ButtonGroup.svelte';
@@ -0,0 +1,48 @@
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, Density, Rounded, Size, Variant } from '../../core/props/types.js';
5
+ /**
6
+ * The ButtonGroup props that `DefaultsProvider` and `UIProvider` can set for a subtree. The
7
+ * group passes them on to its Buttons.
8
+ */
9
+ export interface ButtonGroupDefaults {
10
+ /**
11
+ * The variant of the Buttons.
12
+ * @default 'outlined'
13
+ */
14
+ variant: Variant;
15
+ /**
16
+ * The size of the Buttons.
17
+ * @default 'md'
18
+ */
19
+ size: Size;
20
+ /**
21
+ * The density of the Buttons.
22
+ * @default 'default'
23
+ */
24
+ density: Density;
25
+ /**
26
+ * The colour of the Buttons.
27
+ * @default 'primary'
28
+ */
29
+ color: Color;
30
+ /**
31
+ * The rounding of the group's outer corners; inner corners are square.
32
+ * @default true
33
+ */
34
+ rounded: Rounded;
35
+ }
36
+ declare module '../../core/defaults/context.js' {
37
+ interface ComponentDefaults {
38
+ ButtonGroup: ButtonGroupDefaults;
39
+ }
40
+ }
41
+ /**
42
+ * Buttons joined into one control: shared borders, square inner corners, and the same
43
+ * variant, size, density and colour unless a Button says otherwise. Give it an `aria-label`.
44
+ */
45
+ export type ButtonGroupProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<ButtonGroupDefaults> & {
46
+ /** The Buttons. */
47
+ children?: Snippet;
48
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ // A surface with a header, content and actions. See CardProps for the props.
3
+ import { useDefaults } from '../../core/defaults/context.js';
4
+ import { sharedClasses } from '../../core/props/classes.js';
5
+ import './card.css';
6
+ import type { CardDefaults, CardProps } from './types.js';
7
+
8
+ let {
9
+ variant,
10
+ color,
11
+ density,
12
+ rounded,
13
+ title,
14
+ subtitle,
15
+ level,
16
+ prepend,
17
+ append,
18
+ actions,
19
+ children,
20
+ class: className,
21
+ ref = $bindable(null),
22
+ ...rest
23
+ }: CardProps = $props();
24
+
25
+ const resolve = useDefaults<CardDefaults>('Card', {
26
+ variant: 'elevated',
27
+ color: 'neutral',
28
+ density: 'default',
29
+ rounded: true
30
+ });
31
+ const p = $derived(resolve({ variant, color, density, rounded }));
32
+ </script>
33
+
34
+ <div bind:this={ref} {...rest} class={['sv-card', sharedClasses(p, 'Card'), className]}>
35
+ {#if title || subtitle || prepend || append}
36
+ <div class="sv-card__header">
37
+ {#if prepend}<div class="sv-card__prepend">{@render prepend()}</div>{/if}
38
+ {#if title || subtitle}
39
+ <div class="sv-card__heading">
40
+ {#if title}
41
+ <svelte:element this={level ? `h${level}` : 'div'} class="sv-card__title">
42
+ {title}
43
+ </svelte:element>
44
+ {/if}
45
+ {#if subtitle}<div class="sv-card__subtitle">{subtitle}</div>{/if}
46
+ </div>
47
+ {/if}
48
+ {#if append}<div class="sv-card__append">{@render append()}</div>{/if}
49
+ </div>
50
+ {/if}
51
+ {@render children?.()}
52
+ {#if actions}<div class="sv-card__actions">{@render actions()}</div>{/if}
53
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { CardProps } from './types.js';
2
+ declare const Card: import("svelte").Component<CardProps, {}, "ref">;
3
+ type Card = ReturnType<typeof Card>;
4
+ export default Card;
@@ -0,0 +1,62 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* Sections a φ step apart inside Fibonacci padding, both times the density. */
5
+ .sv-card {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: calc(var(--sv-space-13) * var(--sv-density));
9
+ box-sizing: border-box;
10
+ min-inline-size: 0;
11
+ padding: calc(var(--sv-space-21) * var(--sv-density));
12
+ border: var(--sv-hairline) solid var(--sv-variant-border);
13
+ border-radius: var(--sv-rounded, var(--sv-radius-lg));
14
+ background-color: var(--sv-variant-bg);
15
+ box-shadow: var(--sv-variant-shadow);
16
+ color: var(--sv-variant-fg);
17
+ font-size: var(--sv-text-sm);
18
+ line-height: var(--sv-leading-normal);
19
+ }
20
+
21
+ /* A neutral outline is the theme's border, not the text colour. */
22
+ .sv-card.sv-variant-outlined.sv-color-neutral {
23
+ --sv-variant-border: var(--sv-color-border);
24
+ }
25
+
26
+ .sv-card__header {
27
+ display: flex;
28
+ gap: var(--sv-space-13);
29
+ align-items: center;
30
+ }
31
+
32
+ .sv-card__heading {
33
+ display: grid;
34
+ flex: 1;
35
+ gap: var(--sv-space-3);
36
+ min-inline-size: 0;
37
+ }
38
+
39
+ .sv-card__title {
40
+ margin: 0;
41
+ font: var(--sv-weight-display) var(--sv-text-lg) / var(--sv-leading-snug) var(--sv-font-display);
42
+ letter-spacing: var(--sv-tracking-display);
43
+ }
44
+
45
+ .sv-card__subtitle {
46
+ font-size: var(--sv-text-xs);
47
+ }
48
+
49
+ .sv-card__prepend,
50
+ .sv-card__append {
51
+ display: flex;
52
+ flex: none;
53
+ align-items: center;
54
+ }
55
+
56
+ .sv-card__actions {
57
+ display: flex;
58
+ flex-wrap: wrap;
59
+ gap: var(--sv-space-8);
60
+ align-items: center;
61
+ }
62
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Card } from './Card.svelte';
2
+ export type { CardDefaults, CardProps } from './types.js';
@@ -0,0 +1 @@
1
+ export { default as Card } from './Card.svelte';
@@ -0,0 +1,56 @@
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, Density, Rounded, Variant } from '../../core/props/types.js';
5
+ /** The Card props that `DefaultsProvider` and `UIProvider` can set for a subtree. */
6
+ export interface CardDefaults {
7
+ /**
8
+ * Visual weight: a raised surface by default.
9
+ * @default 'elevated'
10
+ */
11
+ variant: Variant;
12
+ /**
13
+ * The colour the variant is painted with. Neutral cards use the theme's surface, text and
14
+ * border colours.
15
+ * @default 'neutral'
16
+ */
17
+ color: Color;
18
+ /**
19
+ * Multiplies the padding and the space between sections.
20
+ * @default 'default'
21
+ */
22
+ density: Density;
23
+ /**
24
+ * Corner rounding. `true` keeps the theme's radius.
25
+ * @default true
26
+ */
27
+ rounded: Rounded;
28
+ }
29
+ declare module '../../core/defaults/context.js' {
30
+ interface ComponentDefaults {
31
+ Card: CardDefaults;
32
+ }
33
+ }
34
+ /**
35
+ * A surface that groups content about one thing: a header, the content and actions. Links
36
+ * and buttons inside it are what is clickable, not the card.
37
+ */
38
+ export type CardProps = ElementProps<HTMLDivElement, HTMLAttributes<HTMLDivElement>, Partial<CardDefaults> & {
39
+ /** The title, in the header. */
40
+ title?: string;
41
+ /** A line under the title. */
42
+ subtitle?: string;
43
+ /**
44
+ * Makes the title a heading of this level (`<h2>`, `<h3>`…), so it is in the page's
45
+ * outline. Without it the title is styled text.
46
+ */
47
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
48
+ /** Content before the title, such as an avatar or an icon. */
49
+ prepend?: Snippet;
50
+ /** Content after the title, such as a menu button. */
51
+ append?: Snippet;
52
+ /** Buttons or links at the bottom. */
53
+ actions?: Snippet;
54
+ /** The content. */
55
+ children?: Snippet;
56
+ }>;
@@ -0,0 +1 @@
1
+ export {};