@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 +82 -16
- package/dist/index.css +42 -0
- package/dist/index.d.ts +53 -17
- package/dist/index.js +127 -25
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.tsx +195 -42
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 |
|
|
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 |
|
|
96
|
-
| `retry()` | function |
|
|
97
|
-
| `restart()` | function | Tear down the active path without firing hooks and start
|
|
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
|
-
| `
|
|
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
|
-
| `
|
|
131
|
-
| `
|
|
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={
|
|
277
|
+
value={data()?.firstName ?? ""}
|
|
216
278
|
onInput={(e) => setData("firstName", e.currentTarget.value)}
|
|
217
279
|
/>
|
|
218
|
-
<Show when={
|
|
219
|
-
<p class="error">{
|
|
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={
|
|
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={
|
|
244
|
-
<p class="error">{
|
|
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/
|
|
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 `
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
44
|
-
*
|
|
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
|
|
73
|
-
|
|
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
|
-
* `
|
|
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) =>
|
|
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) =>
|
|
100
|
-
renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) =>
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
22
|
+
setSnapshot(engine.snapshot());
|
|
18
23
|
}
|
|
19
24
|
options?.onEvent?.(event);
|
|
20
|
-
}
|
|
21
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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.
|
|
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(
|
|
118
|
-
? props.
|
|
119
|
-
: _jsx(
|
|
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.
|
|
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.
|
|
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.
|
|
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 `
|
|
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
|
-
|
|
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
|
|
72
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
* `
|
|
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) =>
|
|
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) =>
|
|
199
|
-
renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) =>
|
|
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
|
-
*
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
284
|
-
const
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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.
|
|
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
|
-
{/*
|
|
346
|
-
<
|
|
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={!
|
|
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
|
-
|
|
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
|
-
|
|
670
|
+
layout: "wizard" | "form";
|
|
518
671
|
}) {
|
|
519
|
-
const isFormMode = () => props.
|
|
672
|
+
const isFormMode = () => props.layout === "form";
|
|
520
673
|
const isLoading = () => props.snapshot.status !== "idle";
|
|
521
674
|
const submitLabel = () =>
|
|
522
675
|
isLoading() && props.loadingLabel
|