@daltonr/pathwrite-angular 0.2.1 → 0.3.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 CHANGED
@@ -41,7 +41,7 @@ export class MyComponent {
41
41
  | Method | Description |
42
42
  |--------|-------------|
43
43
  | `start(definition, data?)` | Start or re-start a path. |
44
- | `startSubPath(definition, data?)` | Push a sub-path. Requires an active path. |
44
+ | `startSubPath(definition, data?, meta?)` | Push a sub-path. Requires an active path. `meta` is returned unchanged to `onSubPathComplete` / `onSubPathCancel`. |
45
45
  | `next()` | Advance one step. Completes the path on the last step. |
46
46
  | `previous()` | Go back one step. No-op when already on the first step of a top-level path. |
47
47
  | `cancel()` | Cancel the active path (or sub-path). |
@@ -199,7 +199,12 @@ The Angular adapter ships an optional shell component that renders a complete pr
199
199
  The shell lives in a separate entry point so that headless-only usage does not pull in the Angular compiler:
200
200
 
201
201
  ```typescript
202
- import { PathShellComponent, PathStepDirective } from "@daltonr/pathwrite-angular/shell";
202
+ import {
203
+ PathShellComponent,
204
+ PathStepDirective,
205
+ PathShellHeaderDirective,
206
+ PathShellFooterDirective,
207
+ } from "@daltonr/pathwrite-angular/shell";
203
208
  ```
204
209
 
205
210
  ### Usage
@@ -283,6 +288,52 @@ export class MyComponent {
283
288
  | `(cancelled)` | `PathData` | Emitted when the path is cancelled. |
284
289
  | `(pathEvent)` | `PathEvent` | Emitted for every engine event. |
285
290
 
291
+ ### Customising the header and footer
292
+
293
+ Use `pwShellHeader` and `pwShellFooter` directives to replace the built-in progress bar or navigation buttons with your own templates. Both are declared on `<ng-template>` elements inside the shell.
294
+
295
+ **`pwShellHeader`** — receives the current `PathSnapshot` as the implicit template variable:
296
+
297
+ ```typescript
298
+ @Component({
299
+ imports: [PathShellComponent, PathStepDirective, PathShellHeaderDirective],
300
+ template: `
301
+ <pw-shell [path]="myPath">
302
+ <ng-template pwShellHeader let-s>
303
+ <p>Step {{ s.stepIndex + 1 }} of {{ s.stepCount }} — {{ s.stepTitle }}</p>
304
+ </ng-template>
305
+ <ng-template pwStep="details"><app-details-form /></ng-template>
306
+ <ng-template pwStep="review"><app-review-panel /></ng-template>
307
+ </pw-shell>
308
+ `
309
+ })
310
+ export class MyComponent { ... }
311
+ ```
312
+
313
+ **`pwShellFooter`** — receives the snapshot as the implicit variable and an `actions` variable with all navigation callbacks:
314
+
315
+ ```typescript
316
+ @Component({
317
+ imports: [PathShellComponent, PathStepDirective, PathShellFooterDirective],
318
+ template: `
319
+ <pw-shell [path]="myPath">
320
+ <ng-template pwShellFooter let-s let-actions="actions">
321
+ <button (click)="actions.previous()" [disabled]="s.isFirstStep || s.isNavigating">Back</button>
322
+ <button (click)="actions.next()" [disabled]="!s.canMoveNext || s.isNavigating">
323
+ {{ s.isLastStep ? 'Finish' : 'Next' }}
324
+ </button>
325
+ </ng-template>
326
+ <ng-template pwStep="details"><app-details-form /></ng-template>
327
+ </pw-shell>
328
+ `
329
+ })
330
+ export class MyComponent { ... }
331
+ ```
332
+
333
+ `actions` (`PathShellActions`) contains: `next`, `previous`, `cancel`, `goToStep`, `goToStepChecked`, `setData`. All return `Promise<void>`.
334
+
335
+ Both directives can be combined. Only the sections you override are replaced — a custom header still shows the default footer, and vice versa.
336
+
286
337
  ---
287
338
 
288
339
  ## Styling
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
  ngOnDestroy(): void;
31
31
  start(path: PathDefinition<any>, initialData?: PathData): Promise<void>;
32
- startSubPath(path: PathDefinition<any>, initialData?: PathData): Promise<void>;
32
+ startSubPath(path: PathDefinition<any>, initialData?: PathData, meta?: Record<string, unknown>): Promise<void>;
33
33
  next(): Promise<void>;
34
34
  previous(): Promise<void>;
35
35
  cancel(): Promise<void>;
package/dist/index.js CHANGED
@@ -46,8 +46,8 @@ export class PathFacade {
46
46
  start(path, initialData = {}) {
47
47
  return this.engine.start(path, initialData);
48
48
  }
49
- startSubPath(path, initialData = {}) {
50
- return this.engine.startSubPath(path, initialData);
49
+ startSubPath(path, initialData = {}, meta) {
50
+ return this.engine.startSubPath(path, initialData, meta);
51
51
  }
52
52
  next() {
53
53
  return this.engine.next();
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/dist/shell.d.ts CHANGED
@@ -1,7 +1,20 @@
1
1
  import { TemplateRef, EventEmitter, QueryList, OnInit, OnDestroy, Injector } from "@angular/core";
2
- import { PathData, PathDefinition, PathEvent } from "@daltonr/pathwrite-core";
2
+ import { PathData, PathDefinition, PathEvent, PathSnapshot } from "@daltonr/pathwrite-core";
3
3
  import { PathFacade } from "./index";
4
4
  import * as i0 from "@angular/core";
5
+ /**
6
+ * Navigation actions passed as template context to custom `pwShellFooter`
7
+ * templates. Mirrors what React's `renderFooter` and Vue's `#footer` slot
8
+ * receive, using promises so it is consistent with the Angular facade.
9
+ */
10
+ export interface PathShellActions {
11
+ next: () => Promise<void>;
12
+ previous: () => Promise<void>;
13
+ cancel: () => Promise<void>;
14
+ goToStep: (stepId: string) => Promise<void>;
15
+ goToStepChecked: (stepId: string) => Promise<void>;
16
+ setData: (key: string, value: unknown) => Promise<void>;
17
+ }
5
18
  /**
6
19
  * Structural directive that associates a template with a step ID.
7
20
  * Used inside `<pw-shell>` to define per-step content.
@@ -20,6 +33,56 @@ export declare class PathStepDirective {
20
33
  static ɵfac: i0.ɵɵFactoryDeclaration<PathStepDirective, never>;
21
34
  static ɵdir: i0.ɵɵDirectiveDeclaration<PathStepDirective, "[pwStep]", never, { "stepId": { "alias": "pwStep"; "required": true; }; }, {}, never, never, true, never>;
22
35
  }
36
+ /**
37
+ * Replaces the default progress header inside `<pw-shell>`.
38
+ * The template receives the current `PathSnapshot` as the implicit context.
39
+ *
40
+ * ```html
41
+ * <pw-shell [path]="myPath">
42
+ * <ng-template pwShellHeader let-s>
43
+ * <my-custom-progress [snapshot]="s" />
44
+ * </ng-template>
45
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
46
+ * </pw-shell>
47
+ * ```
48
+ */
49
+ export declare class PathShellHeaderDirective {
50
+ readonly templateRef: TemplateRef<{
51
+ $implicit: PathSnapshot;
52
+ }>;
53
+ constructor(templateRef: TemplateRef<{
54
+ $implicit: PathSnapshot;
55
+ }>);
56
+ static ɵfac: i0.ɵɵFactoryDeclaration<PathShellHeaderDirective, never>;
57
+ static ɵdir: i0.ɵɵDirectiveDeclaration<PathShellHeaderDirective, "[pwShellHeader]", never, {}, {}, never, never, true, never>;
58
+ }
59
+ /**
60
+ * Replaces the default navigation footer inside `<pw-shell>`.
61
+ * The template receives the current `PathSnapshot` as the implicit context
62
+ * and a `actions` variable containing all navigation actions.
63
+ *
64
+ * ```html
65
+ * <pw-shell [path]="myPath">
66
+ * <ng-template pwShellFooter let-s let-actions="actions">
67
+ * <button (click)="actions.previous()" [disabled]="s.isFirstStep">Back</button>
68
+ * <button (click)="actions.next()" [disabled]="!s.canMoveNext">Next</button>
69
+ * </ng-template>
70
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
71
+ * </pw-shell>
72
+ * ```
73
+ */
74
+ export declare class PathShellFooterDirective {
75
+ readonly templateRef: TemplateRef<{
76
+ $implicit: PathSnapshot;
77
+ actions: PathShellActions;
78
+ }>;
79
+ constructor(templateRef: TemplateRef<{
80
+ $implicit: PathSnapshot;
81
+ actions: PathShellActions;
82
+ }>);
83
+ static ɵfac: i0.ɵɵFactoryDeclaration<PathShellFooterDirective, never>;
84
+ static ɵdir: i0.ɵɵDirectiveDeclaration<PathShellFooterDirective, "[pwShellFooter]", never, {}, {}, never, never, true, never>;
85
+ }
23
86
  /**
24
87
  * Default UI shell component. Renders a progress indicator, step content,
25
88
  * and navigation buttons.
@@ -54,15 +117,19 @@ export declare class PathShellComponent implements OnInit, OnDestroy {
54
117
  cancelled: EventEmitter<PathData>;
55
118
  pathEvent: EventEmitter<PathEvent>;
56
119
  stepDirectives: QueryList<PathStepDirective>;
120
+ customHeader?: PathShellHeaderDirective;
121
+ customFooter?: PathShellFooterDirective;
57
122
  readonly facade: PathFacade<PathData>;
58
123
  /** The shell's own component-level injector. Passed to ngTemplateOutlet so that
59
124
  * step components can resolve PathFacade (provided by this shell) via inject(). */
60
125
  protected readonly shellInjector: Injector;
61
126
  started: boolean;
127
+ /** Navigation actions passed to custom `pwShellFooter` templates. */
128
+ protected readonly shellActions: PathShellActions;
62
129
  private readonly destroy$;
63
130
  ngOnInit(): void;
64
131
  ngOnDestroy(): void;
65
132
  doStart(): void;
66
133
  static ɵfac: i0.ɵɵFactoryDeclaration<PathShellComponent, never>;
67
- static ɵcmp: i0.ɵɵComponentDeclaration<PathShellComponent, "pw-shell", never, { "path": { "alias": "path"; "required": true; }; "initialData": { "alias": "initialData"; "required": false; }; "autoStart": { "alias": "autoStart"; "required": false; }; "backLabel": { "alias": "backLabel"; "required": false; }; "nextLabel": { "alias": "nextLabel"; "required": false; }; "finishLabel": { "alias": "finishLabel"; "required": false; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; }; "hideCancel": { "alias": "hideCancel"; "required": false; }; "hideProgress": { "alias": "hideProgress"; "required": false; }; }, { "completed": "completed"; "cancelled": "cancelled"; "pathEvent": "pathEvent"; }, ["stepDirectives"], never, true, never>;
134
+ static ɵcmp: i0.ɵɵComponentDeclaration<PathShellComponent, "pw-shell", never, { "path": { "alias": "path"; "required": true; }; "initialData": { "alias": "initialData"; "required": false; }; "autoStart": { "alias": "autoStart"; "required": false; }; "backLabel": { "alias": "backLabel"; "required": false; }; "nextLabel": { "alias": "nextLabel"; "required": false; }; "finishLabel": { "alias": "finishLabel"; "required": false; }; "cancelLabel": { "alias": "cancelLabel"; "required": false; }; "hideCancel": { "alias": "hideCancel"; "required": false; }; "hideProgress": { "alias": "hideProgress"; "required": false; }; }, { "completed": "completed"; "cancelled": "cancelled"; "pathEvent": "pathEvent"; }, ["customHeader", "customFooter", "stepDirectives"], never, true, never>;
68
135
  }
package/dist/shell.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Component, Directive, Input, Output, EventEmitter, ContentChildren, inject, Injector, ChangeDetectionStrategy } from "@angular/core";
1
+ import { Component, Directive, Input, Output, EventEmitter, ContentChild, ContentChildren, inject, Injector, ChangeDetectionStrategy } from "@angular/core";
2
2
  import { CommonModule } from "@angular/common";
3
3
  import { Subject } from "rxjs";
4
4
  import { takeUntil } from "rxjs/operators";
@@ -34,6 +34,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
34
34
  args: [{ required: true, alias: "pwStep" }]
35
35
  }] } });
