@daltonr/pathwrite-solid 0.11.0 → 0.13.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/README.md CHANGED
@@ -10,6 +10,21 @@ npm install @daltonr/pathwrite-core @daltonr/pathwrite-solid
10
10
 
11
11
  Peer dependencies: `solid-js >= 1.8.0`
12
12
 
13
+ ### `tsconfig.json` — required `jsxImportSource`
14
+
15
+ Solid JSX requires `"jsxImportSource": "solid-js"` in your `tsconfig.json`. Using the wrong value (a common mistake is `"solid-js/h"`) produces a cryptic TypeScript error that does not mention Solid or JSX at all.
16
+
17
+ ```json
18
+ {
19
+ "compilerOptions": {
20
+ "jsx": "preserve",
21
+ "jsxImportSource": "solid-js"
22
+ }
23
+ }
24
+ ```
25
+
26
+ If you see a type error about JSX elements being `Element | null | undefined` when they should be `JSX.Element`, check this value first.
27
+
13
28
  ---
14
29
 
15
30
  ## Quick start
@@ -74,6 +89,8 @@ export function DetailsStep() {
74
89
 
75
90
  Step components call `usePathContext()` to access engine state. `<PathShell>` provides the context automatically via `createContext` / `useContext`.
76
91
 
92
+ Each step render function runs once, when its step becomes current, and the component it returns lives until the path moves to a different step. Engine events that leave the step unchanged (`setData` on every keystroke, `validate()`, guard and hook status changes) do not re-create it, so inputs keep their DOM node, focus and local state. Live state reaches the step reactively either through `usePathContext().snapshot()` or through the `snapshot` argument of the render function, whose properties read the current snapshot: `(snap) => <DetailsStep snapshot={snap} />` with `createMemo(() => props.snapshot.data)` inside stays up to date.
93
+
77
94
  ---
78
95
 
79
96
  ## usePath
@@ -82,7 +99,7 @@ Step components call `usePathContext()` to access engine state. `<PathShell>` pr
82
99
 
83
100
  | Return value | Type | Description |
84
101
  |---|---|---|
85
- | `snapshot` | `Accessor<PathSnapshot \| null>` | Current snapshot. Call `snapshot()` to read. `null` when no path is active. Tracked reactively when read inside JSX or effects. |
102
+ | `snapshot` | `Accessor<PathSnapshot \| null>` | Current snapshot. Call `snapshot()` to read. `null` when no path is active or when `completionBehaviour: "dismiss"` is used. With the default `"stayOnFinal"`, the accessor returns a snapshot with `status === "completed"` after the path finishes. Tracked reactively when read inside JSX or effects. |
86
103
  | `start(definition, data?)` | function | Start or re-start a path. |
87
104
  | `next()` | function | Advance one step. Completes the path on the last step. |
88
105
  | `previous()` | function | Go back one step. No-op on the first step of a top-level path. |
@@ -90,11 +107,11 @@ Step components call `usePathContext()` to access engine state. `<PathShell>` pr
90
107
  | `goToStep(stepId)` | function | Jump to a step by ID, bypassing guards and `shouldSkip`. |
91
108
  | `goToStepChecked(stepId)` | function | Jump to a step by ID, checking the relevant navigation guard first. |
92
109
  | `setData(key, value)` | function | Update a single data field. Type-checked when `TData` is provided. |
93
- | `resetStep()` | function | Re-run `onEnter` for the current step without changing step index. |
110
+ | `resetStep()` | function | Restore the current step's data to what it was when the step was entered. Emits `stateChanged` with cause `"resetStep"`; no hooks run. |
94
111
  | `startSubPath(definition, data?, meta?)` | function | Push a sub-path. `meta` is echoed back to `onSubPathComplete` / `onSubPathCancel`. |
95
- | `suspend()` | function | Suspend an async step while work completes. |
96
- | `retry()` | function | Retry the current step after a suspension or error. |
97
- | `restart()` | function | Tear down the active path without firing hooks and start fresh. |
112
+ | `suspend()` | function | Pause the path with intent to return. Emits `suspended`; all state and data are preserved. |
113
+ | `retry()` | function | Re-run the operation that set `snapshot().error`. Increments `retryCount` on repeated failure. No-op when there is no pending error. |
114
+ | `restart()` | function | Tear down the active path without firing hooks and restart the root path with the `initialData` from the original `start()`. Takes no arguments; rejects if nothing has been started. |
98
115
  | `validate()` | function | Set `snapshot().hasValidated` without navigating. Used to trigger inline errors across all tabs in a nested shell. |
99
116
 
100
117
  ---
@@ -118,17 +135,26 @@ Step components call `usePathContext()` to access engine state. `<PathShell>` pr
118
135
  | `path` | `PathDefinition` | required | The path to run. |
119
136
  | `steps` | `Record<string, (snapshot: PathSnapshot) => JSX.Element>` | — | Step render functions keyed by step ID (or `formId` for `StepChoice` steps). |
120
137
  | `initialData` | `PathData` | `{}` | Initial data passed to `engine.start()`. |
121
- | `engine` | `PathEngine` | — | An externally-managed engine. When provided, `PathShell` skips its own `start()`. |
138
+ | `engine` | `PathEngine` | — | An externally-managed engine. When provided, `PathShell` skips its own `start()`. May be provided after mount (e.g. once an async `restoreOrStart()` resolves): the shell adopts it, re-subscribing and re-seeding from the new engine. Set `autoStart` to `false` if the shell should not start its own path in the meantime. |
122
139
  | `autoStart` | `boolean` | `true` | Start the path automatically on mount. Ignored when `engine` is provided. |
123
140
  | `validationDisplay` | `"summary" \| "inline" \| "both"` | `"summary"` | Where `fieldErrors` are rendered. Use `"inline"` to suppress the summary and handle errors inside step components. |
124
- | `footerLayout` | `"wizard" \| "form" \| "auto"` | `"auto"` | `"wizard"`: Back on left, Cancel+Submit on right. `"form"`: Cancel on left, Submit on right, no Back. `"auto"` picks `"form"` for single-step paths. |
141
+ | `layout` | `"wizard" \| "form" \| "auto" \| "tabs"` | `"auto"` | `"wizard"`: Back on left, Cancel+Submit on right. `"form"`: Cancel on left, Submit on right, no Back. `"tabs"`: No progress header or footer — for tabbed interfaces. `"auto"` picks `"form"` for single-step paths. |
142
+ | `progressLayout` | `"merged" \| "split" \| "rootOnly" \| "activeOnly"` | `"merged"` | How the root and sub-path progress bars are arranged while a sub-path is active. |
125
143
  | `hideProgress` | `boolean` | `false` | Hide the progress indicator. Also hidden automatically for single-step top-level paths. |
126
144
  | `hideFooter` | `boolean` | `false` | Hide the footer entirely. The error panel is still shown on async failure. |
127
145
  | `hideCancel` | `boolean` | `false` | Hide the Cancel button. |
146
+ | `backLabel` | `string` | `"Previous"` | Previous button label. |
147
+ | `nextLabel` | `string` | `"Next"` | Next button label. |
148
+ | `completeLabel` | `string` | `"Complete"` | Complete button label (last step). |
149
+ | `loadingLabel` | `string` | `undefined` | Label for the Next/Complete button while an async operation is in progress. When unset, the button keeps its label and shows a CSS spinner. |
150
+ | `cancelLabel` | `string` | `"Cancel"` | Cancel button label. |
151
+ | `class` | `string` | — | Extra CSS class on the root element. |
128
152
  | `validateWhen` | `boolean` | `false` | When it becomes `true`, calls `validate()` on the engine. Bind to the outer shell's `hasAttemptedNext` for nested shells. |
129
153
  | `services` | `object \| null` | `null` | Services object passed through context to all step components. |
130
- | `renderHeader` | `(snapshot) => JSX.Element` | | Replace the default progress header. |
131
- | `renderFooter` | `(snapshot, actions) => JSX.Element` | — | Replace the default navigation buttons. |
154
+ | `restoreKey` | `string` | — | When set, the shell automatically saves its full state (data + active step) into the nearest outer `PathShell`'s data under this key on every change, and restores from it on remount. No-op on a top-level shell. The stored value also carries the inner engine's serialized state, so a remount restores in place: no `onEnter` / `onLeave` re-run, attempted / visited state kept. |
155
+ | `renderHeader` | `(snapshot) => JSX.Element` | — | Replace the default progress header. A custom header is shown even for single-step paths, and hidden under `hideProgress` or `layout="tabs"`. |
156
+ | `renderFooter` | `(snapshot, actions) => JSX.Element` | — | Replace the default navigation buttons. `actions` contains `next`, `previous`, `cancel`, `goToStep`, `goToStepChecked`, `setData`, `restart`, `retry`, `suspend`. |
157
+ | `completionContent` | `(snapshot: PathSnapshot) => JSX.Element` | — | Custom content rendered when `snapshot().status === "completed"` (`completionBehaviour: "stayOnFinal"`). Receives the completed snapshot. If omitted, a default "All done." panel is shown. |
132
158
  | `onComplete` | `(data: PathData) => void` | — | Called when the path completes. |
133
159
  | `onCancel` | `(data: PathData) => void` | — | Called when the path is cancelled. |
134
160
  | `onEvent` | `(event: PathEvent) => void` | — | Called for every engine event. |
@@ -156,6 +182,38 @@ function DetailsStep() {
156
182
  }
157
183
  ```
158
184
 
185
+ ### Avoid repeated `snapshot()` calls — use `createMemo`
186
+
187
+ Each call to `snapshot()` is a separate signal read. In a step component with several fields, calling it inline six times creates six subscriptions and six potential re-renders per update.
188
+
189
+ Wrap it in a `createMemo` to read the signal once and share the result:
190
+
191
+ ```tsx
192
+ import { createMemo } from "solid-js";
193
+ import { usePathContext } from "@daltonr/pathwrite-solid";
194
+
195
+ function DetailsStep() {
196
+ const { snapshot, setData } = usePathContext<ApplicationData>();
197
+ const data = createMemo(() => snapshot()?.data as ApplicationData | undefined);
198
+ const errors = createMemo(() => snapshot()?.fieldErrors);
199
+ const attempted = createMemo(() => snapshot()?.hasAttemptedNext ?? false);
200
+
201
+ return (
202
+ <div>
203
+ <input
204
+ value={data()?.name ?? ""}
205
+ onInput={(e) => setData("name", e.currentTarget.value)}
206
+ />
207
+ <Show when={attempted() && errors()?.name}>
208
+ <p class="error">{errors()?.name}</p>
209
+ </Show>
210
+ </div>
211
+ );
212
+ }
213
+ ```
214
+
215
+ `createMemo` caches the derived value and only recomputes when the underlying signal changes, so all reads within the component share one subscription.
216
+
159
217
  ---
160
218
 
161
219
  ## Complete example
@@ -202,21 +260,25 @@ export const applicationPath: PathDefinition<ApplicationData> = {
202
260
 
203
261
  ```tsx
204
262
  // DetailsStep.tsx
263
+ import { createMemo } from "solid-js";
205
264
  import { usePathContext } from "@daltonr/pathwrite-solid";
206
265
  import type { ApplicationData } from "./application-path";
207
266
 
208
267
  export function DetailsStep() {
209
268
  const { snapshot, setData } = usePathContext<ApplicationData>();
269
+ const data = createMemo(() => snapshot()?.data as ApplicationData | undefined);
270
+ const errors = createMemo(() => snapshot()?.fieldErrors);
271
+ const attempted = createMemo(() => snapshot()?.hasAttemptedNext ?? false);
210
272
 
211
273
  return (
212
274
  <div>
213
275
  <label>First name</label>
214
276
  <input
215
- value={snapshot()?.data.firstName ?? ""}
277
+ value={data()?.firstName ?? ""}
216
278
  onInput={(e) => setData("firstName", e.currentTarget.value)}
217
279
  />
218
- <Show when={snapshot()?.hasAttemptedNext && snapshot()?.fieldErrors.firstName}>
219
- <p class="error">{snapshot()?.fieldErrors.firstName}</p>
280
+ <Show when={attempted() && errors()?.firstName}>
281
+ <p class="error">{errors()?.firstName}</p>
220
282
  </Show>
221
283
  </div>
222
284
  );
@@ -225,23 +287,27 @@ export function DetailsStep() {
225
287
 
226
288
  ```tsx
227
289
  // CoverNoteStep.tsx
290
+ import { createMemo } from "solid-js";
228
291
  import { usePathContext } from "@daltonr/pathwrite-solid";
229
292
  import type { ApplicationData } from "./application-path";
230
293
 
231
294
  export function CoverNoteStep() {
232
295
  const { snapshot, setData } = usePathContext<ApplicationData>();
296
+ const data = createMemo(() => snapshot()?.data as ApplicationData | undefined);
297
+ const errors = createMemo(() => snapshot()?.fieldErrors);
298
+ const attempted = createMemo(() => snapshot()?.hasAttemptedNext ?? false);
233
299
 
234
300
  return (
235
301
  <div>
236
302
  <label>Cover note</label>
237
303
  <textarea
238
- value={snapshot()?.data.coverNote ?? ""}
304
+ value={data()?.coverNote ?? ""}
239
305
  onInput={(e) => setData("coverNote", e.currentTarget.value)}
240
306
  rows="6"
241
307
  placeholder="Tell us why you're a great fit..."
242
308
  />
243
- <Show when={snapshot()?.hasAttemptedNext && snapshot()?.fieldErrors.coverNote}>
244
- <p class="error">{snapshot()?.fieldErrors.coverNote}</p>
309
+ <Show when={attempted() && errors()?.coverNote}>
310
+ <p class="error">{errors()?.coverNote}</p>
245
311
  </Show>
246
312
  </div>
247
313
  );
@@ -343,7 +409,7 @@ function App() {
343
409
  ## Further reading
344
410
 
345
411
  - [SolidJS getting started guide](../../docs/getting-started/frameworks/solidjs.md)
346
- - [Navigation guide](../../docs/guides/navigation.md)
412
+ - [Navigation guide](../../docs/developer-guide/04-navigation.md)
347
413
  - [Full docs](../../docs/README.md)
348
414
 
349
415
  ---
package/dist/index.css CHANGED
@@ -77,6 +77,31 @@
77
77
  font-size: 14px;
78
78
  }
79
79
 
80
+ /* ------------------------------------------------------------------ */
81
+ /* Completion panel */
82
+ /* ------------------------------------------------------------------ */
83
+ .pw-shell__completion {
84
+ text-align: center;
85
+ padding: 40px 16px;
86
+ }
87
+
88
+ .pw-shell__completion-message {
89
+ font-size: 18px;
90
+ font-weight: 600;
91
+ color: var(--pw-color-text);
92
+ margin: 0 0 20px;
93
+ }
94
+
95
+ .pw-shell__completion-restart {
96
+ border: 1px solid var(--pw-color-btn-border);
97
+ background: var(--pw-color-btn-bg);
98
+ color: var(--pw-color-text);
99
+ padding: var(--pw-btn-padding);
100
+ border-radius: var(--pw-btn-radius);
101
+ cursor: pointer;
102
+ font-size: 14px;
103
+ }
104
+
80
105
  /* ------------------------------------------------------------------ */
81
106
  /* Root progress — persistent top-level bar visible during sub-paths */
82
107
  /* ------------------------------------------------------------------ */
@@ -332,6 +357,23 @@
332
357
  content: ":";
333
358
  }
334
359
 
360
+ /* ------------------------------------------------------------------ */
361
+ /* Inline field-level errors and warnings (<FieldError /> component) */
362
+ /* ------------------------------------------------------------------ */
363
+ .pw-field-error {
364
+ display: block;
365
+ font-size: 12px;
366
+ color: var(--pw-color-error);
367
+ margin-top: 4px;
368
+ }
369
+
370
+ .pw-field-warning {
371
+ display: block;
372
+ font-size: 12px;
373
+ color: var(--pw-color-warning);
374
+ margin-top: 4px;
375
+ }
376
+
335
377
  /* ------------------------------------------------------------------ */
336
378
  /* Footer — navigation buttons */
337
379
  /* ------------------------------------------------------------------ */
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { PathData, PathDefinition, PathEngine, PathEvent, PathSnapshot, Progress
3
3
  export interface UsePathOptions {
4
4
  /**
5
5
  * An externally-managed `PathEngine` to subscribe to — for example, the engine
6
- * returned by `createPersistedEngine()` from `@daltonr/pathwrite-store`.
6
+ * returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
7
7
  *
8
8
  * When provided:
9
9
  * - `usePath` will **not** create its own engine.
@@ -11,7 +11,13 @@ export interface UsePathOptions {
11
11
  * - The engine lifecycle (start / cleanup) is the **caller's responsibility**.
12
12
  * - `PathShell` will skip its own `autoStart` call.
13
13
  */
14
- engine?: PathEngine;
14
+ /**
15
+ * An externally managed engine — a plain engine or an accessor. With an
16
+ * accessor the hook tracks it, so an engine that arrives later (e.g. from an
17
+ * async `restoreOrStart()`) or is swapped is adopted — the hook
18
+ * re-subscribes and re-seeds its snapshot from the new engine.
19
+ */
20
+ engine?: PathEngine | Accessor<PathEngine | undefined>;
15
21
  /** Called for every engine event (stateChanged, completed, cancelled, resumed). */
16
22
  onEvent?: (event: PathEvent) => void;
17
23
  }
@@ -31,17 +37,22 @@ export interface UsePathReturn<TData extends PathData = PathData> {
31
37
  previous: () => Promise<void>;
32
38
  /** Cancel the active path (or sub-path). */
33
39
  cancel: () => Promise<void>;
34
- /** Jump directly to a step by ID. Calls onLeave / onEnter but bypasses guards and shouldSkip. */
35
- goToStep: (stepId: string) => Promise<void>;
40
+ /** Jump directly to a step by ID. Calls onLeave / onEnter but bypasses guards and shouldSkip. Pass `{ validateOnLeave: true }` to mark the departing step as attempted before navigating. */
41
+ goToStep: (stepId: string, options?: {
42
+ validateOnLeave?: boolean;
43
+ }) => Promise<void>;
36
44
  /** Jump directly to a step by ID, checking the current step's canMoveNext (forward) or canMovePrevious (backward) guard first. Navigation is blocked if the guard returns false. */
37
- goToStepChecked: (stepId: string) => Promise<void>;
45
+ goToStepChecked: (stepId: string, options?: {
46
+ validateOnLeave?: boolean;
47
+ }) => Promise<void>;
38
48
  /** Update a single data value; triggers re-renders via stateChanged. When `TData` is specified, `key` and `value` are type-checked against your data shape. */
39
49
  setData: <K extends string & keyof TData>(key: K, value: TData[K]) => Promise<void>;
40
50
  /** Reset the current step's data to what it was when the step was entered. Useful for "Clear" or "Reset" buttons. */
41
51
  resetStep: () => Promise<void>;
42
52
  /**
43
- * Tear down any active path (without firing hooks) and immediately start the
44
- * given path fresh. Safe to call whether or not a path is currently active.
53
+ * Tear down any active path (without firing hooks) and immediately restart
54
+ * the root path with the `initialData` from the original `start()` call.
55
+ * Takes no arguments; rejects if the engine has never been started.
45
56
  * Use for "Start over" / retry flows without remounting the component.
46
57
  */
47
58
  restart: () => Promise<void>;
@@ -69,8 +80,12 @@ export interface PathShellActions {
69
80
  next: () => Promise<void>;
70
81
  previous: () => Promise<void>;
71
82
  cancel: () => Promise<void>;
72
- goToStep: (stepId: string) => Promise<void>;
73
- goToStepChecked: (stepId: string) => Promise<void>;
83
+ goToStep: (stepId: string, options?: {
84
+ validateOnLeave?: boolean;
85
+ }) => Promise<void>;
86
+ goToStepChecked: (stepId: string, options?: {
87
+ validateOnLeave?: boolean;
88
+ }) => Promise<void>;
74
89
  setData: (key: string, value: unknown) => Promise<void>;
75
90
  restart: () => Promise<void>;
76
91
  retry: () => Promise<void>;
@@ -80,24 +95,38 @@ export interface PathShellProps {
80
95
  path: PathDefinition<any>;
81
96
  /**
82
97
  * An externally-managed engine — for example, the engine returned by
83
- * `createPersistedEngine()`. When supplied, `PathShell` will skip its own
98
+ * `restoreOrStart()` from `@daltonr/pathwrite-store`. When supplied, `PathShell` will skip its own
84
99
  * `start()` call and drive the UI from the provided engine instead.
85
100
  */
86
101
  engine?: PathEngine;
87
102
  initialData?: PathData;
103
+ /**
104
+ * When set, this shell automatically saves its state into the nearest outer `PathShell`'s
105
+ * data under this key on every change, and restores from that stored state on remount.
106
+ * No-op when used on a top-level shell with no outer `PathShell` ancestor.
107
+ */
108
+ restoreKey?: string;
88
109
  autoStart?: boolean;
89
110
  /**
90
111
  * Step render functions keyed by step ID (or `formId` for StepChoice steps).
91
112
  * ```tsx
92
113
  * <PathShell steps={{ details: (snap) => <DetailsStep snapshot={snap} />, review: (snap) => <ReviewStep snapshot={snap} /> }} />
93
114
  * ```
115
+ * Each function is called once when its step becomes current, and the
116
+ * component it returns lives until the path moves to a different step —
117
+ * engine events that leave the step unchanged (`setData`, `validate`,
118
+ * guard / hook status changes) do not re-create it, so inputs keep their
119
+ * DOM node, focus and local state. The `snapshot` argument is live: its
120
+ * properties read the current snapshot reactively, so
121
+ * `createMemo(() => props.snapshot.data)` stays up to date. Reading
122
+ * `usePathContext().snapshot()` inside the step works the same way.
94
123
  */
95
- steps?: Record<string, (snapshot: PathSnapshot) => JSX.Element>;
124
+ steps?: Record<string, (snapshot: PathSnapshot) => ReturnType<Component>>;
96
125
  onComplete?: (data: PathData) => void;
97
126
  onCancel?: (data: PathData) => void;
98
127
  onEvent?: (event: PathEvent) => void;
99
- renderHeader?: (snapshot: PathSnapshot) => JSX.Element;
100
- renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) => JSX.Element;
128
+ renderHeader?: (snapshot: PathSnapshot) => ReturnType<Component>;
129
+ renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) => ReturnType<Component>;
101
130
  backLabel?: string;
102
131
  nextLabel?: string;
103
132
  completeLabel?: string;
@@ -108,12 +137,13 @@ export interface PathShellProps {
108
137
  /** If true, hide the footer (navigation buttons). The error panel is still shown on async failure regardless of this prop. */
109
138
  hideFooter?: boolean;
110
139
  /**
111
- * Footer layout mode:
140
+ * Shell layout mode:
112
141
  * - `"auto"` (default): Uses "form" for single-step top-level paths, "wizard" otherwise.
113
- * - `"wizard"`: Back button on left, Cancel and Submit together on right.
114
- * - `"form"`: Cancel on left, Submit alone on right. Back button never shown.
142
+ * - `"wizard"`: Progress header + Back button on left, Cancel and Submit together on right.
143
+ * - `"form"`: Progress header + Cancel on left, Submit alone on right. Back button never shown.
144
+ * - `"tabs"`: No progress header, no footer. Use for tabbed interfaces with a custom tab bar inside the step body.
115
145
  */
116
- footerLayout?: "wizard" | "form" | "auto";
146
+ layout?: "wizard" | "form" | "auto" | "tabs";
117
147
  /**
118
148
  * Controls whether the shell renders its auto-generated field-error summary box.
119
149
  * - `"summary"` (default): Shell renders the labeled error list below the step body.
@@ -137,6 +167,12 @@ export interface PathShellProps {
137
167
  /** When true, calls `validate()` on the engine so all steps show inline errors simultaneously. Useful when this shell is nested inside a step of an outer shell: bind to the outer snapshot's `hasAttemptedNext`. */
138
168
  validateWhen?: boolean;
139
169
  class?: string;
170
+ /**
171
+ * Content rendered when `snapshot.status === "completed"` (i.e. after the path
172
+ * finishes with `completionBehaviour: "stayOnFinal"`). Defaults to a simple
173
+ * "All done." panel with a Restart button.
174
+ */
175
+ completionContent?: (snapshot: PathSnapshot) => JSX.Element;
140
176
  }
141
177
  export declare const PathShell: Component<PathShellProps>;
142
178
  export type { PathData, FieldErrors, PathDefinition, PathEvent, PathSnapshot, PathStep, PathStepContext, ProgressLayout, RootProgress, SerializedPathState, } from "@daltonr/pathwrite-core";
package/dist/index.js CHANGED
@@ -1,31 +1,46 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "solid-js/jsx-runtime";
2
- import { createSignal, onCleanup, onMount, createContext, useContext, createEffect, For, Show, } from "solid-js";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "solid-js/jsx-runtime";
2
+ import { createSignal, createMemo, untrack, onCleanup, onMount, createContext, useContext, createEffect, on, For, Show, } from "solid-js";
3
3
  import { PathEngine, formatFieldKey, errorPhaseMessage, } from "@daltonr/pathwrite-core";
4
4
  // ---------------------------------------------------------------------------
5
5
  // usePath composable
6
6
  // ---------------------------------------------------------------------------
7
7
  export function usePath(options) {
8
- const engine = options?.engine ?? new PathEngine();
8
+ let ownEngine = null;
9
+ const resolveEngine = () => {
10
+ const external = typeof options?.engine === "function" ? options.engine() : options?.engine;
11
+ return external ?? (ownEngine ??= new PathEngine());
12
+ };
13
+ let engine = resolveEngine();
9
14
  const [snapshot, setSnapshot] = createSignal(engine.snapshot(),
10
15
  // always notify — PathEngine produces new snapshot objects on every event
11
16
  { equals: false });
12
- const unsubscribe = engine.subscribe((event) => {
17
+ const onEngineEvent = (event) => {
13
18
  if (event.type === "stateChanged" || event.type === "resumed") {
14
19
  setSnapshot(event.snapshot);
15
20
  }
16
21
  else if (event.type === "completed" || event.type === "cancelled") {
17
- setSnapshot(null);
22
+ setSnapshot(engine.snapshot());
18
23
  }
19
24
  options?.onEvent?.(event);
20
- });
21
- onCleanup(unsubscribe);
25
+ };
26
+ let unsubscribe = engine.subscribe(onEngineEvent);
27
+ // Adopt a late or swapped engine: re-subscribe and re-seed the snapshot.
28
+ createEffect(on(resolveEngine, (next) => {
29
+ if (next === engine)
30
+ return;
31
+ unsubscribe();
32
+ engine = next;
33
+ setSnapshot(engine.snapshot());
34
+ unsubscribe = engine.subscribe(onEngineEvent);
35
+ }, { defer: true }));
36
+ onCleanup(() => unsubscribe());
22
37
  const start = (path, initialData = {}) => engine.start(path, initialData);
23
38
  const startSubPath = (path, initialData = {}, meta) => engine.startSubPath(path, initialData, meta);
24
39
  const next = () => engine.next();
25
40
  const previous = () => engine.previous();
26
41
  const cancel = () => engine.cancel();
27
- const goToStep = (stepId) => engine.goToStep(stepId);
28
- const goToStepChecked = (stepId) => engine.goToStepChecked(stepId);
42
+ const goToStep = (stepId, options) => engine.goToStep(stepId, options);
43
+ const goToStepChecked = (stepId, options) => engine.goToStepChecked(stepId, options);
29
44
  const setData = ((key, value) => engine.setData(key, value));
30
45
  const resetStep = () => engine.resetStep();
31
46
  const restart = () => engine.restart();
@@ -54,20 +69,58 @@ export function usePathContext() {
54
69
  };
55
70
  }
56
71
  export const PathShell = (props) => {
72
+ // Read outer PathShell context BEFORE providing our own.
73
+ const outerCtx = useContext(PathContext);
74
+ // When remounting under restoreKey, rebuild the inner engine from the state the
75
+ // previous instance exported, instead of starting the path and jumping to the
76
+ // step (which re-ran onEnter/onLeave and lost attempted / visited state).
77
+ const restoredEngine = (() => {
78
+ if (props.engine || !props.restoreKey || !outerCtx)
79
+ return null;
80
+ const stored = outerCtx.path.snapshot()?.data[props.restoreKey];
81
+ if (!stored || typeof stored !== "object" || !stored.serializedState)
82
+ return null;
83
+ try {
84
+ return PathEngine.fromState(stored.serializedState, { [props.path.id]: props.path });
85
+ }
86
+ catch {
87
+ return null; // unusable state (e.g. the path definition changed): start fresh below
88
+ }
89
+ })();
90
+ // The shell's own engine is created once; an `engine` prop — present at
91
+ // mount or arriving later — always takes precedence and is adopted by usePath.
92
+ const ownEngine = restoredEngine ?? new PathEngine();
93
+ const currentEngine = () => props.engine ?? ownEngine;
57
94
  const pathReturn = usePath({
58
- engine: props.engine,
95
+ engine: currentEngine,
59
96
  onEvent(event) {
60
97
  props.onEvent?.(event);
61
98
  if (event.type === "completed")
62
99
  props.onComplete?.(event.data);
63
100
  if (event.type === "cancelled")
64
101
  props.onCancel?.(event.data);
102
+ if (props.restoreKey && outerCtx && event.type === "stateChanged") {
103
+ outerCtx.path.setData(props.restoreKey, { ...event.snapshot, serializedState: currentEngine().exportState() });
104
+ }
65
105
  },
66
106
  });
67
107
  const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart, retry, suspend, validate } = pathReturn;
68
108
  onMount(() => {
69
- if (props.autoStart !== false && !props.engine) {
70
- start(props.path, props.initialData ?? {});
109
+ if (props.autoStart !== false && !props.engine && !restoredEngine) {
110
+ let startData = props.initialData ?? {};
111
+ let restoreStepId;
112
+ if (props.restoreKey && outerCtx) {
113
+ const stored = outerCtx.path.snapshot()?.data[props.restoreKey];
114
+ if (stored != null && typeof stored === "object" && "stepId" in stored) {
115
+ startData = stored.data;
116
+ if (stored.stepIndex > 0)
117
+ restoreStepId = stored.stepId;
118
+ }
119
+ }
120
+ const p = start(props.path, startData);
121
+ if (restoreStepId) {
122
+ p.then(() => goToStep(restoreStepId));
123
+ }
71
124
  }
72
125
  });
73
126
  createEffect(() => {
@@ -90,13 +143,60 @@ export const PathShell = (props) => {
90
143
  const mod = layout && layout !== "merged" ? ` pw-shell--progress-${layout}` : "";
91
144
  return props.class ? `${base}${mod} ${props.class}` : `${base}${mod}`;
92
145
  };
93
- const showRoot = () => !props.hideProgress && !!snap().rootProgress && props.progressLayout !== "activeOnly";
94
- const showActive = () => !props.hideProgress && (snap().stepCount > 1 || snap().nestingLevel > 0) && props.progressLayout !== "rootOnly";
95
- const stepContent = () => {
96
- const s = snap();
97
- const key = s.formId ?? s.stepId;
98
- const render = props.steps?.[key];
99
- return render ? render(s) : null;
146
+ const effectiveHideProgress = () => props.hideProgress || props.layout === "tabs";
147
+ const effectiveHideFooter = () => props.hideFooter || props.layout === "tabs";
148
+ const showRoot = () => !effectiveHideProgress() && !!snap().rootProgress && props.progressLayout !== "activeOnly";
149
+ // A custom header is the consumer's decision: show it whenever progress is
150
+ // not hidden, even for a single-step path. Only the *default* header hides
151
+ // for one step (same rule as the React / Vue shells).
152
+ const showActive = () => !effectiveHideProgress() && (props.renderHeader
153
+ ? true
154
+ : (snap().stepCount > 1 || snap().nestingLevel > 0) && props.progressLayout !== "rootOnly");
155
+ // The step render function must only run when the *step* changes. The
156
+ // snapshot signal is `{ equals: false }` (a new object on every engine
157
+ // event), so reading it in a tracked render position would tear the step
158
+ // component down and re-create it on every setData — losing the input's
159
+ // DOM node and focus on each keystroke. Key the rendered content on the
160
+ // step's identity and create it untracked; live state reaches the step
161
+ // through the reactive snapshot proxy below or `usePathContext()`.
162
+ // Which key of `props.steps` renders the current step: the StepChoice's
163
+ // inner step id (`formId`) when content is registered under it, otherwise
164
+ // the slot's own id — the same fallback the React / Vue / Svelte shells use.
165
+ const stepLookupKey = createMemo(() => {
166
+ const s = snapshot();
167
+ if (!s)
168
+ return null;
169
+ if (s.formId && props.steps?.[s.formId])
170
+ return s.formId;
171
+ return s.stepId;
172
+ });
173
+ const stepIdentity = createMemo(() => {
174
+ const s = snapshot();
175
+ return s ? `${s.nestingLevel}:${s.pathId}:${s.formId ?? s.stepId}` : null;
176
+ });
177
+ // A snapshot whose property reads go through the signal, so a step that
178
+ // received it as a prop (`(snap) => <Step snapshot={snap} />`) sees the
179
+ // current values reactively even though the step itself is created once.
180
+ const liveSnapshot = new Proxy({}, {
181
+ get: (_target, key) => snapshot()?.[key],
182
+ has: (_target, key) => { const s = snapshot(); return s ? key in s : false; },
183
+ ownKeys: () => { const s = snapshot(); return s ? Reflect.ownKeys(s) : []; },
184
+ getOwnPropertyDescriptor: (_target, key) => {
185
+ const s = snapshot();
186
+ const d = s ? Object.getOwnPropertyDescriptor(s, key) : undefined;
187
+ return d ? { ...d, configurable: true } : undefined;
188
+ },
189
+ });
190
+ // Rendered inside <PathContext.Provider>, so the memo (and the step it
191
+ // creates) is owned by the provider and `usePathContext()` resolves.
192
+ const StepContent = () => {
193
+ const content = createMemo(() => {
194
+ if (stepIdentity() === null)
195
+ return null;
196
+ const render = props.steps?.[untrack(stepLookupKey)];
197
+ return render ? untrack(() => render(liveSnapshot)) : null;
198
+ });
199
+ return _jsx(_Fragment, { children: content() });
100
200
  };
101
201
  const showValidation = () => props.validationDisplay !== "inline" &&
102
202
  (snap().hasAttemptedNext || snap().hasValidated) &&
@@ -107,16 +207,18 @@ export const PathShell = (props) => {
107
207
  (snap().hasAttemptedNext || snap().hasValidated) &&
108
208
  !!snap().blockingError;
109
209
  const resolvedFooterLayout = () => {
110
- const fl = props.footerLayout ?? "auto";
111
- if (fl !== "auto")
210
+ const fl = props.layout ?? "auto";
211
+ if (fl !== "auto" && fl !== "tabs")
112
212
  return fl;
113
213
  return snap().stepCount === 1 && snap().nestingLevel === 0 ? "form" : "wizard";
114
214
  };
115
215
  return (_jsx(PathContext.Provider, { value: contextValue, children: _jsx(Show, { when: snapshot(), fallback: _jsx("div", { class: "pw-shell", children: _jsxs("div", { class: "pw-shell__empty", children: [_jsx("p", { children: "No active path." }), _jsx(Show, { when: props.autoStart === false, children: _jsx("button", { type: "button", class: "pw-shell__start-btn", onClick: () => start(props.path, props.initialData ?? {}), children: "Start" }) })] }) }), children: _jsxs("div", { class: shellClass(), children: [_jsx(Show, { when: showRoot(), children: _jsx(SolidRootProgress, { root: snap().rootProgress }) }), _jsx(Show, { when: showActive(), children: props.renderHeader
116
216
  ? props.renderHeader(snap())
117
- : _jsx(SolidHeader, { snapshot: snap() }) }), _jsx("div", { class: "pw-shell__body", children: stepContent() }), _jsx(Show, { when: showValidation(), children: _jsx("ul", { class: "pw-shell__validation", children: _jsx(For, { each: Object.entries(snap().fieldErrors), children: ([key, msg]) => (_jsxs("li", { class: "pw-shell__validation-item", children: [_jsx(Show, { when: key !== "_", children: _jsx("span", { class: "pw-shell__validation-label", children: formatFieldKey(key) }) }), msg] })) }) }) }), _jsx(Show, { when: showWarnings(), children: _jsx("ul", { class: "pw-shell__warnings", children: _jsx(For, { each: Object.entries(snap().fieldWarnings), children: ([key, msg]) => (_jsxs("li", { class: "pw-shell__warnings-item", children: [_jsx(Show, { when: key !== "_", children: _jsx("span", { class: "pw-shell__warnings-label", children: formatFieldKey(key) }) }), msg] })) }) }) }), _jsx(Show, { when: showBlockingError(), children: _jsx("p", { class: "pw-shell__blocking-error", children: snap().blockingError }) }), _jsx(Show, { when: snap().status === "error" && snap().error, fallback: _jsx(Show, { when: !props.hideFooter, children: props.renderFooter
118
- ? props.renderFooter(snap(), actions)
119
- : _jsx(SolidFooter, { snapshot: snap(), actions: actions, backLabel: props.backLabel ?? "Previous", nextLabel: props.nextLabel ?? "Next", completeLabel: props.completeLabel ?? "Complete", loadingLabel: props.loadingLabel, cancelLabel: props.cancelLabel ?? "Cancel", hideCancel: props.hideCancel ?? false, footerLayout: resolvedFooterLayout() }) }), children: _jsx(SolidErrorPanel, { snapshot: snap(), actions: actions }) })] }) }) }));
217
+ : _jsx(SolidHeader, { snapshot: snap() }) }), _jsx(Show, { when: snap().status === "completed", children: _jsx("div", { class: "pw-shell__body", children: props.completionContent
218
+ ? props.completionContent(snap())
219
+ : (_jsxs("div", { class: "pw-shell__completion", children: [_jsx("p", { class: "pw-shell__completion-message", children: "All done." }), _jsx("button", { type: "button", class: "pw-shell__completion-restart", onClick: () => restart(), children: "Start over" })] })) }) }), _jsxs(Show, { when: snap().status !== "completed", children: [_jsx("div", { class: "pw-shell__body", children: _jsx(StepContent, {}) }), _jsx(Show, { when: showValidation(), children: _jsx("ul", { class: "pw-shell__validation", children: _jsx(For, { each: Object.entries(snap().fieldErrors), children: ([key, msg]) => (_jsxs("li", { class: "pw-shell__validation-item", children: [_jsx(Show, { when: key !== "_", children: _jsx("span", { class: "pw-shell__validation-label", children: formatFieldKey(key) }) }), msg] })) }) }) }), _jsx(Show, { when: showWarnings(), children: _jsx("ul", { class: "pw-shell__warnings", children: _jsx(For, { each: Object.entries(snap().fieldWarnings), children: ([key, msg]) => (_jsxs("li", { class: "pw-shell__warnings-item", children: [_jsx(Show, { when: key !== "_", children: _jsx("span", { class: "pw-shell__warnings-label", children: formatFieldKey(key) }) }), msg] })) }) }) }), _jsx(Show, { when: showBlockingError(), children: _jsx("p", { class: "pw-shell__blocking-error", children: snap().blockingError }) }), _jsx(Show, { when: snap().status === "error" && snap().error, fallback: _jsx(Show, { when: !effectiveHideFooter(), children: props.renderFooter
220
+ ? props.renderFooter(snap(), actions)
221
+ : _jsx(SolidFooter, { snapshot: snap(), actions: actions, backLabel: props.backLabel ?? "Previous", nextLabel: props.nextLabel ?? "Next", completeLabel: props.completeLabel ?? "Complete", loadingLabel: props.loadingLabel, cancelLabel: props.cancelLabel ?? "Cancel", hideCancel: props.hideCancel ?? false, layout: resolvedFooterLayout() }) }), children: _jsx(SolidErrorPanel, { snapshot: snap(), actions: actions }) })] })] }) }) }));
120
222
  };
121
223
  // ---------------------------------------------------------------------------
122
224
  // Root progress
@@ -144,7 +246,7 @@ function SolidErrorPanel(props) {
144
246
  // Default footer (navigation buttons)
145
247
  // ---------------------------------------------------------------------------
146
248
  function SolidFooter(props) {
147
- const isFormMode = () => props.footerLayout === "form";
249
+ const isFormMode = () => props.layout === "form";
148
250
  const isLoading = () => props.snapshot.status !== "idle";
149
251
  const submitLabel = () => isLoading() && props.loadingLabel
150
252
  ? props.loadingLabel
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daltonr/pathwrite-solid",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "SolidJS adapter for @daltonr/pathwrite-core — reactive usePath() composable and optional PathShell component.",
@@ -47,7 +47,7 @@
47
47
  "solid-js": ">=1.8.0"
48
48
  },
49
49
  "dependencies": {
50
- "@daltonr/pathwrite-core": "^0.11.0"
50
+ "@daltonr/pathwrite-core": "^0.13.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "solid-js": "^1.9.0"
package/src/index.tsx CHANGED
@@ -1,10 +1,13 @@
1
1
  import {
2
2
  createSignal,
3
+ createMemo,
4
+ untrack,
3
5
  onCleanup,
4
6
  onMount,
5
7
  createContext,
6
8
  useContext,
7
9
  createEffect,
10
+ on,
8
11
  For,
9
12
  Show,
10
13
  type Component,
@@ -17,6 +20,7 @@ import {
17
20
  PathEngine,
18
21
  PathEvent,
19
22
  PathSnapshot,
23
+ SerializedPathState,
20
24
  ProgressLayout,
21
25
  RootProgress,
22
26
  formatFieldKey,
@@ -30,7 +34,7 @@ import {
30
34
  export interface UsePathOptions {
31
35
  /**
32
36
  * An externally-managed `PathEngine` to subscribe to — for example, the engine
33
- * returned by `createPersistedEngine()` from `@daltonr/pathwrite-store`.
37
+ * returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
34
38
  *
35
39
  * When provided:
36
40
  * - `usePath` will **not** create its own engine.
@@ -38,7 +42,13 @@ export interface UsePathOptions {
38
42
  * - The engine lifecycle (start / cleanup) is the **caller's responsibility**.
39
43
  * - `PathShell` will skip its own `autoStart` call.
40
44
  */
41
- engine?: PathEngine;
45
+ /**
46
+ * An externally managed engine — a plain engine or an accessor. With an
47
+ * accessor the hook tracks it, so an engine that arrives later (e.g. from an
48
+ * async `restoreOrStart()`) or is swapped is adopted — the hook
49
+ * re-subscribes and re-seeds its snapshot from the new engine.
50
+ */
51
+ engine?: PathEngine | Accessor<PathEngine | undefined>;
42
52
  /** Called for every engine event (stateChanged, completed, cancelled, resumed). */
43
53
  onEvent?: (event: PathEvent) => void;
44
54
  }
@@ -59,17 +69,18 @@ export interface UsePathReturn<TData extends PathData = PathData> {
59
69
  previous: () => Promise<void>;
60
70
  /** Cancel the active path (or sub-path). */
61
71
  cancel: () => Promise<void>;
62
- /** Jump directly to a step by ID. Calls onLeave / onEnter but bypasses guards and shouldSkip. */
63
- goToStep: (stepId: string) => Promise<void>;
72
+ /** Jump directly to a step by ID. Calls onLeave / onEnter but bypasses guards and shouldSkip. Pass `{ validateOnLeave: true }` to mark the departing step as attempted before navigating. */
73
+ goToStep: (stepId: string, options?: { validateOnLeave?: boolean }) => Promise<void>;
64
74
  /** Jump directly to a step by ID, checking the current step's canMoveNext (forward) or canMovePrevious (backward) guard first. Navigation is blocked if the guard returns false. */
65
- goToStepChecked: (stepId: string) => Promise<void>;
75
+ goToStepChecked: (stepId: string, options?: { validateOnLeave?: boolean }) => Promise<void>;
66
76
  /** Update a single data value; triggers re-renders via stateChanged. When `TData` is specified, `key` and `value` are type-checked against your data shape. */
67
77
  setData: <K extends string & keyof TData>(key: K, value: TData[K]) => Promise<void>;
68
78
  /** Reset the current step's data to what it was when the step was entered. Useful for "Clear" or "Reset" buttons. */
69
79
  resetStep: () => Promise<void>;
70
80
  /**
71
- * Tear down any active path (without firing hooks) and immediately start the
72
- * given path fresh. Safe to call whether or not a path is currently active.
81
+ * Tear down any active path (without firing hooks) and immediately restart
82
+ * the root path with the `initialData` from the original `start()` call.
83
+ * Takes no arguments; rejects if the engine has never been started.
73
84
  * Use for "Start over" / retry flows without remounting the component.
74
85
  */
75
86
  restart: () => Promise<void>;
@@ -86,7 +97,12 @@ export interface UsePathReturn<TData extends PathData = PathData> {
86
97
  // ---------------------------------------------------------------------------
87
98
 
88
99
  export function usePath<TData extends PathData = PathData>(options?: UsePathOptions): UsePathReturn<TData> {
89
- const engine = options?.engine ?? new PathEngine();
100
+ let ownEngine: PathEngine | null = null;
101
+ const resolveEngine = (): PathEngine => {
102
+ const external = typeof options?.engine === "function" ? options.engine() : options?.engine;
103
+ return external ?? (ownEngine ??= new PathEngine());
104
+ };
105
+ let engine = resolveEngine();
90
106
 
91
107
  const [snapshot, setSnapshot] = createSignal<PathSnapshot<TData> | null>(
92
108
  engine.snapshot() as PathSnapshot<TData> | null,
@@ -94,16 +110,26 @@ export function usePath<TData extends PathData = PathData>(options?: UsePathOpti
94
110
  { equals: false }
95
111
  );
96
112
 
97
- const unsubscribe = engine.subscribe((event: PathEvent) => {
113
+ const onEngineEvent = (event: PathEvent): void => {
98
114
  if (event.type === "stateChanged" || event.type === "resumed") {
99
115
  setSnapshot(event.snapshot as PathSnapshot<TData>);
100
116
  } else if (event.type === "completed" || event.type === "cancelled") {
101
- setSnapshot(null);
117
+ setSnapshot(engine.snapshot() as PathSnapshot<TData> | null);
102
118
  }
103
119
  options?.onEvent?.(event);
104
- });
120
+ };
121
+ let unsubscribe = engine.subscribe(onEngineEvent);
122
+
123
+ // Adopt a late or swapped engine: re-subscribe and re-seed the snapshot.
124
+ createEffect(on(resolveEngine, (next) => {
125
+ if (next === engine) return;
126
+ unsubscribe();
127
+ engine = next;
128
+ setSnapshot(engine.snapshot() as PathSnapshot<TData> | null);
129
+ unsubscribe = engine.subscribe(onEngineEvent);
130
+ }, { defer: true }));
105
131
 
106
- onCleanup(unsubscribe);
132
+ onCleanup(() => unsubscribe());
107
133
 
108
134
  const start = (path: PathDefinition<any>, initialData: PathData = {}): Promise<void> =>
109
135
  engine.start(path, initialData);
@@ -114,8 +140,8 @@ export function usePath<TData extends PathData = PathData>(options?: UsePathOpti
114
140
  const next = (): Promise<void> => engine.next();
115
141
  const previous = (): Promise<void> => engine.previous();
116
142
  const cancel = (): Promise<void> => engine.cancel();
117
- const goToStep = (stepId: string): Promise<void> => engine.goToStep(stepId);
118
- const goToStepChecked = (stepId: string): Promise<void> => engine.goToStepChecked(stepId);
143
+ const goToStep = (stepId: string, options?: { validateOnLeave?: boolean }): Promise<void> => engine.goToStep(stepId, options);
144
+ const goToStepChecked = (stepId: string, options?: { validateOnLeave?: boolean }): Promise<void> => engine.goToStepChecked(stepId, options);
119
145
 
120
146
  const setData = (<K extends string & keyof TData>(key: K, value: TData[K]): Promise<void> =>
121
147
  engine.setData(key, value as unknown)) as UsePathReturn<TData>["setData"];
@@ -167,8 +193,8 @@ export interface PathShellActions {
167
193
  next: () => Promise<void>;
168
194
  previous: () => Promise<void>;
169
195
  cancel: () => Promise<void>;
170
- goToStep: (stepId: string) => Promise<void>;
171
- goToStepChecked: (stepId: string) => Promise<void>;
196
+ goToStep: (stepId: string, options?: { validateOnLeave?: boolean }) => Promise<void>;
197
+ goToStepChecked: (stepId: string, options?: { validateOnLeave?: boolean }) => Promise<void>;
172
198
  setData: (key: string, value: unknown) => Promise<void>;
173
199
  restart: () => Promise<void>;
174
200
  retry: () => Promise<void>;
@@ -179,24 +205,38 @@ export interface PathShellProps {
179
205
  path: PathDefinition<any>;
180
206
  /**
181
207
  * An externally-managed engine — for example, the engine returned by
182
- * `createPersistedEngine()`. When supplied, `PathShell` will skip its own
208
+ * `restoreOrStart()` from `@daltonr/pathwrite-store`. When supplied, `PathShell` will skip its own
183
209
  * `start()` call and drive the UI from the provided engine instead.
184
210
  */
185
211
  engine?: PathEngine;
186
212
  initialData?: PathData;
213
+ /**
214
+ * When set, this shell automatically saves its state into the nearest outer `PathShell`'s
215
+ * data under this key on every change, and restores from that stored state on remount.
216
+ * No-op when used on a top-level shell with no outer `PathShell` ancestor.
217
+ */
218
+ restoreKey?: string;
187
219
  autoStart?: boolean;
188
220
  /**
189
221
  * Step render functions keyed by step ID (or `formId` for StepChoice steps).
190
222
  * ```tsx
191
223
  * <PathShell steps={{ details: (snap) => <DetailsStep snapshot={snap} />, review: (snap) => <ReviewStep snapshot={snap} /> }} />
192
224
  * ```
225
+ * Each function is called once when its step becomes current, and the
226
+ * component it returns lives until the path moves to a different step —
227
+ * engine events that leave the step unchanged (`setData`, `validate`,
228
+ * guard / hook status changes) do not re-create it, so inputs keep their
229
+ * DOM node, focus and local state. The `snapshot` argument is live: its
230
+ * properties read the current snapshot reactively, so
231
+ * `createMemo(() => props.snapshot.data)` stays up to date. Reading
232
+ * `usePathContext().snapshot()` inside the step works the same way.
193
233
  */
194
- steps?: Record<string, (snapshot: PathSnapshot) => JSX.Element>;
234
+ steps?: Record<string, (snapshot: PathSnapshot) => ReturnType<Component>>;
195
235
  onComplete?: (data: PathData) => void;
196
236
  onCancel?: (data: PathData) => void;
197
237
  onEvent?: (event: PathEvent) => void;
198
- renderHeader?: (snapshot: PathSnapshot) => JSX.Element;
199
- renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) => JSX.Element;
238
+ renderHeader?: (snapshot: PathSnapshot) => ReturnType<Component>;
239
+ renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) => ReturnType<Component>;
200
240
  backLabel?: string;
201
241
  nextLabel?: string;
202
242
  completeLabel?: string;
@@ -207,12 +247,13 @@ export interface PathShellProps {
207
247
  /** If true, hide the footer (navigation buttons). The error panel is still shown on async failure regardless of this prop. */
208
248
  hideFooter?: boolean;
209
249
  /**
210
- * Footer layout mode:
250
+ * Shell layout mode:
211
251
  * - `"auto"` (default): Uses "form" for single-step top-level paths, "wizard" otherwise.
212
- * - `"wizard"`: Back button on left, Cancel and Submit together on right.
213
- * - `"form"`: Cancel on left, Submit alone on right. Back button never shown.
252
+ * - `"wizard"`: Progress header + Back button on left, Cancel and Submit together on right.
253
+ * - `"form"`: Progress header + Cancel on left, Submit alone on right. Back button never shown.
254
+ * - `"tabs"`: No progress header, no footer. Use for tabbed interfaces with a custom tab bar inside the step body.
214
255
  */
215
- footerLayout?: "wizard" | "form" | "auto";
256
+ layout?: "wizard" | "form" | "auto" | "tabs";
216
257
  /**
217
258
  * Controls whether the shell renders its auto-generated field-error summary box.
218
259
  * - `"summary"` (default): Shell renders the labeled error list below the step body.
@@ -236,23 +277,67 @@ export interface PathShellProps {
236
277
  /** When true, calls `validate()` on the engine so all steps show inline errors simultaneously. Useful when this shell is nested inside a step of an outer shell: bind to the outer snapshot's `hasAttemptedNext`. */
237
278
  validateWhen?: boolean;
238
279
  class?: string;
280
+ /**
281
+ * Content rendered when `snapshot.status === "completed"` (i.e. after the path
282
+ * finishes with `completionBehaviour: "stayOnFinal"`). Defaults to a simple
283
+ * "All done." panel with a Restart button.
284
+ */
285
+ completionContent?: (snapshot: PathSnapshot) => JSX.Element;
239
286
  }
240
287
 
241
288
  export const PathShell: Component<PathShellProps> = (props) => {
289
+ // Read outer PathShell context BEFORE providing our own.
290
+ const outerCtx = useContext(PathContext);
291
+
292
+ // When remounting under restoreKey, rebuild the inner engine from the state the
293
+ // previous instance exported, instead of starting the path and jumping to the
294
+ // step (which re-ran onEnter/onLeave and lost attempted / visited state).
295
+ const restoredEngine: PathEngine | null = (() => {
296
+ if (props.engine || !props.restoreKey || !outerCtx) return null;
297
+ const stored = outerCtx.path.snapshot()?.data[props.restoreKey] as { serializedState?: SerializedPathState } | undefined;
298
+ if (!stored || typeof stored !== "object" || !stored.serializedState) return null;
299
+ try {
300
+ return PathEngine.fromState(stored.serializedState, { [props.path.id]: props.path });
301
+ } catch {
302
+ return null; // unusable state (e.g. the path definition changed): start fresh below
303
+ }
304
+ })();
305
+ // The shell's own engine is created once; an `engine` prop — present at
306
+ // mount or arriving later — always takes precedence and is adopted by usePath.
307
+ const ownEngine = restoredEngine ?? new PathEngine();
308
+ const currentEngine = (): PathEngine => props.engine ?? ownEngine;
309
+
242
310
  const pathReturn = usePath({
243
- engine: props.engine,
311
+ engine: currentEngine,
244
312
  onEvent(event) {
245
313
  props.onEvent?.(event);
246
314
  if (event.type === "completed") props.onComplete?.(event.data as PathData);
247
315
  if (event.type === "cancelled") props.onCancel?.(event.data as PathData);
316
+ if (props.restoreKey && outerCtx && event.type === "stateChanged") {
317
+ (outerCtx.path.setData as unknown as (key: string, value: unknown) => void)(
318
+ props.restoreKey, { ...event.snapshot, serializedState: currentEngine().exportState() }
319
+ );
320
+ }
248
321
  },
249
322
  });
250
323
 
251
324
  const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart, retry, suspend, validate } = pathReturn;
252
325
 
253
326
  onMount(() => {
254
- if (props.autoStart !== false && !props.engine) {
255
- start(props.path, props.initialData ?? {});
327
+ if (props.autoStart !== false && !props.engine && !restoredEngine) {
328
+ let startData: PathData = props.initialData ?? {};
329
+ let restoreStepId: string | undefined;
330
+ if (props.restoreKey && outerCtx) {
331
+ const stored = outerCtx.path.snapshot()?.data[props.restoreKey] as PathSnapshot | undefined;
332
+ if (stored != null && typeof stored === "object" && "stepId" in stored) {
333
+ startData = stored.data as PathData;
334
+ if (stored.stepIndex > 0) restoreStepId = stored.stepId as string;
335
+ }
336
+ }
337
+ const p = start(props.path, startData);
338
+ if (restoreStepId) {
339
+ p.then(() => goToStep(restoreStepId!));
340
+ }
256
341
  }
257
342
  });
258
343
 
@@ -280,14 +365,60 @@ export const PathShell: Component<PathShellProps> = (props) => {
280
365
  return props.class ? `${base}${mod} ${props.class}` : `${base}${mod}`;
281
366
  };
282
367
 
283
- const showRoot = () => !props.hideProgress && !!snap().rootProgress && props.progressLayout !== "activeOnly";
284
- const showActive = () => !props.hideProgress && (snap().stepCount > 1 || snap().nestingLevel > 0) && props.progressLayout !== "rootOnly";
368
+ const effectiveHideProgress = () => props.hideProgress || props.layout === "tabs";
369
+ const effectiveHideFooter = () => props.hideFooter || props.layout === "tabs";
370
+ const showRoot = () => !effectiveHideProgress() && !!snap().rootProgress && props.progressLayout !== "activeOnly";
371
+ // A custom header is the consumer's decision: show it whenever progress is
372
+ // not hidden, even for a single-step path. Only the *default* header hides
373
+ // for one step (same rule as the React / Vue shells).
374
+ const showActive = () => !effectiveHideProgress() && (props.renderHeader
375
+ ? true
376
+ : (snap().stepCount > 1 || snap().nestingLevel > 0) && props.progressLayout !== "rootOnly");
377
+
378
+ // The step render function must only run when the *step* changes. The
379
+ // snapshot signal is `{ equals: false }` (a new object on every engine
380
+ // event), so reading it in a tracked render position would tear the step
381
+ // component down and re-create it on every setData — losing the input's
382
+ // DOM node and focus on each keystroke. Key the rendered content on the
383
+ // step's identity and create it untracked; live state reaches the step
384
+ // through the reactive snapshot proxy below or `usePathContext()`.
385
+ // Which key of `props.steps` renders the current step: the StepChoice's
386
+ // inner step id (`formId`) when content is registered under it, otherwise
387
+ // the slot's own id — the same fallback the React / Vue / Svelte shells use.
388
+ const stepLookupKey = createMemo<string | null>(() => {
389
+ const s = snapshot();
390
+ if (!s) return null;
391
+ if (s.formId && props.steps?.[s.formId]) return s.formId;
392
+ return s.stepId;
393
+ });
394
+ const stepIdentity = createMemo<string | null>(() => {
395
+ const s = snapshot();
396
+ return s ? `${s.nestingLevel}:${s.pathId}:${s.formId ?? s.stepId}` : null;
397
+ });
285
398
 
286
- const stepContent = () => {
287
- const s = snap();
288
- const key = s.formId ?? s.stepId;
289
- const render = props.steps?.[key];
290
- return render ? render(s) : null;
399
+ // A snapshot whose property reads go through the signal, so a step that
400
+ // received it as a prop (`(snap) => <Step snapshot={snap} />`) sees the
401
+ // current values reactively even though the step itself is created once.
402
+ const liveSnapshot = new Proxy({} as PathSnapshot, {
403
+ get: (_target, key) => (snapshot() as unknown as Record<PropertyKey, unknown> | null)?.[key],
404
+ has: (_target, key) => { const s = snapshot(); return s ? key in s : false; },
405
+ ownKeys: () => { const s = snapshot(); return s ? Reflect.ownKeys(s) : []; },
406
+ getOwnPropertyDescriptor: (_target, key) => {
407
+ const s = snapshot();
408
+ const d = s ? Object.getOwnPropertyDescriptor(s, key) : undefined;
409
+ return d ? { ...d, configurable: true } : undefined;
410
+ },
411
+ });
412
+
413
+ // Rendered inside <PathContext.Provider>, so the memo (and the step it
414
+ // creates) is owned by the provider and `usePathContext()` resolves.
415
+ const StepContent: Component = () => {
416
+ const content = createMemo(() => {
417
+ if (stepIdentity() === null) return null;
418
+ const render = props.steps?.[untrack(stepLookupKey)!];
419
+ return render ? untrack(() => render(liveSnapshot)) : null;
420
+ });
421
+ return <>{content()}</>;
291
422
  };
292
423
 
293
424
  const showValidation = () =>
@@ -305,8 +436,8 @@ export const PathShell: Component<PathShellProps> = (props) => {
305
436
  !!snap().blockingError;
306
437
 
307
438
  const resolvedFooterLayout = () => {
308
- const fl = props.footerLayout ?? "auto";
309
- if (fl !== "auto") return fl;
439
+ const fl = props.layout ?? "auto";
440
+ if (fl !== "auto" && fl !== "tabs") return fl;
310
441
  return snap().stepCount === 1 && snap().nestingLevel === 0 ? "form" : "wizard";
311
442
  };
312
443
 
@@ -342,8 +473,29 @@ export const PathShell: Component<PathShellProps> = (props) => {
342
473
  ? props.renderHeader(snap())
343
474
  : <SolidHeader snapshot={snap()} />}
344
475
  </Show>
345
- {/* Bodystep content */}
346
- <div class="pw-shell__body">{stepContent()}</div>
476
+ {/* Completion panel shown when path finishes with stayOnFinal */}
477
+ <Show when={snap().status === "completed"}>
478
+ <div class="pw-shell__body">
479
+ {props.completionContent
480
+ ? props.completionContent(snap())
481
+ : (
482
+ <div class="pw-shell__completion">
483
+ <p class="pw-shell__completion-message">All done.</p>
484
+ <button
485
+ type="button"
486
+ class="pw-shell__completion-restart"
487
+ onClick={() => restart()}
488
+ >
489
+ Start over
490
+ </button>
491
+ </div>
492
+ )
493
+ }
494
+ </div>
495
+ </Show>
496
+ {/* Body — step content (hidden when completed) */}
497
+ <Show when={snap().status !== "completed"}>
498
+ <div class="pw-shell__body"><StepContent /></div>
347
499
  {/* Validation messages */}
348
500
  <Show when={showValidation()}>
349
501
  <ul class="pw-shell__validation">
@@ -382,7 +534,7 @@ export const PathShell: Component<PathShellProps> = (props) => {
382
534
  <Show
383
535
  when={snap().status === "error" && snap().error}
384
536
  fallback={
385
- <Show when={!props.hideFooter}>
537
+ <Show when={!effectiveHideFooter()}>
386
538
  {props.renderFooter
387
539
  ? props.renderFooter(snap(), actions)
388
540
  : <SolidFooter
@@ -394,7 +546,7 @@ export const PathShell: Component<PathShellProps> = (props) => {
394
546
  loadingLabel={props.loadingLabel}
395
547
  cancelLabel={props.cancelLabel ?? "Cancel"}
396
548
  hideCancel={props.hideCancel ?? false}
397
- footerLayout={resolvedFooterLayout()}
549
+ layout={resolvedFooterLayout()}
398
550
  />
399
551
  }
400
552
  </Show>
@@ -402,6 +554,7 @@ export const PathShell: Component<PathShellProps> = (props) => {
402
554
  >
403
555
  <SolidErrorPanel snapshot={snap()} actions={actions} />
404
556
  </Show>
557
+ </Show>{/* end status !== completed */}
405
558
  </div>
406
559
  </Show>
407
560
  </PathContext.Provider>
@@ -514,9 +667,9 @@ function SolidFooter(props: {
514
667
  loadingLabel?: string;
515
668
  cancelLabel: string;
516
669
  hideCancel: boolean;
517
- footerLayout: "wizard" | "form";
670
+ layout: "wizard" | "form";
518
671
  }) {
519
- const isFormMode = () => props.footerLayout === "form";
672
+ const isFormMode = () => props.layout === "form";
520
673
  const isLoading = () => props.snapshot.status !== "idle";
521
674
  const submitLabel = () =>
522
675
  isLoading() && props.loadingLabel