@nqmcreative/ui 0.1.0 → 0.2.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 (308) hide show
  1. package/README.md +151 -439
  2. package/cli/index.mjs +67 -30
  3. package/dist/core/calendar.d.ts +3 -0
  4. package/dist/core/calendar.js +36 -0
  5. package/dist/core/dialog.svelte.d.ts +14 -0
  6. package/dist/core/dialog.svelte.js +23 -0
  7. package/dist/core/files.d.ts +35 -0
  8. package/dist/core/files.js +62 -0
  9. package/dist/core/index.d.ts +37 -0
  10. package/dist/core/index.js +35 -0
  11. package/dist/core/list.svelte.d.ts +41 -0
  12. package/dist/core/list.svelte.js +77 -0
  13. package/dist/core/number.d.ts +7 -0
  14. package/dist/core/number.js +17 -0
  15. package/dist/core/pagination.d.ts +6 -0
  16. package/dist/core/pagination.js +21 -0
  17. package/dist/core/password.d.ts +8 -0
  18. package/dist/core/password.js +23 -0
  19. package/dist/core/table.d.ts +22 -0
  20. package/dist/core/table.js +41 -0
  21. package/dist/core/theme.svelte.d.ts +16 -0
  22. package/dist/core/theme.svelte.js +34 -0
  23. package/dist/core/trigger.d.ts +35 -0
  24. package/dist/core/trigger.js +77 -0
  25. package/dist/index.d.ts +11 -103
  26. package/dist/index.js +11 -75
  27. package/dist/{components → styles/matte}/AccordionItem.svelte +1 -1
  28. package/dist/{components → styles/matte}/AccordionItem.svelte.d.ts +1 -1
  29. package/dist/{components → styles/matte}/Alert.svelte +8 -2
  30. package/dist/{components → styles/matte}/Alert.svelte.d.ts +1 -1
  31. package/dist/{components → styles/matte}/Avatar.svelte +1 -1
  32. package/dist/{components → styles/matte}/Avatar.svelte.d.ts +1 -1
  33. package/dist/{components → styles/matte}/Badge.svelte +8 -3
  34. package/dist/{components → styles/matte}/Badge.svelte.d.ts +1 -3
  35. package/dist/{components → styles/matte}/Breadcrumb.svelte +2 -2
  36. package/dist/{components → styles/matte}/Breadcrumb.svelte.d.ts +1 -1
  37. package/dist/{components → styles/matte}/Button.svelte +1 -1
  38. package/dist/{components → styles/matte}/Button.svelte.d.ts +1 -1
  39. package/dist/styles/matte/CTASection.svelte +76 -0
  40. package/dist/styles/matte/CTASection.svelte.d.ts +18 -0
  41. package/dist/{components → styles/matte}/Calendar.svelte +7 -17
  42. package/dist/{components → styles/matte}/Calendar.svelte.d.ts +1 -1
  43. package/dist/{components → styles/matte}/Card.svelte +1 -1
  44. package/dist/{components → styles/matte}/Card.svelte.d.ts +1 -1
  45. package/dist/{components → styles/matte}/Checkbox.svelte +1 -1
  46. package/dist/{components → styles/matte}/Checkbox.svelte.d.ts +1 -1
  47. package/dist/{components → styles/matte}/CheckboxGroup.svelte +1 -1
  48. package/dist/{components → styles/matte}/CheckboxGroup.svelte.d.ts +1 -1
  49. package/dist/{components → styles/matte}/Combobox.svelte +31 -42
  50. package/dist/{components → styles/matte}/Combobox.svelte.d.ts +1 -1
  51. package/dist/{components → styles/matte}/CommandPalette.svelte +26 -41
  52. package/dist/{components → styles/matte}/CommandPalette.svelte.d.ts +1 -1
  53. package/dist/{components → styles/matte}/ConfirmDialog.svelte +2 -2
  54. package/dist/{components → styles/matte}/ConfirmDialog.svelte.d.ts +2 -2
  55. package/dist/{components → styles/matte}/ContextMenu.svelte +5 -7
  56. package/dist/{components → styles/matte}/DatePicker.svelte +7 -11
  57. package/dist/{components → styles/matte}/DatePicker.svelte.d.ts +1 -1
  58. package/dist/{components → styles/matte}/Drawer.svelte +4 -7
  59. package/dist/{components → styles/matte}/Dropdown.svelte +18 -36
  60. package/dist/{components → styles/matte}/Dropdown.svelte.d.ts +1 -1
  61. package/dist/{components → styles/matte}/Dropzone.svelte +11 -43
  62. package/dist/{components → styles/matte}/Dropzone.svelte.d.ts +2 -5
  63. package/dist/{components → styles/matte}/EmptyState.svelte +1 -1
  64. package/dist/{components → styles/matte}/EmptyState.svelte.d.ts +1 -1
  65. package/dist/styles/matte/FeatureCard.svelte +58 -0
  66. package/dist/styles/matte/FeatureCard.svelte.d.ts +16 -0
  67. package/dist/styles/matte/FeatureGrid.svelte +62 -0
  68. package/dist/styles/matte/FeatureGrid.svelte.d.ts +16 -0
  69. package/dist/{components → styles/matte}/Footer.svelte +1 -1
  70. package/dist/{components → styles/matte}/Footer.svelte.d.ts +1 -1
  71. package/dist/styles/matte/HeroSection.svelte +80 -0
  72. package/dist/styles/matte/HeroSection.svelte.d.ts +21 -0
  73. package/dist/{components → styles/matte}/Input.svelte +1 -1
  74. package/dist/{components → styles/matte}/Input.svelte.d.ts +1 -1
  75. package/dist/{components → styles/matte}/Link.svelte +1 -1
  76. package/dist/{components → styles/matte}/Link.svelte.d.ts +1 -1
  77. package/dist/{components → styles/matte}/LocaleProvider.svelte +1 -1
  78. package/dist/{components → styles/matte}/LocaleProvider.svelte.d.ts +1 -1
  79. package/dist/styles/matte/LogoCloud.svelte +61 -0
  80. package/dist/styles/matte/LogoCloud.svelte.d.ts +19 -0
  81. package/dist/{components → styles/matte}/MenuItem.svelte +1 -1
  82. package/dist/{components → styles/matte}/MenuItem.svelte.d.ts +1 -1
  83. package/dist/{components → styles/matte}/Modal.svelte +4 -7
  84. package/dist/{components → styles/matte}/MultiSelect.svelte +18 -37
  85. package/dist/{components → styles/matte}/MultiSelect.svelte.d.ts +1 -1
  86. package/dist/{components → styles/matte}/Navbar.svelte +2 -2
  87. package/dist/{components → styles/matte}/Navbar.svelte.d.ts +1 -1
  88. package/dist/{components → styles/matte}/NumberInput.svelte +4 -8
  89. package/dist/{components → styles/matte}/NumberInput.svelte.d.ts +1 -1
  90. package/dist/{components → styles/matte}/Pagination.svelte +4 -15
  91. package/dist/{components → styles/matte}/Pagination.svelte.d.ts +1 -1
  92. package/dist/{components → styles/matte}/PasswordInput.svelte +4 -13
  93. package/dist/{components → styles/matte}/PasswordInput.svelte.d.ts +1 -1
  94. package/dist/{components → styles/matte}/Popover.svelte +16 -41
  95. package/dist/{components → styles/matte}/Popover.svelte.d.ts +1 -1
  96. package/dist/styles/matte/PricingCard.svelte +107 -0
  97. package/dist/styles/matte/PricingCard.svelte.d.ts +25 -0
  98. package/dist/{components → styles/matte}/Progress.svelte +3 -2
  99. package/dist/{components → styles/matte}/Progress.svelte.d.ts +1 -1
  100. package/dist/{components → styles/matte}/Radio.svelte +1 -1
  101. package/dist/{components → styles/matte}/Radio.svelte.d.ts +1 -1
  102. package/dist/{components → styles/matte}/RadioGroup.svelte +1 -1
  103. package/dist/{components → styles/matte}/RadioGroup.svelte.d.ts +1 -1
  104. package/dist/{components → styles/matte}/SegmentedControl.svelte +1 -1
  105. package/dist/{components → styles/matte}/SegmentedControl.svelte.d.ts +1 -1
  106. package/dist/{components → styles/matte}/Select.svelte +1 -1
  107. package/dist/{components → styles/matte}/Select.svelte.d.ts +1 -1
  108. package/dist/{components → styles/matte}/Sidebar.svelte +2 -2
  109. package/dist/{components → styles/matte}/Sidebar.svelte.d.ts +1 -1
  110. package/dist/{components → styles/matte}/Slider.svelte +3 -2
  111. package/dist/{components → styles/matte}/Slider.svelte.d.ts +1 -1
  112. package/dist/{components → styles/matte}/Spinner.svelte +2 -2
  113. package/dist/{components → styles/matte}/Spinner.svelte.d.ts +1 -1
  114. package/dist/{components → styles/matte}/Stat.svelte +1 -1
  115. package/dist/{components → styles/matte}/Stat.svelte.d.ts +1 -1
  116. package/dist/styles/matte/StatsBand.svelte +57 -0
  117. package/dist/styles/matte/StatsBand.svelte.d.ts +20 -0
  118. package/dist/{components → styles/matte}/Steps.svelte +1 -1
  119. package/dist/{components → styles/matte}/Steps.svelte.d.ts +1 -1
  120. package/dist/{components → styles/matte}/Switch.svelte +1 -1
  121. package/dist/{components → styles/matte}/Switch.svelte.d.ts +1 -1
  122. package/dist/{components → styles/matte}/Table.svelte +6 -28
  123. package/dist/{components → styles/matte}/Table.svelte.d.ts +2 -6
  124. package/dist/{components → styles/matte}/Tabs.svelte +8 -1
  125. package/dist/{components → styles/matte}/Tabs.svelte.d.ts +1 -1
  126. package/dist/styles/matte/Testimonial.svelte +67 -0
  127. package/dist/styles/matte/Testimonial.svelte.d.ts +19 -0
  128. package/dist/{components → styles/matte}/Textarea.svelte +1 -1
  129. package/dist/{components → styles/matte}/Textarea.svelte.d.ts +1 -1
  130. package/dist/{components → styles/matte}/ThemeToggle.svelte +14 -27
  131. package/dist/{components → styles/matte}/ThemeToggle.svelte.d.ts +2 -6
  132. package/dist/{components → styles/matte}/Toaster.svelte +4 -4
  133. package/dist/{fonts.css → styles/matte/fonts.css} +4 -3
  134. package/dist/styles/matte/index.d.ts +109 -0
  135. package/dist/styles/matte/index.js +83 -0
  136. package/dist/{theme.css → styles/matte/theme.css} +0 -1
  137. package/dist/styles/paper/Accordion.svelte +17 -0
  138. package/dist/styles/paper/Accordion.svelte.d.ts +8 -0
  139. package/dist/styles/paper/AccordionItem.svelte +46 -0
  140. package/dist/styles/paper/AccordionItem.svelte.d.ts +14 -0
  141. package/dist/styles/paper/Alert.svelte +99 -0
  142. package/dist/styles/paper/Alert.svelte.d.ts +18 -0
  143. package/dist/styles/paper/Avatar.svelte +60 -0
  144. package/dist/styles/paper/Avatar.svelte.d.ts +16 -0
  145. package/dist/styles/paper/AvatarGroup.svelte +17 -0
  146. package/dist/styles/paper/AvatarGroup.svelte.d.ts +8 -0
  147. package/dist/styles/paper/Badge.svelte +58 -0
  148. package/dist/styles/paper/Badge.svelte.d.ts +16 -0
  149. package/dist/styles/paper/Breadcrumb.svelte +49 -0
  150. package/dist/styles/paper/Breadcrumb.svelte.d.ts +14 -0
  151. package/dist/styles/paper/Button.svelte +96 -0
  152. package/dist/styles/paper/Button.svelte.d.ts +21 -0
  153. package/dist/styles/paper/CTASection.svelte +76 -0
  154. package/dist/styles/paper/CTASection.svelte.d.ts +18 -0
  155. package/dist/styles/paper/Calendar.svelte +202 -0
  156. package/dist/styles/paper/Calendar.svelte.d.ts +22 -0
  157. package/dist/styles/paper/Card.svelte +78 -0
  158. package/dist/styles/paper/Card.svelte.d.ts +21 -0
  159. package/dist/styles/paper/Checkbox.svelte +75 -0
  160. package/dist/styles/paper/Checkbox.svelte.d.ts +15 -0
  161. package/dist/styles/paper/CheckboxGroup.svelte +111 -0
  162. package/dist/styles/paper/CheckboxGroup.svelte.d.ts +30 -0
  163. package/dist/styles/paper/Combobox.svelte +266 -0
  164. package/dist/styles/paper/Combobox.svelte.d.ts +29 -0
  165. package/dist/styles/paper/CommandPalette.svelte +209 -0
  166. package/dist/styles/paper/CommandPalette.svelte.d.ts +32 -0
  167. package/dist/styles/paper/ConfirmDialog.svelte +97 -0
  168. package/dist/styles/paper/ConfirmDialog.svelte.d.ts +22 -0
  169. package/dist/styles/paper/ContextMenu.svelte +88 -0
  170. package/dist/styles/paper/ContextMenu.svelte.d.ts +15 -0
  171. package/dist/styles/paper/DatePicker.svelte +192 -0
  172. package/dist/styles/paper/DatePicker.svelte.d.ts +23 -0
  173. package/dist/styles/paper/Divider.svelte +30 -0
  174. package/dist/styles/paper/Divider.svelte.d.ts +10 -0
  175. package/dist/styles/paper/Drawer.svelte +165 -0
  176. package/dist/styles/paper/Drawer.svelte.d.ts +20 -0
  177. package/dist/styles/paper/Dropdown.svelte +94 -0
  178. package/dist/styles/paper/Dropdown.svelte.d.ts +23 -0
  179. package/dist/styles/paper/Dropzone.svelte +210 -0
  180. package/dist/styles/paper/Dropzone.svelte.d.ts +29 -0
  181. package/dist/styles/paper/EmptyState.svelte +71 -0
  182. package/dist/styles/paper/EmptyState.svelte.d.ts +18 -0
  183. package/dist/styles/paper/FeatureCard.svelte +58 -0
  184. package/dist/styles/paper/FeatureCard.svelte.d.ts +16 -0
  185. package/dist/styles/paper/FeatureGrid.svelte +62 -0
  186. package/dist/styles/paper/FeatureGrid.svelte.d.ts +16 -0
  187. package/dist/styles/paper/Field.svelte +42 -0
  188. package/dist/styles/paper/Field.svelte.d.ts +16 -0
  189. package/dist/styles/paper/Footer.svelte +91 -0
  190. package/dist/styles/paper/Footer.svelte.d.ts +25 -0
  191. package/dist/styles/paper/HeroSection.svelte +86 -0
  192. package/dist/styles/paper/HeroSection.svelte.d.ts +21 -0
  193. package/dist/styles/paper/Input.svelte +60 -0
  194. package/dist/styles/paper/Input.svelte.d.ts +18 -0
  195. package/dist/styles/paper/InputGroup.svelte +20 -0
  196. package/dist/styles/paper/InputGroup.svelte.d.ts +11 -0
  197. package/dist/styles/paper/Kbd.svelte +17 -0
  198. package/dist/styles/paper/Kbd.svelte.d.ts +8 -0
  199. package/dist/styles/paper/Label.svelte +16 -0
  200. package/dist/styles/paper/Label.svelte.d.ts +9 -0
  201. package/dist/styles/paper/Link.svelte +44 -0
  202. package/dist/styles/paper/Link.svelte.d.ts +16 -0
  203. package/dist/styles/paper/LocaleProvider.svelte +24 -0
  204. package/dist/styles/paper/LocaleProvider.svelte.d.ts +10 -0
  205. package/dist/styles/paper/LogoCloud.svelte +61 -0
  206. package/dist/styles/paper/LogoCloud.svelte.d.ts +19 -0
  207. package/dist/styles/paper/MenuItem.svelte +64 -0
  208. package/dist/styles/paper/MenuItem.svelte.d.ts +18 -0
  209. package/dist/styles/paper/MenuSeparator.svelte +22 -0
  210. package/dist/styles/paper/MenuSeparator.svelte.d.ts +8 -0
  211. package/dist/styles/paper/Modal.svelte +118 -0
  212. package/dist/styles/paper/Modal.svelte.d.ts +21 -0
  213. package/dist/styles/paper/MultiSelect.svelte +287 -0
  214. package/dist/styles/paper/MultiSelect.svelte.d.ts +31 -0
  215. package/dist/styles/paper/Navbar.svelte +201 -0
  216. package/dist/styles/paper/Navbar.svelte.d.ts +33 -0
  217. package/dist/styles/paper/NumberInput.svelte +96 -0
  218. package/dist/styles/paper/NumberInput.svelte.d.ts +15 -0
  219. package/dist/styles/paper/Pagination.svelte +83 -0
  220. package/dist/styles/paper/Pagination.svelte.d.ts +15 -0
  221. package/dist/styles/paper/PasswordInput.svelte +100 -0
  222. package/dist/styles/paper/PasswordInput.svelte.d.ts +12 -0
  223. package/dist/styles/paper/Popover.svelte +89 -0
  224. package/dist/styles/paper/Popover.svelte.d.ts +19 -0
  225. package/dist/styles/paper/PricingCard.svelte +108 -0
  226. package/dist/styles/paper/PricingCard.svelte.d.ts +25 -0
  227. package/dist/styles/paper/Progress.svelte +59 -0
  228. package/dist/styles/paper/Progress.svelte.d.ts +17 -0
  229. package/dist/styles/paper/Radio.svelte +55 -0
  230. package/dist/styles/paper/Radio.svelte.d.ts +15 -0
  231. package/dist/styles/paper/RadioGroup.svelte +95 -0
  232. package/dist/styles/paper/RadioGroup.svelte.d.ts +27 -0
  233. package/dist/styles/paper/SegmentedControl.svelte +88 -0
  234. package/dist/styles/paper/SegmentedControl.svelte.d.ts +25 -0
  235. package/dist/styles/paper/Select.svelte +61 -0
  236. package/dist/styles/paper/Select.svelte.d.ts +20 -0
  237. package/dist/styles/paper/Sidebar.svelte +206 -0
  238. package/dist/styles/paper/Sidebar.svelte.d.ts +36 -0
  239. package/dist/styles/paper/Skeleton.svelte +46 -0
  240. package/dist/styles/paper/Skeleton.svelte.d.ts +13 -0
  241. package/dist/styles/paper/Slider.svelte +80 -0
  242. package/dist/styles/paper/Slider.svelte.d.ts +19 -0
  243. package/dist/styles/paper/Spinner.svelte +34 -0
  244. package/dist/styles/paper/Spinner.svelte.d.ts +13 -0
  245. package/dist/styles/paper/Stat.svelte +51 -0
  246. package/dist/styles/paper/Stat.svelte.d.ts +16 -0
  247. package/dist/styles/paper/StatsBand.svelte +63 -0
  248. package/dist/styles/paper/StatsBand.svelte.d.ts +20 -0
  249. package/dist/styles/paper/Steps.svelte +141 -0
  250. package/dist/styles/paper/Steps.svelte.d.ts +24 -0
  251. package/dist/styles/paper/Switch.svelte +64 -0
  252. package/dist/styles/paper/Switch.svelte.d.ts +14 -0
  253. package/dist/styles/paper/Table.svelte +217 -0
  254. package/dist/styles/paper/Table.svelte.d.ts +66 -0
  255. package/dist/styles/paper/Tabs.svelte +102 -0
  256. package/dist/styles/paper/Tabs.svelte.d.ts +23 -0
  257. package/dist/styles/paper/Testimonial.svelte +64 -0
  258. package/dist/styles/paper/Testimonial.svelte.d.ts +19 -0
  259. package/dist/styles/paper/Textarea.svelte +54 -0
  260. package/dist/styles/paper/Textarea.svelte.d.ts +12 -0
  261. package/dist/styles/paper/ThemeToggle.svelte +130 -0
  262. package/dist/styles/paper/ThemeToggle.svelte.d.ts +16 -0
  263. package/dist/styles/paper/Toaster.svelte +132 -0
  264. package/dist/styles/paper/Toaster.svelte.d.ts +8 -0
  265. package/dist/styles/paper/Tooltip.svelte +33 -0
  266. package/dist/styles/paper/Tooltip.svelte.d.ts +12 -0
  267. package/dist/styles/paper/fonts.css +46 -0
  268. package/dist/styles/paper/index.d.ts +109 -0
  269. package/dist/styles/paper/index.js +83 -0
  270. package/dist/styles/paper/theme.css +222 -0
  271. package/package.json +531 -201
  272. package/registry.json +658 -339
  273. /package/dist/{actions → core/actions}/anchor.d.ts +0 -0
  274. /package/dist/{actions → core/actions}/anchor.js +0 -0
  275. /package/dist/{actions → core/actions}/dismissable.d.ts +0 -0
  276. /package/dist/{actions → core/actions}/dismissable.js +0 -0
  277. /package/dist/{date.d.ts → core/date.d.ts} +0 -0
  278. /package/dist/{date.js → core/date.js} +0 -0
  279. /package/dist/{locale.svelte.d.ts → core/locale.svelte.d.ts} +0 -0
  280. /package/dist/{locale.svelte.js → core/locale.svelte.js} +0 -0
  281. /package/dist/{toast.svelte.d.ts → core/toast.svelte.d.ts} +0 -0
  282. /package/dist/{toast.svelte.js → core/toast.svelte.js} +0 -0
  283. /package/dist/{tones.d.ts → core/tones.d.ts} +0 -0
  284. /package/dist/{tones.js → core/tones.js} +0 -0
  285. /package/dist/{components → styles/matte}/Accordion.svelte +0 -0
  286. /package/dist/{components → styles/matte}/Accordion.svelte.d.ts +0 -0
  287. /package/dist/{components → styles/matte}/AvatarGroup.svelte +0 -0
  288. /package/dist/{components → styles/matte}/AvatarGroup.svelte.d.ts +0 -0
  289. /package/dist/{components → styles/matte}/ContextMenu.svelte.d.ts +0 -0
  290. /package/dist/{components → styles/matte}/Divider.svelte +0 -0
  291. /package/dist/{components → styles/matte}/Divider.svelte.d.ts +0 -0
  292. /package/dist/{components → styles/matte}/Drawer.svelte.d.ts +0 -0
  293. /package/dist/{components → styles/matte}/Field.svelte +0 -0
  294. /package/dist/{components → styles/matte}/Field.svelte.d.ts +0 -0
  295. /package/dist/{components → styles/matte}/InputGroup.svelte +0 -0
  296. /package/dist/{components → styles/matte}/InputGroup.svelte.d.ts +0 -0
  297. /package/dist/{components → styles/matte}/Kbd.svelte +0 -0
  298. /package/dist/{components → styles/matte}/Kbd.svelte.d.ts +0 -0
  299. /package/dist/{components → styles/matte}/Label.svelte +0 -0
  300. /package/dist/{components → styles/matte}/Label.svelte.d.ts +0 -0
  301. /package/dist/{components → styles/matte}/MenuSeparator.svelte +0 -0
  302. /package/dist/{components → styles/matte}/MenuSeparator.svelte.d.ts +0 -0
  303. /package/dist/{components → styles/matte}/Modal.svelte.d.ts +0 -0
  304. /package/dist/{components → styles/matte}/Skeleton.svelte +0 -0
  305. /package/dist/{components → styles/matte}/Skeleton.svelte.d.ts +0 -0
  306. /package/dist/{components → styles/matte}/Toaster.svelte.d.ts +0 -0
  307. /package/dist/{components → styles/matte}/Tooltip.svelte +0 -0
  308. /package/dist/{components → styles/matte}/Tooltip.svelte.d.ts +0 -0
