@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
@@ -0,0 +1,18 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import { type Tone } from '../../core/tones.js';
4
+ export type CTAVariant = 'tinted' | 'solid' | 'outline';
5
+ interface Props extends HTMLAttributes<HTMLElement> {
6
+ title: string;
7
+ description?: string;
8
+ tone?: Tone;
9
+ variant?: CTAVariant;
10
+ /** Side by side on wide screens instead of stacked and centred. */
11
+ inline?: boolean;
12
+ /** The buttons. */
13
+ actions?: Snippet;
14
+ children?: Snippet;
15
+ }
16
+ declare const CTASection: import("svelte").Component<Props, {}, "">;
17
+ type CTASection = ReturnType<typeof CTASection>;
18
+ export default CTASection;
@@ -1,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import {
3
- addDays,
4
3
  addMonths,
5
4
  fromISO,
6
5
  isOutOfRange,
@@ -10,9 +9,10 @@
10
9
  toISO,
11
10
  today,
12
11
  weekdayNames
13
- } from '../date.js';
14
- import { useLocale } from '../locale.svelte.js';
15
- import { focusRing, toneFill, toneRing, toneText, type Tone } from '../tones.js';
12
+ } from '../../core/date.js';
13
+ import { calendarKeyMove } from '../../core/calendar.js';
14
+ import { useLocale } from '../../core/locale.svelte.js';
15
+ import { focusRing, toneFill, toneRing, toneText, type Tone } from '../../core/tones.js';
16
16
 
17
17
  interface Props {
18
18
  /** Bindable `YYYY-MM-DD`, or `''` for nothing selected. */
@@ -91,20 +91,10 @@
91
91
  }
92
92
 
