@nqmcreative/ui 0.1.1 → 0.2.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 (308) hide show
  1. package/README.md +89 -34
  2. package/cli/index.mjs +83 -33
  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/styles/matte/index.d.ts +109 -0
  134. package/dist/styles/matte/index.js +83 -0
  135. package/dist/styles/paper/Accordion.svelte +17 -0
  136. package/dist/styles/paper/Accordion.svelte.d.ts +8 -0
  137. package/dist/styles/paper/AccordionItem.svelte +46 -0
  138. package/dist/styles/paper/AccordionItem.svelte.d.ts +14 -0
  139. package/dist/styles/paper/Alert.svelte +99 -0
  140. package/dist/styles/paper/Alert.svelte.d.ts +18 -0
  141. package/dist/styles/paper/Avatar.svelte +60 -0
  142. package/dist/styles/paper/Avatar.svelte.d.ts +16 -0
  143. package/dist/styles/paper/AvatarGroup.svelte +17 -0
  144. package/dist/styles/paper/AvatarGroup.svelte.d.ts +8 -0
  145. package/dist/styles/paper/Badge.svelte +58 -0
  146. package/dist/styles/paper/Badge.svelte.d.ts +16 -0
  147. package/dist/styles/paper/Breadcrumb.svelte +49 -0
  148. package/dist/styles/paper/Breadcrumb.svelte.d.ts +14 -0
  149. package/dist/styles/paper/Button.svelte +96 -0
  150. package/dist/styles/paper/Button.svelte.d.ts +21 -0
  151. package/dist/styles/paper/CTASection.svelte +76 -0
  152. package/dist/styles/paper/CTASection.svelte.d.ts +18 -0
  153. package/dist/styles/paper/Calendar.svelte +202 -0
  154. package/dist/styles/paper/Calendar.svelte.d.ts +22 -0
  155. package/dist/styles/paper/Card.svelte +78 -0
  156. package/dist/styles/paper/Card.svelte.d.ts +21 -0
  157. package/dist/styles/paper/Checkbox.svelte +75 -0
  158. package/dist/styles/paper/Checkbox.svelte.d.ts +15 -0
  159. package/dist/styles/paper/CheckboxGroup.svelte +111 -0
  160. package/dist/styles/paper/CheckboxGroup.svelte.d.ts +30 -0
  161. package/dist/styles/paper/Combobox.svelte +266 -0
  162. package/dist/styles/paper/Combobox.svelte.d.ts +29 -0
  163. package/dist/styles/paper/CommandPalette.svelte +209 -0
  164. package/dist/styles/paper/CommandPalette.svelte.d.ts +32 -0
  165. package/dist/styles/paper/ConfirmDialog.svelte +97 -0
  166. package/dist/styles/paper/ConfirmDialog.svelte.d.ts +22 -0
  167. package/dist/styles/paper/ContextMenu.svelte +88 -0
  168. package/dist/styles/paper/ContextMenu.svelte.d.ts +15 -0
  169. package/dist/styles/paper/DatePicker.svelte +192 -0
  170. package/dist/styles/paper/DatePicker.svelte.d.ts +23 -0
  171. package/dist/styles/paper/Divider.svelte +30 -0
  172. package/dist/styles/paper/Divider.svelte.d.ts +10 -0
  173. package/dist/styles/paper/Drawer.svelte +165 -0
  174. package/dist/styles/paper/Drawer.svelte.d.ts +20 -0
  175. package/dist/styles/paper/Dropdown.svelte +94 -0
  176. package/dist/styles/paper/Dropdown.svelte.d.ts +23 -0
  177. package/dist/styles/paper/Dropzone.svelte +210 -0
  178. package/dist/styles/paper/Dropzone.svelte.d.ts +29 -0
  179. package/dist/styles/paper/EmptyState.svelte +71 -0
  180. package/dist/styles/paper/EmptyState.svelte.d.ts +18 -0
  181. package/dist/styles/paper/FeatureCard.svelte +58 -0
  182. package/dist/styles/paper/FeatureCard.svelte.d.ts +16 -0
  183. package/dist/styles/paper/FeatureGrid.svelte +62 -0
  184. package/dist/styles/paper/FeatureGrid.svelte.d.ts +16 -0
  185. package/dist/styles/paper/Field.svelte +42 -0
  186. package/dist/styles/paper/Field.svelte.d.ts +16 -0
  187. package/dist/styles/paper/Footer.svelte +91 -0
  188. package/dist/styles/paper/Footer.svelte.d.ts +25 -0
  189. package/dist/styles/paper/HeroSection.svelte +86 -0
  190. package/dist/styles/paper/HeroSection.svelte.d.ts +21 -0
  191. package/dist/styles/paper/Input.svelte +60 -0
  192. package/dist/styles/paper/Input.svelte.d.ts +18 -0
  193. package/dist/styles/paper/InputGroup.svelte +20 -0
  194. package/dist/styles/paper/InputGroup.svelte.d.ts +11 -0
  195. package/dist/styles/paper/Kbd.svelte +17 -0
  196. package/dist/styles/paper/Kbd.svelte.d.ts +8 -0
  197. package/dist/styles/paper/Label.svelte +16 -0
  198. package/dist/styles/paper/Label.svelte.d.ts +9 -0
  199. package/dist/styles/paper/Link.svelte +44 -0
  200. package/dist/styles/paper/Link.svelte.d.ts +16 -0
  201. package/dist/styles/paper/LocaleProvider.svelte +24 -0
  202. package/dist/styles/paper/LocaleProvider.svelte.d.ts +10 -0
  203. package/dist/styles/paper/LogoCloud.svelte +61 -0
  204. package/dist/styles/paper/LogoCloud.svelte.d.ts +19 -0
  205. package/dist/styles/paper/MenuItem.svelte +64 -0
  206. package/dist/styles/paper/MenuItem.svelte.d.ts +18 -0
  207. package/dist/styles/paper/MenuSeparator.svelte +22 -0
  208. package/dist/styles/paper/MenuSeparator.svelte.d.ts +8 -0
  209. package/dist/styles/paper/Modal.svelte +118 -0
  210. package/dist/styles/paper/Modal.svelte.d.ts +21 -0
  211. package/dist/styles/paper/MultiSelect.svelte +287 -0
  212. package/dist/styles/paper/MultiSelect.svelte.d.ts +31 -0
  213. package/dist/styles/paper/Navbar.svelte +201 -0
  214. package/dist/styles/paper/Navbar.svelte.d.ts +33 -0
  215. package/dist/styles/paper/NumberInput.svelte +96 -0
  216. package/dist/styles/paper/NumberInput.svelte.d.ts +15 -0
  217. package/dist/styles/paper/Pagination.svelte +83 -0
  218. package/dist/styles/paper/Pagination.svelte.d.ts +15 -0
  219. package/dist/styles/paper/PasswordInput.svelte +100 -0
  220. package/dist/styles/paper/PasswordInput.svelte.d.ts +12 -0
  221. package/dist/styles/paper/Popover.svelte +89 -0
  222. package/dist/styles/paper/Popover.svelte.d.ts +19 -0
  223. package/dist/styles/paper/PricingCard.svelte +108 -0
  224. package/dist/styles/paper/PricingCard.svelte.d.ts +25 -0
  225. package/dist/styles/paper/Progress.svelte +59 -0
  226. package/dist/styles/paper/Progress.svelte.d.ts +17 -0
  227. package/dist/styles/paper/Radio.svelte +55 -0
  228. package/dist/styles/paper/Radio.svelte.d.ts +15 -0
  229. package/dist/styles/paper/RadioGroup.svelte +95 -0
  230. package/dist/styles/paper/RadioGroup.svelte.d.ts +27 -0
  231. package/dist/styles/paper/SegmentedControl.svelte +88 -0
  232. package/dist/styles/paper/SegmentedControl.svelte.d.ts +25 -0
  233. package/dist/styles/paper/Select.svelte +61 -0
  234. package/dist/styles/paper/Select.svelte.d.ts +20 -0
  235. package/dist/styles/paper/Sidebar.svelte +206 -0
  236. package/dist/styles/paper/Sidebar.svelte.d.ts +36 -0
  237. package/dist/styles/paper/Skeleton.svelte +46 -0
  238. package/dist/styles/paper/Skeleton.svelte.d.ts +13 -0
  239. package/dist/styles/paper/Slider.svelte +80 -0
  240. package/dist/styles/paper/Slider.svelte.d.ts +19 -0
  241. package/dist/styles/paper/Spinner.svelte +34 -0
  242. package/dist/styles/paper/Spinner.svelte.d.ts +13 -0
  243. package/dist/styles/paper/Stat.svelte +51 -0
  244. package/dist/styles/paper/Stat.svelte.d.ts +16 -0
  245. package/dist/styles/paper/StatsBand.svelte +63 -0
  246. package/dist/styles/paper/StatsBand.svelte.d.ts +20 -0
  247. package/dist/styles/paper/Steps.svelte +141 -0
  248. package/dist/styles/paper/Steps.svelte.d.ts +24 -0
  249. package/dist/styles/paper/Switch.svelte +64 -0
  250. package/dist/styles/paper/Switch.svelte.d.ts +14 -0
  251. package/dist/styles/paper/Table.svelte +217 -0
  252. package/dist/styles/paper/Table.svelte.d.ts +66 -0
  253. package/dist/styles/paper/Tabs.svelte +102 -0
  254. package/dist/styles/paper/Tabs.svelte.d.ts +23 -0
  255. package/dist/styles/paper/Testimonial.svelte +64 -0
  256. package/dist/styles/paper/Testimonial.svelte.d.ts +19 -0
  257. package/dist/styles/paper/Textarea.svelte +54 -0
  258. package/dist/styles/paper/Textarea.svelte.d.ts +12 -0
  259. package/dist/styles/paper/ThemeToggle.svelte +130 -0
  260. package/dist/styles/paper/ThemeToggle.svelte.d.ts +16 -0
  261. package/dist/styles/paper/Toaster.svelte +132 -0
  262. package/dist/styles/paper/Toaster.svelte.d.ts +8 -0
  263. package/dist/styles/paper/Tooltip.svelte +33 -0
  264. package/dist/styles/paper/Tooltip.svelte.d.ts +12 -0
  265. package/dist/styles/paper/fonts.css +46 -0
  266. package/dist/styles/paper/index.d.ts +109 -0
  267. package/dist/styles/paper/index.js +83 -0
  268. package/dist/styles/paper/theme.css +222 -0
  269. package/package.json +531 -201
  270. package/registry.json +658 -339
  271. /package/dist/{actions → core/actions}/anchor.d.ts +0 -0
  272. /package/dist/{actions → core/actions}/anchor.js +0 -0
  273. /package/dist/{actions → core/actions}/dismissable.d.ts +0 -0
  274. /package/dist/{actions → core/actions}/dismissable.js +0 -0
  275. /package/dist/{date.d.ts → core/date.d.ts} +0 -0
  276. /package/dist/{date.js → core/date.js} +0 -0
  277. /package/dist/{locale.svelte.d.ts → core/locale.svelte.d.ts} +0 -0
  278. /package/dist/{locale.svelte.js → core/locale.svelte.js} +0 -0
  279. /package/dist/{toast.svelte.d.ts → core/toast.svelte.d.ts} +0 -0
  280. /package/dist/{toast.svelte.js → core/toast.svelte.js} +0 -0
  281. /package/dist/{tones.d.ts → core/tones.d.ts} +0 -0
  282. /package/dist/{tones.js → core/tones.js} +0 -0
  283. /package/dist/{components → styles/matte}/Accordion.svelte +0 -0
  284. /package/dist/{components → styles/matte}/Accordion.svelte.d.ts +0 -0
  285. /package/dist/{components → styles/matte}/AvatarGroup.svelte +0 -0
  286. /package/dist/{components → styles/matte}/AvatarGroup.svelte.d.ts +0 -0
  287. /package/dist/{components → styles/matte}/ContextMenu.svelte.d.ts +0 -0
  288. /package/dist/{components → styles/matte}/Divider.svelte +0 -0
  289. /package/dist/{components → styles/matte}/Divider.svelte.d.ts +0 -0
  290. /package/dist/{components → styles/matte}/Drawer.svelte.d.ts +0 -0
  291. /package/dist/{components → styles/matte}/Field.svelte +0 -0
  292. /package/dist/{components → styles/matte}/Field.svelte.d.ts +0 -0
  293. /package/dist/{components → styles/matte}/InputGroup.svelte +0 -0
  294. /package/dist/{components → styles/matte}/InputGroup.svelte.d.ts +0 -0
  295. /package/dist/{components → styles/matte}/Kbd.svelte +0 -0
  296. /package/dist/{components → styles/matte}/Kbd.svelte.d.ts +0 -0
  297. /package/dist/{components → styles/matte}/Label.svelte +0 -0
  298. /package/dist/{components → styles/matte}/Label.svelte.d.ts +0 -0
  299. /package/dist/{components → styles/matte}/MenuSeparator.svelte +0 -0
  300. /package/dist/{components → styles/matte}/MenuSeparator.svelte.d.ts +0 -0
  301. /package/dist/{components → styles/matte}/Modal.svelte.d.ts +0 -0
  302. /package/dist/{components → styles/matte}/Skeleton.svelte +0 -0
  303. /package/dist/{components → styles/matte}/Skeleton.svelte.d.ts +0 -0
  304. /package/dist/{components → styles/matte}/Toaster.svelte.d.ts +0 -0
  305. /package/dist/{components → styles/matte}/Tooltip.svelte +0 -0
  306. /package/dist/{components → styles/matte}/Tooltip.svelte.d.ts +0 -0
  307. /package/dist/{fonts.css → styles/matte/fonts.css} +0 -0
  308. /package/dist/{theme.css → styles/matte/theme.css} +0 -0
