@praxisui/stepper 8.0.0-beta.20 → 8.0.0-beta.21

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.
@@ -1,19 +1,19 @@
1
1
  import * as i1$1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { Inject, Component, inject, ChangeDetectorRef, signal, ElementRef, Renderer2, EventEmitter, computed, TemplateRef, Output, Input, ContentChild, ChangeDetectionStrategy, ENVIRONMENT_INITIALIZER, isDevMode, effect, ViewChild } from '@angular/core';
4
+ import { Inject, Component, EventEmitter, inject, DestroyRef, Injector, ChangeDetectorRef, ViewContainerRef, ViewChild, Output, ChangeDetectionStrategy, Input, signal, ElementRef, Renderer2, effect, computed, TemplateRef, ContentChild, ENVIRONMENT_INITIALIZER, isDevMode } from '@angular/core';
5
5
  import { ActivatedRoute } from '@angular/router';
6
6
  import * as i2$1 from '@angular/material/stepper';
7
7
  import { MatStepperModule } from '@angular/material/stepper';
8
- import * as i6 from '@angular/material/button';
8
+ import * as i3$1 from '@angular/material/button';
9
9
  import { MatButtonModule } from '@angular/material/button';
10
- import * as i5$1 from '@angular/material/icon';
10
+ import * as i4$1 from '@angular/material/icon';
11
11
  import { MatIconModule } from '@angular/material/icon';
12
- import { providePraxisI18n, PraxisI18nService, IconPickerService, createEmptyRichContentDocument, PraxisIconDirective, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, DynamicWidgetLoaderDirective, EmptyStateCardComponent, EDITORIAL_WIDGET_TAG, ComponentMetadataRegistry, createCorporateLoggerConfig, ConsoleLoggerSink, CONFIG_STORAGE } from '@praxisui/core';
12
+ import { PraxisIconDirective, providePraxisI18n, PraxisI18nService, IconPickerService, createEmptyRichContentDocument, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, DynamicWidgetLoaderDirective, EmptyStateCardComponent, EDITORIAL_WIDGET_TAG, ComponentMetadataRegistry, createCorporateLoggerConfig, ConsoleLoggerSink, CONFIG_STORAGE } from '@praxisui/core';
13
13
  import * as i2 from '@angular/forms';
14
14
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
15
15
  import { PraxisDynamicFormConfigEditor, PraxisDynamicForm } from '@praxisui/dynamic-form';
16
- import { SettingsPanelService, SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
16
+ import { SETTINGS_PANEL_DATA, SettingsPanelService } from '@praxisui/settings-panel';
17
17
  import * as i3 from '@angular/material/form-field';
18
18
  import { MatFormFieldModule } from '@angular/material/form-field';
19
19
  import * as i4 from '@angular/material/input';
@@ -28,13 +28,16 @@ import * as i1 from '@angular/material/dialog';
28
28
  import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
29
29
  import * as i10 from '@angular/material/tabs';
30
30
  import { MatTabsModule } from '@angular/material/tabs';
31
- import { BehaviorSubject } from 'rxjs';
31
+ import { isObservable, firstValueFrom, BehaviorSubject, Subscription } from 'rxjs';
32
32
  import { PraxisListConfigEditor } from '@praxisui/list';
33
33
  import { PraxisFilesUploadConfigEditor } from '@praxisui/files-upload';
34
34
  import { ComponentPaletteDialogComponent } from '@praxisui/page-builder';
35
35
  import * as i5 from '@angular/material/checkbox';
36
36
  import { MatCheckboxModule } from '@angular/material/checkbox';
37
- import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
37
+ import * as i5$1 from '@angular/material/progress-spinner';
38
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
39
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
40
+ import { BaseAiAdapter, AiBackendApiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnOrchestratorService, createPraxisAssistantViewportLayout, PraxisAiAssistantShellComponent } from '@praxisui/ai';
38
41
  import { PraxisRichContent } from '@praxisui/rich-content';
39
42
  import { take } from 'rxjs/operators';
40
43
  import * as i1$2 from '@angular/material/card';
@@ -93,7 +96,7 @@ class SelectQuickConfigDialogComponent {
93
96
  <button mat-button (click)="cancel()">Cancelar</button>
94
97
  <button mat-flat-button color="primary" (click)="confirm()">Adicionar</button>
95
98
  </div>
96
- `, isInline: true, styles: [".g{display:grid}.gap-12{gap:12px}.w-full{width:100%}.row{display:flex}.ai-center{align-items:center}.gap-16{gap:16px}.g-auto-220{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
99
+ `, isInline: true, styles: [".g{display:grid}.gap-12{gap:12px}.w-full{width:100%}.row{display:flex}.ai-center{align-items:center}.gap-16{gap:16px}.g-auto-220{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
97
100
  }
98
101
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SelectQuickConfigDialogComponent, decorators: [{
99
102
  type: Component,
@@ -137,6 +140,283 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
137
140
  args: [MAT_DIALOG_DATA]
138
141
  }] }] });
139
142
 
