@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,54 @@
1
+ // Minimal oklch maths: enough to pick readable "on" colours and to check WCAG contrast.
2
+ // Conversion from Björn Ottosson's OKLab reference (https://bottosson.github.io/posts/oklab/).
3
+ const OKLCH = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*(?:\/\s*([\d.]+)(%?))?\s*\)$/i;
4
+ /** Parses `oklch(L C H)` or `oklch(L C H / A)` with numbers or percentages. */
5
+ export function parseOklch(value) {
6
+ const match = OKLCH.exec(value.trim());
7
+ if (!match)
8
+ return undefined;
9
+ const [, l = '0', lPct, c = '0', cPct, h = '0', a, aPct] = match;
10
+ return {
11
+ l: lPct ? +l / 100 : +l,
12
+ c: cPct ? (+c / 100) * 0.4 : +c,
13
+ h: +h,
14
+ alpha: a === undefined ? 1 : aPct ? +a / 100 : +a
15
+ };
16
+ }
17
+ const clamp01 = (value) => Math.min(1, Math.max(0, value));
18
+ /** Linear-light sRGB channels, clamped to the sRGB gamut. */
19
+ export function toLinearSrgb({ l, c, h }) {
20
+ const rad = (h * Math.PI) / 180;
21
+ const a = c * Math.cos(rad);
22
+ const b = c * Math.sin(rad);
23
+ const l3 = (l + 0.3963377774 * a + 0.2158037573 * b) ** 3;
24
+ const m3 = (l - 0.1055613458 * a - 0.0638541728 * b) ** 3;
25
+ const s3 = (l - 0.0894841775 * a - 1.291485548 * b) ** 3;
26
+ return [
27
+ clamp01(4.0767416621 * l3 - 3.3077115913 * m3 + 0.2309699292 * s3),
28
+ clamp01(-1.2684380046 * l3 + 2.6097574011 * m3 - 0.3413193965 * s3),
29
+ clamp01(-0.0041960863 * l3 - 0.7034186147 * m3 + 1.707614701 * s3)
30
+ ];
31
+ }
32
+ /** WCAG relative luminance of an opaque colour. */
33
+ export function luminance(color) {
34
+ const [r, g, b] = toLinearSrgb(color);
35
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
36
+ }
37
+ /** WCAG 2 contrast ratio between two opaque oklch colours (1–21). */
38
+ export function contrast(a, b) {
39
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
40
+ return (hi + 0.05) / (lo + 0.05);
41
+ }
42
+ const format = ({ l, c, h }) => `oklch(${l} ${c} ${h})`;
43
+ /**
44
+ * Picks a readable text colour for a filled background: a deep ink or a near-white, both
45
+ * tinted with the background's hue, whichever contrasts more.
46
+ */
47
+ export function onColor(background) {
48
+ const bg = parseOklch(background);
49
+ if (!bg)
50
+ return undefined;
51
+ const dark = { l: 0.2, c: 0.02, h: bg.h, alpha: 1 };
52
+ const light = { l: 0.985, c: 0.005, h: bg.h, alpha: 1 };
53
+ return format(contrast(bg, dark) >= contrast(bg, light) ? dark : light);
54
+ }
@@ -0,0 +1,25 @@
1
+ import type { ThemeChoice, ThemeDefinition } from './types.js';
2
+ /** The nearest `<ThemeProvider>`, as seen by `useTheme()`. All fields are reactive. */
3
+ export interface ThemeInstance {
4
+ /** "system" or a theme name. */
5
+ readonly choice: ThemeChoice;
6
+ /**
7
+ * The theme in effect. With "system" it follows `prefers-color-scheme`; during server
8
+ * rendering, where the preference is unknown, it is the `light` theme.
9
+ */
10
+ readonly name: string;
11
+ readonly current: ThemeDefinition;
12
+ readonly isDark: boolean;
13
+ readonly themes: Readonly<Record<string, ThemeDefinition>>;
14
+ /** Theme names that "system" and `toggle()` switch between. */
15
+ readonly light: string;
16
+ readonly dark: string;
17
+ /** Selects a theme name or "system". The root provider remembers it. */
18
+ set(choice: ThemeChoice): void;
19
+ /** Switches between the `light` and `dark` themes. */
20
+ toggle(): void;
21
+ }
22
+ export declare const hasThemeContext: () => boolean;
23
+ export declare const setThemeContext: (theme: ThemeInstance) => ThemeInstance;
24
+ /** Returns the nearest theme. Must be called during component initialisation. */
25
+ export declare function useTheme(): ThemeInstance;
@@ -0,0 +1,14 @@
1
+ import { getContext, hasContext, setContext } from 'svelte';
2
+ import { sveltierError } from '../errors/errors.js';
3
+ // A private symbol key instead of createContext(): its `has` function only exists from
4
+ // Svelte 5.57, and the supported range starts at 5.40.
5
+ const KEY = Symbol('sveltier.theme');
6
+ export const hasThemeContext = () => hasContext(KEY);
7
+ export const setThemeContext = (theme) => setContext(KEY, theme);
8
+ /** Returns the nearest theme. Must be called during component initialisation. */
9
+ export function useTheme() {
10
+ if (!hasContext(KEY)) {
11
+ throw sveltierError('SV1007', 'useTheme() was called outside a <ThemeProvider>. Call it in a component inside <UIProvider> or <ThemeProvider>.');
12
+ }
13
+ return getContext(KEY);
14
+ }
@@ -0,0 +1,25 @@
1
+ import type { ThemeChoice, ThemeDefinition } from './types.js';
2
+ export declare const THEME_ATTRIBUTE = "data-sv-theme";
3
+ export interface ThemeCssOptions {
4
+ themes: Record<string, ThemeDefinition>;
5
+ /** Theme used by "system" when the OS prefers light. */
6
+ light: string;
7
+ /** Theme used by "system" when the OS prefers dark. */
8
+ dark: string;
9
+ /** What `<html>` shows before any attribute is set (no JavaScript, nothing stored). */
10
+ fallback: ThemeChoice;
11
+ }
12
+ /**
13
+ * One stylesheet for every theme, keyed by `data-sv-theme`. "system" is pure CSS
14
+ * (`prefers-color-scheme`), so the right theme paints before any JavaScript runs.
15
+ * It also holds a `.sv-color-<name>` class for every colour with an `on-` colour (intents
16
+ * and custom colours), which a component's `color` prop sets.
17
+ */
18
+ export declare function themeCss({ themes, light, dark, fallback }: ThemeCssOptions): string;
19
+ /**
20
+ * Render-blocking script for `<head>`: applies a stored choice to `<html>` before the body
21
+ * is parsed, if it is one of `choices`. Exposed so a Content Security Policy can hash it.
22
+ */
23
+ export declare function themeScript(storageKey: string, choices: string[]): string;
24
+ /** Markup for `<svelte:head>`: the theme stylesheet, then the optional script. */
25
+ export declare function themeHead(css: string, script: string, nonce?: string): string;
@@ -0,0 +1,73 @@
1
+ import { sveltierError } from '../errors/errors.js';
2
+ export const THEME_ATTRIBUTE = 'data-sv-theme';
3
+ const NAME = /^(?!system$)[a-z][\w-]*$/i;
4
+ const KEY = /^[a-z][\w-]*$/i;
5
+ const UNSAFE = /[<>{};]/;
6
+ const NONCE = /^[\w+/=-]+$/;
7
+ function check(ok, code, message) {
8
+ if (!ok)
9
+ throw sveltierError(code, message);
10
+ }
11
+ /** `{color-scheme:…;--sv-color-scrim:…;--sv-color-x:…;--sv-on-x:…;--sv-var:…}` for one theme. */
12
+ function block(theme, name, registered) {
13
+ check(theme, 'SV1002', `Unknown theme "${name}". Registered: ${registered}.`);
14
+ // The veil behind modal layers: the theme's ink over a light theme, its background over a
15
+ // dark one. Written here, where the mode is known: bundlers rewrite CSS light-dark() into
16
+ // variables that only their own color-scheme rules set, and these themes are set at runtime.
17
+ const scrim = theme.dark ? 'var(--sv-color-background) 61.8%' : 'var(--sv-color-text) 38.2%';
18
+ let out = `color-scheme:${theme.dark ? 'dark' : 'light'};--sv-color-scrim:color-mix(in oklch,${scrim},transparent)`;
19
+ const entries = [
20
+ ...Object.entries(theme.colors).map(([k, v]) => [k.startsWith('on-') ? k : `color-${k}`, v]),
21
+ ...Object.entries(theme.variables)
22
+ ];
23
+ for (const [key, value] of entries) {
24
+ check(KEY.test(key), 'SV1003', `Invalid colour or variable name "${key}". Use letters, digits, - and _, starting with a letter.`);
25
+ check(!UNSAFE.test(String(value)), 'SV1004', `Unsafe value for "${key}": it contains <, >, {, } or ;. Use a plain CSS value.`);
26
+ out += `;--sv-${key}:${value}`;
27
+ }
28
+ return `{${out}}`;
29
+ }
30
+ /**
31
+ * One stylesheet for every theme, keyed by `data-sv-theme`. "system" is pure CSS
32
+ * (`prefers-color-scheme`), so the right theme paints before any JavaScript runs.
33
+ * It also holds a `.sv-color-<name>` class for every colour with an `on-` colour (intents
34
+ * and custom colours), which a component's `color` prop sets.
35
+ */
36
+ export function themeCss({ themes, light, dark, fallback }) {
37
+ const attr = (name) => `[${THEME_ATTRIBUTE}="${name}"]`;
38
+ const bare = `:root:not([${THEME_ATTRIBUTE}])`;
39
+ const system = attr('system') + (fallback === 'system' ? `,${bare}` : '');
40
+ const colors = new Set();
41
+ const registered = Object.keys(themes).join(', ');
42
+ let css = '';
43
+ for (const [name, theme] of Object.entries(themes)) {
44
+ check(NAME.test(name), 'SV1005', `Invalid theme name "${name}". Use letters, digits, - and _, starting with a letter; "system" is reserved.`);
45
+ css += attr(name) + block(theme, name, registered);
46
+ for (const key in theme.colors)
47
+ if (key.startsWith('on-'))
48
+ colors.add(key.slice(3));
49
+ }
50
+ css += `@media (prefers-color-scheme:light){${system}${block(themes[light], light, registered)}}`;
51
+ css += `@media (prefers-color-scheme:dark){${system}${block(themes[dark], dark, registered)}}`;
52
+ if (fallback !== 'system')
53
+ css += bare + block(themes[fallback], fallback, registered);
54
+ let classes = '';
55
+ for (const color of colors) {
56
+ classes += `.sv-color-${color}{--sv-color:var(--sv-color-${color});--sv-on-color:var(--sv-on-${color})}`;
57
+ }
58
+ return `@layer sv.tokens,sv.base,sv.components,sv.utilities;@layer sv.tokens{${css}}@layer sv.base{${classes}}`;
59
+ }
60
+ /**
61
+ * Render-blocking script for `<head>`: applies a stored choice to `<html>` before the body
62
+ * is parsed, if it is one of `choices`. Exposed so a Content Security Policy can hash it.
63
+ */
64
+ export function themeScript(storageKey, choices) {
65
+ const json = (data) => JSON.stringify(data).replace(/</g, '\\u003c');
66
+ return `(function(){try{var t=localStorage.getItem(${json(storageKey)});if(${json(choices)}.indexOf(t)>-1)document.documentElement.setAttribute("${THEME_ATTRIBUTE}",t)}catch(e){}})()`;
67
+ }
68
+ /** Markup for `<svelte:head>`: the theme stylesheet, then the optional script. */
69
+ export function themeHead(css, script, nonce) {
70
+ check(nonce === undefined || NONCE.test(nonce), 'SV1006', 'Invalid nonce. Pass the base64 nonce of your Content Security Policy as it is.');
71
+ const attr = nonce ? ` nonce="${nonce}"` : '';
72
+ return `<style id="sv-theme"${attr}>${css}</style>${script && `<script${attr}>${script}</script>`}`;
73
+ }
@@ -0,0 +1,11 @@
1
+ import type { ThemeDefinition, ThemeInput } from './types.js';
2
+ /**
3
+ * Builds a complete theme from the parts you change over `base`, the theme you extend.
4
+ * Missing colours and variables come from `base`. `on-` colours are recomputed for every
5
+ * colour you override, unless you pass them yourself. `base` is never mutated.
6
+ *
7
+ * @example
8
+ * import { monolithDark } from '@sveltier/ui/themes/monolith';
9
+ * const midnight = defineTheme({ colors: { primary: 'oklch(0.78 0.11 260)' } }, monolithDark);
10
+ */
11
+ export declare function defineTheme(input: ThemeInput, base: ThemeDefinition): ThemeDefinition;
@@ -0,0 +1,21 @@
1
+ import { withOnColors } from './resolve.js';
2
+ /**
3
+ * Builds a complete theme from the parts you change over `base`, the theme you extend.
4
+ * Missing colours and variables come from `base`. `on-` colours are recomputed for every
5
+ * colour you override, unless you pass them yourself. `base` is never mutated.
6
+ *
7
+ * @example
8
+ * import { monolithDark } from '@sveltier/ui/themes/monolith';
9
+ * const midnight = defineTheme({ colors: { primary: 'oklch(0.78 0.11 260)' } }, monolithDark);
10
+ */
11
+ export function defineTheme(input, base) {
12
+ const overrides = input.colors ?? {};
13
+ const colors = { ...base.colors };
14
+ for (const name of Object.keys(overrides))
15
+ delete colors[`on-${name}`];
16
+ return withOnColors({
17
+ dark: input.dark ?? base.dark,
18
+ colors: { ...colors, ...overrides },
19
+ variables: { ...base.variables, ...input.variables }
20
+ });
21
+ }
@@ -0,0 +1,6 @@
1
+ import { type ThemeDefinition } from './types.js';
2
+ /**
3
+ * Returns a copy of the theme where every non-neutral colour without an explicit `on-`
4
+ * colour gets a computed one (a deep ink or a near-white, whichever contrasts more).
5
+ */
6
+ export declare function withOnColors(theme: ThemeDefinition): ThemeDefinition;
@@ -0,0 +1,18 @@
1
+ import { onColor } from './color.js';
2
+ import { NEUTRAL_COLORS } from './types.js';
3
+ const NEUTRAL = new Set(NEUTRAL_COLORS);
4
+ /**
5
+ * Returns a copy of the theme where every non-neutral colour without an explicit `on-`
6
+ * colour gets a computed one (a deep ink or a near-white, whichever contrasts more).
7
+ */
8
+ export function withOnColors(theme) {
9
+ const colors = { ...theme.colors };
10
+ for (const [name, value] of Object.entries(theme.colors)) {
11
+ if (NEUTRAL.has(name) || name.startsWith('on-') || colors[`on-${name}`])
12
+ continue;
13
+ const on = onColor(value);
14
+ if (on)
15
+ colors[`on-${name}`] = on;
16
+ }
17
+ return { ...theme, colors };
18
+ }
@@ -0,0 +1,13 @@
1
+ @layer sv.tokens, sv.base, sv.components, sv.utilities;
2
+
3
+ @layer sv.components {
4
+ /* A theme scope only re-declares custom properties, which inherit through display: contents. */
5
+ .sv-theme-provider {
6
+ display: contents;
7
+ }
8
+
9
+ .sv-theme-provider--background {
10
+ display: block;
11
+ background-color: var(--sv-color-background);
12
+ }
13
+ }
@@ -0,0 +1,35 @@
1
+ /** Neutral roles: page, surfaces, rules and text. They have no `on-` colour. */
2
+ export declare const NEUTRAL_COLORS: readonly ["background", "surface", "surface-raised", "border", "border-soft", "border-strong", "text", "text-muted", "text-subtle"];
3
+ /**
4
+ * Intent colours, usable as a component's `color`. Each gets an `on-` colour for text on a
5
+ * filled background. `up` / `down` are price direction and are kept separate from
6
+ * `success` / `error`, because some markets show rising prices in red.
7
+ */
8
+ export declare const INTENT_COLORS: readonly ["primary", "success", "warning", "error", "info", "up", "down"];
9
+ export type NeutralColor = (typeof NEUTRAL_COLORS)[number];
10
+ export type IntentColor = (typeof INTENT_COLORS)[number];
11
+ /** Every colour value is an `oklch()` string. */
12
+ export type ThemeColors = Record<NeutralColor | IntentColor, string> & Partial<Record<`on-${IntentColor}`, string>> & Record<string, string>;
13
+ /**
14
+ * The theme contract: every theme sets all of these, so one theme switch restyles type,
15
+ * shape, depth and motion as well as colour. Emitted as `--sv-<name>`.
16
+ */
17
+ export declare const THEME_VARIABLES: readonly ["font-display", "font-ui", "font-data", "weight-display", "tracking-display", "label-size", "label-transform", "label-tracking", "button-transform", "button-tracking", "radius-sm", "radius-md", "radius-lg", "radius-xl", "radius-full", "surface-alpha", "surface-blur", "backdrop", "ornament", "bevel", "shadow", "ease", "duration-fast", "duration-normal", "duration-slow"];
18
+ export type ThemeVariable = (typeof THEME_VARIABLES)[number];
19
+ export type ThemeVariables = Record<ThemeVariable, string | number>;
20
+ export interface ThemeDefinition {
21
+ /** Dark themes set `color-scheme: dark` and are the `dark` target of "system". */
22
+ dark: boolean;
23
+ /** Emitted as `--sv-color-<name>`, and `on-<name>` keys as `--sv-on-<name>`. */
24
+ colors: ThemeColors;
25
+ /** The theme contract plus any extra custom properties, emitted as `--sv-<name>`. */
26
+ variables: ThemeVariables & Record<string, string | number>;
27
+ }
28
+ /** Partial theme accepted by `defineTheme()`; missing values come from the base theme. */
29
+ export interface ThemeInput {
30
+ dark?: boolean;
31
+ colors?: Partial<ThemeColors>;
32
+ variables?: Partial<ThemeVariables> & Record<string, string | number>;
33
+ }
34
+ /** A user choice: a theme name, or "system" to follow `prefers-color-scheme`. */
35
+ export type ThemeChoice = 'system' | (string & {});
@@ -0,0 +1,61 @@
1
+ /** Neutral roles: page, surfaces, rules and text. They have no `on-` colour. */
2
+ export const NEUTRAL_COLORS = [
3
+ 'background',
4
+ 'surface',
5
+ 'surface-raised',
6
+ 'border',
7
+ 'border-soft',
8
+ 'border-strong',
9
+ 'text',
10
+ 'text-muted',
11
+ 'text-subtle'
12
+ ];
13
+ /**
14
+ * Intent colours, usable as a component's `color`. Each gets an `on-` colour for text on a
15
+ * filled background. `up` / `down` are price direction and are kept separate from
16
+ * `success` / `error`, because some markets show rising prices in red.
17
+ */
18
+ export const INTENT_COLORS = [
19
+ 'primary',
20
+ 'success',
21
+ 'warning',
22
+ 'error',
23
+ 'info',
24
+ 'up',
25
+ 'down'
26
+ ];
27
+ /**
28
+ * The theme contract: every theme sets all of these, so one theme switch restyles type,
29
+ * shape, depth and motion as well as colour. Emitted as `--sv-<name>`.
30
+ */
31
+ export const THEME_VARIABLES = [
32
+ // Type
33
+ 'font-display',
34
+ 'font-ui',
35
+ 'font-data',
36
+ 'weight-display',
37
+ 'tracking-display',
38
+ 'label-size',
39
+ 'label-transform',
40
+ 'label-tracking',
41
+ 'button-transform',
42
+ 'button-tracking',
43
+ // Shape
44
+ 'radius-sm',
45
+ 'radius-md',
46
+ 'radius-lg',
47
+ 'radius-xl',
48
+ 'radius-full',
49
+ // Depth
50
+ 'surface-alpha',
51
+ 'surface-blur',
52
+ 'backdrop',
53
+ 'ornament',
54
+ 'bevel',
55
+ 'shadow',
56
+ // Motion (collapsed to near zero when the user prefers reduced motion)
57
+ 'ease',
58
+ 'duration-fast',
59
+ 'duration-normal',
60
+ 'duration-slow'
61
+ ];
@@ -0,0 +1,192 @@
1
+ <script lang="ts">
2
+ // Where the toasts show: the region in the top layer and the live regions that read them
3
+ // out. The provider renders one at the end of the page, and the modal shell one inside each
4
+ // open dialog; only the topmost outlet shows the toasts.
5
+ import { flip } from 'svelte/animate';
6
+ import { on } from 'svelte/events';
7
+ import { easing, fade, motion, rise } from '../../primitives/motion/motion.js';
8
+ import '../../styles/visually-hidden.css';
9
+ import { useLocale } from '../locale/locale.js';
10
+ import { sharedClasses } from '../props/classes.js';
11
+ import './toast.css';
12
+ import type { ToastEntry, Toasts } from './toast.svelte.js';
13
+
14
+ let {
15
+ toasts,
16
+ outlet,
17
+ ref = $bindable(null)
18
+ }: {
19
+ toasts: Toasts;
20
+ /** This outlet's token, which the toasts compare with their topmost outlet. */
21
+ outlet: object;
22
+ /** The region, which a dialog counts as inside itself. */
23
+ ref?: HTMLElement | null;
24
+ } = $props();
25
+
26
+ const locale = useLocale();
27
+ const top = $derived(toasts.top === outlet);
28
+ const style = $derived(toasts.style);
29
+ const notes = $derived(top ? toasts.announcements : []);
30
+
31
+ const CLOSE =
32
+ 'M6.4 5 12 10.6 17.6 5 19 6.4 13.4 12l5.6 5.6-1.4 1.4-5.6-5.6L6.4 19 5 17.6l5.6-5.6L5 6.4z';
33
+
34
+ // The region joins the top layer when it starts showing toasts, and again each time it
35
+ // becomes the topmost outlet, so it sits above whatever opened before. Emptied, it stays,
36
+ // which lets the last toast fade out.
37
+ const showing = $derived(top && toasts.list.length > 0);
38
+ $effect(() => {
39
+ if (!showing || !ref) return;
40
+ if (ref.matches(':popover-open')) ref.hidePopover();
41
+ ref.showPopover();
42
+ });
43
+
44
+ // The timers wait while the pointer or focus is on the toasts.
45
+ const hover = {};
46
+ const focus = {};
47
+ $effect(() => {
48
+ if (!top) return;
49
+ return () => {
50
+ toasts.resume(hover);
51
+ toasts.resume(focus);
52
+ };
53
+ });
54
+
55
+ // Where focus goes back to when the user leaves the toasts.
56
+ let back: HTMLElement | null = null;
57
+
58
+ // F8 moves focus to the toasts, the way to reach an action before its toast leaves; Escape
59
+ // in them goes back to where focus came from. Captured, so the layer stack never sees that
60
+ // Escape and an open dialog stays open.
61
+ $effect(() => {
62
+ if (!top) return;
63
+ return on(document, 'keydown', onkey, { capture: true });
64
+ });
65
+
66
+ function onkey(event: KeyboardEvent) {
67
+ if (!ref) return;
68
+ const inside = ref.contains(document.activeElement);
69
+ if (event.key === 'Escape') {
70
+ if (!inside || !back?.isConnected) return;
71
+ event.preventDefault();
72
+ goBack();
73
+ return;
74
+ }
75
+ const plain = !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
76
+ if (event.key !== 'F8' || !plain || toasts.list.length === 0) return;
77
+ event.preventDefault();
78
+ if (!inside) back = focused(document.activeElement);
79
+ ref.focus();
80
+ }
81
+
82
+ const focused = (element: unknown) =>
83
+ element instanceof HTMLElement && element !== document.body ? element : null;
84
+
85
+ function enter(event: FocusEvent) {
86
+ toasts.pause(focus);
87
+ if (!ref?.contains(event.relatedTarget as Node | null)) {
88
+ back = focused(event.relatedTarget) ?? back;
89
+ }
90
+ }
91
+
92
+ function exit(event: FocusEvent) {
93
+ if (!(event.relatedTarget instanceof Node && ref?.contains(event.relatedTarget))) {
94
+ toasts.resume(focus);
95
+ }
96
+ }
97
+
98
+ function goBack() {
99
+ if (back?.isConnected) back.focus();
100
+ back = null;
101
+ }
102
+
103
+ // A toast that closes with focus in it hands focus on first: to the toasts left, else back.
104
+ function leave() {
105
+ if (!ref?.contains(document.activeElement)) return;
106
+ if (toasts.list.length > 1) ref.focus();
107
+ else goBack();
108
+ }
109
+
110
+ function act(toast: ToastEntry) {
111
+ leave();
112
+ try {
113
+ toast.action?.onclick();
114
+ } finally {
115
+ toasts.dismiss(toast.id);
116
+ }
117
+ }
118
+
119
+ function close(toast: ToastEntry) {
120
+ leave();
121
+ toasts.dismiss(toast.id);
122
+ }
123
+
124
+ // Toasts below one that leaves move into its place with the theme's timing.
125
+ function move(node: Element, rects: { from: DOMRect; to: DOMRect }) {
126
+ const timing = motion(node);
127
+ return flip(node, rects, { duration: timing.normal, easing: easing(timing.ease) });
128
+ }
129
+ </script>
130
+
131
+ <!-- Read out once each, then emptied: the toasts themselves are not live. -->
132
+ {#snippet read(assertive: boolean)}
133
+ {#each notes as note (note.id)}
134
+ {#if note.assertive === assertive}<p>{note.message}</p>
135
+ {#if note.action}<p>{note.action}</p>{/if}{/if}
136
+ {/each}
137
+ {/snippet}
138
+ <div class="sv-visually-hidden" aria-live="polite">{@render read(false)}</div>
139
+ <div class="sv-visually-hidden" aria-live="assertive">{@render read(true)}</div>
140
+
141
+ <section
142
+ bind:this={ref}
143
+ popover="manual"
144
+ tabindex="-1"
145
+ aria-label="{locale.t('notifications')} (F8)"
146
+ class="sv-toasts"
147
+ onfocusin={enter}
148
+ onfocusout={exit}
149
+ >
150
+ {#if top}
151
+ <ol
152
+ class="sv-toasts__list"
153
+ onpointerenter={() => toasts.pause(hover)}
154
+ onpointerleave={() => toasts.resume(hover)}
155
+ >
156
+ {#each toasts.list as toast (toast.id)}
157
+ <li
158
+ class={[
159
+ 'sv-toast',
160
+ sharedClasses(
161
+ {
162
+ variant: 'flat',
163
+ color: toast.color,
164
+ density: style.density,
165
+ rounded: style.rounded
166
+ },
167
+ 'Toast'
168
+ )
169
+ ]}
170
+ in:rise
171
+ out:fade
172
+ animate:move
173
+ >
174
+ <p class="sv-toast__message">{toast.message}</p>
175
+ {#if toast.action}
176
+ <button type="button" class="sv-toast__action" onclick={() => act(toast)}>
177
+ {toast.action.label}
178
+ </button>
179
+ {/if}
180
+ <button
181
+ type="button"
182
+ class="sv-toast__close"
183
+ aria-label={locale.t('close')}
184
+ onclick={() => close(toast)}
185
+ >
186
+ <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d={CLOSE} /></svg>
187
+ </button>
188
+ </li>
189
+ {/each}
190
+ </ol>
191
+ {/if}
192
+ </section>
@@ -0,0 +1,11 @@
1
+ import type { Toasts } from './toast.svelte.js';
2
+ type $$ComponentProps = {
3
+ toasts: Toasts;
4
+ /** This outlet's token, which the toasts compare with their topmost outlet. */
5
+ outlet: object;
6
+ /** The region, which a dialog counts as inside itself. */
7
+ ref?: HTMLElement | null;
8
+ };
9
+ declare const ToastOutlet: import("svelte").Component<$$ComponentProps, {}, "ref">;
10
+ type ToastOutlet = ReturnType<typeof ToastOutlet>;
11
+ export default ToastOutlet;
@@ -0,0 +1,39 @@
1
+ <script lang="ts" module>
2
+ import type { Snippet } from 'svelte';
3
+
4
+ /**
5
+ * Gives its subtree toasts: `useToast()` inside it shows them at the bottom of the screen.
6
+ * `<UIProvider>` already includes one; add it yourself only when the app uses
7
+ * `<ThemeProvider>` alone.
8
+ *
9
+ * @example
10
+ * <ThemeProvider themes={monolith}>
11
+ * <ToastProvider>
12
+ * {@render children()}
13
+ * </ToastProvider>
14
+ * </ThemeProvider>
15
+ */
16
+ export interface ToastProviderProps {
17
+ children?: Snippet;
18
+ }
19
+ </script>
20
+
21
+ <script lang="ts">
22
+ // The toasts of a subtree, and the outlet that shows them while no modal dialog is open.
23
+ import { useDefaults } from '../defaults/context.js';
24
+ import { setToasts, Toasts, type ToastDefaults } from './toast.svelte.js';
25
+ import ToastOutlet from './ToastOutlet.svelte';
26
+
27
+ let { children }: ToastProviderProps = $props();
28
+
29
+ const resolve = useDefaults<ToastDefaults>('Toast', {
30
+ color: 'neutral',
31
+ duration: 6000,
32
+ density: 'default',
33
+ rounded: true
34
+ });
35
+ const toasts = setToasts(new Toasts(() => resolve({})));
36
+ </script>
37
+
38
+ {@render children?.()}
39
+ <ToastOutlet {toasts} outlet={toasts.base} />
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ /**
3
+ * Gives its subtree toasts: `useToast()` inside it shows them at the bottom of the screen.
4
+ * `<UIProvider>` already includes one; add it yourself only when the app uses
5
+ * `<ThemeProvider>` alone.
6
+ *
7
+ * @example
8
+ * <ThemeProvider themes={monolith}>
9
+ * <ToastProvider>
10
+ * {@render children()}
11
+ * </ToastProvider>
12
+ * </ThemeProvider>
13
+ */
14
+ export interface ToastProviderProps {
15
+ children?: Snippet;
16
+ }
17
+ declare const ToastProvider: import("svelte").Component<ToastProviderProps, {}, "">;
18
+ type ToastProvider = ReturnType<typeof ToastProvider>;
19
+ export default ToastProvider;