93
93
  function onKeydown(event: KeyboardEvent) {
94
- const moves: Record<string, () => Date> = {
95
- ArrowLeft: () => addDays(focused, -1),
96
- ArrowRight: () => addDays(focused, 1),
97
- ArrowUp: () => addDays(focused, -7),
98
- ArrowDown: () => addDays(focused, 7),
99
- Home: () => addDays(focused, -((focused.getDay() - weekStart + 7) % 7)),
100
- End: () => addDays(focused, 6 - ((focused.getDay() - weekStart + 7) % 7)),
101
- PageUp: () => addMonths(focused, event.shiftKey ? -12 : -1),
102
- PageDown: () => addMonths(focused, event.shiftKey ? 12 : 1)
103
- };
104
- const move = moves[event.key];
105
- if (move) {
94
+ const next = calendarKeyMove(event.key, focused, weekStart, event.shiftKey);
95
+ if (next) {
106
96
  event.preventDefault();
107
- moveFocus(move());
97
+ moveFocus(next);
108
98
  return;
109
99
  }
110
100
  if (event.key === 'Enter' || event.key === ' ') {
@@ -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`, or `''` for nothing selected. */
4
4
  value?: string;
@@ -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 { toneBorderLeft, toneHoverBorder, toneSurface, type Tone } from '../tones.js';
4
+ import { toneBorderLeft, toneHoverBorder, toneSurface, type Tone } from '../../core/tones.js';
5
5
 
6
6
  export type CardVariant = 'outline' | 'filled' | 'tinted';
7
7
 
@@ -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
  export type CardVariant = 'outline' | 'filled' | 'tinted';
5
5
  interface Props extends HTMLAttributes<HTMLDivElement> {
6
6
  variant?: CardVariant;
@@ -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
  checked?: boolean;
@@ -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
  checked?: boolean;
6
6
  /** Renders the dash state — visual only, `checked` stays false. */
@@ -2,7 +2,7 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLFieldsetAttributes } from 'svelte/elements';
4
4
  import Checkbox from './Checkbox.svelte';
5
- import type { Tone } from '../tones.js';
5
+ import type { Tone } from '../../core/tones.js';
6
6
 
7
7
  export interface CheckboxOption {
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 CheckboxOption {
5
5
  value: string;
6
6
  label: string;
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">
2
- import { anchored } from '../actions/anchor.js';
3
- import { clickOutside, portal } from '../actions/dismissable.js';
4
- import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../tones.js';
5
- import { useLocale } from '../locale.svelte.js';
2
+ import { anchored } from '../../core/actions/anchor.js';
3
+ import { clickOutside, portal } from '../../core/actions/dismissable.js';
4
+ import { ListCursor, groupItems, matchQuery, revealIndex } from '../../core/list.svelte.js';
5
+ import { toneFocusWithinBorder, toneSoft, toneText, type Tone } from '../../core/tones.js';
6
+ import { useLocale } from '../../core/locale.svelte.js';
6
7
 
7
8
  export interface ComboboxOption {
8
9
  value: string;
@@ -50,45 +51,35 @@
50
51
 
51
52
  let open = $state(false);
52
53
  let query = $state('');
53
- let active = $state(0);
54
54
  let wrapper: HTMLElement | null = $state(null);
55
55
  let inputEl: HTMLInputElement | null = $state(null);
56
56
  let listEl: HTMLElement | null = $state(null);
57
57
 
58
58
  const selected = $derived(options.find((option) => option.value === value));
59
59
 
60
- const matches = $derived.by(() => {
61
- const needle = query.trim().toLowerCase();
62
- if (!needle) return options;
63
- return options.filter(
64
- (option) =>
65
- option.label.toLowerCase().includes(needle) ||
66
- option.description?.toLowerCase().includes(needle)
67
- );
68
- });
60
+ const matches = $derived(
61
+ matchQuery(options, query, (option) => `${option.label} ${option.description ?? ''}`)
62
+ );
69
63
 
70
64
  /** Options in render order, grouped when any option declares a `group`. */
71
- const groups = $derived.by(() => {
72
- const out: [string, ComboboxOption[]][] = [];
73
- for (const option of matches) {
74
- const key = option.group ?? '';
75
- const bucket = out.find(([name]) => name === key);
76
- if (bucket) bucket[1].push(option);
77
- else out.push([key, [option]]);
78
- }
79
- return out;
80
- });
81
-
65
+ const groups = $derived(groupItems(matches));
82
66
  const flat = $derived(groups.flatMap(([, items]) => items));
83
67
 
68
+ const cursor = new ListCursor(() => flat);
69
+ const active = $derived(cursor.index);
70
+
71
+ /**
72
+ * Set while we hand focus back to the field after a choice. Focusing fires
73
+ * `focus` synchronously, and this field opens on focus — without the guard,
74
+ * picking an option would immediately reopen the list it just closed.
75
+ */
76
+ let restoring = false;
77
+
84
78
  function openList() {
85
- if (disabled || open) return;
79
+ if (disabled || open || restoring) return;
86
80
  open = true;
87
81
  query = '';
88
- active = Math.max(
89
- 0,
90
- flat.findIndex((option) => option.value === value)
91
- );
82
+ cursor.reset((option) => option.value === value);
92
83
  }
93
84
 
94
85
  function choose(option: ComboboxOption) {
@@ -97,7 +88,9 @@
97
88
  onchange?.(option.value);
98
89
  open = false;
99
90
  query = '';
91
+ restoring = true;
100
92
  inputEl?.focus();
93
+ restoring = false;
101
94
  }
102
95
 
103
96
  function clear(event: MouseEvent) {
@@ -105,18 +98,14 @@
105
98
  value = '';
106
99
  query = '';
107
100
  onchange?.('');
101
+ restoring = true;
108
102
  inputEl?.focus();
103
+ restoring = false;
109
104
  }
110
105
 
111
106
  function move(step: number) {
112
- if (flat.length === 0) return;
113
- let next = active;
114
- for (let i = 0; i < flat.length; i++) {
115
- next = (next + step + flat.length) % flat.length;
116
- if (!flat[next].disabled) break;
117
- }
118
- active = next;
119
- listEl?.querySelector(`[data-index="${next}"]`)?.scrollIntoView({ block: 'nearest' });
107
+ cursor.move(step);
108
+ revealIndex(listEl, cursor.index);
120
109
  }
121
110
 
122
111
  function onKeydown(event: KeyboardEvent) {
@@ -131,9 +120,9 @@
131
120
  if (open) move(-1);
132
121
  break;
133
122
  case 'Enter':
134
- if (open && flat[active]) {
123
+ if (open && cursor.current) {
135
124
  event.preventDefault();
136
- choose(flat[active]);
125
+ choose(cursor.current);
137
126
  }
138
127
  break;
139
128
  case 'Escape':
@@ -173,7 +162,7 @@
173
162
  oninput={(event) => {
174
163
  query = event.currentTarget.value;
175
164
  open = true;
176
- active = 0;
165
+ cursor.index = 0;
177
166
  }}
178
167
  onfocus={openList}
179
168
  onkeydown={onKeydown}
@@ -239,7 +228,7 @@
239
228
  aria-selected={option.value === value}
240
229
  aria-disabled={option.disabled}
241
230
  onclick={() => choose(option)}
242
- onpointermove={() => (active = index)}
231
+ onpointermove={() => (cursor.index = index)}
243
232
  class="flex cursor-pointer flex-col gap-0.5 px-3 py-2 text-[14px] transition-colors duration-100
244
233
  {option.disabled ? 'pointer-events-none opacity-40' : ''}
245
234
  {index === active ? toneSoft[tone] : 'text-text-secondary'}"
@@ -1,4 +1,4 @@
1
- import { type Tone } from '../tones.js';
1
+ import { type Tone } from '../../core/tones.js';
2
2
  export interface ComboboxOption {
3
3
  value: string;
4
4
  label: string;
@@ -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;