143
+ class StepperNestedSettingsDialogComponent {
144
+ data;
145
+ dialogRef;
146
+ applied = new EventEmitter();
147
+ contentHost;
148
+ isDirty = false;
149
+ isValid = true;
150
+ isBusy = false;
151
+ contentRef;
152
+ destroyRef = inject(DestroyRef);
153
+ injector = inject(Injector);
154
+ cdr = inject(ChangeDetectorRef);
155
+ constructor(data, dialogRef) {
156
+ this.data = data;
157
+ this.dialogRef = dialogRef;
158
+ }
159
+ get canApply() {
160
+ return this.isDirty && this.isValid && !this.isBusy;
161
+ }
162
+ get canSave() {
163
+ return this.isDirty && this.isValid && !this.isBusy;
164
+ }
165
+ ngAfterViewInit() {
166
+ const childInjector = Injector.create({
167
+ parent: this.injector,
168
+ providers: [
169
+ {
170
+ provide: SETTINGS_PANEL_DATA,
171
+ useValue: {
172
+ id: this.data.id,
173
+ ...(this.data.inputs ?? {}),
174
+ },
175
+ },
176
+ ],
177
+ });
178
+ this.contentRef = this.contentHost.createComponent(this.data.component, {
179
+ injector: childInjector,
180
+ });
181
+ this.applyInputs(this.contentRef, this.data.inputs);
182
+ this.bindState(this.contentRef.instance);
183
+ this.contentRef.changeDetectorRef.detectChanges();
184
+ this.cdr.detectChanges();
185
+ }
186
+ onApply() {
187
+ if (!this.canApply) {
188
+ return;
189
+ }
190
+ this.applied.emit(this.getNestedValue());
191
+ }
192
+ onSave() {
193
+ if (!this.canSave) {
194
+ return;
195
+ }
196
+ const instance = this.contentRef?.instance;
197
+ const result = instance?.onSave?.();
198
+ if (isObservable(result)) {
199
+ firstValueFrom(result)
200
+ .then((value) => this.closeWithValue(value))
201
+ .catch(() => { });
202
+ return;
203
+ }
204
+ if (result instanceof Promise) {
205
+ result.then((value) => this.closeWithValue(value)).catch(() => { });
206
+ return;
207
+ }
208
+ this.closeWithValue(result !== undefined ? result : this.getNestedValue());
209
+ }
210
+ onReset() {
211
+ this.contentRef?.instance?.reset?.();
212
+ }
213
+ onCancel() {
214
+ this.dialogRef.close(undefined);
215
+ }
216
+ getNestedValue() {
217
+ return this.contentRef?.instance?.getSettingsValue?.();
218
+ }
219
+ closeWithValue(value) {
220
+ this.dialogRef.close({ action: 'save', value });
221
+ }
222
+ bindState(instance) {
223
+ instance.isDirty$
224
+ ?.pipe(takeUntilDestroyed(this.destroyRef))
225
+ .subscribe((dirty) => {
226
+ this.isDirty = dirty;
227
+ this.cdr.markForCheck();
228
+ });
229
+ instance.isValid$
230
+ ?.pipe(takeUntilDestroyed(this.destroyRef))
231
+ .subscribe((valid) => {
232
+ this.isValid = valid;
233
+ this.cdr.markForCheck();
234
+ });
235
+ instance.isBusy$
236
+ ?.pipe(takeUntilDestroyed(this.destroyRef))
237
+ .subscribe((busy) => {
238
+ this.isBusy = busy;
239
+ this.cdr.markForCheck();
240
+ });
241
+ const selected = instance?.selected;
242
+ if (selected && typeof selected.subscribe === 'function') {
243
+ const selected$ = typeof selected.pipe === 'function'
244
+ ? selected.pipe(takeUntilDestroyed(this.destroyRef))
245
+ : selected;
246
+ selected$.subscribe((value) => this.applied.emit(value));
247
+ }
248
+ }
249
+ applyInputs(contentRef, inputs) {
250
+ if (!inputs) {
251
+ return;
252
+ }
253
+ const supportedInputs = this.resolveSupportedInputs(contentRef);
254
+ for (const [key, value] of Object.entries(inputs)) {
255
+ if (supportedInputs && !supportedInputs.has(key)) {
256
+ continue;
257
+ }
258
+ try {
259
+ contentRef.setInput(key, value);
260
+ }
261
+ catch {
262
+ contentRef.instance[key] = value;
263
+ }
264
+ }
265
+ }
266
+ resolveSupportedInputs(contentRef) {
267
+ const declaredInputs = contentRef.componentType?.ɵcmp?.inputs;
268
+ if (!declaredInputs || typeof declaredInputs !== 'object') {
269
+ return null;
270
+ }
271
+ return new Set(Object.keys(declaredInputs));
272
+ }
273
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: StepperNestedSettingsDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
274
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: StepperNestedSettingsDialogComponent, isStandalone: true, selector: "praxis-stepper-nested-settings-dialog", outputs: { applied: "applied" }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `
275
+ <section class="pdx-stepper-nested-dialog" data-testid="stepper-nested-settings-dialog">
276
+ <header class="pdx-stepper-nested-dialog__header">
277
+ <div>
278
+ <p class="pdx-stepper-nested-dialog__eyebrow">Nested component editor</p>
279
+ <h2>{{ data.title }}</h2>
280
+ </div>
281
+ <button
282
+ mat-icon-button
283
+ type="button"
284
+ data-testid="stepper-nested-settings-cancel"
285
+ aria-label="Close nested editor"
286
+ (click)="onCancel()">
287
+ <mat-icon [praxisIcon]="'close'"></mat-icon>
288
+ </button>
289
+ </header>
290
+
291
+ <div class="pdx-stepper-nested-dialog__status" [class.invalid]="!isValid">
292
+ <mat-progress-spinner
293
+ *ngIf="isBusy"
294
+ diameter="18"
295
+ mode="indeterminate">
296
+ </mat-progress-spinner>
297
+ <span *ngIf="isBusy">Operation in progress...</span>
298
+ <span *ngIf="!isBusy && !isValid">Review the highlighted fields before applying.</span>
299
+ <span *ngIf="!isBusy && isValid && isDirty">Ready to apply nested changes.</span>
300
+ <span *ngIf="!isBusy && isValid && !isDirty">No nested changes yet.</span>
301
+ </div>
302
+
303
+ <div class="pdx-stepper-nested-dialog__body">
304
+ <ng-container #contentHost></ng-container>
305
+ </div>
306
+
307
+ <footer class="pdx-stepper-nested-dialog__footer">
308
+ <button
309
+ mat-button
310
+ type="button"
311
+ data-testid="stepper-nested-settings-reset"
312
+ [disabled]="isBusy"
313
+ (click)="onReset()">
314
+ Reset
315
+ </button>
316
+ <span class="pdx-stepper-nested-dialog__spacer"></span>
317
+ <button
318
+ mat-stroked-button
319
+ type="button"
320
+ data-testid="stepper-nested-settings-apply"
321
+ [disabled]="!canApply"
322
+ (click)="onApply()">
323
+ Apply
324
+ </button>
325
+ <button
326
+ mat-flat-button
327
+ color="primary"
328
+ type="button"
329
+ data-testid="stepper-nested-settings-save"
330
+ [disabled]="!canSave"
331
+ (click)="onSave()">
332
+ Save
333
+ </button>
334
+ </footer>
335
+ </section>
336
+ `, isInline: true, styles: [":host{display:block}.pdx-stepper-nested-dialog{--pdx-nested-surface: color-mix(in srgb, var(--md-sys-color-surface-container, #1f2630) 92%, black);background:var(--pdx-nested-surface);color:var(--md-sys-color-on-surface, #eef2ff);min-width:min(760px,88vw);max-width:92vw;max-height:86vh;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto;overflow:hidden}.pdx-stepper-nested-dialog__header,.pdx-stepper-nested-dialog__footer{display:flex;align-items:center;gap:12px;padding:16px 20px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #4b5563) 48%,transparent)}.pdx-stepper-nested-dialog__header{justify-content:space-between;border-bottom:1px solid}.pdx-stepper-nested-dialog__header h2{margin:0;font-size:18px;font-weight:800;letter-spacing:-.01em}.pdx-stepper-nested-dialog__eyebrow{margin:0 0 4px;color:var(--md-sys-color-primary, #8ab4ff);font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.pdx-stepper-nested-dialog__status{min-height:34px;display:flex;align-items:center;gap:8px;padding:8px 20px;color:var(--md-sys-color-on-surface-variant, #c7d2fe);background:color-mix(in srgb,var(--md-sys-color-primary-container, #1d3a5f) 18%,transparent);font-size:12px}.pdx-stepper-nested-dialog__status.invalid{color:var(--md-sys-color-error, #ffb4ab);background:color-mix(in srgb,var(--md-sys-color-error-container, #5f1b1b) 18%,transparent)}.pdx-stepper-nested-dialog__body{min-height:0;overflow:auto;padding:16px 20px 22px}.pdx-stepper-nested-dialog__footer{border-top:1px solid}.pdx-stepper-nested-dialog__spacer{flex:1 1 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
337
+ }
338
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: StepperNestedSettingsDialogComponent, decorators: [{
339
+ type: Component,
340
+ args: [{ selector: 'praxis-stepper-nested-settings-dialog', standalone: true, imports: [
341
+ CommonModule,
342
+ MatButtonModule,
343
+ MatDialogModule,
344
+ MatIconModule,
345
+ MatProgressSpinnerModule,
346
+ PraxisIconDirective,
347
+ ], template: `
348
+ <section class="pdx-stepper-nested-dialog" data-testid="stepper-nested-settings-dialog">
349
+ <header class="pdx-stepper-nested-dialog__header">
350
+ <div>
351
+ <p class="pdx-stepper-nested-dialog__eyebrow">Nested component editor</p>
352
+ <h2>{{ data.title }}</h2>
353
+ </div>
354
+ <button
355
+ mat-icon-button
356
+ type="button"
357
+ data-testid="stepper-nested-settings-cancel"
358
+ aria-label="Close nested editor"
359
+ (click)="onCancel()">
360
+ <mat-icon [praxisIcon]="'close'"></mat-icon>
361
+ </button>
362
+ </header>
363
+
364
+ <div class="pdx-stepper-nested-dialog__status" [class.invalid]="!isValid">
365
+ <mat-progress-spinner
366
+ *ngIf="isBusy"
367
+ diameter="18"
368
+ mode="indeterminate">
369
+ </mat-progress-spinner>
370
+ <span *ngIf="isBusy">Operation in progress...</span>
371
+ <span *ngIf="!isBusy && !isValid">Review the highlighted fields before applying.</span>
372
+ <span *ngIf="!isBusy && isValid && isDirty">Ready to apply nested changes.</span>
373
+ <span *ngIf="!isBusy && isValid && !isDirty">No nested changes yet.</span>
374
+ </div>
375
+
376
+ <div class="pdx-stepper-nested-dialog__body">
377
+ <ng-container #contentHost></ng-container>
378
+ </div>
379
+
380
+ <footer class="pdx-stepper-nested-dialog__footer">
381
+ <button
382
+ mat-button
383
+ type="button"
384
+ data-testid="stepper-nested-settings-reset"
385
+ [disabled]="isBusy"
386
+ (click)="onReset()">
387
+ Reset
388
+ </button>
389
+ <span class="pdx-stepper-nested-dialog__spacer"></span>
390
+ <button
391
+ mat-stroked-button
392
+ type="button"
393
+ data-testid="stepper-nested-settings-apply"
394
+ [disabled]="!canApply"
395
+ (click)="onApply()">
396
+ Apply
397
+ </button>
398
+ <button
399
+ mat-flat-button
400
+ color="primary"
401
+ type="button"
402
+ data-testid="stepper-nested-settings-save"
403
+ [disabled]="!canSave"
404
+ (click)="onSave()">
405
+ Save
406
+ </button>
407
+ </footer>
408
+ </section>
409
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.pdx-stepper-nested-dialog{--pdx-nested-surface: color-mix(in srgb, var(--md-sys-color-surface-container, #1f2630) 92%, black);background:var(--pdx-nested-surface);color:var(--md-sys-color-on-surface, #eef2ff);min-width:min(760px,88vw);max-width:92vw;max-height:86vh;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto;overflow:hidden}.pdx-stepper-nested-dialog__header,.pdx-stepper-nested-dialog__footer{display:flex;align-items:center;gap:12px;padding:16px 20px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #4b5563) 48%,transparent)}.pdx-stepper-nested-dialog__header{justify-content:space-between;border-bottom:1px solid}.pdx-stepper-nested-dialog__header h2{margin:0;font-size:18px;font-weight:800;letter-spacing:-.01em}.pdx-stepper-nested-dialog__eyebrow{margin:0 0 4px;color:var(--md-sys-color-primary, #8ab4ff);font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.pdx-stepper-nested-dialog__status{min-height:34px;display:flex;align-items:center;gap:8px;padding:8px 20px;color:var(--md-sys-color-on-surface-variant, #c7d2fe);background:color-mix(in srgb,var(--md-sys-color-primary-container, #1d3a5f) 18%,transparent);font-size:12px}.pdx-stepper-nested-dialog__status.invalid{color:var(--md-sys-color-error, #ffb4ab);background:color-mix(in srgb,var(--md-sys-color-error-container, #5f1b1b) 18%,transparent)}.pdx-stepper-nested-dialog__body{min-height:0;overflow:auto;padding:16px 20px 22px}.pdx-stepper-nested-dialog__footer{border-top:1px solid}.pdx-stepper-nested-dialog__spacer{flex:1 1 auto}\n"] }]
410
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
411
+ type: Inject,
412
+ args: [MAT_DIALOG_DATA]
413
+ }] }, { type: i1.MatDialogRef }], propDecorators: { applied: [{
414
+ type: Output
415
+ }], contentHost: [{
416
+ type: ViewChild,
417
+ args: ['contentHost', { read: ViewContainerRef, static: true }]
418
+ }] } });
419
+
140
420
  const PRAXIS_STEPPER_EN_US = {
141
421
  'praxis.stepper.editor.tabs.general': 'General',
142
422
  'praxis.stepper.editor.tabs.steps': 'Steps',
@@ -593,39 +873,53 @@ function resolvePraxisStepperText(i18n, key, fallback) {
593
873
 
594
874
  class PraxisStepperConfigEditor {
595
875
  i18n = inject(PraxisI18nService);
876
+ set stepperConfig(value) {
877
+ if (value == null) {
878
+ return;
879
+ }
880
+ this.initializeConfig(value, false);
881
+ }
596
882
  config = { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
597
883
  activeStepRef = null;
598
884
  // SettingsValueProvider observables
599
885
  isDirty$ = new BehaviorSubject(false);
600
886
  isValid$ = new BehaviorSubject(true);
601
887
  isBusy$ = new BehaviorSubject(false);
602
- settings = inject(SettingsPanelService);
603
888
  dialog = inject(MatDialog);
604
889
  iconPicker = inject(IconPickerService);
605
890
  cdr = inject(ChangeDetectorRef);
606
891
  constructor(data) {
607
892
  let seed = data?.config ?? data;
608
- // Normalize when seed is a JSON string
609
- if (typeof seed === 'string') {
893
+ this.initializeConfig(seed, true);
894
+ }
895
+ initializeConfig(seed, dirtyWhenEmpty) {
896
+ let normalizedSeed = seed;
897
+ if (typeof normalizedSeed === 'string') {
610
898
  try {
611
- seed = JSON.parse(seed);
899
+ normalizedSeed = JSON.parse(normalizedSeed);
612
900
  }
613
901
  catch {
614
- seed = undefined;
902
+ normalizedSeed = undefined;
615
903
  }
616
904
  }
617
- if (seed && typeof seed === 'object') {
618
- // shallow clone to detach references
619
- this.config = JSON.parse(JSON.stringify(seed));
905
+ if (normalizedSeed && typeof normalizedSeed === 'object') {
906
+ this.config = JSON.parse(JSON.stringify(normalizedSeed));
620
907
  if (!Array.isArray(this.config.steps)) {
621
908
  this.config.steps = [];
622
909
  }
910
+ this.isDirty$.next(false);
623
911
  }
624
912
  else {
625
- this.config.steps = [{ id: 'step1', label: this.tx('editor.defaults.newStep', 'New step') }];
626
- this.isDirty$.next(true);
913
+ this.config = {
914
+ steps: [{ id: 'step1', label: this.tx('editor.defaults.newStep', 'New step') }],
915
+ orientation: 'horizontal',
916
+ headerPosition: 'top',
917
+ linear: false,
918
+ };
919
+ this.isDirty$.next(dirtyWhenEmpty);
627
920
  }
628
921
  this.ensureActiveStep();
922
+ this.validate();
629
923
  }
630
924
  tx(key, fallback) {
631
925
  return resolvePraxisStepperText(this.i18n, key, fallback);
@@ -999,18 +1293,26 @@ class PraxisStepperConfigEditor {
999
1293
  const step = this.activeStep;
1000
1294
  if (!step)
1001
1295
  return;
1002
- const ref = this.settings.open({ id: `stepper:form:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureStepForm', 'Configure Step Form'), content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig: step.form?.config || { sections: [] }, formId: step.form?.formId || step.id, mode: step.form?.mode || 'create' } } });
1003
1296
  const apply = (val) => {
1004
1297
  const v = val || {};
1005
1298
  step.form = {
1006
- config: v.formConfig || step.form?.config || { sections: [] },
1299
+ config: v.formConfig || v.config || step.form?.config || { sections: [] },
1007
1300
  formId: v?.formId || step.form?.formId || step.id,
1008
- mode: v?.inputsPatch?.mode || step.form?.mode || 'create',
1301
+ mode: v?.inputsPatch?.mode || v?.bindings?.mode || step.form?.mode || 'create',
1009
1302
  };
1010
1303
  this.markDirty();
1011
1304
  };
1012
- ref.applied$.subscribe(apply);
1013
- ref.saved$.subscribe(apply);
1305
+ this.openNestedSettingsEditor({
1306
+ id: `stepper:form:${step.id || this.activeIndex}`,
1307
+ title: this.tx('editor.dialog.configureStepForm', 'Configure Step Form'),
1308
+ component: PraxisDynamicFormConfigEditor,
1309
+ inputs: {
1310
+ formConfig: step.form?.config || { sections: [] },
1311
+ formId: step.form?.formId || step.id,
1312
+ mode: step.form?.mode || 'create',
1313
+ },
1314
+ apply,
1315
+ });
1014
1316
  }
1015
1317
  editMainForm() { this.addMainForm(); }
1016
1318
  removeMainForm() { const s = this.activeStep; if (!s)
@@ -1023,16 +1325,27 @@ class PraxisStepperConfigEditor {
1023
1325
  const current = { ...(this.ensureWidgets().find(w => w.id === 'praxis-list')?.inputs?.config || {}) };
1024
1326
  // Ensure minimal selection setup
1025
1327
  current.selection = current.selection || { mode: 'single', return: 'value' };
1026
- const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'), content: { component: PraxisListConfigEditor, inputs: { config: current, listId: step.id || 'list' } } });
1328
+ let targetWidget;
1329
+ const listId = `${step.id || 'step'}-list-${Date.now()}`;
1027
1330
  const apply = (val) => {
1028
1331
  const cfg = (val && (val.config || val)) || current;
1029
- const wd = { id: 'praxis-list', inputs: { config: cfg, listId: `${step.id || 'step'}-list-${Date.now()}` } };
1030
1332
  const arr = this.ensureWidgets();
1031
- arr.push(wd);
1333
+ if (!targetWidget) {
1334
+ targetWidget = { id: 'praxis-list', inputs: { config: cfg, listId } };
1335
+ arr.push(targetWidget);
1336
+ }
1337
+ else {
1338
+ targetWidget.inputs = { ...(targetWidget.inputs || {}), config: cfg, listId };
1339
+ }
1032
1340
  this.markDirty();
1033
1341
  };
1034
- ref.applied$.subscribe(apply);
1035
- ref.saved$.subscribe(apply);
1342
+ this.openNestedSettingsEditor({
1343
+ id: `stepper:list:${step.id || this.activeIndex}`,
1344
+ title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'),
1345
+ component: PraxisListConfigEditor,
1346
+ inputs: { config: current, listId: step.id || 'list' },
1347
+ apply,
1348
+ });
1036
1349
  }
1037
1350
  addSearchableSelect() {
1038
1351
  const step = this.activeStep;
@@ -1062,14 +1375,26 @@ class PraxisStepperConfigEditor {
1062
1375
  const step = this.activeStep;
1063
1376
  if (!step)
1064
1377
  return;
1065
- const ref = this.settings.open({ id: `stepper:upload:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'), content: { component: PraxisFilesUploadConfigEditor, inputs: {} } });
1378
+ let targetWidget;
1379
+ const filesUploadId = `${step.id || 'step'}-upload-${Date.now()}`;
1066
1380
  const apply = (cfg) => {
1067
- const wd = { id: 'praxis-files-upload', inputs: { config: cfg, filesUploadId: `${step.id || 'step'}-upload-${Date.now()}` } };
1068
- this.ensureWidgets().push(wd);
1381
+ const arr = this.ensureWidgets();
1382
+ if (!targetWidget) {
1383
+ targetWidget = { id: 'praxis-files-upload', inputs: { config: cfg, filesUploadId } };
1384
+ arr.push(targetWidget);
1385
+ }
1386
+ else {
1387
+ targetWidget.inputs = { ...(targetWidget.inputs || {}), config: cfg, filesUploadId };
1388
+ }
1069
1389
  this.markDirty();
1070
1390
  };
1071
- ref.applied$.subscribe(apply);
1072
- ref.saved$.subscribe(apply);
1391
+ this.openNestedSettingsEditor({
1392
+ id: `stepper:upload:${step.id || this.activeIndex}`,
1393
+ title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'),
1394
+ component: PraxisFilesUploadConfigEditor,
1395
+ inputs: {},
1396
+ apply,
1397
+ });
1073
1398
  }
1074
1399
  openMoreComponents() {
1075
1400
  const dlg = this.dialog.open(ComponentPaletteDialogComponent, { width: '560px', data: { title: this.tx('editor.dialog.addComponentToStep', 'Add component to step'), allowedWidgetIds: ['praxis-dynamic-form', 'praxis-list', 'pdx-material-searchable-select', 'praxis-files-upload'] } });
@@ -1116,14 +1441,18 @@ class PraxisStepperConfigEditor {
1116
1441
  { rows: [[{ name: 'items', label: this.tx('editor.defaults.items', 'Items'), controlType: 'TRANSFER_LIST', transferOptions: { source: [], target: [] } }]] }
1117
1442
  ]
1118
1443
  };
1119
- const ref = this.settings.open({ id: `stepper:transfer:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureTransfer', 'Configure Item Transfer'), content: { component: PraxisDynamicFormConfigEditor, inputs: { formConfig, formId: step.id || 'transfer' } } });
1120
1444
  const apply = (val) => {
1121
1445
  const v = val || {};
1122
- step.form = { config: v.formConfig || formConfig, formId: v?.formId || step.id, mode: v?.inputsPatch?.mode || 'create' };
1446
+ step.form = { config: v.formConfig || v.config || formConfig, formId: v?.formId || step.id, mode: v?.inputsPatch?.mode || v?.bindings?.mode || 'create' };
1123
1447
  this.markDirty();
1124
1448
  };
1125
- ref.applied$.subscribe(apply);
1126
- ref.saved$.subscribe(apply);
1449
+ this.openNestedSettingsEditor({
1450
+ id: `stepper:transfer:${step.id || this.activeIndex}`,
1451
+ title: this.tx('editor.dialog.configureTransfer', 'Configure Item Transfer'),
1452
+ component: PraxisDynamicFormConfigEditor,
1453
+ inputs: { formConfig, formId: step.id || 'transfer' },
1454
+ apply,
1455
+ });
1127
1456
  }
1128
1457
  editWidget(w) {
1129
1458
  switch (w.id) {
@@ -1136,14 +1465,18 @@ class PraxisStepperConfigEditor {
1136
1465
  const step = this.activeStep;
1137
1466
  if (!step)
1138
1467
  return;
1139
- const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'), content: { component: PraxisListConfigEditor, inputs: { config: cfg, listId: step.id || 'list' } } });
1140
1468
  const apply = (val) => {
1141
1469
  const next = (val && (val.config || val)) || cfg;
1142
1470
  w.inputs = { ...(w.inputs || {}), config: next };
1143
1471
  this.markDirty();
1144
1472
  };
1145
- ref.applied$.subscribe(apply);
1146
- ref.saved$.subscribe(apply);
1473
+ this.openNestedSettingsEditor({
1474
+ id: `stepper:list:${step.id || this.activeIndex}`,
1475
+ title: this.tx('editor.dialog.configureListSelection', 'Configure List (selection)'),
1476
+ component: PraxisListConfigEditor,
1477
+ inputs: { config: cfg, listId: step.id || 'list' },
1478
+ apply,
1479
+ });
1147
1480
  break;
1148
1481
  }
1149
1482
  case 'pdx-material-searchable-select': {
@@ -1160,10 +1493,14 @@ class PraxisStepperConfigEditor {
1160
1493
  }
1161
1494
  case 'praxis-files-upload': {
1162
1495
  const cfg = w.inputs?.config || {};
1163
- const ref = this.settings.open({ id: `stepper:upload:edit`, title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'), content: { component: PraxisFilesUploadConfigEditor, inputs: { ...cfg } } });
1164
1496
  const apply = (val) => { w.inputs = { ...(w.inputs || {}), config: val }; this.markDirty(); };
1165
- ref.applied$.subscribe(apply);
1166
- ref.saved$.subscribe(apply);
1497
+ this.openNestedSettingsEditor({
1498
+ id: `stepper:upload:edit`,
1499
+ title: this.tx('editor.dialog.configureFilesUpload', 'Configure File Upload'),
1500
+ component: PraxisFilesUploadConfigEditor,
1501
+ inputs: { ...cfg },
1502
+ apply,
1503
+ });
1167
1504
  break;
1168
1505
  }
1169
1506
  default:
@@ -1171,6 +1508,32 @@ class PraxisStepperConfigEditor {
1171
1508
  break;
1172
1509
  }
1173
1510
  }
1511
+ openNestedSettingsEditor(options) {
1512
+ const dialogRef = this.dialog.open(StepperNestedSettingsDialogComponent, {
1513
+ width: 'min(960px, 92vw)',
1514
+ maxWidth: '96vw',
1515
+ maxHeight: '92vh',
1516
+ autoFocus: false,
1517
+ restoreFocus: false,
1518
+ data: {
1519
+ id: options.id,
1520
+ title: options.title,
1521
+ component: options.component,
1522
+ inputs: options.inputs,
1523
+ },
1524
+ });
1525
+ dialogRef.componentInstance?.applied.subscribe((value) => {
1526
+ options.apply(value);
1527
+ this.cdr.markForCheck();
1528
+ });
1529
+ dialogRef.afterClosed().subscribe((result) => {
1530
+ if (result?.action !== 'save') {
1531
+ return;
1532
+ }
1533
+ options.apply(result.value);
1534
+ this.cdr.markForCheck();
1535
+ });
1536
+ }
1174
1537
  // SettingsValueProvider
1175
1538
  getSettingsValue() { return this.config; }
1176
1539
  onSave() { return this.getSettingsValue(); }
@@ -1186,7 +1549,7 @@ class PraxisStepperConfigEditor {
1186
1549
  }
1187
1550
  }
1188
1551
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepperConfigEditor, deps: [{ token: SETTINGS_PANEL_DATA }], target: i0.ɵɵFactoryTarget.Component });
1189
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepperConfigEditor, isStandalone: true, selector: "praxis-stepper-config-editor", providers: [providePraxisStepperI18n()], ngImport: i0, template: `
1552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepperConfigEditor, isStandalone: true, selector: "praxis-stepper-config-editor", inputs: { stepperConfig: "stepperConfig" }, providers: [providePraxisStepperI18n()], ngImport: i0, template: `
1190
1553
  <div class="pdx-editor">
1191
1554
  <mat-tab-group>
1192
1555
  <mat-tab [label]="tx('editor.tabs.general', 'General')">
@@ -1780,7 +2143,7 @@ class PraxisStepperConfigEditor {
1780
2143
  </mat-tab>
1781
2144
  </mat-tab-group>
1782
2145
  </div>
1783
- `, isInline: true, styles: [".pdx-editor{display:grid;gap:16px}.pdx-editor .mat-mdc-form-field{width:100%}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-toggles{display:flex;gap:12px;flex-wrap:wrap}.tab-pad{padding:16px;display:grid;gap:16px;background:var(--md-sys-color-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 78%,transparent);border-radius:16px}.help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.editor-intro{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;padding:4px 2px 2px}.editor-intro-copy{display:grid;gap:6px;max-width:760px}.eyebrow{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);font-weight:600}.editor-title{font-size:22px;line-height:1.15;font-weight:650;color:var(--md-sys-color-on-surface)}.editor-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);line-height:1.45;font-size:14px}.editor-intro-meta{display:flex;gap:8px;align-items:flex-start}.meta-pill{display:grid;gap:2px;min-width:88px;padding:10px 12px;border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);background:var(--md-sys-color-surface-container-low)}.meta-label{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--md-sys-color-on-surface-variant)}.quick-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:6px}.icons-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin:8px 0}.icon-item{display:grid;gap:6px;align-content:start}.icons-hint{margin-top:4px}.settings-group{display:grid;gap:14px;padding:2px 0 4px}.settings-group+.settings-group,.settings-group+.disclosure,.disclosure+.settings-group{padding-top:18px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 60%,transparent)}.group-head{display:grid;gap:4px;max-width:72ch}.inline-actions-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;align-items:start}.inline-action-item{display:grid;gap:8px;align-content:start;min-width:0}.pdx-steps{display:grid;gap:12px;padding:4px 0 2px}.steps-workspace{display:grid;grid-template-columns:minmax(260px,320px) minmax(0,1fr);gap:24px;align-items:start}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.pdx-step-list{display:grid;gap:10px}.pdx-step-item{display:grid;grid-template-columns:20px 1fr auto;gap:10px;align-items:start;padding:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 68%,transparent);border-radius:14px;background:var(--md-sys-color-surface);cursor:pointer;outline:none}.pdx-step-item.active{border-color:color-mix(in srgb,var(--md-sys-color-primary) 55%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 26%,var(--md-sys-color-surface));box-shadow:none}.pdx-step-item:focus-visible{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.drag-handle{display:flex;align-items:center;color:var(--md-sys-color-on-surface-variant)}.step-summary{display:grid;gap:8px;min-width:0}.step-summary-head{display:grid;gap:2px}.step-summary-index{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--md-sys-color-on-surface-variant);font-weight:600}.step-summary-title{font-size:15px;line-height:1.3;font-weight:600;color:var(--md-sys-color-on-surface)}.step-summary-sub{font-size:12px;color:var(--md-sys-color-on-surface-variant);font-family:var(--md-ref-typeface-plain, monospace);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.step-summary-flags{display:flex;gap:6px;flex-wrap:wrap}.summary-chip{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:600}.summary-chip-warn{background:color-mix(in srgb,var(--md-sys-color-error-container) 60%,transparent);color:var(--md-sys-color-on-error-container)}.pdx-active-step{display:grid;gap:18px;min-width:0}.pdx-active-step .hdr{display:flex;gap:12px;align-items:flex-start;justify-content:space-between}.active-step-head{display:grid;gap:4px}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:12px;padding:0;border:none;border-radius:0;background:transparent}.section-body{display:grid;gap:12px}.section-title{font-weight:600;font-size:15px;color:var(--md-sys-color-on-surface)}.section-subtitle{font-size:13px;color:var(--md-sys-color-on-surface-variant);line-height:1.45}.section-head{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.editorial-section{padding-bottom:6px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 68%,transparent)}.detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.field-span-2{grid-column:span 2}.toggle-group{display:flex;gap:10px;flex-wrap:wrap;padding-top:4px}.disclosure{padding:0 0 12px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 62%,transparent)}.disclosure summary{list-style:none;display:flex;justify-content:space-between;align-items:baseline;gap:16px;cursor:pointer;padding:0;position:relative}.disclosure summary::-webkit-details-marker{display:none}.disclosure summary:after{content:\"expand_more\";font-family:Material Icons;font-size:18px;color:var(--md-sys-color-on-surface-variant);transition:transform .16s ease}.disclosure[open] summary:after{transform:rotate(180deg)}.disclosure summary:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 58%,transparent);outline-offset:4px;border-radius:8px}.disclosure-body{padding-top:12px}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:20px 1fr auto;align-items:start;gap:12px;padding:10px 0;border:none;border-radius:0;background:transparent;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.widget-item .info{display:grid;gap:2px;min-width:0}.widget-item .info .name{font-weight:600}.widget-item .info .sub{font-size:12px;color:var(--md-sys-color-on-surface-variant);line-height:1.45}.widget-item .info .meta{margin-top:2px;font-size:11px;color:var(--md-sys-color-on-surface-variant);font-family:var(--md-ref-typeface-plain, monospace);opacity:.85}.widget-item .actions{display:flex;gap:2px;flex-wrap:nowrap;justify-content:flex-end;align-items:flex-start;opacity:.92}.editorial-item{align-items:start}.editorial-item .actions{justify-content:flex-end}.cta-row{display:flex;gap:8px;align-items:center}.spacer{flex:1 1 auto}.muted{color:var(--md-sys-color-on-surface-variant)}.cta-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;margin-bottom:4px}.cta-row-item{display:grid;gap:10px;padding:12px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.tokens-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;margin:8px 0}.token-item{display:contents}.pdx-appearance{margin-top:8px;display:grid;gap:8px}.pdx-appearance-actions{display:flex;gap:8px;flex-wrap:wrap}.zone-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}.zone-column{display:grid;gap:10px;min-width:0}.zone-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.zone-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}.zone-title{font-weight:600}.zone-column+.zone-column{padding-left:16px;border-left:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.zone-count{font-size:12px;padding:2px 8px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.advanced-list{margin-top:4px}.form-row-card{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.form-row-main{display:flex;align-items:center;gap:12px;min-width:0}.form-row-actions{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}.code-card{margin-top:8px}.code-head{font-weight:600;margin-bottom:4px}.code{white-space:pre;overflow:auto;background:var(--md-sys-color-surface-container-highest)}.w-full{grid-column:1 / -1}.min-180{min-width:180px}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}.cta-row-item .cta-head{display:grid;grid-template-columns:20px 1fr;align-items:start;gap:10px}.cta-row-item .cta-title{font-weight:600;color:var(--md-sys-color-on-surface)}.cta-row-item .cta-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant);line-height:1.45;margin-top:2px}.cta-row-item .cta-actions{display:flex;gap:8px;align-items:center}.widget-item:last-child,.cta-row-item:last-child,.form-row-card:last-child{border-bottom:none}@media(max-width:900px){.editor-intro{flex-direction:column}.steps-workspace{grid-template-columns:1fr;gap:20px}.pdx-step-item{grid-template-columns:20px 1fr}.pdx-actions{grid-column:1 / -1;justify-self:end}.widget-item{grid-template-columns:20px 1fr}.widget-item .actions{grid-column:1 / -1;justify-content:flex-end}.form-row-card{flex-direction:column;align-items:flex-start}.form-row-actions{justify-content:flex-start}.zone-column+.zone-column{padding-left:0;border-left:none;padding-top:12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}}@media(max-width:640px){.tab-pad{padding:14px}.editor-title{font-size:20px}.pdx-active-step .hdr{align-items:flex-start;flex-direction:column}.detail-grid{grid-template-columns:1fr}.field-span-2{grid-column:auto}.toggle-group{flex-direction:column;align-items:flex-start}.zone-head{align-items:flex-start;flex-direction:column}.zone-actions,.widget-item .actions{justify-content:flex-start}.disclosure summary{flex-direction:column;align-items:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i8.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i8.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i8.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i10.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i10.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }] });
2146
+ `, isInline: true, styles: [".pdx-editor{display:grid;gap:16px}.pdx-editor .mat-mdc-form-field{width:100%}.pdx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}.pdx-toggles{display:flex;gap:12px;flex-wrap:wrap}.tab-pad{padding:16px;display:grid;gap:16px;background:var(--md-sys-color-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 78%,transparent);border-radius:16px}.help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.editor-intro{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;padding:4px 2px 2px}.editor-intro-copy{display:grid;gap:6px;max-width:760px}.eyebrow{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);font-weight:600}.editor-title{font-size:22px;line-height:1.15;font-weight:650;color:var(--md-sys-color-on-surface)}.editor-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);line-height:1.45;font-size:14px}.editor-intro-meta{display:flex;gap:8px;align-items:flex-start}.meta-pill{display:grid;gap:2px;min-width:88px;padding:10px 12px;border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);background:var(--md-sys-color-surface-container-low)}.meta-label{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--md-sys-color-on-surface-variant)}.quick-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:6px}.icons-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin:8px 0}.icon-item{display:grid;gap:6px;align-content:start}.icons-hint{margin-top:4px}.settings-group{display:grid;gap:14px;padding:2px 0 4px}.settings-group+.settings-group,.settings-group+.disclosure,.disclosure+.settings-group{padding-top:18px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 60%,transparent)}.group-head{display:grid;gap:4px;max-width:72ch}.inline-actions-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;align-items:start}.inline-action-item{display:grid;gap:8px;align-content:start;min-width:0}.pdx-steps{display:grid;gap:12px;padding:4px 0 2px}.steps-workspace{display:grid;grid-template-columns:minmax(260px,320px) minmax(0,1fr);gap:24px;align-items:start}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center;gap:16px}.pdx-step-list{display:grid;gap:10px}.pdx-step-item{display:grid;grid-template-columns:20px 1fr auto;gap:10px;align-items:start;padding:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 68%,transparent);border-radius:14px;background:var(--md-sys-color-surface);cursor:pointer;outline:none}.pdx-step-item.active{border-color:color-mix(in srgb,var(--md-sys-color-primary) 55%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 26%,var(--md-sys-color-surface));box-shadow:none}.pdx-step-item:focus-visible{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.drag-handle{display:flex;align-items:center;color:var(--md-sys-color-on-surface-variant)}.step-summary{display:grid;gap:8px;min-width:0}.step-summary-head{display:grid;gap:2px}.step-summary-index{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--md-sys-color-on-surface-variant);font-weight:600}.step-summary-title{font-size:15px;line-height:1.3;font-weight:600;color:var(--md-sys-color-on-surface)}.step-summary-sub{font-size:12px;color:var(--md-sys-color-on-surface-variant);font-family:var(--md-ref-typeface-plain, monospace);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.step-summary-flags{display:flex;gap:6px;flex-wrap:wrap}.summary-chip{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:600}.summary-chip-warn{background:color-mix(in srgb,var(--md-sys-color-error-container) 60%,transparent);color:var(--md-sys-color-on-error-container)}.pdx-active-step{display:grid;gap:18px;min-width:0}.pdx-active-step .hdr{display:flex;gap:12px;align-items:flex-start;justify-content:space-between}.active-step-head{display:grid;gap:4px}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:12px;padding:0;border:none;border-radius:0;background:transparent}.section-body{display:grid;gap:12px}.section-title{font-weight:600;font-size:15px;color:var(--md-sys-color-on-surface)}.section-subtitle{font-size:13px;color:var(--md-sys-color-on-surface-variant);line-height:1.45}.section-head{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.editorial-section{padding-bottom:6px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 68%,transparent)}.detail-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.field-span-2{grid-column:span 2}.toggle-group{display:flex;gap:10px;flex-wrap:wrap;padding-top:4px}.disclosure{padding:0 0 12px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 62%,transparent)}.disclosure summary{list-style:none;display:flex;justify-content:space-between;align-items:baseline;gap:16px;cursor:pointer;padding:0;position:relative}.disclosure summary::-webkit-details-marker{display:none}.disclosure summary:after{content:\"expand_more\";font-family:Material Icons;font-size:18px;color:var(--md-sys-color-on-surface-variant);transition:transform .16s ease}.disclosure[open] summary:after{transform:rotate(180deg)}.disclosure summary:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 58%,transparent);outline-offset:4px;border-radius:8px}.disclosure-body{padding-top:12px}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:20px 1fr auto;align-items:start;gap:12px;padding:10px 0;border:none;border-radius:0;background:transparent;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.widget-item .info{display:grid;gap:2px;min-width:0}.widget-item .info .name{font-weight:600}.widget-item .info .sub{font-size:12px;color:var(--md-sys-color-on-surface-variant);line-height:1.45}.widget-item .info .meta{margin-top:2px;font-size:11px;color:var(--md-sys-color-on-surface-variant);font-family:var(--md-ref-typeface-plain, monospace);opacity:.85}.widget-item .actions{display:flex;gap:2px;flex-wrap:nowrap;justify-content:flex-end;align-items:flex-start;opacity:.92}.editorial-item{align-items:start}.editorial-item .actions{justify-content:flex-end}.cta-row{display:flex;gap:8px;align-items:center}.spacer{flex:1 1 auto}.muted{color:var(--md-sys-color-on-surface-variant)}.cta-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;margin-bottom:4px}.cta-row-item{display:grid;gap:10px;padding:12px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.tokens-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;margin:8px 0}.token-item{display:contents}.pdx-appearance{margin-top:8px;display:grid;gap:8px}.pdx-appearance-actions{display:flex;gap:8px;flex-wrap:wrap}.zone-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px}.zone-column{display:grid;gap:10px;min-width:0}.zone-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.zone-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}.zone-title{font-weight:600}.zone-column+.zone-column{padding-left:16px;border-left:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.zone-count{font-size:12px;padding:2px 8px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.advanced-list{margin-top:4px}.form-row-card{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}.form-row-main{display:flex;align-items:center;gap:12px;min-width:0}.form-row-actions{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}.code-card{margin-top:8px}.code-head{font-weight:600;margin-bottom:4px}.code{white-space:pre;overflow:auto;background:var(--md-sys-color-surface-container-highest)}.w-full{grid-column:1 / -1}.min-180{min-width:180px}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}.cta-row-item .cta-head{display:grid;grid-template-columns:20px 1fr;align-items:start;gap:10px}.cta-row-item .cta-title{font-weight:600;color:var(--md-sys-color-on-surface)}.cta-row-item .cta-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant);line-height:1.45;margin-top:2px}.cta-row-item .cta-actions{display:flex;gap:8px;align-items:center}.widget-item:last-child,.cta-row-item:last-child,.form-row-card:last-child{border-bottom:none}@media(max-width:900px){.editor-intro{flex-direction:column}.steps-workspace{grid-template-columns:1fr;gap:20px}.pdx-step-item{grid-template-columns:20px 1fr}.pdx-actions{grid-column:1 / -1;justify-self:end}.widget-item{grid-template-columns:20px 1fr}.widget-item .actions{grid-column:1 / -1;justify-content:flex-end}.form-row-card{flex-direction:column;align-items:flex-start}.form-row-actions{justify-content:flex-start}.zone-column+.zone-column{padding-left:0;border-left:none;padding-top:12px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 56%,transparent)}}@media(max-width:640px){.tab-pad{padding:14px}.editor-title{font-size:20px}.pdx-active-step .hdr{align-items:flex-start;flex-direction:column}.detail-grid{grid-template-columns:1fr}.field-span-2{grid-column:auto}.toggle-group{flex-direction:column;align-items:flex-start}.zone-head{align-items:flex-start;flex-direction:column}.zone-actions,.widget-item .actions{justify-content:flex-start}.disclosure summary{flex-direction:column;align-items:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i8.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i8.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i8.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i10.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i10.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }] });
1784
2147
  }
1785
2148
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepperConfigEditor, decorators: [{
1786
2149
  type: Component,
@@ -2395,7 +2758,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2395
2758
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2396
2759
  type: Inject,
2397
2760
  args: [SETTINGS_PANEL_DATA]
2398
- }] }] });
2761
+ }] }], propDecorators: { stepperConfig: [{
2762
+ type: Input
2763
+ }] } });
2399
2764
 
