@daltonr/pathwrite-angular 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/shell.js CHANGED
@@ -1,42 +1,10 @@
1
- var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
- function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
- var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
- var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
- var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
- var _, done = false;
7
- for (var i = decorators.length - 1; i >= 0; i--) {
8
- var context = {};
9
- for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
- for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
- context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
- var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
- if (kind === "accessor") {
14
- if (result === void 0) continue;
15
- if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
- if (_ = accept(result.get)) descriptor.get = _;
17
- if (_ = accept(result.set)) descriptor.set = _;
18
- if (_ = accept(result.init)) initializers.unshift(_);
19
- }
20
- else if (_ = accept(result)) {
21
- if (kind === "field") initializers.unshift(_);
22
- else descriptor[key] = _;
23
- }
24
- }
25
- if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
- done = true;
27
- };
28
- var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
- var useValue = arguments.length > 2;
30
- for (var i = 0; i < initializers.length; i++) {
31
- value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
- }
33
- return useValue ? value : void 0;
34
- };
35
- import { Component, Directive, Input, Output, EventEmitter, ContentChildren, inject, ChangeDetectionStrategy } from "@angular/core";
1
+ import { Component, Directive, Input, Output, EventEmitter, ContentChildren, inject, Injector, ChangeDetectionStrategy } from "@angular/core";
36
2
  import { CommonModule } from "@angular/common";
37
3
  import { Subject } from "rxjs";
38
4
  import { takeUntil } from "rxjs/operators";
39
5
  import { PathFacade } from "./index";
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/common";
40
8
  // ---------------------------------------------------------------------------
41
9
  // PathStepDirective
42
10
  // ---------------------------------------------------------------------------
@@ -51,35 +19,20 @@ import { PathFacade } from "./index";
51
19
  * </pw-shell>
52
20
  * ```
53
21
  */
54
- let PathStepDirective = (() => {
55
- let _classDecorators = [Directive({ selector: "[pwStep]", standalone: true })];
56
- let _classDescriptor;
57
- let _classExtraInitializers = [];
58
- let _classThis;
59
- let _stepId_decorators;
60
- let _stepId_initializers = [];
61
- let _stepId_extraInitializers = [];
62
- var PathStepDirective = class {
63
- static { _classThis = this; }
64
- static {
65
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
66
- _stepId_decorators = [Input({ required: true, alias: "pwStep" })];
67
- __esDecorate(null, null, _stepId_decorators, { kind: "field", name: "stepId", static: false, private: false, access: { has: obj => "stepId" in obj, get: obj => obj.stepId, set: (obj, value) => { obj.stepId = value; } }, metadata: _metadata }, _stepId_initializers, _stepId_extraInitializers);
68
- __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
69
- PathStepDirective = _classThis = _classDescriptor.value;
70
- if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
71
- __runInitializers(_classThis, _classExtraInitializers);
72
- }
73
- templateRef;
74
- stepId = __runInitializers(this, _stepId_initializers, void 0);
75
- constructor(templateRef) {
76
- __runInitializers(this, _stepId_extraInitializers);
77
- this.templateRef = templateRef;
78
- }
79
- };
80
- return PathStepDirective = _classThis;
81
- })();
82
- export { PathStepDirective };
22
+ export class PathStepDirective {
23
+ constructor(templateRef) {
24
+ this.templateRef = templateRef;
25
+ }
26
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathStepDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
27
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: PathStepDirective, isStandalone: true, selector: "[pwStep]", inputs: { stepId: ["pwStep", "stepId"] }, ngImport: i0 }); }
28
+ }
29
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathStepDirective, decorators: [{
30
+ type: Directive,
31
+ args: [{ selector: "[pwStep]", standalone: true }]
32
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { stepId: [{
33
+ type: Input,
34
+ args: [{ required: true, alias: "pwStep" }]
35
+ }] } });
83
36
  // ---------------------------------------------------------------------------
84
37
  // PathShellComponent
85
38
  // ---------------------------------------------------------------------------
@@ -94,14 +47,56 @@ export { PathStepDirective };
94
47
  * </pw-shell>
95
48
  * ```
96
49
  */
