@connextar/house 0.3.0 → 0.5.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 (58) hide show
  1. package/README.md +242 -6
  2. package/dist/setup-guide/bits.d.ts +89 -0
  3. package/dist/setup-guide/bits.d.ts.map +1 -0
  4. package/dist/setup-guide/bits.js +134 -0
  5. package/dist/setup-guide/bits.js.map +1 -0
  6. package/dist/setup-guide/card.d.ts +33 -0
  7. package/dist/setup-guide/card.d.ts.map +1 -0
  8. package/dist/setup-guide/card.js +56 -0
  9. package/dist/setup-guide/card.js.map +1 -0
  10. package/dist/setup-guide/class-names.d.ts +68 -0
  11. package/dist/setup-guide/class-names.d.ts.map +1 -0
  12. package/dist/setup-guide/class-names.js +63 -0
  13. package/dist/setup-guide/class-names.js.map +1 -0
  14. package/dist/setup-guide/context.d.ts +89 -0
  15. package/dist/setup-guide/context.d.ts.map +1 -0
  16. package/dist/setup-guide/context.js +124 -0
  17. package/dist/setup-guide/context.js.map +1 -0
  18. package/dist/setup-guide/guide.d.ts +159 -0
  19. package/dist/setup-guide/guide.d.ts.map +1 -0
  20. package/dist/setup-guide/guide.js +128 -0
  21. package/dist/setup-guide/guide.js.map +1 -0
  22. package/dist/setup-guide/index.d.ts +27 -0
  23. package/dist/setup-guide/index.d.ts.map +1 -0
  24. package/dist/setup-guide/index.js +27 -0
  25. package/dist/setup-guide/index.js.map +1 -0
  26. package/dist/setup-guide/launcher.d.ts +38 -0
  27. package/dist/setup-guide/launcher.d.ts.map +1 -0
  28. package/dist/setup-guide/launcher.js +60 -0
  29. package/dist/setup-guide/launcher.js.map +1 -0
  30. package/dist/setup-guide/strip.d.ts +21 -0
  31. package/dist/setup-guide/strip.d.ts.map +1 -0
  32. package/dist/setup-guide/strip.js +42 -0
  33. package/dist/setup-guide/strip.js.map +1 -0
  34. package/dist/wizard/index.d.ts +26 -0
  35. package/dist/wizard/index.d.ts.map +1 -0
  36. package/dist/wizard/index.js +26 -0
  37. package/dist/wizard/index.js.map +1 -0
  38. package/dist/wizard/invalid.d.ts +91 -0
  39. package/dist/wizard/invalid.d.ts.map +1 -0
  40. package/dist/wizard/invalid.js +121 -0
  41. package/dist/wizard/invalid.js.map +1 -0
  42. package/dist/wizard/react-hook-form-index.d.ts +12 -0
  43. package/dist/wizard/react-hook-form-index.d.ts.map +1 -0
  44. package/dist/wizard/react-hook-form-index.js +12 -0
  45. package/dist/wizard/react-hook-form-index.js.map +1 -0
  46. package/dist/wizard/rhf-adapter.d.ts +32 -0
  47. package/dist/wizard/rhf-adapter.d.ts.map +1 -0
  48. package/dist/wizard/rhf-adapter.js +58 -0
  49. package/dist/wizard/rhf-adapter.js.map +1 -0
  50. package/dist/wizard/rules.d.ts +92 -0
  51. package/dist/wizard/rules.d.ts.map +1 -0
  52. package/dist/wizard/rules.js +105 -0
  53. package/dist/wizard/rules.js.map +1 -0
  54. package/dist/wizard/wizard.d.ts +127 -0
  55. package/dist/wizard/wizard.d.ts.map +1 -0
  56. package/dist/wizard/wizard.js +195 -0
  57. package/dist/wizard/wizard.js.map +1 -0
  58. package/package.json +19 -2