2400
2765
  /**
2401
2766
  * Capabilities catalog for Praxis Stepper (StepperMetadata).
@@ -2531,6 +2896,8 @@ const STEPPER_AI_CAPABILITIES = {
2531
2896
 
2532
2897
  class StepperAiAdapter extends BaseAiAdapter {
2533
2898
  stepper;
2899
+ componentId = 'praxis-stepper';
2900
+ componentType = 'stepper';
2534
2901
  componentName = 'Praxis Stepper';
2535
2902
  constructor(stepper) {
2536
2903
  super();
@@ -2554,6 +2921,43 @@ class StepperAiAdapter extends BaseAiAdapter {
2554
2921
  hasForms: steps.some((s) => !!s.form),
2555
2922
  };
2556
2923
  }
2924
+ getDataProfile() {
2925
+ const cfg = this.getCurrentConfig();
2926
+ const steps = cfg.steps || [];
2927
+ return {
2928
+ stepperId: this.stepper.stepperId,
2929
+ stepCount: steps.length,
2930
+ formStepCount: steps.filter((step) => !!step.form).length,
2931
+ widgetStepCount: steps.filter((step) => Array.isArray(step.widgets) && step.widgets.length > 0).length,
2932
+ richContentStepCount: steps.filter((step) => (this.hasRichContent(step.stepBlocksBeforeForm)
2933
+ || this.hasRichContent(step.stepBlocksAfterForm))).length,
2934
+ linear: !!cfg.linear,
2935
+ orientation: cfg.orientation || 'horizontal',
2936
+ };
2937
+ }
2938
+ getSchemaFields() {
2939
+ return (this.getCurrentConfig().steps || []).map((step, index) => ({
2940
+ name: step.id || step.label || `step-${index + 1}`,
2941
+ label: step.label || step.id || `Etapa ${index + 1}`,
2942
+ optional: !!step.optional,
2943
+ hasForm: !!step.form,
2944
+ hasWidgets: Array.isArray(step.widgets) && step.widgets.length > 0,
2945
+ }));
2946
+ }
2947
+ getAuthoringContext() {
2948
+ return {
2949
+ authoringManifestRef: 'PRAXIS_STEPPER_AUTHORING_MANIFEST',
2950
+ runtimeAuthoringPolicy: {
2951
+ mode: 'agentic-authoring',
2952
+ enableCustomization: !!this.stepper.enableCustomization,
2953
+ canApplyLocalPatch: false,
2954
+ reason: 'praxis-stepper exige componentEditPlan validado pelo manifesto antes de aplicar mudancas runtime.',
2955
+ },
2956
+ domainCatalog: {
2957
+ recommendedAuthoringFlow: 'component_authoring',
2958
+ },
2959
+ };
2960
+ }
2557
2961
  createSnapshot() {
2558
2962
  return this.getCurrentConfig();
2559
2963
  }
@@ -2612,6 +3016,283 @@ class StepperAiAdapter extends BaseAiAdapter {
2612
3016
  return JSON.parse(JSON.stringify(config));
2613
3017
  }
2614
3018
  }
3019
+ hasRichContent(document) {
3020
+ return Array.isArray(document?.nodes) && document.nodes.length > 0;
3021
+ }
3022
+ }
3023
+
3024
+ class StepperAgenticAuthoringTurnFlow {
3025
+ adapter;
3026
+ aiApi;
3027
+ mode = 'agentic-authoring';
3028
+ constructor(adapter, aiApi) {
3029
+ this.adapter = adapter;
3030
+ this.aiApi = aiApi;
3031
+ }
3032
+ async submit(request) {
3033
+ const prompt = (request.prompt ?? '').trim();
3034
+ if (!prompt)
3035
+ return { state: 'listening', phase: 'capture', statusText: '' };
3036
+ const componentId = this.adapter.componentId || request.componentId || 'praxis-stepper';
3037
+ const componentType = this.adapter.componentType || request.componentType || 'stepper';
3038
+ const currentState = this.toAiJsonObject(this.adapter.getCurrentConfig());
3039
+ const dataProfile = this.optionalJsonObject(this.adapter.getDataProfile?.());
3040
+ const runtimeState = this.optionalJsonObject(this.adapter.getRuntimeState?.());
3041
+ const schemaFields = this.adapter.getSchemaFields?.()
3042
+ ?.map((field) => this.toAiJsonObject(field))
3043
+ .filter((field) => Object.keys(field).length > 0);
3044
+ const contextHints = this.optionalJsonObject(this.adapter.getAuthoringContext?.());
3045
+ if (this.shouldRouteToGovernedDecision(prompt, contextHints)) {
3046
+ return this.toGovernedDecisionHandoff(prompt, request);
3047
+ }
3048
+ const response = await firstValueFrom(this.aiApi.getPatch({
3049
+ componentId,
3050
+ componentType,
3051
+ userPrompt: prompt,
3052
+ sessionId: request.sessionId,
3053
+ clientTurnId: request.clientTurnId,
3054
+ messages: this.toChatMessages(request.messages, prompt),
3055
+ currentState,
3056
+ currentStateDigest: this.buildCurrentStateDigest(dataProfile),
3057
+ uiContextRef: { componentId, componentType },
3058
+ ...(dataProfile ? { dataProfile } : {}),
3059
+ ...(runtimeState ? { runtimeState } : {}),
3060
+ ...(schemaFields?.length ? { schemaFields } : {}),
3061
+ ...(contextHints ? { contextHints } : {}),
3062
+ }));
3063
+ return this.toTurnResult(this.compileAdapterResponse(response), request);
3064
+ }
3065
+ async apply(_request) {
3066
+ return {
3067
+ state: 'error',
3068
+ phase: 'apply',
3069
+ assistantMessage: 'O stepper ainda exige componentEditPlan validado pelo manifesto antes de aplicar mudancas locais.',
3070
+ errorText: 'Aplicacao local bloqueada ate existir compilacao manifest-backed para praxis-stepper.',
3071
+ canApply: false,
3072
+ pendingPatch: null,
3073
+ };
3074
+ }
3075
+ cancel() {
3076
+ return Promise.resolve({
3077
+ state: 'listening',
3078
+ phase: 'capture',
3079
+ assistantMessage: 'Solicitacao cancelada.',
3080
+ statusText: '',
3081
+ canApply: false,
3082
+ pendingPatch: null,
3083
+ pendingClarification: null,
3084
+ });
3085
+ }
3086
+ retry(request) {
3087
+ const lastPrompt = [...(request.messages ?? [])].reverse()
3088
+ .find((message) => message.role === 'user')?.text;
3089
+ return this.submit({ ...request, prompt: lastPrompt ?? request.prompt, action: { kind: 'retry' } });
3090
+ }
3091
+ toTurnResult(response, request) {
3092
+ if (!response) {
3093
+ return { state: 'error', phase: 'capture', assistantMessage: 'Resposta vazia da IA.', errorText: 'Resposta vazia da IA.' };
3094
+ }
3095
+ if (response.type === 'clarification') {
3096
+ return {
3097
+ state: 'clarification',
3098
+ phase: 'clarify',
3099
+ sessionId: response.sessionId ?? request.sessionId,
3100
+ assistantMessage: response.message || 'Preciso de mais detalhes para continuar.',
3101
+ clarificationQuestions: this.toClarificationQuestions(response),
3102
+ quickReplies: this.toQuickReplies(response),
3103
+ canApply: false,
3104
+ };
3105
+ }
3106
+ if (response.type === 'info') {
3107
+ const message = response.message || response.explanation || 'Informacao gerada.';
3108
+ return { state: 'success', phase: 'summarize', sessionId: response.sessionId ?? request.sessionId, assistantMessage: message, statusText: message, canApply: false };
3109
+ }
3110
+ if (response.type === 'error') {
3111
+ const message = response.message || 'Falha ao gerar alteracao de stepper.';
3112
+ return {
3113
+ state: 'error',
3114
+ phase: 'capture',
3115
+ sessionId: response.sessionId ?? request.sessionId,
3116
+ assistantMessage: message,
3117
+ errorText: message,
3118
+ diagnostics: response.warnings?.length ? { warnings: response.warnings } : undefined,
3119
+ };
3120
+ }
3121
+ if (response.patch && Object.keys(response.patch).length > 0) {
3122
+ return {
3123
+ state: 'error',
3124
+ phase: 'review',
3125
+ sessionId: response.sessionId ?? request.sessionId,
3126
+ assistantMessage: 'O stepper rejeitou patch livre. Gere um componentEditPlan validado pelo PRAXIS_STEPPER_AUTHORING_MANIFEST antes de propor alteracao local.',
3127
+ errorText: 'Patch livre de stepper rejeitado.',
3128
+ canApply: false,
3129
+ pendingPatch: null,
3130
+ diagnostics: {
3131
+ warnings: [
3132
+ 'free-stepper-patch-rejected',
3133
+ 'Use componentEditPlan validado contra PRAXIS_STEPPER_AUTHORING_MANIFEST.',
3134
+ ],
3135
+ },
3136
+ };
3137
+ }
3138
+ return {
3139
+ state: 'success',
3140
+ phase: 'summarize',
3141
+ sessionId: response.sessionId ?? request.sessionId,
3142
+ assistantMessage: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
3143
+ statusText: response.message || response.explanation || 'Nenhuma alteracao necessaria.',
3144
+ canApply: false,
3145
+ };
3146
+ }
3147
+ compileAdapterResponse(response) {
3148
+ const compiled = this.adapter.compileAiResponse?.(response);
3149
+ if (!compiled)
3150
+ return response;
3151
+ if (compiled.type === 'error') {
3152
+ return {
3153
+ type: 'error',
3154
+ message: compiled.message || 'O componentEditPlan do stepper nao passou na validacao de capacidades.',
3155
+ warnings: compiled.warnings,
3156
+ };
3157
+ }
3158
+ const warnings = [...(response.warnings ?? []), ...(compiled.warnings ?? [])];
3159
+ return { ...response, ...compiled, patch: compiled.patch, warnings: warnings.length ? warnings : undefined };
3160
+ }
3161
+ toChatMessages(messages, prompt) {
3162
+ const supported = (messages ?? [])
3163
+ .filter((message) => message.role === 'user' || message.role === 'assistant' || message.role === 'system')
3164
+ .map((message) => ({ role: message.role, content: message.text }))
3165
+ .filter((message) => message.content.trim().length > 0);
3166
+ return supported.length ? supported : [{ role: 'user', content: prompt }];
3167
+ }
3168
+ toClarificationQuestions(response) {
3169
+ const labels = response.questions?.length
3170
+ ? response.questions
3171
+ : response.message ? [response.message] : ['Qual ajuste voce quer aplicar no stepper?'];
3172
+ const options = this.toQuickReplies(response).map((reply) => ({ id: reply.id, label: reply.label, value: reply.prompt }));
3173
+ return labels.map((label, index) => ({
3174
+ id: `stepper-clarification-${index + 1}`,
3175
+ type: options.length ? 'single-choice' : 'text',
3176
+ label,
3177
+ allowCustom: true,
3178
+ options,
3179
+ }));
3180
+ }
3181
+ toQuickReplies(response) {
3182
+ const payloads = response.optionPayloads ?? [];
3183
+ if (payloads.length) {
3184
+ return payloads.map((option, index) => {
3185
+ const label = option.label?.trim() || option.value?.trim() || `Opcao ${index + 1}`;
3186
+ const prompt = option.example?.trim() || option.value?.trim() || label;
3187
+ return { id: `option-${index + 1}`, label, prompt, kind: 'clarification-option' };
3188
+ });
3189
+ }
3190
+ return (response.options ?? [])
3191
+ .filter((option) => !!option?.trim())
3192
+ .map((option, index) => ({ id: `option-${index + 1}`, label: option.trim(), prompt: option.trim(), kind: 'clarification-option' }));
3193
+ }
3194
+ buildCurrentStateDigest(dataProfile) {
3195
+ const stepCount = typeof dataProfile?.['stepCount'] === 'number' ? dataProfile['stepCount'] : undefined;
3196
+ return stepCount !== undefined ? { rowCount: stepCount } : {};
3197
+ }
3198
+ shouldRouteToGovernedDecision(prompt, contextHints) {
3199
+ const normalized = prompt.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
3200
+ const recommendedFlow = this.toRecord(contextHints?.['domainCatalog'])?.['recommendedAuthoringFlow'];
3201
+ if (recommendedFlow === 'shared_rule_authoring')
3202
+ return true;
3203
+ return [
3204
+ 'regra',
3205
+ 'politica',
3206
+ 'policy',
3207
+ 'compliance',
3208
+ 'lgpd',
3209
+ 'privacidade',
3210
+ 'aprovacao',
3211
+ 'aprovar',
3212
+ 'publicar',
3213
+ 'materializar',
3214
+ 'enforcement',
3215
+ 'validacao de negocio',
3216
+ 'validar negocio',
3217
+ 'elegibilidade',
3218
+ 'permissao',
3219
+ 'acesso',
3220
+ ].some((term) => normalized.includes(term));
3221
+ }
3222
+ toGovernedDecisionHandoff(prompt, request) {
3223
+ const message = 'Esse pedido parece alterar uma decisao de negocio compartilhada. O stepper pode localizar a etapa e a experiencia afetada, mas a regra deve seguir pelo fluxo governado de domain-rules antes de qualquer materializacao runtime.';
3224
+ return {
3225
+ state: 'clarification',
3226
+ phase: 'clarify',
3227
+ sessionId: request.sessionId,
3228
+ assistantMessage: message,
3229
+ statusText: 'Handoff governado necessario.',
3230
+ canApply: false,
3231
+ quickReplies: [
3232
+ {
3233
+ id: 'shared-rule-handoff',
3234
+ label: 'Continuar como regra governada',
3235
+ prompt,
3236
+ kind: 'shared-rule-handoff',
3237
+ description: 'Criar intake de domain-rules em vez de aplicar patch local no stepper.',
3238
+ icon: 'rule',
3239
+ tone: 'warning',
3240
+ contextHints: {
3241
+ flowId: 'shared_rule_authoring',
3242
+ source: 'praxis-stepper',
3243
+ recommendedAction: 'domain-rules/intake',
3244
+ },
3245
+ },
3246
+ ],
3247
+ clarificationQuestions: [
3248
+ {
3249
+ id: 'stepper-governed-rule-confirmation',
3250
+ type: 'confirm',
3251
+ label: 'Deseja continuar pelo fluxo governado de regras compartilhadas?',
3252
+ description: 'Esse caminho permite intake, simulacao, aprovacao/publicacao, materializacao e validacao de enforcement.',
3253
+ required: true,
3254
+ options: [
3255
+ {
3256
+ id: 'shared-rule-handoff',
3257
+ label: 'Sim, continuar governado',
3258
+ value: prompt,
3259
+ description: 'Nao aplicar como patch local do stepper.',
3260
+ contextHints: { flowId: 'shared_rule_authoring', source: 'praxis-stepper' },
3261
+ },
3262
+ ],
3263
+ },
3264
+ ],
3265
+ diagnostics: {
3266
+ governedDecisionHandoff: {
3267
+ flowId: 'shared_rule_authoring',
3268
+ sourcePrompt: prompt,
3269
+ sourceComponent: 'praxis-stepper',
3270
+ },
3271
+ },
3272
+ };
3273
+ }
3274
+ optionalJsonObject(value) {
3275
+ if (value === undefined || value === null)
3276
+ return undefined;
3277
+ const object = this.toAiJsonObject(value);
3278
+ return Object.keys(object).length ? object : undefined;
3279
+ }
3280
+ toAiJsonObject(value) {
3281
+ const record = this.toRecord(value);
3282
+ if (!record)
3283
+ return {};
3284
+ try {
3285
+ return JSON.parse(JSON.stringify(record));
3286
+ }
3287
+ catch {
3288
+ return {};
3289
+ }
3290
+ }
3291
+ toRecord(value) {
3292
+ return value && typeof value === 'object' && !Array.isArray(value)
3293
+ ? value
3294
+ : null;
3295
+ }
2615
3296
  }
2616
3297
 
2617
3298
  class PraxisStepper {
@@ -2685,10 +3366,37 @@ class PraxisStepper {
2685
3366
  catch {
2686
3367
  return undefined;
2687
3368
  } })();
3369
+ cdr = inject(ChangeDetectorRef);
3370
+ aiApi = inject(AiBackendApiService);
3371
+ assistantSessions = inject(PraxisAssistantSessionRegistryService);
3372
+ aiTurnOrchestrator = inject(PraxisAssistantTurnOrchestratorService);
3373
+ aiAssistantSessionEffect = effect(() => {
3374
+ const session = this.assistantSessions.activeSession();
3375
+ if (!session || session.id !== this.resolveAiAssistantSessionId())
3376
+ return;
3377
+ if (!this.aiAssistantOpen) {
3378
+ this.openAiAssistantFromSession(session);
3379
+ }
3380
+ }, ...(ngDevMode ? [{ debugName: "aiAssistantSessionEffect" }] : []));
2688
3381
  warnedMissingId = false;
2689
3382
  emptyStepRichContentDocument = createEmptyRichContentDocument();
2690
3383
  animationDone = new EventEmitter();
2691
3384
  aiAdapter = new StepperAiAdapter(this);
3385
+ aiAssistantOpen = false;
3386
+ aiAssistantPrompt = '';
3387
+ aiAssistantViewState = null;
3388
+ aiAssistantLayout = createPraxisAssistantViewportLayout();
3389
+ aiAssistantLabels = {
3390
+ title: 'Copiloto semantico Praxis',
3391
+ subtitle: 'Converse, revise e governe ajustes do stepper.',
3392
+ prompt: 'Mensagem',
3393
+ promptPlaceholder: 'Descreva o ajuste que voce precisa no fluxo.',
3394
+ emptyConversation: 'Diga o que voce quer alterar no stepper.',
3395
+ submit: 'Interpretar pedido',
3396
+ apply: 'Aplicar ajuste',
3397
+ };
3398
+ aiAssistantController = null;
3399
+ aiAssistantStateSubscription = null;
2692
3400
  // Computed getters
2693
3401
  steps = computed(() => this._config()?.steps || [], ...(ngDevMode ? [{ debugName: "steps" }] : []));
2694
3402
  orientation = computed(() => this._config()?.orientation || 'horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
@@ -2879,6 +3587,306 @@ class PraxisStepper {
2879
3587
  this.persistConfig(cloned);
2880
3588
  this.scheduleDomSync();
2881
3589
  }
3590
+ openAiAssistant() {
3591
+ this.initializeAiAssistantController();
3592
+ this.aiAssistantOpen = true;
3593
+ this.aiAssistantController?.setContextItems(this.buildAiAssistantContextItems());
3594
+ this.syncAiAssistantSession('active');
3595
+ this.cdr.markForCheck();
3596
+ }
3597
+ openAiAssistantFromSession(session) {
3598
+ if (session.id !== this.resolveAiAssistantSessionId())
3599
+ return;
3600
+ this.initializeAiAssistantController();
3601
+ this.aiAssistantOpen = true;
3602
+ this.aiAssistantController?.setContextItems(this.buildAiAssistantContextItems());
3603
+ this.syncAiAssistantSession('active');
3604
+ this.cdr.markForCheck();
3605
+ }
3606
+ closeAiAssistant() {
3607
+ this.aiAssistantOpen = false;
3608
+ this.syncAiAssistantSession('minimized');
3609
+ this.cdr.markForCheck();
3610
+ }
3611
+ onAiAssistantPromptChange(prompt) {
3612
+ this.aiAssistantPrompt = prompt;
3613
+ this.syncAiAssistantSession();
3614
+ }
3615
+ onAiAssistantSubmit(prompt) {
3616
+ this.aiAssistantController?.submitPrompt(prompt).subscribe((state) => {
3617
+ this.aiAssistantPrompt = '';
3618
+ this.aiAssistantViewState = state;
3619
+ this.syncAiAssistantSession();
3620
+ this.cdr.markForCheck();
3621
+ });
3622
+ }
3623
+ onAiAssistantApply() {
3624
+ this.aiAssistantController?.apply().subscribe((state) => {
3625
+ this.aiAssistantViewState = state;
3626
+ this.syncAiAssistantSession();
3627
+ this.cdr.markForCheck();
3628
+ });
3629
+ }
3630
+ onAiAssistantRetry() {
3631
+ this.aiAssistantController?.retry().subscribe((state) => {
3632
+ this.aiAssistantViewState = state;
3633
+ this.syncAiAssistantSession();
3634
+ this.cdr.markForCheck();
3635
+ });
3636
+ }
3637
+ onAiAssistantCancel() {
3638
+ this.aiAssistantController?.cancel().subscribe((state) => {
3639
+ this.aiAssistantPrompt = '';
3640
+ this.aiAssistantViewState = state;
3641
+ this.syncAiAssistantSession();
3642
+ this.cdr.markForCheck();
3643
+ });
3644
+ }
3645
+ onAiAssistantQuickReply(reply) {
3646
+ const controller = this.aiAssistantController;
3647
+ if (!controller)
3648
+ return;
3649
+ const state = controller.snapshot();
3650
+ const next$ = state.state === 'clarification'
3651
+ ? controller.answerClarification(reply.prompt)
3652
+ : controller.submitPrompt(reply.prompt, {
3653
+ kind: reply.kind || 'quick-reply',
3654
+ id: reply.id,
3655
+ value: reply.prompt,
3656
+ });
3657
+ next$.subscribe((nextState) => {
3658
+ this.aiAssistantPrompt = '';
3659
+ this.aiAssistantViewState = nextState;
3660
+ this.syncAiAssistantSession();
3661
+ this.cdr.markForCheck();
3662
+ });
3663
+ }
3664
+ onAiAssistantEditMessage(message) {
3665
+ this.aiAssistantPrompt = message.text;
3666
+ this.cdr.markForCheck();
3667
+ }
3668
+ onAiAssistantResendMessage(message) {
3669
+ this.aiAssistantController?.resendMessage(message.id).subscribe((state) => {
3670
+ this.aiAssistantPrompt = '';
3671
+ this.aiAssistantViewState = state;
3672
+ this.syncAiAssistantSession();
3673
+ this.cdr.markForCheck();
3674
+ });
3675
+ }
3676
+ onAiAssistantLayoutChange(layout) {
3677
+ this.aiAssistantLayout = layout;
3678
+ }
3679
+ buildAiAssistantContextItems() {
3680
+ const steps = this.steps();
3681
+ const items = [
3682
+ {
3683
+ id: 'component',
3684
+ label: 'Componente',
3685
+ value: 'Stepper',
3686
+ kind: 'component',
3687
+ icon: 'view_timeline',
3688
+ },
3689
+ {
3690
+ id: 'stepper-id',
3691
+ label: 'Stepper',
3692
+ value: this.safeAiAssistantStepperId(),
3693
+ kind: 'custom',
3694
+ icon: 'tag',
3695
+ },
3696
+ {
3697
+ id: 'steps',
3698
+ label: 'Etapas',
3699
+ value: String(steps.length),
3700
+ kind: 'custom',
3701
+ icon: 'format_list_numbered',
3702
+ },
3703
+ ];
3704
+ const selected = steps[this.selectedIndexComputed()];
3705
+ if (selected) {
3706
+ items.push({
3707
+ id: 'selected-step',
3708
+ label: 'Etapa ativa',
3709
+ value: selected.label || selected.id || String(this.selectedIndexComputed()),
3710
+ kind: 'custom',
3711
+ icon: 'ads_click',
3712
+ });
3713
+ }
3714
+ return items;
3715
+ }
3716
+ initializeAiAssistantController() {
3717
+ if (this.aiAssistantController)
3718
+ return;
3719
+ const flow = new StepperAgenticAuthoringTurnFlow(this.aiAdapter, this.aiApi);
3720
+ const controller = this.aiTurnOrchestrator.createController(flow, {
3721
+ componentId: this.aiAdapter.componentId || 'praxis-stepper',
3722
+ componentType: this.aiAdapter.componentType || 'stepper',
3723
+ contextItems: this.buildAiAssistantContextItems(),
3724
+ });
3725
+ this.aiAssistantController = controller;
3726
+ this.aiAssistantViewState = controller.snapshot();
3727
+ this.aiAssistantStateSubscription?.unsubscribe();
3728
+ this.aiAssistantStateSubscription = controller.state$.subscribe((state) => {
3729
+ this.aiAssistantViewState = state;
3730
+ this.syncAiAssistantSession();
3731
+ this.cdr.markForCheck();
3732
+ });
3733
+ this.cdr.markForCheck();
3734
+ }
3735
+ buildAiAssistantContextSnapshot() {
3736
+ const counts = this.collectAiAssistantCounts();
3737
+ const stepNames = this.collectAiAssistantStepNames();
3738
+ return {
3739
+ identity: {
3740
+ sessionId: this.resolveAiAssistantSessionId(),
3741
+ ownerId: this.resolveAiAssistantOwnerId(),
3742
+ ownerType: 'stepper',
3743
+ componentId: 'praxis-stepper',
3744
+ componentType: 'stepper',
3745
+ routeKey: this.resolveAiAssistantRouteKey(),
3746
+ },
3747
+ target: {
3748
+ kind: 'component',
3749
+ id: this.resolveAiAssistantOwnerId(),
3750
+ label: this.safeAiAssistantStepperId(),
3751
+ metadata: {
3752
+ stepperId: this.safeAiAssistantStepperId(),
3753
+ hasCustomization: !!this.enableCustomization,
3754
+ },
3755
+ },
3756
+ contextItems: this.buildAiAssistantContextItems().map((item) => ({
3757
+ id: item.id,
3758
+ label: item.label,
3759
+ value: item.value || '',
3760
+ kind: item.kind,
3761
+ })),
3762
+ mode: 'agentic-authoring',
3763
+ authoringManifestRef: {
3764
+ componentId: 'praxis-stepper',
3765
+ source: 'PRAXIS_STEPPER_AUTHORING_MANIFEST',
3766
+ },
3767
+ schemaFields: stepNames.length ? stepNames : undefined,
3768
+ dataProfileDigest: {
3769
+ summary: `${counts.stepCount} etapa(s), ${counts.formStepCount} formulario(s), ${counts.widgetStepCount} grupo(s) de widget(s)`,
3770
+ counts,
3771
+ },
3772
+ runtimeStateDigest: {
3773
+ summary: `Stepper ${this.linear() ? 'linear' : 'nao linear'}, etapa ativa ${this.selectedIndexComputed() + 1}`,
3774
+ fields: [
3775
+ 'steps',
3776
+ 'selectedIndex',
3777
+ 'linear',
3778
+ 'orientation',
3779
+ ],
3780
+ },
3781
+ capabilityRefs: [
3782
+ {
3783
+ id: 'stepper.component-edit-plan',
3784
+ label: 'Plano de edicao de stepper',
3785
+ source: 'PRAXIS_STEPPER_AUTHORING_MANIFEST',
3786
+ risk: 'medium',
3787
+ },
3788
+ ],
3789
+ governanceHints: [
3790
+ {
3791
+ kind: 'business-rule-boundary',
3792
+ label: 'Regras compartilhadas exigem governanca',
3793
+ reason: 'Politicas de acesso, validacoes reutilizaveis e compliance nao devem ser aplicadas como patch local do stepper.',
3794
+ risk: 'high',
3795
+ },
3796
+ ],
3797
+ };
3798
+ }
3799
+ syncAiAssistantSession(visibility = null) {
3800
+ if (!this.enableCustomization)
3801
+ return;
3802
+ if (!this.aiAssistantOpen && !this.hasAiAssistantSessionState() && visibility !== 'minimized')
3803
+ return;
3804
+ const state = this.aiAssistantViewState;
3805
+ this.assistantSessions.upsertContextSession(this.buildAiAssistantContextSnapshot(), {
3806
+ title: 'Copiloto semantico Praxis',
3807
+ summary: this.resolveAiAssistantSummary(),
3808
+ mode: state?.mode || 'agentic-authoring',
3809
+ state: state?.state || 'idle',
3810
+ visibility: visibility ?? (this.aiAssistantOpen ? 'active' : 'minimized'),
3811
+ badge: this.resolveAiAssistantBadge(),
3812
+ icon: this.resolveAiAssistantIcon(),
3813
+ });
3814
+ }
3815
+ hasAiAssistantSessionState() {
3816
+ return !!this.aiAssistantPrompt.trim()
3817
+ || !!this.aiAssistantViewState?.messages?.length
3818
+ || !!this.aiAssistantViewState?.quickReplies?.length
3819
+ || !!this.aiAssistantViewState?.pendingPatch
3820
+ || !!this.aiAssistantViewState?.statusText?.trim()
3821
+ || !!this.aiAssistantViewState?.errorText?.trim();
3822
+ }
3823
+ resolveAiAssistantSessionId() {
3824
+ return `stepper:${this.resolveAiAssistantRouteKey()}:${this.resolveAiAssistantOwnerId()}`;
3825
+ }
3826
+ resolveAiAssistantOwnerId() {
3827
+ return (this.componentInstanceId || this.safeAiAssistantStepperId() || 'stepper').trim() || 'stepper';
3828
+ }
3829
+ safeAiAssistantStepperId() {
3830
+ return String(this.stepperId || '').trim();
3831
+ }
3832
+ resolveAiAssistantRouteKey() {
3833
+ const routePath = this.route?.snapshot?.routeConfig?.path?.trim();
3834
+ return routePath || 'local';
3835
+ }
3836
+ resolveAiAssistantSummary() {
3837
+ const status = this.aiAssistantViewState?.statusText?.trim();
3838
+ if (status)
3839
+ return status;
3840
+ const error = this.aiAssistantViewState?.errorText?.trim();
3841
+ if (error)
3842
+ return error;
3843
+ const prompt = this.aiAssistantPrompt.trim();
3844
+ if (prompt)
3845
+ return prompt.length > 96 ? `${prompt.slice(0, 93)}...` : prompt;
3846
+ const lastMessage = [...(this.aiAssistantViewState?.messages ?? [])].reverse()
3847
+ .find((message) => message.role === 'assistant' || message.role === 'user');
3848
+ if (lastMessage?.text) {
3849
+ return lastMessage.text.length > 96 ? `${lastMessage.text.slice(0, 93)}...` : lastMessage.text;
3850
+ }
3851
+ return 'Assistente contextual do stepper.';
3852
+ }
3853
+ resolveAiAssistantBadge() {
3854
+ const state = this.aiAssistantViewState?.state;
3855
+ if (state === 'error')
3856
+ return 'erro';
3857
+ if (state === 'clarification')
3858
+ return 'revisar';
3859
+ if (state === 'review')
3860
+ return 'preview';
3861
+ if (state === 'success')
3862
+ return 'ok';
3863
+ return undefined;
3864
+ }
3865
+ resolveAiAssistantIcon() {
3866
+ const state = this.aiAssistantViewState?.state;
3867
+ if (state === 'error')
3868
+ return 'error';
3869
+ if (state === 'clarification')
3870
+ return 'rule';
3871
+ if (state === 'review')
3872
+ return 'rate_review';
3873
+ return 'auto_awesome';
3874
+ }
3875
+ collectAiAssistantStepNames() {
3876
+ return Array.from(new Set(this.steps()
3877
+ .map((step, index) => step.id || step.label || `step-${index + 1}`)
3878
+ .filter((name) => typeof name === 'string' && !!name.trim())));
3879
+ }
3880
+ collectAiAssistantCounts() {
3881
+ const steps = this.steps();
3882
+ return {
3883
+ stepCount: steps.length,
3884
+ formStepCount: steps.filter((step) => !!step.form).length,
3885
+ widgetStepCount: steps.filter((step) => Array.isArray(step.widgets) && step.widgets.length > 0).length,
3886
+ richContentStepCount: steps.filter((step) => (this.hasRichContent(step.stepBlocksBeforeForm)
3887
+ || this.hasRichContent(step.stepBlocksAfterForm))).length,
3888
+ };
3889
+ }
2882
3890
  // CTA helpers
2883
3891
  addFirstStep() {
2884
3892
  const current = this._config() || { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
@@ -2996,6 +4004,10 @@ class PraxisStepper {
2996
4004
  dedupeKey: 'praxis-stepper:missing-stepper-id',
2997
4005
  });
2998
4006
  }
4007
+ ngOnDestroy() {
4008
+ this.assistantSessions.removeContextSession(this.buildAiAssistantContextSnapshot().identity);
4009
+ this.aiAssistantStateSubscription?.unsubscribe();
4010
+ }
2999
4011
  ngOnInit() {
3000
4012
  const key = this.storageKey();
3001
4013
  if (!key)
@@ -3055,8 +4067,45 @@ class PraxisStepper {
3055
4067
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
3056
4068
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepper, isStandalone: true, selector: "praxis-stepper", inputs: { stepperId: "stepperId", componentInstanceId: "componentInstanceId", config: "config", selectedIndexInput: "selectedIndexInput", selectedIndex: "selectedIndex", disableRippleInput: "disableRippleInput", enableCustomization: "enableCustomization", labelPosition: "labelPosition", color: "color", serverValidate: "serverValidate", stepperContext: "stepperContext" }, outputs: { selectedIndexChange: "selectedIndexChange", widgetEvent: "widgetEvent", stepFormReady: "stepFormReady", stepFormValueChange: "stepFormValueChange", animationDone: "animationDone", selectionChange: "selectionChange" }, host: { properties: { "class": "densityClass()" } }, queries: [{ propertyName: "stepLabelTpl", first: true, predicate: ["stepLabelTpl"], descendants: true, read: TemplateRef }], ngImport: i0, template: `
3057
4069
  <div class="stepper-ai-assistant" *ngIf="enableCustomization">
3058
- <praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
4070
+ <button
4071
+ mat-mini-fab
4072
+ color="primary"
4073
+ type="button"
4074
+ class="stepper-ai-assistant-trigger"
4075
+ aria-label="Abrir copiloto semantico Praxis do stepper"
4076
+ data-testid="praxis-stepper-ai-assistant-trigger"
4077
+ (click)="openAiAssistant()"
4078
+ >
4079
+ <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
4080
+ </button>
3059
4081
  </div>
4082
+ <praxis-ai-assistant-shell
4083
+ *ngIf="aiAssistantOpen && aiAssistantViewState"
4084
+ [mode]="aiAssistantViewState.mode"
4085
+ [state]="aiAssistantViewState.state"
4086
+ [contextItems]="aiAssistantViewState.contextItems"
4087
+ [attachments]="aiAssistantViewState.attachments"
4088
+ [messages]="aiAssistantViewState.messages"
4089
+ [quickReplies]="aiAssistantViewState.quickReplies"
4090
+ [prompt]="aiAssistantPrompt"
4091
+ [statusText]="aiAssistantViewState.statusText"
4092
+ [errorText]="aiAssistantViewState.errorText"
4093
+ [busy]="aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'"
4094
+ [canApply]="aiAssistantViewState.canApply"
4095
+ [labels]="aiAssistantLabels"
4096
+ [layout]="aiAssistantLayout"
4097
+ testIdPrefix="praxis-stepper-ai-assistant"
4098
+ (promptChange)="onAiAssistantPromptChange($event)"
4099
+ (submitPrompt)="onAiAssistantSubmit($event)"
4100
+ (apply)="onAiAssistantApply()"
4101
+ (retryTurn)="onAiAssistantRetry()"
4102
+ (cancelTurn)="onAiAssistantCancel()"
4103
+ (quickReply)="onAiAssistantQuickReply($event)"
4104
+ (editMessage)="onAiAssistantEditMessage($event)"
4105
+ (resendMessage)="onAiAssistantResendMessage($event)"
4106
+ (layoutChange)="onAiAssistantLayoutChange($event)"
4107
+ (close)="closeAiAssistant()"
4108
+ ></praxis-ai-assistant-shell>
3060
4109
  <ng-container *ngIf="steps().length > 0; else emptyState">
3061
4110
  <mat-stepper
3062
4111
  #stepperRoot
@@ -3211,16 +4260,53 @@ class PraxisStepper {
3211
4260
  >
3212
4261
  <mat-icon fontIcon="edit"></mat-icon>
3213
4262
  </button>
3214
- `, isInline: true, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatStepperModule }, { kind: "component", type: i2$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i2$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i2$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: i2$1.MatStepperIcon, selector: "ng-template[matStepperIcon]", inputs: ["matStepperIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "formId", "componentInstanceId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantComponent, selector: "praxis-ai-assistant", inputs: ["adapter", "riskPolicy", "allowManualPatchEdit"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4263
+ `, isInline: true, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}.stepper-ai-assistant-trigger{box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatStepperModule }, { kind: "component", type: i2$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i2$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i2$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: i2$1.MatStepperIcon, selector: "ng-template[matStepperIcon]", inputs: ["matStepperIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "submitUrl", "submitMethod", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "formId", "componentInstanceId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "layoutChange"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3215
4264
  }
3216
4265
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepper, decorators: [{
3217
4266
  type: Component,
3218
- args: [{ selector: 'praxis-stepper', standalone: true, imports: [CommonModule, ReactiveFormsModule, MatStepperModule, MatButtonModule, MatIconModule, PraxisIconDirective, PraxisDynamicForm, DynamicWidgetLoaderDirective, EmptyStateCardComponent, PraxisAiAssistantComponent, PraxisRichContent], host: {
4267
+ args: [{ selector: 'praxis-stepper', standalone: true, imports: [CommonModule, ReactiveFormsModule, MatStepperModule, MatButtonModule, MatIconModule, PraxisIconDirective, PraxisDynamicForm, DynamicWidgetLoaderDirective, EmptyStateCardComponent, PraxisAiAssistantShellComponent, PraxisRichContent], host: {
3219
4268
  '[class]': 'densityClass()'
3220
4269
  }, template: `
3221
4270
  <div class="stepper-ai-assistant" *ngIf="enableCustomization">
3222
- <praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
4271
+ <button
4272
+ mat-mini-fab
4273
+ color="primary"
4274
+ type="button"
4275
+ class="stepper-ai-assistant-trigger"
4276
+ aria-label="Abrir copiloto semantico Praxis do stepper"
4277
+ data-testid="praxis-stepper-ai-assistant-trigger"
4278
+ (click)="openAiAssistant()"
4279
+ >
4280
+ <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
4281
+ </button>
3223
4282
  </div>
4283
+ <praxis-ai-assistant-shell
4284
+ *ngIf="aiAssistantOpen && aiAssistantViewState"
4285
+ [mode]="aiAssistantViewState.mode"
4286
+ [state]="aiAssistantViewState.state"
4287
+ [contextItems]="aiAssistantViewState.contextItems"
4288
+ [attachments]="aiAssistantViewState.attachments"
4289
+ [messages]="aiAssistantViewState.messages"
4290
+ [quickReplies]="aiAssistantViewState.quickReplies"
4291
+ [prompt]="aiAssistantPrompt"
4292
+ [statusText]="aiAssistantViewState.statusText"
4293
+ [errorText]="aiAssistantViewState.errorText"
4294
+ [busy]="aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'"
4295
+ [canApply]="aiAssistantViewState.canApply"
4296
+ [labels]="aiAssistantLabels"
4297
+ [layout]="aiAssistantLayout"
4298
+ testIdPrefix="praxis-stepper-ai-assistant"
4299
+ (promptChange)="onAiAssistantPromptChange($event)"
4300
+ (submitPrompt)="onAiAssistantSubmit($event)"
4301
+ (apply)="onAiAssistantApply()"
4302
+ (retryTurn)="onAiAssistantRetry()"
4303
+ (cancelTurn)="onAiAssistantCancel()"
4304
+ (quickReply)="onAiAssistantQuickReply($event)"
4305
+ (editMessage)="onAiAssistantEditMessage($event)"
4306
+ (resendMessage)="onAiAssistantResendMessage($event)"
4307
+ (layoutChange)="onAiAssistantLayoutChange($event)"
4308
+ (close)="closeAiAssistant()"
4309
+ ></praxis-ai-assistant-shell>
3224
4310
  <ng-container *ngIf="steps().length > 0; else emptyState">
3225
4311
  <mat-stepper
3226
4312
  #stepperRoot
@@ -3375,7 +4461,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3375
4461
  >
3376
4462
  <mat-icon fontIcon="edit"></mat-icon>
3377
4463
  </button>
3378
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}\n"] }]
4464
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;padding:12px;box-shadow:var(--mat-elevation-level1)}.praxis-stepper.pdx-stepper-ft-light{background:transparent;border:none;border-radius:0;padding:0;box-shadow:none}:host(.density-compact) ::ng-deep .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) ::ng-deep .mat-step-header{min-height:44px}.pdx-step-content{padding:12px 4px 8px;color:var(--md-sys-color-on-surface)}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}::ng-deep .praxis-stepper .mat-step-header{border-radius:999px;margin:4px 0;color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label{color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .praxis-stepper .mat-step-header.cdk-keyboard-focused,::ng-deep .praxis-stepper .mat-step-header.cdk-program-focused{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}::ng-deep .praxis-stepper .mat-step-icon{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}::ng-deep .praxis-stepper .mat-step-icon-selected{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}::ng-deep .praxis-stepper .mat-step-icon-state-done{background:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}::ng-deep .praxis-stepper .mat-step-icon-state-error{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}::ng-deep .praxis-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}::ng-deep .praxis-stepper .mat-stepper-vertical-line:before{border-left-color:var(--md-sys-color-outline-variant)}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal{background:transparent;--mat-stepper-header-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-on-surface) 8%, transparent );--mat-stepper-header-focus-state-layer-color: transparent;--mat-stepper-header-hover-state-layer-shape: 14px;--mat-stepper-header-focus-state-layer-shape: 14px}::ng-deep .pdx-stepper-ft-light .mat-step-header{margin:0}::ng-deep .pdx-stepper-ft-light .mat-step-header .mat-step-header-ripple{display:none}::ng-deep .ft-stepper{background:transparent}.ft-stepper-content{padding:0}.ft-stepper-content .form-section{border:none;padding:0;background:transparent}.nav-align-start{justify-content:flex-start}.nav-align-center{justify-content:center}.nav-align-end{justify-content:flex-end}.nav-align-space-between{justify-content:space-between}.edit-fab{position:absolute;right:12px;bottom:12px;z-index:2}.stepper-ai-assistant{position:absolute;right:12px;bottom:72px;z-index:3}.stepper-ai-assistant-trigger{box-shadow:var(--md-sys-elevation-level2, 0 4px 12px rgba(0, 0, 0, .18))}\n"] }]
3379
4465
  }], propDecorators: { stepLabelTpl: [{
3380
4466
  type: ContentChild,
3381
4467
  args: ['stepLabelTpl', { read: TemplateRef }]
@@ -3416,6 +4502,86 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
3416
4502
  type: Output
3417
4503
  }] } });
3418
4504
 
4505
+ class PraxisStepperWidgetConfigEditor {
4506
+ inputs = null;
4507
+ widgetKey;
4508
+ stepperEditor;
4509
+ isDirty$ = new BehaviorSubject(false);
4510
+ isValid$ = new BehaviorSubject(true);
4511
+ isBusy$ = new BehaviorSubject(false);
4512
+ subscription = new Subscription();
4513
+ emptyConfig = {
4514
+ steps: [],
4515
+ orientation: 'horizontal',
4516
+ headerPosition: 'top',
4517
+ linear: false,
4518
+ };
4519
+ get config() {
4520
+ return this.inputs?.config ?? this.emptyConfig;
4521
+ }
4522
+ get stepperId() {
4523
+ return this.inputs?.stepperId ?? this.widgetKey;
4524
+ }
4525
+ ngAfterViewInit() {
4526
+ if (!this.stepperEditor) {
4527
+ return;
4528
+ }
4529
+ this.subscription.add(this.stepperEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
4530
+ this.subscription.add(this.stepperEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
4531
+ this.subscription.add(this.stepperEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
4532
+ }
4533
+ ngOnDestroy() {
4534
+ this.subscription.unsubscribe();
4535
+ }
4536
+ getSettingsValue() {
4537
+ return this.buildValue(this.stepperEditor?.getSettingsValue());
4538
+ }
4539
+ onSave() {
4540
+ return this.buildValue(this.stepperEditor?.onSave?.() ?? this.stepperEditor?.getSettingsValue());
4541
+ }
4542
+ reset() {
4543
+ this.stepperEditor?.reset();
4544
+ }
4545
+ buildValue(config) {
4546
+ const nextConfig = config ?? this.config;
4547
+ return {
4548
+ inputs: {
4549
+ ...(this.inputs ?? {}),
4550
+ config: nextConfig,
4551
+ ...(this.stepperId ? { stepperId: this.stepperId } : {}),
4552
+ ...(typeof nextConfig.selectedIndex === 'number' ? { selectedIndex: nextConfig.selectedIndex } : {}),
4553
+ },
4554
+ };
4555
+ }
4556
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepperWidgetConfigEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
4557
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisStepperWidgetConfigEditor, isStandalone: true, selector: "praxis-stepper-widget-config-editor", inputs: { inputs: "inputs", widgetKey: "widgetKey" }, viewQueries: [{ propertyName: "stepperEditor", first: true, predicate: ["stepperEditor"], descendants: true }], ngImport: i0, template: `
4558
+ <section data-testid="stepper-widget-config-editor">
4559
+ <praxis-stepper-config-editor #stepperEditor [stepperConfig]="config" />
4560
+ </section>
4561
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PraxisStepperConfigEditor, selector: "praxis-stepper-config-editor", inputs: ["stepperConfig"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4562
+ }
4563
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisStepperWidgetConfigEditor, decorators: [{
4564
+ type: Component,
4565
+ args: [{
4566
+ selector: 'praxis-stepper-widget-config-editor',
4567
+ standalone: true,
4568
+ imports: [CommonModule, PraxisStepperConfigEditor],
4569
+ template: `
4570
+ <section data-testid="stepper-widget-config-editor">
4571
+ <praxis-stepper-config-editor #stepperEditor [stepperConfig]="config" />
4572
+ </section>
4573
+ `,
4574
+ changeDetection: ChangeDetectionStrategy.OnPush,
4575
+ }]
4576
+ }], propDecorators: { inputs: [{
4577
+ type: Input
4578
+ }], widgetKey: [{
4579
+ type: Input
4580
+ }], stepperEditor: [{
4581
+ type: ViewChild,
4582
+ args: ['stepperEditor']
4583
+ }] } });
4584
+
3419
4585
  class PraxisWizardBenefitsGridComponent {
3420
4586
  blockId;
3421
4587
  title;
@@ -3440,7 +4606,7 @@ class PraxisWizardBenefitsGridComponent {
3440
4606
  </div>
3441
4607
  </div>
3442
4608
  </section>
3443
- `, isInline: true, styles: [":host{display:block}.pwx-benefits{display:flex;flex-direction:column;gap:10px}.pwx-benefits-title{margin:0;font-size:.9rem;font-weight:600;color:var(--md-sys-color-on-surface);letter-spacing:.02em;display:flex;align-items:center;gap:12px}.pwx-benefits-title:before,.pwx-benefits-title:after{content:\"\";height:1px;flex:1;background:var(--md-sys-color-outline-variant)}.pwx-benefits-grid{display:grid;grid-template-columns:repeat(var(--pwx-columns),minmax(0,1fr));gap:12px 16px;align-items:start}.pwx-benefits-grid.is-boxed{padding:12px 14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface)}.pwx-benefit{display:flex;gap:10px;align-items:flex-start;min-height:0}.pwx-benefit-icon{width:24px;min-width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;line-height:1;color:var(--praxis-wizard-accent, var(--md-sys-color-primary))}.pwx-benefit-icon mat-icon{width:24px;height:24px;font-size:24px;line-height:24px;display:block;overflow:visible}.pwx-benefit-title{font-weight:600;font-size:.88rem;color:var(--md-sys-color-on-surface)}.pwx-benefit-text{font-size:.82rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));line-height:1.35}@media(max-width:720px){.pwx-benefits-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:480px){.pwx-benefits-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4609
+ `, isInline: true, styles: [":host{display:block}.pwx-benefits{display:flex;flex-direction:column;gap:10px}.pwx-benefits-title{margin:0;font-size:.9rem;font-weight:600;color:var(--md-sys-color-on-surface);letter-spacing:.02em;display:flex;align-items:center;gap:12px}.pwx-benefits-title:before,.pwx-benefits-title:after{content:\"\";height:1px;flex:1;background:var(--md-sys-color-outline-variant)}.pwx-benefits-grid{display:grid;grid-template-columns:repeat(var(--pwx-columns),minmax(0,1fr));gap:12px 16px;align-items:start}.pwx-benefits-grid.is-boxed{padding:12px 14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface)}.pwx-benefit{display:flex;gap:10px;align-items:flex-start;min-height:0}.pwx-benefit-icon{width:24px;min-width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;line-height:1;color:var(--praxis-wizard-accent, var(--md-sys-color-primary))}.pwx-benefit-icon mat-icon{width:24px;height:24px;font-size:24px;line-height:24px;display:block;overflow:visible}.pwx-benefit-title{font-weight:600;font-size:.88rem;color:var(--md-sys-color-on-surface)}.pwx-benefit-text{font-size:.82rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));line-height:1.35}@media(max-width:720px){.pwx-benefits-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:480px){.pwx-benefits-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3444
4610
  }
3445
4611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisWizardBenefitsGridComponent, decorators: [{
3446
4612
  type: Component,
@@ -3595,6 +4761,14 @@ const PRAXIS_STEPPER_COMPONENT_METADATA = {
3595
4761
  friendlyName: 'Praxis Stepper',
3596
4762
  description: 'Stepper configurável (horizontal/vertical/linear) com passos e conteúdo dinâmico.',
3597
4763
  icon: 'format_list_numbered',
4764
+ authoringManifestRef: {
4765
+ componentId: 'praxis-stepper',
4766
+ source: 'PRAXIS_STEPPER_AUTHORING_MANIFEST',
4767
+ },
4768
+ configEditor: {
4769
+ component: PraxisStepperWidgetConfigEditor,
4770
+ title: 'Configure stepper',
4771
+ },
3598
4772
  inputs: [
3599
4773
  { name: 'stepperId', type: 'string', label: 'ID do Stepper', description: 'Identificador para persistência (obrigatório)' },
3600
4774
  { name: 'componentInstanceId', type: 'string', label: 'ID da instância', description: 'Identificador opcional para múltiplas instâncias na mesma rota' },
@@ -4232,7 +5406,7 @@ class PraxisWizardCtaBarComponent {
4232
5406
  {{ primaryLabel }}
4233
5407
  </button>
4234
5408
  </div>
4235
- `, isInline: true, styles: [":host{display:block}.pwx-cta{display:flex;justify-content:flex-end;align-items:center;gap:12px;padding-top:16px}.pwx-cta:not(.has-secondary){justify-content:center}.pwx-cta.is-sticky{position:sticky;bottom:0;background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface));padding:12px 0 8px;border-top:1px solid var(--praxis-wizard-border, var(--md-sys-color-outline-variant))}.pwx-cta.has-secondary .pwx-cta-primary{min-width:200px}.pwx-cta-primary{min-width:240px;height:36px;border-radius:4px;font-weight:600;text-transform:none;padding:0 18px}.pwx-cta-secondary{color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));text-transform:none;font-weight:500;padding:0 4px;min-width:auto}@media(max-width:600px){.pwx-cta{flex-direction:column;align-items:stretch}.pwx-cta-primary{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5409
+ `, isInline: true, styles: [":host{display:block}.pwx-cta{display:flex;justify-content:flex-end;align-items:center;gap:12px;padding-top:16px}.pwx-cta:not(.has-secondary){justify-content:center}.pwx-cta.is-sticky{position:sticky;bottom:0;background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface));padding:12px 0 8px;border-top:1px solid var(--praxis-wizard-border, var(--md-sys-color-outline-variant))}.pwx-cta.has-secondary .pwx-cta-primary{min-width:200px}.pwx-cta-primary{min-width:240px;height:36px;border-radius:4px;font-weight:600;text-transform:none;padding:0 18px}.pwx-cta-secondary{color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));text-transform:none;font-weight:500;padding:0 4px;min-width:auto}@media(max-width:600px){.pwx-cta{flex-direction:column;align-items:stretch}.pwx-cta-primary{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4236
5410
  }
4237
5411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisWizardCtaBarComponent, decorators: [{
4238
5412
  type: Component,
@@ -5003,4 +6177,4 @@ const PRAXIS_STEPPER_AUTHORING_MANIFEST = {
5003
6177
  * Generated bundle index. Do not edit.
5004
6178
  */
