@daltonr/pathwrite-react 0.5.0 → 0.6.1
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 +65 -1
- package/dist/index.css +281 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +35 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +50 -10
package/README.md
CHANGED
|
@@ -189,6 +189,36 @@ import { PathShell } from "@daltonr/pathwrite-react";
|
|
|
189
189
|
/>
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
+
> **⚠️ Important: `steps` Keys Must Match Step IDs**
|
|
193
|
+
>
|
|
194
|
+
> The keys in the `steps` object **must exactly match** the step IDs from your path definition:
|
|
195
|
+
>
|
|
196
|
+
> ```typescript
|
|
197
|
+
> const myPath: PathDefinition = {
|
|
198
|
+
> id: 'signup',
|
|
199
|
+
> steps: [
|
|
200
|
+
> { id: 'details' }, // ← Step ID
|
|
201
|
+
> { id: 'review' } // ← Step ID
|
|
202
|
+
> ]
|
|
203
|
+
> };
|
|
204
|
+
> ```
|
|
205
|
+
>
|
|
206
|
+
> ```tsx
|
|
207
|
+
> <PathShell
|
|
208
|
+
> path={myPath}
|
|
209
|
+
> steps={{
|
|
210
|
+
> details: <DetailsForm />, // ✅ Matches "details" step
|
|
211
|
+
> review: <ReviewPanel />, // ✅ Matches "review" step
|
|
212
|
+
> foo: <FooPanel /> // ❌ No step with id "foo"
|
|
213
|
+
> }}
|
|
214
|
+
> />
|
|
215
|
+
> ```
|
|
216
|
+
>
|
|
217
|
+
> If a key doesn't match any step ID, PathShell will render:
|
|
218
|
+
> **`No content for step "foo"`**
|
|
219
|
+
>
|
|
220
|
+
> **💡 Tip:** Use your IDE's "Go to Definition" on the step ID in your path definition, then copy-paste the exact string when creating the `steps` object. This ensures perfect matching and avoids typos.
|
|
221
|
+
|
|
192
222
|
### Props
|
|
193
223
|
|
|
194
224
|
| Prop | Type | Default | Description |
|
|
@@ -206,7 +236,8 @@ import { PathShell } from "@daltonr/pathwrite-react";
|
|
|
206
236
|
| `completeLabel` | `string` | `"Complete"` | Complete button label (last step). |
|
|
207
237
|
| `cancelLabel` | `string` | `"Cancel"` | Cancel button label. |
|
|
208
238
|
| `hideCancel` | `boolean` | `false` | Hide the Cancel button. |
|
|
209
|
-
| `hideProgress` | `boolean` | `false` | Hide the progress indicator. |
|
|
239
|
+
| `hideProgress` | `boolean` | `false` | Hide the progress indicator. Also hidden automatically for single-step top-level paths. |
|
|
240
|
+
| `footerLayout` | `"wizard" \| "form" \| "auto"` | `"auto"` | Footer button layout. `"auto"` uses `"form"` for single-step top-level paths, `"wizard"` otherwise. `"wizard"`: Back on left, Cancel+Submit on right. `"form"`: Cancel on left, Submit on right, no Back button. |
|
|
210
241
|
| `className` | `string` | — | Extra CSS class on the root element. |
|
|
211
242
|
| `renderHeader` | `(snapshot) => ReactNode` | — | Render prop to replace the progress header. |
|
|
212
243
|
| `renderFooter` | `(snapshot, actions) => ReactNode` | — | Render prop to replace the navigation footer. |
|
|
@@ -235,6 +266,39 @@ Use `renderHeader` and `renderFooter` to replace the built-in progress bar or na
|
|
|
235
266
|
|
|
236
267
|
`PathShellActions` contains: `next`, `previous`, `cancel`, `goToStep`, `goToStepChecked`, `setData`, `restart`.
|
|
237
268
|
|
|
269
|
+
### Resetting the path
|
|
270
|
+
|
|
271
|
+
Use the `key` prop to reset `<PathShell>` to step 1. Changing `key` forces React to discard the old component and mount a fresh one — this is idiomatic React and requires no new API:
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
const [formKey, setFormKey] = useState(0);
|
|
275
|
+
|
|
276
|
+
<PathShell
|
|
277
|
+
key={formKey}
|
|
278
|
+
path={myPath}
|
|
279
|
+
initialData={{ name: "" }}
|
|
280
|
+
onComplete={handleDone}
|
|
281
|
+
steps={{ details: <DetailsForm /> }}
|
|
282
|
+
/>
|
|
283
|
+
|
|
284
|
+
<button onClick={() => setFormKey(k => k + 1)}>Try Again</button>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Incrementing `formKey` discards the old shell and mounts a completely fresh one — path engine, child component state, and DOM are all reset.
|
|
288
|
+
|
|
289
|
+
If your "Try Again" button is inside the success/cancelled panel you conditionally render after completion, the pattern is even simpler:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
const [isActive, setIsActive] = useState(true);
|
|
293
|
+
|
|
294
|
+
{isActive
|
|
295
|
+
? <PathShell path={myPath} onComplete={() => setIsActive(false)} steps={...} />
|
|
296
|
+
: <SuccessPanel onRetry={() => setIsActive(true)} />
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
React function components have no instance, so there is no `ref.restart()` method. The `key` prop achieves the same result and is the React-idiomatic way to reset any component tree.
|
|
301
|
+
|
|
238
302
|
### Context sharing
|
|
239
303
|
|
|
240
304
|
`<PathShell>` provides a path context automatically — step components rendered inside it can call `usePathContext()` without a separate `<PathProvider>`:
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Pathwrite — Default Shell Stylesheet
|
|
3
|
+
*
|
|
4
|
+
* Optional CSS for the <PathShell> / <pw-shell> default UI components.
|
|
5
|
+
* Import this file if you want sensible out-of-the-box styling.
|
|
6
|
+
* Every visual value is a CSS custom property (--pw-*) so you can
|
|
7
|
+
* theme the shell without overriding selectors.
|
|
8
|
+
*
|
|
9
|
+
* Usage (React / Vue):
|
|
10
|
+
* import "adapter-package/styles.css";
|
|
11
|
+
*
|
|
12
|
+
* Usage (Angular) — add to the styles array in angular.json:
|
|
13
|
+
* "node_modules/@daltonr/pathwrite-angular/dist/index.css"
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/* ------------------------------------------------------------------ */
|
|
17
|
+
/* Custom property defaults */
|
|
18
|
+
/* ------------------------------------------------------------------ */
|
|
19
|
+
:root {
|
|
20
|
+
/* Layout */
|
|
21
|
+
--pw-shell-max-width: 720px;
|
|
22
|
+
--pw-shell-padding: 24px;
|
|
23
|
+
--pw-shell-gap: 20px;
|
|
24
|
+
--pw-shell-radius: 10px;
|
|
25
|
+
|
|
26
|
+
/* Colours */
|
|
27
|
+
--pw-color-bg: #ffffff;
|
|
28
|
+
--pw-color-border: #dbe4f0;
|
|
29
|
+
--pw-color-text: #1f2937;
|
|
30
|
+
--pw-color-muted: #5b677a;
|
|
31
|
+
--pw-color-primary: #2563eb;
|
|
32
|
+
--pw-color-primary-light: rgba(37, 99, 235, 0.12);
|
|
33
|
+
--pw-color-btn-bg: #f8fbff;
|
|
34
|
+
--pw-color-btn-border: #c2d0e5;
|
|
35
|
+
|
|
36
|
+
/* Progress */
|
|
37
|
+
--pw-dot-size: 32px;
|
|
38
|
+
--pw-dot-font-size: 13px;
|
|
39
|
+
--pw-track-height: 4px;
|
|
40
|
+
|
|
41
|
+
/* Buttons */
|
|
42
|
+
--pw-btn-padding: 8px 16px;
|
|
43
|
+
--pw-btn-radius: 6px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ------------------------------------------------------------------ */
|
|
47
|
+
/* Shell root */
|
|
48
|
+
/* ------------------------------------------------------------------ */
|
|
49
|
+
.pw-shell {
|
|
50
|
+
max-width: var(--pw-shell-max-width);
|
|
51
|
+
margin: 0 auto;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: var(--pw-shell-gap);
|
|
55
|
+
padding: var(--pw-shell-padding);
|
|
56
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
57
|
+
color: var(--pw-color-text);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* ------------------------------------------------------------------ */
|
|
61
|
+
/* Empty state */
|
|
62
|
+
/* ------------------------------------------------------------------ */
|
|
63
|
+
.pw-shell__empty {
|
|
64
|
+
text-align: center;
|
|
65
|
+
padding: 32px 16px;
|
|
66
|
+
color: var(--pw-color-muted);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.pw-shell__start-btn {
|
|
70
|
+
margin-top: 12px;
|
|
71
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
72
|
+
background: var(--pw-color-btn-bg);
|
|
73
|
+
color: var(--pw-color-text);
|
|
74
|
+
padding: var(--pw-btn-padding);
|
|
75
|
+
border-radius: var(--pw-btn-radius);
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
font-size: 14px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* ------------------------------------------------------------------ */
|
|
81
|
+
/* Header — progress indicator */
|
|
82
|
+
/* ------------------------------------------------------------------ */
|
|
83
|
+
.pw-shell__header {
|
|
84
|
+
background: var(--pw-color-bg);
|
|
85
|
+
border: 1px solid var(--pw-color-border);
|
|
86
|
+
border-radius: var(--pw-shell-radius);
|
|
87
|
+
padding: 20px 24px 16px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.pw-shell__steps {
|
|
91
|
+
display: flex;
|
|
92
|
+
justify-content: space-between;
|
|
93
|
+
margin-bottom: 12px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.pw-shell__step {
|
|
97
|
+
display: flex;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 6px;
|
|
101
|
+
flex: 1;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.pw-shell__step-dot {
|
|
105
|
+
width: var(--pw-dot-size);
|
|
106
|
+
height: var(--pw-dot-size);
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
font-size: var(--pw-dot-font-size);
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
border: 2px solid var(--pw-color-border);
|
|
114
|
+
background: var(--pw-color-bg);
|
|
115
|
+
color: var(--pw-color-muted);
|
|
116
|
+
transition: all 0.25s ease;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.pw-shell__step--completed .pw-shell__step-dot {
|
|
120
|
+
background: var(--pw-color-primary);
|
|
121
|
+
border-color: var(--pw-color-primary);
|
|
122
|
+
color: #fff;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.pw-shell__step--current .pw-shell__step-dot {
|
|
126
|
+
border-color: var(--pw-color-primary);
|
|
127
|
+
color: var(--pw-color-primary);
|
|
128
|
+
box-shadow: 0 0 0 3px var(--pw-color-primary-light);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.pw-shell__step-label {
|
|
132
|
+
font-size: 12px;
|
|
133
|
+
color: var(--pw-color-muted);
|
|
134
|
+
text-align: center;
|
|
135
|
+
white-space: nowrap;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.pw-shell__step--current .pw-shell__step-label {
|
|
139
|
+
color: var(--pw-color-primary);
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.pw-shell__step--completed .pw-shell__step-label {
|
|
144
|
+
color: var(--pw-color-text);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Track / fill */
|
|
148
|
+
.pw-shell__track {
|
|
149
|
+
height: var(--pw-track-height);
|
|
150
|
+
background: var(--pw-color-border);
|
|
151
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
152
|
+
overflow: hidden;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.pw-shell__track-fill {
|
|
156
|
+
height: 100%;
|
|
157
|
+
background: var(--pw-color-primary);
|
|
158
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
159
|
+
transition: width 0.3s ease;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ------------------------------------------------------------------ */
|
|
163
|
+
/* Body — step content */
|
|
164
|
+
/* ------------------------------------------------------------------ */
|
|
165
|
+
.pw-shell__body {
|
|
166
|
+
background: var(--pw-color-bg);
|
|
167
|
+
border: 1px solid var(--pw-color-border);
|
|
168
|
+
border-radius: var(--pw-shell-radius);
|
|
169
|
+
padding: var(--pw-shell-padding);
|
|
170
|
+
min-height: 120px;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* ------------------------------------------------------------------ */
|
|
174
|
+
/* Validation messages */
|
|
175
|
+
/* ------------------------------------------------------------------ */
|
|
176
|
+
:root {
|
|
177
|
+
--pw-color-error: #dc2626;
|
|
178
|
+
--pw-color-error-bg: #fef2f2;
|
|
179
|
+
--pw-color-error-border: #fecaca;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.pw-shell__validation {
|
|
183
|
+
list-style: none;
|
|
184
|
+
margin: 0;
|
|
185
|
+
padding: 12px 16px;
|
|
186
|
+
background: var(--pw-color-error-bg);
|
|
187
|
+
border: 1px solid var(--pw-color-error-border);
|
|
188
|
+
border-radius: var(--pw-shell-radius);
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: 4px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.pw-shell__validation-item {
|
|
195
|
+
font-size: 13px;
|
|
196
|
+
color: var(--pw-color-error);
|
|
197
|
+
padding-left: 16px;
|
|
198
|
+
position: relative;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.pw-shell__validation-item::before {
|
|
202
|
+
content: "•";
|
|
203
|
+
position: absolute;
|
|
204
|
+
left: 4px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.pw-shell__validation-label {
|
|
208
|
+
font-weight: 600;
|
|
209
|
+
margin-right: 3px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.pw-shell__validation-label::after {
|
|
213
|
+
content: ":";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* ------------------------------------------------------------------ */
|
|
217
|
+
/* Footer — navigation buttons */
|
|
218
|
+
/* ------------------------------------------------------------------ */
|
|
219
|
+
.pw-shell__footer {
|
|
220
|
+
display: flex;
|
|
221
|
+
justify-content: space-between;
|
|
222
|
+
align-items: center;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.pw-shell__footer-left,
|
|
226
|
+
.pw-shell__footer-right {
|
|
227
|
+
display: flex;
|
|
228
|
+
gap: 8px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.pw-shell__btn {
|
|
232
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
233
|
+
background: var(--pw-color-btn-bg);
|
|
234
|
+
color: var(--pw-color-text);
|
|
235
|
+
padding: var(--pw-btn-padding);
|
|
236
|
+
border-radius: var(--pw-btn-radius);
|
|
237
|
+
cursor: pointer;
|
|
238
|
+
font-size: 14px;
|
|
239
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.pw-shell__btn:hover:not(:disabled) {
|
|
243
|
+
background: var(--pw-color-border);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.pw-shell__btn:disabled {
|
|
247
|
+
opacity: 0.5;
|
|
248
|
+
cursor: not-allowed;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.pw-shell__btn--next {
|
|
252
|
+
background: var(--pw-color-primary);
|
|
253
|
+
border-color: var(--pw-color-primary);
|
|
254
|
+
color: #fff;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.pw-shell__btn--next:hover:not(:disabled) {
|
|
258
|
+
background: #1d4ed8;
|
|
259
|
+
border-color: #1d4ed8;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.pw-shell__btn--back {
|
|
263
|
+
background: transparent;
|
|
264
|
+
border-color: var(--pw-color-primary);
|
|
265
|
+
color: var(--pw-color-primary);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.pw-shell__btn--back:hover:not(:disabled) {
|
|
269
|
+
background: var(--pw-color-primary-light);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.pw-shell__btn--cancel {
|
|
273
|
+
color: var(--pw-color-muted);
|
|
274
|
+
border-color: transparent;
|
|
275
|
+
background: transparent;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.pw-shell__btn--cancel:hover:not(:disabled) {
|
|
279
|
+
background: var(--pw-color-primary-light);
|
|
280
|
+
}
|
|
281
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -90,8 +90,15 @@ export interface PathShellProps {
|
|
|
90
90
|
cancelLabel?: string;
|
|
91
91
|
/** If true, hide the Cancel button. Defaults to `false`. */
|
|
92
92
|
hideCancel?: boolean;
|
|
93
|
-
/** If true, hide the progress indicator. Defaults to `false`. */
|
|
93
|
+
/** If true, hide the progress indicator. Also hidden automatically when the path has only one step. Defaults to `false`. */
|
|
94
94
|
hideProgress?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Footer layout mode:
|
|
97
|
+
* - `"auto"` (default): Uses "form" for single-step top-level paths, "wizard" otherwise.
|
|
98
|
+
* - `"wizard"`: Back button on left, Cancel and Submit together on right.
|
|
99
|
+
* - `"form"`: Cancel on left, Submit alone on right. Back button never shown.
|
|
100
|
+
*/
|
|
101
|
+
footerLayout?: "wizard" | "form" | "auto";
|
|
95
102
|
/** Optional extra CSS class on the root element. */
|
|
96
103
|
className?: string;
|
|
97
104
|
/** Render prop to replace the entire header (progress area). Receives the snapshot. */
|
|
@@ -125,6 +132,6 @@ export interface PathShellActions {
|
|
|
125
132
|
* />
|
|
126
133
|
* ```
|
|
127
134
|
*/
|
|
128
|
-
export declare function PathShell({ path: pathDef, engine: externalEngine, steps, initialData, autoStart, onComplete, onCancel, onEvent, backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, hideProgress, className, renderHeader, renderFooter, }: PathShellProps): ReactElement;
|
|
129
|
-
export type { PathData, PathDefinition, PathEvent, PathSnapshot, PathStep, PathStepContext, SerializedPathState } from "@daltonr/pathwrite-core";
|
|
135
|
+
export declare function PathShell({ path: pathDef, engine: externalEngine, steps, initialData, autoStart, onComplete, onCancel, onEvent, backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, hideProgress, footerLayout, className, renderHeader, renderFooter, }: PathShellProps): ReactElement;
|
|
136
|
+
export type { PathData, FieldErrors, PathDefinition, PathEvent, PathSnapshot, PathStep, PathStepContext, SerializedPathState } from "@daltonr/pathwrite-core";
|
|
130
137
|
export { PathEngine } from "@daltonr/pathwrite-core";
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,14 @@ export function usePathContext() {
|
|
|
79
79
|
}
|
|
80
80
|
return ctx;
|
|
81
81
|
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Helpers
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
/** Converts a camelCase or lowercase field key to a display label.
|
|
86
|
+
* e.g. "firstName" → "First Name", "email" → "Email" */
|
|
87
|
+
function formatFieldKey(key) {
|
|
88
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, c => c.toUpperCase()).trim();
|
|
89
|
+
}
|
|
82
90
|
/**
|
|
83
91
|
* Default UI shell that renders a progress indicator, step content, and navigation
|
|
84
92
|
* buttons. Pass a `steps` map to define per-step content.
|
|
@@ -95,7 +103,7 @@ export function usePathContext() {
|
|
|
95
103
|
* />
|
|
96
104
|
* ```
|
|
97
105
|
*/
|
|
98
|
-
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, className, renderHeader, renderFooter, }) {
|
|
106
|
+
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, }) {
|
|
99
107
|
const pathReturn = usePath({
|
|
100
108
|
engine: externalEngine,
|
|
101
109
|
onEvent(event) {
|
|
@@ -134,16 +142,16 @@ export function PathShell({ path: pathDef, engine: externalEngine, steps, initia
|
|
|
134
142
|
// Header — progress indicator
|
|
135
143
|
!hideProgress && (renderHeader
|
|
136
144
|
? renderHeader(snapshot)
|
|
137
|
-
: defaultHeader(snapshot)),
|
|
145
|
+
: (snapshot.stepCount > 1 || snapshot.nestingLevel > 0) && defaultHeader(snapshot)),
|
|
138
146
|
// Body — step content
|
|
139
147
|
createElement("div", { className: "pw-shell__body" }, stepContent),
|
|
140
|
-
// Validation messages
|
|
141
|
-
snapshot.
|
|
148
|
+
// Validation messages — labeled by field name
|
|
149
|
+
snapshot.hasAttemptedNext && Object.keys(snapshot.fieldMessages).length > 0 && createElement("ul", { className: "pw-shell__validation" }, ...Object.entries(snapshot.fieldMessages).map(([key, msg]) => createElement("li", { key, className: "pw-shell__validation-item" }, key !== "_" && createElement("span", { className: "pw-shell__validation-label" }, formatFieldKey(key)), msg))),
|
|
142
150
|
// Footer — navigation buttons
|
|
143
151
|
renderFooter
|
|
144
152
|
? renderFooter(snapshot, actions)
|
|
145
153
|
: defaultFooter(snapshot, actions, {
|
|
146
|
-
backLabel, nextLabel, completeLabel, cancelLabel, hideCancel
|
|
154
|
+
backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, footerLayout
|
|
147
155
|
})));
|
|
148
156
|
}
|
|
149
157
|
// ---------------------------------------------------------------------------
|
|
@@ -159,20 +167,38 @@ function defaultHeader(snapshot) {
|
|
|
159
167
|
})));
|
|
160
168
|
}
|
|
161
169
|
function defaultFooter(snapshot, actions, labels) {
|
|
162
|
-
|
|
170
|
+
// Auto-detect layout: single-step top-level paths use "form", everything else uses "wizard"
|
|
171
|
+
const resolvedLayout = labels.footerLayout === "auto"
|
|
172
|
+
? (snapshot.stepCount === 1 && snapshot.nestingLevel === 0 ? "form" : "wizard")
|
|
173
|
+
: labels.footerLayout;
|
|
174
|
+
const isFormMode = resolvedLayout === "form";
|
|
175
|
+
return createElement("div", { className: "pw-shell__footer" }, createElement("div", { className: "pw-shell__footer-left" },
|
|
176
|
+
// Form mode: Cancel on the left
|
|
177
|
+
isFormMode && !labels.hideCancel && createElement("button", {
|
|
178
|
+
type: "button",
|
|
179
|
+
className: "pw-shell__btn pw-shell__btn--cancel",
|
|
180
|
+
disabled: snapshot.isNavigating,
|
|
181
|
+
onClick: actions.cancel
|
|
182
|
+
}, labels.cancelLabel),
|
|
183
|
+
// Wizard mode: Back on the left
|
|
184
|
+
!isFormMode && !snapshot.isFirstStep && createElement("button", {
|
|
163
185
|
type: "button",
|
|
164
186
|
className: "pw-shell__btn pw-shell__btn--back",
|
|
165
187
|
disabled: snapshot.isNavigating || !snapshot.canMovePrevious,
|
|
166
188
|
onClick: actions.previous
|
|
167
|
-
}, labels.backLabel)), createElement("div", { className: "pw-shell__footer-right" },
|
|
189
|
+
}, labels.backLabel)), createElement("div", { className: "pw-shell__footer-right" },
|
|
190
|
+
// Wizard mode: Cancel on the right
|
|
191
|
+
!isFormMode && !labels.hideCancel && createElement("button", {
|
|
168
192
|
type: "button",
|
|
169
193
|
className: "pw-shell__btn pw-shell__btn--cancel",
|
|
170
194
|
disabled: snapshot.isNavigating,
|
|
171
195
|
onClick: actions.cancel
|
|
172
|
-
}, labels.cancelLabel),
|
|
196
|
+
}, labels.cancelLabel),
|
|
197
|
+
// Both modes: Submit on the right
|
|
198
|
+
createElement("button", {
|
|
173
199
|
type: "button",
|
|
174
200
|
className: "pw-shell__btn pw-shell__btn--next",
|
|
175
|
-
disabled: snapshot.isNavigating
|
|
201
|
+
disabled: snapshot.isNavigating,
|
|
176
202
|
onClick: actions.next
|
|
177
203
|
}, snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)));
|
|
178
204
|
}
|
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.
|
|
3
|
+
"version": "0.6.1",
|
|
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.",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
27
|
"import": "./dist/index.js"
|
|
28
28
|
},
|
|
29
|
-
"./styles.css": "./dist/index.css"
|
|
29
|
+
"./styles.css": "./dist/index.css",
|
|
30
|
+
"./dist/index.css": "./dist/index.css"
|
|
30
31
|
},
|
|
31
32
|
"main": "dist/index.js",
|
|
32
33
|
"types": "dist/index.d.ts",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"react": ">=18.0.0"
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"@daltonr/pathwrite-core": "^0.
|
|
49
|
+
"@daltonr/pathwrite-core": "^0.6.1"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"react": "^18.3.1",
|
package/src/index.ts
CHANGED
|
@@ -189,6 +189,16 @@ export function usePathContext<TData extends PathData = PathData>(): UsePathRetu
|
|
|
189
189
|
return ctx as UsePathReturn<TData>;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// Helpers
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
/** Converts a camelCase or lowercase field key to a display label.
|
|
197
|
+
* e.g. "firstName" → "First Name", "email" → "Email" */
|
|
198
|
+
function formatFieldKey(key: string): string {
|
|
199
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, c => c.toUpperCase()).trim();
|
|
200
|
+
}
|
|
201
|
+
|
|
192
202
|
// ---------------------------------------------------------------------------
|
|
193
203
|
// Default UI — PathShell
|
|
194
204
|
// ---------------------------------------------------------------------------
|
|
@@ -224,8 +234,15 @@ export interface PathShellProps {
|
|
|
224
234
|
cancelLabel?: string;
|
|
225
235
|
/** If true, hide the Cancel button. Defaults to `false`. */
|
|
226
236
|
hideCancel?: boolean;
|
|
227
|
-
/** If true, hide the progress indicator. Defaults to `false`. */
|
|
237
|
+
/** If true, hide the progress indicator. Also hidden automatically when the path has only one step. Defaults to `false`. */
|
|
228
238
|
hideProgress?: boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Footer layout mode:
|
|
241
|
+
* - `"auto"` (default): Uses "form" for single-step top-level paths, "wizard" otherwise.
|
|
242
|
+
* - `"wizard"`: Back button on left, Cancel and Submit together on right.
|
|
243
|
+
* - `"form"`: Cancel on left, Submit alone on right. Back button never shown.
|
|
244
|
+
*/
|
|
245
|
+
footerLayout?: "wizard" | "form" | "auto";
|
|
229
246
|
/** Optional extra CSS class on the root element. */
|
|
230
247
|
className?: string;
|
|
231
248
|
/** Render prop to replace the entire header (progress area). Receives the snapshot. */
|
|
@@ -276,6 +293,7 @@ export function PathShell({
|
|
|
276
293
|
cancelLabel = "Cancel",
|
|
277
294
|
hideCancel = false,
|
|
278
295
|
hideProgress = false,
|
|
296
|
+
footerLayout = "auto",
|
|
279
297
|
className,
|
|
280
298
|
renderHeader,
|
|
281
299
|
renderFooter,
|
|
@@ -330,20 +348,23 @@ export function PathShell({
|
|
|
330
348
|
// Header — progress indicator
|
|
331
349
|
!hideProgress && (renderHeader
|
|
332
350
|
? renderHeader(snapshot)
|
|
333
|
-
: defaultHeader(snapshot)),
|
|
351
|
+
: (snapshot.stepCount > 1 || snapshot.nestingLevel > 0) && defaultHeader(snapshot)),
|
|
334
352
|
// Body — step content
|
|
335
353
|
createElement("div", { className: "pw-shell__body" }, stepContent),
|
|
336
|
-
// Validation messages
|
|
337
|
-
snapshot.
|
|
338
|
-
...snapshot.
|
|
339
|
-
createElement("li", { key
|
|
354
|
+
// Validation messages — labeled by field name
|
|
355
|
+
snapshot.hasAttemptedNext && Object.keys(snapshot.fieldMessages).length > 0 && createElement("ul", { className: "pw-shell__validation" },
|
|
356
|
+
...Object.entries(snapshot.fieldMessages).map(([key, msg]) =>
|
|
357
|
+
createElement("li", { key, className: "pw-shell__validation-item" },
|
|
358
|
+
key !== "_" && createElement("span", { className: "pw-shell__validation-label" }, formatFieldKey(key)),
|
|
359
|
+
msg
|
|
360
|
+
)
|
|
340
361
|
)
|
|
341
362
|
),
|
|
342
363
|
// Footer — navigation buttons
|
|
343
364
|
renderFooter
|
|
344
365
|
? renderFooter(snapshot, actions)
|
|
345
366
|
: defaultFooter(snapshot, actions, {
|
|
346
|
-
backLabel, nextLabel, completeLabel, cancelLabel, hideCancel
|
|
367
|
+
backLabel, nextLabel, completeLabel, cancelLabel, hideCancel, footerLayout
|
|
347
368
|
})
|
|
348
369
|
)
|
|
349
370
|
);
|
|
@@ -389,6 +410,7 @@ interface FooterLabels {
|
|
|
389
410
|
completeLabel: string;
|
|
390
411
|
cancelLabel: string;
|
|
391
412
|
hideCancel: boolean;
|
|
413
|
+
footerLayout: "wizard" | "form" | "auto";
|
|
392
414
|
}
|
|
393
415
|
|
|
394
416
|
function defaultFooter(
|
|
@@ -396,9 +418,24 @@ function defaultFooter(
|
|
|
396
418
|
actions: PathShellActions,
|
|
397
419
|
labels: FooterLabels
|
|
398
420
|
): ReactElement {
|
|
421
|
+
// Auto-detect layout: single-step top-level paths use "form", everything else uses "wizard"
|
|
422
|
+
const resolvedLayout = labels.footerLayout === "auto"
|
|
423
|
+
? (snapshot.stepCount === 1 && snapshot.nestingLevel === 0 ? "form" : "wizard")
|
|
424
|
+
: labels.footerLayout;
|
|
425
|
+
|
|
426
|
+
const isFormMode = resolvedLayout === "form";
|
|
427
|
+
|
|
399
428
|
return createElement("div", { className: "pw-shell__footer" },
|
|
400
429
|
createElement("div", { className: "pw-shell__footer-left" },
|
|
401
|
-
|
|
430
|
+
// Form mode: Cancel on the left
|
|
431
|
+
isFormMode && !labels.hideCancel && createElement("button", {
|
|
432
|
+
type: "button",
|
|
433
|
+
className: "pw-shell__btn pw-shell__btn--cancel",
|
|
434
|
+
disabled: snapshot.isNavigating,
|
|
435
|
+
onClick: actions.cancel
|
|
436
|
+
}, labels.cancelLabel),
|
|
437
|
+
// Wizard mode: Back on the left
|
|
438
|
+
!isFormMode && !snapshot.isFirstStep && createElement("button", {
|
|
402
439
|
type: "button",
|
|
403
440
|
className: "pw-shell__btn pw-shell__btn--back",
|
|
404
441
|
disabled: snapshot.isNavigating || !snapshot.canMovePrevious,
|
|
@@ -406,16 +443,18 @@ function defaultFooter(
|
|
|
406
443
|
}, labels.backLabel)
|
|
407
444
|
),
|
|
408
445
|
createElement("div", { className: "pw-shell__footer-right" },
|
|
409
|
-
|
|
446
|
+
// Wizard mode: Cancel on the right
|
|
447
|
+
!isFormMode && !labels.hideCancel && createElement("button", {
|
|
410
448
|
type: "button",
|
|
411
449
|
className: "pw-shell__btn pw-shell__btn--cancel",
|
|
412
450
|
disabled: snapshot.isNavigating,
|
|
413
451
|
onClick: actions.cancel
|
|
414
452
|
}, labels.cancelLabel),
|
|
453
|
+
// Both modes: Submit on the right
|
|
415
454
|
createElement("button", {
|
|
416
455
|
type: "button",
|
|
417
456
|
className: "pw-shell__btn pw-shell__btn--next",
|
|
418
|
-
disabled: snapshot.isNavigating
|
|
457
|
+
disabled: snapshot.isNavigating,
|
|
419
458
|
onClick: actions.next
|
|
420
459
|
}, snapshot.isLastStep ? labels.completeLabel : labels.nextLabel)
|
|
421
460
|
)
|
|
@@ -436,6 +475,7 @@ function cls(...parts: (string | undefined | false | null)[]): string {
|
|
|
436
475
|
|
|
437
476
|
export type {
|
|
438
477
|
PathData,
|
|
478
|
+
FieldErrors,
|
|
439
479
|
PathDefinition,
|
|
440
480
|
PathEvent,
|
|
441
481
|
PathSnapshot,
|