@daltonr/pathwrite-angular 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -27
- package/dist/index.css +40 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/shell.d.ts +29 -11
- package/dist/shell.js +49 -21
- package/dist/shell.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +14 -5
- package/src/shell.ts +55 -17
package/README.md
CHANGED
|
@@ -410,7 +410,7 @@ import {
|
|
|
410
410
|
@Component({
|
|
411
411
|
imports: [PathShellComponent, PathStepDirective],
|
|
412
412
|
template: `
|
|
413
|
-
<pw-shell [path]="myPath" [initialData]="{ name: '' }" (
|
|
413
|
+
<pw-shell [path]="myPath" [initialData]="{ name: '' }" (complete)="onDone($event)">
|
|
414
414
|
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
415
415
|
<ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
416
416
|
</pw-shell>
|
|
@@ -484,7 +484,7 @@ The parent component hosting `<pw-shell>` does **not** need its own
|
|
|
484
484
|
@Component({
|
|
485
485
|
imports: [PathShellComponent, PathStepDirective],
|
|
486
486
|
template: `
|
|
487
|
-
<pw-shell #shell [path]="myPath" (
|
|
487
|
+
<pw-shell #shell [path]="myPath" (complete)="onDone($event)">
|
|
488
488
|
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
489
489
|
</pw-shell>
|
|
490
490
|
`
|
|
@@ -499,9 +499,10 @@ export class MyComponent {
|
|
|
499
499
|
|
|
500
500
|
| Input | Type | Default | Description |
|
|
501
501
|
|-------|------|---------|-------------|
|
|
502
|
-
| `path` | `PathDefinition` |
|
|
502
|
+
| `path` | `PathDefinition` | — | The path definition to drive. Required unless `[engine]` is provided. |
|
|
503
|
+
| `engine` | `PathEngine` | — | An externally-managed engine (e.g. from `restoreOrStart()`). When provided, `autoStart` is suppressed and the shell immediately reflects the engine's current state. Use `@if (engine)` in the parent template to gate mounting until the engine is ready. |
|
|
503
504
|
| `initialData` | `PathData` | `{}` | Initial data passed to `facade.start()`. |
|
|
504
|
-
| `autoStart` | `boolean` | `true` | Start the path automatically on `ngOnInit`. |
|
|
505
|
+
| `autoStart` | `boolean` | `true` | Start the path automatically on `ngOnInit`. Ignored when `[engine]` is provided. |
|
|
505
506
|
| `backLabel` | `string` | `"Previous"` | Previous button label. |
|
|
506
507
|
| `nextLabel` | `string` | `"Next"` | Next button label. |
|
|
507
508
|
| `completeLabel` | `string` | `"Complete"` | Complete button label (last step). |
|
|
@@ -514,9 +515,9 @@ export class MyComponent {
|
|
|
514
515
|
|
|
515
516
|
| Output | Payload | Description |
|
|
516
517
|
|--------|---------|-------------|
|
|
517
|
-
| `(
|
|
518
|
-
| `(
|
|
519
|
-
| `(
|
|
518
|
+
| `(complete)` | `PathData` | Emitted when the path finishes naturally. |
|
|
519
|
+
| `(cancel)` | `PathData` | Emitted when the path is cancelled. |
|
|
520
|
+
| `(event)` | `PathEvent` | Emitted for every engine event. |
|
|
520
521
|
|
|
521
522
|
### Customising the header and footer
|
|
522
523
|
|
|
@@ -576,7 +577,7 @@ Toggle an `@if` flag to destroy and recreate the shell. Every child component re
|
|
|
576
577
|
|
|
577
578
|
```html
|
|
578
579
|
@if (isActive) {
|
|
579
|
-
<pw-shell [path]="myPath" (
|
|
580
|
+
<pw-shell [path]="myPath" (complete)="isActive = false" (cancel)="isActive = false">
|
|
580
581
|
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
581
582
|
</pw-shell>
|
|
582
583
|
} @else {
|
|
@@ -589,7 +590,7 @@ Toggle an `@if` flag to destroy and recreate the shell. Every child component re
|
|
|
589
590
|
Use the existing `#shell` template reference — `restart()` is a public method:
|
|
590
591
|
|
|
591
592
|
```html
|
|
592
|
-
<pw-shell #shell [path]="myPath" (
|
|
593
|
+
<pw-shell #shell [path]="myPath" (complete)="onDone($event)">
|
|
593
594
|
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
594
595
|
</pw-shell>
|
|
595
596
|
|
|
@@ -872,24 +873,24 @@ Use it to distinguish initialization from re-entry:
|
|
|
872
873
|
|
|
873
874
|
## Persistence
|
|
874
875
|
|
|
875
|
-
Use with [@daltonr/pathwrite-store
|
|
876
|
+
Use with [@daltonr/pathwrite-store](../store) for automatic state persistence. The engine is created externally via `restoreOrStart()` and passed directly to `<pw-shell>` via the `[engine]` input.
|
|
876
877
|
|
|
877
878
|
### Simple persistence example
|
|
878
879
|
|
|
879
880
|
```typescript
|
|
880
|
-
import { Component,
|
|
881
|
-
import {
|
|
882
|
-
import {
|
|
881
|
+
import { Component, OnInit } from '@angular/core';
|
|
882
|
+
import { PathEngine } from '@daltonr/pathwrite-angular';
|
|
883
|
+
import { PathShellComponent, PathStepDirective } from '@daltonr/pathwrite-angular/shell';
|
|
884
|
+
import { HttpStore, restoreOrStart, persistence } from '@daltonr/pathwrite-store';
|
|
883
885
|
import { signupPath } from './signup-path';
|
|
884
886
|
|
|
885
887
|
@Component({
|
|
886
888
|
selector: 'app-signup-wizard',
|
|
887
889
|
standalone: true,
|
|
888
890
|
imports: [PathShellComponent, PathStepDirective],
|
|
889
|
-
providers: [PathFacade],
|
|
890
891
|
template: `
|
|
891
|
-
@if (
|
|
892
|
-
<pw-shell [path]="path" [
|
|
892
|
+
@if (engine) {
|
|
893
|
+
<pw-shell [path]="path" [engine]="engine" (complete)="onComplete($event)">
|
|
893
894
|
<ng-template pwStep="details"><app-details-form /></ng-template>
|
|
894
895
|
<ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
895
896
|
</pw-shell>
|
|
@@ -899,10 +900,8 @@ import { signupPath } from './signup-path';
|
|
|
899
900
|
`
|
|
900
901
|
})
|
|
901
902
|
export class SignupWizardComponent implements OnInit {
|
|
902
|
-
private readonly facade = inject(PathFacade);
|
|
903
|
-
|
|
904
903
|
path = signupPath;
|
|
905
|
-
|
|
904
|
+
engine: PathEngine | null = null;
|
|
906
905
|
|
|
907
906
|
async ngOnInit() {
|
|
908
907
|
const store = new HttpStore({ baseUrl: '/api/wizard' });
|
|
@@ -914,14 +913,11 @@ export class SignupWizardComponent implements OnInit {
|
|
|
914
913
|
path: this.path,
|
|
915
914
|
initialData: { name: '', email: '' },
|
|
916
915
|
observers: [
|
|
917
|
-
|
|
916
|
+
persistence({ store, key, strategy: 'onNext' })
|
|
918
917
|
]
|
|
919
918
|
});
|
|
920
919
|
|
|
921
|
-
|
|
922
|
-
// reflects the engine's current state and forwards all events.
|
|
923
|
-
this.facade.adoptEngine(engine);
|
|
924
|
-
this.ready = true;
|
|
920
|
+
this.engine = engine;
|
|
925
921
|
|
|
926
922
|
if (restored) {
|
|
927
923
|
console.log('Progress restored — resuming from', engine.snapshot()?.stepId);
|
|
@@ -936,9 +932,8 @@ export class SignupWizardComponent implements OnInit {
|
|
|
936
932
|
|
|
937
933
|
### Key points
|
|
938
934
|
|
|
939
|
-
- **`
|
|
940
|
-
-
|
|
941
|
-
- **The facade is the same one the shell uses** (provided in the component's `providers`), so the shell's template bindings, progress indicator, and navigation buttons all work automatically.
|
|
935
|
+
- **`[engine]`** passes an externally-managed engine directly to the shell. The shell adopts it immediately and skips `autoStart`.
|
|
936
|
+
- **`@if (engine)`** acts as the async gate — the shell only mounts once the engine is ready, so there is no timing window where `autoStart` could fire before the engine arrives.
|
|
942
937
|
- **`restoreOrStart()`** handles the load-or-create logic: if saved state exists on the server, it restores the engine mid-flow; otherwise it starts fresh.
|
|
943
938
|
|
|
944
939
|
---
|
package/dist/index.css
CHANGED
|
@@ -246,6 +246,9 @@
|
|
|
246
246
|
--pw-color-error: #dc2626;
|
|
247
247
|
--pw-color-error-bg: #fef2f2;
|
|
248
248
|
--pw-color-error-border: #fecaca;
|
|
249
|
+
--pw-color-warning: #d97706;
|
|
250
|
+
--pw-color-warning-bg: #fffbeb;
|
|
251
|
+
--pw-color-warning-border: #fde68a;
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
.pw-shell__validation {
|
|
@@ -282,6 +285,43 @@
|
|
|
282
285
|
content: ":";
|
|
283
286
|
}
|
|
284
287
|
|
|
288
|
+
/* ------------------------------------------------------------------ */
|
|
289
|
+
/* Warning messages */
|
|
290
|
+
/* ------------------------------------------------------------------ */
|
|
291
|
+
.pw-shell__warnings {
|
|
292
|
+
list-style: none;
|
|
293
|
+
margin: 0;
|
|
294
|
+
padding: 12px 16px;
|
|
295
|
+
background: var(--pw-color-warning-bg);
|
|
296
|
+
border: 1px solid var(--pw-color-warning-border);
|
|
297
|
+
border-radius: var(--pw-shell-radius);
|
|
298
|
+
display: flex;
|
|
299
|
+
flex-direction: column;
|
|
300
|
+
gap: 4px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.pw-shell__warnings-item {
|
|
304
|
+
font-size: 13px;
|
|
305
|
+
color: var(--pw-color-warning);
|
|
306
|
+
padding-left: 16px;
|
|
307
|
+
position: relative;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.pw-shell__warnings-item::before {
|
|
311
|
+
content: "•";
|
|
312
|
+
position: absolute;
|
|
313
|
+
left: 4px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.pw-shell__warnings-label {
|
|
317
|
+
font-weight: 600;
|
|
318
|
+
margin-right: 3px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.pw-shell__warnings-label::after {
|
|
322
|
+
content: ":";
|
|
323
|
+
}
|
|
324
|
+
|
|
285
325
|
/* ------------------------------------------------------------------ */
|
|
286
326
|
/* Footer — navigation buttons */
|
|
287
327
|
/* ------------------------------------------------------------------ */
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare class PathFacade<TData extends PathData = PathData> implements On
|
|
|
29
29
|
constructor();
|
|
30
30
|
/**
|
|
31
31
|
* Adopt an externally-managed `PathEngine` — for example, the engine returned
|
|
32
|
-
* by `restoreOrStart()` from `@daltonr/pathwrite-store
|
|
32
|
+
* by `restoreOrStart()` from `@daltonr/pathwrite-store`.
|
|
33
33
|
*
|
|
34
34
|
* The facade immediately reflects the engine's current state and forwards all
|
|
35
35
|
* subsequent events. The **caller** is responsible for the engine's lifecycle
|
|
@@ -50,12 +50,15 @@ export declare class PathFacade<TData extends PathData = PathData> implements On
|
|
|
50
50
|
* Use for "Start over" / retry flows without destroying and re-creating the
|
|
51
51
|
* component that provides this facade.
|
|
52
52
|
*/
|
|
53
|
-
restart(
|
|
53
|
+
restart(): Promise<void>;
|
|
54
54
|
startSubPath(path: PathDefinition<any>, initialData?: PathData, meta?: Record<string, unknown>): Promise<void>;
|
|
55
55
|
next(): Promise<void>;
|
|
56
56
|
previous(): Promise<void>;
|
|
57
57
|
cancel(): Promise<void>;
|
|
58
58
|
setData<K extends string & keyof TData>(key: K, value: TData[K]): Promise<void>;
|
|
59
|
+
/** Reset the current step's data to what it was when the step was entered.
|
|
60
|
+
* Useful for "Clear" or "Reset" buttons that undo changes within a step. */
|
|
61
|
+
resetStep(): Promise<void>;
|
|
59
62
|
goToStep(stepId: string): Promise<void>;
|
|
60
63
|
/** Jump to a step by ID, checking the current step's canMoveNext (forward) or
|
|
61
64
|
* canMovePrevious (backward) guard first. Navigation is blocked if the guard
|
|
@@ -85,6 +88,8 @@ export interface InjectPathReturn<TData extends PathData = PathData> {
|
|
|
85
88
|
cancel: () => Promise<void>;
|
|
86
89
|
/** Update a single data field. */
|
|
87
90
|
setData: <K extends string & keyof TData>(key: K, value: TData[K]) => Promise<void>;
|
|
91
|
+
/** Reset the current step's data to what it was when the step was entered. */
|
|
92
|
+
resetStep: () => Promise<void>;
|
|
88
93
|
/** Jump to a step by ID without checking guards. */
|
|
89
94
|
goToStep: (stepId: string) => Promise<void>;
|
|
90
95
|
/** Jump to a step by ID, checking guards first. */
|
|
@@ -93,7 +98,7 @@ export interface InjectPathReturn<TData extends PathData = PathData> {
|
|
|
93
98
|
* Tears down any active path and immediately starts the given path fresh.
|
|
94
99
|
* Use for "Start over" / retry flows.
|
|
95
100
|
*/
|
|
96
|
-
restart: (
|
|
101
|
+
restart: () => Promise<void>;
|
|
97
102
|
}
|
|
98
103
|
/**
|
|
99
104
|
* Inject a PathFacade and return a signal-based API for use in Angular components.
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ export class PathFacade {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Adopt an externally-managed `PathEngine` — for example, the engine returned
|
|
34
|
-
* by `restoreOrStart()` from `@daltonr/pathwrite-store
|
|
34
|
+
* by `restoreOrStart()` from `@daltonr/pathwrite-store`.
|
|
35
35
|
*
|
|
36
36
|
* The facade immediately reflects the engine's current state and forwards all
|
|
37
37
|
* subsequent events. The **caller** is responsible for the engine's lifecycle
|
|
@@ -80,8 +80,8 @@ export class PathFacade {
|
|
|
80
80
|
* Use for "Start over" / retry flows without destroying and re-creating the
|
|
81
81
|
* component that provides this facade.
|
|
82
82
|
*/
|
|
83
|
-
restart(
|
|
84
|
-
return this._engine.restart(
|
|
83
|
+
restart() {
|
|
84
|
+
return this._engine.restart();
|
|
85
85
|
}
|
|
86
86
|
startSubPath(path, initialData = {}, meta) {
|
|
87
87
|
return this._engine.startSubPath(path, initialData, meta);
|
|
@@ -98,6 +98,11 @@ export class PathFacade {
|
|
|
98
98
|
setData(key, value) {
|
|
99
99
|
return this._engine.setData(key, value);
|
|
100
100
|
}
|
|
101
|
+
/** Reset the current step's data to what it was when the step was entered.
|
|
102
|
+
* Useful for "Clear" or "Reset" buttons that undo changes within a step. */
|
|
103
|
+
resetStep() {
|
|
104
|
+
return this._engine.resetStep();
|
|
105
|
+
}
|
|
101
106
|
goToStep(stepId) {
|
|
102
107
|
return this._engine.goToStep(stepId);
|
|
103
108
|
}
|
|
@@ -166,9 +171,10 @@ export function injectPath() {
|
|
|
166
171
|
previous: () => facade.previous(),
|
|
167
172
|
cancel: () => facade.cancel(),
|
|
168
173
|
setData: (key, value) => facade.setData(key, value),
|
|
174
|
+
resetStep: () => facade.resetStep(),
|
|
169
175
|
goToStep: (stepId) => facade.goToStep(stepId),
|
|
170
176
|
goToStepChecked: (stepId) => facade.goToStepChecked(stepId),
|
|
171
|
-
restart: (
|
|
177
|
+
restart: () => facade.restart(),
|
|
172
178
|
};
|
|
173
179
|
}
|
|
174
180
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAyB,MAAM,EAAU,MAAM,EAAE,MAAM,eAAe,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAc,OAAO,EAAE,MAAM,MAAM,CAAC;AAC5D,OAAO,EAGL,UAAU,EAGX,MAAM,yBAAyB,CAAC;;AAEjC;;;;;;;;;;;;;GAaG;AAEH,MAAM,OAAO,UAAU;IAYrB;QAXQ,YAAO,GAAG,IAAI,UAAU,EAAE,CAAC;QAClB,YAAO,GAAG,IAAI,eAAe,CAA6B,IAAI,CAAC,CAAC;QAChE,aAAQ,GAAG,IAAI,OAAO,EAAa,CAAC;QAC7C,2BAAsB,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;QACrC,iBAAY,GAAG,MAAM,CAA6B,IAAI,CAAC,CAAC;QAEzD,WAAM,GAA2C,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7E,YAAO,GAA0B,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC9E,0FAA0F;QAC1E,gBAAW,GAAuC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QAG/F,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;OAYG;IACI,WAAW,CAAC,MAAkB;QACnC,+DAA+D;QAC/D,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAEO,aAAa,CAAC,MAAkB;QACtC,0EAA0E;QAC1E,kEAAkE;QAClE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAgC,CAAC;QAChE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE/B,IAAI,CAAC,sBAAsB,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACvD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC9D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAA+B,CAAC,CAAC;gBACzD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,QAA+B,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACpE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,WAAW;QAChB,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAEM,KAAK,CAAC,IAAyB,EAAE,cAAwB,EAAE;QAChE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACI,OAAO
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/shell.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TemplateRef, EventEmitter, QueryList, OnInit, OnDestroy, Injector } from "@angular/core";
|
|
2
|
-
import { PathData, PathDefinition, PathEvent, PathSnapshot, ProgressLayout } from "@daltonr/pathwrite-core";
|
|
1
|
+
import { TemplateRef, EventEmitter, QueryList, OnInit, OnChanges, OnDestroy, SimpleChanges, Injector } from "@angular/core";
|
|
2
|
+
import { PathData, PathDefinition, PathEngine, PathEvent, PathSnapshot, ProgressLayout } from "@daltonr/pathwrite-core";
|
|
3
3
|
import { PathFacade } from "./index";
|
|
4
4
|
import * as i0 from "@angular/core";
|
|
5
5
|
/**
|
|
@@ -90,15 +90,30 @@ export declare class PathShellFooterDirective {
|
|
|
90
90
|
* and navigation buttons.
|
|
91
91
|
*
|
|
92
92
|
* ```html
|
|
93
|
-
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (
|
|
93
|
+
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (complete)="onDone($event)">
|
|
94
94
|
* <ng-template pwStep="details"><app-details-form /></ng-template>
|
|
95
95
|
* <ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
96
96
|
* </pw-shell>
|
|
97
97
|
* ```
|
|
98
98
|
*/
|
|
99
|
-
export declare class PathShellComponent implements OnInit, OnDestroy {
|
|
100
|
-
/** The path definition to run. Required. */
|
|
101
|
-
path
|
|
99
|
+
export declare class PathShellComponent implements OnInit, OnChanges, OnDestroy {
|
|
100
|
+
/** The path definition to run. Required unless [engine] is provided. */
|
|
101
|
+
path?: PathDefinition<any>;
|
|
102
|
+
/**
|
|
103
|
+
* An externally-managed `PathEngine` to adopt — for example, the engine
|
|
104
|
+
* returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
|
|
105
|
+
*
|
|
106
|
+
* When provided the shell skips `autoStart` and immediately reflects the
|
|
107
|
+
* engine's current state. Gate the shell's existence on the engine being
|
|
108
|
+
* ready using `@if (engine)` so the input is always non-null on mount:
|
|
109
|
+
*
|
|
110
|
+
* ```html
|
|
111
|
+
* @if (engine) {
|
|
112
|
+
* <pw-shell [engine]="engine" [path]="myPath" ...></pw-shell>
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
engine?: PathEngine;
|
|
102
117
|
/** Initial data merged into the path engine on start. */
|
|
103
118
|
initialData: PathData;
|
|
104
119
|
/** Start the path automatically on ngOnInit. Set to false to call doStart() manually. */
|
|
@@ -137,9 +152,9 @@ export declare class PathShellComponent implements OnInit, OnDestroy {
|
|
|
137
152
|
* - "activeOnly": Only the active (sub-path) bar — root bar hidden.
|
|
138
153
|
*/
|
|
139
154
|
progressLayout: ProgressLayout;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
complete: EventEmitter<PathData>;
|
|
156
|
+
cancel: EventEmitter<PathData>;
|
|
157
|
+
event: EventEmitter<PathEvent>;
|
|
143
158
|
stepDirectives: QueryList<PathStepDirective>;
|
|
144
159
|
customHeader?: PathShellHeaderDirective;
|
|
145
160
|
customFooter?: PathShellFooterDirective;
|
|
@@ -151,6 +166,7 @@ export declare class PathShellComponent implements OnInit, OnDestroy {
|
|
|
151
166
|
/** Navigation actions passed to custom `pwShellFooter` templates. */
|
|
152
167
|
protected readonly shellActions: PathShellActions;
|
|
153
168
|
private readonly destroy$;
|
|
169
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
154
170
|
ngOnInit(): void;
|
|
155
171
|
ngOnDestroy(): void;
|
|
156
172
|
doStart(): void;
|
|
@@ -164,13 +180,15 @@ export declare class PathShellComponent implements OnInit, OnDestroy {
|
|
|
164
180
|
* ```
|
|
165
181
|
*/
|
|
166
182
|
restart(): Promise<void>;
|
|
167
|
-
/** Returns Object.entries(s.
|
|
183
|
+
/** Returns Object.entries(s.fieldErrors) for use in *ngFor. */
|
|
168
184
|
protected fieldEntries(s: PathSnapshot): [string, string][];
|
|
185
|
+
/** Returns Object.entries(s.fieldWarnings) for use in *ngFor. */
|
|
186
|
+
protected warningEntries(s: PathSnapshot): [string, string][];
|
|
169
187
|
/** Resolves "auto" footerLayout based on snapshot. Single-step top-level → "form", otherwise → "wizard". */
|
|
170
188
|
protected getResolvedFooterLayout(s: PathSnapshot): "wizard" | "form";
|
|
171
189
|
/** Converts a camelCase or lowercase field key to a display label.
|
|
172
190
|
* e.g. "firstName" → "First Name", "email" → "Email" */
|
|
173
191
|
protected formatFieldKey(key: string): string;
|
|
174
192
|
static ɵfac: i0.ɵɵFactoryDeclaration<PathShellComponent, never>;
|
|
175
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<PathShellComponent, "pw-shell", never, { "path": { "alias": "path"; "required":
|
|
193
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PathShellComponent, "pw-shell", never, { "path": { "alias": "path"; "required": false; }; "engine": { "alias": "engine"; "required": false; }; "initialData": { "alias": "initialData"; "required": false; }; "autoStart": { "alias": "autoStart"; "required": false; }; "backLabel": { "alias": "backLabel"; "required": false; }; "nextLabel": { "alias": "nextLabel"; "required": false; }; "completeLabel": { "alias": "completeLabel"; "required": false; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; }; "hideCancel": { "alias": "hideCancel"; "required": false; }; "hideProgress": { "alias": "hideProgress"; "required": false; }; "footerLayout": { "alias": "footerLayout"; "required": false; }; "validationDisplay": { "alias": "validationDisplay"; "required": false; }; "progressLayout": { "alias": "progressLayout"; "required": false; }; }, { "complete": "complete"; "cancel": "cancel"; "event": "event"; }, ["customHeader", "customFooter", "stepDirectives"], never, true, never>;
|
|
176
194
|
}
|
package/dist/shell.js
CHANGED
|
@@ -97,7 +97,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
97
97
|
* and navigation buttons.
|
|
98
98
|
*
|
|
99
99
|
* ```html
|
|
100
|
-
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (
|
|
100
|
+
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (complete)="onDone($event)">
|
|
101
101
|
* <ng-template pwStep="details"><app-details-form /></ng-template>
|
|
102
102
|
* <ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
103
103
|
* </pw-shell>
|
|
@@ -134,7 +134,7 @@ export class PathShellComponent {
|
|
|
134
134
|
* - `"inline"`: Suppress the summary — handle errors inside the step template instead.
|
|
135
135
|
* - `"both"`: Render the shell summary AND whatever the step template renders.
|
|
136
136
|
*/
|
|
137
|
-
this.validationDisplay = "
|
|
137
|
+
this.validationDisplay = "summary";
|
|
138
138
|
/**
|
|
139
139
|
* Controls how progress bars are arranged when a sub-path is active.
|
|
140
140
|
* - "merged" (default): Root and sub-path bars in one card.
|
|
@@ -143,9 +143,9 @@ export class PathShellComponent {
|
|
|
143
143
|
* - "activeOnly": Only the active (sub-path) bar — root bar hidden.
|
|
144
144
|
*/
|
|
145
145
|
this.progressLayout = "merged";
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
148
|
-
this.
|
|
146
|
+
this.complete = new EventEmitter();
|
|
147
|
+
this.cancel = new EventEmitter();
|
|
148
|
+
this.event = new EventEmitter();
|
|
149
149
|
this.facade = inject(PathFacade);
|
|
150
150
|
/** The shell's own component-level injector. Passed to ngTemplateOutlet so that
|
|
151
151
|
* step components can resolve PathFacade (provided by this shell) via inject(). */
|
|
@@ -159,19 +159,24 @@ export class PathShellComponent {
|
|
|
159
159
|
goToStep: (id) => this.facade.goToStep(id),
|
|
160
160
|
goToStepChecked: (id) => this.facade.goToStepChecked(id),
|
|
161
161
|
setData: (key, value) => this.facade.setData(key, value),
|
|
162
|
-
restart: () => this.facade.restart(
|
|
162
|
+
restart: () => this.facade.restart(),
|
|
163
163
|
};
|
|
164
164
|
this.destroy$ = new Subject();
|
|
165
165
|
}
|
|
166
|
+
ngOnChanges(changes) {
|
|
167
|
+
if (changes['engine'] && this.engine) {
|
|
168
|
+
this.facade.adoptEngine(this.engine);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
166
171
|
ngOnInit() {
|
|
167
172
|
this.facade.events$.pipe(takeUntil(this.destroy$)).subscribe((event) => {
|
|
168
|
-
this.
|
|
173
|
+
this.event.emit(event);
|
|
169
174
|
if (event.type === "completed")
|
|
170
|
-
this.
|
|
175
|
+
this.complete.emit(event.data);
|
|
171
176
|
if (event.type === "cancelled")
|
|
172
|
-
this.
|
|
177
|
+
this.cancel.emit(event.data);
|
|
173
178
|
});
|
|
174
|
-
if (this.autoStart) {
|
|
179
|
+
if (this.autoStart && !this.engine) {
|
|
175
180
|
this.doStart();
|
|
176
181
|
}
|
|
177
182
|
}
|
|
@@ -180,6 +185,8 @@ export class PathShellComponent {
|
|
|
180
185
|
this.destroy$.complete();
|
|
181
186
|
}
|
|
182
187
|
doStart() {
|
|
188
|
+
if (!this.path)
|
|
189
|
+
throw new Error('[pw-shell] [path] is required when no [engine] is provided');
|
|
183
190
|
this.started = true;
|
|
184
191
|
this.facade.start(this.path, this.initialData);
|
|
185
192
|
}
|
|
@@ -193,11 +200,15 @@ export class PathShellComponent {
|
|
|
193
200
|
* ```
|
|
194
201
|
*/
|
|
195
202
|
restart() {
|
|
196
|
-
return this.facade.restart(
|
|
203
|
+
return this.facade.restart();
|
|
197
204
|
}
|
|
198
|
-
/** Returns Object.entries(s.
|
|
205
|
+
/** Returns Object.entries(s.fieldErrors) for use in *ngFor. */
|
|
199
206
|
fieldEntries(s) {
|
|
200
|
-
return Object.entries(s.
|
|
207
|
+
return Object.entries(s.fieldErrors);
|
|
208
|
+
}
|
|
209
|
+
/** Returns Object.entries(s.fieldWarnings) for use in *ngFor. */
|
|
210
|
+
warningEntries(s) {
|
|
211
|
+
return Object.entries(s.fieldWarnings);
|
|
201
212
|
}
|
|
202
213
|
/** Resolves "auto" footerLayout based on snapshot. Single-step top-level → "form", otherwise → "wizard". */
|
|
203
214
|
getResolvedFooterLayout(s) {
|
|
@@ -211,7 +222,7 @@ export class PathShellComponent {
|
|
|
211
222
|
return key.replace(/([A-Z])/g, " $1").replace(/^./, c => c.toUpperCase()).trim();
|
|
212
223
|
}
|
|
213
224
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
214
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PathShellComponent, isStandalone: true, selector: "pw-shell", inputs: { path: "path", initialData: "initialData", autoStart: "autoStart", backLabel: "backLabel", nextLabel: "nextLabel", completeLabel: "completeLabel", cancelLabel: "cancelLabel", hideCancel: "hideCancel", hideProgress: "hideProgress", footerLayout: "footerLayout", validationDisplay: "validationDisplay", progressLayout: "progressLayout" }, outputs: {
|
|
225
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PathShellComponent, isStandalone: true, selector: "pw-shell", inputs: { path: "path", engine: "engine", initialData: "initialData", autoStart: "autoStart", backLabel: "backLabel", nextLabel: "nextLabel", completeLabel: "completeLabel", cancelLabel: "cancelLabel", hideCancel: "hideCancel", hideProgress: "hideProgress", footerLayout: "footerLayout", validationDisplay: "validationDisplay", progressLayout: "progressLayout" }, outputs: { complete: "complete", cancel: "cancel", event: "event" }, providers: [PathFacade], queries: [{ propertyName: "customHeader", first: true, predicate: PathShellHeaderDirective, descendants: true }, { propertyName: "customFooter", first: true, predicate: PathShellFooterDirective, descendants: true }, { propertyName: "stepDirectives", predicate: PathStepDirective }], usesOnChanges: true, ngImport: i0, template: `
|
|
215
226
|
<!-- Empty state -->
|
|
216
227
|
<div class="pw-shell" *ngIf="!(facade.state$ | async)">
|
|
217
228
|
<div class="pw-shell__empty" *ngIf="!started">
|
|
@@ -264,7 +275,8 @@ export class PathShellComponent {
|
|
|
264
275
|
<!-- Body — step content -->
|
|
265
276
|
<div class="pw-shell__body">
|
|
266
277
|
<ng-container *ngFor="let stepDir of stepDirectives">
|
|
267
|
-
|
|
278
|
+
<!-- Match by formId first (inner step of a StepChoice), then stepId -->
|
|
279
|
+
<ng-container *ngIf="stepDir.stepId === (s.formId ?? s.stepId)">
|
|
268
280
|
<ng-container *ngTemplateOutlet="stepDir.templateRef; injector: shellInjector"></ng-container>
|
|
269
281
|
</ng-container>
|
|
270
282
|
</ng-container>
|
|
@@ -277,6 +289,13 @@ export class PathShellComponent {
|
|
|
277
289
|
</li>
|
|
278
290
|
</ul>
|
|
279
291
|
|
|
292
|
+
<!-- Warning messages — non-blocking, shown immediately (no hasAttemptedNext gate) -->
|
|
293
|
+
<ul class="pw-shell__warnings" *ngIf="validationDisplay !== 'inline' && warningEntries(s).length > 0">
|
|
294
|
+
<li *ngFor="let entry of warningEntries(s)" class="pw-shell__warnings-item">
|
|
295
|
+
<span *ngIf="entry[0] !== '_'" class="pw-shell__warnings-label">{{ formatFieldKey(entry[0]) }}</span>{{ entry[1] }}
|
|
296
|
+
</li>
|
|
297
|
+
</ul>
|
|
298
|
+
|
|
280
299
|
<!-- Footer — custom or default navigation buttons -->
|
|
281
300
|
<ng-container *ngIf="customFooter; else defaultFooter">
|
|
282
301
|
<ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
|
|
@@ -384,7 +403,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
384
403
|
<!-- Body — step content -->
|
|
385
404
|
<div class="pw-shell__body">
|
|
386
405
|
<ng-container *ngFor="let stepDir of stepDirectives">
|
|
387
|
-
|
|
406
|
+
<!-- Match by formId first (inner step of a StepChoice), then stepId -->
|
|
407
|
+
<ng-container *ngIf="stepDir.stepId === (s.formId ?? s.stepId)">
|
|
388
408
|
<ng-container *ngTemplateOutlet="stepDir.templateRef; injector: shellInjector"></ng-container>
|
|
389
409
|
</ng-container>
|
|
390
410
|
</ng-container>
|
|
@@ -397,6 +417,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
397
417
|
</li>
|
|
398
418
|
</ul>
|
|
399
419
|
|
|
420
|
+
<!-- Warning messages — non-blocking, shown immediately (no hasAttemptedNext gate) -->
|
|
421
|
+
<ul class="pw-shell__warnings" *ngIf="validationDisplay !== 'inline' && warningEntries(s).length > 0">
|
|
422
|
+
<li *ngFor="let entry of warningEntries(s)" class="pw-shell__warnings-item">
|
|
423
|
+
<span *ngIf="entry[0] !== '_'" class="pw-shell__warnings-label">{{ formatFieldKey(entry[0]) }}</span>{{ entry[1] }}
|
|
424
|
+
</li>
|
|
425
|
+
</ul>
|
|
426
|
+
|
|
400
427
|
<!-- Footer — custom or default navigation buttons -->
|
|
401
428
|
<ng-container *ngIf="customFooter; else defaultFooter">
|
|
402
429
|
<ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
|
|
@@ -444,8 +471,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
444
471
|
`
|
|
445
472
|
}]
|
|
446
473
|
}], propDecorators: { path: [{
|
|
447
|
-
type: Input
|
|
448
|
-
|
|
474
|
+
type: Input
|
|
475
|
+
}], engine: [{
|
|
476
|
+
type: Input
|
|
449
477
|
}], initialData: [{
|
|
450
478
|
type: Input
|
|
451
479
|
}], autoStart: [{
|
|
@@ -468,11 +496,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
468
496
|
type: Input
|
|
469
497
|
}], progressLayout: [{
|
|
470
498
|
type: Input
|
|
471
|
-
}],
|
|
499
|
+
}], complete: [{
|
|
472
500
|
type: Output
|
|
473
|
-
}],
|
|
501
|
+
}], cancel: [{
|
|
474
502
|
type: Output
|
|
475
|
-
}],
|
|
503
|
+
}], event: [{
|
|
476
504
|
type: Output
|
|
477
505
|
}], stepDirectives: [{
|
|
478
506
|
type: ContentChildren,
|
package/dist/shell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,SAAS,EAET,KAAK,EACL,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,eAAe,
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daltonr/pathwrite-angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Angular adapter for @daltonr/pathwrite-core — RxJS observables, signal-friendly, with optional <pw-shell> default UI.",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@angular/compiler-cli": "^17.3.12"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@daltonr/pathwrite-core": "^0.
|
|
64
|
+
"@daltonr/pathwrite-core": "^0.9.0"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -41,7 +41,7 @@ export class PathFacade<TData extends PathData = PathData> implements OnDestroy
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Adopt an externally-managed `PathEngine` — for example, the engine returned
|
|
44
|
-
* by `restoreOrStart()` from `@daltonr/pathwrite-store
|
|
44
|
+
* by `restoreOrStart()` from `@daltonr/pathwrite-store`.
|
|
45
45
|
*
|
|
46
46
|
* The facade immediately reflects the engine's current state and forwards all
|
|
47
47
|
* subsequent events. The **caller** is responsible for the engine's lifecycle
|
|
@@ -94,8 +94,8 @@ export class PathFacade<TData extends PathData = PathData> implements OnDestroy
|
|
|
94
94
|
* Use for "Start over" / retry flows without destroying and re-creating the
|
|
95
95
|
* component that provides this facade.
|
|
96
96
|
*/
|
|
97
|
-
public restart(
|
|
98
|
-
return this._engine.restart(
|
|
97
|
+
public restart(): Promise<void> {
|
|
98
|
+
return this._engine.restart();
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
public startSubPath(path: PathDefinition<any>, initialData: PathData = {}, meta?: Record<string, unknown>): Promise<void> {
|
|
@@ -118,6 +118,12 @@ export class PathFacade<TData extends PathData = PathData> implements OnDestroy
|
|
|
118
118
|
return this._engine.setData(key, value as unknown);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/** Reset the current step's data to what it was when the step was entered.
|
|
122
|
+
* Useful for "Clear" or "Reset" buttons that undo changes within a step. */
|
|
123
|
+
public resetStep(): Promise<void> {
|
|
124
|
+
return this._engine.resetStep();
|
|
125
|
+
}
|
|
126
|
+
|
|
121
127
|
public goToStep(stepId: string): Promise<void> {
|
|
122
128
|
return this._engine.goToStep(stepId);
|
|
123
129
|
}
|
|
@@ -158,6 +164,8 @@ export interface InjectPathReturn<TData extends PathData = PathData> {
|
|
|
158
164
|
cancel: () => Promise<void>;
|
|
159
165
|
/** Update a single data field. */
|
|
160
166
|
setData: <K extends string & keyof TData>(key: K, value: TData[K]) => Promise<void>;
|
|
167
|
+
/** Reset the current step's data to what it was when the step was entered. */
|
|
168
|
+
resetStep: () => Promise<void>;
|
|
161
169
|
/** Jump to a step by ID without checking guards. */
|
|
162
170
|
goToStep: (stepId: string) => Promise<void>;
|
|
163
171
|
/** Jump to a step by ID, checking guards first. */
|
|
@@ -166,7 +174,7 @@ export interface InjectPathReturn<TData extends PathData = PathData> {
|
|
|
166
174
|
* Tears down any active path and immediately starts the given path fresh.
|
|
167
175
|
* Use for "Start over" / retry flows.
|
|
168
176
|
*/
|
|
169
|
-
restart: (
|
|
177
|
+
restart: () => Promise<void>;
|
|
170
178
|
}
|
|
171
179
|
|
|
172
180
|
/**
|
|
@@ -223,9 +231,10 @@ export function injectPath<TData extends PathData = PathData>(): InjectPathRetur
|
|
|
223
231
|
previous: () => facade.previous(),
|
|
224
232
|
cancel: () => facade.cancel(),
|
|
225
233
|
setData: (key, value) => facade.setData(key, value),
|
|
234
|
+
resetStep: () => facade.resetStep(),
|
|
226
235
|
goToStep: (stepId) => facade.goToStep(stepId),
|
|
227
236
|
goToStepChecked: (stepId) => facade.goToStepChecked(stepId),
|
|
228
|
-
restart: (
|
|
237
|
+
restart: () => facade.restart(),
|
|
229
238
|
};
|
|
230
239
|
}
|
|
231
240
|
|
package/src/shell.ts
CHANGED
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
ContentChildren,
|
|
10
10
|
QueryList,
|
|
11
11
|
OnInit,
|
|
12
|
+
OnChanges,
|
|
12
13
|
OnDestroy,
|
|
14
|
+
SimpleChanges,
|
|
13
15
|
inject,
|
|
14
16
|
Injector,
|
|
15
17
|
ChangeDetectionStrategy
|
|
@@ -20,6 +22,7 @@ import { takeUntil } from "rxjs/operators";
|
|
|
20
22
|
import {
|
|
21
23
|
PathData,
|
|
22
24
|
PathDefinition,
|
|
25
|
+
PathEngine,
|
|
23
26
|
PathEvent,
|
|
24
27
|
PathSnapshot,
|
|
25
28
|
ProgressLayout,
|
|
@@ -127,7 +130,7 @@ export class PathShellFooterDirective {
|
|
|
127
130
|
* and navigation buttons.
|
|
128
131
|
*
|
|
129
132
|
* ```html
|
|
130
|
-
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (
|
|
133
|
+
* <pw-shell [path]="myPath" [initialData]="{ name: '' }" (complete)="onDone($event)">
|
|
131
134
|
* <ng-template pwStep="details"><app-details-form /></ng-template>
|
|
132
135
|
* <ng-template pwStep="review"><app-review-panel /></ng-template>
|
|
133
136
|
* </pw-shell>
|
|
@@ -192,7 +195,8 @@ export class PathShellFooterDirective {
|
|
|
192
195
|
<!-- Body — step content -->
|
|
193
196
|
<div class="pw-shell__body">
|
|
194
197
|
<ng-container *ngFor="let stepDir of stepDirectives">
|
|
195
|
-
|
|
198
|
+
<!-- Match by formId first (inner step of a StepChoice), then stepId -->
|
|
199
|
+
<ng-container *ngIf="stepDir.stepId === (s.formId ?? s.stepId)">
|
|
196
200
|
<ng-container *ngTemplateOutlet="stepDir.templateRef; injector: shellInjector"></ng-container>
|
|
197
201
|
</ng-container>
|
|
198
202
|
</ng-container>
|
|
@@ -205,6 +209,13 @@ export class PathShellFooterDirective {
|
|
|
205
209
|
</li>
|
|
206
210
|
</ul>
|
|
207
211
|
|
|
212
|
+
<!-- Warning messages — non-blocking, shown immediately (no hasAttemptedNext gate) -->
|
|
213
|
+
<ul class="pw-shell__warnings" *ngIf="validationDisplay !== 'inline' && warningEntries(s).length > 0">
|
|
214
|
+
<li *ngFor="let entry of warningEntries(s)" class="pw-shell__warnings-item">
|
|
215
|
+
<span *ngIf="entry[0] !== '_'" class="pw-shell__warnings-label">{{ formatFieldKey(entry[0]) }}</span>{{ entry[1] }}
|
|
216
|
+
</li>
|
|
217
|
+
</ul>
|
|
218
|
+
|
|
208
219
|
<!-- Footer — custom or default navigation buttons -->
|
|
209
220
|
<ng-container *ngIf="customFooter; else defaultFooter">
|
|
210
221
|
<ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
|
|
@@ -251,9 +262,24 @@ export class PathShellFooterDirective {
|
|
|
251
262
|
</div>
|
|
252
263
|
`
|
|
253
264
|
})
|
|
254
|
-
export class PathShellComponent implements OnInit, OnDestroy {
|
|
255
|
-
/** The path definition to run. Required. */
|
|
256
|
-
@Input(
|
|
265
|
+
export class PathShellComponent implements OnInit, OnChanges, OnDestroy {
|
|
266
|
+
/** The path definition to run. Required unless [engine] is provided. */
|
|
267
|
+
@Input() path?: PathDefinition<any>;
|
|
268
|
+
/**
|
|
269
|
+
* An externally-managed `PathEngine` to adopt — for example, the engine
|
|
270
|
+
* returned by `restoreOrStart()` from `@daltonr/pathwrite-store`.
|
|
271
|
+
*
|
|
272
|
+
* When provided the shell skips `autoStart` and immediately reflects the
|
|
273
|
+
* engine's current state. Gate the shell's existence on the engine being
|
|
274
|
+
* ready using `@if (engine)` so the input is always non-null on mount:
|
|
275
|
+
*
|
|
276
|
+
* ```html
|
|
277
|
+
* @if (engine) {
|
|
278
|
+
* <pw-shell [engine]="engine" [path]="myPath" ...></pw-shell>
|
|
279
|
+
* }
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
@Input() engine?: PathEngine;
|
|
257
283
|
/** Initial data merged into the path engine on start. */
|
|
258
284
|
@Input() initialData: PathData = {};
|
|
259
285
|
/** Start the path automatically on ngOnInit. Set to false to call doStart() manually. */
|
|
@@ -283,7 +309,7 @@ export class PathShellComponent implements OnInit, OnDestroy {
|
|
|
283
309
|
* - `"inline"`: Suppress the summary — handle errors inside the step template instead.
|
|
284
310
|
* - `"both"`: Render the shell summary AND whatever the step template renders.
|
|
285
311
|
*/
|
|
286
|
-
@Input() validationDisplay: "summary" | "inline" | "both" = "
|
|
312
|
+
@Input() validationDisplay: "summary" | "inline" | "both" = "summary";
|
|
287
313
|
/**
|
|
288
314
|
* Controls how progress bars are arranged when a sub-path is active.
|
|
289
315
|
* - "merged" (default): Root and sub-path bars in one card.
|
|
@@ -293,9 +319,9 @@ export class PathShellComponent implements OnInit, OnDestroy {
|
|
|
293
319
|
*/
|
|
294
320
|
@Input() progressLayout: ProgressLayout = "merged";
|
|
295
321
|
|
|
296
|
-
@Output()
|
|
297
|
-
@Output()
|
|
298
|
-
@Output()
|
|
322
|
+
@Output() complete = new EventEmitter<PathData>();
|
|
323
|
+
@Output() cancel = new EventEmitter<PathData>();
|
|
324
|
+
@Output() event = new EventEmitter<PathEvent>();
|
|
299
325
|
|
|
300
326
|
@ContentChildren(PathStepDirective) stepDirectives!: QueryList<PathStepDirective>;
|
|
301
327
|
@ContentChild(PathShellHeaderDirective) customHeader?: PathShellHeaderDirective;
|
|
@@ -315,19 +341,25 @@ export class PathShellComponent implements OnInit, OnDestroy {
|
|
|
315
341
|
goToStep: (id) => this.facade.goToStep(id),
|
|
316
342
|
goToStepChecked: (id) => this.facade.goToStepChecked(id),
|
|
317
343
|
setData: (key, value) => this.facade.setData(key, value as never),
|
|
318
|
-
restart: () => this.facade.restart(
|
|
344
|
+
restart: () => this.facade.restart(),
|
|
319
345
|
};
|
|
320
346
|
|
|
321
347
|
private readonly destroy$ = new Subject<void>();
|
|
322
348
|
|
|
349
|
+
public ngOnChanges(changes: SimpleChanges): void {
|
|
350
|
+
if (changes['engine'] && this.engine) {
|
|
351
|
+
this.facade.adoptEngine(this.engine);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
323
355
|
public ngOnInit(): void {
|
|
324
356
|
this.facade.events$.pipe(takeUntil(this.destroy$)).subscribe((event) => {
|
|
325
|
-
this.
|
|
326
|
-
if (event.type === "completed") this.
|
|
327
|
-
if (event.type === "cancelled") this.
|
|
357
|
+
this.event.emit(event);
|
|
358
|
+
if (event.type === "completed") this.complete.emit(event.data);
|
|
359
|
+
if (event.type === "cancelled") this.cancel.emit(event.data);
|
|
328
360
|
});
|
|
329
361
|
|
|
330
|
-
if (this.autoStart) {
|
|
362
|
+
if (this.autoStart && !this.engine) {
|
|
331
363
|
this.doStart();
|
|
332
364
|
}
|
|
333
365
|
}
|
|
@@ -338,6 +370,7 @@ export class PathShellComponent implements OnInit, OnDestroy {
|
|
|
338
370
|
}
|
|
339
371
|
|
|
340
372
|
public doStart(): void {
|
|
373
|
+
if (!this.path) throw new Error('[pw-shell] [path] is required when no [engine] is provided');
|
|
341
374
|
this.started = true;
|
|
342
375
|
this.facade.start(this.path, this.initialData);
|
|
343
376
|
}
|
|
@@ -352,12 +385,17 @@ export class PathShellComponent implements OnInit, OnDestroy {
|
|
|
352
385
|
* ```
|
|
353
386
|
*/
|
|
354
387
|
public restart(): Promise<void> {
|
|
355
|
-
return this.facade.restart(
|
|
388
|
+
return this.facade.restart();
|
|
356
389
|
}
|
|
357
390
|
|
|
358
|
-
/** Returns Object.entries(s.
|
|
391
|
+
/** Returns Object.entries(s.fieldErrors) for use in *ngFor. */
|
|
359
392
|
protected fieldEntries(s: PathSnapshot): [string, string][] {
|
|
360
|
-
return Object.entries(s.
|
|
393
|
+
return Object.entries(s.fieldErrors) as [string, string][];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Returns Object.entries(s.fieldWarnings) for use in *ngFor. */
|
|
397
|
+
protected warningEntries(s: PathSnapshot): [string, string][] {
|
|
398
|
+
return Object.entries(s.fieldWarnings) as [string, string][];
|
|
361
399
|
}
|
|
362
400
|
|
|
363
401
|
/** Resolves "auto" footerLayout based on snapshot. Single-step top-level → "form", otherwise → "wizard". */
|