@@ -9,10 +9,11 @@
9
9
  </script>
10
10
 
11
11
  <script lang="ts">
12
- import { anchored } from '../actions/anchor.js';
13
- import { clickOutside, portal } from '../actions/dismissable.js';
14
- import { useLocale } from '../locale.svelte.js';
15
- import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../tones.js';
12
+ import { anchored } from '../../core/actions/anchor.js';
13
+ import { clickOutside, portal } from '../../core/actions/dismissable.js';
14
+ import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
15
+ import { useLocale } from '../../core/locale.svelte.js';
16
+ import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../../core/tones.js';
16
17
 
17
18
  interface Props {
18
19
  /** Bindable — the `value` of every chosen option. */
@@ -56,7 +57,6 @@
56
57
 
57
58
  let open = $state(false);
58
59
  let query = $state('');
59
- let active = $state(0);
60
60
  let wrapper: HTMLElement | null = $state(null);
61
61
  let inputEl: HTMLInputElement | null = $state(null);
62
62
  let listEl: HTMLElement | null = $state(null);
@@ -67,29 +67,16 @@
67
67
  const full = $derived(max > 0 && value.length >= max);
68
68
  const collapsed = $derived(maxChips > 0 && chosen.length > maxChips);
69
69
 
70
- const matches = $derived.by(() => {
71
- const needle = query.trim().toLowerCase();
72
- if (!needle) return options;
73
- return options.filter(
74
- (option) =>
75
- option.label.toLowerCase().includes(needle) ||
76
- option.description?.toLowerCase().includes(needle)
77
- );
78
- });
79
-
80
- const groups = $derived.by(() => {
81
- const out: [string, MultiSelectOption[]][] = [];
82
- for (const option of matches) {
83
- const key = option.group ?? '';
84
- const bucket = out.find(([n]) => n === key);
85
- if (bucket) bucket[1].push(option);
86
- else out.push([key, [option]]);
87
- }
88
- return out;
89
- });
70
+ const matches = $derived(
71
+ matchQuery(options, query, (option) => `${option.label} ${option.description ?? ''}`)
72
+ );
90
73
 
74
+ const groups = $derived(groupItems(matches));
91
75
  const flat = $derived(groups.flatMap(([, items]) => items));
92
76
 
77
+ const cursor = new ListCursor(() => flat);
78
+ const active = $derived(cursor.index);
79
+
93
80
  function toggle(option: MultiSelectOption) {
94
81
  const has = value.includes(option.value);
95
82
  if (option.disabled || (!has && full)) return;
@@ -103,14 +90,8 @@
103
90
  }
104
91
 
105
92
  function move(step: number) {
106
- if (flat.length === 0) return;
107
- let next = active;
108
- for (let i = 0; i < flat.length; i++) {
109
- next = (next + step + flat.length) % flat.length;
110
- if (!flat[next].disabled) break;
111
- }
112
- active = next;
113
- listEl?.querySelector(`[data-index="${next}"]`)?.scrollIntoView({ block: 'nearest' });
93
+ cursor.move(step);
94
+ revealIndex(listEl, cursor.index);
114
95
  }
115
96
 
116
97
  function onKeydown(event: KeyboardEvent) {
@@ -125,9 +106,9 @@
125
106
  if (open) move(-1);
126
107
  break;
127
108
  case 'Enter':
128
- if (open && flat[active]) {
109
+ if (open && cursor.current) {
129
110
  event.preventDefault();
130
- toggle(flat[active]);
111
+ toggle(cursor.current);
131
112
  }
132
113
  break;
133
114
  case 'Backspace':
@@ -201,7 +182,7 @@
201
182
  placeholder={chosen.length ? '' : (placeholder ?? t.current.comboboxPlaceholder)}
202
183
  oninput={() => {
203
184
  open = true;
204
- active = 0;
185
+ cursor.index = 0;
205
186
  }}
206
187
  onfocus={() => (open = true)}
207
188
  onkeydown={onKeydown}
@@ -263,7 +244,7 @@
263
244
  aria-selected={checked}
264
245
  aria-disabled={option.disabled || (full && !checked)}
265
246
  onclick={() => toggle(option)}
266
- onpointermove={() => (active = index)}
247
+ onpointermove={() => (cursor.index = index)}
267
248
  class="flex cursor-pointer items-start gap-2.5 px-3 py-2 text-[14px] transition-colors duration-100
268
249
  {option.disabled || (full && !checked) ? 'pointer-events-none opacity-40' : ''}
269
250
  {index === active ? toneSoft[tone] : 'text-text-secondary'}"
@@ -5,7 +5,7 @@ export interface MultiSelectOption {
5
5
  disabled?: boolean;
6
6
  group?: string;
7
7
  }
8
- import { type Tone } from '../tones.js';
8
+ import { type Tone } from '../../core/tones.js';
9
9
  interface Props {
10
10
  /** Bindable — the `value` of every chosen option. */
11
11
  value?: string[];
@@ -14,8 +14,8 @@
14
14
 
15
15
  <script lang="ts">
16
16
  import type { Snippet } from 'svelte';
17
- import { useLocale } from '../locale.svelte.js';
18
- import { focusRing, toneRing, toneText, type Tone } from '../tones.js';
17
+ import { useLocale } from '../../core/locale.svelte.js';
18
+ import { focusRing, toneRing, toneText, type Tone } from '../../core/tones.js';
19
19
  import Drawer from './Drawer.svelte';
20
20
  import Dropdown from './Dropdown.svelte';
21
21
  import MenuItem from './MenuItem.svelte';
@@ -10,7 +10,7 @@ export interface NavItem {
10
10
  badge?: string | number;
11
11
  }
12
12
  import type { Snippet } from 'svelte';
13
- import { type Tone } from '../tones.js';
13
+ import { type Tone } from '../../core/tones.js';
14
14
  interface Props {
15
15
  items?: NavItem[];
16
16
  /** Logo or wordmark on the left. */
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
- import { toneFocusWithinBorder, type Tone } from '../tones.js';
4
- import { useLocale } from '../locale.svelte.js';
3
+ import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+ import { clampToStep } from '../../core/number.js';
5
6
 
6
7
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
7
8
  value?: number;
@@ -29,12 +30,7 @@
29
30
 
30
31
  const t = useLocale();
31
32
 
32
- const decimals = $derived((String(step).split('.')[1] ?? '').length);
33
-
34
- function clamp(next: number) {
35
- if (Number.isNaN(next)) return min === -Infinity ? 0 : min;
36
- return Number(Math.min(max, Math.max(min, next)).toFixed(decimals));
37
- }
33
+ const clamp = (next: number) => clampToStep(next, min, max, step);
38
34
 
39
35
  function nudge(direction: 1 | -1) {
40
36
  value = clamp(value + direction * step);
@@ -1,5 +1,5 @@
1
1
  import type { HTMLInputAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
4
4
  value?: number;
5
5
  min?: number;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { focusRing, toneRing, toneSolid, type Tone } from '../tones.js';
4
- import { useLocale } from '../locale.svelte.js';
3
+ import { focusRing, toneRing, toneSolid, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+ import { pageRange } from '../../core/pagination.js';
5
6
 
6
7
  interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onchange'> {
7
8
  /** Bindable, 1-based. */
@@ -26,19 +27,7 @@
26
27
 
27
28
  const t = useLocale();
28
29
 
29
- const pages = $derived.by<(number | '…')[]>(() => {
30
- if (total <= 5 + siblings * 2) {
31
- return Array.from({ length: total }, (_, i) => i + 1);
32
- }
33
- const start = Math.max(2, page - siblings);
34
- const end = Math.min(total - 1, page + siblings);
35
- const out: (number | '…')[] = [1];
36
- if (start > 2) out.push('…');
37
- for (let i = start; i <= end; i++) out.push(i);
38
- if (end < total - 1) out.push('…');
39
- out.push(total);
40
- return out;
41
- });
30
+ const pages = $derived(pageRange(page, total, siblings));
42
31
 
43
32
  function go(next: number) {
44
33
  const clamped = Math.min(total, Math.max(1, next));
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onchange'> {
4
4
  /** Bindable, 1-based. */
5
5
  page?: number;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
- import { toneFocusWithinBorder, type Tone } from '../tones.js';
4
- import { useLocale } from '../locale.svelte.js';
3
+ import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+ import { passwordScore } from '../../core/password.js';
5
6
 
6
7
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type'> {
7
8
  value?: string;
@@ -25,17 +26,7 @@
25
26
 
26
27
  let visible = $state(false);
27
28
 
28
- /** Deliberately simple: length plus character variety, four buckets. */
29
- const score = $derived.by(() => {
30
- if (!value) return 0;
31
- let points = 0;
32
- if (value.length >= 8) points++;
33
- if (value.length >= 12) points++;
34
- if (/[a-z]/.test(value) && /[A-Z]/.test(value)) points++;
35
- if (/\d/.test(value)) points++;
36
- if (/[^\w\s]/.test(value)) points++;
37
- return Math.min(4, points);
38
- });
29
+ const score = $derived(passwordScore(value));
39
30
 
40
31
  const bars = ['bg-danger', 'bg-danger', 'bg-warning', 'bg-info', 'bg-success'];
41
32
  const texts = ['text-danger', 'text-danger', 'text-warning', 'text-info', 'text-success'];
@@ -1,5 +1,5 @@
1
1
  import type { HTMLInputAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type'> {
4
4
  value?: string;
5
5
  tone?: Tone;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
- import { anchored, type Placement } from '../actions/anchor.js';
4
- import { clickOutside, focusTrap, portal } from '../actions/dismissable.js';
3
+ import { anchored, type Placement } from '../../core/actions/anchor.js';
4
+ import { clickOutside, focusTrap, portal } from '../../core/actions/dismissable.js';
5
+ import { HOVER_GRACE, describeTrigger, popupTrigger } from '../../core/trigger.js';
5
6
 
6
7
  interface Props {
7
8
  trigger: Snippet;
@@ -32,45 +33,10 @@
32
33
  }: Props = $props();
33
34
 
34
35
  let anchorEl: HTMLElement | null = $state(null);
36
+ /** Held so the panel itself can cancel the hover close it inherited. */
35
37
  let closeTimer: ReturnType<typeof setTimeout> | undefined;
36
38
 
37
- function triggerBehaviour(node: HTMLElement) {
38
- const toggle = () => (open = !open);
39
- const show = () => {
40
- clearTimeout(closeTimer);
41
- open = true;
42
- };
43
- const hide = () => {
44
- closeTimer = setTimeout(() => (open = false), 120);
45
- };
46
-
47
- if (on === 'click') {
48
- node.addEventListener('click', toggle);
49
- } else {
50
- node.addEventListener('pointerenter', show);
51
- node.addEventListener('pointerleave', hide);
52
- node.addEventListener('focusin', show);
53
- node.addEventListener('focusout', hide);
54
- }
55
-
56
- return {
57
- destroy() {
58
- clearTimeout(closeTimer);
59
- node.removeEventListener('click', toggle);
60
- node.removeEventListener('pointerenter', show);
61
- node.removeEventListener('pointerleave', hide);
62
- node.removeEventListener('focusin', show);
63
- node.removeEventListener('focusout', hide);
64
- }
65
- };
66
- }
67
-
68
- $effect(() => {
69
- const control = anchorEl?.querySelector('button, a, [role="button"]');
70
- if (!control) return;
71
- control.setAttribute('aria-haspopup', 'dialog');
72
- control.setAttribute('aria-expanded', String(open));
73
- });
39
+ $effect(() => describeTrigger(anchorEl, 'dialog', open));
74
40
 
75
41
  function onKeydown(event: KeyboardEvent) {
76
42
  if (event.key !== 'Escape') return;
@@ -80,7 +46,16 @@
80
46
  }
81
47
  </script>
82
48
 
83
- <span bind:this={anchorEl} use:triggerBehaviour class="inline-flex {triggerClass}">
49
+ <span
50
+ bind:this={anchorEl}
51
+ use:popupTrigger={{
52
+ toggle: () => (open = !open),
53
+ open: () => (open = true),
54
+ close: () => (open = false),
55
+ on
56
+ }}
57
+ class="inline-flex {triggerClass}"
58
+ >
84
59
  {@render trigger()}
85
60
  </span>
86
61
 
@@ -97,7 +72,7 @@
97
72
  onkeydown={onKeydown}
98
73
  onpointerenter={() => clearTimeout(closeTimer)}
99
74
  onpointerleave={() => {
100
- if (on === 'hover') closeTimer = setTimeout(() => (open = false), 120);
75
+ if (on === 'hover') closeTimer = setTimeout(() => (open = false), HOVER_GRACE);
101
76
  }}
102
77
  role="dialog"
103
78
  aria-label={title}
@@ -1,5 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
- import { type Placement } from '../actions/anchor.js';
2
+ import { type Placement } from '../../core/actions/anchor.js';
3
3
  interface Props {
4
4
  trigger: Snippet;
5
5
  children: Snippet;
@@ -0,0 +1,107 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { toneBorder, toneFill, toneSoft, toneText, type Tone } from '../../core/tones.js';
5
+
6
+ interface Props extends HTMLAttributes<HTMLDivElement> {
7
+ name: string;
8
+ /** Already formatted — the component does not do currency. */
9
+ price: string;
10
+ /** `/ month`, `per seat`, whatever follows the figure. */
11
+ period?: string;
12
+ description?: string;
13
+ /** One line each. Rendered with a tick. */
14
+ features?: string[];
15
+ /** Pill in the top corner, e.g. "Most popular". */
16
+ badge?: string;
17
+ /** Thicker border and a tinted header — for the plan you want chosen. */
18
+ featured?: boolean;
19
+ tone?: Tone;
20
+ /** The button. */
21
+ action?: Snippet;
22
+ /** Extra content under the feature list. */
23
+ children?: Snippet;
24
+ }
25
+
26
+ let {
27
+ name,
28
+ price,
29
+ period,
30
+ description,
31
+ features = [],
32
+ badge,
33
+ featured = false,
34
+ tone = 'brand',
35
+ action,
36
+ class: className = '',
37
+ children,
38
+ ...rest
39
+ }: Props = $props();
40
+ </script>
41
+
42
+ <div
43
+ class="flex flex-col bg-bg {featured
44
+ ? `border-2 ${toneBorder[tone]}`
45
+ : 'border border-hairline'} {className}"
46
+ {...rest}
47
+ >
48
+ <div class="flex flex-col gap-4 p-6 {featured ? toneSoft[tone] : ''}">
49
+ <div class="flex items-start justify-between gap-3">
50
+ <h3 class="font-heading text-lg font-medium tracking-tight {featured ? '' : 'text-text'}">
51
+ {name}
52
+ </h3>
53
+ {#if badge}
54
+ <span
55
+ class="shrink-0 rounded-full px-2.5 py-1 font-mono text-[10px] tracking-wide {featured
56
+ ? `${toneFill[tone]} text-text-inverse`
57
+ : toneSoft[tone]}"
58
+ >
59
+ {badge}
60
+ </span>
61
+ {/if}
62
+ </div>
63
+
64
+ <div class="flex items-baseline gap-1.5">
65
+ <span
66
+ class="font-heading text-4xl font-medium tracking-tight {featured
67
+ ? toneText[tone]
68
+ : 'text-text'}"
69
+ >
70
+ {price}
71
+ </span>
72
+ {#if period}
73
+ <span class="font-sans text-sm text-text-muted">{period}</span>
74
+ {/if}
75
+ </div>
76
+
77
+ {#if description}
78
+ <p class="font-sans text-sm leading-relaxed text-text-secondary">{description}</p>
79
+ {/if}
80
+ </div>
81
+
82
+ {#if features.length}
83
+ <ul class="flex flex-1 flex-col gap-3 border-t border-hairline p-6">
84
+ {#each features as feature (feature)}
85
+ <li class="flex items-start gap-3 font-sans text-sm text-text-secondary">
86
+ <svg
87
+ class="mt-0.5 size-4 shrink-0 {toneText[tone]}"
88
+ viewBox="0 0 16 16"
89
+ fill="none"
90
+ aria-hidden="true"
91
+ >
92
+ <path d="m3 8 3.2 3.2L13 4.4" stroke="currentColor" stroke-width="1.6" />
93
+ </svg>
94
+ <span class="leading-snug">{feature}</span>
95
+ </li>
96
+ {/each}
97
+ </ul>
98
+ {/if}
99
+
100
+ {#if children}
101
+ <div class="px-6 pb-2">{@render children()}</div>
102
+ {/if}
103
+
104
+ {#if action}
105
+ <div class="p-6 pt-2">{@render action()}</div>
106
+ {/if}
107
+ </div>
@@ -0,0 +1,25 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ interface Props extends HTMLAttributes<HTMLDivElement> {
5
+ name: string;
6
+ /** Already formatted — the component does not do currency. */
7
+ price: string;
8
+ /** `/ month`, `per seat`, whatever follows the figure. */
9
+ period?: string;
10
+ description?: string;
11
+ /** One line each. Rendered with a tick. */
12
+ features?: string[];
13
+ /** Pill in the top corner, e.g. "Most popular". */
14
+ badge?: string;
15
+ /** Thicker border and a tinted header — for the plan you want chosen. */
16
+ featured?: boolean;
17
+ tone?: Tone;
18
+ /** The button. */
19
+ action?: Snippet;
20
+ /** Extra content under the feature list. */
21
+ children?: Snippet;
22
+ }
23
+ declare const PricingCard: import("svelte").Component<Props, {}, "">;
24
+ type PricingCard = ReturnType<typeof PricingCard>;
25
+ export default PricingCard;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { toneFill, type Tone } from '../tones.js';
3
+ import { toneFill, type Tone } from '../../core/tones.js';
4
+ import { percentOf } from '../../core/number.js';
4
5
 
5
6
  export type ProgressSize = 'sm' | 'md' | 'lg';
6
7
 
@@ -29,7 +30,7 @@
29
30
  }: Props = $props();
30
31
 
31
32
  const sizes: Record<ProgressSize, string> = { sm: 'h-1', md: 'h-2', lg: 'h-3' };
32
- const pct = $derived(Math.min(100, Math.max(0, (value / max) * 100)));
33
+ const pct = $derived(percentOf(value, 0, max));
33
34
  </script>
34
35
 
35
36
  <div class="flex w-full flex-col gap-2 {className}" {...rest}>
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  export type ProgressSize = 'sm' | 'md' | 'lg';
4
4
  interface Props extends HTMLAttributes<HTMLDivElement> {
5
5
  value?: number;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLInputAttributes } from 'svelte/elements';
4
- import { peerFocusRing, tonePeerChecked, tonePeerFocus, type Tone } from '../tones.js';
4
+ import { peerFocusRing, tonePeerChecked, tonePeerFocus, type Tone } from '../../core/tones.js';
5
5
 
6
6
  interface Props extends Omit<HTMLInputAttributes, 'type' | 'size'> {
7
7
  /** Bind the same variable across a set of radios. */
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
- import { type Tone } from '../tones.js';
3
+ import { type Tone } from '../../core/tones.js';
4
4
  interface Props extends Omit<HTMLInputAttributes, 'type' | 'size'> {
5
5
  /** Bind the same variable across a set of radios. */
6
6
  group?: string;
@@ -2,7 +2,7 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLFieldsetAttributes } from 'svelte/elements';
4
4
  import Radio from './Radio.svelte';
5
- import type { Tone } from '../tones.js';
5
+ import type { Tone } from '../../core/tones.js';
6
6
 
7
7
  export interface RadioOption {
8
8
  value: string;
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLFieldsetAttributes } from 'svelte/elements';
3
- import type { Tone } from '../tones.js';
3
+ import type { Tone } from '../../core/tones.js';
4
4
  export interface RadioOption {
5
5
  value: string;
6
6
  label: string;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { focusRing, toneRing, toneSoft, type Tone } from '../tones.js';
3
+ import { focusRing, toneRing, toneSoft, type Tone } from '../../core/tones.js';
4
4
 
5
5
  export interface SegmentOption {
6
6
  value: string;
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  export interface SegmentOption {
4
4
  value: string;
5
5
  label: string;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLSelectAttributes } from 'svelte/elements';
4
- import { toneFocusBorder, type Tone } from '../tones.js';
4
+ import { toneFocusBorder, type Tone } from '../../core/tones.js';
5
5
 
6
6
  export interface SelectOption {
7
7
  value: string;
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLSelectAttributes } from 'svelte/elements';
3
- import { type Tone } from '../tones.js';
3
+ import { type Tone } from '../../core/tones.js';
4
4
  export interface SelectOption {
5
5
  value: string;
6
6
  label: string;
@@ -21,8 +21,8 @@
21
21
 
22
22
  <script lang="ts">
23
23
  import type { Snippet } from 'svelte';
24
- import { useLocale } from '../locale.svelte.js';
25
- import { focusRing, toneRing, toneSoft, type Tone } from '../tones.js';
24
+ import { useLocale } from '../../core/locale.svelte.js';
25
+ import { focusRing, toneRing, toneSoft, type Tone } from '../../core/tones.js';
26
26
 
27
27
  interface Props {
28
28
  sections: SidebarSection[];
@@ -16,7 +16,7 @@ export interface SidebarSection {
16
16
  items: SidebarItem[];
17
17
  }
18
18
  import type { Snippet } from 'svelte';
19
- import { type Tone } from '../tones.js';
19
+ import { type Tone } from '../../core/tones.js';
20
20
  interface Props {
21
21
  sections: SidebarSection[];
22
22
  /** Bindable — the `id` (or `href`) of the current item. */
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
- import { toneText, type Tone } from '../tones.js';
3
+ import { toneText, type Tone } from '../../core/tones.js';
4
+ import { percentOf } from '../../core/number.js';
4
5
 
5
6
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
6
7
  value?: number;
@@ -32,7 +33,7 @@
32
33
  ...rest
33
34
  }: Props = $props();
34
35
 
35
- const pct = $derived(Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)));
36
+ const pct = $derived(percentOf(value, min, max));
36
37
 
37
38
  // The filled part of the track and the thumb both paint with `currentColor`,
38
39
  // so a single tone class on the input drives every vendor pseudo-element.
@@ -1,5 +1,5 @@
1
1
  import type { HTMLInputAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  interface Props extends Omit<HTMLInputAttributes, 'size' | 'type' | 'value' | 'min' | 'max'> {
4
4
  value?: number;
5
5
  min?: number;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { toneText, type Tone } from '../tones.js';
4
- import { useLocale } from '../locale.svelte.js';
3
+ import { toneText, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
5
 
6
6
  export type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg';
7
7
 
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  export type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg';
4
4
  interface Props extends HTMLAttributes<HTMLSpanElement> {
5
5
  size?: SpinnerSize;