@frame-kit/ui-ng 0.1.15 → 0.1.17
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.
|
@@ -17,6 +17,18 @@ class WizardDialogRef {
|
|
|
17
17
|
cancelLabel;
|
|
18
18
|
nextLabel;
|
|
19
19
|
backLabel;
|
|
20
|
+
/** Optional consumer-supplied header rendered above the stepper. */
|
|
21
|
+
headerComponent;
|
|
22
|
+
/** Inputs applied to `headerComponent` when it is created. */
|
|
23
|
+
headerInputs;
|
|
24
|
+
/** Optional consumer-supplied footer, replacing the built-in buttons. */
|
|
25
|
+
footerComponent;
|
|
26
|
+
/** Inputs applied to `footerComponent` when it is created. */
|
|
27
|
+
footerInputs;
|
|
28
|
+
/** Optional consumer-supplied stepper, replacing the built-in pill row. */
|
|
29
|
+
stepperComponent;
|
|
30
|
+
/** Inputs applied to `stepperComponent` when it is created. */
|
|
31
|
+
stepperInputs;
|
|
20
32
|
// ===== NAVIGATION STATE =====
|
|
21
33
|
currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
|
|
22
34
|
highestVisitedIndex = signal(0, ...(ngDevMode ? [{ debugName: "highestVisitedIndex" }] : /* istanbul ignore next */ []));
|
|
@@ -46,6 +58,12 @@ class WizardDialogRef {
|
|
|
46
58
|
this.cancelLabel = config.cancelLabel ?? 'Cancel';
|
|
47
59
|
this.nextLabel = config.nextLabel ?? 'Next';
|
|
48
60
|
this.backLabel = config.backLabel ?? 'Back';
|
|
61
|
+
this.headerComponent = config.headerComponent ?? null;
|
|
62
|
+
this.headerInputs = config.headerInputs ?? {};
|
|
63
|
+
this.footerComponent = config.footerComponent ?? null;
|
|
64
|
+
this.footerInputs = config.footerInputs ?? {};
|
|
65
|
+
this.stepperComponent = config.stepperComponent ?? null;
|
|
66
|
+
this.stepperInputs = config.stepperInputs ?? {};
|
|
49
67
|
this.consumerData = config.data;
|
|
50
68
|
}
|
|
51
69
|
get data() {
|
|
@@ -112,24 +130,48 @@ class WizardDialogContainerComponent {
|
|
|
112
130
|
data = inject(DIALOG_DATA);
|
|
113
131
|
injector = inject(Injector);
|
|
114
132
|
bodyOutlet = viewChild('bodyOutlet', { ...(ngDevMode ? { debugName: "bodyOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
133
|
+
headerOutlet = viewChild('headerOutlet', { ...(ngDevMode ? { debugName: "headerOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
134
|
+
footerOutlet = viewChild('footerOutlet', { ...(ngDevMode ? { debugName: "footerOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
135
|
+
stepperOutlet = viewChild('stepperOutlet', { ...(ngDevMode ? { debugName: "stepperOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
115
136
|
ref = this.data.wizardRef;
|
|
116
137
|
classes = computed(() => 'fk-wizard-dialog', ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
117
138
|
get hostClass() {
|
|
118
139
|
return this.classes();
|
|
119
140
|
}
|
|
120
141
|
ngAfterViewInit() {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
142
|
+
// One injector for both regions so a consumer-supplied header can inject
|
|
143
|
+
// WIZARD_DIALOG_REF exactly like the step content does.
|
|
125
144
|
const childInjector = Injector.create({
|
|
126
145
|
parent: this.injector,
|
|
127
146
|
providers: [{ provide: WIZARD_DIALOG_REF, useValue: this.ref }],
|
|
128
147
|
});
|
|
148
|
+
this.mountRegion(this.headerOutlet(), this.ref.headerComponent, this.ref.headerInputs, childInjector);
|
|
149
|
+
this.mountRegion(this.footerOutlet(), this.ref.footerComponent, this.ref.footerInputs, childInjector);
|
|
150
|
+
this.mountRegion(this.stepperOutlet(), this.ref.stepperComponent, this.ref.stepperInputs, childInjector);
|
|
151
|
+
const outlet = this.bodyOutlet();
|
|
152
|
+
if (!outlet) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
129
155
|
outlet.createComponent(this.data.contentComponent, {
|
|
130
156
|
injector: childInjector,
|
|
131
157
|
});
|
|
132
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Render an optional consumer-supplied region (header or footer) into its
|
|
161
|
+
* fixed outlet, applying the configured inputs so consumers configure it
|
|
162
|
+
* declaratively from the wizard config. Shares the wizard injector, so the
|
|
163
|
+
* component can inject `WIZARD_DIALOG_REF`.
|
|
164
|
+
*/
|
|
165
|
+
mountRegion(outlet, component, inputs, injector) {
|
|
166
|
+
if (!component || !outlet) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const componentRef = outlet.createComponent(component, { injector });
|
|
170
|
+
for (const [name, value] of Object.entries(inputs)) {
|
|
171
|
+
componentRef.setInput(name, value);
|
|
172
|
+
}
|
|
173
|
+
componentRef.changeDetectorRef.detectChanges();
|
|
174
|
+
}
|
|
133
175
|
onCancel() {
|
|
134
176
|
this.ref.close();
|
|
135
177
|
}
|
|
@@ -137,13 +179,19 @@ class WizardDialogContainerComponent {
|
|
|
137
179
|
this.ref.emitSubmit();
|
|
138
180
|
}
|
|
139
181
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WizardDialogContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
140
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WizardDialogContainerComponent, isStandalone: true, selector: "fk-wizard-dialog-container", host: { properties: { "class": "this.hostClass" } }, viewQueries: [{ propertyName: "bodyOutlet", first: true, predicate: ["bodyOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<!-- Stepper -->\n<div\n class=\"fk-wizard-dialog__stepper\"\n
|
|
182
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WizardDialogContainerComponent, isStandalone: true, selector: "fk-wizard-dialog-container", host: { properties: { "class": "this.hostClass" } }, viewQueries: [{ propertyName: "bodyOutlet", first: true, predicate: ["bodyOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "headerOutlet", first: true, predicate: ["headerOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "footerOutlet", first: true, predicate: ["footerOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "stepperOutlet", first: true, predicate: ["stepperOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<!-- Consumer-supplied header (fixed, above the stepper) -->\n@if (ref.headerComponent) {\n <div class=\"fk-wizard-dialog__header\">\n <ng-template #headerOutlet />\n </div>\n}\n\n<!-- Stepper -->\n@if (ref.stepperComponent) {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n >\n <ng-template #stepperOutlet />\n </div>\n} @else {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n role=\"tablist\"\n >\n @for (step of ref.steps; track $index) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"fk-wizard-dialog__step\"\n [class.fk-wizard-dialog__step--active]=\"$index === ref.currentIndex()\"\n [class.fk-wizard-dialog__step--completed]=\"$index < ref.currentIndex()\"\n [attr.aria-selected]=\"$index === ref.currentIndex()\"\n [disabled]=\"ref.linear && $index > ref.highestVisitedIndex()\"\n (click)=\"ref.goTo($index)\"\n >\n <span class=\"fk-wizard-dialog__step-number\">{{ $index + 1 }}</span>\n <span class=\"fk-wizard-dialog__step-title\">{{ step.title }}</span>\n @if (step.optional) {\n <span class=\"fk-wizard-dialog__step-optional\">(Optional)</span>\n }\n </button>\n }\n </div>\n\n <!-- Scrollable body -->\n}\n\n<div class=\"fk-wizard-dialog__body\">\n <ng-template #bodyOutlet />\n</div>\n\n<!-- Footer (moved to dialog footer by DialogService) -->\n<div\n class=\"fk-wizard-dialog__footer\"\n [class.fk-wizard-dialog__footer--hidden]=\"!ref.chromeVisible()\"\n libDialogFooter\n>\n @if (ref.footerComponent) {\n <ng-template #footerOutlet />\n } @else {\n @if (ref.isFirstStep()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"onCancel()\">\n {{ ref.cancelLabel }}\n </fk-button>\n } @else {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"ref.previous()\">\n {{ ref.backLabel }}\n </fk-button>\n }\n\n @if (ref.extraAction(); as action) {\n <fk-button\n [variant]=\"action.variant ?? 'outline'\"\n type=\"button\"\n (click)=\"action.onClick()\"\n >\n {{ action.label }}\n </fk-button>\n }\n\n @if (ref.isLastStep()) {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.submitDisabled()\"\n (click)=\"onSubmit()\"\n >\n {{ ref.submitLabel }}\n </fk-button>\n } @else {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.nextDisabled()\"\n (click)=\"ref.next()\"\n >\n {{ ref.nextLabel }}\n </fk-button>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden;margin-top:var(--fk-wizard-dialog-top-offset, -1rem)}.fk-wizard-dialog__header{padding:var(--fk-wizard-dialog-header-padding, 0);flex-shrink:0}.fk-wizard-dialog__stepper{display:flex;gap:var(--fk-wizard-dialog-stepper-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-wizard-dialog-stepper-padding, 0 0 .75rem);flex-shrink:0}.fk-wizard-dialog__stepper--hidden{display:none}.fk-wizard-dialog__step{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fk-rhythm-2, .5rem);padding:var(--fk-rhythm-2, .5rem);font-family:var(--fk-input-font-family, inherit);font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .875rem));color:var(--fk-wizard-dialog-step-color, var(--fk-form-hint-color, #6b7280));background:transparent;border:none;cursor:pointer}.fk-wizard-dialog__step:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18));border-radius:var(--fk-radius-sm, .25rem)}.fk-wizard-dialog__step:disabled{opacity:.5;cursor:not-allowed}.fk-wizard-dialog__step--active{color:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff))}.fk-wizard-dialog__step--completed{color:var(--fk-wizard-dialog-step-completed-color, var(--fk-form-label-color, #0b1420))}.fk-wizard-dialog__step-number{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;font-size:var(--fk-font-size-xs, .75rem);font-weight:600;border-radius:50%;border:1px solid currentColor}.fk-wizard-dialog__step--active .fk-wizard-dialog__step-number{background:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff));color:var(--fk-wizard-dialog-step-number-active-color, #fff);border-color:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff))}.fk-wizard-dialog__step-optional{font-size:var(--fk-font-size-xs, .75rem);opacity:.7}.fk-wizard-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;padding:var(--fk-wizard-dialog-body-padding, var(--fk-rhythm-4, 1rem) 0);--fk-form-field-gap: 0}.fk-wizard-dialog__footer{display:flex;gap:var(--fk-wizard-dialog-footer-gap, var(--fk-rhythm-3, .75rem));padding:var(--fk-wizard-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-wizard-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-wizard-dialog__footer--hidden{display:none}.fk-wizard-dialog__footer>*{flex:1 1 0;min-width:0}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
141
183
|
}
|
|
142
184
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WizardDialogContainerComponent, decorators: [{
|
|
143
185
|
type: Component,
|
|
144
|
-
args: [{ selector: 'fk-wizard-dialog-container', standalone: true, imports: [ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Stepper -->\n<div\n class=\"fk-wizard-dialog__stepper\"\n
|
|
186
|
+
args: [{ selector: 'fk-wizard-dialog-container', standalone: true, imports: [ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Consumer-supplied header (fixed, above the stepper) -->\n@if (ref.headerComponent) {\n <div class=\"fk-wizard-dialog__header\">\n <ng-template #headerOutlet />\n </div>\n}\n\n<!-- Stepper -->\n@if (ref.stepperComponent) {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n >\n <ng-template #stepperOutlet />\n </div>\n} @else {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n role=\"tablist\"\n >\n @for (step of ref.steps; track $index) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"fk-wizard-dialog__step\"\n [class.fk-wizard-dialog__step--active]=\"$index === ref.currentIndex()\"\n [class.fk-wizard-dialog__step--completed]=\"$index < ref.currentIndex()\"\n [attr.aria-selected]=\"$index === ref.currentIndex()\"\n [disabled]=\"ref.linear && $index > ref.highestVisitedIndex()\"\n (click)=\"ref.goTo($index)\"\n >\n <span class=\"fk-wizard-dialog__step-number\">{{ $index + 1 }}</span>\n <span class=\"fk-wizard-dialog__step-title\">{{ step.title }}</span>\n @if (step.optional) {\n <span class=\"fk-wizard-dialog__step-optional\">(Optional)</span>\n }\n </button>\n }\n </div>\n\n <!-- Scrollable body -->\n}\n\n<div class=\"fk-wizard-dialog__body\">\n <ng-template #bodyOutlet />\n</div>\n\n<!-- Footer (moved to dialog footer by DialogService) -->\n<div\n class=\"fk-wizard-dialog__footer\"\n [class.fk-wizard-dialog__footer--hidden]=\"!ref.chromeVisible()\"\n libDialogFooter\n>\n @if (ref.footerComponent) {\n <ng-template #footerOutlet />\n } @else {\n @if (ref.isFirstStep()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"onCancel()\">\n {{ ref.cancelLabel }}\n </fk-button>\n } @else {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"ref.previous()\">\n {{ ref.backLabel }}\n </fk-button>\n }\n\n @if (ref.extraAction(); as action) {\n <fk-button\n [variant]=\"action.variant ?? 'outline'\"\n type=\"button\"\n (click)=\"action.onClick()\"\n >\n {{ action.label }}\n </fk-button>\n }\n\n @if (ref.isLastStep()) {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.submitDisabled()\"\n (click)=\"onSubmit()\"\n >\n {{ ref.submitLabel }}\n </fk-button>\n } @else {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.nextDisabled()\"\n (click)=\"ref.next()\"\n >\n {{ ref.nextLabel }}\n </fk-button>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden;margin-top:var(--fk-wizard-dialog-top-offset, -1rem)}.fk-wizard-dialog__header{padding:var(--fk-wizard-dialog-header-padding, 0);flex-shrink:0}.fk-wizard-dialog__stepper{display:flex;gap:var(--fk-wizard-dialog-stepper-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-wizard-dialog-stepper-padding, 0 0 .75rem);flex-shrink:0}.fk-wizard-dialog__stepper--hidden{display:none}.fk-wizard-dialog__step{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fk-rhythm-2, .5rem);padding:var(--fk-rhythm-2, .5rem);font-family:var(--fk-input-font-family, inherit);font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .875rem));color:var(--fk-wizard-dialog-step-color, var(--fk-form-hint-color, #6b7280));background:transparent;border:none;cursor:pointer}.fk-wizard-dialog__step:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18));border-radius:var(--fk-radius-sm, .25rem)}.fk-wizard-dialog__step:disabled{opacity:.5;cursor:not-allowed}.fk-wizard-dialog__step--active{color:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff))}.fk-wizard-dialog__step--completed{color:var(--fk-wizard-dialog-step-completed-color, var(--fk-form-label-color, #0b1420))}.fk-wizard-dialog__step-number{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;font-size:var(--fk-font-size-xs, .75rem);font-weight:600;border-radius:50%;border:1px solid currentColor}.fk-wizard-dialog__step--active .fk-wizard-dialog__step-number{background:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff));color:var(--fk-wizard-dialog-step-number-active-color, #fff);border-color:var(--fk-wizard-dialog-step-active-color, var(--fk-color-primary, #0a84ff))}.fk-wizard-dialog__step-optional{font-size:var(--fk-font-size-xs, .75rem);opacity:.7}.fk-wizard-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;padding:var(--fk-wizard-dialog-body-padding, var(--fk-rhythm-4, 1rem) 0);--fk-form-field-gap: 0}.fk-wizard-dialog__footer{display:flex;gap:var(--fk-wizard-dialog-footer-gap, var(--fk-rhythm-3, .75rem));padding:var(--fk-wizard-dialog-footer-padding, var(--fk-rhythm-4, 1rem) var(--fk-rhythm-6, 1.5rem));border-top:var(--fk-wizard-dialog-footer-border, 1px solid var(--fk-color-border, #d9e2ee));flex-shrink:0}.fk-wizard-dialog__footer--hidden{display:none}.fk-wizard-dialog__footer>*{flex:1 1 0;min-width:0}\n"] }]
|
|
145
187
|
}], propDecorators: { bodyOutlet: [{ type: i0.ViewChild, args: ['bodyOutlet', { ...{
|
|
146
188
|
read: ViewContainerRef,
|
|
189
|
+
}, isSignal: true }] }], headerOutlet: [{ type: i0.ViewChild, args: ['headerOutlet', { ...{
|
|
190
|
+
read: ViewContainerRef,
|
|
191
|
+
}, isSignal: true }] }], footerOutlet: [{ type: i0.ViewChild, args: ['footerOutlet', { ...{
|
|
192
|
+
read: ViewContainerRef,
|
|
193
|
+
}, isSignal: true }] }], stepperOutlet: [{ type: i0.ViewChild, args: ['stepperOutlet', { ...{
|
|
194
|
+
read: ViewContainerRef,
|
|
147
195
|
}, isSignal: true }] }], hostClass: [{
|
|
148
196
|
type: HostBinding,
|
|
149
197
|
args: ['class']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-kit-ui-ng-ui-wizard-dialog.mjs","sources":["../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-ref.ts","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-container.component.ts","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-container.component.html","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog.service.ts","../../../../packages/ui-ng/ui/wizard-dialog/frame-kit-ui-ng-ui-wizard-dialog.ts"],"sourcesContent":["import { computed, signal } from '@angular/core';\n\nimport { Observable, Subject } from 'rxjs';\n\nimport type { DialogRef } from '@frame-kit/ui-ng/ui/dialog';\nimport type {\n WizardDialogConfig,\n WizardDialogStep,\n} from './wizard-dialog.types';\n\n/**\n * Optional extra footer button the consumer can surface on any step\n * — typically a \"View X\" jump-off on the results/last step. Sits\n * between Back and Submit in the wizard's footer. Set via\n * `WizardDialogRef.extraAction.set(...)` on step entry; clear with\n * `null` on step exit (or just rely on swapping it out).\n */\nexport interface WizardExtraAction {\n /** Button label, e.g. \"View Identities\". */\n label: string;\n /** Visual variant. Defaults to `\"outline\"` so the extra action\n * doesn't compete with the primary Submit button. */\n variant?: 'primary' | 'outline' | 'secondary' | 'danger';\n /** Click handler — typically closes the wizard with a sentinel. */\n onClick: () => void;\n}\n\nexport const WIZARD_DIALOG_REF = Symbol('WIZARD_DIALOG_REF');\n\nexport class WizardDialogRef<TResult = unknown, TData = unknown> {\n private dialogRef!: DialogRef<TResult>;\n private readonly consumerData: TData | undefined;\n private readonly submitSubject = new Subject<void>();\n private readonly stepChangeSubject = new Subject<number>();\n\n // ===== CONFIG =====\n\n readonly steps: WizardDialogStep[];\n readonly linear: boolean;\n readonly submitLabel: string;\n readonly cancelLabel: string;\n readonly nextLabel: string;\n readonly backLabel: string;\n\n // ===== NAVIGATION STATE =====\n\n readonly currentIndex = signal(0);\n readonly highestVisitedIndex = signal(0);\n\n readonly totalSteps = computed(() => this.steps.length);\n\n readonly isFirstStep = computed(() => this.currentIndex() === 0);\n\n readonly isLastStep = computed(\n () => this.currentIndex() === this.steps.length - 1,\n );\n\n readonly currentStep = computed(() => this.steps[this.currentIndex()]);\n\n // ===== CONSUMER-CONTROLLED STATE =====\n\n readonly submitDisabled = signal(false);\n readonly nextDisabled = signal(false);\n readonly chromeVisible = signal(true);\n /**\n * Optional third footer button. When non-null, the wizard chrome\n * renders an additional `<fk-button>` between Back and Submit\n * using this metadata. Consumers typically wire this in an\n * `effect` keyed on `currentIndex` so the button only appears on\n * the step(s) that need it.\n */\n readonly extraAction = signal<WizardExtraAction | null>(null);\n\n // ===== OBSERVABLES =====\n\n readonly submitted: Observable<void> = this.submitSubject.asObservable();\n readonly stepChanged: Observable<number> =\n this.stepChangeSubject.asObservable();\n\n constructor(config: WizardDialogConfig<TData>) {\n this.steps = config.steps;\n this.linear = config.linear ?? true;\n this.submitLabel = config.submitLabel ?? 'Submit';\n this.cancelLabel = config.cancelLabel ?? 'Cancel';\n this.nextLabel = config.nextLabel ?? 'Next';\n this.backLabel = config.backLabel ?? 'Back';\n this.consumerData = config.data;\n }\n\n get data(): TData | undefined {\n return this.consumerData;\n }\n\n // ===== NAVIGATION =====\n\n next(): boolean {\n if (this.isLastStep()) {\n return false;\n }\n\n this.currentIndex.update((i) => i + 1);\n this.updateHighestVisited();\n this.stepChangeSubject.next(this.currentIndex());\n\n return true;\n }\n\n previous(): boolean {\n if (this.isFirstStep()) {\n return false;\n }\n\n this.currentIndex.update((i) => i - 1);\n this.stepChangeSubject.next(this.currentIndex());\n\n return true;\n }\n\n goTo(index: number): boolean {\n if (index < 0 || index >= this.steps.length) {\n return false;\n }\n\n if (this.linear && index > this.highestVisitedIndex()) {\n return false;\n }\n\n if (index > this.currentIndex() && this.nextDisabled()) {\n return false;\n }\n\n this.currentIndex.set(index);\n this.updateHighestVisited();\n this.stepChangeSubject.next(index);\n\n return true;\n }\n\n private updateHighestVisited(): void {\n const current = this.currentIndex();\n\n if (current > this.highestVisitedIndex()) {\n this.highestVisitedIndex.set(current);\n }\n }\n\n // ===== DIALOG LIFECYCLE =====\n\n close(result?: TResult): void {\n this.dialogRef.close(result);\n }\n\n afterClosed(): Observable<TResult | undefined> {\n return this.dialogRef.afterClosed();\n }\n\n // ===== INTERNAL =====\n\n /** @internal Called by container when submit button is clicked. */\n emitSubmit(): void {\n this.submitSubject.next();\n }\n\n /** @internal Called by WizardDialogService after dialog is opened. */\n setDialogRef(ref: DialogRef<TResult>): void {\n this.dialogRef = ref;\n }\n}\n","import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n inject,\n Injector,\n viewChild,\n ViewContainerRef,\n} from '@angular/core';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { DIALOG_DATA } from '@frame-kit/ui-ng/ui/dialog';\nimport type { WizardDialogContainerData } from './wizard-dialog.service';\nimport { WIZARD_DIALOG_REF, WizardDialogRef } from './wizard-dialog-ref';\n\n@Component({\n selector: 'fk-wizard-dialog-container',\n standalone: true,\n imports: [ButtonComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './wizard-dialog-container.component.html',\n styleUrl: './wizard-dialog-container.component.scss',\n})\nexport class WizardDialogContainerComponent implements AfterViewInit {\n private readonly data = inject(\n DIALOG_DATA as never,\n ) as WizardDialogContainerData;\n private readonly injector = inject(Injector);\n private readonly bodyOutlet = viewChild('bodyOutlet', {\n read: ViewContainerRef,\n });\n\n readonly ref: WizardDialogRef = this.data.wizardRef;\n\n readonly classes = computed(() => 'fk-wizard-dialog');\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n ngAfterViewInit(): void {\n const outlet = this.bodyOutlet();\n\n if (!outlet) {\n return;\n }\n\n const childInjector = Injector.create({\n parent: this.injector,\n providers: [{ provide: WIZARD_DIALOG_REF as never, useValue: this.ref }],\n });\n\n outlet.createComponent(this.data.contentComponent, {\n injector: childInjector,\n });\n }\n\n onCancel(): void {\n this.ref.close();\n }\n\n onSubmit(): void {\n this.ref.emitSubmit();\n }\n}\n","<!-- Stepper -->\n<div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n role=\"tablist\"\n>\n @for (step of ref.steps; track $index) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"fk-wizard-dialog__step\"\n [class.fk-wizard-dialog__step--active]=\"$index === ref.currentIndex()\"\n [class.fk-wizard-dialog__step--completed]=\"$index < ref.currentIndex()\"\n [attr.aria-selected]=\"$index === ref.currentIndex()\"\n [disabled]=\"ref.linear && $index > ref.highestVisitedIndex()\"\n (click)=\"ref.goTo($index)\"\n >\n <span class=\"fk-wizard-dialog__step-number\">{{ $index + 1 }}</span>\n <span class=\"fk-wizard-dialog__step-title\">{{ step.title }}</span>\n @if (step.optional) {\n <span class=\"fk-wizard-dialog__step-optional\">(Optional)</span>\n }\n </button>\n }\n</div>\n\n<!-- Scrollable body -->\n<div class=\"fk-wizard-dialog__body\">\n <ng-template #bodyOutlet />\n</div>\n\n<!-- Footer (moved to dialog footer by DialogService) -->\n<div\n class=\"fk-wizard-dialog__footer\"\n [class.fk-wizard-dialog__footer--hidden]=\"!ref.chromeVisible()\"\n libDialogFooter\n>\n @if (ref.isFirstStep()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"onCancel()\">\n {{ ref.cancelLabel }}\n </fk-button>\n } @else {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"ref.previous()\">\n {{ ref.backLabel }}\n </fk-button>\n }\n\n @if (ref.extraAction(); as action) {\n <fk-button\n [variant]=\"action.variant ?? 'outline'\"\n type=\"button\"\n (click)=\"action.onClick()\"\n >\n {{ action.label }}\n </fk-button>\n }\n\n @if (ref.isLastStep()) {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.submitDisabled()\"\n (click)=\"onSubmit()\"\n >\n {{ ref.submitLabel }}\n </fk-button>\n } @else {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.nextDisabled()\"\n (click)=\"ref.next()\"\n >\n {{ ref.nextLabel }}\n </fk-button>\n }\n</div>\n","import { inject, Injectable, Type } from '@angular/core';\n\nimport { DialogService } from '@frame-kit/ui-ng/ui/dialog';\nimport type { DialogRef } from '@frame-kit/ui-ng/ui/dialog';\nimport type { WizardDialogConfig } from './wizard-dialog.types';\nimport { WizardDialogContainerComponent } from './wizard-dialog-container.component';\nimport { WizardDialogRef } from './wizard-dialog-ref';\n\nexport interface WizardDialogContainerData {\n wizardRef: WizardDialogRef;\n contentComponent: Type<unknown>;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class WizardDialogService {\n private readonly dialogService = inject(DialogService);\n\n open<TResult = unknown, TData = unknown>(\n content: Type<unknown>,\n config: WizardDialogConfig<TData>,\n ): WizardDialogRef<TResult, TData> {\n const wizardRef = new WizardDialogRef<TResult, TData>(config);\n\n const dialogRef = this.dialogService.open<\n TResult,\n WizardDialogContainerData\n >(WizardDialogContainerComponent, {\n header: config.header,\n size: config.size ?? 'lg',\n closable: config.closable,\n closeOnEscape: config.closeOnEscape,\n closeOnBackdrop: config.closeOnBackdrop,\n animation: config.animation,\n fullscreenMobile: config.fullscreenMobile,\n className: ['fk-wizard-dialog-host', config.className]\n .filter(Boolean)\n .join(' '),\n ariaLabel: config.ariaLabel,\n ariaDescribedBy: config.ariaDescribedBy,\n flexBody: true,\n data: {\n wizardRef: wizardRef as WizardDialogRef,\n contentComponent: content,\n },\n });\n\n wizardRef.setDialogRef(dialogRef as DialogRef<TResult>);\n\n return wizardRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"frame-kit-ui-ng-ui-wizard-dialog.mjs","sources":["../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-ref.ts","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-container.component.ts","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog-container.component.html","../../../../packages/ui-ng/ui/wizard-dialog/wizard-dialog.service.ts","../../../../packages/ui-ng/ui/wizard-dialog/frame-kit-ui-ng-ui-wizard-dialog.ts"],"sourcesContent":["import type { Type } from '@angular/core';\nimport { computed, signal } from '@angular/core';\n\nimport { Observable, Subject } from 'rxjs';\n\nimport type { DialogRef } from '@frame-kit/ui-ng/ui/dialog';\nimport type {\n WizardDialogConfig,\n WizardDialogStep,\n} from './wizard-dialog.types';\n\n/**\n * Optional extra footer button the consumer can surface on any step\n * — typically a \"View X\" jump-off on the results/last step. Sits\n * between Back and Submit in the wizard's footer. Set via\n * `WizardDialogRef.extraAction.set(...)` on step entry; clear with\n * `null` on step exit (or just rely on swapping it out).\n */\nexport interface WizardExtraAction {\n /** Button label, e.g. \"View Identities\". */\n label: string;\n /** Visual variant. Defaults to `\"outline\"` so the extra action\n * doesn't compete with the primary Submit button. */\n variant?: 'primary' | 'outline' | 'secondary' | 'danger';\n /** Click handler — typically closes the wizard with a sentinel. */\n onClick: () => void;\n}\n\nexport const WIZARD_DIALOG_REF = Symbol('WIZARD_DIALOG_REF');\n\nexport class WizardDialogRef<TResult = unknown, TData = unknown> {\n private dialogRef!: DialogRef<TResult>;\n private readonly consumerData: TData | undefined;\n private readonly submitSubject = new Subject<void>();\n private readonly stepChangeSubject = new Subject<number>();\n\n // ===== CONFIG =====\n\n readonly steps: WizardDialogStep[];\n readonly linear: boolean;\n readonly submitLabel: string;\n readonly cancelLabel: string;\n readonly nextLabel: string;\n readonly backLabel: string;\n\n /** Optional consumer-supplied header rendered above the stepper. */\n readonly headerComponent: Type<unknown> | null;\n\n /** Inputs applied to `headerComponent` when it is created. */\n readonly headerInputs: Record<string, unknown>;\n\n /** Optional consumer-supplied footer, replacing the built-in buttons. */\n readonly footerComponent: Type<unknown> | null;\n\n /** Inputs applied to `footerComponent` when it is created. */\n readonly footerInputs: Record<string, unknown>;\n\n /** Optional consumer-supplied stepper, replacing the built-in pill row. */\n readonly stepperComponent: Type<unknown> | null;\n\n /** Inputs applied to `stepperComponent` when it is created. */\n readonly stepperInputs: Record<string, unknown>;\n\n // ===== NAVIGATION STATE =====\n\n readonly currentIndex = signal(0);\n readonly highestVisitedIndex = signal(0);\n\n readonly totalSteps = computed(() => this.steps.length);\n\n readonly isFirstStep = computed(() => this.currentIndex() === 0);\n\n readonly isLastStep = computed(\n () => this.currentIndex() === this.steps.length - 1,\n );\n\n readonly currentStep = computed(() => this.steps[this.currentIndex()]);\n\n // ===== CONSUMER-CONTROLLED STATE =====\n\n readonly submitDisabled = signal(false);\n readonly nextDisabled = signal(false);\n readonly chromeVisible = signal(true);\n /**\n * Optional third footer button. When non-null, the wizard chrome\n * renders an additional `<fk-button>` between Back and Submit\n * using this metadata. Consumers typically wire this in an\n * `effect` keyed on `currentIndex` so the button only appears on\n * the step(s) that need it.\n */\n readonly extraAction = signal<WizardExtraAction | null>(null);\n\n // ===== OBSERVABLES =====\n\n readonly submitted: Observable<void> = this.submitSubject.asObservable();\n readonly stepChanged: Observable<number> =\n this.stepChangeSubject.asObservable();\n\n constructor(config: WizardDialogConfig<TData>) {\n this.steps = config.steps;\n this.linear = config.linear ?? true;\n this.submitLabel = config.submitLabel ?? 'Submit';\n this.cancelLabel = config.cancelLabel ?? 'Cancel';\n this.nextLabel = config.nextLabel ?? 'Next';\n this.backLabel = config.backLabel ?? 'Back';\n this.headerComponent = config.headerComponent ?? null;\n this.headerInputs = config.headerInputs ?? {};\n this.footerComponent = config.footerComponent ?? null;\n this.footerInputs = config.footerInputs ?? {};\n this.stepperComponent = config.stepperComponent ?? null;\n this.stepperInputs = config.stepperInputs ?? {};\n this.consumerData = config.data;\n }\n\n get data(): TData | undefined {\n return this.consumerData;\n }\n\n // ===== NAVIGATION =====\n\n next(): boolean {\n if (this.isLastStep()) {\n return false;\n }\n\n this.currentIndex.update((i) => i + 1);\n this.updateHighestVisited();\n this.stepChangeSubject.next(this.currentIndex());\n\n return true;\n }\n\n previous(): boolean {\n if (this.isFirstStep()) {\n return false;\n }\n\n this.currentIndex.update((i) => i - 1);\n this.stepChangeSubject.next(this.currentIndex());\n\n return true;\n }\n\n goTo(index: number): boolean {\n if (index < 0 || index >= this.steps.length) {\n return false;\n }\n\n if (this.linear && index > this.highestVisitedIndex()) {\n return false;\n }\n\n if (index > this.currentIndex() && this.nextDisabled()) {\n return false;\n }\n\n this.currentIndex.set(index);\n this.updateHighestVisited();\n this.stepChangeSubject.next(index);\n\n return true;\n }\n\n private updateHighestVisited(): void {\n const current = this.currentIndex();\n\n if (current > this.highestVisitedIndex()) {\n this.highestVisitedIndex.set(current);\n }\n }\n\n // ===== DIALOG LIFECYCLE =====\n\n close(result?: TResult): void {\n this.dialogRef.close(result);\n }\n\n afterClosed(): Observable<TResult | undefined> {\n return this.dialogRef.afterClosed();\n }\n\n // ===== INTERNAL =====\n\n /** @internal Called by container when submit button is clicked. */\n emitSubmit(): void {\n this.submitSubject.next();\n }\n\n /** @internal Called by WizardDialogService after dialog is opened. */\n setDialogRef(ref: DialogRef<TResult>): void {\n this.dialogRef = ref;\n }\n}\n","import {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n inject,\n Injector,\n viewChild,\n Type,\n ViewContainerRef,\n} from '@angular/core';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { DIALOG_DATA } from '@frame-kit/ui-ng/ui/dialog';\nimport type { WizardDialogContainerData } from './wizard-dialog.service';\nimport { WIZARD_DIALOG_REF, WizardDialogRef } from './wizard-dialog-ref';\n\n@Component({\n selector: 'fk-wizard-dialog-container',\n standalone: true,\n imports: [ButtonComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './wizard-dialog-container.component.html',\n styleUrl: './wizard-dialog-container.component.scss',\n})\nexport class WizardDialogContainerComponent implements AfterViewInit {\n private readonly data = inject(\n DIALOG_DATA as never,\n ) as WizardDialogContainerData;\n private readonly injector = inject(Injector);\n private readonly bodyOutlet = viewChild('bodyOutlet', {\n read: ViewContainerRef,\n });\n private readonly headerOutlet = viewChild('headerOutlet', {\n read: ViewContainerRef,\n });\n private readonly footerOutlet = viewChild('footerOutlet', {\n read: ViewContainerRef,\n });\n private readonly stepperOutlet = viewChild('stepperOutlet', {\n read: ViewContainerRef,\n });\n\n readonly ref: WizardDialogRef = this.data.wizardRef;\n\n readonly classes = computed(() => 'fk-wizard-dialog');\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n ngAfterViewInit(): void {\n // One injector for both regions so a consumer-supplied header can inject\n // WIZARD_DIALOG_REF exactly like the step content does.\n const childInjector = Injector.create({\n parent: this.injector,\n providers: [{ provide: WIZARD_DIALOG_REF as never, useValue: this.ref }],\n });\n\n this.mountRegion(\n this.headerOutlet(),\n this.ref.headerComponent,\n this.ref.headerInputs,\n childInjector,\n );\n\n this.mountRegion(\n this.footerOutlet(),\n this.ref.footerComponent,\n this.ref.footerInputs,\n childInjector,\n );\n\n this.mountRegion(\n this.stepperOutlet(),\n this.ref.stepperComponent,\n this.ref.stepperInputs,\n childInjector,\n );\n\n const outlet = this.bodyOutlet();\n\n if (!outlet) {\n return;\n }\n\n outlet.createComponent(this.data.contentComponent, {\n injector: childInjector,\n });\n }\n\n /**\n * Render an optional consumer-supplied region (header or footer) into its\n * fixed outlet, applying the configured inputs so consumers configure it\n * declaratively from the wizard config. Shares the wizard injector, so the\n * component can inject `WIZARD_DIALOG_REF`.\n */\n private mountRegion(\n outlet: ViewContainerRef | undefined,\n component: Type<unknown> | null,\n inputs: Record<string, unknown>,\n injector: Injector,\n ): void {\n if (!component || !outlet) {\n return;\n }\n\n const componentRef = outlet.createComponent(component, { injector });\n\n for (const [name, value] of Object.entries(inputs)) {\n componentRef.setInput(name, value);\n }\n\n componentRef.changeDetectorRef.detectChanges();\n }\n\n onCancel(): void {\n this.ref.close();\n }\n\n onSubmit(): void {\n this.ref.emitSubmit();\n }\n}\n","<!-- Consumer-supplied header (fixed, above the stepper) -->\n@if (ref.headerComponent) {\n <div class=\"fk-wizard-dialog__header\">\n <ng-template #headerOutlet />\n </div>\n}\n\n<!-- Stepper -->\n@if (ref.stepperComponent) {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n >\n <ng-template #stepperOutlet />\n </div>\n} @else {\n <div\n class=\"fk-wizard-dialog__stepper\"\n [class.fk-wizard-dialog__stepper--hidden]=\"!ref.chromeVisible()\"\n role=\"tablist\"\n >\n @for (step of ref.steps; track $index) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"fk-wizard-dialog__step\"\n [class.fk-wizard-dialog__step--active]=\"$index === ref.currentIndex()\"\n [class.fk-wizard-dialog__step--completed]=\"$index < ref.currentIndex()\"\n [attr.aria-selected]=\"$index === ref.currentIndex()\"\n [disabled]=\"ref.linear && $index > ref.highestVisitedIndex()\"\n (click)=\"ref.goTo($index)\"\n >\n <span class=\"fk-wizard-dialog__step-number\">{{ $index + 1 }}</span>\n <span class=\"fk-wizard-dialog__step-title\">{{ step.title }}</span>\n @if (step.optional) {\n <span class=\"fk-wizard-dialog__step-optional\">(Optional)</span>\n }\n </button>\n }\n </div>\n\n <!-- Scrollable body -->\n}\n\n<div class=\"fk-wizard-dialog__body\">\n <ng-template #bodyOutlet />\n</div>\n\n<!-- Footer (moved to dialog footer by DialogService) -->\n<div\n class=\"fk-wizard-dialog__footer\"\n [class.fk-wizard-dialog__footer--hidden]=\"!ref.chromeVisible()\"\n libDialogFooter\n>\n @if (ref.footerComponent) {\n <ng-template #footerOutlet />\n } @else {\n @if (ref.isFirstStep()) {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"onCancel()\">\n {{ ref.cancelLabel }}\n </fk-button>\n } @else {\n <fk-button variant=\"outline\" type=\"button\" (click)=\"ref.previous()\">\n {{ ref.backLabel }}\n </fk-button>\n }\n\n @if (ref.extraAction(); as action) {\n <fk-button\n [variant]=\"action.variant ?? 'outline'\"\n type=\"button\"\n (click)=\"action.onClick()\"\n >\n {{ action.label }}\n </fk-button>\n }\n\n @if (ref.isLastStep()) {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.submitDisabled()\"\n (click)=\"onSubmit()\"\n >\n {{ ref.submitLabel }}\n </fk-button>\n } @else {\n <fk-button\n variant=\"primary\"\n type=\"button\"\n [disabled]=\"ref.nextDisabled()\"\n (click)=\"ref.next()\"\n >\n {{ ref.nextLabel }}\n </fk-button>\n }\n }\n</div>\n","import { inject, Injectable, Type } from '@angular/core';\n\nimport { DialogService } from '@frame-kit/ui-ng/ui/dialog';\nimport type { DialogRef } from '@frame-kit/ui-ng/ui/dialog';\nimport type { WizardDialogConfig } from './wizard-dialog.types';\nimport { WizardDialogContainerComponent } from './wizard-dialog-container.component';\nimport { WizardDialogRef } from './wizard-dialog-ref';\n\nexport interface WizardDialogContainerData {\n wizardRef: WizardDialogRef;\n contentComponent: Type<unknown>;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class WizardDialogService {\n private readonly dialogService = inject(DialogService);\n\n open<TResult = unknown, TData = unknown>(\n content: Type<unknown>,\n config: WizardDialogConfig<TData>,\n ): WizardDialogRef<TResult, TData> {\n const wizardRef = new WizardDialogRef<TResult, TData>(config);\n\n const dialogRef = this.dialogService.open<\n TResult,\n WizardDialogContainerData\n >(WizardDialogContainerComponent, {\n header: config.header,\n size: config.size ?? 'lg',\n closable: config.closable,\n closeOnEscape: config.closeOnEscape,\n closeOnBackdrop: config.closeOnBackdrop,\n animation: config.animation,\n fullscreenMobile: config.fullscreenMobile,\n className: ['fk-wizard-dialog-host', config.className]\n .filter(Boolean)\n .join(' '),\n ariaLabel: config.ariaLabel,\n ariaDescribedBy: config.ariaDescribedBy,\n flexBody: true,\n data: {\n wizardRef: wizardRef as WizardDialogRef,\n contentComponent: content,\n },\n });\n\n wizardRef.setDialogRef(dialogRef as DialogRef<TResult>);\n\n return wizardRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -24,6 +24,44 @@ interface WizardDialogConfig<TData = unknown> extends Pick<DialogConfig<TData>,
|
|
|
24
24
|
nextLabel?: string;
|
|
25
25
|
/** Label for the back button. Default: `"Back"`. */
|
|
26
26
|
backLabel?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Component rendered in a fixed region above the stepper — the wizard's
|
|
29
|
+
* own header. Use this when the plain `header` string isn't enough (e.g.
|
|
30
|
+
* an icon-tile header with a subtitle); pair it with `header: null` so the
|
|
31
|
+
* underlying dialog doesn't also render its title bar.
|
|
32
|
+
*
|
|
33
|
+
* The component is created with the wizard's injector, so it can inject
|
|
34
|
+
* `WIZARD_DIALOG_REF` to read step state or close the wizard.
|
|
35
|
+
*/
|
|
36
|
+
headerComponent?: Type<unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* Inputs applied to `headerComponent` via `setInput` — e.g.
|
|
39
|
+
* `{ icon: 'key-outline', title: 'Create API Key' }`.
|
|
40
|
+
*/
|
|
41
|
+
headerInputs?: Record<string, unknown>;
|
|
42
|
+
/**
|
|
43
|
+
* Component rendered in place of the built-in footer buttons. Use this when
|
|
44
|
+
* the default Cancel/Back + Next/Submit row isn't enough (e.g. a step
|
|
45
|
+
* counter, icon-bearing buttons).
|
|
46
|
+
*
|
|
47
|
+
* The component is created with the wizard's injector, so it can inject
|
|
48
|
+
* `WIZARD_DIALOG_REF` to drive navigation (`next()`, `previous()`, `close()`)
|
|
49
|
+
* and read step state.
|
|
50
|
+
*/
|
|
51
|
+
footerComponent?: Type<unknown>;
|
|
52
|
+
/** Inputs applied to `footerComponent` via `setInput`. */
|
|
53
|
+
footerInputs?: Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Component rendered in place of the built-in stepper. Use this when the
|
|
56
|
+
* default numbered-pill row isn't enough (e.g. connecting progress lines,
|
|
57
|
+
* per-step kickers, completion checks).
|
|
58
|
+
*
|
|
59
|
+
* The component is created with the wizard's injector, so it can inject
|
|
60
|
+
* `WIZARD_DIALOG_REF` to read `steps` / `currentIndex` and call `goTo()`.
|
|
61
|
+
*/
|
|
62
|
+
stepperComponent?: Type<unknown>;
|
|
63
|
+
/** Inputs applied to `stepperComponent` via `setInput`. */
|
|
64
|
+
stepperInputs?: Record<string, unknown>;
|
|
27
65
|
}
|
|
28
66
|
|
|
29
67
|
/**
|
|
@@ -54,6 +92,18 @@ declare class WizardDialogRef<TResult = unknown, TData = unknown> {
|
|
|
54
92
|
readonly cancelLabel: string;
|
|
55
93
|
readonly nextLabel: string;
|
|
56
94
|
readonly backLabel: string;
|
|
95
|
+
/** Optional consumer-supplied header rendered above the stepper. */
|
|
96
|
+
readonly headerComponent: Type<unknown> | null;
|
|
97
|
+
/** Inputs applied to `headerComponent` when it is created. */
|
|
98
|
+
readonly headerInputs: Record<string, unknown>;
|
|
99
|
+
/** Optional consumer-supplied footer, replacing the built-in buttons. */
|
|
100
|
+
readonly footerComponent: Type<unknown> | null;
|
|
101
|
+
/** Inputs applied to `footerComponent` when it is created. */
|
|
102
|
+
readonly footerInputs: Record<string, unknown>;
|
|
103
|
+
/** Optional consumer-supplied stepper, replacing the built-in pill row. */
|
|
104
|
+
readonly stepperComponent: Type<unknown> | null;
|
|
105
|
+
/** Inputs applied to `stepperComponent` when it is created. */
|
|
106
|
+
readonly stepperInputs: Record<string, unknown>;
|
|
57
107
|
readonly currentIndex: _angular_core.WritableSignal<number>;
|
|
58
108
|
readonly highestVisitedIndex: _angular_core.WritableSignal<number>;
|
|
59
109
|
readonly totalSteps: _angular_core.Signal<number>;
|
|
@@ -102,10 +152,20 @@ declare class WizardDialogContainerComponent implements AfterViewInit {
|
|
|
102
152
|
private readonly data;
|
|
103
153
|
private readonly injector;
|
|
104
154
|
private readonly bodyOutlet;
|
|
155
|
+
private readonly headerOutlet;
|
|
156
|
+
private readonly footerOutlet;
|
|
157
|
+
private readonly stepperOutlet;
|
|
105
158
|
readonly ref: WizardDialogRef;
|
|
106
159
|
readonly classes: _angular_core.Signal<string>;
|
|
107
160
|
get hostClass(): string;
|
|
108
161
|
ngAfterViewInit(): void;
|
|
162
|
+
/**
|
|
163
|
+
* Render an optional consumer-supplied region (header or footer) into its
|
|
164
|
+
* fixed outlet, applying the configured inputs so consumers configure it
|
|
165
|
+
* declaratively from the wizard config. Shares the wizard injector, so the
|
|
166
|
+
* component can inject `WIZARD_DIALOG_REF`.
|
|
167
|
+
*/
|
|
168
|
+
private mountRegion;
|
|
109
169
|
onCancel(): void;
|
|
110
170
|
onSubmit(): void;
|
|
111
171
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<WizardDialogContainerComponent, never>;
|
|
@@ -12,25 +12,27 @@ A service-driven wizard dialog for multi-step workflows. Opens its own dialog vi
|
|
|
12
12
|
|
|
13
13
|
### WizardDialogConfig
|
|
14
14
|
|
|
15
|
-
| Option | Type
|
|
16
|
-
| ------------------ |
|
|
17
|
-
| `steps` | `WizardDialogStep[]`
|
|
18
|
-
| `linear` | `boolean`
|
|
19
|
-
| `submitLabel` | `string`
|
|
20
|
-
| `cancelLabel` | `string`
|
|
21
|
-
| `nextLabel` | `string`
|
|
22
|
-
| `backLabel` | `string`
|
|
23
|
-
| `header` | `string`
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
15
|
+
| Option | Type | Default | Description |
|
|
16
|
+
| ------------------ | ------------------------- | -------------- | ---------------------------------------- |
|
|
17
|
+
| `steps` | `WizardDialogStep[]` | required | Step definitions (title + contentKey) |
|
|
18
|
+
| `linear` | `boolean` | `true` | Enforce sequential navigation |
|
|
19
|
+
| `submitLabel` | `string` | `"Submit"` | Label for the final step action button |
|
|
20
|
+
| `cancelLabel` | `string` | `"Cancel"` | Label for cancel button (first step) |
|
|
21
|
+
| `nextLabel` | `string` | `"Next"` | Label for next step button |
|
|
22
|
+
| `backLabel` | `string` | `"Back"` | Label for back button |
|
|
23
|
+
| `header` | `string` | — | Dialog header title |
|
|
24
|
+
| `headerComponent` | `Type<unknown>` | — | Custom header rendered above the stepper |
|
|
25
|
+
| `headerInputs` | `Record<string, unknown>` | `{}` | Inputs applied to `headerComponent` |
|
|
26
|
+
| `size` | `DialogSize` | `"lg"` | Dialog size |
|
|
27
|
+
| `data` | `TData` | — | Data passed to the content component |
|
|
28
|
+
| `closable` | `boolean` | `true` | Show close button |
|
|
29
|
+
| `closeOnEscape` | `boolean` | `true` | Close on Escape key |
|
|
30
|
+
| `closeOnBackdrop` | `boolean` | `false` | Close on backdrop click |
|
|
31
|
+
| `animation` | `DialogAnimation` | `"scale-fade"` | Open/close animation |
|
|
32
|
+
| `fullscreenMobile` | `boolean` | `false` | Fullscreen on mobile viewports |
|
|
33
|
+
| `className` | `string` | — | Additional CSS class on dialog |
|
|
34
|
+
| `ariaLabel` | `string` | — | Accessible label for the dialog |
|
|
35
|
+
| `ariaDescribedBy` | `string` | — | ID of describing element |
|
|
34
36
|
|
|
35
37
|
### WizardDialogRef
|
|
36
38
|
|
|
@@ -68,6 +70,96 @@ Metadata describing the optional third footer button. Set `wizardRef.extraAction
|
|
|
68
70
|
|
|
69
71
|
The content component is dynamically created inside the wizard body. It receives a `WIZARD_DIALOG_REF` injection token to access navigation state and lifecycle events. Step content is rendered via `@switch` on `wizardRef.currentIndex()`.
|
|
70
72
|
|
|
73
|
+
### Custom header
|
|
74
|
+
|
|
75
|
+
The plain `header` string renders the underlying dialog's title bar. When a
|
|
76
|
+
wizard needs richer chrome — an icon tile, a subtitle, a branded header — pass
|
|
77
|
+
a component instead. It renders in a **fixed region above the stepper**, so it
|
|
78
|
+
stays put while the body scrolls.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
wizardDialog.open(CreateApiKeyWizard, {
|
|
82
|
+
header: null, // suppress the plain title bar
|
|
83
|
+
headerComponent: MyWizardHeaderComponent,
|
|
84
|
+
headerInputs: { icon: 'key-outline', title: 'Create API Key' },
|
|
85
|
+
steps: [...],
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The header is created with the wizard's own injector, so it can
|
|
90
|
+
`inject(WIZARD_DIALOG_REF)` to read step state or close the wizard.
|
|
91
|
+
|
|
92
|
+
### Custom footer
|
|
93
|
+
|
|
94
|
+
Same mechanism for the footer. Supply `footerComponent` to replace the built-in
|
|
95
|
+
Cancel/Back + Next/Submit row — useful for a step counter, icon-bearing
|
|
96
|
+
buttons, or any layout the defaults don't cover. It renders inside the wizard's
|
|
97
|
+
own fixed footer region, so it stays pinned while the body scrolls.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
wizardDialog.open(CreateApiKeyWizard, {
|
|
101
|
+
footerComponent: MyWizardFooterComponent,
|
|
102
|
+
steps: [...],
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Like the header, it's created with the wizard's injector — so it can
|
|
107
|
+
`inject(WIZARD_DIALOG_REF)` and drive navigation via `next()`, `previous()`,
|
|
108
|
+
and `close()`.
|
|
109
|
+
|
|
110
|
+
### Custom stepper
|
|
111
|
+
|
|
112
|
+
`stepperComponent` replaces the built-in numbered-pill row — for progress
|
|
113
|
+
lines, per-step kickers, completion checks, or any other treatment. It renders
|
|
114
|
+
in the same fixed stepper region and respects `chromeVisible`.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
wizardDialog.open(CreateApiKeyWizard, {
|
|
118
|
+
stepperComponent: MyWizardStepperComponent,
|
|
119
|
+
steps: [...],
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
It reads `steps`, `currentIndex`, and `highestVisitedIndex` off the injected
|
|
124
|
+
`WIZARD_DIALOG_REF`, and calls `goTo()` to navigate. A custom stepper owns its
|
|
125
|
+
own ARIA — the built-in `role="tablist"` markup is not applied to it.
|
|
126
|
+
|
|
127
|
+
### Custom chrome: host display requirement
|
|
128
|
+
|
|
129
|
+
Each region wrapper is a flex container that mounts your component's **host
|
|
130
|
+
element** as its flex item. A host defaults to `display: block`, which
|
|
131
|
+
collapses the component's own internal layout (spacers, right-aligned
|
|
132
|
+
buttons). Every custom header / stepper / footer component must declare its
|
|
133
|
+
host display:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
@Component({
|
|
137
|
+
// ...
|
|
138
|
+
styles: `
|
|
139
|
+
:host {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
width: 100%;
|
|
143
|
+
}
|
|
144
|
+
`,
|
|
145
|
+
})
|
|
146
|
+
export class MyWizardFooterComponent {}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Symptom if you forget: the footer's spacer does nothing and buttons bunch to
|
|
150
|
+
the left.
|
|
151
|
+
|
|
152
|
+
### Chrome slots at a glance
|
|
153
|
+
|
|
154
|
+
All three regions follow the same pattern, so a consumer can override one and
|
|
155
|
+
keep the library defaults for the rest:
|
|
156
|
+
|
|
157
|
+
| Region | Config option | Falls back to |
|
|
158
|
+
| ------- | ------------------ | ---------------------------------- |
|
|
159
|
+
| Header | `headerComponent` | none (no default header) |
|
|
160
|
+
| Stepper | `stepperComponent` | built-in numbered pills |
|
|
161
|
+
| Footer | `footerComponent` | built-in Cancel/Back + Next/Submit |
|
|
162
|
+
|
|
71
163
|
## Features
|
|
72
164
|
|
|
73
165
|
- Service-driven: opens its own dialog with proper footer pinning
|
|
@@ -252,6 +344,8 @@ The footer's existing flex layout (`flex: 1 1 0` on each child) stretches all th
|
|
|
252
344
|
## Design Tokens
|
|
253
345
|
|
|
254
346
|
```scss
|
|
347
|
+
--fk-wizard-dialog-top-offset
|
|
348
|
+
--fk-wizard-dialog-header-padding
|
|
255
349
|
--fk-wizard-dialog-stepper-gap
|
|
256
350
|
--fk-wizard-dialog-stepper-padding
|
|
257
351
|
--fk-wizard-dialog-step-color
|