@daltonr/pathwrite-react 0.1.1 → 0.1.3
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 +79 -0
- package/dist/index.css +226 -0
- package/dist/index.d.ts +20 -22
- package/dist/index.js +22 -38
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -95,6 +95,85 @@ function NavButtons() {
|
|
|
95
95
|
|
|
96
96
|
All action callbacks are **referentially stable** — safe to pass as props or include in dependency arrays without causing unnecessary re-renders.
|
|
97
97
|
|
|
98
|
+
### Typed snapshot data
|
|
99
|
+
|
|
100
|
+
`usePath` and `usePathContext` accept an optional generic so that `snapshot.data` is typed:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
interface FormData extends PathData {
|
|
104
|
+
name: string;
|
|
105
|
+
age: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const { snapshot } = usePath<FormData>();
|
|
109
|
+
snapshot?.data.name; // string
|
|
110
|
+
snapshot?.data.age; // number
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The generic is a **type-level assertion** — it narrows `snapshot.data` for convenience but is not enforced at runtime. Define your data shape once in a `PathDefinition<FormData>` and the types will stay consistent throughout.
|
|
114
|
+
|
|
115
|
+
### Snapshot guard booleans
|
|
116
|
+
|
|
117
|
+
The snapshot includes `canMoveNext` and `canMovePrevious` — the evaluated results of the current step's navigation guards. Use them to proactively disable buttons:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<button onClick={previous} disabled={snapshot.isNavigating || !snapshot.canMovePrevious}>Back</button>
|
|
121
|
+
<button onClick={next} disabled={snapshot.isNavigating || !snapshot.canMoveNext}>Next</button>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
These update automatically when data changes (e.g. after `setData`). Async guards default to `true` optimistically.
|
|
125
|
+
|
|
126
|
+
## Context sharing
|
|
127
|
+
|
|
128
|
+
### `PathProvider` + `usePathContext`
|
|
129
|
+
|
|
130
|
+
Wrap a subtree in `<PathProvider>` so multiple components share the same engine instance. Consume with `usePathContext()`.
|
|
131
|
+
|
|
132
|
+
### `PathShell` context
|
|
133
|
+
|
|
134
|
+
`<PathShell>` also provides context automatically. Step components rendered inside `<PathShell>` can call `usePathContext()` without a separate `<PathProvider>`:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
function DetailsForm() {
|
|
138
|
+
const { snapshot, setData } = usePathContext();
|
|
139
|
+
return (
|
|
140
|
+
<input
|
|
141
|
+
value={String(snapshot?.data.name ?? "")}
|
|
142
|
+
onChange={(e) => setData("name", e.target.value)}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
<PathShell
|
|
148
|
+
path={myPath}
|
|
149
|
+
initialData={{ name: "" }}
|
|
150
|
+
onComplete={handleDone}
|
|
151
|
+
steps={{
|
|
152
|
+
details: <DetailsForm />,
|
|
153
|
+
review: <ReviewPanel />,
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Styling
|
|
159
|
+
|
|
160
|
+
`<PathShell>` renders structural HTML with BEM-style `pw-shell__*` CSS classes but ships with no embedded styles. Import the optional stylesheet for sensible defaults:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import "@daltonr/pathwrite-react/styles.css";
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
All visual values are CSS custom properties (`--pw-*`), so you can theme without overriding selectors:
|
|
167
|
+
|
|
168
|
+
```css
|
|
169
|
+
:root {
|
|
170
|
+
--pw-color-primary: #8b5cf6;
|
|
171
|
+
--pw-shell-radius: 12px;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
98
177
|
## Design notes
|
|
99
178
|
|
|
100
179
|
- **`useSyncExternalStore`** — the hook subscribes to the core `PathEngine` using React 18's `useSyncExternalStore`, giving tear-free reads with no `useEffect` timing gaps.
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
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:
|
|
10
|
+
* import "@daltonr/pathwrite-shell.css"; // bundler import
|
|
11
|
+
* <link href="pathwrite/shell.css" ...> // HTML link
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* ------------------------------------------------------------------ */
|
|
15
|
+
/* Custom property defaults */
|
|
16
|
+
/* ------------------------------------------------------------------ */
|
|
17
|
+
:root {
|
|
18
|
+
/* Layout */
|
|
19
|
+
--pw-shell-max-width: 720px;
|
|
20
|
+
--pw-shell-padding: 24px;
|
|
21
|
+
--pw-shell-gap: 20px;
|
|
22
|
+
--pw-shell-radius: 10px;
|
|
23
|
+
|
|
24
|
+
/* Colours */
|
|
25
|
+
--pw-color-bg: #ffffff;
|
|
26
|
+
--pw-color-border: #dbe4f0;
|
|
27
|
+
--pw-color-text: #1f2937;
|
|
28
|
+
--pw-color-muted: #5b677a;
|
|
29
|
+
--pw-color-primary: #2563eb;
|
|
30
|
+
--pw-color-primary-light: rgba(37, 99, 235, 0.12);
|
|
31
|
+
--pw-color-btn-bg: #f8fbff;
|
|
32
|
+
--pw-color-btn-border: #c2d0e5;
|
|
33
|
+
|
|
34
|
+
/* Progress */
|
|
35
|
+
--pw-dot-size: 32px;
|
|
36
|
+
--pw-dot-font-size: 13px;
|
|
37
|
+
--pw-track-height: 4px;
|
|
38
|
+
|
|
39
|
+
/* Buttons */
|
|
40
|
+
--pw-btn-padding: 8px 16px;
|
|
41
|
+
--pw-btn-radius: 6px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ------------------------------------------------------------------ */
|
|
45
|
+
/* Shell root */
|
|
46
|
+
/* ------------------------------------------------------------------ */
|
|
47
|
+
.pw-shell {
|
|
48
|
+
max-width: var(--pw-shell-max-width);
|
|
49
|
+
margin: 0 auto;
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: var(--pw-shell-gap);
|
|
53
|
+
padding: var(--pw-shell-padding);
|
|
54
|
+
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
55
|
+
color: var(--pw-color-text);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* ------------------------------------------------------------------ */
|
|
59
|
+
/* Empty state */
|
|
60
|
+
/* ------------------------------------------------------------------ */
|
|
61
|
+
.pw-shell__empty {
|
|
62
|
+
text-align: center;
|
|
63
|
+
padding: 32px 16px;
|
|
64
|
+
color: var(--pw-color-muted);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.pw-shell__start-btn {
|
|
68
|
+
margin-top: 12px;
|
|
69
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
70
|
+
background: var(--pw-color-btn-bg);
|
|
71
|
+
color: var(--pw-color-text);
|
|
72
|
+
padding: var(--pw-btn-padding);
|
|
73
|
+
border-radius: var(--pw-btn-radius);
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
font-size: 14px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* ------------------------------------------------------------------ */
|
|
79
|
+
/* Header — progress indicator */
|
|
80
|
+
/* ------------------------------------------------------------------ */
|
|
81
|
+
.pw-shell__header {
|
|
82
|
+
background: var(--pw-color-bg);
|
|
83
|
+
border: 1px solid var(--pw-color-border);
|
|
84
|
+
border-radius: var(--pw-shell-radius);
|
|
85
|
+
padding: 20px 24px 16px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.pw-shell__steps {
|
|
89
|
+
display: flex;
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
margin-bottom: 12px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.pw-shell__step {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
align-items: center;
|
|
98
|
+
gap: 6px;
|
|
99
|
+
flex: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.pw-shell__step-dot {
|
|
103
|
+
width: var(--pw-dot-size);
|
|
104
|
+
height: var(--pw-dot-size);
|
|
105
|
+
border-radius: 50%;
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
font-size: var(--pw-dot-font-size);
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
border: 2px solid var(--pw-color-border);
|
|
112
|
+
background: var(--pw-color-bg);
|
|
113
|
+
color: var(--pw-color-muted);
|
|
114
|
+
transition: all 0.25s ease;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.pw-shell__step--completed .pw-shell__step-dot {
|
|
118
|
+
background: var(--pw-color-primary);
|
|
119
|
+
border-color: var(--pw-color-primary);
|
|
120
|
+
color: #fff;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.pw-shell__step--current .pw-shell__step-dot {
|
|
124
|
+
border-color: var(--pw-color-primary);
|
|
125
|
+
color: var(--pw-color-primary);
|
|
126
|
+
box-shadow: 0 0 0 3px var(--pw-color-primary-light);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.pw-shell__step-label {
|
|
130
|
+
font-size: 12px;
|
|
131
|
+
color: var(--pw-color-muted);
|
|
132
|
+
text-align: center;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.pw-shell__step--current .pw-shell__step-label {
|
|
137
|
+
color: var(--pw-color-primary);
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.pw-shell__step--completed .pw-shell__step-label {
|
|
142
|
+
color: var(--pw-color-text);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Track / fill */
|
|
146
|
+
.pw-shell__track {
|
|
147
|
+
height: var(--pw-track-height);
|
|
148
|
+
background: var(--pw-color-border);
|
|
149
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.pw-shell__track-fill {
|
|
154
|
+
height: 100%;
|
|
155
|
+
background: var(--pw-color-primary);
|
|
156
|
+
border-radius: calc(var(--pw-track-height) / 2);
|
|
157
|
+
transition: width 0.3s ease;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ------------------------------------------------------------------ */
|
|
161
|
+
/* Body — step content */
|
|
162
|
+
/* ------------------------------------------------------------------ */
|
|
163
|
+
.pw-shell__body {
|
|
164
|
+
background: var(--pw-color-bg);
|
|
165
|
+
border: 1px solid var(--pw-color-border);
|
|
166
|
+
border-radius: var(--pw-shell-radius);
|
|
167
|
+
padding: var(--pw-shell-padding);
|
|
168
|
+
min-height: 120px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* ------------------------------------------------------------------ */
|
|
172
|
+
/* Footer — navigation buttons */
|
|
173
|
+
/* ------------------------------------------------------------------ */
|
|
174
|
+
.pw-shell__footer {
|
|
175
|
+
display: flex;
|
|
176
|
+
justify-content: space-between;
|
|
177
|
+
align-items: center;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.pw-shell__footer-left,
|
|
181
|
+
.pw-shell__footer-right {
|
|
182
|
+
display: flex;
|
|
183
|
+
gap: 8px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.pw-shell__btn {
|
|
187
|
+
border: 1px solid var(--pw-color-btn-border);
|
|
188
|
+
background: var(--pw-color-btn-bg);
|
|
189
|
+
color: var(--pw-color-text);
|
|
190
|
+
padding: var(--pw-btn-padding);
|
|
191
|
+
border-radius: var(--pw-btn-radius);
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
font-size: 14px;
|
|
194
|
+
transition: background 0.15s ease, border-color 0.15s ease;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.pw-shell__btn:hover:not(:disabled) {
|
|
198
|
+
background: var(--pw-color-border);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.pw-shell__btn:disabled {
|
|
202
|
+
opacity: 0.5;
|
|
203
|
+
cursor: not-allowed;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.pw-shell__btn--next {
|
|
207
|
+
background: var(--pw-color-primary);
|
|
208
|
+
border-color: var(--pw-color-primary);
|
|
209
|
+
color: #fff;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.pw-shell__btn--next:hover:not(:disabled) {
|
|
213
|
+
background: #1d4ed8;
|
|
214
|
+
border-color: #1d4ed8;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.pw-shell__btn--cancel {
|
|
218
|
+
color: var(--pw-color-muted);
|
|
219
|
+
border-color: transparent;
|
|
220
|
+
background: transparent;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.pw-shell__btn--cancel:hover:not(:disabled) {
|
|
224
|
+
background: var(--pw-color-primary-light);
|
|
225
|
+
}
|
|
226
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export interface UsePathOptions {
|
|
|
4
4
|
/** Called for every engine event (stateChanged, completed, cancelled, resumed). */
|
|
5
5
|
onEvent?: (event: PathEvent) => void;
|
|
6
6
|
}
|
|
7
|
-
export interface UsePathReturn {
|
|
7
|
+
export interface UsePathReturn<TData extends PathData = PathData> {
|
|
8
8
|
/** Current path snapshot, or `null` when no path is active. Triggers a React re-render on change. */
|
|
9
|
-
snapshot: PathSnapshot | null;
|
|
9
|
+
snapshot: PathSnapshot<TData> | null;
|
|
10
10
|
/** Start (or restart) a path. */
|
|
11
11
|
start: (path: PathDefinition, initialData?: PathData) => void;
|
|
12
12
|
/** Push a sub-path onto the stack. Requires an active path. */
|
|
@@ -26,7 +26,7 @@ export type PathProviderProps = PropsWithChildren<{
|
|
|
26
26
|
/** Forwarded to the internal usePath hook. */
|
|
27
27
|
onEvent?: (event: PathEvent) => void;
|
|
28
28
|
}>;
|
|
29
|
-
export declare function usePath(options?: UsePathOptions): UsePathReturn
|
|
29
|
+
export declare function usePath<TData extends PathData = PathData>(options?: UsePathOptions): UsePathReturn<TData>;
|
|
30
30
|
/**
|
|
31
31
|
* Provides a single `usePath` instance to all descendants.
|
|
32
32
|
* Consume with `usePathContext()`.
|
|
@@ -35,21 +35,16 @@ export declare function PathProvider({ children, onEvent }: PathProviderProps):
|
|
|
35
35
|
/**
|
|
36
36
|
* Access the nearest `PathProvider`'s path instance.
|
|
37
37
|
* Throws if used outside of a `<PathProvider>`.
|
|
38
|
+
*
|
|
39
|
+
* The optional generic narrows `snapshot.data` for convenience — it is a
|
|
40
|
+
* **type-level assertion**, not a runtime guarantee.
|
|
38
41
|
*/
|
|
39
|
-
export declare function usePathContext(): UsePathReturn
|
|
40
|
-
export interface PathStepProps {
|
|
41
|
-
/** Must match a step `id` in the path definition. */
|
|
42
|
-
id: string;
|
|
43
|
-
children: ReactNode;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Wraps step content. Only renders its children when the current step matches `id`.
|
|
47
|
-
* Must be used inside a `<PathShell>`.
|
|
48
|
-
*/
|
|
49
|
-
export declare function PathStep(_props: PathStepProps): ReactElement | null;
|
|
42
|
+
export declare function usePathContext<TData extends PathData = PathData>(): UsePathReturn<TData>;
|
|
50
43
|
export interface PathShellProps {
|
|
51
44
|
/** The path definition to drive. */
|
|
52
45
|
path: PathDefinition;
|
|
46
|
+
/** Map of step ID → content. The shell renders `steps[snapshot.stepId]` for the current step. */
|
|
47
|
+
steps: Record<string, ReactNode>;
|
|
53
48
|
/** Initial data passed to `engine.start()`. */
|
|
54
49
|
initialData?: PathData;
|
|
55
50
|
/** If true, the path is started automatically on mount. Defaults to `true`. */
|
|
@@ -78,8 +73,6 @@ export interface PathShellProps {
|
|
|
78
73
|
renderHeader?: (snapshot: PathSnapshot) => ReactNode;
|
|
79
74
|
/** Render prop to replace the entire footer (navigation area). Receives the snapshot and actions. */
|
|
80
75
|
renderFooter?: (snapshot: PathSnapshot, actions: PathShellActions) => ReactNode;
|
|
81
|
-
/** `<PathStep>` children. */
|
|
82
|
-
children: ReactNode;
|
|
83
76
|
}
|
|
84
77
|
export interface PathShellActions {
|
|
85
78
|
next: () => void;
|
|
@@ -90,13 +83,18 @@ export interface PathShellActions {
|
|
|
90
83
|
}
|
|
91
84
|
/**
|
|
92
85
|
* Default UI shell that renders a progress indicator, step content, and navigation
|
|
93
|
-
* buttons.
|
|
86
|
+
* buttons. Pass a `steps` map to define per-step content.
|
|
94
87
|
*
|
|
95
88
|
* ```tsx
|
|
96
|
-
* <PathShell
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
89
|
+
* <PathShell
|
|
90
|
+
* path={myPath}
|
|
91
|
+
* initialData={{ name: "" }}
|
|
92
|
+
* onComplete={handleDone}
|
|
93
|
+
* steps={{
|
|
94
|
+
* details: <DetailsForm />,
|
|
95
|
+
* review: <ReviewPanel />,
|
|
96
|
+
* }}
|
|
97
|
+
* />
|
|
100
98
|
* ```
|
|
101
99
|
*/
|
|
102
|
-
export declare function PathShell({ path: pathDef, initialData, autoStart, onComplete, onCancel, onEvent, backLabel, nextLabel, finishLabel, cancelLabel, hideCancel, hideProgress, className, renderHeader, renderFooter,
|
|
100
|
+
export declare function PathShell({ path: pathDef, steps, initialData, autoStart, onComplete, onCancel, onEvent, backLabel, nextLabel, finishLabel, cancelLabel, hideCancel, hideProgress, className, renderHeader, renderFooter, }: PathShellProps): ReactElement;
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,9 @@ export function PathProvider({ children, onEvent }) {
|
|
|
52
52
|
/**
|
|
53
53
|
* Access the nearest `PathProvider`'s path instance.
|
|
54
54
|
* Throws if used outside of a `<PathProvider>`.
|
|
55
|
+
*
|
|
56
|
+
* The optional generic narrows `snapshot.data` for convenience — it is a
|
|
57
|
+
* **type-level assertion**, not a runtime guarantee.
|
|
55
58
|
*/
|
|
56
59
|
export function usePathContext() {
|
|
57
60
|
const ctx = useContext(PathContext);
|
|
@@ -60,27 +63,23 @@ export function usePathContext() {
|
|
|
60
63
|
}
|
|
61
64
|
return ctx;
|
|
62
65
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Wraps step content. Only renders its children when the current step matches `id`.
|
|
65
|
-
* Must be used inside a `<PathShell>`.
|
|
66
|
-
*/
|
|
67
|
-
export function PathStep(_props) {
|
|
68
|
-
// Rendering is handled by PathShell — PathStep is never rendered directly.
|
|
69
|
-
// It exists purely as a typed container so PathShell can inspect its props.
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
66
|
/**
|
|
73
67
|
* Default UI shell that renders a progress indicator, step content, and navigation
|
|
74
|
-
* buttons.
|
|
68
|
+
* buttons. Pass a `steps` map to define per-step content.
|
|
75
69
|
*
|
|
76
70
|
* ```tsx
|
|
77
|
-
* <PathShell
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
71
|
+
* <PathShell
|
|
72
|
+
* path={myPath}
|
|
73
|
+
* initialData={{ name: "" }}
|
|
74
|
+
* onComplete={handleDone}
|
|
75
|
+
* steps={{
|
|
76
|
+
* details: <DetailsForm />,
|
|
77
|
+
* review: <ReviewPanel />,
|
|
78
|
+
* }}
|
|
79
|
+
* />
|
|
81
80
|
* ```
|
|
82
81
|
*/
|
|
83
|
-
export function PathShell({ path: pathDef, initialData = {}, autoStart = true, onComplete, onCancel, onEvent, backLabel = "Back", nextLabel = "Next", finishLabel = "Finish", cancelLabel = "Cancel", hideCancel = false, hideProgress = false, className, renderHeader, renderFooter,
|
|
82
|
+
export function PathShell({ path: pathDef, steps, initialData = {}, autoStart = true, onComplete, onCancel, onEvent, backLabel = "Back", nextLabel = "Next", finishLabel = "Finish", cancelLabel = "Cancel", hideCancel = false, hideProgress = false, className, renderHeader, renderFooter, }) {
|
|
84
83
|
const pathReturn = usePath({
|
|
85
84
|
onEvent(event) {
|
|
86
85
|
onEvent?.(event);
|
|
@@ -100,17 +99,17 @@ export function PathShell({ path: pathDef, initialData = {}, autoStart = true, o
|
|
|
100
99
|
}
|
|
101
100
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
101
|
}, []);
|
|
103
|
-
//
|
|
104
|
-
const stepContent =
|
|
102
|
+
// Look up step content from the steps map
|
|
103
|
+
const stepContent = snapshot ? (steps[snapshot.stepId] ?? null) : null;
|
|
105
104
|
if (!snapshot) {
|
|
106
|
-
return createElement("div", { className: cls("pw-shell", className) }, createElement("div", { className: "pw-shell__empty" }, createElement("p", null, "No active path."), !autoStart && createElement("button", {
|
|
105
|
+
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", {
|
|
107
106
|
type: "button",
|
|
108
107
|
className: "pw-shell__start-btn",
|
|
109
108
|
onClick: () => start(pathDef, initialData)
|
|
110
|
-
}, "Start")));
|
|
109
|
+
}, "Start"))));
|
|
111
110
|
}
|
|
112
111
|
const actions = { next, previous, cancel, goToStep, setData };
|
|
113
|
-
return createElement("div", { className: cls("pw-shell", className) },
|
|
112
|
+
return createElement(PathContext.Provider, { value: pathReturn }, createElement("div", { className: cls("pw-shell", className) },
|
|
114
113
|
// Header — progress indicator
|
|
115
114
|
!hideProgress && (renderHeader
|
|
116
115
|
? renderHeader(snapshot)
|
|
@@ -122,7 +121,7 @@ export function PathShell({ path: pathDef, initialData = {}, autoStart = true, o
|
|
|
122
121
|
? renderFooter(snapshot, actions)
|
|
123
122
|
: defaultFooter(snapshot, actions, {
|
|
124
123
|
backLabel, nextLabel, finishLabel, cancelLabel, hideCancel
|
|
125
|
-
}));
|
|
124
|
+
})));
|
|
126
125
|
}
|
|
127
126
|
// ---------------------------------------------------------------------------
|
|
128
127
|
// Default header (progress indicator)
|
|
@@ -140,7 +139,7 @@ function defaultFooter(snapshot, actions, labels) {
|
|
|
140
139
|
return createElement("div", { className: "pw-shell__footer" }, createElement("div", { className: "pw-shell__footer-left" }, !snapshot.isFirstStep && createElement("button", {
|
|
141
140
|
type: "button",
|
|
142
141
|
className: "pw-shell__btn pw-shell__btn--back",
|
|
143
|
-
disabled: snapshot.isNavigating,
|
|
142
|
+
disabled: snapshot.isNavigating || !snapshot.canMovePrevious,
|
|
144
143
|
onClick: actions.previous
|
|
145
144
|
}, labels.backLabel)), createElement("div", { className: "pw-shell__footer-right" }, !labels.hideCancel && createElement("button", {
|
|
146
145
|
type: "button",
|
|
@@ -150,28 +149,13 @@ function defaultFooter(snapshot, actions, labels) {
|
|
|
150
149
|
}, labels.cancelLabel), createElement("button", {
|
|
151
150
|
type: "button",
|
|
152
151
|
className: "pw-shell__btn pw-shell__btn--next",
|
|
153
|
-
disabled: snapshot.isNavigating,
|
|
152
|
+
disabled: snapshot.isNavigating || !snapshot.canMoveNext,
|
|
154
153
|
onClick: actions.next
|
|
155
154
|
}, snapshot.isLastStep ? labels.finishLabel : labels.nextLabel)));
|
|
156
155
|
}
|
|
157
156
|
// ---------------------------------------------------------------------------
|
|
158
157
|
// Helpers
|
|
159
158
|
// ---------------------------------------------------------------------------
|
|
160
|
-
function resolveStepContent(children, snapshot) {
|
|
161
|
-
if (!snapshot || !children)
|
|
162
|
-
return null;
|
|
163
|
-
const arr = Array.isArray(children) ? children : [children];
|
|
164
|
-
for (const child of arr) {
|
|
165
|
-
if (child &&
|
|
166
|
-
typeof child === "object" &&
|
|
167
|
-
"type" in child &&
|
|
168
|
-
child.type === PathStep &&
|
|
169
|
-
child.props?.id === snapshot.stepId) {
|
|
170
|
-
return child.props.children ?? null;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
159
|
function cls(...parts) {
|
|
176
160
|
return parts.filter(Boolean).join(" ");
|
|
177
161
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,MAAM,EACN,oBAAoB,EACrB,MAAM,OAAO,CAAC;AAEf,OAAO,EAGL,UAAU,EAGX,MAAM,yBAAyB,CAAC;AAmCjC,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,MAAM,UAAU,OAAO,
|
|
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.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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.",
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
"multi-step",
|
|
19
19
|
"workflow"
|
|
20
20
|
],
|
|
21
|
-
"sideEffects":
|
|
21
|
+
"sideEffects": ["**/*.css"],
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"import": "./dist/index.js"
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
|
+
"./styles.css": "./dist/index.css"
|
|
27
28
|
},
|
|
28
29
|
"main": "dist/index.js",
|
|
29
30
|
"types": "dist/index.d.ts",
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
"LICENSE"
|
|
34
35
|
],
|
|
35
36
|
"scripts": {
|
|
36
|
-
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"build": "tsc -p tsconfig.json && cp ../shell.css dist/index.css",
|
|
37
38
|
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
38
39
|
"prepublishOnly": "npm run clean && npm run build"
|
|
39
40
|
},
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
"react": ">=18.0.0"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
|
-
"@daltonr/pathwrite-core": "^0.1.
|
|
45
|
+
"@daltonr/pathwrite-core": "^0.1.3"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"react": "^18.3.1",
|