36
36
  // ---------------------------------------------------------------------------
37
+ // PathShellHeaderDirective
38
+ // ---------------------------------------------------------------------------
39
+ /**
40
+ * Replaces the default progress header inside `<pw-shell>`.
41
+ * The template receives the current `PathSnapshot` as the implicit context.
42
+ *
43
+ * ```html
44
+ * <pw-shell [path]="myPath">
45
+ * <ng-template pwShellHeader let-s>
46
+ * <my-custom-progress [snapshot]="s" />
47
+ * </ng-template>
48
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
49
+ * </pw-shell>
50
+ * ```
51
+ */
52
+ export class PathShellHeaderDirective {
53
+ constructor(templateRef) {
54
+ this.templateRef = templateRef;
55
+ }
56
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellHeaderDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
57
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: PathShellHeaderDirective, isStandalone: true, selector: "[pwShellHeader]", ngImport: i0 }); }
58
+ }
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellHeaderDirective, decorators: [{
60
+ type: Directive,
61
+ args: [{ selector: "[pwShellHeader]", standalone: true }]
62
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
63
+ // ---------------------------------------------------------------------------
64
+ // PathShellFooterDirective
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Replaces the default navigation footer inside `<pw-shell>`.
68
+ * The template receives the current `PathSnapshot` as the implicit context
69
+ * and a `actions` variable containing all navigation actions.
70
+ *
71
+ * ```html
72
+ * <pw-shell [path]="myPath">
73
+ * <ng-template pwShellFooter let-s let-actions="actions">
74
+ * <button (click)="actions.previous()" [disabled]="s.isFirstStep">Back</button>
75
+ * <button (click)="actions.next()" [disabled]="!s.canMoveNext">Next</button>
76
+ * </ng-template>
77
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
78
+ * </pw-shell>
79
+ * ```
80
+ */
81
+ export class PathShellFooterDirective {
82
+ constructor(templateRef) {
83
+ this.templateRef = templateRef;
84
+ }
85
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellFooterDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
86
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: PathShellFooterDirective, isStandalone: true, selector: "[pwShellFooter]", ngImport: i0 }); }
87
+ }
88
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellFooterDirective, decorators: [{
89
+ type: Directive,
90
+ args: [{ selector: "[pwShellFooter]", standalone: true }]
91
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
92
+ // ---------------------------------------------------------------------------
37
93
  // PathShellComponent
38
94
  // ---------------------------------------------------------------------------
39
95
  /**
@@ -73,6 +129,15 @@ export class PathShellComponent {
73
129
  * step components can resolve PathFacade (provided by this shell) via inject(). */
74
130
  this.shellInjector = inject(Injector);
75
131
  this.started = false;
132
+ /** Navigation actions passed to custom `pwShellFooter` templates. */
133
+ this.shellActions = {
134
+ next: () => this.facade.next(),
135
+ previous: () => this.facade.previous(),
136
+ cancel: () => this.facade.cancel(),
137
+ goToStep: (id) => this.facade.goToStep(id),
138
+ goToStepChecked: (id) => this.facade.goToStepChecked(id),
139
+ setData: (key, value) => this.facade.setData(key, value),
140
+ };
76
141
  this.destroy$ = new Subject();
77
142
  }
78
143
  ngOnInit() {
@@ -96,7 +161,7 @@ export class PathShellComponent {
96
161
  this.facade.start(this.path, this.initialData);
97
162
  }
98
163
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
99
- 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", finishLabel: "finishLabel", cancelLabel: "cancelLabel", hideCancel: "hideCancel", hideProgress: "hideProgress" }, outputs: { completed: "completed", cancelled: "cancelled", pathEvent: "pathEvent" }, providers: [PathFacade], queries: [{ propertyName: "stepDirectives", predicate: PathStepDirective }], ngImport: i0, template: `
164
+ 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", finishLabel: "finishLabel", cancelLabel: "cancelLabel", hideCancel: "hideCancel", hideProgress: "hideProgress" }, outputs: { completed: "completed", cancelled: "cancelled", pathEvent: "pathEvent" }, providers: [PathFacade], queries: [{ propertyName: "customHeader", first: true, predicate: PathShellHeaderDirective, descendants: true }, { propertyName: "customFooter", first: true, predicate: PathShellFooterDirective, descendants: true }, { propertyName: "stepDirectives", predicate: PathStepDirective }], ngImport: i0, template: `
100
165
  <!-- Empty state -->
101
166
  <div class="pw-shell" *ngIf="!(facade.state$ | async)">
102
167
  <div class="pw-shell__empty" *ngIf="!started">
@@ -107,22 +172,27 @@ export class PathShellComponent {
107
172
 
108
173
  <!-- Active path -->
109
174
  <div class="pw-shell" *ngIf="facade.state$ | async as s">
110
- <!-- Header — progress indicator -->
111
- <div class="pw-shell__header" *ngIf="!hideProgress">
112
- <div class="pw-shell__steps">
113
- <div
114
- *ngFor="let step of s.steps; let i = index"
115
- class="pw-shell__step"
116
- [ngClass]="'pw-shell__step--' + step.status"
117
- >
118
- <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
119
- <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
175
+ <!-- Header — custom or default progress indicator -->
176
+ <ng-container *ngIf="customHeader; else defaultHeader">
177
+ <ng-container *ngTemplateOutlet="customHeader.templateRef; context: { $implicit: s }"></ng-container>
178
+ </ng-container>
179
+ <ng-template #defaultHeader>
180
+ <div class="pw-shell__header" *ngIf="!hideProgress">
181
+ <div class="pw-shell__steps">
182
+ <div
183
+ *ngFor="let step of s.steps; let i = index"
184
+ class="pw-shell__step"
185
+ [ngClass]="'pw-shell__step--' + step.status"
186
+ >
187
+ <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
188
+ <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
189
+ </div>
190
+ </div>
191
+ <div class="pw-shell__track">
192
+ <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
120
193
  </div>
121
194
  </div>
122
- <div class="pw-shell__track">
123
- <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
124
- </div>
125
- </div>
195
+ </ng-template>
126
196
 
127
197
  <!-- Body — step content -->
128
198
  <div class="pw-shell__body">
@@ -138,33 +208,38 @@ export class PathShellComponent {
138
208
  <li *ngFor="let msg of s.validationMessages" class="pw-shell__validation-item">{{ msg }}</li>
139
209
  </ul>
140
210
 
141
- <!-- Footer — navigation buttons -->
142
- <div class="pw-shell__footer">
143
- <div class="pw-shell__footer-left">
144
- <button
145
- *ngIf="!s.isFirstStep"
146
- type="button"
147
- class="pw-shell__btn pw-shell__btn--back"
148
- [disabled]="s.isNavigating || !s.canMovePrevious"
149
- (click)="facade.previous()"
150
- >{{ backLabel }}</button>
151
- </div>
152
- <div class="pw-shell__footer-right">
153
- <button
154
- *ngIf="!hideCancel"
155
- type="button"
156
- class="pw-shell__btn pw-shell__btn--cancel"
157
- [disabled]="s.isNavigating"
158
- (click)="facade.cancel()"
159
- >{{ cancelLabel }}</button>
160
- <button
161
- type="button"
162
- class="pw-shell__btn pw-shell__btn--next"
163
- [disabled]="s.isNavigating || !s.canMoveNext"
164
- (click)="facade.next()"
165
- >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
211
+ <!-- Footer — custom or default navigation buttons -->
212
+ <ng-container *ngIf="customFooter; else defaultFooter">
213
+ <ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
214
+ </ng-container>
215
+ <ng-template #defaultFooter>
216
+ <div class="pw-shell__footer">
217
+ <div class="pw-shell__footer-left">
218
+ <button
219
+ *ngIf="!s.isFirstStep"
220
+ type="button"
221
+ class="pw-shell__btn pw-shell__btn--back"
222
+ [disabled]="s.isNavigating || !s.canMovePrevious"
223
+ (click)="facade.previous()"
224
+ >{{ backLabel }}</button>
225
+ </div>
226
+ <div class="pw-shell__footer-right">
227
+ <button
228
+ *ngIf="!hideCancel"
229
+ type="button"
230
+ class="pw-shell__btn pw-shell__btn--cancel"
231
+ [disabled]="s.isNavigating"
232
+ (click)="facade.cancel()"
233
+ >{{ cancelLabel }}</button>
234
+ <button
235
+ type="button"
236
+ class="pw-shell__btn pw-shell__btn--next"
237
+ [disabled]="s.isNavigating || !s.canMoveNext"
238
+ (click)="facade.next()"
239
+ >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
240
+ </div>
166
241
  </div>
167
- </div>
242
+ </ng-template>
168
243
  </div>
169
244
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
170
245
  }
@@ -187,22 +262,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
187
262
 
188
263
  <!-- Active path -->
189
264
  <div class="pw-shell" *ngIf="facade.state$ | async as s">
190
- <!-- Header — progress indicator -->
191
- <div class="pw-shell__header" *ngIf="!hideProgress">
192
- <div class="pw-shell__steps">
193
- <div
194
- *ngFor="let step of s.steps; let i = index"
195
- class="pw-shell__step"
196
- [ngClass]="'pw-shell__step--' + step.status"
197
- >
198
- <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
199
- <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
265
+ <!-- Header — custom or default progress indicator -->
266
+ <ng-container *ngIf="customHeader; else defaultHeader">
267
+ <ng-container *ngTemplateOutlet="customHeader.templateRef; context: { $implicit: s }"></ng-container>
268
+ </ng-container>
269
+ <ng-template #defaultHeader>
270
+ <div class="pw-shell__header" *ngIf="!hideProgress">
271
+ <div class="pw-shell__steps">
272
+ <div
273
+ *ngFor="let step of s.steps; let i = index"
274
+ class="pw-shell__step"
275
+ [ngClass]="'pw-shell__step--' + step.status"
276
+ >
277
+ <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
278
+ <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
279
+ </div>
280
+ </div>
281
+ <div class="pw-shell__track">
282
+ <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
200
283
  </div>
201
284
  </div>
202
- <div class="pw-shell__track">
203
- <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
204
- </div>
205
- </div>
285
+ </ng-template>
206
286
 
207
287
  <!-- Body — step content -->
208
288
  <div class="pw-shell__body">
@@ -218,33 +298,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
218
298
  <li *ngFor="let msg of s.validationMessages" class="pw-shell__validation-item">{{ msg }}</li>
219
299
  </ul>
220
300
 
221
- <!-- Footer — navigation buttons -->
222
- <div class="pw-shell__footer">
223
- <div class="pw-shell__footer-left">
224
- <button
225
- *ngIf="!s.isFirstStep"
226
- type="button"
227
- class="pw-shell__btn pw-shell__btn--back"
228
- [disabled]="s.isNavigating || !s.canMovePrevious"
229
- (click)="facade.previous()"
230
- >{{ backLabel }}</button>
231
- </div>
232
- <div class="pw-shell__footer-right">
233
- <button
234
- *ngIf="!hideCancel"
235
- type="button"
236
- class="pw-shell__btn pw-shell__btn--cancel"
237
- [disabled]="s.isNavigating"
238
- (click)="facade.cancel()"
239
- >{{ cancelLabel }}</button>
240
- <button
241
- type="button"
242
- class="pw-shell__btn pw-shell__btn--next"
243
- [disabled]="s.isNavigating || !s.canMoveNext"
244
- (click)="facade.next()"
245
- >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
301
+ <!-- Footer — custom or default navigation buttons -->
302
+ <ng-container *ngIf="customFooter; else defaultFooter">
303
+ <ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
304
+ </ng-container>
305
+ <ng-template #defaultFooter>
306
+ <div class="pw-shell__footer">
307
+ <div class="pw-shell__footer-left">
308
+ <button
309
+ *ngIf="!s.isFirstStep"
310
+ type="button"
311
+ class="pw-shell__btn pw-shell__btn--back"
312
+ [disabled]="s.isNavigating || !s.canMovePrevious"
313
+ (click)="facade.previous()"
314
+ >{{ backLabel }}</button>
315
+ </div>
316
+ <div class="pw-shell__footer-right">
317
+ <button
318
+ *ngIf="!hideCancel"
319
+ type="button"
320
+ class="pw-shell__btn pw-shell__btn--cancel"
321
+ [disabled]="s.isNavigating"
322
+ (click)="facade.cancel()"
323
+ >{{ cancelLabel }}</button>
324
+ <button
325
+ type="button"
326
+ class="pw-shell__btn pw-shell__btn--next"
327
+ [disabled]="s.isNavigating || !s.canMoveNext"
328
+ (click)="facade.next()"
329
+ >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
330
+ </div>
246
331
  </div>
247
- </div>
332
+ </ng-template>
248
333
  </div>
249
334
  `
250
335
  }]
@@ -276,5 +361,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
276
361
  }], stepDirectives: [{
277
362
  type: ContentChildren,
278
363
  args: [PathStepDirective]
364
+ }], customHeader: [{
365
+ type: ContentChild,
366
+ args: [PathShellHeaderDirective]
367
+ }], customFooter: [{
368
+ type: ContentChild,
369
+ args: [PathShellFooterDirective]
279
370
  }] } });
280
371
  //# sourceMappingURL=shell.js.map
package/dist/shell.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"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"}
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.2.1",
3
+ "version": "0.3.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.",
@@ -60,7 +60,7 @@
60
60
  "@angular/compiler-cli": "^17.0.0"
61
61
  },
62
62
  "dependencies": {
63
- "@daltonr/pathwrite-core": "^0.2.1"
63
+ "@daltonr/pathwrite-core": "^0.3.0"
64
64
  },
65
65
  "publishConfig": {
66
66
  "access": "public"
package/src/index.ts CHANGED
@@ -58,8 +58,8 @@ export class PathFacade<TData extends PathData = PathData> implements OnDestroy
58
58
  return this.engine.start(path, initialData);
59
59
  }
60
60
 
61
- public startSubPath(path: PathDefinition<any>, initialData: PathData = {}): Promise<void> {
62
- return this.engine.startSubPath(path, initialData);
61
+ public startSubPath(path: PathDefinition<any>, initialData: PathData = {}, meta?: Record<string, unknown>): Promise<void> {
62
+ return this.engine.startSubPath(path, initialData, meta);
63
63
  }
64
64
 
65
65
  public next(): Promise<void> {
package/src/shell.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  Input,
6
6
  Output,
7
7
  EventEmitter,
8
+ ContentChild,
8
9
  ContentChildren,
9
10
  QueryList,
10
11
  OnInit,
@@ -19,10 +20,29 @@ import { takeUntil } from "rxjs/operators";
19
20
  import {
20
21
  PathData,
21
22
  PathDefinition,
22
- PathEvent
23
+ PathEvent,
24
+ PathSnapshot
23
25
  } from "@daltonr/pathwrite-core";
24
26
  import { PathFacade } from "./index";
25
27
 
28
+ // ---------------------------------------------------------------------------
29
+ // PathShellActions
30
+ // ---------------------------------------------------------------------------
31
+
32
+ /**
33
+ * Navigation actions passed as template context to custom `pwShellFooter`
34
+ * templates. Mirrors what React's `renderFooter` and Vue's `#footer` slot
35
+ * receive, using promises so it is consistent with the Angular facade.
36
+ */
37
+ export interface PathShellActions {
38
+ next: () => Promise<void>;
39
+ previous: () => Promise<void>;
40
+ cancel: () => Promise<void>;
41
+ goToStep: (stepId: string) => Promise<void>;
42
+ goToStepChecked: (stepId: string) => Promise<void>;
43
+ setData: (key: string, value: unknown) => Promise<void>;
44
+ }
45
+
26
46
  // ---------------------------------------------------------------------------
27
47
  // PathStepDirective
28
48
  // ---------------------------------------------------------------------------
@@ -44,6 +64,56 @@ export class PathStepDirective {
44
64
  public constructor(public readonly templateRef: TemplateRef<unknown>) {}
45
65
  }
46
66
 
67
+ // ---------------------------------------------------------------------------
68
+ // PathShellHeaderDirective
69
+ // ---------------------------------------------------------------------------
70
+
71
+ /**
72
+ * Replaces the default progress header inside `<pw-shell>`.
73
+ * The template receives the current `PathSnapshot` as the implicit context.
74
+ *
75
+ * ```html
76
+ * <pw-shell [path]="myPath">
77
+ * <ng-template pwShellHeader let-s>
78
+ * <my-custom-progress [snapshot]="s" />
79
+ * </ng-template>
80
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
81
+ * </pw-shell>
82
+ * ```
83
+ */
84
+ @Directive({ selector: "[pwShellHeader]", standalone: true })
85
+ export class PathShellHeaderDirective {
86
+ public constructor(
87
+ public readonly templateRef: TemplateRef<{ $implicit: PathSnapshot }>
88
+ ) {}
89
+ }
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // PathShellFooterDirective
93
+ // ---------------------------------------------------------------------------
94
+
95
+ /**
96
+ * Replaces the default navigation footer inside `<pw-shell>`.
97
+ * The template receives the current `PathSnapshot` as the implicit context
98
+ * and a `actions` variable containing all navigation actions.
99
+ *
100
+ * ```html
101
+ * <pw-shell [path]="myPath">
102
+ * <ng-template pwShellFooter let-s let-actions="actions">
103
+ * <button (click)="actions.previous()" [disabled]="s.isFirstStep">Back</button>
104
+ * <button (click)="actions.next()" [disabled]="!s.canMoveNext">Next</button>
105
+ * </ng-template>
106
+ * <ng-template pwStep="details"><app-details-form /></ng-template>
107
+ * </pw-shell>
108
+ * ```
109
+ */
110
+ @Directive({ selector: "[pwShellFooter]", standalone: true })
111
+ export class PathShellFooterDirective {
112
+ public constructor(
113
+ public readonly templateRef: TemplateRef<{ $implicit: PathSnapshot; actions: PathShellActions }>
114
+ ) {}
115
+ }
116
+
47
117
  // ---------------------------------------------------------------------------
48
118
  // PathShellComponent
49
119
  // ---------------------------------------------------------------------------
@@ -76,22 +146,27 @@ export class PathStepDirective {
76
146
 
77
147
  <!-- Active path -->
78
148
  <div class="pw-shell" *ngIf="facade.state$ | async as s">
79
- <!-- Header — progress indicator -->
80
- <div class="pw-shell__header" *ngIf="!hideProgress">
81
- <div class="pw-shell__steps">
82
- <div
83
- *ngFor="let step of s.steps; let i = index"
84
- class="pw-shell__step"
85
- [ngClass]="'pw-shell__step--' + step.status"
86
- >
87
- <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
88
- <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
149
+ <!-- Header — custom or default progress indicator -->
150
+ <ng-container *ngIf="customHeader; else defaultHeader">
151
+ <ng-container *ngTemplateOutlet="customHeader.templateRef; context: { $implicit: s }"></ng-container>
152
+ </ng-container>
153
+ <ng-template #defaultHeader>
154
+ <div class="pw-shell__header" *ngIf="!hideProgress">
155
+ <div class="pw-shell__steps">
156
+ <div
157
+ *ngFor="let step of s.steps; let i = index"
158
+ class="pw-shell__step"
159
+ [ngClass]="'pw-shell__step--' + step.status"
160
+ >
161
+ <span class="pw-shell__step-dot">{{ step.status === 'completed' ? '✓' : (i + 1) }}</span>
162
+ <span class="pw-shell__step-label">{{ step.title ?? step.id }}</span>
163
+ </div>
164
+ </div>
165
+ <div class="pw-shell__track">
166
+ <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
89
167
  </div>
90
168
  </div>
91
- <div class="pw-shell__track">
92
- <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
93
- </div>
94
- </div>
169
+ </ng-template>
95
170
 
96
171
  <!-- Body — step content -->
97
172
  <div class="pw-shell__body">
@@ -107,33 +182,38 @@ export class PathStepDirective {
107
182
  <li *ngFor="let msg of s.validationMessages" class="pw-shell__validation-item">{{ msg }}</li>
108
183
  </ul>
109
184
 
110
- <!-- Footer — navigation buttons -->
111
- <div class="pw-shell__footer">
112
- <div class="pw-shell__footer-left">
113
- <button
114
- *ngIf="!s.isFirstStep"
115
- type="button"
116
- class="pw-shell__btn pw-shell__btn--back"
117
- [disabled]="s.isNavigating || !s.canMovePrevious"
118
- (click)="facade.previous()"
119
- >{{ backLabel }}</button>
120
- </div>
121
- <div class="pw-shell__footer-right">
122
- <button
123
- *ngIf="!hideCancel"
124
- type="button"
125
- class="pw-shell__btn pw-shell__btn--cancel"
126
- [disabled]="s.isNavigating"
127
- (click)="facade.cancel()"
128
- >{{ cancelLabel }}</button>
129
- <button
130
- type="button"
131
- class="pw-shell__btn pw-shell__btn--next"
132
- [disabled]="s.isNavigating || !s.canMoveNext"
133
- (click)="facade.next()"
134
- >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
185
+ <!-- Footer — custom or default navigation buttons -->
186
+ <ng-container *ngIf="customFooter; else defaultFooter">
187
+ <ng-container *ngTemplateOutlet="customFooter.templateRef; context: { $implicit: s, actions: shellActions }"></ng-container>
188
+ </ng-container>
189
+ <ng-template #defaultFooter>
190
+ <div class="pw-shell__footer">
191
+ <div class="pw-shell__footer-left">
192
+ <button
193
+ *ngIf="!s.isFirstStep"
194
+ type="button"
195
+ class="pw-shell__btn pw-shell__btn--back"
196
+ [disabled]="s.isNavigating || !s.canMovePrevious"
197
+ (click)="facade.previous()"
198
+ >{{ backLabel }}</button>
199
+ </div>
200
+ <div class="pw-shell__footer-right">
201
+ <button
202
+ *ngIf="!hideCancel"
203
+ type="button"
204
+ class="pw-shell__btn pw-shell__btn--cancel"
205
+ [disabled]="s.isNavigating"
206
+ (click)="facade.cancel()"
207
+ >{{ cancelLabel }}</button>
208
+ <button
209
+ type="button"
210
+ class="pw-shell__btn pw-shell__btn--next"
211
+ [disabled]="s.isNavigating || !s.canMoveNext"
212
+ (click)="facade.next()"
213
+ >{{ s.isLastStep ? finishLabel : nextLabel }}</button>
214
+ </div>
135
215
  </div>
136
- </div>
216
+ </ng-template>
137
217
  </div>
138
218
  `
139
219
  })
@@ -162,6 +242,8 @@ export class PathShellComponent implements OnInit, OnDestroy {
162
242
  @Output() pathEvent = new EventEmitter<PathEvent>();
163
243
 
164
244
  @ContentChildren(PathStepDirective) stepDirectives!: QueryList<PathStepDirective>;
245
+ @ContentChild(PathShellHeaderDirective) customHeader?: PathShellHeaderDirective;
246
+ @ContentChild(PathShellFooterDirective) customFooter?: PathShellFooterDirective;
165
247
 
166
248
  public readonly facade = inject(PathFacade);
167
249
  /** The shell's own component-level injector. Passed to ngTemplateOutlet so that
@@ -169,6 +251,16 @@ export class PathShellComponent implements OnInit, OnDestroy {
169
251
  protected readonly shellInjector = inject(Injector);
170
252
  public started = false;
171
253
 
254
+ /** Navigation actions passed to custom `pwShellFooter` templates. */
255
+ protected readonly shellActions: PathShellActions = {
256
+ next: () => this.facade.next(),
257
+ previous: () => this.facade.previous(),
258
+ cancel: () => this.facade.cancel(),
259
+ goToStep: (id) => this.facade.goToStep(id),
260
+ goToStepChecked: (id) => this.facade.goToStepChecked(id),
261
+ setData: (key, value) => this.facade.setData(key, value as never),
262
+ };
263
+
172
264
  private readonly destroy$ = new Subject<void>();
173
265
 
174
266
  public ngOnInit(): void {
@@ -193,5 +285,3 @@ export class PathShellComponent implements OnInit, OnDestroy {
193
285
  this.facade.start(this.path, this.initialData);
194
286
  }
195
287
  }
196
-
197
-