5005
6179
 
5006
- export { FT_WIZARD_CONFIG, FT_WIZARD_JSON, PRAXIS_STEPPER_AUTHORING_MANIFEST, PRAXIS_STEPPER_COMPONENT_METADATA, PRAXIS_WIZARD_BENEFITS_METADATA, PRAXIS_WIZARD_CONTENT_METADATA, PRAXIS_WIZARD_DIVIDER_METADATA, PRAXIS_WIZARD_NOTICE_METADATA, PraxisStepper, PraxisStepperConfigEditor, PraxisWizardFormComponent, STEPPER_AI_CAPABILITIES, providePraxisStepperMetadata };
6180
+ export { FT_WIZARD_CONFIG, FT_WIZARD_JSON, PRAXIS_STEPPER_AUTHORING_MANIFEST, PRAXIS_STEPPER_COMPONENT_METADATA, PRAXIS_WIZARD_BENEFITS_METADATA, PRAXIS_WIZARD_CONTENT_METADATA, PRAXIS_WIZARD_DIVIDER_METADATA, PRAXIS_WIZARD_NOTICE_METADATA, PraxisStepper, PraxisStepperConfigEditor, PraxisStepperWidgetConfigEditor, PraxisWizardFormComponent, STEPPER_AI_CAPABILITIES, providePraxisStepperMetadata };