@seekalfred/primitives 0.6.0 → 0.7.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 (322) hide show
  1. package/README.md +19 -11
  2. package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
  3. package/dist/activity-heatmap/activity-heatmap.js +699 -0
  4. package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
  5. package/dist/activity-heatmap/index.d.ts +2 -0
  6. package/dist/activity-heatmap/index.js +2 -0
  7. package/dist/alert/alert.d.ts +5 -1
  8. package/dist/alert/alert.js +68 -7
  9. package/dist/alert/alert.js.map +1 -1
  10. package/dist/alert-dialog/alert-dialog.d.ts +45 -18
  11. package/dist/alert-dialog/alert-dialog.js +128 -9
  12. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  13. package/dist/alert-dialog/index.d.ts +2 -2
  14. package/dist/alert-dialog/index.js +2 -2
  15. package/dist/animated-counter/animated-counter.d.ts +38 -0
  16. package/dist/animated-counter/animated-counter.js +230 -0
  17. package/dist/animated-counter/animated-counter.js.map +1 -0
  18. package/dist/animated-counter/index.d.ts +2 -0
  19. package/dist/animated-counter/index.js +2 -0
  20. package/dist/announcement-bar/announcement-bar.d.ts +67 -0
  21. package/dist/announcement-bar/announcement-bar.js +364 -0
  22. package/dist/announcement-bar/announcement-bar.js.map +1 -0
  23. package/dist/announcement-bar/index.d.ts +2 -0
  24. package/dist/announcement-bar/index.js +2 -0
  25. package/dist/badge/badge.d.ts +1 -1
  26. package/dist/bar-chart/bar-chart.d.ts +51 -0
  27. package/dist/bar-chart/bar-chart.js +565 -0
  28. package/dist/bar-chart/bar-chart.js.map +1 -0
  29. package/dist/bar-chart/index.d.ts +2 -0
  30. package/dist/bar-chart/index.js +2 -0
  31. package/dist/breadcrumb/breadcrumb.d.ts +2 -2
  32. package/dist/breadcrumb/breadcrumb.js +12 -3
  33. package/dist/breadcrumb/breadcrumb.js.map +1 -1
  34. package/dist/brush-chart/brush-chart.d.ts +64 -0
  35. package/dist/brush-chart/brush-chart.js +1056 -0
  36. package/dist/brush-chart/brush-chart.js.map +1 -0
  37. package/dist/brush-chart/index.d.ts +2 -0
  38. package/dist/brush-chart/index.js +2 -0
  39. package/dist/button/button.d.ts +2 -2
  40. package/dist/button/button.js +31 -21
  41. package/dist/button/button.js.map +1 -1
  42. package/dist/button-group/button-group.js +3 -4
  43. package/dist/button-group/button-group.js.map +1 -1
  44. package/dist/card/card.js +1 -1
  45. package/dist/card/card.js.map +1 -1
  46. package/dist/card-stack/card-stack.d.ts +54 -0
  47. package/dist/card-stack/card-stack.js +492 -0
  48. package/dist/card-stack/card-stack.js.map +1 -0
  49. package/dist/card-stack/index.d.ts +2 -0
  50. package/dist/card-stack/index.js +2 -0
  51. package/dist/carousel/carousel.d.ts +56 -0
  52. package/dist/carousel/carousel.js +389 -0
  53. package/dist/carousel/carousel.js.map +1 -0
  54. package/dist/carousel/index.d.ts +2 -0
  55. package/dist/carousel/index.js +2 -0
  56. package/dist/checkbox/checkbox.js +4 -4
  57. package/dist/checkbox/checkbox.js.map +1 -1
  58. package/dist/chip-group/chip-group.d.ts +37 -0
  59. package/dist/chip-group/chip-group.js +148 -0
  60. package/dist/chip-group/chip-group.js.map +1 -0
  61. package/dist/chip-group/index.d.ts +2 -0
  62. package/dist/chip-group/index.js +2 -0
  63. package/dist/countdown/countdown.d.ts +45 -0
  64. package/dist/countdown/countdown.js +298 -0
  65. package/dist/countdown/countdown.js.map +1 -0
  66. package/dist/countdown/index.d.ts +2 -0
  67. package/dist/countdown/index.js +2 -0
  68. package/dist/date-picker/picker-parts.js +1 -1
  69. package/dist/date-picker/picker-parts.js.map +1 -1
  70. package/dist/dialog/dialog.js +1 -1
  71. package/dist/dialog/dialog.js.map +1 -1
  72. package/dist/donut-chart/donut-chart.d.ts +64 -0
  73. package/dist/donut-chart/donut-chart.js +576 -0
  74. package/dist/donut-chart/donut-chart.js.map +1 -0
  75. package/dist/donut-chart/index.d.ts +2 -0
  76. package/dist/donut-chart/index.js +2 -0
  77. package/dist/empty-state/empty-state.d.ts +21 -10
  78. package/dist/empty-state/empty-state.js +32 -26
  79. package/dist/empty-state/empty-state.js.map +1 -1
  80. package/dist/empty-state/index.d.ts +2 -2
  81. package/dist/empty-state/index.js +2 -2
  82. package/dist/file-drop-zone/file-drop-zone.js +1 -1
  83. package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
  84. package/dist/filter-bar/filter-bar.d.ts +47 -26
  85. package/dist/filter-bar/filter-bar.js +272 -156
  86. package/dist/filter-bar/filter-bar.js.map +1 -1
  87. package/dist/gauge/gauge.d.ts +45 -0
  88. package/dist/gauge/gauge.js +219 -0
  89. package/dist/gauge/gauge.js.map +1 -0
  90. package/dist/gauge/index.d.ts +2 -0
  91. package/dist/gauge/index.js +2 -0
  92. package/dist/in-view-title/in-view-title.d.ts +33 -0
  93. package/dist/in-view-title/in-view-title.js +119 -0
  94. package/dist/in-view-title/in-view-title.js.map +1 -0
  95. package/dist/in-view-title/index.d.ts +2 -0
  96. package/dist/in-view-title/index.js +2 -0
  97. package/dist/index.d.ts +49 -6
  98. package/dist/index.js +48 -8
  99. package/dist/lib/cn.js +11 -1
  100. package/dist/lib/cn.js.map +1 -1
  101. package/dist/lib/field-message.js +28 -10
  102. package/dist/lib/field-message.js.map +1 -1
  103. package/dist/lib/field-surface.js +9 -8
  104. package/dist/lib/field-surface.js.map +1 -1
  105. package/dist/lib/flag-emoji.js +50 -0
  106. package/dist/lib/flag-emoji.js.map +1 -0
  107. package/dist/lib/flip.js +11 -3
  108. package/dist/lib/flip.js.map +1 -1
  109. package/dist/lib/menu-highlight.js +64 -0
  110. package/dist/lib/menu-highlight.js.map +1 -0
  111. package/dist/lib/motion.js +9 -2
  112. package/dist/lib/motion.js.map +1 -1
  113. package/dist/lib/rolling-value.js +1 -1
  114. package/dist/lib/rolling-value.js.map +1 -1
  115. package/dist/lib/spring-tween.js +500 -0
  116. package/dist/lib/spring-tween.js.map +1 -0
  117. package/dist/lib/swap-text.js +3 -1
  118. package/dist/lib/swap-text.js.map +1 -1
  119. package/dist/line-chart/index.d.ts +2 -0
  120. package/dist/line-chart/index.js +2 -0
  121. package/dist/line-chart/line-chart.d.ts +76 -0
  122. package/dist/line-chart/line-chart.js +611 -0
  123. package/dist/line-chart/line-chart.js.map +1 -0
  124. package/dist/mention-input/index.d.ts +2 -0
  125. package/dist/mention-input/index.js +2 -0
  126. package/dist/mention-input/mention-input.d.ts +98 -0
  127. package/dist/mention-input/mention-input.js +576 -0
  128. package/dist/mention-input/mention-input.js.map +1 -0
  129. package/dist/menu/menu.d.ts +2 -0
  130. package/dist/menu/menu.js +23 -12
  131. package/dist/menu/menu.js.map +1 -1
  132. package/dist/money-input/index.d.ts +2 -0
  133. package/dist/money-input/index.js +2 -0
  134. package/dist/money-input/money-input.d.ts +65 -0
  135. package/dist/money-input/money-input.js +607 -0
  136. package/dist/money-input/money-input.js.map +1 -0
  137. package/dist/morph-select/index.d.ts +2 -0
  138. package/dist/morph-select/index.js +2 -0
  139. package/dist/morph-select/morph-select.d.ts +71 -0
  140. package/dist/morph-select/morph-select.js +693 -0
  141. package/dist/morph-select/morph-select.js.map +1 -0
  142. package/dist/multi-select/index.d.ts +2 -0
  143. package/dist/multi-select/index.js +2 -0
  144. package/dist/multi-select/multi-select.d.ts +36 -0
  145. package/dist/multi-select/multi-select.js +152 -0
  146. package/dist/multi-select/multi-select.js.map +1 -0
  147. package/dist/number-field/index.d.ts +2 -0
  148. package/dist/number-field/index.js +2 -0
  149. package/dist/number-field/number-field.d.ts +42 -0
  150. package/dist/number-field/number-field.js +199 -0
  151. package/dist/number-field/number-field.js.map +1 -0
  152. package/dist/onboarding-checklist/index.d.ts +2 -0
  153. package/dist/onboarding-checklist/index.js +2 -0
  154. package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
  155. package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
  156. package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
  157. package/dist/password-field/password-field.js +2 -2
  158. package/dist/password-field/password-field.js.map +1 -1
  159. package/dist/phone-input/index.d.ts +3 -0
  160. package/dist/phone-input/index.js +3 -0
  161. package/dist/phone-input/phone-countries.d.ts +29 -0
  162. package/dist/phone-input/phone-countries.js +170 -0
  163. package/dist/phone-input/phone-countries.js.map +1 -0
  164. package/dist/phone-input/phone-input.d.ts +66 -0
  165. package/dist/phone-input/phone-input.js +440 -0
  166. package/dist/phone-input/phone-input.js.map +1 -0
  167. package/dist/popover/popover.d.ts +12 -0
  168. package/dist/popover/popover.js +31 -7
  169. package/dist/popover/popover.js.map +1 -1
  170. package/dist/progress/progress.js +1 -1
  171. package/dist/radio-group/radio-group.js +1 -1
  172. package/dist/radio-group/radio-group.js.map +1 -1
  173. package/dist/reactions/index.d.ts +2 -0
  174. package/dist/reactions/index.js +2 -0
  175. package/dist/reactions/reactions.d.ts +50 -0
  176. package/dist/reactions/reactions.js +315 -0
  177. package/dist/reactions/reactions.js.map +1 -0
  178. package/dist/rich-text-editor/index.d.ts +3 -0
  179. package/dist/rich-text-editor/index.js +2 -0
  180. package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
  181. package/dist/rich-text-editor/rich-text-editor.js +909 -0
  182. package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
  183. package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
  184. package/dist/rich-text-editor/rich-text-engine.js +366 -0
  185. package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
  186. package/dist/rich-text-editor/rich-text-html.js +174 -0
  187. package/dist/rich-text-editor/rich-text-html.js.map +1 -0
  188. package/dist/rich-text-editor/rich-text-icons.js +43 -0
  189. package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
  190. package/dist/ridgeline/index.d.ts +2 -0
  191. package/dist/ridgeline/index.js +2 -0
  192. package/dist/ridgeline/ridgeline.d.ts +55 -0
  193. package/dist/ridgeline/ridgeline.js +701 -0
  194. package/dist/ridgeline/ridgeline.js.map +1 -0
  195. package/dist/scroll-area/index.d.ts +2 -2
  196. package/dist/scroll-area/index.js +2 -2
  197. package/dist/scroll-area/scroll-area.d.ts +68 -31
  198. package/dist/scroll-area/scroll-area.js +208 -59
  199. package/dist/scroll-area/scroll-area.js.map +1 -1
  200. package/dist/scrub-input/evaluate.d.ts +14 -0
  201. package/dist/scrub-input/evaluate.js +72 -0
  202. package/dist/scrub-input/evaluate.js.map +1 -0
  203. package/dist/scrub-input/index.d.ts +3 -0
  204. package/dist/scrub-input/index.js +3 -0
  205. package/dist/scrub-input/scrub-input.d.ts +74 -0
  206. package/dist/scrub-input/scrub-input.js +486 -0
  207. package/dist/scrub-input/scrub-input.js.map +1 -0
  208. package/dist/search-field/search-field.d.ts +2 -1
  209. package/dist/search-field/search-field.js +4 -4
  210. package/dist/search-field/search-field.js.map +1 -1
  211. package/dist/select/select.d.ts +3 -1
  212. package/dist/select/select.js +20 -8
  213. package/dist/select/select.js.map +1 -1
  214. package/dist/separator/separator.d.ts +1 -1
  215. package/dist/sheet/sheet.js +2 -1
  216. package/dist/sheet/sheet.js.map +1 -1
  217. package/dist/shortcut-recorder/index.d.ts +3 -0
  218. package/dist/shortcut-recorder/index.js +3 -0
  219. package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
  220. package/dist/shortcut-recorder/shortcut-model.js +206 -0
  221. package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
  222. package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
  223. package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
  224. package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
  225. package/dist/slider/index.d.ts +2 -2
  226. package/dist/slider/slider.d.ts +46 -14
  227. package/dist/slider/slider.js +151 -67
  228. package/dist/slider/slider.js.map +1 -1
  229. package/dist/slope-chart/index.d.ts +2 -0
  230. package/dist/slope-chart/index.js +2 -0
  231. package/dist/slope-chart/slope-chart.d.ts +54 -0
  232. package/dist/slope-chart/slope-chart.js +568 -0
  233. package/dist/slope-chart/slope-chart.js.map +1 -0
  234. package/dist/sparkline/index.d.ts +2 -0
  235. package/dist/sparkline/index.js +2 -0
  236. package/dist/sparkline/sparkline.d.ts +46 -0
  237. package/dist/sparkline/sparkline.js +390 -0
  238. package/dist/sparkline/sparkline.js.map +1 -0
  239. package/dist/split-bar/index.d.ts +2 -0
  240. package/dist/split-bar/index.js +2 -0
  241. package/dist/split-bar/split-bar.d.ts +62 -0
  242. package/dist/split-bar/split-bar.js +513 -0
  243. package/dist/split-bar/split-bar.js.map +1 -0
  244. package/dist/split-button/split-button.d.ts +1 -1
  245. package/dist/split-button/split-button.js +12 -11
  246. package/dist/split-button/split-button.js.map +1 -1
  247. package/dist/stat-card/index.d.ts +2 -2
  248. package/dist/stat-card/index.js +2 -2
  249. package/dist/stat-card/stat-card.d.ts +24 -4
  250. package/dist/stat-card/stat-card.js +114 -17
  251. package/dist/stat-card/stat-card.js.map +1 -1
  252. package/dist/stepper/index.d.ts +2 -0
  253. package/dist/stepper/index.js +2 -0
  254. package/dist/stepper/stepper.d.ts +51 -0
  255. package/dist/stepper/stepper.js +215 -0
  256. package/dist/stepper/stepper.js.map +1 -0
  257. package/dist/streamgraph/index.d.ts +2 -0
  258. package/dist/streamgraph/index.js +2 -0
  259. package/dist/streamgraph/streamgraph.d.ts +70 -0
  260. package/dist/streamgraph/streamgraph.js +613 -0
  261. package/dist/streamgraph/streamgraph.js.map +1 -0
  262. package/dist/styles.css +1 -1
  263. package/dist/swipe-actions/index.d.ts +2 -0
  264. package/dist/swipe-actions/index.js +2 -0
  265. package/dist/swipe-actions/swipe-actions.d.ts +67 -0
  266. package/dist/swipe-actions/swipe-actions.js +552 -0
  267. package/dist/swipe-actions/swipe-actions.js.map +1 -0
  268. package/dist/switch/switch.js +2 -2
  269. package/dist/switch/switch.js.map +1 -1
  270. package/dist/table/index.d.ts +2 -2
  271. package/dist/table/index.js +2 -2
  272. package/dist/table/table.d.ts +56 -4
  273. package/dist/table/table.js +340 -165
  274. package/dist/table/table.js.map +1 -1
  275. package/dist/tabs/tabs.js +2 -2
  276. package/dist/tabs/tabs.js.map +1 -1
  277. package/dist/tag-input/index.d.ts +2 -0
  278. package/dist/tag-input/index.js +2 -0
  279. package/dist/tag-input/tag-input.d.ts +40 -0
  280. package/dist/tag-input/tag-input.js +269 -0
  281. package/dist/tag-input/tag-input.js.map +1 -0
  282. package/dist/text-morph/index.d.ts +2 -0
  283. package/dist/text-morph/index.js +2 -0
  284. package/dist/text-morph/text-morph.d.ts +23 -0
  285. package/dist/text-morph/text-morph.js +21 -0
  286. package/dist/text-morph/text-morph.js.map +1 -0
  287. package/dist/text-reveal/index.d.ts +2 -0
  288. package/dist/text-reveal/index.js +2 -0
  289. package/dist/text-reveal/text-reveal.d.ts +27 -0
  290. package/dist/text-reveal/text-reveal.js +51 -0
  291. package/dist/text-reveal/text-reveal.js.map +1 -0
  292. package/dist/text-shimmer/index.d.ts +2 -0
  293. package/dist/text-shimmer/index.js +2 -0
  294. package/dist/text-shimmer/text-shimmer.d.ts +29 -0
  295. package/dist/text-shimmer/text-shimmer.js +29 -0
  296. package/dist/text-shimmer/text-shimmer.js.map +1 -0
  297. package/dist/time-picker/time-picker.js +2 -2
  298. package/dist/time-picker/time-picker.js.map +1 -1
  299. package/dist/toast/index.d.ts +2 -2
  300. package/dist/toast/index.js +2 -2
  301. package/dist/toast/toast.d.ts +6 -0
  302. package/dist/toast/toast.js +82 -40
  303. package/dist/toast/toast.js.map +1 -1
  304. package/dist/tooltip/tooltip.d.ts +9 -2
  305. package/dist/tooltip/tooltip.js +7 -7
  306. package/dist/tooltip/tooltip.js.map +1 -1
  307. package/dist/treemap/index.d.ts +2 -0
  308. package/dist/treemap/index.js +2 -0
  309. package/dist/treemap/treemap.d.ts +53 -0
  310. package/dist/treemap/treemap.js +699 -0
  311. package/dist/treemap/treemap.js.map +1 -0
  312. package/dist/usage-meter/index.d.ts +2 -0
  313. package/dist/usage-meter/index.js +2 -0
  314. package/dist/usage-meter/usage-meter.d.ts +50 -0
  315. package/dist/usage-meter/usage-meter.js +440 -0
  316. package/dist/usage-meter/usage-meter.js.map +1 -0
  317. package/dist/waffle-chart/index.d.ts +2 -0
  318. package/dist/waffle-chart/index.js +2 -0
  319. package/dist/waffle-chart/waffle-chart.d.ts +57 -0
  320. package/dist/waffle-chart/waffle-chart.js +426 -0
  321. package/dist/waffle-chart/waffle-chart.js.map +1 -0
  322. package/package.json +165 -3