@@ -16,9 +16,11 @@
16
16
  </script>
17
17
 
18
18
  <script lang="ts">
19
- import { focusTrap } from '../actions/dismissable.js';
20
- import { useLocale } from '../locale.svelte.js';
21
- import { toneSoft, type Tone } from '../tones.js';
19
+ import { focusTrap } from '../../core/actions/dismissable.js';
20
+ import { syncDialog } from '../../core/dialog.svelte.js';
21
+ import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
22
+ import { useLocale } from '../../core/locale.svelte.js';
23
+ import { toneSoft, type Tone } from '../../core/tones.js';
22
24
  import Kbd from './Kbd.svelte';
23
25
 
24
26
  interface Props {
@@ -53,40 +55,29 @@
53
55
  let inputEl: HTMLInputElement | null = $state(null);
54
56
  let listEl: HTMLElement | null = $state(null);
55
57
  let query = $state('');
56
- let active = $state(0);
57
58
 
58
- const matches = $derived.by(() => {
59
- const needle = query.trim().toLowerCase();
60
- if (!needle) return items;
61
- return items.filter((item) =>
62
- `${item.label} ${item.description ?? ''} ${item.keywords ?? ''} ${item.group ?? ''}`
63
- .toLowerCase()
64
- .includes(needle)
65
- );
66
- });
67
-
68
- const groups = $derived.by(() => {
69
- const out: [string, CommandItem[]][] = [];
70
- for (const item of matches) {
71
- const key = item.group ?? '';
72
- const bucket = out.find(([name]) => name === key);
73
- if (bucket) bucket[1].push(item);
74
- else out.push([key, [item]]);
75
- }
76
- return out;
77
- });
59
+ const matches = $derived(
60
+ matchQuery(
61
+ items,
62
+ query,
63
+ (item) => `${item.label} ${item.description ?? ''} ${item.keywords ?? ''} ${item.group ?? ''}`
64
+ )
65
+ );
78
66
 
67
+ const groups = $derived(groupItems(matches));
79
68
  const flat = $derived(groups.flatMap(([, group]) => group));
80
69
 
70
+ const cursor = new ListCursor(() => flat);
71
+ const active = $derived(cursor.index);
72
+
81
73
  $effect(() => {
82
74
  if (!dialog) return;
83
- if (open && !dialog.open) {
84
- dialog.showModal();
75
+ const wasOpen = dialog.open;
76
+ syncDialog(dialog, open);
77
+ if (open && !wasOpen) {
85
78
  query = '';
86
- active = 0;
79
+ cursor.reset();
87
80
  queueMicrotask(() => inputEl?.focus());
88
- } else if (!open && dialog.open) {
89
- dialog.close();
90
81
  }
91
82
  });
92
83
 
@@ -110,14 +101,8 @@
110
101
  }
111
102
 
112
103
  function move(step: number) {
113
- if (flat.length === 0) return;
114
- let next = active;
115
- for (let i = 0; i < flat.length; i++) {
116
- next = (next + step + flat.length) % flat.length;
117
- if (!flat[next].disabled) break;
118
- }
119
- active = next;
120
- listEl?.querySelector(`[data-index="${next}"]`)?.scrollIntoView({ block: 'nearest' });
104
+ cursor.move(step);
105
+ revealIndex(listEl, cursor.index);
121
106
  }
122
107
 
123
108
  function onKeydown(event: KeyboardEvent) {
@@ -131,9 +116,9 @@
131
116
  move(-1);
132
117
  break;
133
118
  case 'Enter':
134
- if (flat[active]) {
119
+ if (cursor.current) {
135
120
  event.preventDefault();
136
- run(flat[active]);
121
+ run(cursor.current);
137
122
  }
138
123
  break;
139
124
  case 'Escape':
@@ -166,7 +151,7 @@
166
151
  <input
167
152
  bind:this={inputEl}
168
153
  bind:value={query}
169
- oninput={() => (active = 0)}
154
+ oninput={() => cursor.reset()}
170
155
  type="text"
171
156
  autocomplete="off"
172
157
  aria-label={placeholder ?? t.current.commandPlaceholder}
@@ -203,7 +188,7 @@
203
188
  aria-selected={index === active}
204
189
  aria-disabled={item.disabled}
205
190
  onclick={() => run(item)}
206
- onpointermove={() => (active = index)}
191
+ onpointermove={() => (cursor.index = index)}
207
192
  class="flex cursor-pointer items-center gap-3 px-4 py-2.5 font-sans text-[14px] transition-colors duration-100
208
193
  {item.disabled ? 'pointer-events-none opacity-40' : ''}
209
194
  {index === active ? toneSoft[tone] : 'text-text-secondary'}"
@@ -12,7 +12,7 @@ export interface CommandItem {
12
12
  disabled?: boolean;
13
13
  onselect?: () => void;
14
14
  }
15
- import { type Tone } from '../tones.js';
15
+ import { type Tone } from '../../core/tones.js';
16
16
  interface Props {
17
17
  open?: boolean;
18
18
  items: CommandItem[];
@@ -2,8 +2,8 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import Button from './Button.svelte';
4
4
  import Modal from './Modal.svelte';
5
- import { useLocale } from '../locale.svelte.js';
6
- import { toneSoft, type Tone } from '../tones.js';
5
+ import { useLocale } from '../../core/locale.svelte.js';
6
+ import { toneSoft, type Tone } from '../../core/tones.js';
7
7
 
8
8
  interface Props {
9
9
  open?: boolean;
@@ -1,5 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
- import { type Tone } from '../tones.js';
2
+ import { type Tone } from '../../core/tones.js';
3
3
  interface Props {
4
4
  open?: boolean;
5
5
  title: string;
@@ -17,6 +17,6 @@ interface Props {
17
17
  /** Extra content between the description and the buttons. */
18
18
  children?: Snippet;
19
19
  }
20
- declare const ConfirmDialog: import("svelte").Component<Props, {}, "loading" | "open">;
20
+ declare const ConfirmDialog: import("svelte").Component<Props, {}, "open" | "loading">;
21
21
  type ConfirmDialog = ReturnType<typeof ConfirmDialog>;
22
22
  export default ConfirmDialog;
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
- import { anchored } from '../actions/anchor.js';
4
- import { clickOutside, focusTrap, navigateList, portal } from '../actions/dismissable.js';
5
- import { useLocale } from '../locale.svelte.js';
3
+ import { anchored } from '../../core/actions/anchor.js';
4
+ import { clickOutside, focusTrap, navigateList, portal } from '../../core/actions/dismissable.js';
5
+ import { menuItems } from '../../core/trigger.js';
6
+ import { useLocale } from '../../core/locale.svelte.js';
6
7
 
7
8
  interface Props {
8
9
  /** The region that responds to a right-click. */
@@ -57,10 +58,7 @@
57
58
  open = false;
58
59
  return;
59
60
  }
60
- if (!menuEl) return;
61
- navigateList(event, [
62
- ...menuEl.querySelectorAll<HTMLElement>('[role="menuitem"]:not([disabled])')
63
- ]);
61
+ navigateList(event, menuItems(menuEl));
64
62
  }
65
63
  </script>
66
64
 
@@ -1,9 +1,10 @@
1
1
  <script lang="ts">
2
- import { anchored } from '../actions/anchor.js';
3
- import { clickOutside, portal } from '../actions/dismissable.js';
4
- import { formatISO, parseFormatted } from '../date.js';
5
- import { useLocale } from '../locale.svelte.js';
6
- import { toneFocusWithinBorder, type Tone } from '../tones.js';
2
+ import { anchored } from '../../core/actions/anchor.js';
3
+ import { clickOutside, portal } from '../../core/actions/dismissable.js';
4
+ import { dateHint } from '../../core/calendar.js';
5
+ import { formatISO, parseFormatted } from '../../core/date.js';
6
+ import { useLocale } from '../../core/locale.svelte.js';
7
+ import { toneFocusWithinBorder, type Tone } from '../../core/tones.js';
7
8
  import Calendar from './Calendar.svelte';
8
9
 
9
10
  interface Props {
@@ -53,12 +54,7 @@
53
54
 
54
55
  /** While typing the field shows the raw text; otherwise the formatted value. */
55
56
  const display = $derived(editing ? text : formatISO(value, t.current.dateFormat));
56
- const hint = $derived(placeholder ?? formatHint());
57
-
58
- function formatHint() {
59
- const parts = { dmy: 'DD/MM/YYYY', mdy: 'MM/DD/YYYY', ymd: 'YYYY/MM/DD' };
60
- return parts[t.current.dateFormat];
61
- }
57
+ const hint = $derived(placeholder ?? dateHint(t.current.dateFormat));
62
58
 
63
59
  function commit() {
64
60
  editing = false;
@@ -1,4 +1,4 @@
1
- import { type Tone } from '../tones.js';
1
+ import { type Tone } from '../../core/tones.js';
2
2
  interface Props {
3
3
  /** Bindable `YYYY-MM-DD` — the same shape as `<input type="date">`. */
4
4
  value?: string;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLDialogAttributes } from 'svelte/elements';
4
- import { useLocale } from '../locale.svelte.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+ import { isBackdropClick, syncDialog } from '../../core/dialog.svelte.js';
5
6
 
6
7
  export type DrawerSide = 'left' | 'right' | 'top' | 'bottom';
7
8
  export type DrawerSize = 'sm' | 'md' | 'lg' | 'full';
@@ -67,11 +68,7 @@
67
68
  bottom: 'animate-[drawer-bottom_220ms_cubic-bezier(0.16,1,0.3,1)]'
68
69
  };
69
70
 
70
- $effect(() => {
71
- if (!dialog) return;
72
- if (open && !dialog.open) dialog.showModal();
73
- else if (!open && dialog.open) dialog.close();
74
- });
71
+ $effect(() => syncDialog(dialog, open));
75
72
 
76
73
  function close() {
77
74
  open = false;
@@ -83,7 +80,7 @@
83
80
  bind:this={dialog}
84
81
  onclose={close}
85
82
  onclick={(event) => {
86
- if (dismissible && event.target === dialog) close();
83
+ if (dismissible && isBackdropClick(event, dialog)) close();
87
84
  }}
88
85
  oncancel={(event) => {
89
86
  if (!dismissible) event.preventDefault();
@@ -1,8 +1,9 @@
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, navigateList, portal } from '../actions/dismissable.js';
5
- import { useLocale } from '../locale.svelte.js';
3
+ import { anchored, type Placement } from '../../core/actions/anchor.js';
4
+ import { clickOutside, focusTrap, navigateList, portal } from '../../core/actions/dismissable.js';
5
+ import { describeTrigger, menuItems, popupTrigger } from '../../core/trigger.js';
6
+ import { useLocale } from '../../core/locale.svelte.js';
6
7
 
7
8
  interface Props {
8
9
  /** The control that opens the menu — put a `Button` in here. */
@@ -41,34 +42,8 @@
41
42
  let anchorEl: HTMLElement | null = $state(null);
42
43
  let menuEl: HTMLElement | null = $state(null);
43
44
 
44
- /**
45
- * Wires the consumer's own trigger element rather than wrapping it in another
46
- * button: the ARIA state belongs on the real control, not on our span.
47
- */
48
- function triggerBehaviour(node: HTMLElement) {
49
- const toggle = () => (open = !open);
50
- const onKeydown = (event: KeyboardEvent) => {
51
- if (event.key === 'ArrowDown' && !open) {
52
- event.preventDefault();
53
- open = true;
54
- }
55
- };
56
- node.addEventListener('click', toggle);
57
- node.addEventListener('keydown', onKeydown);
58
- return {
59
- destroy() {
60
- node.removeEventListener('click', toggle);
61
- node.removeEventListener('keydown', onKeydown);
62
- }
63
- };
64
- }
65
-
66
- $effect(() => {
67
- const control = anchorEl?.querySelector('button, a, [role="button"]');
68
- if (!control) return;
69
- control.setAttribute('aria-haspopup', 'menu');
70
- control.setAttribute('aria-expanded', String(open));
71
- });
45
+ // The ARIA state goes on the consumer's own control, not on our wrapper.
46
+ $effect(() => describeTrigger(anchorEl, 'menu', open));
72
47
 
73
48
  function onMenuKeydown(event: KeyboardEvent) {
74
49
  if (event.key === 'Escape' || event.key === 'Tab') {
@@ -77,10 +52,7 @@
77
52
  open = false;
78
53
  return;
79
54
  }
80
- if (!menuEl) return;
81
- navigateList(event, [
82
- ...menuEl.querySelectorAll<HTMLElement>('[role="menuitem"]:not([disabled])')
83
- ]);
55
+ navigateList(event, menuItems(menuEl));
84
56
  }
85
57
 
86
58
  function onMenuClick(event: MouseEvent) {
@@ -89,7 +61,17 @@
89
61
  }
90
62
  </script>
91
63
 
92
- <span bind:this={anchorEl} use:triggerBehaviour class="inline-flex {triggerClass}">
64
+ <span
65
+ bind:this={anchorEl}
66
+ use:popupTrigger={{
67
+ toggle: () => (open = !open),
68
+ open: () => (open = true),
69
+ close: () => (open = false),
70
+ arrowOpens: true,
71
+ isOpen: () => open
72
+ }}
73
+ class="inline-flex {triggerClass}"
74
+ >
93
75
  {@render trigger()}
94
76
  </span>
95
77
 
@@ -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
  /** The control that opens the menu — put a `Button` in here. */
5
5
  trigger: Snippet;
@@ -1,12 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
- import { toneBorder, toneSoft, toneSurface, toneText, type Tone } from '../tones.js';
4
- import { useLocale } from '../locale.svelte.js';
5
-
6
- export interface RejectedFile {
7
- file: File;
8
- reason: 'type' | 'size' | 'count';
9
- }
3
+ import { toneBorder, toneSoft, toneSurface, toneText, type Tone } from '../../core/tones.js';
4
+ import { useLocale } from '../../core/locale.svelte.js';
5
+ import { formatSize as toReadableSize, sortFiles, type RejectedFile } from '../../core/files.js';
10
6
 
11
7
  interface Props {
12
8
  /** Bindable list of accepted files. */
@@ -67,46 +63,18 @@
67
63
  return parts.join(' · ');
68
64
  });
69
65
 
70
- function formatSize(bytes: number) {
71
- const units = t.current.byteUnits;
72
- if (bytes < 1024) return `${bytes} ${units[0]}`;
73
- let value = bytes / 1024;
74
- let i = 1;
75
- while (value >= 1024 && i < units.length - 1) {
76
- value /= 1024;
77
- i++;
78
- }
79
- return `${value.toFixed(Number.isInteger(value) || value >= 10 ? 0 : 1)} ${units[i]}`;
80
- }
81
-
82
- function matchesAccept(file: File) {
83
- if (!accept) return true;
84
- return accept.split(',').some((raw) => {
85
- const rule = raw.trim().toLowerCase();
86
- if (!rule) return true;
87
- if (rule.startsWith('.')) return file.name.toLowerCase().endsWith(rule);
88
- if (rule.endsWith('/*')) return file.type.startsWith(rule.slice(0, -1));
89
- return file.type.toLowerCase() === rule;
90
- });
91
- }
66
+ const formatSize = (bytes: number) => toReadableSize(bytes, t.current.byteUnits);
92
67
 
93
68
  function add(incoming: FileList | File[] | null) {
94
69
  if (!incoming || disabled) return;
95
70
 
96
- const accepted: File[] = [];
97
- const bad: RejectedFile[] = [];
98
- let room = maxFiles ? maxFiles - (multiple ? files.length : 0) : Infinity;
99
-
100
- for (const file of Array.from(incoming)) {
101
- if (!matchesAccept(file)) bad.push({ file, reason: 'type' });
102
- else if (maxSize && file.size > maxSize) bad.push({ file, reason: 'size' });
103
- else if (room <= 0) bad.push({ file, reason: 'count' });
104
- else {
105
- accepted.push(file);
106
- room--;
107
- }
108
- if (!multiple && accepted.length === 1) break;
109
- }
71
+ const { accepted, rejected: bad } = sortFiles(incoming, {
72
+ accept,
73
+ maxSize,
74
+ maxFiles,
75
+ multiple,
76
+ held: files.length
77
+ });
110
78
 
111
79
  rejected = bad;
112
80
  if (bad.length) onreject?.(bad);
@@ -1,9 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
- import { type Tone } from '../tones.js';
3
- export interface RejectedFile {
4
- file: File;
5
- reason: 'type' | 'size' | 'count';
6
- }
2
+ import { type Tone } from '../../core/tones.js';
3
+ import { type RejectedFile } from '../../core/files.js';
7
4
  interface Props {
8
5
  /** Bindable list of accepted files. */
9
6
  files?: File[];
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
- import { toneSoft, type Tone } from '../tones.js';
4
+ import { toneSoft, type Tone } from '../../core/tones.js';
5
5
 
6
6
  interface Props extends HTMLAttributes<HTMLDivElement> {
7
7
  title: string;
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { type Tone } from '../tones.js';
3
+ import { type Tone } from '../../core/tones.js';
4
4
  interface Props extends HTMLAttributes<HTMLDivElement> {
5
5
  title: string;
6
6
  description?: string;
@@ -0,0 +1,58 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { focusRing, toneHoverText, toneRing, toneSoft, type Tone } from '../../core/tones.js';
5
+
6
+ interface Props extends HTMLAttributes<HTMLDivElement> {
7
+ title: string;
8
+ description?: string;
9
+ tone?: Tone;
10
+ /** Turns the whole card into a link. */
11
+ href?: string;
12
+ /** Glyph inside the tinted square. */
13
+ icon?: Snippet;
14
+ children?: Snippet;
15
+ }
16
+
17
+ let {
18
+ title,
19
+ description,
20
+ tone = 'brand',
21
+ href,
22
+ icon,
23
+ class: className = '',
24
+ children,
25
+ ...rest
26
+ }: Props = $props();
27
+ </script>
28
+
29
+ <svelte:element
30
+ this={href ? 'a' : 'div'}
31
+ {href}
32
+ class="group flex flex-col gap-3 bg-bg p-6 {href
33
+ ? `transition-colors duration-150 ease-brand-out ${focusRing} ${toneRing[tone]}`
34
+ : ''} {className}"
35
+ {...rest}
36
+ >
37
+ {#if icon}
38
+ <span class="flex size-10 items-center justify-center {toneSoft[tone]}">
39
+ {@render icon()}
40
+ </span>
41
+ {/if}
42
+
43
+ <h3
44
+ class="font-heading text-base font-medium text-text {href
45
+ ? `transition-colors duration-150 ${toneHoverText[tone]}`
46
+ : ''}"
47
+ >
48
+ {title}
49
+ </h3>
50
+
51
+ {#if description}
52
+ <p class="font-sans text-sm leading-relaxed text-text-secondary">{description}</p>
53
+ {/if}
54
+
55
+ {#if children}
56
+ {@render children()}
57
+ {/if}
58
+ </svelte:element>
@@ -0,0 +1,16 @@
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
+ title: string;
6
+ description?: string;
7
+ tone?: Tone;
8
+ /** Turns the whole card into a link. */
9
+ href?: string;
10
+ /** Glyph inside the tinted square. */
11
+ icon?: Snippet;
12
+ children?: Snippet;
13
+ }
14
+ declare const FeatureCard: import("svelte").Component<Props, {}, "">;
15
+ type FeatureCard = ReturnType<typeof FeatureCard>;
16
+ export default FeatureCard;
@@ -0,0 +1,62 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+
5
+ export type FeatureColumns = 2 | 3 | 4;
6
+
7
+ interface Props extends HTMLAttributes<HTMLElement> {
8
+ eyebrow?: string;
9
+ title?: string;
10
+ description?: string;
11
+ columns?: FeatureColumns;
12
+ /** Hairline grid rather than free-standing cards. */
13
+ bordered?: boolean;
14
+ /** `FeatureCard`s, or anything else. */
15
+ children: Snippet;
16
+ }
17
+
18
+ let {
19
+ eyebrow,
20
+ title,
21
+ description,
22
+ columns = 3,
23
+ bordered = false,
24
+ class: className = '',
25
+ children,
26
+ ...rest
27
+ }: Props = $props();
28
+
29
+ const cols: Record<FeatureColumns, string> = {
30
+ 2: 'sm:grid-cols-2',
31
+ 3: 'sm:grid-cols-2 lg:grid-cols-3',
32
+ 4: 'sm:grid-cols-2 lg:grid-cols-4'
33
+ };
34
+ </script>
35
+
36
+ <section class="w-full px-6 py-20 {className}" {...rest}>
37
+ <div class="mx-auto flex w-full max-w-6xl flex-col gap-12">
38
+ {#if eyebrow || title || description}
39
+ <div class="flex max-w-xl flex-col gap-3">
40
+ {#if eyebrow}
41
+ <span class="font-mono text-xs tracking-wide text-text-muted uppercase">{eyebrow}</span>
42
+ {/if}
43
+ {#if title}
44
+ <h2 class="font-heading text-3xl font-medium tracking-tight text-balance text-text">
45
+ {title}
46
+ </h2>
47
+ {/if}
48
+ {#if description}
49
+ <p class="font-sans leading-relaxed text-pretty text-text-secondary">{description}</p>
50
+ {/if}
51
+ </div>
52
+ {/if}
53
+
54
+ <div
55
+ class="grid {cols[columns]} {bordered
56
+ ? 'gap-px border border-hairline bg-hairline'
57
+ : 'gap-10'}"
58
+ >
59
+ {@render children()}
60
+ </div>
61
+ </div>
62
+ </section>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ export type FeatureColumns = 2 | 3 | 4;
4
+ interface Props extends HTMLAttributes<HTMLElement> {
5
+ eyebrow?: string;
6
+ title?: string;
7
+ description?: string;
8
+ columns?: FeatureColumns;
9
+ /** Hairline grid rather than free-standing cards. */
10
+ bordered?: boolean;
11
+ /** `FeatureCard`s, or anything else. */
12
+ children: Snippet;
13
+ }
14
+ declare const FeatureGrid: import("svelte").Component<Props, {}, "">;
15
+ type FeatureGrid = ReturnType<typeof FeatureGrid>;
16
+ export default FeatureGrid;
@@ -13,7 +13,7 @@
13
13
 
14
14
  <script lang="ts">
15
15
  import type { Snippet } from 'svelte';
16
- import { toneHoverText, type Tone } from '../tones.js';
16
+ import { toneHoverText, type Tone } from '../../core/tones.js';
17
17
 
18
18
  interface Props {
19
19
  columns?: FooterColumn[];
@@ -8,7 +8,7 @@ export interface FooterColumn {
8
8
  links: FooterLink[];
9
9
  }
10
10
  import type { Snippet } from 'svelte';
11
- import { type Tone } from '../tones.js';
11
+ import { type Tone } from '../../core/tones.js';
12
12
  interface Props {
13
13
  columns?: FooterColumn[];
14
14
  /** Logo, wordmark and a line of copy on the left. */