97
- let PathShellComponent = (() => {
98
- let _classDecorators = [Component({
99
- selector: "pw-shell",
100
- standalone: true,
101
- imports: [CommonModule],
102
- providers: [PathFacade],
103
- changeDetection: ChangeDetectionStrategy.Default,
104
- template: `
50
+ export class PathShellComponent {
51
+ constructor() {
52
+ /** Initial data merged into the path engine on start. */
53
+ this.initialData = {};
54
+ /** Start the path automatically on ngOnInit. Set to false to call doStart() manually. */
55
+ this.autoStart = true;
56
+ /** Label for the Back navigation button. */
57
+ this.backLabel = "Back";
58
+ /** Label for the Next navigation button. */
59
+ this.nextLabel = "Next";
60
+ /** Label for the Next button when on the last step. */
61
+ this.finishLabel = "Finish";
62
+ /** Label for the Cancel button. */
63
+ this.cancelLabel = "Cancel";
64
+ /** Hide the Cancel button entirely. */
65
+ this.hideCancel = false;
66
+ /** Hide the step progress indicator in the header. */
67
+ this.hideProgress = false;
68
+ this.completed = new EventEmitter();
69
+ this.cancelled = new EventEmitter();
70
+ this.pathEvent = new EventEmitter();
71
+ this.facade = inject(PathFacade);
72
+ /** The shell's own component-level injector. Passed to ngTemplateOutlet so that
73
+ * step components can resolve PathFacade (provided by this shell) via inject(). */
74
+ this.shellInjector = inject(Injector);
75
+ this.started = false;
76
+ this.destroy$ = new Subject();
77
+ }
78
+ ngOnInit() {
79
+ this.facade.events$.pipe(takeUntil(this.destroy$)).subscribe((event) => {
80
+ this.pathEvent.emit(event);
81
+ if (event.type === "completed")
82
+ this.completed.emit(event.data);
83
+ if (event.type === "cancelled")
84
+ this.cancelled.emit(event.data);
85
+ });
86
+ if (this.autoStart) {
87
+ this.doStart();
88
+ }
89
+ }
90
+ ngOnDestroy() {
91
+ this.destroy$.next();
92
+ this.destroy$.complete();
93
+ }
94
+ doStart() {
95
+ this.started = true;
96
+ this.facade.start(this.path, this.initialData);
97
+ }
98
+ 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: `
105
100
  <!-- Empty state -->
106
101
  <div class="pw-shell" *ngIf="!(facade.state$ | async)">
107
102
  <div class="pw-shell__empty" *ngIf="!started">
@@ -133,11 +128,96 @@ let PathShellComponent = (() => {
133
128
  <div class="pw-shell__body">
134
129
  <ng-container *ngFor="let stepDir of stepDirectives">
135
130
  <ng-container *ngIf="stepDir.stepId === s.stepId">
136
- <ng-container *ngTemplateOutlet="stepDir.templateRef"></ng-container>
131
+ <ng-container *ngTemplateOutlet="stepDir.templateRef; injector: shellInjector"></ng-container>
137
132
  </ng-container>
138
133
  </ng-container>
139
134
  </div>
140
135
 
136
+ <!-- Validation messages -->
137
+ <ul class="pw-shell__validation" *ngIf="s.validationMessages.length > 0">
138
+ <li *ngFor="let msg of s.validationMessages" class="pw-shell__validation-item">{{ msg }}</li>
139
+ </ul>
140
+
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>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ `, 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
+ }
171
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PathShellComponent, decorators: [{
172
+ type: Component,
173
+ args: [{
174
+ selector: "pw-shell",
175
+ standalone: true,
176
+ imports: [CommonModule],
177
+ providers: [PathFacade],
178
+ changeDetection: ChangeDetectionStrategy.Default,
179
+ template: `
180
+ <!-- Empty state -->
181
+ <div class="pw-shell" *ngIf="!(facade.state$ | async)">
182
+ <div class="pw-shell__empty" *ngIf="!started">
183
+ <p>No active path.</p>
184
+ <button *ngIf="!autoStart" type="button" class="pw-shell__start-btn" (click)="doStart()">Start</button>
185
+ </div>
186
+ </div>
187
+
188
+ <!-- Active path -->
189
+ <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>
200
+ </div>
201
+ </div>
202
+ <div class="pw-shell__track">
203
+ <div class="pw-shell__track-fill" [style.width.%]="s.progress * 100"></div>
204
+ </div>
205
+ </div>
206
+
207
+ <!-- Body — step content -->
208
+ <div class="pw-shell__body">
209
+ <ng-container *ngFor="let stepDir of stepDirectives">
210
+ <ng-container *ngIf="stepDir.stepId === s.stepId">
211
+ <ng-container *ngTemplateOutlet="stepDir.templateRef; injector: shellInjector"></ng-container>
212
+ </ng-container>
213
+ </ng-container>
214
+ </div>
215
+
216
+ <!-- Validation messages -->
217
+ <ul class="pw-shell__validation" *ngIf="s.validationMessages.length > 0">
218
+ <li *ngFor="let msg of s.validationMessages" class="pw-shell__validation-item">{{ msg }}</li>
219
+ </ul>
220
+
141
221
  <!-- Footer — navigation buttons -->
142
222
  <div class="pw-shell__footer">
143
223
  <div class="pw-shell__footer-left">
@@ -167,122 +247,34 @@ let PathShellComponent = (() => {
167
247
  </div>
168
248
  </div>
169
249
  `
170
- })];
171
- let _classDescriptor;
172
- let _classExtraInitializers = [];
173
- let _classThis;
174
- let _path_decorators;
175
- let _path_initializers = [];
176
- let _path_extraInitializers = [];
177
- let _initialData_decorators;
178
- let _initialData_initializers = [];
179
- let _initialData_extraInitializers = [];
180
- let _autoStart_decorators;
181
- let _autoStart_initializers = [];
182
- let _autoStart_extraInitializers = [];
183
- let _backLabel_decorators;
184
- let _backLabel_initializers = [];
185
- let _backLabel_extraInitializers = [];
186
- let _nextLabel_decorators;
187
- let _nextLabel_initializers = [];
188
- let _nextLabel_extraInitializers = [];
189
- let _finishLabel_decorators;
190
- let _finishLabel_initializers = [];
191
- let _finishLabel_extraInitializers = [];
192
- let _cancelLabel_decorators;
193
- let _cancelLabel_initializers = [];
194
- let _cancelLabel_extraInitializers = [];
195
- let _hideCancel_decorators;
196
- let _hideCancel_initializers = [];
197
- let _hideCancel_extraInitializers = [];
198
- let _hideProgress_decorators;
199
- let _hideProgress_initializers = [];
200
- let _hideProgress_extraInitializers = [];
201
- let _completed_decorators;
202
- let _completed_initializers = [];
203
- let _completed_extraInitializers = [];
204
- let _cancelled_decorators;
205
- let _cancelled_initializers = [];
206
- let _cancelled_extraInitializers = [];
207
- let _pathEvent_decorators;
208
- let _pathEvent_initializers = [];
209
- let _pathEvent_extraInitializers = [];
210
- let _stepDirectives_decorators;
211
- let _stepDirectives_initializers = [];
212
- let _stepDirectives_extraInitializers = [];
213
- var PathShellComponent = class {
214
- static { _classThis = this; }
215
- static {
216
- const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
217
- _path_decorators = [Input({ required: true })];
218
- _initialData_decorators = [Input()];
219
- _autoStart_decorators = [Input()];
220
- _backLabel_decorators = [Input()];
221
- _nextLabel_decorators = [Input()];
222
- _finishLabel_decorators = [Input()];
223
- _cancelLabel_decorators = [Input()];
224
- _hideCancel_decorators = [Input()];
225
- _hideProgress_decorators = [Input()];
226
- _completed_decorators = [Output()];
227
- _cancelled_decorators = [Output()];
228
- _pathEvent_decorators = [Output()];
229
- _stepDirectives_decorators = [ContentChildren(PathStepDirective)];
230
- __esDecorate(null, null, _path_decorators, { kind: "field", name: "path", static: false, private: false, access: { has: obj => "path" in obj, get: obj => obj.path, set: (obj, value) => { obj.path = value; } }, metadata: _metadata }, _path_initializers, _path_extraInitializers);
231
- __esDecorate(null, null, _initialData_decorators, { kind: "field", name: "initialData", static: false, private: false, access: { has: obj => "initialData" in obj, get: obj => obj.initialData, set: (obj, value) => { obj.initialData = value; } }, metadata: _metadata }, _initialData_initializers, _initialData_extraInitializers);
232
- __esDecorate(null, null, _autoStart_decorators, { kind: "field", name: "autoStart", static: false, private: false, access: { has: obj => "autoStart" in obj, get: obj => obj.autoStart, set: (obj, value) => { obj.autoStart = value; } }, metadata: _metadata }, _autoStart_initializers, _autoStart_extraInitializers);
233
- __esDecorate(null, null, _backLabel_decorators, { kind: "field", name: "backLabel", static: false, private: false, access: { has: obj => "backLabel" in obj, get: obj => obj.backLabel, set: (obj, value) => { obj.backLabel = value; } }, metadata: _metadata }, _backLabel_initializers, _backLabel_extraInitializers);
234
- __esDecorate(null, null, _nextLabel_decorators, { kind: "field", name: "nextLabel", static: false, private: false, access: { has: obj => "nextLabel" in obj, get: obj => obj.nextLabel, set: (obj, value) => { obj.nextLabel = value; } }, metadata: _metadata }, _nextLabel_initializers, _nextLabel_extraInitializers);
235
- __esDecorate(null, null, _finishLabel_decorators, { kind: "field", name: "finishLabel", static: false, private: false, access: { has: obj => "finishLabel" in obj, get: obj => obj.finishLabel, set: (obj, value) => { obj.finishLabel = value; } }, metadata: _metadata }, _finishLabel_initializers, _finishLabel_extraInitializers);
236
- __esDecorate(null, null, _cancelLabel_decorators, { kind: "field", name: "cancelLabel", static: false, private: false, access: { has: obj => "cancelLabel" in obj, get: obj => obj.cancelLabel, set: (obj, value) => { obj.cancelLabel = value; } }, metadata: _metadata }, _cancelLabel_initializers, _cancelLabel_extraInitializers);
237
- __esDecorate(null, null, _hideCancel_decorators, { kind: "field", name: "hideCancel", static: false, private: false, access: { has: obj => "hideCancel" in obj, get: obj => obj.hideCancel, set: (obj, value) => { obj.hideCancel = value; } }, metadata: _metadata }, _hideCancel_initializers, _hideCancel_extraInitializers);
238
- __esDecorate(null, null, _hideProgress_decorators, { kind: "field", name: "hideProgress", static: false, private: false, access: { has: obj => "hideProgress" in obj, get: obj => obj.hideProgress, set: (obj, value) => { obj.hideProgress = value; } }, metadata: _metadata }, _hideProgress_initializers, _hideProgress_extraInitializers);
239
- __esDecorate(null, null, _completed_decorators, { kind: "field", name: "completed", static: false, private: false, access: { has: obj => "completed" in obj, get: obj => obj.completed, set: (obj, value) => { obj.completed = value; } }, metadata: _metadata }, _completed_initializers, _completed_extraInitializers);
240
- __esDecorate(null, null, _cancelled_decorators, { kind: "field", name: "cancelled", static: false, private: false, access: { has: obj => "cancelled" in obj, get: obj => obj.cancelled, set: (obj, value) => { obj.cancelled = value; } }, metadata: _metadata }, _cancelled_initializers, _cancelled_extraInitializers);
241
- __esDecorate(null, null, _pathEvent_decorators, { kind: "field", name: "pathEvent", static: false, private: false, access: { has: obj => "pathEvent" in obj, get: obj => obj.pathEvent, set: (obj, value) => { obj.pathEvent = value; } }, metadata: _metadata }, _pathEvent_initializers, _pathEvent_extraInitializers);
242
- __esDecorate(null, null, _stepDirectives_decorators, { kind: "field", name: "stepDirectives", static: false, private: false, access: { has: obj => "stepDirectives" in obj, get: obj => obj.stepDirectives, set: (obj, value) => { obj.stepDirectives = value; } }, metadata: _metadata }, _stepDirectives_initializers, _stepDirectives_extraInitializers);
243
- __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
244
- PathShellComponent = _classThis = _classDescriptor.value;
245
- if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
246
- __runInitializers(_classThis, _classExtraInitializers);
247
- }
248
- path = __runInitializers(this, _path_initializers, void 0);
249
- initialData = (__runInitializers(this, _path_extraInitializers), __runInitializers(this, _initialData_initializers, {}));
250
- autoStart = (__runInitializers(this, _initialData_extraInitializers), __runInitializers(this, _autoStart_initializers, true));
251
- backLabel = (__runInitializers(this, _autoStart_extraInitializers), __runInitializers(this, _backLabel_initializers, "Back"));
252
- nextLabel = (__runInitializers(this, _backLabel_extraInitializers), __runInitializers(this, _nextLabel_initializers, "Next"));
253
- finishLabel = (__runInitializers(this, _nextLabel_extraInitializers), __runInitializers(this, _finishLabel_initializers, "Finish"));
254
- cancelLabel = (__runInitializers(this, _finishLabel_extraInitializers), __runInitializers(this, _cancelLabel_initializers, "Cancel"));
255
- hideCancel = (__runInitializers(this, _cancelLabel_extraInitializers), __runInitializers(this, _hideCancel_initializers, false));
256
- hideProgress = (__runInitializers(this, _hideCancel_extraInitializers), __runInitializers(this, _hideProgress_initializers, false));
257
- completed = (__runInitializers(this, _hideProgress_extraInitializers), __runInitializers(this, _completed_initializers, new EventEmitter()));
258
- cancelled = (__runInitializers(this, _completed_extraInitializers), __runInitializers(this, _cancelled_initializers, new EventEmitter()));
259
- pathEvent = (__runInitializers(this, _cancelled_extraInitializers), __runInitializers(this, _pathEvent_initializers, new EventEmitter()));
260
- stepDirectives = (__runInitializers(this, _pathEvent_extraInitializers), __runInitializers(this, _stepDirectives_initializers, void 0));
261
- facade = (__runInitializers(this, _stepDirectives_extraInitializers), inject(PathFacade));
262
- started = false;
263
- destroy$ = new Subject();
264
- ngOnInit() {
265
- this.facade.events$.pipe(takeUntil(this.destroy$)).subscribe((event) => {
266
- this.pathEvent.emit(event);
267
- if (event.type === "completed")
268
- this.completed.emit(event.data);
269
- if (event.type === "cancelled")
270
- this.cancelled.emit(event.data);
271
- });
272
- if (this.autoStart) {
273
- this.doStart();
274
- }
275
- }
276
- ngOnDestroy() {
277
- this.destroy$.next();
278
- this.destroy$.complete();
279
- }
280
- doStart() {
281
- this.started = true;
282
- this.facade.start(this.path, this.initialData);
283
- }
284
- };
285
- return PathShellComponent = _classThis;
286
- })();
287
- export { PathShellComponent };
250
+ }]
251
+ }], propDecorators: { path: [{
252
+ type: Input,
253
+ args: [{ required: true }]
254
+ }], initialData: [{
255
+ type: Input
256
+ }], autoStart: [{
257
+ type: Input
258
+ }], backLabel: [{
259
+ type: Input
260
+ }], nextLabel: [{
261
+ type: Input
262
+ }], finishLabel: [{
263
+ type: Input
264
+ }], cancelLabel: [{
265
+ type: Input
266
+ }], hideCancel: [{
267
+ type: Input
268
+ }], hideProgress: [{
269
+ type: Input
270
+ }], completed: [{
271
+ type: Output
272
+ }], cancelled: [{
273
+ type: Output
274
+ }], pathEvent: [{
275
+ type: Output
276
+ }], stepDirectives: [{
277
+ type: ContentChildren,
278
+ args: [PathStepDirective]
279
+ }] } });
288
280
  //# 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.1.5",
3
+ "version": "0.2.1",
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.",
@@ -40,17 +40,27 @@
40
40
  "LICENSE"
41
41
  ],
42
42
  "scripts": {
43
- "build": "tsc -p tsconfig.json && cp ../shell.css dist/index.css",
43
+ "build": "ngc -p tsconfig.json && cp ../shell.css dist/index.css",
44
44
  "clean": "rm -rf dist tsconfig.tsbuildinfo",
45
- "prepublishOnly": "npm run clean && npm run build"
45
+ "prepublishOnly": "test -d dist && echo 'dist already built, skipping' || (npm run clean && npm run build)"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@angular/core": ">=16.0.0",
49
49
  "@angular/common": ">=16.0.0",
50
+ "@angular/forms": ">=16.0.0",
50
51
  "rxjs": "^7.0.0"
51
52
  },
53
+ "peerDependenciesMeta": {
54
+ "@angular/forms": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "devDependencies": {
59
+ "@angular/compiler": "^17.0.0",
60
+ "@angular/compiler-cli": "^17.0.0"
61
+ },
52
62
  "dependencies": {
53
- "@daltonr/pathwrite-core": "^0.1.5"
63
+ "@daltonr/pathwrite-core": "^0.2.1"
54
64
  },
55
65
  "publishConfig": {
56
66
  "access": "public"
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Injectable, OnDestroy } from "@angular/core";
1
+ import { Injectable, OnDestroy, DestroyRef, signal, Signal } from "@angular/core";
2
2
  import { BehaviorSubject, Observable, Subject } from "rxjs";
3
3
  import {
4
4
  PathData,
@@ -8,23 +8,42 @@ import {
8
8
  PathSnapshot
9
9
  } from "@daltonr/pathwrite-core";
10
10
 
11
+ /**
12
+ * Angular facade over PathEngine. Provide at component level for an isolated
13
+ * instance per component; Angular handles cleanup via ngOnDestroy.
14
+ *
15
+ * The optional generic `TData` narrows `state$`, `stateSignal`, `snapshot()`,
16
+ * and `setData()` to your data shape. It is a **type-level assertion** — no
17
+ * runtime validation is performed. Inject as `PathFacade` (untyped default)
18
+ * then cast:
19
+ *
20
+ * ```typescript
21
+ * const facade = inject(PathFacade) as PathFacade<MyData>;
22
+ * facade.snapshot()?.data.name; // typed as string (or whatever MyData defines)
23
+ * ```
24
+ */
11
25
  @Injectable()
12
- export class PathFacade implements OnDestroy {
26
+ export class PathFacade<TData extends PathData = PathData> implements OnDestroy {
13
27
  private readonly engine = new PathEngine();
14
- private readonly _state$ = new BehaviorSubject<PathSnapshot | null>(null);
28
+ private readonly _state$ = new BehaviorSubject<PathSnapshot<TData> | null>(null);
15
29
  private readonly _events$ = new Subject<PathEvent>();
16
30
  private readonly unsubscribeFromEngine: () => void;
31
+ private readonly _stateSignal = signal<PathSnapshot<TData> | null>(null);
17
32
 
18
- public readonly state$: Observable<PathSnapshot | null> = this._state$.asObservable();
33
+ public readonly state$: Observable<PathSnapshot<TData> | null> = this._state$.asObservable();
19
34
  public readonly events$: Observable<PathEvent> = this._events$.asObservable();
35
+ /** Signal version of state$. Updates on every path state change. Requires Angular 16+. */
36
+ public readonly stateSignal: Signal<PathSnapshot<TData> | null> = this._stateSignal.asReadonly();
20
37
 
21
38
  public constructor() {
22
39
  this.unsubscribeFromEngine = this.engine.subscribe((event) => {
23
40
  this._events$.next(event);
24
41
  if (event.type === "stateChanged" || event.type === "resumed") {
25
- this._state$.next(event.snapshot);
42
+ this._state$.next(event.snapshot as PathSnapshot<TData>);
43
+ this._stateSignal.set(event.snapshot as PathSnapshot<TData>);
26
44
  } else if (event.type === "completed" || event.type === "cancelled") {
27
45
  this._state$.next(null);
46
+ this._stateSignal.set(null);
28
47
  }
29
48
  });
30
49
  }
@@ -35,11 +54,11 @@ export class PathFacade implements OnDestroy {
35
54
  this._state$.complete();
36
55
  }
37
56
 
38
- public start(path: PathDefinition, initialData: PathData = {}): Promise<void> {
57
+ public start(path: PathDefinition<any>, initialData: PathData = {}): Promise<void> {
39
58
  return this.engine.start(path, initialData);
40
59
  }
41
60
 
42
- public startSubPath(path: PathDefinition, initialData: PathData = {}): Promise<void> {
61
+ public startSubPath(path: PathDefinition<any>, initialData: PathData = {}): Promise<void> {
43
62
  return this.engine.startSubPath(path, initialData);
44
63
  }
45
64
 
@@ -55,18 +74,91 @@ export class PathFacade implements OnDestroy {
55
74
  return this.engine.cancel();
56
75
  }
57
76
 
58
- public setData(key: string, value: unknown): Promise<void> {
59
- return this.engine.setData(key, value);
77
+ public setData<K extends string & keyof TData>(key: K, value: TData[K]): Promise<void> {
78
+ return this.engine.setData(key, value as unknown);
60
79
  }
61
80
 
62
81
  public goToStep(stepId: string): Promise<void> {
63
82
  return this.engine.goToStep(stepId);
64
83
  }
65
84
 
66
- public snapshot(): PathSnapshot | null {
85
+ /** Jump to a step by ID, checking the current step's canMoveNext (forward) or
86
+ * canMovePrevious (backward) guard first. Navigation is blocked if the guard
87
+ * returns false. Throws if the step ID does not exist. */
88
+ public goToStepChecked(stepId: string): Promise<void> {
89
+ return this.engine.goToStepChecked(stepId);
90
+ }
91
+
92
+ public snapshot(): PathSnapshot<TData> | null {
67
93
  return this._state$.getValue();
68
94
  }
69
95
  }
70
96
 
97
+ // ---------------------------------------------------------------------------
98
+ // Forms integration
99
+ // ---------------------------------------------------------------------------
71
100
 
101
+ /**
102
+ * Minimal interface describing what syncFormGroup needs from an Angular
103
+ * FormGroup. Typed as a duck interface so that @angular/forms is not a
104
+ * required import — any object with getRawValue() and valueChanges works.
105
+ *
106
+ * Angular's FormGroup satisfies this interface automatically.
107
+ */
108
+ export interface FormGroupLike {
109
+ /** Returns all control values including disabled ones (FormGroup.getRawValue()). */
110
+ getRawValue(): Record<string, unknown>;
111
+ /** Observable that emits whenever any control value changes. */
112
+ readonly valueChanges: Observable<unknown>;
113
+ }
72
114
 
115
+ /**
116
+ * Syncs every key of an Angular FormGroup to the path engine via setData.
117
+ *
118
+ * - Immediately writes getRawValue() to the facade so canMoveNext guards
119
+ * evaluate against the current form state on the very first snapshot.
120
+ * - Subscribes to valueChanges and re-applies getRawValue() on every emission
121
+ * so disabled controls are always included.
122
+ * - Guards against calling setData when no path is active, so it is safe to
123
+ * call syncFormGroup before or after facade.start().
124
+ * - Returns a cleanup function that unsubscribes from the observable.
125
+ * Pass a DestroyRef to wire cleanup automatically to the component lifecycle.
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * export class MyStepComponent implements OnInit {
130
+ * private readonly facade = inject(PathFacade) as PathFacade<MyData>;
131
+ * protected readonly form = new FormGroup({
132
+ * name: new FormControl('', Validators.required),
133
+ * email: new FormControl(''),
134
+ * });
135
+ *
136
+ * ngOnInit() {
137
+ * syncFormGroup(this.facade, this.form, inject(DestroyRef));
138
+ * }
139
+ * }
140
+ * ```
141
+ */
142
+ export function syncFormGroup<TData extends PathData = PathData>(
143
+ facade: PathFacade<TData>,
144
+ formGroup: FormGroupLike,
145
+ destroyRef?: DestroyRef
146
+ ): () => void {
147
+ const baseFacade = facade as PathFacade<PathData>;
148
+
149
+ function applyValues(): void {
150
+ if (baseFacade.snapshot() === null) return; // no active path — nothing to sync
151
+ for (const [key, value] of Object.entries(formGroup.getRawValue())) {
152
+ void baseFacade.setData(key, value);
153
+ }
154
+ }
155
+
156
+ // Write current form values immediately so guards see the initial state.
157
+ applyValues();
158
+
159
+ const subscription = formGroup.valueChanges.subscribe(() => applyValues());
160
+
161
+ const cleanup = () => subscription.unsubscribe();
162
+ destroyRef?.onDestroy(cleanup);
163
+ return cleanup;
164
+ }