@daltonr/pathwrite-react 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -285,6 +285,16 @@
285
285
  content: ":";
286
286
  }
287
287
 
288
+ /* ------------------------------------------------------------------ */
289
+ /* Blocking error (guard-level message, not field-attached) */
290
+ /* ------------------------------------------------------------------ */
291
+ .pw-shell__blocking-error {
292
+ margin: 0;
293
+ padding: 8px 16px;
294
+ font-size: 13px;
295
+ color: var(--pw-color-error);
296
+ }
297
+
288
298
  /* ------------------------------------------------------------------ */
289
299
  /* Warning messages */
290
300
  /* ------------------------------------------------------------------ */
@@ -361,6 +371,7 @@
361
371
  background: var(--pw-color-primary);
362
372
  border-color: var(--pw-color-primary);
363
373
  color: #fff;
374
+ position: relative;
364
375
  }
365
376
 
366
377
  .pw-shell__btn--next:hover:not(:disabled) {
@@ -368,6 +379,29 @@
368
379
  border-color: #1d4ed8;
369
380
  }
370
381
 
382
+ @keyframes pw-spin {
383
+ to { transform: rotate(360deg); }
384
+ }
385
+
386
+ .pw-shell__btn--next.pw-shell__btn--loading {
387
+ color: transparent;
388
+ pointer-events: none;
389
+ }
390
+
391
+ .pw-shell__btn--next.pw-shell__btn--loading::after {
392
+ content: "";
393
+ position: absolute;
394
+ top: 50%;
395
+ left: 50%;
396
+ width: 14px;
397
+ height: 14px;
398
+ margin: -7px 0 0 -7px;
399
+ border: 2px solid rgba(255, 255, 255, 0.35);
400
+ border-top-color: #fff;
401
+ border-radius: 50%;
402
+ animation: pw-spin 0.6s linear infinite;
403
+ }
404
+
371
405
  .pw-shell__btn--back {
372
406
  background: transparent;
373
407
  border-color: var(--pw-color-primary);
@@ -388,3 +422,55 @@
388
422
  background: var(--pw-color-primary-light);
389
423
  }
390
424
 
425
+ /* ------------------------------------------------------------------ */
426
+ /* Error panel — replaces footer when status === "error" */
427
+ /* ------------------------------------------------------------------ */
428
+ .pw-shell__error {
429
+ background: var(--pw-color-error-bg);
430
+ border: 1px solid var(--pw-color-error-border);
431
+ border-radius: var(--pw-shell-radius);
432
+ padding: 16px 20px;
433
+ display: flex;
434
+ flex-direction: column;
435
+ gap: 10px;
436
+ }
437
+
438
+ .pw-shell__error-title {
439
+ font-size: 14px;
440
+ font-weight: 600;
441
+ color: var(--pw-color-error);
442
+ }
443
+
444
+ .pw-shell__error-message {
445
+ font-size: 13px;
446
+ color: var(--pw-color-muted);
447
+ }
448
+
449
+ .pw-shell__error-actions {
450
+ display: flex;
451
+ gap: 8px;
452
+ align-items: center;
453
+ margin-top: 2px;
454
+ }
455
+
456
+ .pw-shell__btn--retry {
457
+ background: var(--pw-color-error);
458
+ border-color: var(--pw-color-error);
459
+ color: #fff;
460
+ }
461
+
462
+ .pw-shell__btn--retry:hover:not(:disabled) {
463
+ opacity: 0.9;
464
+ }
465
+
466
+ .pw-shell__btn--suspend {
467
+ color: var(--pw-color-muted);
468
+ border-color: transparent;
469
+ background: transparent;
470
+ font-size: 13px;
471
+ }
472
+
473
+ .pw-shell__btn--suspend:hover:not(:disabled) {
474
+ background: var(--pw-color-primary-light);
475
+ }
476
+
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import type { PropsWithChildren, ReactElement, ReactNode } from "react";
1
+ import type { ChangeEvent, PropsWithChildren, ReactElement, ReactNode } from "react";
2
2
  import { PathData, PathDefinition, PathEngine, PathEvent, PathSnapshot, ProgressLayout } from "@daltonr/pathwrite-core";
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-http`.
6
+ * returned by `createPersistedEngine()` from `@daltonr/pathwrite-store`.
7
7
  *
8
8
  * When provided:
9
9
  * - `usePath` will **not** create its own engine.
@@ -37,30 +37,86 @@ export interface UsePathReturn<TData extends PathData = PathData> {
37
37
  /** Reset the current step's data to what it was when the step was entered. Useful for "Clear" or "Reset" buttons. */
38
38
  resetStep: () => void;
39
39
  /**
40
- * Tear down any active path (without firing hooks) and immediately start the
41
- * given path fresh. Safe to call whether or not a path is currently active.
40
+ * Tear down any active path (without firing hooks) and immediately restart
41
+ * the same path with the same initial data. Safe to call at any time.
42
42
  * Use for "Start over" / retry flows without remounting the component.
43
43
  */
44
- restart: (path: PathDefinition<any>, initialData?: PathData) => void;
44
+ restart: () => void;
45
+ /**
46
+ * Re-runs the operation that set `snapshot.error`. Increments `snapshot.error.retryCount`
47
+ * on repeated failure so shells can escalate from "Try again" to "Come back later".
48
+ * No-op when there is no pending error.
49
+ */
50
+ retry: () => void;
51
+ /**
52
+ * Pauses the path with intent to return. Emits a `suspended` event that the application
53
+ * listens for to dismiss the wizard UI. All state and data are preserved.
54
+ */
55
+ suspend: () => void;
45
56
  }
46
57
  export type PathProviderProps = PropsWithChildren<{
47
58
  /** Forwarded to the internal usePath hook. */
48
59
  onEvent?: (event: PathEvent) => void;
60
+ /**
61
+ * Services object passed through context to all step components.
62
+ * Step components access it via `usePathContext<TData, TServices>()`.
63
+ * Typed as `unknown` here so `PathProvider` stays non-generic — provide a
64
+ * typed services interface via the `TServices` type parameter on `usePathContext`.
65
+ */
66
+ services?: unknown;
49
67
  }>;
50
68
  export declare function usePath<TData extends PathData = PathData>(options?: UsePathOptions): UsePathReturn<TData>;
51
69
  /**
52
70
  * Provides a single `usePath` instance to all descendants.
53
71
  * Consume with `usePathContext()`.
54
72
  */
55
- export declare function PathProvider({ children, onEvent }: PathProviderProps): ReactElement;
73
+ export declare function PathProvider({ children, onEvent, services }: PathProviderProps): ReactElement;
56
74
  /**
57
- * Access the nearest `PathProvider`'s path instance.
58
- * Throws if used outside of a `<PathProvider>`.
75
+ * Access the nearest `PathProvider`'s path instance and optional services object.
76
+ * Throws if used outside of a `<PathProvider>` or `<PathShell>`.
59
77
  *
60
- * The optional generic narrows `snapshot.data` for convenience — it is a
61
- * **type-level assertion**, not a runtime guarantee.
78
+ * Both generics are type-level assertions, not runtime guarantees:
79
+ * - `TData` narrows `snapshot.data`
80
+ * - `TServices` types the `services` value — must match what was passed to `PathShell` or `PathProvider`
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * function OfficeStep() {
85
+ * const { snapshot, services } = usePathContext<HiringData, HiringServices>();
86
+ * // services is typed as HiringServices
87
+ * }
88
+ * ```
62
89
  */