@@ -0,0 +1,128 @@
1
+ /**
2
+ * What a new account is asked to do, how far through it is, and what that has
3
+ * earned. No React and no DOM, so the rules are tested without a browser and
4
+ * hold whatever draws them.
5
+ *
6
+ * **Nothing about progress is stored.** A step is *done* when the account holds
7
+ * what it asks for — a learner, a price, a published course — however it got
8
+ * there; the host reads that fresh each time. What *is* stored is the reward:
9
+ * one entry per step per account, keyed on the step, so a step pays once
10
+ * however many times its thing is made, deleted and made again. That split is
11
+ * the whole design, and it is why `done` and `earned` arrive here as two
12
+ * separate sets rather than one status per step.
13
+ *
14
+ * A step key is permanent. Rewards are keyed on it, so renaming one pays
15
+ * everybody a second time.
16
+ */
17
+ const rewardOf = (step) => step.reward ?? 0;
18
+ const sum = (numbers) => numbers.reduce((total, n) => total + n, 0);
19
+ /** Every step of every item, in order. */
20
+ export function stepsOf(items) {
21
+ return items.flatMap((item) => [...item.steps]);
22
+ }
23
+ /** Every step key, for checking what a request names before trusting it. */
24
+ export function stepKeysOf(items) {
25
+ return new Set(stepsOf(items).map((step) => step.key));
26
+ }
27
+ /**
28
+ * Whether an item can be started yet.
29
+ *
30
+ * Only while nothing of it is done: an item that somehow got started stays
31
+ * open, because telling somebody they cannot do a thing they have half done is
32
+ * worse than a requirement quietly not applying.
33
+ */
34
+ function blockedBy(item, done, doneCount) {
35
+ if (doneCount > 0 || !item.requires?.length)
36
+ return null;
37
+ const unmet = item.requires.some((key) => !done.has(key));
38
+ return unmet ? (item.blockedLabel ?? "Not yet") : null;
39
+ }
40
+ /** The guide as it stands for one account. Pure: the same inputs always give the same answer. */
41
+ export function buildGuide({ pathway, items, done, earned, hidden = false }) {
42
+ const built = items.map((def) => {
43
+ const steps = def.steps.map((step) => ({
44
+ ...step,
45
+ reward: rewardOf(step),
46
+ done: done.has(step.key),
47
+ earned: earned.has(step.key),
48
+ }));
49
+ const doneCount = steps.filter((step) => step.done).length;
50
+ return {
51
+ ...def,
52
+ steps,
53
+ reward: sum(steps.map((step) => step.reward)),
54
+ earnedReward: sum(steps.filter((step) => step.earned).map((step) => step.reward)),
55
+ doneCount,
56
+ // An item with no steps at all is not "done" — it has nothing to be done about.
57
+ done: steps.length > 0 && doneCount === steps.length,
58
+ blocked: blockedBy(def, done, doneCount),
59
+ };
60
+ });
61
+ const all = built.flatMap((item) => item.steps);
62
+ return {
63
+ pathway,
64
+ items: built,
65
+ totalReward: sum(all.map((step) => step.reward)),
66
+ earnedReward: sum(all.filter((step) => step.earned).map((step) => step.reward)),
67
+ doneItems: built.filter((item) => item.done).length,
68
+ nextKey: built.find((item) => !item.done && !item.blocked)?.key ?? null,
69
+ complete: all.length > 0 && all.every((step) => step.done && step.earned),
70
+ pendingKeys: all.filter((step) => step.done && !step.earned).map((step) => step.key),
71
+ hidden,
72
+ };
73
+ }
74
+ export function findItem(guide, key) {
75
+ return guide?.items.find((item) => item.key === key) ?? null;
76
+ }
77
+ /**
78
+ * What counts as done: what the records show now, plus everything already paid
79
+ * for.
80
+ *
81
+ * A reward, once earned, is not taken back — so a step whose thing has since
82
+ * been deleted stays ticked rather than reopening and asking to be paid a
83
+ * second time. Hosts pass the result of this as `done`.
84
+ */
85
+ export function doneSteps(facts, earned) {
86
+ return new Set([...facts, ...earned]);
87
+ }
88
+ /**
89
+ * The steps this account has done and not been paid for — what a sync owes it.
90
+ *
91
+ * Kept here, away from the database, because *which* steps are owed is a rule
92
+ * and writing the entries is a transaction. The host loops over this and writes
93
+ * one row each, letting its unique index refuse a second payment: two tabs
94
+ * asking at the same moment both get this list, and only one of them gets to
95
+ * write each row.
96
+ */
97
+ export function rewardsOwed(items, done, earned) {
98
+ return stepsOf(items)
99
+ .filter((step) => done.has(step.key) && !earned.has(step.key) && rewardOf(step) > 0)
100
+ .map((step) => ({ key: step.key, title: step.title, reward: rewardOf(step) }));
101
+ }
102
+ /**
103
+ * How far through one item is.
104
+ *
105
+ * `ready` is for a flow that saves nothing until its last step: its choices are
106
+ * made but nothing exists yet, so they tick without being done. They count
107
+ * towards the bar — the point of the bar is to show the end approaching — but
108
+ * never towards what has been earned.
109
+ */
110
+ export function itemProgress(item, ready) {
111
+ const isReady = (step) => !step.done && Boolean(ready?.has(step.key));
112
+ const progressed = item.steps.filter((step) => step.done || isReady(step)).length;
113
+ const total = item.steps.length;
114
+ return {
115
+ progressed,
116
+ total,
117
+ percent: total === 0 ? 0 : Math.round((progressed / total) * 100),
118
+ nextKey: item.steps.find((step) => !step.done && !isReady(step))?.key ?? null,
119
+ };
120
+ }
121
+ export function stepState(step, nextKey, ready) {
122
+ if (step.done)
123
+ return "done";
124
+ if (ready?.has(step.key))
125
+ return "ready";
126
+ return step.key === nextKey ? "next" : "todo";
127
+ }
128
+ //# sourceMappingURL=guide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guide.js","sourceRoot":"","sources":["../../src/setup-guide/guide.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `@connextar/house/setup-guide` — the checklist a new account works through,
3
+ * and what finishing a step earns.
4
+ *
5
+ * It exists because the hard parts are not the checklist. They are: knowing
6
+ * what is done without storing it (so a thing made any other way still counts),
7
+ * paying for it exactly once however many tabs ask at the same moment, and
8
+ * saying so while the person is still looking at what they just did. Those are
9
+ * the same three problems in every app, and they have one right answer each.
10
+ *
11
+ * What the host supplies is everything that is genuinely its own: the steps,
12
+ * how each one is read from its records, where the reward is written, and what
13
+ * a reward is even called. This package holds no routes, makes no requests,
14
+ * imports no toast library and knows nothing about a database.
15
+ *
16
+ * The three surfaces are a card for a home page, a strip for the screen where
17
+ * an item's steps are actually done, and a launcher for the header. The panel
18
+ * the launcher opens is the app's own sheet — see `launcher.tsx`.
19
+ */
20
+ export { buildGuide, doneSteps, findItem, itemProgress, rewardsOwed, stepKeysOf, stepState, stepsOf, type BuildGuideInput, type GuideItem, type GuideStep, type ItemProgress, type SetupGuide, type SetupGuideLink, type SetupHowTo, type SetupItemDef, type SetupReward, type SetupStepDef, type StepState, } from "./guide.js";
21
+ export { DEFAULT_REWARD_WORDS, rewardWord, SetupGuideProvider, useSetupGuide, type RewardWords, type SetupGuideProviderProps, type SetupGuideState, type SetupGuideTransport, type SetupLinkComponent, type SetupLinkProps, type SetupSyncResult, } from "./context.js";
22
+ export { SETUP_BAND_STYLE, SETUP_GUIDE_CLASS_NAMES, type SetupGuideClassNames } from "./class-names.js";
23
+ export { GuideIconLink, HowText, HowToButton, ItemHelp, MiniProgress, ProgressRing, RewardChip, RewardRing, Segments, StepCircle, useClassNames, type ClassNameOverrides, type RewardState, } from "./bits.js";
24
+ export { SetupCard, type SetupActions, type SetupCardProps } from "./card.js";
25
+ export { SetupStrip, type SetupStripProps } from "./strip.js";
26
+ export { SetupGuideList, SetupGuideSummary, SetupLauncherButton } from "./launcher.js";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/setup-guide/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,UAAU,EACV,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,EACV,SAAS,EACT,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExG,OAAO,EACL,aAAa,EACb,OAAO,EACP,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `@connextar/house/setup-guide` — the checklist a new account works through,
3
+ * and what finishing a step earns.
4
+ *
5
+ * It exists because the hard parts are not the checklist. They are: knowing
6
+ * what is done without storing it (so a thing made any other way still counts),
7
+ * paying for it exactly once however many tabs ask at the same moment, and
8
+ * saying so while the person is still looking at what they just did. Those are
9
+ * the same three problems in every app, and they have one right answer each.
10
+ *
11
+ * What the host supplies is everything that is genuinely its own: the steps,
12
+ * how each one is read from its records, where the reward is written, and what
13
+ * a reward is even called. This package holds no routes, makes no requests,
14
+ * imports no toast library and knows nothing about a database.
15
+ *
16
+ * The three surfaces are a card for a home page, a strip for the screen where
17
+ * an item's steps are actually done, and a launcher for the header. The panel
18
+ * the launcher opens is the app's own sheet — see `launcher.tsx`.
19
+ */
20
+ export { buildGuide, doneSteps, findItem, itemProgress, rewardsOwed, stepKeysOf, stepState, stepsOf, } from "./guide.js";
21
+ export { DEFAULT_REWARD_WORDS, rewardWord, SetupGuideProvider, useSetupGuide, } from "./context.js";
22
+ export { SETUP_BAND_STYLE, SETUP_GUIDE_CLASS_NAMES } from "./class-names.js";
23
+ export { GuideIconLink, HowText, HowToButton, ItemHelp, MiniProgress, ProgressRing, RewardChip, RewardRing, Segments, StepCircle, useClassNames, } from "./bits.js";
24
+ export { SetupCard } from "./card.js";
25
+ export { SetupStrip } from "./strip.js";
26
+ export { SetupGuideList, SetupGuideSummary, SetupLauncherButton } from "./launcher.js";
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/setup-guide/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,UAAU,EACV,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,UAAU,EACV,SAAS,EACT,OAAO,GAYR,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,UAAU,EACV,kBAAkB,EAClB,aAAa,GAQd,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAA6B,MAAM,kBAAkB,CAAC;AAExG,OAAO,EACL,aAAa,EACb,OAAO,EACP,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,GAGd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,SAAS,EAA0C,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type ClassNameOverrides } from "./bits.js";
2
+ /**
3
+ * The header's Get started, and the contents of the panel it opens.
4
+ *
5
+ * The panel itself is the app's own — every one of them has a sheet or a drawer
6
+ * already, with its own idea of how a thing slides in and what closes it. So
7
+ * this package ships what goes *inside* one (`SetupGuideSummary`,
8
+ * `SetupGuideList`) and a button that opens it, and the app puts them together:
9
+ *
10
+ * ```tsx
11
+ * <SetupLauncherButton />
12
+ * <Sheet open={setup.panelOpen} onOpenChange={setup.setPanelOpen}>
13
+ * <SheetContent>
14
+ * <SetupGuideSummary />
15
+ * <SetupGuideList onGo={() => setup.setPanelOpen(false)} />
16
+ * </SheetContent>
17
+ * </Sheet>
18
+ * ```
19
+ */
20
+ /** The pill: how far along, what has been earned, and a way into the whole guide. */
21
+ export declare function SetupLauncherButton({ label, className, classNames, }: {
22
+ label?: string;
23
+ className?: string;
24
+ classNames?: ClassNameOverrides;
25
+ }): import("react").JSX.Element | null;
26
+ /** The block at the top of the panel: the ring, the count, and one bar per item. */
27
+ export declare function SetupGuideSummary({ className, classNames }: {
28
+ className?: string;
29
+ classNames?: ClassNameOverrides;
30
+ }): import("react").JSX.Element | null;
31
+ /** Every item as a row, for the app's own panel. */
32
+ export declare function SetupGuideList({ onGo, className, classNames, }: {
33
+ /** Called when a row's action is followed, so the panel can close itself. */
34
+ onGo?: () => void;
35
+ className?: string;
36
+ classNames?: ClassNameOverrides;
37
+ }): import("react").JSX.Element | null;
38
+ //# sourceMappingURL=launcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../src/setup-guide/launcher.tsx"],"names":[],"mappings":"AAKA,OAAO,EASL,KAAK,kBAAkB,EACxB,MAAM,WAAW,CAAC;AAInB;;;;;;;;;;;;;;;;;GAiBG;AAEH,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,EAClC,KAAqB,EACrB,SAAS,EACT,UAAU,GACX,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC,sCA6BA;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,kBAAkB,CAAA;CAAE,sCAoBnH;AAED,oDAAoD;AACpD,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,SAAS,EACT,UAAU,GACX,EAAE;IACD,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC,sCAmBA"}
@@ -0,0 +1,60 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { ArrowRight, Sparkles } from "lucide-react";
4
+ import { cx } from "../internal/cx.js";
5
+ import { ItemHelp, MiniProgress, ProgressRing, RewardChip, RewardRing, Segments, StepCircle, useClassNames, } from "./bits.js";
6
+ import { rewardWord, useSetupGuide } from "./context.js";
7
+ /**
8
+ * The header's Get started, and the contents of the panel it opens.
9
+ *
10
+ * The panel itself is the app's own — every one of them has a sheet or a drawer
11
+ * already, with its own idea of how a thing slides in and what closes it. So
12
+ * this package ships what goes *inside* one (`SetupGuideSummary`,
13
+ * `SetupGuideList`) and a button that opens it, and the app puts them together:
14
+ *
15
+ * ```tsx
16
+ * <SetupLauncherButton />
17
+ * <Sheet open={setup.panelOpen} onOpenChange={setup.setPanelOpen}>
18
+ * <SheetContent>
19
+ * <SetupGuideSummary />
20
+ * <SetupGuideList onGo={() => setup.setPanelOpen(false)} />
21
+ * </SheetContent>
22
+ * </Sheet>
23
+ * ```
24
+ */
25
+ /** The pill: how far along, what has been earned, and a way into the whole guide. */
26
+ export function SetupLauncherButton({ label = "Get started", className, classNames, }) {
27
+ const setup = useSetupGuide();
28
+ const c = useClassNames(classNames);
29
+ const guide = setup?.guide;
30
+ if (!setup || !guide || guide.hidden || guide.complete)
31
+ return null;
32
+ const words = setup.words;
33
+ const share = guide.items.length === 0 ? 0 : Math.round((guide.doneItems / guide.items.length) * 100);
34
+ return (_jsxs("button", { type: "button", onClick: () => setup.setPanelOpen(true), className: cx(c.launcher, className), "aria-label": `${label}: ${guide.doneItems} of ${guide.items.length} steps done, ${guide.earnedReward} of ${guide.totalReward} ${rewardWord(guide.totalReward, words)} earned`, children: [_jsx(ProgressRing, { value: share }), _jsx("span", { className: "hidden lg:inline", children: label }), _jsxs("span", { className: "inline-flex h-[22px] items-center gap-1 rounded-full border border-primary/30 bg-primary/10 px-1.5 text-xs text-primary tabular-nums", children: [_jsx(Sparkles, { className: "size-3", "aria-hidden": true }), guide.earnedReward, "/", guide.totalReward] }), setup.justEarned ? (_jsxs("span", { "aria-hidden": true, className: c.launcherBadge, children: ["+", setup.justEarned] })) : null] }));
35
+ }
36
+ /** The block at the top of the panel: the ring, the count, and one bar per item. */
37
+ export function SetupGuideSummary({ className, classNames }) {
38
+ const setup = useSetupGuide();
39
+ const guide = setup?.guide;
40
+ if (!setup || !guide)
41
+ return null;
42
+ const words = setup.words;
43
+ return (_jsxs("div", { className: cx("flex items-center gap-3.5 rounded-xl border border-border bg-muted/40 p-3.5", className), children: [_jsx(RewardRing, { earned: guide.earnedReward, total: guide.totalReward, size: 60, tone: "light", words: words }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("p", { className: "text-[15px] font-semibold", children: [guide.earnedReward, " of ", guide.totalReward, " ", rewardWord(guide.totalReward, words), " earned"] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [guide.doneItems, " of ", guide.items.length, " steps done"] }), _jsx(Segments, { done: guide.doneItems, total: guide.items.length, tone: "light", classNames: classNames })] })] }));
44
+ }
45
+ /** Every item as a row, for the app's own panel. */
46
+ export function SetupGuideList({ onGo, className, classNames, }) {
47
+ const setup = useSetupGuide();
48
+ const guide = setup?.guide;
49
+ if (!setup || !guide)
50
+ return null;
51
+ return (_jsx("ol", { className: className, children: guide.items.map((item, index) => (_jsx(PanelRow, { item: item, index: index, isNext: item.key === guide.nextKey, onGo: onGo, classNames: classNames }, item.key))) }));
52
+ }
53
+ function PanelRow({ item, index, isNext, onGo, classNames, }) {
54
+ const c = useClassNames(classNames);
55
+ const setup = useSetupGuide();
56
+ const Link = setup?.Link ?? (({ children, ...rest }) => _jsx("a", { ...rest, children: children }));
57
+ const paid = item.steps.length > 0 && item.steps.every((step) => step.earned);
58
+ return (_jsxs("li", { className: "flex gap-3 border-b border-border py-3.5 last:border-b-0", children: [_jsx(StepCircle, { state: item.done ? "done" : isNext ? "next" : "todo", n: index + 1, size: "sm", className: "mt-px", classNames: classNames }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("p", { className: cx("flex-1 text-sm font-semibold", item.done && c.rowTitleDone), children: [item.title, _jsx("span", { className: c.srOnly, children: item.done ? " (done)" : " (to do)" })] }), item.reward > 0 ? (_jsx(RewardChip, { reward: item.reward, state: paid ? "earned" : "todo", classNames: classNames })) : null] }), item.done ? null : (_jsxs(_Fragment, { children: [item.steps.length > 1 ? (_jsxs(_Fragment, { children: [_jsx(MiniProgress, { done: item.doneCount, total: item.steps.length }), isNext && item.screen ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "Its steps show on that screen, with a progress bar." })) : null] })) : null, _jsxs("div", { className: "flex items-center gap-1", children: [item.blocked ? (_jsx("span", { className: c.blocked, children: item.blocked })) : (_jsxs(Link, { href: item.href, onClick: onGo, className: cx(c.button, isNext ? c.buttonPrimary : c.buttonOutline), children: [item.actionLabel, isNext ? _jsx(ArrowRight, { className: "size-4", "aria-hidden": true }) : null] })), _jsx(ItemHelp, { item: item, className: "ml-auto", classNames: classNames })] })] }))] })] }));
59
+ }
60
+ //# sourceMappingURL=launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/setup-guide/launcher.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import { type ClassNameOverrides } from "./bits.js";
3
+ export interface SetupStripProps {
4
+ /** Which item's steps this screen is where you do. */
5
+ itemKey: string;
6
+ /**
7
+ * Steps whose choices are made but not yet saved — for a flow that keeps
8
+ * everything until its last press. They fill the bar without being earned.
9
+ */
10
+ ready?: ReadonlySet<string>;
11
+ className?: string;
12
+ classNames?: ClassNameOverrides;
13
+ }
14
+ /**
15
+ * One item's steps, on the screen where they are done, with a progress bar.
16
+ *
17
+ * Gone as soon as every step is paid: a screen somebody uses every day should
18
+ * not keep a checklist on it for ever.
19
+ */
20
+ export declare function SetupStrip({ itemKey, ready, className, classNames }: SetupStripProps): React.JSX.Element | null;
21
+ //# sourceMappingURL=strip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../../src/setup-guide/strip.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAqE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAYvH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,eAAe,4BAuFpF"}
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDown } from "lucide-react";
4
+ import * as React from "react";
5
+ import { cx } from "../internal/cx.js";
6
+ import { GuideIconLink, HowToButton, RewardChip, StepCircle, useClassNames } from "./bits.js";
7
+ import { rewardWord, useSetupGuide } from "./context.js";
8
+ import { findItem, itemProgress, stepState } from "./guide.js";
9
+ // Answered by the strip's own width: beside a sidebar, the window says nothing
10
+ // useful about how much room this actually has.
11
+ const COLUMNS = {
12
+ 3: "@2xl:grid-cols-3",
13
+ 4: "@3xl:grid-cols-4",
14
+ 5: "@4xl:grid-cols-5",
15
+ };
16
+ /**
17
+ * One item's steps, on the screen where they are done, with a progress bar.
18
+ *
19
+ * Gone as soon as every step is paid: a screen somebody uses every day should
20
+ * not keep a checklist on it for ever.
21
+ */
22
+ export function SetupStrip({ itemKey, ready, className, classNames }) {
23
+ const setup = useSetupGuide();
24
+ const c = useClassNames(classNames);
25
+ const [open, setOpen] = React.useState(true);
26
+ const item = findItem(setup?.guide, itemKey);
27
+ if (!setup?.guide || setup.guide.hidden || !item)
28
+ return null;
29
+ if (item.steps.length === 0 || item.steps.every((step) => step.earned))
30
+ return null;
31
+ const words = setup.words;
32
+ const { progressed, total, percent, nextKey } = itemProgress(item, ready);
33
+ const owing = item.reward - item.earnedReward;
34
+ const summary = item.paysOnComplete
35
+ ? `${progressed} of ${total} ready · ${owing} ${rewardWord(owing, words)} land when it is built`
36
+ : `${item.doneCount} of ${total} done · ${item.earnedReward} of ${item.reward} ${rewardWord(item.reward, words)} earned`;
37
+ return (_jsxs("section", { "aria-label": item.title, className: cx("@container", c.strip, className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-3.5 gap-y-3", children: [item.icon ? (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-secondary", children: item.icon })) : null, _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h2", { className: c.stripTitle, children: item.title }), _jsx("p", { className: c.stripSummary, children: summary })] }), _jsxs("div", { className: "flex w-full items-center gap-3 sm:w-auto", children: [_jsx("div", { role: "progressbar", "aria-label": `${item.title}: ${percent}%`, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": percent, className: cx(c.bar, "flex-1 sm:w-56"), children: _jsx("div", { className: c.barFill, style: { width: `${percent}%` } }) }), _jsxs("span", { className: "text-[13px] font-semibold tabular-nums", children: [percent, "%"] }), _jsx("button", { type: "button", "aria-expanded": open, "aria-label": open ? "Hide the steps" : "Show the steps", onClick: () => setOpen((current) => !current), className: c.iconButton, children: _jsx(ChevronDown, { className: cx("size-4 transition-transform", !open && "-rotate-90"), "aria-hidden": true }) })] })] }), open ? (_jsx("ol", { className: cx("mt-3.5 grid gap-2.5 @md:grid-cols-2", COLUMNS[total]), children: item.steps.map((step, index) => {
38
+ const state = stepState(step, nextKey, ready);
39
+ return (_jsxs("li", { className: cx(c.stripTile, state === "next" && c.stripTileNext), children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(StepCircle, { state: state, n: index + 1, size: "sm", classNames: classNames }), step.reward > 0 ? (_jsx(RewardChip, { reward: step.reward, state: step.earned ? "earned" : item.paysOnComplete ? "on-complete" : "todo", words: words, classNames: classNames })) : null] }), _jsxs("p", { className: cx("text-[13.5px] leading-snug font-semibold", step.done && c.rowTitleDone), children: [step.title, _jsx("span", { className: c.srOnly, children: step.done ? " (done)" : state === "ready" ? " (ready — pays when built)" : " (to do)" })] }), _jsxs("div", { className: "-ml-1.5 mt-auto flex items-center", children: [step.how ? (_jsx(HowToButton, { how: step.how, guide: step.guide, className: "size-7", classNames: classNames })) : null, _jsx(GuideIconLink, { guide: step.guide, className: "size-7", classNames: classNames }), state === "next" ? _jsx("span", { className: "ml-auto text-xs font-semibold text-primary", children: "Next" }) : null] })] }, step.key));
40
+ }) })) : null] }));
41
+ }
42
+ //# sourceMappingURL=strip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strip.js","sourceRoot":"","sources":["../../src/setup-guide/strip.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAA2B,MAAM,WAAW,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE/D,+EAA+E;AAC/E,gDAAgD;AAChD,MAAM,OAAO,GAA2B;IACtC,CAAC,EAAE,kBAAkB;IACrB,CAAC,EAAE,kBAAkB;IACrB,CAAC,EAAE,kBAAkB;CACtB,CAAC;AAcF;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAmB;IACnF,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,MAAM,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAE7C,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9D,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc;QACjC,CAAC,CAAC,GAAG,UAAU,OAAO,KAAK,YAAY,KAAK,IAAI,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,wBAAwB;QAChG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,OAAO,KAAK,WAAW,IAAI,CAAC,YAAY,OAAO,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3H,OAAO,CACL,iCAAqB,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,aAC9E,eAAK,SAAS,EAAC,+CAA+C,aAC3D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CACX,eAAM,SAAS,EAAC,0EAA0E,YAAE,IAAI,CAAC,IAAI,GAAQ,CAC9G,CAAC,CAAC,CAAC,IAAI,EACR,eAAK,SAAS,EAAC,gBAAgB,aAC7B,aAAI,SAAS,EAAE,CAAC,CAAC,UAAU,YAAG,IAAI,CAAC,KAAK,GAAM,EAC9C,YAAG,SAAS,EAAE,CAAC,CAAC,YAAY,YAAG,OAAO,GAAK,IACvC,EACN,eAAK,SAAS,EAAC,0CAA0C,aACvD,cACE,IAAI,EAAC,aAAa,gBACN,GAAG,IAAI,CAAC,KAAK,KAAK,OAAO,GAAG,mBACzB,CAAC,mBACD,GAAG,mBACH,OAAO,EACtB,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,gBAAgB,CAAC,YAEtC,cAAK,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,OAAO,GAAG,EAAE,GAAI,GAC1D,EACN,gBAAM,SAAS,EAAC,wCAAwC,aAAE,OAAO,SAAS,EAC1E,iBACE,IAAI,EAAC,QAAQ,mBACE,IAAI,gBACP,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,EACtD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,EAC7C,SAAS,EAAE,CAAC,CAAC,UAAU,YAEvB,KAAC,WAAW,IAAC,SAAS,EAAE,EAAE,CAAC,6BAA6B,EAAE,CAAC,IAAI,IAAI,YAAY,CAAC,wBAAgB,GACzF,IACL,IACF,EAEL,IAAI,CAAC,CAAC,CAAC,CACN,aAAI,SAAS,EAAE,EAAE,CAAC,qCAAqC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,YACrE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;oBAC9B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;oBAC9C,OAAO,CACL,cAAmB,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,aAAa,CAAC,aAChF,eAAK,SAAS,EAAC,yCAAyC,aACtD,KAAC,UAAU,IAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,EAAC,IAAI,EAAC,UAAU,EAAE,UAAU,GAAI,EAC3E,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACjB,KAAC,UAAU,IACT,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,EAC5E,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,GACtB,CACH,CAAC,CAAC,CAAC,IAAI,IACJ,EACN,aAAG,SAAS,EAAE,EAAE,CAAC,0CAA0C,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,YAAY,CAAC,aACtF,IAAI,CAAC,KAAK,EACX,eAAM,SAAS,EAAE,CAAC,CAAC,MAAM,YACtB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,UAAU,GACjF,IACL,EACJ,eAAK,SAAS,EAAC,mCAAmC,aAC/C,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CACV,KAAC,WAAW,IAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAC,QAAQ,EAAC,UAAU,EAAE,UAAU,GAAI,CAC7F,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,aAAa,IAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAC,QAAQ,EAAC,UAAU,EAAE,UAAU,GAAI,EAC9E,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,4CAA4C,qBAAY,CAAC,CAAC,CAAC,IAAI,IAC/F,KAxBC,IAAI,CAAC,GAAG,CAyBZ,CACN,CAAC;gBACJ,CAAC,CAAC,GACC,CACN,CAAC,CAAC,CAAC,IAAI,IACA,CACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `@connextar/house/wizard` — one long form, split into steps that check
3
+ * themselves.
4
+ *
5
+ * Five apps wrote this and four of them shipped a defect in it: a booking
6
+ * created from step two because two buttons shared a slot and React switched the
7
+ * type mid-click; three forms that refused to save with nothing on screen saying
8
+ * why; a stepper that checked no step at all on submit and sent a record whose
9
+ * first step had been cleared. None of those are mistakes about wizards. They are
10
+ * mistakes about what a form must do before it agrees to send, and there is one
11
+ * right answer to that, which is why this is here rather than in five places.
12
+ *
13
+ * Form-library-agnostic on purpose: the host supplies the check
14
+ * (`onValidateStep`, or a `validate` on the step), so react-hook-form, plain
15
+ * state and a form held in `useState` can all host it. The react-hook-form
16
+ * adapter is `@connextar/house/wizard/react-hook-form`, kept apart so that
17
+ * `react-hook-form` stays the optional peer dependency it is declared to be.
18
+ *
19
+ * What reaches the person, when a refusal has nowhere to show itself, goes
20
+ * through the `ActionFeedbackProvider` from `@connextar/house/ux` — so this
21
+ * module imports no toast library and no design system.
22
+ */
23
+ export { ERROR_ATTRIBUTE, fieldProblems, INVALID_MESSAGES, isOnScreen, REPORT_DELAY, reportInvalid, shownErrorFields, unseenProblems, useInvalidReporter, type FieldProblem, type InvalidMessages, type InvalidReporter, } from "./invalid.js";
24
+ export { checkStep, firstFailure, isReachable, markerState, nextIndex, percentComplete, previousIndex, stepResult, type MarkerState, type StepCheck, type StepCheckable, type StepFailure, type StepOutcome, type StepResult, } from "./rules.js";
25
+ export { FieldError, FormWizard, ReviewRow, WIZARD_CLASS_NAMES, type FormWizardProps, type WizardClassNames, type WizardStep, } from "./wizard.js";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wizard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `@connextar/house/wizard` — one long form, split into steps that check
3
+ * themselves.
4
+ *
5
+ * Five apps wrote this and four of them shipped a defect in it: a booking
6
+ * created from step two because two buttons shared a slot and React switched the
7
+ * type mid-click; three forms that refused to save with nothing on screen saying
8
+ * why; a stepper that checked no step at all on submit and sent a record whose
9
+ * first step had been cleared. None of those are mistakes about wizards. They are
10
+ * mistakes about what a form must do before it agrees to send, and there is one
11
+ * right answer to that, which is why this is here rather than in five places.
12
+ *
13
+ * Form-library-agnostic on purpose: the host supplies the check
14
+ * (`onValidateStep`, or a `validate` on the step), so react-hook-form, plain
15
+ * state and a form held in `useState` can all host it. The react-hook-form
16
+ * adapter is `@connextar/house/wizard/react-hook-form`, kept apart so that
17
+ * `react-hook-form` stays the optional peer dependency it is declared to be.
18
+ *
19
+ * What reaches the person, when a refusal has nowhere to show itself, goes
20
+ * through the `ActionFeedbackProvider` from `@connextar/house/ux` — so this
21
+ * module imports no toast library and no design system.
22
+ */
23
+ export { ERROR_ATTRIBUTE, fieldProblems, INVALID_MESSAGES, isOnScreen, REPORT_DELAY, reportInvalid, shownErrorFields, unseenProblems, useInvalidReporter, } from "./invalid.js";
24
+ export { checkStep, firstFailure, isReachable, markerState, nextIndex, percentComplete, previousIndex, stepResult, } from "./rules.js";
25
+ export { FieldError, FormWizard, ReviewRow, WIZARD_CLASS_NAMES, } from "./wizard.js";
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wizard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,kBAAkB,GAInB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,GAOX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,UAAU,EACV,UAAU,EACV,SAAS,EACT,kBAAkB,GAInB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { type ActionReporter } from "../ux/feedback.js";
2
+ /**
3
+ * Saying why a form refused, when the reason is somewhere nobody can look.
4
+ *
5
+ * A wizard keeps fields on steps that are mounted but hidden, and a form library
6
+ * will not call a submit handler while any field is invalid. An error shown
7
+ * beside its field speaks for itself. One on a field nobody can see — another
8
+ * step, a field the form hides because it does not apply, a rule that belongs to
9
+ * no field at all — makes the button look broken, and that one has to be said
10
+ * out loud. This is the half of the wizard that has to read the DOM, so it is
11
+ * kept apart from the rules.
12
+ *
13
+ * Where it is said is the app's decision, not this package's: the message goes to
14
+ * the `ActionFeedbackProvider` that `@connextar/house/ux` already defines, so an
15
+ * app wires one reporter to whatever it uses to tell people things and this
16
+ * module imports no toast library.
17
+ */
18
+ /**
19
+ * The attribute a field's error message carries, so a visible one can be told
20
+ * from a hidden one. `FieldError` sets it; an app's own message component sets
21
+ * it too (`<p data-error-for="title">`), which is the whole integration.
22
+ */
23
+ export declare const ERROR_ATTRIBUTE = "data-error-for";
24
+ /** How long to wait before looking. */
25
+ export declare const REPORT_DELAY = 50;
26
+ export interface InvalidMessages {
27
+ /** The heading. */
28
+ title: string;
29
+ /** Used when no problem carried a message of its own. */
30
+ fallback: string;
31
+ }
32
+ export declare const INVALID_MESSAGES: InvalidMessages;
33
+ export interface FieldProblem {
34
+ name: string;
35
+ message: string | null;
36
+ }
37
+ /**
38
+ * The problems in an error object, whatever shape the form library gave them.
39
+ * Only the entries that are objects count: a form library's error map holds one
40
+ * per field, and anything else in there is not a field error.
41
+ */
42
+ export declare function fieldProblems(errors: object): FieldProblem[];
43
+ /**
44
+ * Rendered, outside a hidden step, and — where the page has layout at all —
45
+ * taking up space.
46
+ *
47
+ * A DOM without layout, like a test's, has no boxes to measure, so `hidden`
48
+ * decides there on its own. Measuring alone was AltEd's version, and under jsdom
49
+ * it called every message invisible and said everything twice.
50
+ */
51
+ export declare function isOnScreen(element: HTMLElement): boolean;
52
+ /** The field names whose message is on screen right now. */
53
+ export declare function shownErrorFields(root: ParentNode): string[];
54
+ /**
55
+ * The problems with nothing on screen to show them.
56
+ *
57
+ * A name matches a shown message exactly, or as its prefix: an error on
58
+ * `times` is answered by a message on `times.0.start`, because that is where a
59
+ * form library puts the message for an array field's row.
60
+ */
61
+ export declare function unseenProblems(problems: readonly FieldProblem[], shown: readonly string[]): FieldProblem[];
62
+ export type InvalidReporter = (errors: object) => void;
63
+ /**
64
+ * Report the errors an invalid form refused on, if any of them has nowhere to
65
+ * show itself.
66
+ *
67
+ * Deferred, because it has to run after the form has re-rendered with its errors
68
+ * and after a wizard has moved to the failing step — before that, every message
69
+ * is still hidden and it would say everything twice. Returns a way to cancel,
70
+ * for a component that unmounts in between.
71
+ *
72
+ * Two silences and one noise:
73
+ *
74
+ * - Problems, all of them showing → quiet. The fields say it better.
75
+ * - Problems, at least one unseen → the first unseen message, or the fallback.
76
+ * - **No problems at all → the fallback**, not quiet. A form that refuses with
77
+ * an empty error map is the worst of the cases, not the mildest: something
78
+ * said no and named nothing, and the person is left pressing a dead button.
79
+ */
80
+ export declare function reportInvalid(errors: object, report: ActionReporter, options?: {
81
+ delay?: number;
82
+ root?: ParentNode;
83
+ messages?: Partial<InvalidMessages>;
84
+ }): () => void;
85
+ /**
86
+ * `reportInvalid` bound to the app's reporter — pass it straight to a form
87
+ * library's invalid handler (`handleSubmit(onSubmit, report)`), or let
88
+ * `stepValidator` from `@connextar/house/wizard/react-hook-form` call it.
89
+ */
90
+ export declare function useInvalidReporter(messages?: Partial<InvalidMessages>): InvalidReporter;
91
+ //# sourceMappingURL=invalid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invalid.d.ts","sourceRoot":"","sources":["../../src/wizard/invalid.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;;;;;;;;;GAeG;AAEH;;;;GAIG;AACH,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAEhD,uCAAuC;AACvC,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,EAAE,eAG9B,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAM5D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAIxD;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,CAI3D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,EAAE,CAE1G;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;CAAO,GACvF,MAAM,IAAI,CAcZ;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAYvF"}