@daltonr/pathwrite-angular 0.1.5 → 0.2.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 +145 -12
- package/dist/index.css +39 -5
- package/dist/index.d.ts +70 -5
- package/dist/index.js +121 -98
- package/dist/index.js.map +1 -1
- package/dist/shell.d.ts +19 -2
- package/dist/shell.js +183 -191
- package/dist/shell.js.map +1 -1
- package/package.json +13 -3
- package/src/index.ts +100 -8
- package/src/shell.ts +19 -1
package/dist/shell.js
CHANGED
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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":"
|
|
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.2.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.",
|
|
@@ -40,17 +40,27 @@
|
|
|
40
40
|
"LICENSE"
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
43
|
-
"build": "
|
|
43
|
+
"build": "ngc -p tsconfig.json && cp ../shell.css dist/index.css",
|
|
44
44
|
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
45
45
|
"prepublishOnly": "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.
|
|
63
|
+
"@daltonr/pathwrite-core": "^0.2.0"
|
|
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
|
}
|
|
@@ -55,18 +74,91 @@ export class PathFacade implements OnDestroy {
|
|
|
55
74
|
return this.engine.cancel();
|
|
56
75
|
}
|
|
57
76
|
|
|
58
|
-
public setData(key:
|
|
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
|
-
|
|
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
|
+
}
|