63
- export declare function usePathContext<TData extends PathData = PathData>(): UsePathReturn<TData>;
90
+ export declare function usePathContext<TData extends PathData = PathData, TServices = unknown>(): Omit<UsePathReturn<TData>, "snapshot"> & {
91
+ snapshot: PathSnapshot<TData>;
92
+ services: TServices;
93
+ };
94
+ /**
95
+ * Binding helper for a single `<input>`, `<select>`, or `<textarea>` field.
96
+ *
97
+ * Returns `{ value, onChange }` tied to `snapshot.data[field]`, so you can
98
+ * spread it directly onto an element and eliminate the repetitive
99
+ * `onChange={e => setData("field", e.target.value)}` pattern:
100
+ *
101
+ * ```tsx
102
+ * function NameStep() {
103
+ * const name = useField<MyData, "name">("name");
104
+ * return <input type="text" {...name} />;
105
+ * }
106
+ * ```
107
+ *
108
+ * - `value` is always a `string` (falls back to `""` when the data key is unset).
109
+ * - `onChange` calls `setData(field, e.target.value)`.
110
+ *
111
+ * For inputs that need a value transform (e.g. `.trim()`, `Number()`) keep
112
+ * an explicit `onChange` handler — this helper is for the no-transform case.
113
+ *
114
+ * Must be called inside a `<PathShell>` or `<PathProvider>`.
115
+ */
116
+ export declare function useField<TData extends PathData, K extends string & keyof TData>(field: K): {
117
+ value: string;
118
+ onChange: (e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;
119
+ };
64
120
  export interface PathShellProps {
65
121
  /** The path definition to drive. */
66
122
  path: PathDefinition<any>;
@@ -88,6 +144,8 @@ export interface PathShellProps {
88
144
  nextLabel?: string;
89
145
  /** Label for the Complete button (shown on the last step). Defaults to `"Complete"`. */
90
146
  completeLabel?: string;
147
+ /** Label shown on the Next/Complete button while an async operation is in progress. Defaults to `undefined` (button shows a CSS spinner but keeps its label). */
148
+ loadingLabel?: string;
91
149
  /** Label for the Cancel button. Defaults to `"Cancel"`. */
92
150
  cancelLabel?: string;
93
151
  /** If true, hide the Cancel button. Defaults to `false`. */
@@ -122,6 +180,26 @@ export interface PathShellProps {
122
180
  * - `"activeOnly"`: Only the active (sub-path) bar — root bar hidden.
123
181
  */
124
182
  progressLayout?: ProgressLayout;
183
+ /**
184
+ * Services object passed through context to all step components.
185
+ * Step components access it via `usePathContext<TData, TServices>()`.
186
+ *
187
+ * The same services object that was passed to your path factory function
188
+ * should be passed here so step components can call service methods directly
189
+ * (e.g. parameterised queries that depend on mid-step user input).
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * const svc = new LiveHiringServices();
194
+ * const path = createHiringPath(svc);
195
+ * <PathShell path={path} services={svc} steps={{ ... }} />
196
+ * ```
197
+ */
198
+ services?: unknown;
199
+ }
200
+ export interface PathShellHandle {
201
+ /** Restart the shell's current path with its original `initialData`, without unmounting. */
202
+ restart: () => void;
125
203
  }
126
204
  export interface PathShellActions {
127
205
  next: () => void;
@@ -132,6 +210,10 @@ export interface PathShellActions {
132
210
  setData: (key: string, value: unknown) => void;
133
211
  /** Restart the shell's current path with its current `initialData`. */
134
212
  restart: () => void;
213
+ /** Re-run the operation that set `snapshot.error`. See `PathEngine.retry()`. */
214
+ retry: () => void;
215
+ /** Pause with intent to return, preserving all state. Emits `suspended`. */
216
+ suspend: () => void;
135
217
  }
136
218
  /**
137
219
  * Default UI shell that renders a progress indicator, step content, and navigation
@@ -149,6 +231,6 @@ export interface PathShellActions {
149
231
  * />
150
232
  * ```
151
233
  */
152
- export declare function PathShell({ path: pathDef, engine: externalEngine, steps, initialData, autoStart, onComplete, onCancel, onEvent, backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, hideProgress, footerLayout, className, renderHeader, renderFooter, validationDisplay, progressLayout, }: PathShellProps): ReactElement;
234
+ export declare const PathShell: import("react").ForwardRefExoticComponent<PathShellProps & import("react").RefAttributes<PathShellHandle>>;
153
235
  export type { PathData, FieldErrors, PathDefinition, PathEvent, PathSnapshot, PathStep, PathStepContext, ProgressLayout, RootProgress, SerializedPathState, StepChoice, } from "@daltonr/pathwrite-core";
154
236
  export { PathEngine } from "@daltonr/pathwrite-core";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createContext, createElement, useCallback, useContext, useEffect, useRef, useSyncExternalStore } from "react";
2
- import { PathEngine } from "@daltonr/pathwrite-core";
1
+ import { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useSyncExternalStore } from "react";
2
+ import { PathEngine, formatFieldKey, errorPhaseMessage, } from "@daltonr/pathwrite-core";
3
3
  // ---------------------------------------------------------------------------
4
4
  // usePath hook
5
5
  // ---------------------------------------------------------------------------
@@ -51,42 +51,80 @@ export function usePath(options) {
51
51
  const goToStepChecked = useCallback((stepId) => engine.goToStepChecked(stepId), [engine]);
52
52
  const setData = useCallback((key, value) => engine.setData(key, value), [engine]);
53
53
  const resetStep = useCallback(() => engine.resetStep(), [engine]);
54
- const restart = useCallback((path, initialData = {}) => engine.restart(path, initialData), [engine]);
55
- return { snapshot, start, startSubPath, next, previous, cancel, goToStep, goToStepChecked, setData, resetStep, restart };
54
+ const restart = useCallback(() => engine.restart(), [engine]);
55
+ const retry = useCallback(() => engine.retry(), [engine]);
56
+ const suspend = useCallback(() => engine.suspend(), [engine]);
57
+ return { snapshot, start, startSubPath, next, previous, cancel, goToStep, goToStepChecked, setData, resetStep, restart, retry, suspend };
56
58
  }
57
- // ---------------------------------------------------------------------------
58
- // Context + Provider
59
- // ---------------------------------------------------------------------------
60
59
  const PathContext = createContext(null);
61
60
  /**
62
61
  * Provides a single `usePath` instance to all descendants.
63
62
  * Consume with `usePathContext()`.
64
63
  */
65
- export function PathProvider({ children, onEvent }) {
64
+ export function PathProvider({ children, onEvent, services }) {
66
65
  const path = usePath({ onEvent });
67
- return createElement(PathContext.Provider, { value: path }, children);
66
+ return createElement(PathContext.Provider, { value: { path, services: services ?? null } }, children);
68
67
  }
69
68
  /**
70
- * Access the nearest `PathProvider`'s path instance.
71
- * Throws if used outside of a `<PathProvider>`.
69
+ * Access the nearest `PathProvider`'s path instance and optional services object.
70
+ * Throws if used outside of a `<PathProvider>` or `<PathShell>`.
71
+ *
72
+ * Both generics are type-level assertions, not runtime guarantees:
73
+ * - `TData` narrows `snapshot.data`
74
+ * - `TServices` types the `services` value — must match what was passed to `PathShell` or `PathProvider`
72
75
  *
73
- * The optional generic narrows `snapshot.data` for convenience — it is a
74
- * **type-level assertion**, not a runtime guarantee.
76
+ * @example
77
+ * ```tsx
78
+ * function OfficeStep() {
79
+ * const { snapshot, services } = usePathContext<HiringData, HiringServices>();
80
+ * // services is typed as HiringServices
81
+ * }
82
+ * ```
75
83
  */
76
84
  export function usePathContext() {
77
85
  const ctx = useContext(PathContext);
78
86
  if (ctx === null) {
79
87
  throw new Error("usePathContext must be used within a <PathProvider>.");
80
88
  }
81
- return ctx;
89
+ return {
90
+ ...ctx.path,
91
+ services: ctx.services
92
+ };
82
93
  }
83
94
  // ---------------------------------------------------------------------------
84
- // Helpers
95
+ // useField — input binding helper
85
96
  // ---------------------------------------------------------------------------
86
- /** Converts a camelCase or lowercase field key to a display label.
87
- * e.g. "firstName" "First Name", "email" "Email" */
88
- function formatFieldKey(key) {
89
- return key.replace(/([A-Z])/g, " $1").replace(/^./, c => c.toUpperCase()).trim();
97
+ /**
98
+ * Binding helper for a single `<input>`, `<select>`, or `<textarea>` field.
99
+ *
100
+ * Returns `{ value, onChange }` tied to `snapshot.data[field]`, so you can
101
+ * spread it directly onto an element and eliminate the repetitive
102
+ * `onChange={e => setData("field", e.target.value)}` pattern:
103
+ *
104
+ * ```tsx
105
+ * function NameStep() {
106
+ * const name = useField<MyData, "name">("name");
107
+ * return <input type="text" {...name} />;
108
+ * }
109
+ * ```
110
+ *
111
+ * - `value` is always a `string` (falls back to `""` when the data key is unset).
112
+ * - `onChange` calls `setData(field, e.target.value)`.
113
+ *
114
+ * For inputs that need a value transform (e.g. `.trim()`, `Number()`) keep
115
+ * an explicit `onChange` handler — this helper is for the no-transform case.
116
+ *
117
+ * Must be called inside a `<PathShell>` or `<PathProvider>`.
118
+ */
119
+ export function useField(field) {
120
+ const { snapshot, setData } = usePathContext();
121
+ const onChange = useCallback((e) => {
122
+ setData(field, e.target.value);
123
+ },
124
+ // field is a string literal at the call site and never changes; setData is stable
125
+ // eslint-disable-next-line react-hooks/exhaustive-deps
126
+ [field, setData]);
127
+ return { value: String(snapshot.data[field] ?? ""), onChange };
90
128
  }
91
129
  /**
92
130
  * Default UI shell that renders a progress indicator, step content, and navigation
@@ -104,7 +142,7 @@ function formatFieldKey(key) {
104
142
  * />
105
143
  * ```
106
144
  */
107
- export function PathShell({ path: pathDef, engine: externalEngine, steps, initialData = {}, autoStart = true, onComplete, onCancel, onEvent, backLabel = "Previous", nextLabel = "Next", completeLabel = "Complete", cancelLabel = "Cancel", hideCancel = false, hideProgress = false, footerLayout = "auto", className, renderHeader, renderFooter, validationDisplay = "inline", progressLayout = "merged", }) {
145
+ export const PathShell = forwardRef(function PathShell({ path: pathDef, engine: externalEngine, steps, initialData = {}, autoStart = true, onComplete, onCancel, onEvent, backLabel = "Previous", nextLabel = "Next", completeLabel = "Complete", loadingLabel, cancelLabel = "Cancel", hideCancel = false, hideProgress = false, footerLayout = "auto", className, renderHeader, renderFooter, validationDisplay = "summary", progressLayout = "merged", services, }, ref) {
108
146
  const pathReturn = usePath({
109
147
  engine: externalEngine,
110
148
  onEvent(event) {
@@ -115,7 +153,10 @@ export function PathShell({ path: pathDef, engine: externalEngine, steps, initia
115
153
  onCancel?.(event.data);
116
154
  }
117
155
  });
118
- const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart } = pathReturn;
156
+ const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart, retry, suspend } = pathReturn;
157
+ useImperativeHandle(ref, () => ({
158
+ restart: () => restart(),
159
+ }));
119
160
  // Auto-start on mount — skipped when an external engine is provided since
120
161
  // the caller is responsible for starting it (e.g. via createPersistedEngine).
121
162
  const startedRef = useRef(false);
@@ -133,8 +174,9 @@ export function PathShell({ path: pathDef, engine: externalEngine, steps, initia
133
174
  const stepContent = snapshot
134
175
  ? ((snapshot.formId ? steps[snapshot.formId] : undefined) ?? steps[snapshot.stepId] ?? null)
135
176
  : null;
177
+ const contextValue = { path: pathReturn, services: services ?? null };
136
178
  if (!snapshot) {
137
- return createElement(PathContext.Provider, { value: pathReturn }, createElement("div", { className: cls("pw-shell", className) }, createElement("div", { className: "pw-shell__empty" }, createElement("p", null, "No active path."), !autoStart && createElement("button", {
179
+ return createElement(PathContext.Provider, { value: contextValue }, createElement("div", { className: cls("pw-shell", className) }, createElement("div", { className: "pw-shell__empty" }, createElement("p", null, "No active path."), !autoStart && createElement("button", {
138
180
  type: "button",
139
181
  className: "pw-shell__start-btn",
140
182
  onClick: () => start(pathDef, initialData)
@@ -142,13 +184,15 @@ export function PathShell({ path: pathDef, engine: externalEngine, steps, initia
142
184
  }
143
185
  const actions = {
144
186
  next, previous, cancel, goToStep, goToStepChecked, setData,
145
- restart: () => restart(pathDef, initialData)
187
+ restart: () => restart(),
188
+ retry: () => retry(),
189
+ suspend: () => suspend(),
146
190
  };
147
191
  const showRoot = !hideProgress && !!snapshot.rootProgress && progressLayout !== "activeOnly";
148
192
  const showActive = !hideProgress && (renderHeader
149
193
  ? true
150
194
  : (snapshot.stepCount > 1 || snapshot.nestingLevel > 0) && progressLayout !== "rootOnly");
151
- return createElement(PathContext.Provider, { value: pathReturn }, createElement("div", { className: cls("pw-shell", progressLayout !== "merged" && `pw-shell--progress-${progressLayout}`, className) },
195
+ return createElement(PathContext.Provider, { value: contextValue }, createElement("div", { className: cls("pw-shell", progressLayout !== "merged" && `pw-shell--progress-${progressLayout}`, className) },
152
196
  // Root progress — persistent top-level bar visible during sub-paths
153
197
  showRoot && defaultRootProgress(snapshot.rootProgress),
154
198
  // Header — progress indicator (active path)
@@ -161,13 +205,19 @@ export function PathShell({ path: pathDef, engine: externalEngine, steps, initia
161
205
  validationDisplay !== "inline" && snapshot.hasAttemptedNext && Object.keys(snapshot.fieldErrors).length > 0 && createElement("ul", { className: "pw-shell__validation" }, ...Object.entries(snapshot.fieldErrors).map(([key, msg]) => createElement("li", { key, className: "pw-shell__validation-item" }, key !== "_" && createElement("span", { className: "pw-shell__validation-label" }, formatFieldKey(key)), msg))),
162
206
  // Warning messages — non-blocking, shown immediately (no hasAttemptedNext gate)
163
207
  validationDisplay !== "inline" && Object.keys(snapshot.fieldWarnings).length > 0 && createElement("ul", { className: "pw-shell__warnings" }, ...Object.entries(snapshot.fieldWarnings).map(([key, msg]) => createElement("li", { key, className: "pw-shell__warnings-item" }, key !== "_" && createElement("span", { className: "pw-shell__warnings-label" }, formatFieldKey(key)), msg))),
164
- // Footernavigation buttons
165
- renderFooter
166
- ? renderFooter(snapshot, actions)
167
- : defaultFooter(snapshot, actions, {
168
- backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, footerLayout
169
- })));
170
- }
208
+ // Blocking error guard returned { allowed: false, reason }
209
+ validationDisplay !== "inline" && snapshot.hasAttemptedNext && snapshot.blockingError &&
210
+ createElement("p", { className: "pw-shell__blocking-error" }, snapshot.blockingError),
211
+ // Error panel — replaces footer when an async operation has failed
212
+ snapshot.status === "error" && snapshot.error
213
+ ? defaultErrorPanel(snapshot, actions)
214
+ // Footer — navigation buttons
215
+ : renderFooter
216
+ ? renderFooter(snapshot, actions)
217
+ : defaultFooter(snapshot, actions, {
218
+ backLabel, nextLabel, completeLabel, loadingLabel, cancelLabel, hideCancel, footerLayout
219
+ })));
220
+ });
171
221
  // ---------------------------------------------------------------------------
172
222
  // Root progress (compact top-level bar visible during sub-paths)
173
223
  // ---------------------------------------------------------------------------
@@ -192,6 +242,30 @@ function defaultHeader(snapshot) {
192
242
  style: { width: `${snapshot.progress * 100}%` }
193
243
  })));
194
244
  }
245
+ // ---------------------------------------------------------------------------
246
+ // Default error panel
247
+ // ---------------------------------------------------------------------------
248
+ function defaultErrorPanel(snapshot, actions) {
249
+ const { error, hasPersistence } = snapshot;
250
+ if (!error)
251
+ return createElement("div", null);
252
+ const escalated = error.retryCount >= 2;
253
+ const title = escalated ? "Still having trouble." : "Something went wrong.";
254
+ const phaseMsg = errorPhaseMessage(error.phase);
255
+ return createElement("div", { className: "pw-shell__error" }, createElement("div", { className: "pw-shell__error-title" }, title), createElement("div", { className: "pw-shell__error-message" }, phaseMsg, error.message && ` ${error.message}`), createElement("div", { className: "pw-shell__error-actions" }, !escalated && createElement("button", {
256
+ type: "button",
257
+ className: "pw-shell__btn pw-shell__btn--retry",
258
+ onClick: actions.retry
259
+ }, "Try again"), hasPersistence && createElement("button", {
260
+ type: "button",
261
+ className: cls("pw-shell__btn", escalated ? "pw-shell__btn--retry" : "pw-shell__btn--suspend"),
262
+ onClick: actions.suspend
263
+ }, "Save and come back later"), escalated && !hasPersistence && createElement("button", {
264
+ type: "button",
265
+ className: "pw-shell__btn pw-shell__btn--retry",
266
+ onClick: actions.retry
267
+ }, "Try again")));
268
+ }
195
269
  function defaultFooter(snapshot, actions, labels) {
196
270
  // Auto-detect layout: single-step top-level paths use "form", everything else uses "wizard"
197
271
  const resolvedLayout = labels.footerLayout === "auto"
@@ -203,30 +277,32 @@ function defaultFooter(snapshot, actions, labels) {
203
277
  isFormMode && !labels.hideCancel && createElement("button", {
204
278
  type: "button",
205
279
  className: "pw-shell__btn pw-shell__btn--cancel",
206
- disabled: snapshot.isNavigating,
280
+ disabled: snapshot.status !== "idle",
207
281
  onClick: actions.cancel
208
282
  }, labels.cancelLabel),
209
283
  // Wizard mode: Back on the left
210
284
  !isFormMode && !snapshot.isFirstStep && createElement("button", {
211
285
  type: "button",
212
286
  className: "pw-shell__btn pw-shell__btn--back",
213
- disabled: snapshot.isNavigating || !snapshot.canMovePrevious,
287
+ disabled: snapshot.status !== "idle" || !snapshot.canMovePrevious,
214
288
  onClick: actions.previous
215
289
  }, labels.backLabel)), createElement("div", { className: "pw-shell__footer-right" },
216
290
  // Wizard mode: Cancel on the right
217
291
  !isFormMode && !labels.hideCancel && createElement("button", {
218
292
  type: "button",
219
293
  className: "pw-shell__btn pw-shell__btn--cancel",
220
- disabled: snapshot.isNavigating,
294
+ disabled: snapshot.status !== "idle",
221
295
  onClick: actions.cancel
222
296
  }, labels.cancelLabel),
223
297
  // Both modes: Submit on the right
224
298
  createElement("button", {
225
299
  type: "button",
226
- className: "pw-shell__btn pw-shell__btn--next",
227
- disabled: snapshot.isNavigating,
300
+ className: cls("pw-shell__btn pw-shell__btn--next", snapshot.status !== "idle" && "pw-shell__btn--loading"),
301
+ disabled: snapshot.status !== "idle",
228
302
  onClick: actions.next
229
- }, snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)));
303
+ }, snapshot.status !== "idle" && labels.loadingLabel
304
+ ? labels.loadingLabel
305
+ : snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)));
230
306
  }
231
307
  // ---------------------------------------------------------------------------
232
308
  // Helpers
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daltonr/pathwrite-react",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "React adapter for @daltonr/pathwrite-core — hooks, context provider, and optional <PathShell> default UI.",
@@ -46,7 +46,7 @@
46
46
  "react": ">=18.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "@daltonr/pathwrite-core": "^0.8.0"
49
+ "@daltonr/pathwrite-core": "^0.10.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "react": "^18.3.1",
package/src/index.ts CHANGED
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  createContext,
3
3
  createElement,
4
+ forwardRef,
4
5
  useCallback,
5
6
  useContext,
6
7
  useEffect,
8
+ useImperativeHandle,
7
9
  useRef,
8
10
  useSyncExternalStore
9
11
  } from "react";
10
- import type { PropsWithChildren, ReactElement, ReactNode } from "react";
12
+ import type { ChangeEvent, PropsWithChildren, ReactElement, ReactNode } from "react";
11
13
  import {
12
14
  PathData,
13
15
  PathDefinition,
@@ -15,7 +17,9 @@ import {
15
17
  PathEvent,
16
18
  PathSnapshot,
17
19
  ProgressLayout,
18
- RootProgress
20
+ RootProgress,
21
+ formatFieldKey,
22
+ errorPhaseMessage,
19
23
  } from "@daltonr/pathwrite-core";
20
24
 
21
25
  // ---------------------------------------------------------------------------
@@ -25,7 +29,7 @@ import {
25
29
  export interface UsePathOptions {
26
30
  /**
27
31
  * An externally-managed `PathEngine` to subscribe to — for example, the engine
28
- * returned by `createPersistedEngine()` from `@daltonr/pathwrite-store-http`.
32
+ * returned by `createPersistedEngine()` from `@daltonr/pathwrite-store`.
29
33
  *
30
34
  * When provided:
31
35
  * - `usePath` will **not** create its own engine.
@@ -60,16 +64,34 @@ export interface UsePathReturn<TData extends PathData = PathData> {
60
64
  /** Reset the current step's data to what it was when the step was entered. Useful for "Clear" or "Reset" buttons. */
61
65
  resetStep: () => void;
62
66
  /**
63
- * Tear down any active path (without firing hooks) and immediately start the
64
- * given path fresh. Safe to call whether or not a path is currently active.
67
+ * Tear down any active path (without firing hooks) and immediately restart
68
+ * the same path with the same initial data. Safe to call at any time.
65
69
  * Use for "Start over" / retry flows without remounting the component.
66
70
  */
67
- restart: (path: PathDefinition<any>, initialData?: PathData) => void;
71
+ restart: () => void;
72
+ /**
73
+ * Re-runs the operation that set `snapshot.error`. Increments `snapshot.error.retryCount`
74
+ * on repeated failure so shells can escalate from "Try again" to "Come back later".
75
+ * No-op when there is no pending error.
76
+ */
77
+ retry: () => void;
78
+ /**
79
+ * Pauses the path with intent to return. Emits a `suspended` event that the application
80
+ * listens for to dismiss the wizard UI. All state and data are preserved.
81
+ */
82
+ suspend: () => void;
68
83
  }
69
84
 
70
85
  export type PathProviderProps = PropsWithChildren<{
71
86
  /** Forwarded to the internal usePath hook. */
72
87
  onEvent?: (event: PathEvent) => void;
88
+ /**
89
+ * Services object passed through context to all step components.
90
+ * Step components access it via `usePathContext<TData, TServices>()`.
91
+ * Typed as `unknown` here so `PathProvider` stays non-generic — provide a
92
+ * typed services interface via the `TServices` type parameter on `usePathContext`.
93
+ */
94
+ services?: unknown;
73
95
  }>;
74
96
 
75
97
  // ---------------------------------------------------------------------------
@@ -156,55 +178,108 @@ export function usePath<TData extends PathData = PathData>(options?: UsePathOpti
156
178
 
157
179
  const resetStep = useCallback(() => engine.resetStep(), [engine]);
158
180
 
159
- const restart = useCallback(
160
- (path: PathDefinition<any>, initialData: PathData = {}) =>
161
- engine.restart(path, initialData),
162
- [engine]
163
- );
181
+ const restart = useCallback(() => engine.restart(), [engine]);
182
+
183
+ const retry = useCallback(() => engine.retry(), [engine]);
164
184
 
165
- return { snapshot, start, startSubPath, next, previous, cancel, goToStep, goToStepChecked, setData, resetStep, restart };
185
+ const suspend = useCallback(() => engine.suspend(), [engine]);
186
+
187
+ return { snapshot, start, startSubPath, next, previous, cancel, goToStep, goToStepChecked, setData, resetStep, restart, retry, suspend };
166
188
  }
167
189
 
168
190
  // ---------------------------------------------------------------------------
169
191
  // Context + Provider
170
192
  // ---------------------------------------------------------------------------
171
193
 
172
- const PathContext = createContext<UsePathReturn | null>(null);
194
+ interface PathContextValue {
195
+ path: UsePathReturn;
196
+ services: unknown;
197
+ }
198
+
199
+ const PathContext = createContext<PathContextValue | null>(null);
173
200
 
174
201
  /**
175
202
  * Provides a single `usePath` instance to all descendants.
176
203
  * Consume with `usePathContext()`.
177
204
  */
178
- export function PathProvider({ children, onEvent }: PathProviderProps): ReactElement {
205
+ export function PathProvider({ children, onEvent, services }: PathProviderProps): ReactElement {
179
206
  const path = usePath({ onEvent });
180
- return createElement(PathContext.Provider, { value: path }, children);
207
+ return createElement(PathContext.Provider, { value: { path, services: services ?? null } }, children);
181
208
  }
182
209
 
183
210
  /**
184
- * Access the nearest `PathProvider`'s path instance.
185
- * Throws if used outside of a `<PathProvider>`.
211
+ * Access the nearest `PathProvider`'s path instance and optional services object.
212
+ * Throws if used outside of a `<PathProvider>` or `<PathShell>`.
186
213
  *
187
- * The optional generic narrows `snapshot.data` for convenience — it is a
188
- * **type-level assertion**, not a runtime guarantee.
214
+ * Both generics are type-level assertions, not runtime guarantees:
215
+ * - `TData` narrows `snapshot.data`
216
+ * - `TServices` types the `services` value — must match what was passed to `PathShell` or `PathProvider`
217
+ *
218
+ * @example
219
+ * ```tsx
220
+ * function OfficeStep() {
221
+ * const { snapshot, services } = usePathContext<HiringData, HiringServices>();
222
+ * // services is typed as HiringServices
223
+ * }
224
+ * ```
189
225
  */
190
- export function usePathContext<TData extends PathData = PathData>(): UsePathReturn<TData> {
226
+ export function usePathContext<TData extends PathData = PathData, TServices = unknown>(): Omit<UsePathReturn<TData>, "snapshot"> & { snapshot: PathSnapshot<TData>; services: TServices } {
191
227
  const ctx = useContext(PathContext);
192
228
  if (ctx === null) {
193
229
  throw new Error("usePathContext must be used within a <PathProvider>.");
194
230
  }
195
- return ctx as UsePathReturn<TData>;
231
+ return {
232
+ ...(ctx.path as unknown as Omit<UsePathReturn<TData>, "snapshot"> & { snapshot: PathSnapshot<TData> }),
233
+ services: ctx.services as TServices
234
+ };
196
235
  }
197
236
 
198
237
  // ---------------------------------------------------------------------------
199
- // Helpers
238
+ // useField — input binding helper
200
239
  // ---------------------------------------------------------------------------
201
240
 
202
- /** Converts a camelCase or lowercase field key to a display label.
203
- * e.g. "firstName" "First Name", "email" "Email" */
204
- function formatFieldKey(key: string): string {
205
- return key.replace(/([A-Z])/g, " $1").replace(/^./, c => c.toUpperCase()).trim();
241
+ /**
242
+ * Binding helper for a single `<input>`, `<select>`, or `<textarea>` field.
243
+ *
244
+ * Returns `{ value, onChange }` tied to `snapshot.data[field]`, so you can
245
+ * spread it directly onto an element and eliminate the repetitive
246
+ * `onChange={e => setData("field", e.target.value)}` pattern:
247
+ *
248
+ * ```tsx
249
+ * function NameStep() {
250
+ * const name = useField<MyData, "name">("name");
251
+ * return <input type="text" {...name} />;
252
+ * }
253
+ * ```
254
+ *
255
+ * - `value` is always a `string` (falls back to `""` when the data key is unset).
256
+ * - `onChange` calls `setData(field, e.target.value)`.
257
+ *
258
+ * For inputs that need a value transform (e.g. `.trim()`, `Number()`) keep
259
+ * an explicit `onChange` handler — this helper is for the no-transform case.
260
+ *
261
+ * Must be called inside a `<PathShell>` or `<PathProvider>`.
262
+ */
263
+ export function useField<TData extends PathData, K extends string & keyof TData>(
264
+ field: K
265
+ ): { value: string; onChange: (e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void } {
266
+ const { snapshot, setData } = usePathContext<TData>();
267
+ const onChange = useCallback(
268
+ (e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
269
+ setData(field, e.target.value as TData[K]);
270
+ },
271
+ // field is a string literal at the call site and never changes; setData is stable
272
+ // eslint-disable-next-line react-hooks/exhaustive-deps
273
+ [field, setData]
274
+ );
275
+ return { value: String(snapshot.data[field] ?? ""), onChange };
206
276
  }
207
277
 
278
+ // ---------------------------------------------------------------------------
279
+ // Helpers
280
+ // ---------------------------------------------------------------------------
281
+
282
+
208
283
  // ---------------------------------------------------------------------------
209
284
  // Default UI — PathShell
210
285
  // ---------------------------------------------------------------------------
@@ -236,6 +311,8 @@ export interface PathShellProps {
236
311
  nextLabel?: string;
237
312
  /** Label for the Complete button (shown on the last step). Defaults to `"Complete"`. */
238
313
  completeLabel?: string;
314
+ /** Label shown on the Next/Complete button while an async operation is in progress. Defaults to `undefined` (button shows a CSS spinner but keeps its label). */
315
+ loadingLabel?: string;
239
316
  /** Label for the Cancel button. Defaults to `"Cancel"`. */
240
317
  cancelLabel?: string;
241
318
  /** If true, hide the Cancel button. Defaults to `false`. */
@@ -270,6 +347,27 @@ export interface PathShellProps {
270
347
  * - `"activeOnly"`: Only the active (sub-path) bar — root bar hidden.
271
348
  */
272
349
  progressLayout?: ProgressLayout;
350
+ /**
351
+ * Services object passed through context to all step components.
352
+ * Step components access it via `usePathContext<TData, TServices>()`.
353
+ *
354
+ * The same services object that was passed to your path factory function
355
+ * should be passed here so step components can call service methods directly
356
+ * (e.g. parameterised queries that depend on mid-step user input).
357
+ *
358
+ * @example
359
+ * ```tsx
360
+ * const svc = new LiveHiringServices();
361
+ * const path = createHiringPath(svc);
362
+ * <PathShell path={path} services={svc} steps={{ ... }} />
363
+ * ```
364
+ */
365
+ services?: unknown;
366
+ }
367
+
368
+ export interface PathShellHandle {
369
+ /** Restart the shell's current path with its original `initialData`, without unmounting. */
370
+ restart: () => void;
273
371
  }
274
372
 
275
373
  export interface PathShellActions {
@@ -281,6 +379,10 @@ export interface PathShellActions {
281
379
  setData: (key: string, value: unknown) => void;
282
380
  /** Restart the shell's current path with its current `initialData`. */
283
381
  restart: () => void;
382
+ /** Re-run the operation that set `snapshot.error`. See `PathEngine.retry()`. */
383
+ retry: () => void;
384
+ /** Pause with intent to return, preserving all state. Emits `suspended`. */
385
+ suspend: () => void;
284
386
  }
285
387
 
286
388
  /**
@@ -299,7 +401,7 @@ export interface PathShellActions {
299
401
  * />
300
402
  * ```
301
403
  */
302
- export function PathShell({
404
+ export const PathShell = forwardRef<PathShellHandle, PathShellProps>(function PathShell({
303
405
  path: pathDef,
304
406
  engine: externalEngine,
305
407
  steps,
@@ -311,6 +413,7 @@ export function PathShell({
311
413
  backLabel = "Previous",
312
414
  nextLabel = "Next",
313
415
  completeLabel = "Complete",
416
+ loadingLabel,
314
417
  cancelLabel = "Cancel",
315
418
  hideCancel = false,
316
419
  hideProgress = false,
@@ -318,9 +421,10 @@ export function PathShell({
318
421
  className,
319
422
  renderHeader,
320
423
  renderFooter,
321
- validationDisplay = "inline",
424
+ validationDisplay = "summary",
322
425
  progressLayout = "merged",
323
- }: PathShellProps): ReactElement {
426
+ services,
427
+ }: PathShellProps, ref): ReactElement {
324
428
  const pathReturn = usePath({
325
429
  engine: externalEngine,
326
430
  onEvent(event) {
@@ -330,7 +434,11 @@ export function PathShell({
330
434
  }
331
435
  });
332
436
 
333
- const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart } = pathReturn;
437
+ const { snapshot, start, next, previous, cancel, goToStep, goToStepChecked, setData, restart, retry, suspend } = pathReturn;
438
+
439
+ useImperativeHandle(ref, () => ({
440
+ restart: () => restart(),
441
+ }));
334
442
 
335
443
  // Auto-start on mount — skipped when an external engine is provided since
336
444
  // the caller is responsible for starting it (e.g. via createPersistedEngine).
@@ -351,8 +459,10 @@ export function PathShell({
351
459
  ? ((snapshot.formId ? steps[snapshot.formId] : undefined) ?? steps[snapshot.stepId] ?? null)
352
460
  : null;
353
461
 
462
+ const contextValue: PathContextValue = { path: pathReturn, services: services ?? null };
463
+
354
464
  if (!snapshot) {
355
- return createElement(PathContext.Provider, { value: pathReturn },
465
+ return createElement(PathContext.Provider, { value: contextValue },
356
466
  createElement("div", { className: cls("pw-shell", className) },
357
467
  createElement("div", { className: "pw-shell__empty" },
358
468
  createElement("p", null, "No active path."),
@@ -368,7 +478,9 @@ export function PathShell({
368
478
 
369
479
  const actions: PathShellActions = {
370
480
  next, previous, cancel, goToStep, goToStepChecked, setData,
371
- restart: () => restart(pathDef, initialData)
481
+ restart: () => restart(),
482
+ retry: () => retry(),
483
+ suspend: () => suspend(),
372
484
  };
373
485
 
374
486
  const showRoot = !hideProgress && !!snapshot.rootProgress && progressLayout !== "activeOnly";
@@ -376,7 +488,7 @@ export function PathShell({
376
488
  ? true
377
489
  : (snapshot.stepCount > 1 || snapshot.nestingLevel > 0) && progressLayout !== "rootOnly");
378
490
 
379
- return createElement(PathContext.Provider, { value: pathReturn },
491
+ return createElement(PathContext.Provider, { value: contextValue },
380
492
  createElement("div", { className: cls("pw-shell", progressLayout !== "merged" && `pw-shell--progress-${progressLayout}`, className) },
381
493
  // Root progress — persistent top-level bar visible during sub-paths
382
494
  showRoot && defaultRootProgress(snapshot.rootProgress!),
@@ -404,15 +516,21 @@ export function PathShell({
404
516
  )
405
517
  )
406
518
  ),
407
- // Footernavigation buttons
408
- renderFooter
409
- ? renderFooter(snapshot, actions)
410
- : defaultFooter(snapshot, actions, {
411
- backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, footerLayout
412
- })
519
+ // Blocking error guard returned { allowed: false, reason }
520
+ validationDisplay !== "inline" && snapshot.hasAttemptedNext && snapshot.blockingError &&
521
+ createElement("p", { className: "pw-shell__blocking-error" }, snapshot.blockingError),
522
+ // Error panel — replaces footer when an async operation has failed
523
+ snapshot.status === "error" && snapshot.error
524
+ ? defaultErrorPanel(snapshot, actions)
525
+ // Footer — navigation buttons
526
+ : renderFooter
527
+ ? renderFooter(snapshot, actions)
528
+ : defaultFooter(snapshot, actions, {
529
+ backLabel, nextLabel, completeLabel, loadingLabel, cancelLabel, hideCancel, footerLayout
530
+ })
413
531
  )
414
532
  );
415
- }
533
+ });
416
534
 
417
535
  // ---------------------------------------------------------------------------
418
536
  // Root progress (compact top-level bar visible during sub-paths)
@@ -474,6 +592,47 @@ function defaultHeader(snapshot: PathSnapshot): ReactElement {
474
592
  );
475
593
  }
476
594
 
595
+ // ---------------------------------------------------------------------------
596
+ // Default error panel
597
+ // ---------------------------------------------------------------------------
598
+
599
+
600
+ function defaultErrorPanel(
601
+ snapshot: PathSnapshot,
602
+ actions: PathShellActions
603
+ ): ReactElement {
604
+ const { error, hasPersistence } = snapshot;
605
+ if (!error) return createElement("div", null);
606
+ const escalated = error.retryCount >= 2;
607
+ const title = escalated ? "Still having trouble." : "Something went wrong.";
608
+ const phaseMsg = errorPhaseMessage(error.phase);
609
+
610
+ return createElement("div", { className: "pw-shell__error" },
611
+ createElement("div", { className: "pw-shell__error-title" }, title),
612
+ createElement("div", { className: "pw-shell__error-message" },
613
+ phaseMsg,
614
+ error.message && ` ${error.message}`
615
+ ),
616
+ createElement("div", { className: "pw-shell__error-actions" },
617
+ !escalated && createElement("button", {
618
+ type: "button",
619
+ className: "pw-shell__btn pw-shell__btn--retry",
620
+ onClick: actions.retry
621
+ }, "Try again"),
622
+ hasPersistence && createElement("button", {
623
+ type: "button",
624
+ className: cls("pw-shell__btn", escalated ? "pw-shell__btn--retry" : "pw-shell__btn--suspend"),
625
+ onClick: actions.suspend
626
+ }, "Save and come back later"),
627
+ escalated && !hasPersistence && createElement("button", {
628
+ type: "button",
629
+ className: "pw-shell__btn pw-shell__btn--retry",
630
+ onClick: actions.retry
631
+ }, "Try again")
632
+ )
633
+ );
634
+ }
635
+
477
636
  // ---------------------------------------------------------------------------
478
637
  // Default footer (navigation buttons)
479
638
  // ---------------------------------------------------------------------------
@@ -482,6 +641,7 @@ interface FooterLabels {
482
641
  backLabel: string;
483
642
  nextLabel: string;
484
643
  completeLabel: string;
644
+ loadingLabel?: string;
485
645
  cancelLabel: string;
486
646
  hideCancel: boolean;
487
647
  footerLayout: "wizard" | "form" | "auto";
@@ -505,14 +665,14 @@ function defaultFooter(
505
665
  isFormMode && !labels.hideCancel && createElement("button", {
506
666
  type: "button",
507
667
  className: "pw-shell__btn pw-shell__btn--cancel",
508
- disabled: snapshot.isNavigating,
668
+ disabled: snapshot.status !== "idle",
509
669
  onClick: actions.cancel
510
670
  }, labels.cancelLabel),
511
671
  // Wizard mode: Back on the left
512
672
  !isFormMode && !snapshot.isFirstStep && createElement("button", {
513
673
  type: "button",
514
674
  className: "pw-shell__btn pw-shell__btn--back",
515
- disabled: snapshot.isNavigating || !snapshot.canMovePrevious,
675
+ disabled: snapshot.status !== "idle" || !snapshot.canMovePrevious,
516
676
  onClick: actions.previous
517
677
  }, labels.backLabel)
518
678
  ),
@@ -521,16 +681,18 @@ function defaultFooter(
521
681
  !isFormMode && !labels.hideCancel && createElement("button", {
522
682
  type: "button",
523
683
  className: "pw-shell__btn pw-shell__btn--cancel",
524
- disabled: snapshot.isNavigating,
684
+ disabled: snapshot.status !== "idle",
525
685
  onClick: actions.cancel
526
686
  }, labels.cancelLabel),
527
687
  // Both modes: Submit on the right
528
688
  createElement("button", {
529
689
  type: "button",
530
- className: "pw-shell__btn pw-shell__btn--next",
531
- disabled: snapshot.isNavigating,
690
+ className: cls("pw-shell__btn pw-shell__btn--next", snapshot.status !== "idle" && "pw-shell__btn--loading"),
691
+ disabled: snapshot.status !== "idle",
532
692
  onClick: actions.next
533
- }, snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)
693
+ }, snapshot.status !== "idle" && labels.loadingLabel
694
+ ? labels.loadingLabel
695
+ : snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)
534
696
  )
535
697
  );
536
698
  }