@@ -0,0 +1,2 @@
1
+ import { OnboardingChecklist, OnboardingChecklistProps, OnboardingStep } from "./onboarding-checklist.js";
2
+ export { OnboardingChecklist, type OnboardingChecklistProps, type OnboardingStep };
@@ -0,0 +1,2 @@
1
+ import { OnboardingChecklist } from "./onboarding-checklist.js";
2
+ export { OnboardingChecklist };
@@ -0,0 +1,55 @@
1
+ //#region src/onboarding-checklist/onboarding-checklist.d.ts
2
+ /**
3
+ * OnboardingChecklist: a getting-started card for a new account or workspace,
4
+ * for a short, one-time setup of three to eight loosely ordered steps. (Use a
5
+ * Stepper when the order is strict and steps map to screens.)
6
+ *
7
+ * The progress ring and the count follow every check: the ring fills on the
8
+ * morph spring, the count rolls its digits, and at 100% a tick draws in the
9
+ * ring while the title morphs to `doneTitle`. A checked step fills its circle
10
+ * from the centre, draws its tick and strikes its title through; 720ms later it
11
+ * folds into a "N completed" row that opens again, and the next unfinished step
12
+ * opens and takes focus if the finished one had it. A step with an `actionLabel`
13
+ * runs `onAction`: resolving checks the step, throwing an Error keeps it open
14
+ * and shows the message. The body can be hidden and shown again.
15
+ *
16
+ * Rows and panels open and close their height on a spring that never
17
+ * overshoots, closing a little quicker. Nothing animates on first render, and
18
+ * reduced motion removes the height animation and keeps short fades.
19
+ *
20
+ * Built on plain buttons and the shared swap and rolling-number helpers; the
21
+ * action is the library's ActionButton, whose arrow becomes a spinner and then
22
+ * a tick that draws itself. Keyboard: Up and Down walk the step titles,
23
+ * Home and End jump to the first and last, Enter or Space expands a step,
24
+ * toggles its checkbox or runs its action.
25
+ */
26
+ export interface OnboardingStep {
27
+ id: string;
28
+ title: string;
29
+ description?: string;
30
+ /** Label of the button that does the step. Without it, the step is checked off by hand. */
31
+ actionLabel?: string;
32
+ /** Runs the step. Resolve to check it off; throw an Error to keep it open and show the error's message. */
33
+ onAction?: () => void | Promise<void>;
34
+ }
35
+ export interface OnboardingChecklistProps {
36
+ /** Card title while steps remain. */
37
+ title: string;
38
+ /** Title once every step is done. @default "You’re all set" */
39
+ doneTitle?: string;
40
+ /** Steps in order. */
41
+ steps: OnboardingStep[];
42
+ /** Step ids that start completed. */
43
+ defaultCompleted?: string[];
44
+ /** Called with the completed ids, in step order, whenever they change. */
45
+ onCompletedChange?: (completed: string[]) => void;
46
+ /** Starts with the body collapsed. @default false */
47
+ defaultHidden?: boolean;
48
+ /** Called when the Hide or Show button is used. */
49
+ onHiddenChange?: (hidden: boolean) => void;
50
+ /** Extra classes for the card. Merged last. */
51
+ className?: string;
52
+ }
53
+ export declare const OnboardingChecklist: import("react").ForwardRefExoticComponent<OnboardingChecklistProps & import("react").RefAttributes<HTMLElement>>;
54
+ //#endregion
55
+ //# sourceMappingURL=onboarding-checklist.d.ts.map
@@ -0,0 +1,577 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { mergeRefs } from "../lib/merge-refs.js";
4
+ import { ActionButton } from "../action-button/action-button.js";
5
+ import { SwapText } from "../lib/swap-text.js";
6
+ import { RollingNumber } from "../lib/field-message.js";
7
+ import { forwardRef, useEffect, useId, useMemo, useReducer, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/onboarding-checklist/onboarding-checklist.tsx
10
+ /** How long a checked step stays in place, struck through, before it folds into the completed row. */
11
+ const SETTLE_MS = 720;
12
+ const ordered = (ids, steps) => steps.map((step) => step.id).filter((id) => ids.includes(id));
13
+ const without = (ids, id) => ids.filter((item) => item !== id);
14
+ const omit = (errors, id) => Object.fromEntries(Object.entries(errors).filter(([key]) => key !== id));
15
+ const titleOf = (steps, id) => steps.find((step) => step.id === id)?.title ?? "Step";
16
+ function init({ steps, completed, hidden }) {
17
+ const done = ordered(completed, steps);
18
+ return {
19
+ done,
20
+ settled: done,
21
+ expanded: steps.find((step) => !done.includes(step.id))?.id ?? null,
22
+ errors: {},
23
+ groupOpen: false,
24
+ hidden,
25
+ message: ""
26
+ };
27
+ }
28
+ function reducer(state, action) {
29
+ switch (action.type) {
30
+ case "check": {
31
+ if (state.done.includes(action.id)) return state;
32
+ const done = ordered([...state.done, action.id], action.steps);
33
+ const total = action.steps.length;
34
+ return {
35
+ ...state,
36
+ done,
37
+ errors: omit(state.errors, action.id),
38
+ message: done.length === total ? `All ${total} steps done.` : `${titleOf(action.steps, action.id)} done. ${done.length} of ${total} complete.`
39
+ };
40
+ }
41
+ case "uncheck": {
42
+ if (!state.done.includes(action.id)) return state;
43
+ const done = without(state.done, action.id);
44
+ return {
45
+ ...state,
46
+ done,
47
+ settled: without(state.settled, action.id),
48
+ expanded: state.expanded ?? action.id,
49
+ message: `${titleOf(action.steps, action.id)} marked as not done. ${done.length} of ${action.steps.length} complete.`
50
+ };
51
+ }
52
+ case "settle": {
53
+ if (!state.done.includes(action.id) || state.settled.includes(action.id)) return state;
54
+ let expanded = state.expanded;
55
+ if (expanded === action.id) {
56
+ const order = action.steps.map((step) => step.id);
57
+ const start = order.indexOf(action.id);
58
+ expanded = order.map((_, offset) => order[(start + offset + 1) % order.length]).find((id) => !state.done.includes(id)) ?? null;
59
+ }
60
+ return {
61
+ ...state,
62
+ settled: ordered([...state.settled, action.id], action.steps),
63
+ expanded
64
+ };
65
+ }
66
+ case "expand": return {
67
+ ...state,
68
+ expanded: state.expanded === action.id ? null : action.id
69
+ };
70
+ case "start": return {
71
+ ...state,
72
+ errors: omit(state.errors, action.id)
73
+ };
74
+ case "fail": return {
75
+ ...state,
76
+ errors: {
77
+ ...state.errors,
78
+ [action.id]: action.message
79
+ },
80
+ message: action.message
81
+ };
82
+ case "group": return {
83
+ ...state,
84
+ groupOpen: !state.groupOpen
85
+ };
86
+ case "hide": return {
87
+ ...state,
88
+ hidden: !state.hidden
89
+ };
90
+ }
91
+ }
92
+ const Chevron = () => /* @__PURE__ */ jsx("svg", {
93
+ width: 16,
94
+ height: 16,
95
+ viewBox: "0 0 24 24",
96
+ fill: "none",
97
+ stroke: "currentColor",
98
+ strokeWidth: 1.75,
99
+ strokeLinecap: "round",
100
+ strokeLinejoin: "round",
101
+ "aria-hidden": "true",
102
+ children: /* @__PURE__ */ jsx("path", { d: "m18 15-6-6-6 6" })
103
+ });
104
+ /**
105
+ * A box that opens and closes its height (a grid track going between 0fr and 1fr).
106
+ * Closed, it is visibility: hidden once folded, so it leaves the tab order.
107
+ */
108
+ function Collapse({ show, children }) {
109
+ return /* @__PURE__ */ jsx("div", {
110
+ "data-shown": show || void 0,
111
+ className: "checklist-collapse",
112
+ children: /* @__PURE__ */ jsx("div", { children })
113
+ });
114
+ }
115
+ /** Every label the slot can show sits invisibly underneath, so a swap never changes the slot's size. */
116
+ function SwapLabel({ text, options }) {
117
+ return /* @__PURE__ */ jsxs("span", {
118
+ className: "checklist-swap",
119
+ "aria-hidden": "true",
120
+ children: [options.map((option, index) => /* @__PURE__ */ jsx("span", {
121
+ className: "checklist-swap-sizer",
122
+ children: option
123
+ }, index)), /* @__PURE__ */ jsx(SwapText, {
124
+ swapKey: text,
125
+ motion: "rise",
126
+ className: "checklist-swap-item",
127
+ children: text
128
+ })]
129
+ });
130
+ }
131
+ /** The ring's stroke fills on a spring as steps are checked; once every step is done a tick draws in its center. */
132
+ function ProgressRing({ done, total }) {
133
+ const ratio = total ? done / total : 0;
134
+ const complete = total > 0 && done === total;
135
+ return /* @__PURE__ */ jsxs("span", {
136
+ className: "checklist-ring",
137
+ role: "progressbar",
138
+ "aria-label": "Setup progress",
139
+ "aria-valuemin": 0,
140
+ "aria-valuemax": total,
141
+ "aria-valuenow": done,
142
+ "aria-valuetext": `${done} of ${total} steps done`,
143
+ children: [/* @__PURE__ */ jsxs("svg", {
144
+ viewBox: "0 0 40 40",
145
+ fill: "none",
146
+ "aria-hidden": "true",
147
+ children: [/* @__PURE__ */ jsx("circle", {
148
+ className: "checklist-ring-track",
149
+ cx: "20",
150
+ cy: "20",
151
+ r: "17",
152
+ strokeWidth: 3
153
+ }), /* @__PURE__ */ jsx("g", {
154
+ transform: "rotate(-90 20 20)",
155
+ children: /* @__PURE__ */ jsx("circle", {
156
+ className: "checklist-ring-fill",
157
+ cx: "20",
158
+ cy: "20",
159
+ r: "17",
160
+ strokeWidth: 3,
161
+ strokeLinecap: "round",
162
+ pathLength: 1,
163
+ "data-started": ratio > 0 ? "" : void 0,
164
+ style: { "--ratio": ratio }
165
+ })
166
+ })]
167
+ }), /* @__PURE__ */ jsx("span", {
168
+ className: "checklist-ring-tick",
169
+ "aria-hidden": "true",
170
+ children: /* @__PURE__ */ jsx(SwapText, {
171
+ swapKey: complete ? "tick" : "",
172
+ motion: "glyph",
173
+ className: "grid place-items-center",
174
+ children: complete ? /* @__PURE__ */ jsx("svg", {
175
+ viewBox: "0 0 40 40",
176
+ fill: "none",
177
+ children: /* @__PURE__ */ jsx("path", {
178
+ className: "checklist-draw",
179
+ pathLength: 1,
180
+ d: "M13.5 20.5 18 25l8.5-9.5",
181
+ stroke: "currentColor",
182
+ strokeWidth: 2.25,
183
+ strokeLinecap: "round",
184
+ strokeLinejoin: "round"
185
+ })
186
+ }) : null
187
+ })
188
+ })]
189
+ });
190
+ }
191
+ /** The fill grows from the center while the tick draws from its short stroke; unchecking retracts both quickly. */
192
+ function CheckButton({ checked, labelledBy, onToggle }) {
193
+ return /* @__PURE__ */ jsx("button", {
194
+ type: "button",
195
+ role: "checkbox",
196
+ "aria-checked": checked,
197
+ "aria-labelledby": labelledBy,
198
+ className: "checklist-check",
199
+ "data-check": "",
200
+ onClick: onToggle,
201
+ children: /* @__PURE__ */ jsxs("span", {
202
+ className: "checklist-check-visual",
203
+ "aria-hidden": "true",
204
+ children: [/* @__PURE__ */ jsx("span", { className: "checklist-check-fill" }), /* @__PURE__ */ jsx("svg", {
205
+ className: "checklist-check-mark",
206
+ viewBox: "0 0 22 22",
207
+ fill: "none",
208
+ children: /* @__PURE__ */ jsx("path", {
209
+ pathLength: 1,
210
+ d: "M6.75 11.25 9.75 14.25 15.25 8.25",
211
+ stroke: "currentColor",
212
+ strokeWidth: 1.75,
213
+ strokeLinecap: "round",
214
+ strokeLinejoin: "round"
215
+ })
216
+ })]
217
+ })
218
+ });
219
+ }
220
+ function StepItem({ step, baseId, done, settled, expanded, error, onToggle, onExpand, onRun }) {
221
+ const titleId = `${baseId}-${step.id}-title`;
222
+ const panelId = `${baseId}-${step.id}-panel`;
223
+ const [lastError, setLastError] = useState(error);
224
+ if (error && error !== lastError) setLastError(error);
225
+ return /* @__PURE__ */ jsx("li", {
226
+ "data-step": step.id,
227
+ "data-done": done || void 0,
228
+ "data-current": expanded || void 0,
229
+ "data-open": settled ? void 0 : "",
230
+ children: /* @__PURE__ */ jsx(Collapse, {
231
+ show: !settled,
232
+ children: /* @__PURE__ */ jsxs("div", {
233
+ className: "checklist-step-inner",
234
+ children: [/* @__PURE__ */ jsx(CheckButton, {
235
+ checked: done,
236
+ labelledBy: titleId,
237
+ onToggle
238
+ }), /* @__PURE__ */ jsxs("div", {
239
+ className: "checklist-step-main",
240
+ children: [/* @__PURE__ */ jsx("button", {
241
+ type: "button",
242
+ className: "checklist-step-title",
243
+ "data-title": "",
244
+ "aria-expanded": expanded,
245
+ "aria-controls": panelId,
246
+ onClick: onExpand,
247
+ children: /* @__PURE__ */ jsx("span", {
248
+ id: titleId,
249
+ className: "checklist-title-text",
250
+ children: step.title
251
+ })
252
+ }), /* @__PURE__ */ jsx(Collapse, {
253
+ show: expanded,
254
+ children: /* @__PURE__ */ jsxs("div", {
255
+ id: panelId,
256
+ role: "region",
257
+ "aria-labelledby": titleId,
258
+ className: "checklist-panel-inner",
259
+ children: [
260
+ step.description ? /* @__PURE__ */ jsx("p", {
261
+ className: "checklist-description",
262
+ children: step.description
263
+ }) : null,
264
+ /* @__PURE__ */ jsx(Collapse, {
265
+ show: Boolean(error),
266
+ children: /* @__PURE__ */ jsx("p", {
267
+ role: "alert",
268
+ className: "checklist-error",
269
+ children: lastError
270
+ })
271
+ }),
272
+ step.actionLabel ? /* @__PURE__ */ jsx(ActionButton, {
273
+ variant: "primary",
274
+ size: "sm",
275
+ className: "mt-3",
276
+ "data-primary": "",
277
+ pendingLabel: step.actionLabel,
278
+ successLabel: step.actionLabel,
279
+ onAction: onRun,
280
+ children: step.actionLabel
281
+ }) : null
282
+ ]
283
+ })
284
+ })]
285
+ })]
286
+ })
287
+ })
288
+ });
289
+ }
290
+ const OnboardingChecklist = forwardRef(function OnboardingChecklist({ title, doneTitle = "You’re all set", steps, defaultCompleted = [], onCompletedChange, defaultHidden = false, onHiddenChange, className }, ref) {
291
+ const baseId = useId();
292
+ const [state, dispatch] = useReducer(reducer, {
293
+ steps,
294
+ completed: defaultCompleted,
295
+ hidden: defaultHidden
296
+ }, init);
297
+ const root = useRef(null);
298
+ const refs = useMemo(() => mergeRefs(ref, root), [ref]);
299
+ const timers = useRef(/* @__PURE__ */ new Map());
300
+ const focusRequest = useRef(null);
301
+ const reportCompleted = useRef(onCompletedChange);
302
+ const reported = useRef(state.done);
303
+ useEffect(() => {
304
+ reportCompleted.current = onCompletedChange;
305
+ });
306
+ useEffect(() => {
307
+ if (reported.current === state.done) return;
308
+ reported.current = state.done;
309
+ reportCompleted.current?.(state.done);
310
+ }, [state.done]);
311
+ useEffect(() => {
312
+ const pending = timers.current;
313
+ return () => pending.forEach(clearTimeout);
314
+ }, []);
315
+ useEffect(() => {
316
+ const request = focusRequest.current;
317
+ const node = root.current;
318
+ if (!request || !node) return;
319
+ focusRequest.current = null;
320
+ let target;
321
+ if (request === "next") {
322
+ const next = state.expanded ? node.querySelector(`[data-step="${state.expanded}"][data-open]`) : null;
323
+ target = next?.querySelector("[data-primary]") ?? next?.querySelector("[data-title]") ?? node.querySelector("[data-group-toggle]");
324
+ } else target = node.querySelector(`[data-step="${request.id}"][data-open] [data-check]`);
325
+ target?.focus({ preventScroll: true });
326
+ });
327
+ function check(id) {
328
+ dispatch({
329
+ type: "check",
330
+ id,
331
+ steps
332
+ });
333
+ if (timers.current.has(id)) return;
334
+ timers.current.set(id, setTimeout(() => {
335
+ timers.current.delete(id);
336
+ if (root.current?.querySelector(`[data-step="${id}"]`)?.contains(document.activeElement)) focusRequest.current = "next";
337
+ dispatch({
338
+ type: "settle",
339
+ id,
340
+ steps
341
+ });
342
+ }, SETTLE_MS));
343
+ }
344
+ function uncheck(id, fromGroup) {
345
+ clearTimeout(timers.current.get(id));
346
+ timers.current.delete(id);
347
+ if (fromGroup) focusRequest.current = { id };
348
+ dispatch({
349
+ type: "uncheck",
350
+ id,
351
+ steps
352
+ });
353
+ }
354
+ async function run(step) {
355
+ if (!step.onAction || state.done.includes(step.id)) return;
356
+ dispatch({
357
+ type: "start",
358
+ id: step.id,
359
+ steps
360
+ });
361
+ try {
362
+ await step.onAction();
363
+ } catch (error) {
364
+ dispatch({
365
+ type: "fail",
366
+ id: step.id,
367
+ message: error instanceof Error && error.message ? error.message : "That didn’t work. Try again."
368
+ });
369
+ throw error;
370
+ }
371
+ check(step.id);
372
+ }
373
+ function toggleHidden() {
374
+ dispatch({ type: "hide" });
375
+ onHiddenChange?.(!state.hidden);
376
+ }
377
+ /** Up and Down walk the step titles, Home and End jump to the first and last. */
378
+ function navigate(event) {
379
+ const target = event.target;
380
+ if (!target.matches("[data-title]") || ![
381
+ "ArrowDown",
382
+ "ArrowUp",
383
+ "Home",
384
+ "End"
385
+ ].includes(event.key)) return;
386
+ const titles = Array.from(event.currentTarget.querySelectorAll("li[data-open] [data-title]"));
387
+ const index = titles.indexOf(target);
388
+ const next = event.key === "Home" ? 0 : event.key === "End" ? titles.length - 1 : (index + (event.key === "ArrowDown" ? 1 : -1) + titles.length) % titles.length;
389
+ event.preventDefault();
390
+ titles[next]?.focus();
391
+ }
392
+ const total = steps.length;
393
+ const doneCount = state.done.length;
394
+ const allDone = total > 0 && doneCount === total;
395
+ const completed = steps.filter((step) => state.settled.includes(step.id));
396
+ const titleId = `${baseId}-title`;
397
+ const bodyId = `${baseId}-body`;
398
+ const groupId = `${baseId}-completed`;
399
+ return /* @__PURE__ */ jsxs("section", {
400
+ ref: refs,
401
+ "aria-labelledby": titleId,
402
+ "data-slot": "onboarding-checklist",
403
+ "data-complete": allDone || void 0,
404
+ "data-hidden": state.hidden || void 0,
405
+ className: cn("checklist box-border font-sans", className),
406
+ children: [
407
+ /* @__PURE__ */ jsxs("div", {
408
+ className: "checklist-header",
409
+ children: [
410
+ /* @__PURE__ */ jsx(ProgressRing, {
411
+ done: doneCount,
412
+ total
413
+ }),
414
+ /* @__PURE__ */ jsxs("div", {
415
+ className: "checklist-heading",
416
+ children: [/* @__PURE__ */ jsxs("h3", {
417
+ id: titleId,
418
+ className: "checklist-title",
419
+ children: [/* @__PURE__ */ jsx("span", {
420
+ className: "sr-only",
421
+ children: allDone ? doneTitle : title
422
+ }), /* @__PURE__ */ jsx(SwapLabel, {
423
+ text: allDone ? doneTitle : title,
424
+ options: [title, doneTitle]
425
+ })]
426
+ }), /* @__PURE__ */ jsxs("p", {
427
+ className: "checklist-count",
428
+ children: [/* @__PURE__ */ jsxs("span", {
429
+ className: "sr-only",
430
+ children: [
431
+ doneCount,
432
+ " of ",
433
+ total,
434
+ " done"
435
+ ]
436
+ }), /* @__PURE__ */ jsxs("span", {
437
+ className: "checklist-count-visual",
438
+ "aria-hidden": "true",
439
+ children: [
440
+ /* @__PURE__ */ jsx(RollingNumber, { word: String(doneCount) }),
441
+ "\xA0of ",
442
+ total,
443
+ " done"
444
+ ]
445
+ })]
446
+ })]
447
+ }),
448
+ /* @__PURE__ */ jsxs("button", {
449
+ type: "button",
450
+ className: "checklist-hide",
451
+ "aria-expanded": !state.hidden,
452
+ "aria-controls": bodyId,
453
+ onClick: toggleHidden,
454
+ children: [
455
+ /* @__PURE__ */ jsx("span", {
456
+ className: "checklist-hide-label",
457
+ children: /* @__PURE__ */ jsx(SwapLabel, {
458
+ text: state.hidden ? "Show" : "Hide",
459
+ options: ["Hide", "Show"]
460
+ })
461
+ }),
462
+ /* @__PURE__ */ jsxs("span", {
463
+ className: "sr-only",
464
+ children: [state.hidden ? "Show" : "Hide", " checklist"]
465
+ }),
466
+ /* @__PURE__ */ jsx("span", {
467
+ className: "checklist-chevron",
468
+ "aria-hidden": "true",
469
+ "data-flipped": state.hidden || void 0,
470
+ children: /* @__PURE__ */ jsx(Chevron, {})
471
+ })
472
+ ]
473
+ })
474
+ ]
475
+ }),
476
+ /* @__PURE__ */ jsx("div", {
477
+ id: bodyId,
478
+ "data-shown": state.hidden ? void 0 : "",
479
+ className: "checklist-collapse",
480
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", {
481
+ className: "checklist-body-inner",
482
+ children: [/* @__PURE__ */ jsx("ul", {
483
+ className: "checklist-list",
484
+ "aria-label": "Steps to do",
485
+ "aria-hidden": completed.length === total ? true : void 0,
486
+ onKeyDown: navigate,
487
+ children: steps.map((step) => /* @__PURE__ */ jsx(StepItem, {
488
+ step,
489
+ baseId,
490
+ done: state.done.includes(step.id),
491
+ settled: state.settled.includes(step.id),
492
+ expanded: state.expanded === step.id,
493
+ error: state.errors[step.id],
494
+ onToggle: () => state.done.includes(step.id) ? uncheck(step.id, false) : check(step.id),
495
+ onExpand: () => dispatch({
496
+ type: "expand",
497
+ id: step.id,
498
+ steps
499
+ }),
500
+ onRun: () => run(step)
501
+ }, step.id))
502
+ }), /* @__PURE__ */ jsxs(Collapse, {
503
+ show: completed.length > 0,
504
+ children: [/* @__PURE__ */ jsxs("button", {
505
+ type: "button",
506
+ className: "checklist-group-toggle",
507
+ "data-group-toggle": "",
508
+ "aria-expanded": state.groupOpen,
509
+ "aria-controls": groupId,
510
+ onClick: () => dispatch({ type: "group" }),
511
+ children: [
512
+ /* @__PURE__ */ jsxs("span", {
513
+ className: "sr-only",
514
+ children: [completed.length, " completed"]
515
+ }),
516
+ /* @__PURE__ */ jsxs("span", {
517
+ className: "checklist-count-visual",
518
+ "aria-hidden": "true",
519
+ children: [/* @__PURE__ */ jsx(RollingNumber, { word: String(completed.length) }), "\xA0completed"]
520
+ }),
521
+ /* @__PURE__ */ jsx("span", {
522
+ className: "checklist-chevron",
523
+ "aria-hidden": "true",
524
+ "data-flipped": state.groupOpen ? void 0 : "",
525
+ children: /* @__PURE__ */ jsx(Chevron, {})
526
+ })
527
+ ]
528
+ }), /* @__PURE__ */ jsx(Collapse, {
529
+ show: state.groupOpen,
530
+ children: /* @__PURE__ */ jsx("div", {
531
+ id: groupId,
532
+ children: /* @__PURE__ */ jsx("ul", {
533
+ className: "checklist-list",
534
+ "aria-label": "Completed steps",
535
+ children: steps.map((step) => {
536
+ const doneId = `${baseId}-${step.id}-done`;
537
+ return /* @__PURE__ */ jsx("li", {
538
+ "data-completed-step": step.id,
539
+ "data-done": "",
540
+ children: /* @__PURE__ */ jsx(Collapse, {
541
+ show: state.settled.includes(step.id),
542
+ children: /* @__PURE__ */ jsxs("div", {
543
+ className: "checklist-step-inner",
544
+ children: [/* @__PURE__ */ jsx(CheckButton, {
545
+ checked: true,
546
+ labelledBy: doneId,
547
+ onToggle: () => uncheck(step.id, true)
548
+ }), /* @__PURE__ */ jsx("span", {
549
+ className: "checklist-done-title",
550
+ children: /* @__PURE__ */ jsx("span", {
551
+ id: doneId,
552
+ className: "checklist-title-text",
553
+ children: step.title
554
+ })
555
+ })]
556
+ })
557
+ })
558
+ }, step.id);
559
+ })
560
+ })
561
+ })
562
+ })]
563
+ })]
564
+ }) })
565
+ }),
566
+ /* @__PURE__ */ jsx("span", {
567
+ className: "sr-only",
568
+ role: "status",
569
+ children: state.message
570
+ })
571
+ ]
572
+ });
573
+ });
574
+ //#endregion
575
+ export { OnboardingChecklist };
576
+
577
+ //# sourceMappingURL=onboarding-checklist.js.map