@hook-sdk/template 0.10.0 → 0.11.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.
- package/dist/index.cjs +60 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +61 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -153,7 +153,12 @@ var AppConfigSchema = import_zod.z.object({
|
|
|
153
153
|
persistedKeys: import_zod.z.array(PersistedKeySchema),
|
|
154
154
|
onboarding: OnboardingSchema.optional(),
|
|
155
155
|
deepLinks: DeepLinksSchema.optional(),
|
|
156
|
-
features_enabled: import_zod.z.array(import_zod.z.string()).optional()
|
|
156
|
+
features_enabled: import_zod.z.array(import_zod.z.string()).optional(),
|
|
157
|
+
// Build-time injected theme metadata (e.g. icon_url for InstallSplash).
|
|
158
|
+
// Apps don't author this directly; deploy workflows fill it from
|
|
159
|
+
// env-resolved bundle host. Permissive shape so apps/workflows can
|
|
160
|
+
// extend without re-bumping the template schema.
|
|
161
|
+
theme: import_zod.z.object({}).passthrough().optional()
|
|
157
162
|
}).strict();
|
|
158
163
|
function parseAppConfig(input) {
|
|
159
164
|
const r = AppConfigSchema.safeParse(input);
|
|
@@ -1829,8 +1834,15 @@ var ErrorBoundary = class extends import_react9.Component {
|
|
|
1829
1834
|
static getDerivedStateFromError(error) {
|
|
1830
1835
|
return { error };
|
|
1831
1836
|
}
|
|
1832
|
-
componentDidCatch(error) {
|
|
1833
|
-
console.error(
|
|
1837
|
+
componentDidCatch(error, info) {
|
|
1838
|
+
console.error(
|
|
1839
|
+
"[ErrorBoundary] caught:",
|
|
1840
|
+
error?.message || "(no message)",
|
|
1841
|
+
"\nstack:",
|
|
1842
|
+
error?.stack || "(no stack)",
|
|
1843
|
+
"\ncomponentStack:",
|
|
1844
|
+
info?.componentStack || "(no componentStack)"
|
|
1845
|
+
);
|
|
1834
1846
|
}
|
|
1835
1847
|
render() {
|
|
1836
1848
|
if (this.state.error) {
|
|
@@ -2604,62 +2616,82 @@ function useOnboardingStep() {
|
|
|
2604
2616
|
// src/OnboardingFlow.tsx
|
|
2605
2617
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2606
2618
|
var isFilled = (v) => v != null && v !== "";
|
|
2619
|
+
var CURRENT_STEP_FIELD = "currentStep";
|
|
2620
|
+
function readPersistedStepIdx(draft) {
|
|
2621
|
+
const raw = draft[CURRENT_STEP_FIELD];
|
|
2622
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : 0;
|
|
2623
|
+
}
|
|
2607
2624
|
function OnboardingFlow({
|
|
2608
2625
|
steps,
|
|
2609
2626
|
screens,
|
|
2610
2627
|
onComplete,
|
|
2611
2628
|
persistKey
|
|
2612
2629
|
}) {
|
|
2613
|
-
const [draft, setDraft] = (0, import_sdk16.usePersistedState)(persistKey, {});
|
|
2614
|
-
const [idx, setIdx] = (0, import_react21.useState)(0);
|
|
2630
|
+
const [draft, setDraft, status] = (0, import_sdk16.usePersistedState)(persistKey, {});
|
|
2615
2631
|
const draftRef = (0, import_react21.useRef)(draft);
|
|
2616
2632
|
draftRef.current = draft;
|
|
2617
|
-
const
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
}
|
|
2629
|
-
const valid = (0, import_react21.useMemo)(
|
|
2630
|
-
() => (step.validates ?? []).every((field) => isFilled(draft[field])),
|
|
2631
|
-
[draft, step]
|
|
2633
|
+
const idx = readPersistedStepIdx(draft);
|
|
2634
|
+
const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
|
|
2635
|
+
const setIdx = (0, import_react21.useCallback)(
|
|
2636
|
+
(n) => {
|
|
2637
|
+
setDraft((prev) => {
|
|
2638
|
+
const prevIdx = readPersistedStepIdx(prev);
|
|
2639
|
+
const nextIdx = typeof n === "function" ? n(prevIdx) : n;
|
|
2640
|
+
return { ...prev, [CURRENT_STEP_FIELD]: nextIdx };
|
|
2641
|
+
});
|
|
2642
|
+
},
|
|
2643
|
+
[setDraft]
|
|
2632
2644
|
);
|
|
2633
2645
|
const setValue = (0, import_react21.useCallback)(
|
|
2634
2646
|
(patch) => {
|
|
2635
2647
|
draftRef.current = { ...draftRef.current, ...patch };
|
|
2636
|
-
setDraft((
|
|
2648
|
+
setDraft((prev) => ({ ...prev, ...patch }));
|
|
2637
2649
|
},
|
|
2638
2650
|
[setDraft]
|
|
2639
2651
|
);
|
|
2652
|
+
const step = steps[clampedIdx];
|
|
2653
|
+
const valid = (0, import_react21.useMemo)(
|
|
2654
|
+
() => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
|
|
2655
|
+
[draft, step]
|
|
2656
|
+
);
|
|
2640
2657
|
const next = (0, import_react21.useCallback)(() => {
|
|
2658
|
+
if (!step) return;
|
|
2641
2659
|
const current = draftRef.current;
|
|
2642
2660
|
const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
|
|
2643
2661
|
if (!validNow) return;
|
|
2644
|
-
if (
|
|
2662
|
+
if (clampedIdx + 1 >= steps.length) {
|
|
2645
2663
|
onComplete(current);
|
|
2646
2664
|
} else {
|
|
2647
|
-
setIdx(
|
|
2665
|
+
setIdx(clampedIdx + 1);
|
|
2648
2666
|
}
|
|
2649
|
-
}, [
|
|
2650
|
-
const
|
|
2667
|
+
}, [clampedIdx, onComplete, step, steps.length, setIdx]);
|
|
2668
|
+
const prevStep = (0, import_react21.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
|
|
2651
2669
|
const ctx = (0, import_react21.useMemo)(
|
|
2652
2670
|
() => ({
|
|
2653
|
-
stepIndex:
|
|
2671
|
+
stepIndex: clampedIdx,
|
|
2654
2672
|
totalSteps: steps.length,
|
|
2655
2673
|
value: draft,
|
|
2656
2674
|
setValue,
|
|
2657
2675
|
valid,
|
|
2658
2676
|
next,
|
|
2659
|
-
prev
|
|
2677
|
+
prev: prevStep
|
|
2660
2678
|
}),
|
|
2661
|
-
[
|
|
2679
|
+
[clampedIdx, steps.length, draft, setValue, valid, next, prevStep]
|
|
2662
2680
|
);
|
|
2681
|
+
if (status.loading) {
|
|
2682
|
+
return null;
|
|
2683
|
+
}
|
|
2684
|
+
if (!step) {
|
|
2685
|
+
throw new Error(
|
|
2686
|
+
`[hook-template] OnboardingFlow: step index ${clampedIdx} out of range (steps.length=${steps.length})`
|
|
2687
|
+
);
|
|
2688
|
+
}
|
|
2689
|
+
const Screen = screens[step.screen];
|
|
2690
|
+
if (!Screen) {
|
|
2691
|
+
throw new Error(
|
|
2692
|
+
`[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
|
|
2693
|
+
);
|
|
2694
|
+
}
|
|
2663
2695
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Screen, {}) });
|
|
2664
2696
|
}
|
|
2665
2697
|
|