@praxisui/stepper 1.0.0-beta.30 → 1.0.0-beta.41

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,14 +1,15 @@
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, signal, EventEmitter, computed, TemplateRef, Output, Input, ContentChild, ChangeDetectionStrategy, ENVIRONMENT_INITIALIZER } from '@angular/core';
4
+ import { Inject, Component, inject, signal, EventEmitter, computed, TemplateRef, Output, Input, ContentChild, ChangeDetectionStrategy, ENVIRONMENT_INITIALIZER, isDevMode, ElementRef, Renderer2, effect, ViewChild } from '@angular/core';
5
+ import { ActivatedRoute } from '@angular/router';
5
6
  import * as i2$1 from '@angular/material/stepper';
6
7
  import { MatStepperModule } from '@angular/material/stepper';
7
8
  import * as i6 from '@angular/material/button';
8
9
  import { MatButtonModule } from '@angular/material/button';
9
10
  import * as i5$1 from '@angular/material/icon';
10
11
  import { MatIconModule } from '@angular/material/icon';
11
- import { IconPickerService, PraxisIconDirective, DynamicWidgetLoaderDirective, EmptyStateCardComponent, ComponentMetadataRegistry } from '@praxisui/core';
12
+ import { IconPickerService, PraxisIconDirective, deepMerge, ASYNC_CONFIG_STORAGE, ComponentKeyService, LoggerService, DynamicWidgetLoaderDirective, EmptyStateCardComponent, ComponentMetadataRegistry, createCorporateLoggerConfig, ConsoleLoggerSink, CONFIG_STORAGE } from '@praxisui/core';
12
13
  import * as i2 from '@angular/forms';
13
14
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
14
15
  import { PraxisDynamicFormConfigEditor, PraxisDynamicForm } from '@praxisui/dynamic-form';
@@ -30,7 +31,9 @@ import * as i11 from '@angular/material/button-toggle';
30
31
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
31
32
  import * as i1 from '@angular/material/dialog';
32
33
  import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
33
- import * as i12 from '@angular/material/tabs';
34
+ import * as i12 from '@angular/material/menu';
35
+ import { MatMenuModule } from '@angular/material/menu';
36
+ import * as i13 from '@angular/material/tabs';
34
37
  import { MatTabsModule } from '@angular/material/tabs';
35
38
  import { BehaviorSubject } from 'rxjs';
36
39
  import { PraxisListConfigEditor } from '@praxisui/list';
@@ -38,6 +41,8 @@ import { PraxisFilesUploadConfigEditor } from '@praxisui/files-upload';
38
41
  import { ComponentPaletteDialogComponent } from '@praxisui/page-builder';
39
42
  import * as i5 from '@angular/material/checkbox';
40
43
  import { MatCheckboxModule } from '@angular/material/checkbox';
44
+ import { BaseAiAdapter, PraxisAiAssistantComponent } from '@praxisui/ai';
45
+ import { take } from 'rxjs/operators';
41
46
 
42
47
  class SelectQuickConfigDialogComponent {
43
48
  ref;
@@ -136,6 +141,340 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
136
141
  args: [MAT_DIALOG_DATA]
137
142
  }] }] });
138
143
 
144
+ class WizardWidgetConfigDialogComponent {
145
+ ref;
146
+ wizardWidgetId;
147
+ dialogTitle;
148
+ model;
149
+ originalInputs;
150
+ constructor(ref, data) {
151
+ this.ref = ref;
152
+ const id = (data?.widgetId || '');
153
+ this.wizardWidgetId = this.isWizardWidgetId(id) ? id : null;
154
+ this.originalInputs = { ...(data?.inputs || {}) };
155
+ this.model = this.buildDraft(this.originalInputs);
156
+ this.dialogTitle = this.resolveTitle(this.wizardWidgetId);
157
+ }
158
+ get benefits() {
159
+ if (!Array.isArray(this.model.items))
160
+ this.model.items = [];
161
+ return this.model.items;
162
+ }
163
+ addBenefit() {
164
+ this.benefits.push({ title: '', text: '', icon: '' });
165
+ }
166
+ removeBenefit(index) {
167
+ this.benefits.splice(index, 1);
168
+ }
169
+ cancel() {
170
+ this.ref.close();
171
+ }
172
+ save() {
173
+ const next = { ...this.originalInputs, ...this.buildInputsForWidget() };
174
+ if (typeof next.blockId === 'string') {
175
+ next.blockId = next.blockId.trim();
176
+ }
177
+ if (!next.blockId)
178
+ delete next.blockId;
179
+ this.ref.close({ inputs: next });
180
+ }
181
+ isWizardWidgetId(value) {
182
+ return (value === 'praxis-wizard-benefits'
183
+ || value === 'praxis-wizard-content'
184
+ || value === 'praxis-wizard-inline-notice'
185
+ || value === 'praxis-wizard-divider');
186
+ }
187
+ resolveTitle(id) {
188
+ switch (id) {
189
+ case 'praxis-wizard-benefits':
190
+ return 'Editar grade de benefícios';
191
+ case 'praxis-wizard-content':
192
+ return 'Editar bloco de conteúdo';
193
+ case 'praxis-wizard-inline-notice':
194
+ return 'Editar aviso inline';
195
+ case 'praxis-wizard-divider':
196
+ return 'Editar divisor';
197
+ default:
198
+ return 'Editar Widget do Wizard';
199
+ }
200
+ }
201
+ buildDraft(inputs) {
202
+ return {
203
+ blockId: inputs.blockId || '',
204
+ title: inputs.title || '',
205
+ subtitle: inputs.subtitle || '',
206
+ text: inputs.text || '',
207
+ caption: inputs.caption || '',
208
+ tone: inputs.tone || 'neutral',
209
+ label: inputs.label || '',
210
+ columns: Number.isFinite(Number(inputs.columns)) ? Number(inputs.columns) : 4,
211
+ boxed: !!inputs.boxed,
212
+ items: Array.isArray(inputs.items)
213
+ ? inputs.items.map((item) => ({ icon: item?.icon || '', title: item?.title || '', text: item?.text || '' }))
214
+ : [],
215
+ };
216
+ }
217
+ buildInputsForWidget() {
218
+ if (!this.wizardWidgetId)
219
+ return { ...this.model };
220
+ const base = {};
221
+ if (this.model.blockId?.trim())
222
+ base.blockId = this.model.blockId.trim();
223
+ switch (this.wizardWidgetId) {
224
+ case 'praxis-wizard-inline-notice':
225
+ base.text = this.model.text || '';
226
+ base.tone = this.model.tone || 'neutral';
227
+ return base;
228
+ case 'praxis-wizard-content':
229
+ base.title = this.model.title || '';
230
+ base.subtitle = this.model.subtitle || '';
231
+ base.text = this.model.text || '';
232
+ base.caption = this.model.caption || '';
233
+ return base;
234
+ case 'praxis-wizard-divider':
235
+ base.label = this.model.label || '';
236
+ return base;
237
+ case 'praxis-wizard-benefits':
238
+ base.title = this.model.title || '';
239
+ base.columns = this.safeColumns(this.model.columns);
240
+ base.boxed = !!this.model.boxed;
241
+ base.items = this.benefits
242
+ .map((item) => ({
243
+ icon: item.icon || '',
244
+ title: item.title || '',
245
+ text: item.text || '',
246
+ }))
247
+ .filter((item) => item.title || item.text || item.icon);
248
+ return base;
249
+ default:
250
+ return base;
251
+ }
252
+ }
253
+ safeColumns(value) {
254
+ const parsed = Number(value);
255
+ if (!Number.isFinite(parsed) || parsed < 1)
256
+ return 1;
257
+ return Math.floor(parsed);
258
+ }
259
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: WizardWidgetConfigDialogComponent, deps: [{ token: i1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
260
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: WizardWidgetConfigDialogComponent, isStandalone: true, selector: "praxis-wizard-widget-config-dialog", ngImport: i0, template: `
261
+ <h2 mat-dialog-title>{{ dialogTitle }}</h2>
262
+
263
+ <div mat-dialog-content class="dialog-grid">
264
+ <ng-container [ngSwitch]="wizardWidgetId">
265
+ <ng-container *ngSwitchCase="'praxis-wizard-inline-notice'">
266
+ <mat-form-field appearance="outline" class="full">
267
+ <mat-label>Texto</mat-label>
268
+ <input matInput [(ngModel)]="model.text" placeholder="Mensagem do aviso" />
269
+ </mat-form-field>
270
+ <mat-form-field appearance="outline">
271
+ <mat-label>Tom</mat-label>
272
+ <select matNativeControl [(ngModel)]="model.tone">
273
+ <option value="neutral">Neutro</option>
274
+ <option value="info">Informativo</option>
275
+ <option value="warning">Atenção</option>
276
+ </select>
277
+ </mat-form-field>
278
+ </ng-container>
279
+
280
+ <ng-container *ngSwitchCase="'praxis-wizard-content'">
281
+ <mat-form-field appearance="outline">
282
+ <mat-label>Título</mat-label>
283
+ <input matInput [(ngModel)]="model.title" />
284
+ </mat-form-field>
285
+ <mat-form-field appearance="outline">
286
+ <mat-label>Subtítulo</mat-label>
287
+ <input matInput [(ngModel)]="model.subtitle" />
288
+ </mat-form-field>
289
+ <mat-form-field appearance="outline" class="full">
290
+ <mat-label>Texto</mat-label>
291
+ <input matInput [(ngModel)]="model.text" />
292
+ </mat-form-field>
293
+ <mat-form-field appearance="outline" class="full">
294
+ <mat-label>Legenda</mat-label>
295
+ <input matInput [(ngModel)]="model.caption" />
296
+ </mat-form-field>
297
+ </ng-container>
298
+
299
+ <ng-container *ngSwitchCase="'praxis-wizard-divider'">
300
+ <mat-form-field appearance="outline" class="full">
301
+ <mat-label>Rótulo</mat-label>
302
+ <input matInput [(ngModel)]="model.label" placeholder="Opcional" />
303
+ </mat-form-field>
304
+ </ng-container>
305
+
306
+ <ng-container *ngSwitchCase="'praxis-wizard-benefits'">
307
+ <mat-form-field appearance="outline">
308
+ <mat-label>Título</mat-label>
309
+ <input matInput [(ngModel)]="model.title" />
310
+ </mat-form-field>
311
+ <mat-form-field appearance="outline">
312
+ <mat-label>Colunas</mat-label>
313
+ <input matInput type="number" min="1" [(ngModel)]="model.columns" />
314
+ </mat-form-field>
315
+ <mat-checkbox [(ngModel)]="model.boxed">Cards com contorno</mat-checkbox>
316
+
317
+ <div class="benefits">
318
+ <div class="benefits-head">
319
+ <strong>Itens de benefício</strong>
320
+ <button mat-stroked-button type="button" (click)="addBenefit()">Adicionar item</button>
321
+ </div>
322
+ <div class="benefit-card" *ngFor="let item of benefits; let i = index">
323
+ <div class="benefit-head">
324
+ <span>Item {{ i + 1 }}</span>
325
+ <button mat-button color="warn" type="button" (click)="removeBenefit(i)">Remover</button>
326
+ </div>
327
+ <mat-form-field appearance="outline">
328
+ <mat-label>Ícone</mat-label>
329
+ <input matInput [(ngModel)]="item.icon" placeholder="Ex.: info" />
330
+ </mat-form-field>
331
+ <mat-form-field appearance="outline">
332
+ <mat-label>Título</mat-label>
333
+ <input matInput [(ngModel)]="item.title" />
334
+ </mat-form-field>
335
+ <mat-form-field appearance="outline" class="full">
336
+ <mat-label>Texto</mat-label>
337
+ <input matInput [(ngModel)]="item.text" />
338
+ </mat-form-field>
339
+ </div>
340
+ </div>
341
+ </ng-container>
342
+ </ng-container>
343
+
344
+ <details class="advanced full">
345
+ <summary>Avançado</summary>
346
+ <div class="advanced-body">
347
+ <mat-form-field appearance="outline" class="full">
348
+ <mat-label>ID estável (avançado)</mat-label>
349
+ <input matInput [(ngModel)]="model.blockId" placeholder="Ex.: ft-edit-wizard:access:block:hero" />
350
+ <mat-hint>Use como chave estável de telemetria/E2E. Evite alterar após publicar.</mat-hint>
351
+ </mat-form-field>
352
+ </div>
353
+ </details>
354
+ </div>
355
+
356
+ <div mat-dialog-actions align="end">
357
+ <button mat-button type="button" (click)="cancel()">Cancelar</button>
358
+ <button mat-flat-button color="primary" type="button" (click)="save()">Salvar</button>
359
+ </div>
360
+ `, isInline: true, styles: [".dialog-grid{display:grid;gap:12px;min-width:min(760px,92vw)}.full{grid-column:1 / -1}.benefits{display:grid;gap:10px;border-top:1px solid var(--md-sys-color-outline-variant);padding-top:8px}.benefits-head{display:flex;justify-content:space-between;align-items:center;gap:8px}.benefit-card{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));padding:10px;border-radius:8px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest)}.benefit-head{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.advanced{border-radius:8px;border:1px solid var(--md-sys-color-outline-variant);padding:8px 10px;background:var(--md-sys-color-surface-container-lowest)}.advanced>summary{cursor:pointer;font-weight:600;list-style:none}.advanced>summary::-webkit-details-marker{display:none}.advanced-body{margin-top:10px;display:grid;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { 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.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { 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: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { 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"] }] });
361
+ }
362
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: WizardWidgetConfigDialogComponent, decorators: [{
363
+ type: Component,
364
+ args: [{ selector: 'praxis-wizard-widget-config-dialog', standalone: true, imports: [
365
+ CommonModule,
366
+ FormsModule,
367
+ MatDialogModule,
368
+ MatFormFieldModule,
369
+ MatInputModule,
370
+ MatCheckboxModule,
371
+ MatButtonModule,
372
+ ], template: `
373
+ <h2 mat-dialog-title>{{ dialogTitle }}</h2>
374
+
375
+ <div mat-dialog-content class="dialog-grid">
376
+ <ng-container [ngSwitch]="wizardWidgetId">
377
+ <ng-container *ngSwitchCase="'praxis-wizard-inline-notice'">
378
+ <mat-form-field appearance="outline" class="full">
379
+ <mat-label>Texto</mat-label>
380
+ <input matInput [(ngModel)]="model.text" placeholder="Mensagem do aviso" />
381
+ </mat-form-field>
382
+ <mat-form-field appearance="outline">
383
+ <mat-label>Tom</mat-label>
384
+ <select matNativeControl [(ngModel)]="model.tone">
385
+ <option value="neutral">Neutro</option>
386
+ <option value="info">Informativo</option>
387
+ <option value="warning">Atenção</option>
388
+ </select>
389
+ </mat-form-field>
390
+ </ng-container>
391
+
392
+ <ng-container *ngSwitchCase="'praxis-wizard-content'">
393
+ <mat-form-field appearance="outline">
394
+ <mat-label>Título</mat-label>
395
+ <input matInput [(ngModel)]="model.title" />
396
+ </mat-form-field>
397
+ <mat-form-field appearance="outline">
398
+ <mat-label>Subtítulo</mat-label>
399
+ <input matInput [(ngModel)]="model.subtitle" />
400
+ </mat-form-field>
401
+ <mat-form-field appearance="outline" class="full">
402
+ <mat-label>Texto</mat-label>
403
+ <input matInput [(ngModel)]="model.text" />
404
+ </mat-form-field>
405
+ <mat-form-field appearance="outline" class="full">
406
+ <mat-label>Legenda</mat-label>
407
+ <input matInput [(ngModel)]="model.caption" />
408
+ </mat-form-field>
409
+ </ng-container>
410
+
411
+ <ng-container *ngSwitchCase="'praxis-wizard-divider'">
412
+ <mat-form-field appearance="outline" class="full">
413
+ <mat-label>Rótulo</mat-label>
414
+ <input matInput [(ngModel)]="model.label" placeholder="Opcional" />
415
+ </mat-form-field>
416
+ </ng-container>
417
+
418
+ <ng-container *ngSwitchCase="'praxis-wizard-benefits'">
419
+ <mat-form-field appearance="outline">
420
+ <mat-label>Título</mat-label>
421
+ <input matInput [(ngModel)]="model.title" />
422
+ </mat-form-field>
423
+ <mat-form-field appearance="outline">
424
+ <mat-label>Colunas</mat-label>
425
+ <input matInput type="number" min="1" [(ngModel)]="model.columns" />
426
+ </mat-form-field>
427
+ <mat-checkbox [(ngModel)]="model.boxed">Cards com contorno</mat-checkbox>
428
+
429
+ <div class="benefits">
430
+ <div class="benefits-head">
431
+ <strong>Itens de benefício</strong>
432
+ <button mat-stroked-button type="button" (click)="addBenefit()">Adicionar item</button>
433
+ </div>
434
+ <div class="benefit-card" *ngFor="let item of benefits; let i = index">
435
+ <div class="benefit-head">
436
+ <span>Item {{ i + 1 }}</span>
437
+ <button mat-button color="warn" type="button" (click)="removeBenefit(i)">Remover</button>
438
+ </div>
439
+ <mat-form-field appearance="outline">
440
+ <mat-label>Ícone</mat-label>
441
+ <input matInput [(ngModel)]="item.icon" placeholder="Ex.: info" />
442
+ </mat-form-field>
443
+ <mat-form-field appearance="outline">
444
+ <mat-label>Título</mat-label>
445
+ <input matInput [(ngModel)]="item.title" />
446
+ </mat-form-field>
447
+ <mat-form-field appearance="outline" class="full">
448
+ <mat-label>Texto</mat-label>
449
+ <input matInput [(ngModel)]="item.text" />
450
+ </mat-form-field>
451
+ </div>
452
+ </div>
453
+ </ng-container>
454
+ </ng-container>
455
+
456
+ <details class="advanced full">
457
+ <summary>Avançado</summary>
458
+ <div class="advanced-body">
459
+ <mat-form-field appearance="outline" class="full">
460
+ <mat-label>ID estável (avançado)</mat-label>
461
+ <input matInput [(ngModel)]="model.blockId" placeholder="Ex.: ft-edit-wizard:access:block:hero" />
462
+ <mat-hint>Use como chave estável de telemetria/E2E. Evite alterar após publicar.</mat-hint>
463
+ </mat-form-field>
464
+ </div>
465
+ </details>
466
+ </div>
467
+
468
+ <div mat-dialog-actions align="end">
469
+ <button mat-button type="button" (click)="cancel()">Cancelar</button>
470
+ <button mat-flat-button color="primary" type="button" (click)="save()">Salvar</button>
471
+ </div>
472
+ `, styles: [".dialog-grid{display:grid;gap:12px;min-width:min(760px,92vw)}.full{grid-column:1 / -1}.benefits{display:grid;gap:10px;border-top:1px solid var(--md-sys-color-outline-variant);padding-top:8px}.benefits-head{display:flex;justify-content:space-between;align-items:center;gap:8px}.benefit-card{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));padding:10px;border-radius:8px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest)}.benefit-head{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.advanced{border-radius:8px;border:1px solid var(--md-sys-color-outline-variant);padding:8px 10px;background:var(--md-sys-color-surface-container-lowest)}.advanced>summary{cursor:pointer;font-weight:600;list-style:none}.advanced>summary::-webkit-details-marker{display:none}.advanced-body{margin-top:10px;display:grid;gap:8px}\n"] }]
473
+ }], ctorParameters: () => [{ type: i1.MatDialogRef }, { type: undefined, decorators: [{
474
+ type: Inject,
475
+ args: [MAT_DIALOG_DATA]
476
+ }] }] });
477
+
139
478
  class PraxisStepperConfigEditor {
140
479
  config = { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
141
480
  activeIndex = 0;
@@ -236,8 +575,8 @@ class PraxisStepperConfigEditor {
236
575
  'container-color': 'var(--md-sys-color-surface-container)',
237
576
  'header-label-text-color': 'var(--md-sys-color-primary)',
238
577
  'header-selected-state-icon-background-color': 'var(--md-sys-color-primary)',
239
- 'header-selected-state-icon-foreground-color': '#fff',
240
- 'line-color': 'color-mix(in oklab, var(--md-sys-color-primary) 40%, transparent)',
578
+ 'header-selected-state-icon-foreground-color': 'var(--md-sys-color-on-primary)',
579
+ 'line-color': 'var(--md-sys-color-primary)',
241
580
  },
242
581
  neutral: {
243
582
  'container-color': 'var(--md-sys-color-surface)',
@@ -245,11 +584,11 @@ class PraxisStepperConfigEditor {
245
584
  'line-color': 'var(--md-sys-color-outline-variant)',
246
585
  },
247
586
  'high-contrast': {
248
- 'container-color': '#000',
249
- 'header-label-text-color': '#fff',
250
- 'header-selected-state-icon-background-color': 'var(--md-sys-color-on-primary, #ffffff)',
251
- 'header-selected-state-icon-foreground-color': '#000',
252
- 'line-color': '#fff',
587
+ 'container-color': 'var(--md-sys-color-surface)',
588
+ 'header-label-text-color': 'var(--md-sys-color-on-surface)',
589
+ 'header-selected-state-icon-background-color': 'var(--md-sys-color-on-surface)',
590
+ 'header-selected-state-icon-foreground-color': 'var(--md-sys-color-surface)',
591
+ 'line-color': 'var(--md-sys-color-on-surface)',
253
592
  },
254
593
  };
255
594
  const preset = presets[id] || {};
@@ -371,15 +710,141 @@ class PraxisStepperConfigEditor {
371
710
  get activeStep() { return this.config.steps?.[this.activeIndex] || null; }
372
711
  ensureWidgets() { const s = this.activeStep; if (!s.widgets)
373
712
  s.widgets = []; return s.widgets; }
713
+ ensureWidgetsBeforeForm() { const s = this.activeStep; if (!s.widgetsBeforeForm)
714
+ s.widgetsBeforeForm = []; return s.widgetsBeforeForm; }
374
715
  displayWidgetName(w) {
375
716
  switch (w.id) {
376
717
  case 'praxis-list': return 'Lista (seleção)';
377
- case 'pdx-material-searchable-select': return 'Select (busca)';
718
+ case 'pdx-material-searchable-select': return 'Seleção com busca';
378
719
  case 'praxis-files-upload': return 'Upload de arquivos';
379
720
  case 'praxis-dynamic-form': return 'Formulário';
721
+ case 'praxis-wizard-benefits': return 'Grade de benefícios';
722
+ case 'praxis-wizard-content': return 'Bloco de conteúdo';
723
+ case 'praxis-wizard-inline-notice': return 'Aviso inline';
724
+ case 'praxis-wizard-divider': return 'Divisor';
380
725
  default: return w.inputs?.title || w.inputs?.label || 'Widget';
381
726
  }
382
727
  }
728
+ editorialBeforeWidgets(step) {
729
+ return (step.widgetsBeforeForm || []).filter((w) => this.isWizardWidgetId(w.id));
730
+ }
731
+ editorialAfterWidgets(step) {
732
+ return (step.widgets || []).filter((w) => this.isWizardWidgetId(w.id));
733
+ }
734
+ advancedWidgets(step) {
735
+ return (step.widgets || []).filter((w) => !this.isWizardWidgetId(w.id));
736
+ }
737
+ widgetBlockId(w) {
738
+ const blockId = String(w.inputs?.blockId || '').trim();
739
+ return blockId || null;
740
+ }
741
+ editorialWidgetSummary(w) {
742
+ const inputs = w.inputs || {};
743
+ const shorten = (value, max = 72) => {
744
+ const text = (value || '').trim();
745
+ if (!text)
746
+ return '';
747
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
748
+ };
749
+ switch (w.id) {
750
+ case 'praxis-wizard-benefits': {
751
+ const count = Array.isArray(inputs.items) ? inputs.items.length : 0;
752
+ const cols = Number.isFinite(Number(inputs.columns)) ? Number(inputs.columns) : 4;
753
+ return `${count} item(ns) • ${cols} coluna(s)`;
754
+ }
755
+ case 'praxis-wizard-content': {
756
+ const text = shorten(inputs.title || inputs.subtitle || inputs.text || inputs.caption, 90);
757
+ return text || 'Sem conteúdo';
758
+ }
759
+ case 'praxis-wizard-inline-notice': {
760
+ const tone = this.toneLabel(inputs.tone);
761
+ const text = shorten(inputs.text, 90);
762
+ return text ? `${tone} • ${text}` : tone;
763
+ }
764
+ case 'praxis-wizard-divider':
765
+ return inputs.label ? `Rótulo: ${inputs.label}` : 'Divisor sem rótulo';
766
+ default:
767
+ return '';
768
+ }
769
+ }
770
+ addEditorialWidget(id, zone = 'before') {
771
+ const step = this.activeStep;
772
+ if (!step)
773
+ return;
774
+ const defaults = this.defaultEditorialInputs(id, step, zone);
775
+ this.openWizardWidgetDialog(id, defaults).subscribe((result) => {
776
+ if (!result?.inputs)
777
+ return;
778
+ const wd = {
779
+ id,
780
+ inputs: { ...defaults, ...result.inputs },
781
+ };
782
+ if (zone === 'before')
783
+ this.ensureWidgetsBeforeForm().push(wd);
784
+ else
785
+ this.ensureWidgets().push(wd);
786
+ this.markDirty();
787
+ });
788
+ }
789
+ dropEditorialBefore(ev) {
790
+ const step = this.activeStep;
791
+ if (!step)
792
+ return;
793
+ const list = this.ensureWidgetsBeforeForm();
794
+ this.reorderSubset(list, (w) => this.isWizardWidgetId(w.id), ev.previousIndex, ev.currentIndex);
795
+ this.markDirty();
796
+ }
797
+ dropEditorialAfter(ev) {
798
+ const step = this.activeStep;
799
+ if (!step)
800
+ return;
801
+ const list = this.ensureWidgets();
802
+ this.reorderSubset(list, (w) => this.isWizardWidgetId(w.id), ev.previousIndex, ev.currentIndex);
803
+ this.markDirty();
804
+ }
805
+ moveEditorialWidget(w, from, to) {
806
+ if (from === to)
807
+ return;
808
+ const fromList = from === 'before' ? this.ensureWidgetsBeforeForm() : this.ensureWidgets();
809
+ const toList = to === 'before' ? this.ensureWidgetsBeforeForm() : this.ensureWidgets();
810
+ const idx = fromList.indexOf(w);
811
+ if (idx < 0)
812
+ return;
813
+ fromList.splice(idx, 1);
814
+ toList.push(w);
815
+ this.markDirty();
816
+ }
817
+ duplicateEditorialWidget(w, zone) {
818
+ const step = this.activeStep;
819
+ if (!step || !this.isWizardWidgetId(w.id))
820
+ return;
821
+ const clone = JSON.parse(JSON.stringify(w));
822
+ const inputs = (clone.inputs = { ...(clone.inputs || {}) });
823
+ inputs.blockId = this.nextEditorialBlockId(step, w.id, zone);
824
+ const list = zone === 'before' ? this.ensureWidgetsBeforeForm() : this.ensureWidgets();
825
+ const idx = list.indexOf(w);
826
+ if (idx >= 0)
827
+ list.splice(idx + 1, 0, clone);
828
+ else
829
+ list.push(clone);
830
+ this.markDirty();
831
+ }
832
+ removeEditorialWidget(w, zone) {
833
+ const list = zone === 'before' ? this.ensureWidgetsBeforeForm() : this.ensureWidgets();
834
+ const idx = list.indexOf(w);
835
+ if (idx < 0)
836
+ return;
837
+ list.splice(idx, 1);
838
+ this.markDirty();
839
+ }
840
+ removeAdvancedWidget(w) {
841
+ const widgets = this.ensureWidgets();
842
+ const idx = widgets.indexOf(w);
843
+ if (idx < 0)
844
+ return;
845
+ widgets.splice(idx, 1);
846
+ this.markDirty();
847
+ }
383
848
  dropWidget(ev) {
384
849
  const arr = this.ensureWidgets();
385
850
  moveItemInArray(arr, ev.previousIndex, ev.currentIndex);
@@ -390,6 +855,103 @@ class PraxisStepperConfigEditor {
390
855
  arr.splice(idx, 1);
391
856
  this.markDirty();
392
857
  }
858
+ canEditWidget(w) {
859
+ return (w.id === 'praxis-dynamic-form'
860
+ || w.id === 'praxis-list'
861
+ || w.id === 'pdx-material-searchable-select'
862
+ || w.id === 'praxis-files-upload'
863
+ || this.isWizardWidgetId(w.id));
864
+ }
865
+ defaultEditorialInputs(id, step, zone) {
866
+ const blockId = this.nextEditorialBlockId(step, id, zone);
867
+ switch (id) {
868
+ case 'praxis-wizard-benefits':
869
+ return {
870
+ blockId,
871
+ title: '',
872
+ columns: 4,
873
+ boxed: true,
874
+ items: [{ icon: '', title: 'Novo benefício', text: '' }],
875
+ };
876
+ case 'praxis-wizard-content':
877
+ return {
878
+ blockId,
879
+ title: '',
880
+ subtitle: '',
881
+ text: '',
882
+ caption: '',
883
+ };
884
+ case 'praxis-wizard-inline-notice':
885
+ return {
886
+ blockId,
887
+ text: '',
888
+ tone: 'neutral',
889
+ };
890
+ case 'praxis-wizard-divider':
891
+ return {
892
+ blockId,
893
+ label: '',
894
+ };
895
+ default:
896
+ return { blockId };
897
+ }
898
+ }
899
+ nextEditorialBlockId(step, id, zone) {
900
+ const stepPart = this.normalizeBlockIdPart(step.id || `step-${this.activeIndex + 1}`);
901
+ const kind = id.replace('praxis-wizard-', '');
902
+ const prefix = `${stepPart}:${zone}:${kind}:`;
903
+ const used = new Set();
904
+ let max = 0;
905
+ const allWidgets = [...(step.widgetsBeforeForm || []), ...(step.widgets || [])];
906
+ allWidgets.forEach((widget) => {
907
+ const blockId = String(widget.inputs?.blockId || '').trim();
908
+ if (!blockId.startsWith(prefix))
909
+ return;
910
+ used.add(blockId);
911
+ const suffix = Number(blockId.slice(prefix.length));
912
+ if (Number.isFinite(suffix)) {
913
+ max = Math.max(max, suffix);
914
+ }
915
+ });
916
+ let nextIdx = Math.max(1, max + 1);
917
+ let candidate = `${prefix}${nextIdx}`;
918
+ while (used.has(candidate)) {
919
+ nextIdx += 1;
920
+ candidate = `${prefix}${nextIdx}`;
921
+ }
922
+ return candidate;
923
+ }
924
+ normalizeBlockIdPart(value) {
925
+ const normalized = (value || '')
926
+ .trim()
927
+ .toLowerCase()
928
+ .replace(/\s+/g, '-')
929
+ .replace(/[^a-z0-9:_-]/g, '');
930
+ return normalized || `step-${this.activeIndex + 1}`;
931
+ }
932
+ toneLabel(value) {
933
+ switch (value) {
934
+ case 'info': return 'Informativo';
935
+ case 'warning': return 'Atenção';
936
+ default: return 'Neutro';
937
+ }
938
+ }
939
+ reorderSubset(list, pick, fromSubsetIndex, toSubsetIndex) {
940
+ const subsetIndices = [];
941
+ list.forEach((item, index) => {
942
+ if (pick(item))
943
+ subsetIndices.push(index);
944
+ });
945
+ const fromReal = subsetIndices[fromSubsetIndex];
946
+ const toReal = subsetIndices[toSubsetIndex];
947
+ if (fromReal == null || toReal == null)
948
+ return;
949
+ const [moved] = list.splice(fromReal, 1);
950
+ let insertAt = toReal;
951
+ if (fromReal < toReal)
952
+ insertAt -= 1;
953
+ list.splice(insertAt, 0, moved);
954
+ }
393
955
  // ------- Main form -------
394
956
  addMainForm() {
395
957
  const step = this.activeStep;
@@ -422,7 +984,7 @@ class PraxisStepperConfigEditor {
422
984
  const ref = this.settings.open({ id: `stepper:list:${step.id || this.activeIndex}`, title: 'Configurar Lista (seleção)', content: { component: PraxisListConfigEditor, inputs: { config: current, listId: step.id || 'list' } } });
423
985
  const apply = (val) => {
424
986
  const cfg = (val && (val.config || val)) || current;
425
- const wd = { id: 'praxis-list', inputs: { config: cfg } };
987
+ const wd = { id: 'praxis-list', inputs: { config: cfg, listId: `${step.id || 'step'}-list-${Date.now()}` } };
426
988
  const arr = this.ensureWidgets();
427
989
  arr.push(wd);
428
990
  this.markDirty();
@@ -460,7 +1022,7 @@ class PraxisStepperConfigEditor {
460
1022
  return;
461
1023
  const ref = this.settings.open({ id: `stepper:upload:${step.id || this.activeIndex}`, title: 'Configurar Upload de Arquivos', content: { component: PraxisFilesUploadConfigEditor, inputs: {} } });
462
1024
  const apply = (cfg) => {
463
- const wd = { id: 'praxis-files-upload', inputs: { config: cfg, componentId: `${step.id || 'step'}-upload-${Date.now()}` } };
1025
+ const wd = { id: 'praxis-files-upload', inputs: { config: cfg, filesUploadId: `${step.id || 'step'}-upload-${Date.now()}` } };
464
1026
  this.ensureWidgets().push(wd);
465
1027
  this.markDirty();
466
1028
  };
@@ -498,7 +1060,7 @@ class PraxisStepperConfigEditor {
498
1060
  if (!step)
499
1061
  return;
500
1062
  const cfg = { mode: 'tree', selection: { mode: 'single' } };
501
- const wd = { id: 'praxis-list', inputs: { config: cfg } };
1063
+ const wd = { id: 'praxis-list', inputs: { config: cfg, listId: `${step.id || 'step'}-list-${Date.now()}` } };
502
1064
  this.ensureWidgets().push(wd);
503
1065
  this.markDirty();
504
1066
  }
@@ -521,7 +1083,7 @@ class PraxisStepperConfigEditor {
521
1083
  ref.applied$.subscribe(apply);
522
1084
  ref.saved$.subscribe(apply);
523
1085
  }
524
- editWidget(w, index) {
1086
+ editWidget(w) {
525
1087
  switch (w.id) {
526
1088
  case 'praxis-dynamic-form':
527
1089
  // treat as embedded form
@@ -562,11 +1124,44 @@ class PraxisStepperConfigEditor {
562
1124
  ref.saved$.subscribe(apply);
563
1125
  break;
564
1126
  }
1127
+ case 'praxis-wizard-benefits':
1128
+ case 'praxis-wizard-content':
1129
+ case 'praxis-wizard-inline-notice':
1130
+ case 'praxis-wizard-divider': {
1131
+ this.openWizardWidgetEditor(w);
1132
+ break;
1133
+ }
565
1134
  default:
566
1135
  // No editor available
567
1136
  break;
568
1137
  }
569
1138
  }
1139
+ openWizardWidgetEditor(w) {
1140
+ if (!this.isWizardWidgetId(w.id))
1141
+ return;
1142
+ this.openWizardWidgetDialog(w.id, { ...(w.inputs || {}) }).subscribe((result) => {
1143
+ if (!result?.inputs)
1144
+ return;
1145
+ w.inputs = { ...(w.inputs || {}), ...result.inputs };
1146
+ this.markDirty();
1147
+ });
1148
+ }
1149
+ openWizardWidgetDialog(widgetId, inputs) {
1150
+ const dialogRef = this.dialog.open(WizardWidgetConfigDialogComponent, {
1151
+ width: '760px',
1152
+ data: {
1153
+ widgetId,
1154
+ inputs: { ...inputs },
1155
+ },
1156
+ });
1157
+ return dialogRef.afterClosed();
1158
+ }
1159
+ isWizardWidgetId(id) {
1160
+ return (id === 'praxis-wizard-benefits'
1161
+ || id === 'praxis-wizard-content'
1162
+ || id === 'praxis-wizard-inline-notice'
1163
+ || id === 'praxis-wizard-divider');
1164
+ }
570
1165
  // SettingsValueProvider
571
1166
  getSettingsValue() { return this.config; }
572
1167
  onSave() { return this.getSettingsValue(); }
@@ -595,7 +1190,16 @@ class PraxisStepperConfigEditor {
595
1190
  <option value="horizontal">Horizontal</option>
596
1191
  <option value="vertical">Vertical</option>
597
1192
  </select>
598
- <mat-hint>Horizontal: cabeçalho no topo • Vertical: lista à esquerda</mat-hint>
1193
+ <button
1194
+ mat-icon-button
1195
+ matSuffix
1196
+ class="help-icon-button"
1197
+ type="button"
1198
+ [matTooltip]="'Horizontal: cabeçalho no topo • Vertical: lista à esquerda'"
1199
+ matTooltipPosition="above"
1200
+ >
1201
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1202
+ </button>
599
1203
  </mat-form-field>
600
1204
  <mat-form-field appearance="outline">
601
1205
  <mat-label>Posição dos títulos</mat-label>
@@ -603,7 +1207,16 @@ class PraxisStepperConfigEditor {
603
1207
  <option value="top">Acima</option>
604
1208
  <option value="bottom">Abaixo</option>
605
1209
  </select>
606
- <mat-hint>Válido na orientação horizontal</mat-hint>
1210
+ <button
1211
+ mat-icon-button
1212
+ matSuffix
1213
+ class="help-icon-button"
1214
+ type="button"
1215
+ [matTooltip]="'Válido na orientação horizontal'"
1216
+ matTooltipPosition="above"
1217
+ >
1218
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1219
+ </button>
607
1220
  </mat-form-field>
608
1221
  <mat-form-field appearance="outline">
609
1222
  <mat-label>Posição do rótulo</mat-label>
@@ -611,7 +1224,16 @@ class PraxisStepperConfigEditor {
611
1224
  <option value="end">Ao lado</option>
612
1225
  <option value="bottom">Abaixo</option>
613
1226
  </select>
614
- <mat-hint>Como o texto aparece no cabeçalho</mat-hint>
1227
+ <button
1228
+ mat-icon-button
1229
+ matSuffix
1230
+ class="help-icon-button"
1231
+ type="button"
1232
+ [matTooltip]="'Como o texto aparece no cabeçalho'"
1233
+ matTooltipPosition="above"
1234
+ >
1235
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1236
+ </button>
615
1237
  </mat-form-field>
616
1238
  <mat-form-field appearance="outline">
617
1239
  <mat-label>Cor</mat-label>
@@ -621,17 +1243,44 @@ class PraxisStepperConfigEditor {
621
1243
  <option value="accent">Acento</option>
622
1244
  <option value="warn">Alerta</option>
623
1245
  </select>
624
- <mat-hint>Aplicável a temas Material 2 (M2)</mat-hint>
1246
+ <button
1247
+ mat-icon-button
1248
+ matSuffix
1249
+ class="help-icon-button"
1250
+ type="button"
1251
+ [matTooltip]="'Aplicável a temas Material 2 (M2)'"
1252
+ matTooltipPosition="above"
1253
+ >
1254
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1255
+ </button>
625
1256
  </mat-form-field>
626
1257
  <mat-form-field appearance="outline">
627
1258
  <mat-label>Duração da animação</mat-label>
628
1259
  <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" placeholder="Ex.: 300ms" />
629
- <mat-hint>Tempo da transição entre etapas</mat-hint>
1260
+ <button
1261
+ mat-icon-button
1262
+ matSuffix
1263
+ class="help-icon-button"
1264
+ type="button"
1265
+ [matTooltip]="'Tempo da transição entre etapas'"
1266
+ matTooltipPosition="above"
1267
+ >
1268
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1269
+ </button>
630
1270
  </mat-form-field>
631
1271
  <mat-form-field appearance="outline">
632
1272
  <mat-label>Etapa selecionada</mat-label>
633
1273
  <input matInput type="number" [(ngModel)]="config.selectedIndex" (ngModelChange)="markDirty()" />
634
- <mat-hint>Índice inicia em 0 (primeira etapa)</mat-hint>
1274
+ <button
1275
+ mat-icon-button
1276
+ matSuffix
1277
+ class="help-icon-button"
1278
+ type="button"
1279
+ [matTooltip]="'Índice inicia em 0 (primeira etapa)'"
1280
+ matTooltipPosition="above"
1281
+ >
1282
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1283
+ </button>
635
1284
  </mat-form-field>
636
1285
  <mat-form-field appearance="outline">
637
1286
  <mat-label>Densidade</mat-label>
@@ -640,22 +1289,58 @@ class PraxisStepperConfigEditor {
640
1289
  <option value="comfortable">Confortável</option>
641
1290
  <option value="compact">Compacta</option>
642
1291
  </select>
643
- <mat-hint>Controla espaçamentos e alturas</mat-hint>
1292
+ <button
1293
+ mat-icon-button
1294
+ matSuffix
1295
+ class="help-icon-button"
1296
+ type="button"
1297
+ [matTooltip]="'Controla espaçamentos e alturas'"
1298
+ matTooltipPosition="above"
1299
+ >
1300
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1301
+ </button>
644
1302
  </mat-form-field>
645
1303
  <mat-form-field appearance="outline" class="w-full">
646
1304
  <mat-label>Classe do stepper (opcional)</mat-label>
647
1305
  <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" placeholder="Ex.: meu-stepper" />
648
- <mat-hint>Permite estilizar com CSS escopado</mat-hint>
1306
+ <button
1307
+ mat-icon-button
1308
+ matSuffix
1309
+ class="help-icon-button"
1310
+ type="button"
1311
+ [matTooltip]="'Permite estilizar com CSS escopado'"
1312
+ matTooltipPosition="above"
1313
+ >
1314
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1315
+ </button>
649
1316
  </mat-form-field>
650
1317
  <mat-form-field appearance="outline" class="w-full">
651
1318
  <mat-label>Classe do cabeçalho (opcional)</mat-label>
652
1319
  <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-header" />
653
- <mat-hint>Use para ajustes finos de aparência</mat-hint>
1320
+ <button
1321
+ mat-icon-button
1322
+ matSuffix
1323
+ class="help-icon-button"
1324
+ type="button"
1325
+ [matTooltip]="'Use para ajustes finos de aparência'"
1326
+ matTooltipPosition="above"
1327
+ >
1328
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1329
+ </button>
654
1330
  </mat-form-field>
655
1331
  <mat-form-field appearance="outline" class="w-full">
656
1332
  <mat-label>Classe do conteúdo (opcional)</mat-label>
657
1333
  <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-content" />
658
- <mat-hint>Aplica uma classe à área de conteúdo</mat-hint>
1334
+ <button
1335
+ mat-icon-button
1336
+ matSuffix
1337
+ class="help-icon-button"
1338
+ type="button"
1339
+ [matTooltip]="'Aplica uma classe à área de conteúdo'"
1340
+ matTooltipPosition="above"
1341
+ >
1342
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1343
+ </button>
659
1344
  </mat-form-field>
660
1345
  </div>
661
1346
  <div class="pdx-toggles">
@@ -677,35 +1362,89 @@ class PraxisStepperConfigEditor {
677
1362
  <div class="pdx-step-item" *ngFor="let s of config.steps; let i = index" cdkDrag [class.active]="activeIndex === i" (click)="setActive(i)">
678
1363
  <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
679
1364
  <div class="pdx-fields">
680
- <mat-form-field appearance="outline" style="min-width: 180px;">
1365
+ <mat-form-field appearance="outline" class="min-180">
681
1366
  <mat-label>Título da etapa</mat-label>
682
1367
  <input matInput [(ngModel)]="s.label" (ngModelChange)="markDirty()" />
683
- <mat-hint>Como aparecerá no cabeçalho</mat-hint>
1368
+ <button
1369
+ mat-icon-button
1370
+ matSuffix
1371
+ class="help-icon-button"
1372
+ type="button"
1373
+ [matTooltip]="'Como aparecerá no cabeçalho'"
1374
+ matTooltipPosition="above"
1375
+ >
1376
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1377
+ </button>
684
1378
  </mat-form-field>
685
1379
  <mat-form-field appearance="outline">
686
1380
  <mat-label>Identificador (opcional)</mat-label>
687
1381
  <input matInput [(ngModel)]="s.id" (ngModelChange)="markDirty()" />
688
- <mat-hint>Útil para automações</mat-hint>
1382
+ <button
1383
+ mat-icon-button
1384
+ matSuffix
1385
+ class="help-icon-button"
1386
+ type="button"
1387
+ [matTooltip]="'Útil para automações'"
1388
+ matTooltipPosition="above"
1389
+ >
1390
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1391
+ </button>
689
1392
  </mat-form-field>
690
1393
  <mat-form-field appearance="outline">
691
1394
  <mat-label>Texto alternativo (acessibilidade)</mat-label>
692
1395
  <input matInput [(ngModel)]="s.ariaLabel" (ngModelChange)="markDirty()" />
693
- <mat-hint>Lido por leitores de tela</mat-hint>
1396
+ <button
1397
+ mat-icon-button
1398
+ matSuffix
1399
+ class="help-icon-button"
1400
+ type="button"
1401
+ [matTooltip]="'Lido por leitores de tela'"
1402
+ matTooltipPosition="above"
1403
+ >
1404
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1405
+ </button>
694
1406
  </mat-form-field>
695
1407
  <mat-form-field appearance="outline">
696
1408
  <mat-label>ID que descreve (opcional)</mat-label>
697
1409
  <input matInput [(ngModel)]="s.ariaLabelledby" (ngModelChange)="markDirty()" />
698
- <mat-hint>ID de um elemento que descreve a etapa</mat-hint>
1410
+ <button
1411
+ mat-icon-button
1412
+ matSuffix
1413
+ class="help-icon-button"
1414
+ type="button"
1415
+ [matTooltip]="'ID de um elemento que descreve a etapa'"
1416
+ matTooltipPosition="above"
1417
+ >
1418
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1419
+ </button>
699
1420
  </mat-form-field>
700
1421
  <mat-form-field appearance="outline">
701
1422
  <mat-label>Ícone/estado do marcador</mat-label>
702
1423
  <input matInput [(ngModel)]="s.state" (ngModelChange)="markDirty()" placeholder="Ex.: number, done, edit" />
703
- <mat-hint>Controla o ícone do passo (quando aplicável)</mat-hint>
1424
+ <button
1425
+ mat-icon-button
1426
+ matSuffix
1427
+ class="help-icon-button"
1428
+ type="button"
1429
+ [matTooltip]="'Controla o ícone do passo (quando aplicável)'"
1430
+ matTooltipPosition="above"
1431
+ >
1432
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1433
+ </button>
704
1434
  </mat-form-field>
705
1435
  <mat-form-field appearance="outline">
706
1436
  <mat-label>Mensagem de erro</mat-label>
707
1437
  <input matInput [(ngModel)]="s.errorMessage" (ngModelChange)="markDirty()" />
708
- <mat-hint>Mostrada quando há erro na etapa</mat-hint>
1438
+ <button
1439
+ mat-icon-button
1440
+ matSuffix
1441
+ class="help-icon-button"
1442
+ type="button"
1443
+ [matTooltip]="'Mostrada quando há erro na etapa'"
1444
+ matTooltipPosition="above"
1445
+ >
1446
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1447
+ </button>
709
1448
  </mat-form-field>
710
1449
  <div class="pdx-flag-group">
711
1450
  <mat-slide-toggle [(ngModel)]="s.optional" (ngModelChange)="markDirty()">Etapa opcional</mat-slide-toggle>
@@ -732,8 +1471,139 @@ class PraxisStepperConfigEditor {
732
1471
  </div>
733
1472
 
734
1473
  <div class="pdx-content-editor">
1474
+ <div class="section editorial-section">
1475
+ <div class="section-head">
1476
+ <div>
1477
+ <div class="section-title">Conteúdo editorial</div>
1478
+ <div class="section-subtitle">Organize os blocos narrativos da etapa antes ou depois do formulário.</div>
1479
+ </div>
1480
+ </div>
1481
+
1482
+ <div class="zone-grid">
1483
+ <div class="zone-card">
1484
+ <div class="zone-head">
1485
+ <div class="zone-title">Antes do formulário</div>
1486
+ <div class="zone-actions">
1487
+ <span class="zone-count">{{ editorialBeforeWidgets(step).length }}</span>
1488
+ <button mat-stroked-button [matMenuTriggerFor]="beforeEditorialMenu">
1489
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
1490
+ Adicionar
1491
+ </button>
1492
+ <mat-menu #beforeEditorialMenu="matMenu">
1493
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'before')">
1494
+ <mat-icon [praxisIcon]="'view_module'"></mat-icon>
1495
+ Grade de benefícios
1496
+ </button>
1497
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'before')">
1498
+ <mat-icon [praxisIcon]="'article'"></mat-icon>
1499
+ Bloco de conteúdo
1500
+ </button>
1501
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'before')">
1502
+ <mat-icon [praxisIcon]="'info'"></mat-icon>
1503
+ Aviso inline
1504
+ </button>
1505
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'before')">
1506
+ <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
1507
+ Divisor
1508
+ </button>
1509
+ </mat-menu>
1510
+ </div>
1511
+ </div>
1512
+ <div cdkDropList (cdkDropListDropped)="dropEditorialBefore($event)" class="widget-list">
1513
+ <div class="widget-item editorial-item" *ngFor="let w of editorialBeforeWidgets(step)" cdkDrag>
1514
+ <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
1515
+ <div class="info">
1516
+ <div class="name">{{ displayWidgetName(w) }}</div>
1517
+ <div class="sub">{{ editorialWidgetSummary(w) }}</div>
1518
+ <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
1519
+ </div>
1520
+ <div class="actions">
1521
+ <button mat-button (click)="editWidget(w)">
1522
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
1523
+ Editar
1524
+ </button>
1525
+ <button mat-button (click)="moveEditorialWidget(w, 'before', 'after')">
1526
+ <mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>
1527
+ Mover para depois
1528
+ </button>
1529
+ <button mat-button (click)="duplicateEditorialWidget(w, 'before')">
1530
+ <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
1531
+ Duplicar
1532
+ </button>
1533
+ <button mat-button color="warn" (click)="removeEditorialWidget(w, 'before')">
1534
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
1535
+ Remover
1536
+ </button>
1537
+ </div>
1538
+ </div>
1539
+ <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">Nenhum bloco nesta zona.</div>
1540
+ </div>
1541
+ </div>
1542
+
1543
+ <div class="zone-card">
1544
+ <div class="zone-head">
1545
+ <div class="zone-title">Depois do formulário</div>
1546
+ <div class="zone-actions">
1547
+ <span class="zone-count">{{ editorialAfterWidgets(step).length }}</span>
1548
+ <button mat-stroked-button [matMenuTriggerFor]="afterEditorialMenu">
1549
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
1550
+ Adicionar
1551
+ </button>
1552
+ <mat-menu #afterEditorialMenu="matMenu">
1553
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'after')">
1554
+ <mat-icon [praxisIcon]="'view_module'"></mat-icon>
1555
+ Grade de benefícios
1556
+ </button>
1557
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'after')">
1558
+ <mat-icon [praxisIcon]="'article'"></mat-icon>
1559
+ Bloco de conteúdo
1560
+ </button>
1561
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'after')">
1562
+ <mat-icon [praxisIcon]="'info'"></mat-icon>
1563
+ Aviso inline
1564
+ </button>
1565
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'after')">
1566
+ <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
1567
+ Divisor
1568
+ </button>
1569
+ </mat-menu>
1570
+ </div>
1571
+ </div>
1572
+ <div cdkDropList (cdkDropListDropped)="dropEditorialAfter($event)" class="widget-list">
1573
+ <div class="widget-item editorial-item" *ngFor="let w of editorialAfterWidgets(step)" cdkDrag>
1574
+ <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
1575
+ <div class="info">
1576
+ <div class="name">{{ displayWidgetName(w) }}</div>
1577
+ <div class="sub">{{ editorialWidgetSummary(w) }}</div>
1578
+ <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
1579
+ </div>
1580
+ <div class="actions">
1581
+ <button mat-button (click)="editWidget(w)">
1582
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
1583
+ Editar
1584
+ </button>
1585
+ <button mat-button (click)="moveEditorialWidget(w, 'after', 'before')">
1586
+ <mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>
1587
+ Mover para antes
1588
+ </button>
1589
+ <button mat-button (click)="duplicateEditorialWidget(w, 'after')">
1590
+ <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
1591
+ Duplicar
1592
+ </button>
1593
+ <button mat-button color="warn" (click)="removeEditorialWidget(w, 'after')">
1594
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
1595
+ Remover
1596
+ </button>
1597
+ </div>
1598
+ </div>
1599
+ <div class="empty" *ngIf="!editorialAfterWidgets(step).length">Nenhum bloco nesta zona.</div>
1600
+ </div>
1601
+ </div>
1602
+ </div>
1603
+ </div>
1604
+
735
1605
  <div class="section">
736
- <div class="section-title">Formulário principal</div>
1606
+ <div class="section-title">Formulário da etapa</div>
737
1607
  <div class="section-body">
738
1608
  <ng-container *ngIf="step.form; else addFormBtn">
739
1609
  <mat-card appearance="outlined" class="mini-card">
@@ -755,22 +1625,18 @@ class PraxisStepperConfigEditor {
755
1625
  </div>
756
1626
 
757
1627
  <div class="section">
758
- <div class="section-title">Conteúdos e componentes</div>
1628
+ <div class="section-head">
1629
+ <div>
1630
+ <div class="section-title">Componentes avançados</div>
1631
+ <div class="section-subtitle">Use para cenários de seleção e integrações específicas.</div>
1632
+ </div>
1633
+ <button mat-stroked-button (click)="openMoreComponents()">
1634
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
1635
+ Mais componentes
1636
+ </button>
1637
+ </div>
759
1638
  <div class="section-body">
760
1639
  <div class="cta-grid">
761
- <div class="cta-card mat-elevation-z2">
762
- <div class="cta-head">
763
- <mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>
764
- <div class="cta-title">Formulário dinâmico</div>
765
- </div>
766
- <div class="cta-desc">Crie campos e validações personalizadas nesta etapa.</div>
767
- <div class="cta-actions">
768
- <button mat-flat-button color="primary" (click)="addMainForm()">
769
- <mat-icon [praxisIcon]="'add'"></mat-icon>
770
- Inserir formulário
771
- </button>
772
- </div>
773
- </div>
774
1640
  <div class="cta-card mat-elevation-z2">
775
1641
  <div class="cta-head">
776
1642
  <mat-icon [praxisIcon]="'account_tree'"></mat-icon>
@@ -797,20 +1663,53 @@ class PraxisStepperConfigEditor {
797
1663
  </button>
798
1664
  </div>
799
1665
  </div>
1666
+ <div class="cta-card mat-elevation-z2">
1667
+ <div class="cta-head">
1668
+ <mat-icon [praxisIcon]="'search'"></mat-icon>
1669
+ <div class="cta-title">Seleção com busca</div>
1670
+ </div>
1671
+ <div class="cta-desc">Campo de seleção com busca remota/local.</div>
1672
+ <div class="cta-actions">
1673
+ <button mat-stroked-button (click)="addSearchableSelect()">
1674
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
1675
+ Inserir seletor
1676
+ </button>
1677
+ </div>
1678
+ </div>
1679
+ <div class="cta-card mat-elevation-z2">
1680
+ <div class="cta-head">
1681
+ <mat-icon [praxisIcon]="'upload_file'"></mat-icon>
1682
+ <div class="cta-title">Upload de arquivos</div>
1683
+ </div>
1684
+ <div class="cta-desc">Anexe documentos com validação de upload.</div>
1685
+ <div class="cta-actions">
1686
+ <button mat-stroked-button (click)="addFilesUpload()">
1687
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
1688
+ Inserir upload
1689
+ </button>
1690
+ </div>
1691
+ </div>
800
1692
  </div>
801
- <div cdkDropList (cdkDropListDropped)="dropWidget($event)" class="widget-list">
802
- <div class="widget-item" *ngFor="let w of (step.widgets || []); let wi = index" cdkDrag>
803
- <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
1693
+
1694
+ <div class="widget-list advanced-list">
1695
+ <div class="widget-item" *ngFor="let w of advancedWidgets(step)">
1696
+ <div class="drag-handle"><mat-icon [praxisIcon]="'extension'"></mat-icon></div>
804
1697
  <div class="info">
805
1698
  <div class="name">{{ displayWidgetName(w) }}</div>
806
1699
  <div class="sub">{{ w.id }}</div>
807
1700
  </div>
808
1701
  <div class="actions">
809
- <button mat-button (click)="editWidget(w, wi)"><mat-icon [praxisIcon]="'tune'"></mat-icon> Editar</button>
810
- <button mat-button color="warn" (click)="removeWidget(wi)"><mat-icon [praxisIcon]="'delete'"></mat-icon> Remover</button>
1702
+ <button mat-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)">
1703
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
1704
+ Editar
1705
+ </button>
1706
+ <button mat-button color="warn" (click)="removeAdvancedWidget(w)">
1707
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
1708
+ Remover
1709
+ </button>
811
1710
  </div>
812
1711
  </div>
813
- <div class="empty" *ngIf="!step.widgets || !step.widgets.length">Nenhum componente adicionado</div>
1712
+ <div class="empty" *ngIf="!advancedWidgets(step).length">Nenhum componente avançado adicionado.</div>
814
1713
  </div>
815
1714
  </div>
816
1715
  </div>
@@ -898,12 +1797,30 @@ class PraxisStepperConfigEditor {
898
1797
  <mat-form-field appearance="outline">
899
1798
  <mat-label>Altura do cabeçalho (px)</mat-label>
900
1799
  <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" placeholder="Ex.: 48" />
901
- <mat-hint>Altura do item do cabeçalho</mat-hint>
1800
+ <button
1801
+ mat-icon-button
1802
+ matSuffix
1803
+ class="help-icon-button"
1804
+ type="button"
1805
+ [matTooltip]="'Altura do item do cabeçalho'"
1806
+ matTooltipPosition="above"
1807
+ >
1808
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1809
+ </button>
902
1810
  </mat-form-field>
903
1811
  <mat-form-field appearance="outline">
904
1812
  <mat-label>Tamanho do texto (px)</mat-label>
905
1813
  <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" placeholder="Ex.: 14" />
906
- <mat-hint>Tamanho do título da etapa</mat-hint>
1814
+ <button
1815
+ mat-icon-button
1816
+ matSuffix
1817
+ class="help-icon-button"
1818
+ type="button"
1819
+ [matTooltip]="'Tamanho do título da etapa'"
1820
+ matTooltipPosition="above"
1821
+ >
1822
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1823
+ </button>
907
1824
  </mat-form-field>
908
1825
  <mat-form-field appearance="outline">
909
1826
  <mat-label>Peso do texto</mat-label>
@@ -920,7 +1837,16 @@ class PraxisStepperConfigEditor {
920
1837
  <mat-form-field appearance="outline" class="w-full">
921
1838
  <mat-label>Classe de tema (opcional)</mat-label>
922
1839
  <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="Ex.: theme-stepper-custom" />
923
- <mat-hint>Aplica as cores apenas dentro desse seletor</mat-hint>
1840
+ <button
1841
+ mat-icon-button
1842
+ matSuffix
1843
+ class="help-icon-button"
1844
+ type="button"
1845
+ [matTooltip]="'Aplica as cores apenas dentro desse seletor'"
1846
+ matTooltipPosition="above"
1847
+ >
1848
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1849
+ </button>
924
1850
  </mat-form-field>
925
1851
  <mat-form-field appearance="outline">
926
1852
  <mat-label>Conjunto de ícones</mat-label>
@@ -930,7 +1856,16 @@ class PraxisStepperConfigEditor {
930
1856
  <option value="material-symbols-rounded">Material Symbols (Rounded)</option>
931
1857
  <option value="material-symbols-sharp">Material Symbols (Sharp)</option>
932
1858
  </select>
933
- <mat-hint>Selecione se usar ícones do Material Symbols</mat-hint>
1859
+ <button
1860
+ mat-icon-button
1861
+ matSuffix
1862
+ class="help-icon-button"
1863
+ type="button"
1864
+ [matTooltip]="'Selecione se usar ícones do Material Symbols'"
1865
+ matTooltipPosition="above"
1866
+ >
1867
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1868
+ </button>
934
1869
  </mat-form-field>
935
1870
  </div>
936
1871
  <div class="icons-grid">
@@ -991,7 +1926,7 @@ class PraxisStepperConfigEditor {
991
1926
  </mat-tab>
992
1927
  </mat-tab-group>
993
1928
  </div>
994
- `, isInline: true, styles: [".pdx-editor{display:grid;gap:16px}.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:12px 4px;display:grid;gap:12px}.help{color:#000000b3;font-size:13px}.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}.pdx-steps{display:grid;gap:8px}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center}.pdx-step-list{display:grid;gap:8px}.pdx-step-item{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:start;padding:8px;border:1px solid rgba(0,0,0,.12);border-radius:8px;cursor:pointer}.pdx-step-item.active{border-color:color-mix(in oklab,var(--md-sys-color-primary) 40%,rgba(0,0,0,.12));box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level2, 0 2px 6px rgba(0,0,0,.12))}.drag-handle{display:flex;align-items:center;color:#0000008a}.pdx-fields{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.pdx-flag-group{display:flex;gap:10px;align-items:center}.pdx-active-step{display:grid;gap:12px;padding-top:8px;border-top:1px dashed rgba(0,0,0,.12)}.pdx-active-step .hdr{display:flex;gap:12px;align-items:center;justify-content:space-between}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:8px}.section-title{font-weight:600;opacity:.85}.mini-card{display:block}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:8px;padding:8px;border:1px solid rgba(0,0,0,.12);border-radius:8px}.widget-item .info .name{font-weight:600}.widget-item .info .sub{font-size:12px;opacity:.7}.widget-item .actions{display:flex;gap:8px}.cta-row{display:flex;gap:8px;align-items:center}.spacer{flex:1 1 auto}.muted{color:#0009}.cta-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px;margin-bottom:8px}.cta-card{display:grid;gap:8px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant, rgba(0,0,0,.12));background:var(--md-sys-color-surface)}.cta-card .cta-head{display:flex;align-items:center;gap:8px}.cta-card .cta-title{font-weight:600}.cta-card .cta-desc{font-size:12px;opacity:.78}.cta-card .cta-actions{display:flex;gap:8px;align-items:center}.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}.code-card{margin-top:8px}.code-head{font-weight:600;margin-bottom:4px}.code{white-space:pre;overflow:auto}\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: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { 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: MatChipsModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i10.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i10.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i10.MatCardAvatar, selector: "[mat-card-avatar], [matCardAvatar]" }, { kind: "component", type: i10.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i10.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i10.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i11.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i11.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i12.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i12.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"] }] });
1929
+ `, 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:12px;display:grid;gap:12px;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.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}.pdx-steps{display:grid;gap:8px}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center}.pdx-step-list{display:grid;gap:8px}.pdx-step-item{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:start;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);cursor:pointer}.pdx-step-item.active{border-color:var(--md-sys-color-primary);box-shadow:var(--mat-elevation-level2)}.drag-handle{display:flex;align-items:center;color:var(--md-sys-color-on-surface-variant)}.pdx-fields{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.pdx-flag-group{display:flex;gap:10px;align-items:center}.pdx-active-step{display:grid;gap:12px;padding-top:8px;border-top:1px dashed var(--md-sys-color-outline-variant)}.pdx-active-step .hdr{display:flex;gap:12px;align-items:center;justify-content:space-between}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container-lowest)}.section-body{display:grid;gap:8px}.section-title{font-weight:600;opacity:.85}.section-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.section-head{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.editorial-section{background:var(--md-sys-color-surface-container-low);border-color:var(--md-sys-color-primary)}.mini-card{display:block}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:8px;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.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)}.widget-item .info .meta{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:8px;flex-wrap:wrap;justify-content:flex-end}.editorial-item{align-items:start}.editorial-item .actions{justify-content:flex-start}.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(240px,1fr));gap:12px;margin-bottom:8px}.cta-card{display:grid;gap:8px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.cta-card .cta-head{display:flex;align-items:center;gap:8px}.cta-card .cta-title{font-weight:600}.cta-card .cta-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.cta-card .cta-actions{display:flex;gap:8px;align-items:center}.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-card{display:grid;gap:8px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.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-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}.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}@media(max-width:900px){.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-start}}@media(max-width:640px){.pdx-active-step .hdr{align-items:flex-start;flex-direction:column}.pdx-flag-group{flex-direction:column;align-items:flex-start}.zone-head{align-items:flex-start;flex-direction:column}.zone-actions{justify-content: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: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { 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: MatChipsModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i10.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i10.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i10.MatCardAvatar, selector: "[mat-card-avatar], [matCardAvatar]" }, { kind: "component", type: i10.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i10.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i10.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i11.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i11.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i12.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i12.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i12.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i13.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i13.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"] }] });
995
1930
  }
996
1931
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisStepperConfigEditor, decorators: [{
997
1932
  type: Component,
@@ -1010,6 +1945,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1010
1945
  MatCardModule,
1011
1946
  MatButtonToggleModule,
1012
1947
  MatDialogModule,
1948
+ MatMenuModule,
1013
1949
  MatTabsModule,
1014
1950
  ], template: `
1015
1951
  <div class="pdx-editor">
@@ -1024,7 +1960,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1024
1960
  <option value="horizontal">Horizontal</option>
1025
1961
  <option value="vertical">Vertical</option>
1026
1962
  </select>
1027
- <mat-hint>Horizontal: cabeçalho no topo • Vertical: lista à esquerda</mat-hint>
1963
+ <button
1964
+ mat-icon-button
1965
+ matSuffix
1966
+ class="help-icon-button"
1967
+ type="button"
1968
+ [matTooltip]="'Horizontal: cabeçalho no topo • Vertical: lista à esquerda'"
1969
+ matTooltipPosition="above"
1970
+ >
1971
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1972
+ </button>
1028
1973
  </mat-form-field>
1029
1974
  <mat-form-field appearance="outline">
1030
1975
  <mat-label>Posição dos títulos</mat-label>
@@ -1032,7 +1977,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1032
1977
  <option value="top">Acima</option>
1033
1978
  <option value="bottom">Abaixo</option>
1034
1979
  </select>
1035
- <mat-hint>Válido na orientação horizontal</mat-hint>
1980
+ <button
1981
+ mat-icon-button
1982
+ matSuffix
1983
+ class="help-icon-button"
1984
+ type="button"
1985
+ [matTooltip]="'Válido na orientação horizontal'"
1986
+ matTooltipPosition="above"
1987
+ >
1988
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
1989
+ </button>
1036
1990
  </mat-form-field>
1037
1991
  <mat-form-field appearance="outline">
1038
1992
  <mat-label>Posição do rótulo</mat-label>
@@ -1040,7 +1994,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1040
1994
  <option value="end">Ao lado</option>
1041
1995
  <option value="bottom">Abaixo</option>
1042
1996
  </select>
1043
- <mat-hint>Como o texto aparece no cabeçalho</mat-hint>
1997
+ <button
1998
+ mat-icon-button
1999
+ matSuffix
2000
+ class="help-icon-button"
2001
+ type="button"
2002
+ [matTooltip]="'Como o texto aparece no cabeçalho'"
2003
+ matTooltipPosition="above"
2004
+ >
2005
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2006
+ </button>
1044
2007
  </mat-form-field>
1045
2008
  <mat-form-field appearance="outline">
1046
2009
  <mat-label>Cor</mat-label>
@@ -1050,17 +2013,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1050
2013
  <option value="accent">Acento</option>
1051
2014
  <option value="warn">Alerta</option>
1052
2015
  </select>
1053
- <mat-hint>Aplicável a temas Material 2 (M2)</mat-hint>
2016
+ <button
2017
+ mat-icon-button
2018
+ matSuffix
2019
+ class="help-icon-button"
2020
+ type="button"
2021
+ [matTooltip]="'Aplicável a temas Material 2 (M2)'"
2022
+ matTooltipPosition="above"
2023
+ >
2024
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2025
+ </button>
1054
2026
  </mat-form-field>
1055
2027
  <mat-form-field appearance="outline">
1056
2028
  <mat-label>Duração da animação</mat-label>
1057
2029
  <input matInput [(ngModel)]="config.animationDuration" (ngModelChange)="markDirty()" placeholder="Ex.: 300ms" />
1058
- <mat-hint>Tempo da transição entre etapas</mat-hint>
2030
+ <button
2031
+ mat-icon-button
2032
+ matSuffix
2033
+ class="help-icon-button"
2034
+ type="button"
2035
+ [matTooltip]="'Tempo da transição entre etapas'"
2036
+ matTooltipPosition="above"
2037
+ >
2038
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2039
+ </button>
1059
2040
  </mat-form-field>
1060
2041
  <mat-form-field appearance="outline">
1061
2042
  <mat-label>Etapa selecionada</mat-label>
1062
2043
  <input matInput type="number" [(ngModel)]="config.selectedIndex" (ngModelChange)="markDirty()" />
1063
- <mat-hint>Índice inicia em 0 (primeira etapa)</mat-hint>
2044
+ <button
2045
+ mat-icon-button
2046
+ matSuffix
2047
+ class="help-icon-button"
2048
+ type="button"
2049
+ [matTooltip]="'Índice inicia em 0 (primeira etapa)'"
2050
+ matTooltipPosition="above"
2051
+ >
2052
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2053
+ </button>
1064
2054
  </mat-form-field>
1065
2055
  <mat-form-field appearance="outline">
1066
2056
  <mat-label>Densidade</mat-label>
@@ -1069,22 +2059,58 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1069
2059
  <option value="comfortable">Confortável</option>
1070
2060
  <option value="compact">Compacta</option>
1071
2061
  </select>
1072
- <mat-hint>Controla espaçamentos e alturas</mat-hint>
2062
+ <button
2063
+ mat-icon-button
2064
+ matSuffix
2065
+ class="help-icon-button"
2066
+ type="button"
2067
+ [matTooltip]="'Controla espaçamentos e alturas'"
2068
+ matTooltipPosition="above"
2069
+ >
2070
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2071
+ </button>
1073
2072
  </mat-form-field>
1074
2073
  <mat-form-field appearance="outline" class="w-full">
1075
2074
  <mat-label>Classe do stepper (opcional)</mat-label>
1076
2075
  <input matInput [(ngModel)]="config.stepperClass" (ngModelChange)="markDirty()" placeholder="Ex.: meu-stepper" />
1077
- <mat-hint>Permite estilizar com CSS escopado</mat-hint>
2076
+ <button
2077
+ mat-icon-button
2078
+ matSuffix
2079
+ class="help-icon-button"
2080
+ type="button"
2081
+ [matTooltip]="'Permite estilizar com CSS escopado'"
2082
+ matTooltipPosition="above"
2083
+ >
2084
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2085
+ </button>
1078
2086
  </mat-form-field>
1079
2087
  <mat-form-field appearance="outline" class="w-full">
1080
2088
  <mat-label>Classe do cabeçalho (opcional)</mat-label>
1081
2089
  <input matInput [(ngModel)]="config.headerClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-header" />
1082
- <mat-hint>Use para ajustes finos de aparência</mat-hint>
2090
+ <button
2091
+ mat-icon-button
2092
+ matSuffix
2093
+ class="help-icon-button"
2094
+ type="button"
2095
+ [matTooltip]="'Use para ajustes finos de aparência'"
2096
+ matTooltipPosition="above"
2097
+ >
2098
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2099
+ </button>
1083
2100
  </mat-form-field>
1084
2101
  <mat-form-field appearance="outline" class="w-full">
1085
2102
  <mat-label>Classe do conteúdo (opcional)</mat-label>
1086
2103
  <input matInput [(ngModel)]="config.contentClass" (ngModelChange)="markDirty()" placeholder="Ex.: stepper-content" />
1087
- <mat-hint>Aplica uma classe à área de conteúdo</mat-hint>
2104
+ <button
2105
+ mat-icon-button
2106
+ matSuffix
2107
+ class="help-icon-button"
2108
+ type="button"
2109
+ [matTooltip]="'Aplica uma classe à área de conteúdo'"
2110
+ matTooltipPosition="above"
2111
+ >
2112
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2113
+ </button>
1088
2114
  </mat-form-field>
1089
2115
  </div>
1090
2116
  <div class="pdx-toggles">
@@ -1106,35 +2132,89 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1106
2132
  <div class="pdx-step-item" *ngFor="let s of config.steps; let i = index" cdkDrag [class.active]="activeIndex === i" (click)="setActive(i)">
1107
2133
  <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
1108
2134
  <div class="pdx-fields">
1109
- <mat-form-field appearance="outline" style="min-width: 180px;">
2135
+ <mat-form-field appearance="outline" class="min-180">
1110
2136
  <mat-label>Título da etapa</mat-label>
1111
2137
  <input matInput [(ngModel)]="s.label" (ngModelChange)="markDirty()" />
1112
- <mat-hint>Como aparecerá no cabeçalho</mat-hint>
2138
+ <button
2139
+ mat-icon-button
2140
+ matSuffix
2141
+ class="help-icon-button"
2142
+ type="button"
2143
+ [matTooltip]="'Como aparecerá no cabeçalho'"
2144
+ matTooltipPosition="above"
2145
+ >
2146
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2147
+ </button>
1113
2148
  </mat-form-field>
1114
2149
  <mat-form-field appearance="outline">
1115
2150
  <mat-label>Identificador (opcional)</mat-label>
1116
2151
  <input matInput [(ngModel)]="s.id" (ngModelChange)="markDirty()" />
1117
- <mat-hint>Útil para automações</mat-hint>
2152
+ <button
2153
+ mat-icon-button
2154
+ matSuffix
2155
+ class="help-icon-button"
2156
+ type="button"
2157
+ [matTooltip]="'Útil para automações'"
2158
+ matTooltipPosition="above"
2159
+ >
2160
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2161
+ </button>
1118
2162
  </mat-form-field>
1119
2163
  <mat-form-field appearance="outline">
1120
2164
  <mat-label>Texto alternativo (acessibilidade)</mat-label>
1121
2165
  <input matInput [(ngModel)]="s.ariaLabel" (ngModelChange)="markDirty()" />
1122
- <mat-hint>Lido por leitores de tela</mat-hint>
2166
+ <button
2167
+ mat-icon-button
2168
+ matSuffix
2169
+ class="help-icon-button"
2170
+ type="button"
2171
+ [matTooltip]="'Lido por leitores de tela'"
2172
+ matTooltipPosition="above"
2173
+ >
2174
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2175
+ </button>
1123
2176
  </mat-form-field>
1124
2177
  <mat-form-field appearance="outline">
1125
2178
  <mat-label>ID que descreve (opcional)</mat-label>
1126
2179
  <input matInput [(ngModel)]="s.ariaLabelledby" (ngModelChange)="markDirty()" />
1127
- <mat-hint>ID de um elemento que descreve a etapa</mat-hint>
2180
+ <button
2181
+ mat-icon-button
2182
+ matSuffix
2183
+ class="help-icon-button"
2184
+ type="button"
2185
+ [matTooltip]="'ID de um elemento que descreve a etapa'"
2186
+ matTooltipPosition="above"
2187
+ >
2188
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2189
+ </button>
1128
2190
  </mat-form-field>
1129
2191
  <mat-form-field appearance="outline">
1130
2192
  <mat-label>Ícone/estado do marcador</mat-label>
1131
2193
  <input matInput [(ngModel)]="s.state" (ngModelChange)="markDirty()" placeholder="Ex.: number, done, edit" />
1132
- <mat-hint>Controla o ícone do passo (quando aplicável)</mat-hint>
2194
+ <button
2195
+ mat-icon-button
2196
+ matSuffix
2197
+ class="help-icon-button"
2198
+ type="button"
2199
+ [matTooltip]="'Controla o ícone do passo (quando aplicável)'"
2200
+ matTooltipPosition="above"
2201
+ >
2202
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2203
+ </button>
1133
2204
  </mat-form-field>
1134
2205
  <mat-form-field appearance="outline">
1135
2206
  <mat-label>Mensagem de erro</mat-label>
1136
2207
  <input matInput [(ngModel)]="s.errorMessage" (ngModelChange)="markDirty()" />
1137
- <mat-hint>Mostrada quando há erro na etapa</mat-hint>
2208
+ <button
2209
+ mat-icon-button
2210
+ matSuffix
2211
+ class="help-icon-button"
2212
+ type="button"
2213
+ [matTooltip]="'Mostrada quando há erro na etapa'"
2214
+ matTooltipPosition="above"
2215
+ >
2216
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2217
+ </button>
1138
2218
  </mat-form-field>
1139
2219
  <div class="pdx-flag-group">
1140
2220
  <mat-slide-toggle [(ngModel)]="s.optional" (ngModelChange)="markDirty()">Etapa opcional</mat-slide-toggle>
@@ -1161,8 +2241,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1161
2241
  </div>
1162
2242
 
1163
2243
  <div class="pdx-content-editor">
2244
+ <div class="section editorial-section">
2245
+ <div class="section-head">
2246
+ <div>
2247
+ <div class="section-title">Conteúdo editorial</div>
2248
+ <div class="section-subtitle">Organize os blocos narrativos da etapa antes ou depois do formulário.</div>
2249
+ </div>
2250
+ </div>
2251
+
2252
+ <div class="zone-grid">
2253
+ <div class="zone-card">
2254
+ <div class="zone-head">
2255
+ <div class="zone-title">Antes do formulário</div>
2256
+ <div class="zone-actions">
2257
+ <span class="zone-count">{{ editorialBeforeWidgets(step).length }}</span>
2258
+ <button mat-stroked-button [matMenuTriggerFor]="beforeEditorialMenu">
2259
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
2260
+ Adicionar
2261
+ </button>
2262
+ <mat-menu #beforeEditorialMenu="matMenu">
2263
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'before')">
2264
+ <mat-icon [praxisIcon]="'view_module'"></mat-icon>
2265
+ Grade de benefícios
2266
+ </button>
2267
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'before')">
2268
+ <mat-icon [praxisIcon]="'article'"></mat-icon>
2269
+ Bloco de conteúdo
2270
+ </button>
2271
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'before')">
2272
+ <mat-icon [praxisIcon]="'info'"></mat-icon>
2273
+ Aviso inline
2274
+ </button>
2275
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'before')">
2276
+ <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
2277
+ Divisor
2278
+ </button>
2279
+ </mat-menu>
2280
+ </div>
2281
+ </div>
2282
+ <div cdkDropList (cdkDropListDropped)="dropEditorialBefore($event)" class="widget-list">
2283
+ <div class="widget-item editorial-item" *ngFor="let w of editorialBeforeWidgets(step)" cdkDrag>
2284
+ <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
2285
+ <div class="info">
2286
+ <div class="name">{{ displayWidgetName(w) }}</div>
2287
+ <div class="sub">{{ editorialWidgetSummary(w) }}</div>
2288
+ <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
2289
+ </div>
2290
+ <div class="actions">
2291
+ <button mat-button (click)="editWidget(w)">
2292
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
2293
+ Editar
2294
+ </button>
2295
+ <button mat-button (click)="moveEditorialWidget(w, 'before', 'after')">
2296
+ <mat-icon [praxisIcon]="'arrow_downward'"></mat-icon>
2297
+ Mover para depois
2298
+ </button>
2299
+ <button mat-button (click)="duplicateEditorialWidget(w, 'before')">
2300
+ <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
2301
+ Duplicar
2302
+ </button>
2303
+ <button mat-button color="warn" (click)="removeEditorialWidget(w, 'before')">
2304
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
2305
+ Remover
2306
+ </button>
2307
+ </div>
2308
+ </div>
2309
+ <div class="empty" *ngIf="!editorialBeforeWidgets(step).length">Nenhum bloco nesta zona.</div>
2310
+ </div>
2311
+ </div>
2312
+
2313
+ <div class="zone-card">
2314
+ <div class="zone-head">
2315
+ <div class="zone-title">Depois do formulário</div>
2316
+ <div class="zone-actions">
2317
+ <span class="zone-count">{{ editorialAfterWidgets(step).length }}</span>
2318
+ <button mat-stroked-button [matMenuTriggerFor]="afterEditorialMenu">
2319
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
2320
+ Adicionar
2321
+ </button>
2322
+ <mat-menu #afterEditorialMenu="matMenu">
2323
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-benefits', 'after')">
2324
+ <mat-icon [praxisIcon]="'view_module'"></mat-icon>
2325
+ Grade de benefícios
2326
+ </button>
2327
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-content', 'after')">
2328
+ <mat-icon [praxisIcon]="'article'"></mat-icon>
2329
+ Bloco de conteúdo
2330
+ </button>
2331
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-inline-notice', 'after')">
2332
+ <mat-icon [praxisIcon]="'info'"></mat-icon>
2333
+ Aviso inline
2334
+ </button>
2335
+ <button mat-menu-item (click)="addEditorialWidget('praxis-wizard-divider', 'after')">
2336
+ <mat-icon [praxisIcon]="'horizontal_rule'"></mat-icon>
2337
+ Divisor
2338
+ </button>
2339
+ </mat-menu>
2340
+ </div>
2341
+ </div>
2342
+ <div cdkDropList (cdkDropListDropped)="dropEditorialAfter($event)" class="widget-list">
2343
+ <div class="widget-item editorial-item" *ngFor="let w of editorialAfterWidgets(step)" cdkDrag>
2344
+ <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
2345
+ <div class="info">
2346
+ <div class="name">{{ displayWidgetName(w) }}</div>
2347
+ <div class="sub">{{ editorialWidgetSummary(w) }}</div>
2348
+ <div class="meta" *ngIf="widgetBlockId(w) as blockId">ID: {{ blockId }}</div>
2349
+ </div>
2350
+ <div class="actions">
2351
+ <button mat-button (click)="editWidget(w)">
2352
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
2353
+ Editar
2354
+ </button>
2355
+ <button mat-button (click)="moveEditorialWidget(w, 'after', 'before')">
2356
+ <mat-icon [praxisIcon]="'arrow_upward'"></mat-icon>
2357
+ Mover para antes
2358
+ </button>
2359
+ <button mat-button (click)="duplicateEditorialWidget(w, 'after')">
2360
+ <mat-icon [praxisIcon]="'content_copy'"></mat-icon>
2361
+ Duplicar
2362
+ </button>
2363
+ <button mat-button color="warn" (click)="removeEditorialWidget(w, 'after')">
2364
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
2365
+ Remover
2366
+ </button>
2367
+ </div>
2368
+ </div>
2369
+ <div class="empty" *ngIf="!editorialAfterWidgets(step).length">Nenhum bloco nesta zona.</div>
2370
+ </div>
2371
+ </div>
2372
+ </div>
2373
+ </div>
2374
+
1164
2375
  <div class="section">
1165
- <div class="section-title">Formulário principal</div>
2376
+ <div class="section-title">Formulário da etapa</div>
1166
2377
  <div class="section-body">
1167
2378
  <ng-container *ngIf="step.form; else addFormBtn">
1168
2379
  <mat-card appearance="outlined" class="mini-card">
@@ -1184,62 +2395,91 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1184
2395
  </div>
1185
2396
 
1186
2397
  <div class="section">
1187
- <div class="section-title">Conteúdos e componentes</div>
2398
+ <div class="section-head">
2399
+ <div>
2400
+ <div class="section-title">Componentes avançados</div>
2401
+ <div class="section-subtitle">Use para cenários de seleção e integrações específicas.</div>
2402
+ </div>
2403
+ <button mat-stroked-button (click)="openMoreComponents()">
2404
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
2405
+ Mais componentes
2406
+ </button>
2407
+ </div>
1188
2408
  <div class="section-body">
1189
2409
  <div class="cta-grid">
1190
2410
  <div class="cta-card mat-elevation-z2">
1191
2411
  <div class="cta-head">
1192
- <mat-icon [praxisIcon]="'dynamic_form'"></mat-icon>
1193
- <div class="cta-title">Formulário dinâmico</div>
2412
+ <mat-icon [praxisIcon]="'account_tree'"></mat-icon>
2413
+ <div class="cta-title">Lista em árvore</div>
1194
2414
  </div>
1195
- <div class="cta-desc">Crie campos e validações personalizadas nesta etapa.</div>
2415
+ <div class="cta-desc">Exiba dados hierárquicos com seleção simples.</div>
1196
2416
  <div class="cta-actions">
1197
- <button mat-flat-button color="primary" (click)="addMainForm()">
2417
+ <button mat-stroked-button (click)="addTreeList()">
1198
2418
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1199
- Inserir formulário
2419
+ Inserir árvore
1200
2420
  </button>
1201
2421
  </div>
1202
2422
  </div>
1203
2423
  <div class="cta-card mat-elevation-z2">
1204
2424
  <div class="cta-head">
1205
- <mat-icon [praxisIcon]="'account_tree'"></mat-icon>
1206
- <div class="cta-title">Lista em árvore</div>
2425
+ <mat-icon [praxisIcon]="'swap_horiz'"></mat-icon>
2426
+ <div class="cta-title">Transferência de itens</div>
1207
2427
  </div>
1208
- <div class="cta-desc">Exiba dados hierárquicos com seleção simples.</div>
2428
+ <div class="cta-desc">Mover itens entre listas (ideal para múltipla seleção).</div>
1209
2429
  <div class="cta-actions">
1210
- <button mat-stroked-button (click)="addTreeList()">
2430
+ <button mat-stroked-button (click)="addTransferListQuick()">
1211
2431
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1212
- Inserir árvore
2432
+ Inserir transferência
1213
2433
  </button>
1214
2434
  </div>
1215
2435
  </div>
1216
2436
  <div class="cta-card mat-elevation-z2">
1217
2437
  <div class="cta-head">
1218
- <mat-icon [praxisIcon]="'swap_horiz'"></mat-icon>
1219
- <div class="cta-title">Transferência de itens</div>
2438
+ <mat-icon [praxisIcon]="'search'"></mat-icon>
2439
+ <div class="cta-title">Seleção com busca</div>
1220
2440
  </div>
1221
- <div class="cta-desc">Mover itens entre listas (ideal para múltipla seleção).</div>
2441
+ <div class="cta-desc">Campo de seleção com busca remota/local.</div>
1222
2442
  <div class="cta-actions">
1223
- <button mat-stroked-button (click)="addTransferListQuick()">
2443
+ <button mat-stroked-button (click)="addSearchableSelect()">
1224
2444
  <mat-icon [praxisIcon]="'add'"></mat-icon>
1225
- Inserir transferência
2445
+ Inserir seletor
2446
+ </button>
2447
+ </div>
2448
+ </div>
2449
+ <div class="cta-card mat-elevation-z2">
2450
+ <div class="cta-head">
2451
+ <mat-icon [praxisIcon]="'upload_file'"></mat-icon>
2452
+ <div class="cta-title">Upload de arquivos</div>
2453
+ </div>
2454
+ <div class="cta-desc">Anexe documentos com validação de upload.</div>
2455
+ <div class="cta-actions">
2456
+ <button mat-stroked-button (click)="addFilesUpload()">
2457
+ <mat-icon [praxisIcon]="'add'"></mat-icon>
2458
+ Inserir upload
1226
2459
  </button>
1227
2460
  </div>
1228
2461
  </div>
1229
2462
  </div>
1230
- <div cdkDropList (cdkDropListDropped)="dropWidget($event)" class="widget-list">
1231
- <div class="widget-item" *ngFor="let w of (step.widgets || []); let wi = index" cdkDrag>
1232
- <div class="drag-handle" cdkDragHandle><mat-icon [praxisIcon]="'drag_indicator'"></mat-icon></div>
2463
+
2464
+ <div class="widget-list advanced-list">
2465
+ <div class="widget-item" *ngFor="let w of advancedWidgets(step)">
2466
+ <div class="drag-handle"><mat-icon [praxisIcon]="'extension'"></mat-icon></div>
1233
2467
  <div class="info">
1234
2468
  <div class="name">{{ displayWidgetName(w) }}</div>
1235
2469
  <div class="sub">{{ w.id }}</div>
1236
2470
  </div>
1237
2471
  <div class="actions">
1238
- <button mat-button (click)="editWidget(w, wi)"><mat-icon [praxisIcon]="'tune'"></mat-icon> Editar</button>
1239
- <button mat-button color="warn" (click)="removeWidget(wi)"><mat-icon [praxisIcon]="'delete'"></mat-icon> Remover</button>
2472
+ <button mat-button (click)="editWidget(w)" [disabled]="!canEditWidget(w)">
2473
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
2474
+ Editar
2475
+ </button>
2476
+ <button mat-button color="warn" (click)="removeAdvancedWidget(w)">
2477
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
2478
+ Remover
2479
+ </button>
1240
2480
  </div>
1241
2481
  </div>
1242
- <div class="empty" *ngIf="!step.widgets || !step.widgets.length">Nenhum componente adicionado</div>
2482
+ <div class="empty" *ngIf="!advancedWidgets(step).length">Nenhum componente avançado adicionado.</div>
1243
2483
  </div>
1244
2484
  </div>
1245
2485
  </div>
@@ -1327,12 +2567,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1327
2567
  <mat-form-field appearance="outline">
1328
2568
  <mat-label>Altura do cabeçalho (px)</mat-label>
1329
2569
  <input matInput type="number" [ngModel]="headerHeightPx" (ngModelChange)="setHeaderHeightPx($event)" placeholder="Ex.: 48" />
1330
- <mat-hint>Altura do item do cabeçalho</mat-hint>
2570
+ <button
2571
+ mat-icon-button
2572
+ matSuffix
2573
+ class="help-icon-button"
2574
+ type="button"
2575
+ [matTooltip]="'Altura do item do cabeçalho'"
2576
+ matTooltipPosition="above"
2577
+ >
2578
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2579
+ </button>
1331
2580
  </mat-form-field>
1332
2581
  <mat-form-field appearance="outline">
1333
2582
  <mat-label>Tamanho do texto (px)</mat-label>
1334
2583
  <input matInput type="number" [ngModel]="headerLabelTextSizePx" (ngModelChange)="setHeaderLabelTextSizePx($event)" placeholder="Ex.: 14" />
1335
- <mat-hint>Tamanho do título da etapa</mat-hint>
2584
+ <button
2585
+ mat-icon-button
2586
+ matSuffix
2587
+ class="help-icon-button"
2588
+ type="button"
2589
+ [matTooltip]="'Tamanho do título da etapa'"
2590
+ matTooltipPosition="above"
2591
+ >
2592
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2593
+ </button>
1336
2594
  </mat-form-field>
1337
2595
  <mat-form-field appearance="outline">
1338
2596
  <mat-label>Peso do texto</mat-label>
@@ -1349,7 +2607,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1349
2607
  <mat-form-field appearance="outline" class="w-full">
1350
2608
  <mat-label>Classe de tema (opcional)</mat-label>
1351
2609
  <input matInput [(ngModel)]="appearance.themeClass" (ngModelChange)="onAppearanceChange()" placeholder="Ex.: theme-stepper-custom" />
1352
- <mat-hint>Aplica as cores apenas dentro desse seletor</mat-hint>
2610
+ <button
2611
+ mat-icon-button
2612
+ matSuffix
2613
+ class="help-icon-button"
2614
+ type="button"
2615
+ [matTooltip]="'Aplica as cores apenas dentro desse seletor'"
2616
+ matTooltipPosition="above"
2617
+ >
2618
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2619
+ </button>
1353
2620
  </mat-form-field>
1354
2621
  <mat-form-field appearance="outline">
1355
2622
  <mat-label>Conjunto de ícones</mat-label>
@@ -1359,7 +2626,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1359
2626
  <option value="material-symbols-rounded">Material Symbols (Rounded)</option>
1360
2627
  <option value="material-symbols-sharp">Material Symbols (Sharp)</option>
1361
2628
  </select>
1362
- <mat-hint>Selecione se usar ícones do Material Symbols</mat-hint>
2629
+ <button
2630
+ mat-icon-button
2631
+ matSuffix
2632
+ class="help-icon-button"
2633
+ type="button"
2634
+ [matTooltip]="'Selecione se usar ícones do Material Symbols'"
2635
+ matTooltipPosition="above"
2636
+ >
2637
+ <mat-icon [praxisIcon]="'help_outline'"></mat-icon>
2638
+ </button>
1363
2639
  </mat-form-field>
1364
2640
  </div>
1365
2641
  <div class="icons-grid">
@@ -1420,12 +2696,225 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1420
2696
  </mat-tab>
1421
2697
  </mat-tab-group>
1422
2698
  </div>
1423
- `, styles: [".pdx-editor{display:grid;gap:16px}.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:12px 4px;display:grid;gap:12px}.help{color:#000000b3;font-size:13px}.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}.pdx-steps{display:grid;gap:8px}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center}.pdx-step-list{display:grid;gap:8px}.pdx-step-item{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:start;padding:8px;border:1px solid rgba(0,0,0,.12);border-radius:8px;cursor:pointer}.pdx-step-item.active{border-color:color-mix(in oklab,var(--md-sys-color-primary) 40%,rgba(0,0,0,.12));box-shadow:var(--mat-elevation-transition),var(--mat-elevation-level2, 0 2px 6px rgba(0,0,0,.12))}.drag-handle{display:flex;align-items:center;color:#0000008a}.pdx-fields{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.pdx-flag-group{display:flex;gap:10px;align-items:center}.pdx-active-step{display:grid;gap:12px;padding-top:8px;border-top:1px dashed rgba(0,0,0,.12)}.pdx-active-step .hdr{display:flex;gap:12px;align-items:center;justify-content:space-between}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:8px}.section-title{font-weight:600;opacity:.85}.mini-card{display:block}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:8px;padding:8px;border:1px solid rgba(0,0,0,.12);border-radius:8px}.widget-item .info .name{font-weight:600}.widget-item .info .sub{font-size:12px;opacity:.7}.widget-item .actions{display:flex;gap:8px}.cta-row{display:flex;gap:8px;align-items:center}.spacer{flex:1 1 auto}.muted{color:#0009}.cta-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px;margin-bottom:8px}.cta-card{display:grid;gap:8px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant, rgba(0,0,0,.12));background:var(--md-sys-color-surface)}.cta-card .cta-head{display:flex;align-items:center;gap:8px}.cta-card .cta-title{font-weight:600}.cta-card .cta-desc{font-size:12px;opacity:.78}.cta-card .cta-actions{display:flex;gap:8px;align-items:center}.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}.code-card{margin-top:8px}.code-head{font-weight:600;margin-bottom:4px}.code{white-space:pre;overflow:auto}\n"] }]
2699
+ `, 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:12px;display:grid;gap:12px;background:var(--md-sys-color-surface);border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.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}.pdx-steps{display:grid;gap:8px}.pdx-steps-header{display:flex;justify-content:space-between;align-items:center}.pdx-step-list{display:grid;gap:8px}.pdx-step-item{display:grid;grid-template-columns:24px 1fr auto;gap:8px;align-items:start;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);cursor:pointer}.pdx-step-item.active{border-color:var(--md-sys-color-primary);box-shadow:var(--mat-elevation-level2)}.drag-handle{display:flex;align-items:center;color:var(--md-sys-color-on-surface-variant)}.pdx-fields{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.pdx-flag-group{display:flex;gap:10px;align-items:center}.pdx-active-step{display:grid;gap:12px;padding-top:8px;border-top:1px dashed var(--md-sys-color-outline-variant)}.pdx-active-step .hdr{display:flex;gap:12px;align-items:center;justify-content:space-between}.pdx-content-editor{display:grid;gap:16px}.section{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;background:var(--md-sys-color-surface-container-lowest)}.section-body{display:grid;gap:8px}.section-title{font-weight:600;opacity:.85}.section-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.section-head{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.editorial-section{background:var(--md-sys-color-surface-container-low);border-color:var(--md-sys-color-primary)}.mini-card{display:block}.widget-list{display:grid;gap:8px}.widget-item{display:grid;grid-template-columns:24px 1fr auto;align-items:center;gap:8px;padding:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.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)}.widget-item .info .meta{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:8px;flex-wrap:wrap;justify-content:flex-end}.editorial-item{align-items:start}.editorial-item .actions{justify-content:flex-start}.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(240px,1fr));gap:12px;margin-bottom:8px}.cta-card{display:grid;gap:8px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.cta-card .cta-head{display:flex;align-items:center;gap:8px}.cta-card .cta-title{font-weight:600}.cta-card .cta-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.cta-card .cta-actions{display:flex;gap:8px;align-items:center}.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-card{display:grid;gap:8px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.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-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}.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}@media(max-width:900px){.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-start}}@media(max-width:640px){.pdx-active-step .hdr{align-items:flex-start;flex-direction:column}.pdx-flag-group{flex-direction:column;align-items:flex-start}.zone-head{align-items:flex-start;flex-direction:column}.zone-actions{justify-content:flex-start}}\n"] }]
1424
2700
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1425
2701
  type: Inject,
1426
2702
  args: [SETTINGS_PANEL_DATA]
1427
2703
  }] }] });
1428
2704
 
2705
+ /**
2706
+ * Capabilities catalog for Praxis Stepper (StepperMetadata).
2707
+ * Paths follow StepperMetadata shape (patch merged at config root).
2708
+ */
2709
+ const ENUMS = {
2710
+ orientation: ['horizontal', 'vertical'],
2711
+ headerPosition: ['top', 'bottom'],
2712
+ labelPosition: ['bottom', 'end'],
2713
+ density: ['default', 'comfortable', 'compact'],
2714
+ matColor: ['primary', 'accent', 'warn'],
2715
+ navVariant: ['basic', 'flat', 'stroked', 'raised'],
2716
+ navAlign: ['start', 'center', 'end', 'space-between'],
2717
+ formMode: ['create', 'edit', 'view'],
2718
+ schemaSource: ['resource', 'filter'],
2719
+ iconsSet: ['material-symbols-outlined', 'material-symbols-rounded', 'material-symbols-sharp'],
2720
+ widgetId: ['praxis-dynamic-form', 'praxis-list', 'pdx-material-searchable-select', 'praxis-files-upload'],
2721
+ stepperTokenKey: [
2722
+ 'container-color',
2723
+ 'line-color',
2724
+ 'header-label-text-color',
2725
+ 'header-optional-label-text-color',
2726
+ 'header-icon-foreground-color',
2727
+ 'header-icon-background-color',
2728
+ 'header-done-state-icon-background-color',
2729
+ 'header-done-state-icon-foreground-color',
2730
+ 'header-edit-state-icon-background-color',
2731
+ 'header-edit-state-icon-foreground-color',
2732
+ 'header-error-state-icon-background-color',
2733
+ 'header-error-state-icon-foreground-color',
2734
+ 'header-error-state-label-text-color',
2735
+ 'header-focus-state-layer-color',
2736
+ 'header-hover-state-layer-color',
2737
+ 'header-label-text-font',
2738
+ 'header-label-text-size',
2739
+ 'header-label-text-weight',
2740
+ 'header-selected-state-label-text-size',
2741
+ 'header-selected-state-label-text-weight',
2742
+ 'container-text-font',
2743
+ 'header-height',
2744
+ 'header-focus-state-layer-shape',
2745
+ 'header-hover-state-layer-shape',
2746
+ 'header-selected-state-icon-background-color',
2747
+ 'header-selected-state-icon-foreground-color',
2748
+ 'header-selected-state-label-text-color',
2749
+ ],
2750
+ };
2751
+ const CAPS = [
2752
+ { path: 'orientation', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.orientation, description: 'Orientation of the stepper.' },
2753
+ { path: 'linear', category: 'behavior', valueKind: 'boolean', description: 'Require sequential completion of steps.' },
2754
+ { path: 'headerPosition', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.headerPosition, description: 'Header position (vertical only).' },
2755
+ { path: 'labelPosition', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.labelPosition, description: 'Label position for horizontal stepper.' },
2756
+ { path: 'color', category: 'appearance', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'Material color palette.' },
2757
+ { path: 'disableRipple', category: 'behavior', valueKind: 'boolean', description: 'Disable ripple for headers.' },
2758
+ { path: 'animationDuration', category: 'behavior', valueKind: 'string', description: 'Animation duration, e.g. 300ms.' },
2759
+ { path: 'selectedIndex', category: 'behavior', valueKind: 'number', description: 'Current step index.' },
2760
+ { path: 'density', category: 'appearance', valueKind: 'enum', allowedValues: ENUMS.density, description: 'Density preset.' },
2761
+ { path: 'stepperClass', category: 'appearance', valueKind: 'string', description: 'CSS class for stepper root.' },
2762
+ { path: 'headerClass', category: 'appearance', valueKind: 'string', description: 'CSS class for header.' },
2763
+ { path: 'contentClass', category: 'appearance', valueKind: 'string', description: 'CSS class for content area.' },
2764
+ { path: 'appearance', category: 'appearance', valueKind: 'object', description: 'Appearance settings.' },
2765
+ { path: 'appearance.themeClass', category: 'appearance', valueKind: 'string', description: 'Theme CSS class for root.' },
2766
+ { path: 'appearance.tokens', category: 'appearance', valueKind: 'object', description: 'Token map for theme overrides.' },
2767
+ { path: 'appearance.tokens.[token]', category: 'appearance', valueKind: 'string', allowedValues: ENUMS.stepperTokenKey, description: 'Token value (CSS value or var).', safetyNotes: 'Token keys follow mat.stepper-overrides.' },
2768
+ { path: 'appearance.icons', category: 'appearance', valueKind: 'object', description: 'Stepper icon overrides.' },
2769
+ { path: 'appearance.icons.number', category: 'appearance', valueKind: 'string', description: 'Icon for number state.' },
2770
+ { path: 'appearance.icons.done', category: 'appearance', valueKind: 'string', description: 'Icon for done state.' },
2771
+ { path: 'appearance.icons.edit', category: 'appearance', valueKind: 'string', description: 'Icon for edit state.' },
2772
+ { path: 'appearance.icons.error', category: 'appearance', valueKind: 'string', description: 'Icon for error state.' },
2773
+ { path: 'appearance.iconsSet', category: 'appearance', valueKind: 'enum', allowedValues: ENUMS.iconsSet, description: 'Icon set class name (Material Symbols).' },
2774
+ { path: 'navigation', category: 'navigation', valueKind: 'object', description: 'Footer navigation config.' },
2775
+ { path: 'navigation.visible', category: 'navigation', valueKind: 'boolean', description: 'Show navigation buttons.' },
2776
+ { path: 'navigation.prevLabel', category: 'navigation', valueKind: 'string', description: 'Previous button label.' },
2777
+ { path: 'navigation.nextLabel', category: 'navigation', valueKind: 'string', description: 'Next button label.' },
2778
+ { path: 'navigation.prevIcon', category: 'navigation', valueKind: 'string', description: 'Previous button icon.' },
2779
+ { path: 'navigation.nextIcon', category: 'navigation', valueKind: 'string', description: 'Next button icon.' },
2780
+ { path: 'navigation.variant', category: 'navigation', valueKind: 'enum', allowedValues: ENUMS.navVariant, description: 'Button variant.' },
2781
+ { path: 'navigation.color', category: 'navigation', valueKind: 'enum', allowedValues: ENUMS.matColor, description: 'Button color.' },
2782
+ { path: 'navigation.align', category: 'navigation', valueKind: 'enum', allowedValues: ENUMS.navAlign, description: 'Navigation alignment.' },
2783
+ { path: 'steps', category: 'steps', valueKind: 'array', description: 'Step definitions.' },
2784
+ { path: 'steps[]', category: 'steps', valueKind: 'object', description: 'Step definition.' },
2785
+ { path: 'steps[].id', category: 'steps', valueKind: 'string', description: 'Step id.' },
2786
+ { path: 'steps[].label', category: 'steps', valueKind: 'string', description: 'Step label.' },
2787
+ { path: 'steps[].description', category: 'steps', valueKind: 'string', description: 'Step description.' },
2788
+ { path: 'steps[].optional', category: 'steps', valueKind: 'boolean', description: 'Mark step as optional.' },
2789
+ { path: 'steps[].editable', category: 'steps', valueKind: 'boolean', description: 'Allow editing completed steps.' },
2790
+ { path: 'steps[].completed', category: 'steps', valueKind: 'boolean', description: 'Force completed state.' },
2791
+ { path: 'steps[].hasError', category: 'steps', valueKind: 'boolean', description: 'Force error state.' },
2792
+ { path: 'steps[].stateIcon', category: 'steps', valueKind: 'string', description: 'Custom state icon key.' },
2793
+ { path: 'steps[].state', category: 'steps', valueKind: 'string', description: 'Custom state name for matStepperIcon.' },
2794
+ { path: 'steps[].errorMessage', category: 'steps', valueKind: 'string', description: 'Error message shown in header.' },
2795
+ { path: 'steps[].ariaLabel', category: 'accessibility', valueKind: 'string', description: 'ARIA label for step header.' },
2796
+ { path: 'steps[].ariaLabelledby', category: 'accessibility', valueKind: 'string', description: 'ARIA labelledby for step header.' },
2797
+ { path: 'steps[].form', category: 'steps', valueKind: 'object', description: 'Optional Dynamic Form config for step.' },
2798
+ { path: 'steps[].form.resourcePath', category: 'steps', valueKind: 'string', description: 'Resource path for Dynamic Form.' },
2799
+ { path: 'steps[].form.resourceId', category: 'steps', valueKind: 'string', description: 'Resource id for Dynamic Form (string or number).', example: '123', safetyNotes: 'Accepts string or number.' },
2800
+ { path: 'steps[].form.mode', category: 'steps', valueKind: 'enum', allowedValues: ENUMS.formMode, description: 'Form mode.' },
2801
+ { path: 'steps[].form.config', category: 'steps', valueKind: 'object', description: 'FormConfig for Dynamic Form.', safetyNotes: 'Use the form catalog for nested paths and FieldMetadata details.' },
2802
+ { path: 'steps[].form.schemaSource', category: 'steps', valueKind: 'enum', allowedValues: ENUMS.schemaSource, description: 'Schema source for Dynamic Form.' },
2803
+ { path: 'steps[].form.formId', category: 'steps', valueKind: 'string', description: 'Form id for Dynamic Form.' },
2804
+ { path: 'steps[].widgets', category: 'steps', valueKind: 'array', description: 'WidgetDefinition list for step content.' },
2805
+ { path: 'steps[].widgets[]', category: 'steps', valueKind: 'object', description: 'WidgetDefinition item.' },
2806
+ { path: 'steps[].widgets[].id', category: 'steps', valueKind: 'enum', allowedValues: ENUMS.widgetId, description: 'Component registry id for widget.', safetyNotes: 'Use ids registered in ComponentMetadataRegistry.' },
2807
+ { path: 'steps[].widgets[].inputs', category: 'steps', valueKind: 'object', description: 'Inputs bound into the widget instance.' },
2808
+ { path: 'steps[].widgets[].outputs', category: 'steps', valueKind: 'object', description: 'Outputs mapped to actions.' },
2809
+ { path: 'steps[].widgets[].outputs.[outputName]', category: 'steps', valueKind: 'object', description: 'Output action mapping (ActionDefinition or "emit").', safetyNotes: 'Use string "emit" to forward the output without mapping.' },
2810
+ { path: 'steps[].widgets[].bindingOrder', category: 'steps', valueKind: 'array', description: 'Explicit input binding order.' },
2811
+ { path: 'steps[].widgets[].bindingOrder[]', category: 'steps', valueKind: 'string', description: 'Input name applied first.' },
2812
+ ];
2813
+ const STEPPER_AI_CAPABILITIES = {
2814
+ version: 'v1.2',
2815
+ enums: ENUMS,
2816
+ targets: [
2817
+ 'praxis-stepper',
2818
+ 'mat-stepper',
2819
+ 'stepper',
2820
+ 'praxis-stepper-config-editor',
2821
+ 'praxis-select-quick-config-dialog',
2822
+ ],
2823
+ notes: [
2824
+ 'steps[] should be merged by id or label to avoid replacing all steps.',
2825
+ 'steps[].form.config uses FormConfig (see form catalog) and may include sections/actions/fieldMetadata.',
2826
+ 'steps[].widgets[].id must be a ComponentMetadataRegistry id (see component-registry catalog).',
2827
+ 'appearance.tokens is a free-form map; host may validate/sanitize.',
2828
+ 'When editing steps[].form.config.fieldMetadata, use FieldMetadata base if no controlType catalog exists.',
2829
+ ],
2830
+ capabilities: CAPS,
2831
+ };
2832
+
2833
+ class StepperAiAdapter extends BaseAiAdapter {
2834
+ stepper;
2835
+ componentName = 'Praxis Stepper';
2836
+ constructor(stepper) {
2837
+ super();
2838
+ this.stepper = stepper;
2839
+ }
2840
+ getCurrentConfig() {
2841
+ const current = this.stepper._config?.() ?? { steps: [] };
2842
+ return this.cloneConfig(current);
2843
+ }
2844
+ getCapabilities() {
2845
+ return STEPPER_AI_CAPABILITIES.capabilities;
2846
+ }
2847
+ getRuntimeState() {
2848
+ const cfg = this.stepper._config?.();
2849
+ const steps = cfg?.steps || [];
2850
+ return {
2851
+ stepsCount: steps.length,
2852
+ selectedIndex: this.stepper.selectedIndexComputed?.() ?? 0,
2853
+ linear: !!cfg?.linear,
2854
+ orientation: cfg?.orientation || 'horizontal',
2855
+ hasForms: steps.some((s) => !!s.form),
2856
+ };
2857
+ }
2858
+ createSnapshot() {
2859
+ return this.getCurrentConfig();
2860
+ }
2861
+ async restoreSnapshot(snapshot) {
2862
+ if (!snapshot)
2863
+ return;
2864
+ this.applyConfig(this.cloneConfig(snapshot));
2865
+ }
2866
+ async applyPatch(patch) {
2867
+ try {
2868
+ const current = this.getCurrentConfig();
2869
+ const next = this.smartMergeStepperConfig(current, patch);
2870
+ this.applyConfig(next);
2871
+ return { success: true };
2872
+ }
2873
+ catch (error) {
2874
+ const message = error instanceof Error ? error.message : 'Unknown error applying patch';
2875
+ return { success: false, error: message };
2876
+ }
2877
+ }
2878
+ applyConfig(config) {
2879
+ const apply = this.stepper.applyConfigFromAdapter;
2880
+ if (typeof apply === 'function') {
2881
+ apply.call(this.stepper, config);
2882
+ return;
2883
+ }
2884
+ this.stepper.config = config;
2885
+ }
2886
+ smartMergeStepperConfig(base, patch) {
2887
+ const result = deepMerge(base, patch);
2888
+ if (patch.steps && Array.isArray(patch.steps)) {
2889
+ const merged = this.mergeByKey(base.steps || [], patch.steps, (s) => s.id || s.label || '');
2890
+ result.steps = merged;
2891
+ }
2892
+ return result;
2893
+ }
2894
+ mergeByKey(baseArr, patchArr, keyFn) {
2895
+ const merged = baseArr.map((orig) => {
2896
+ const key = keyFn(orig);
2897
+ const match = key ? patchArr.find((p) => keyFn(p) === key) : undefined;
2898
+ return match ? deepMerge(orig, match) : orig;
2899
+ });
2900
+ patchArr.forEach((item) => {
2901
+ const key = keyFn(item);
2902
+ if (!key || !baseArr.find((o) => keyFn(o) === key)) {
2903
+ merged.push(item);
2904
+ }
2905
+ });
2906
+ return merged;
2907
+ }
2908
+ cloneConfig(config) {
2909
+ try {
2910
+ return structuredClone(config);
2911
+ }
2912
+ catch {
2913
+ return JSON.parse(JSON.stringify(config));
2914
+ }
2915
+ }
2916
+ }
2917
+
1429
2918
  class PraxisStepper {
1430
2919
  // Templates projetados
1431
2920
  stepLabelTpl;
@@ -1438,6 +2927,8 @@ class PraxisStepper {
1438
2927
  primaryCta = { label: 'Configurar Stepper', icon: 'tune', color: 'primary', action: () => this.openEditor() };
1439
2928
  secondaryCtas = [{ label: 'Adicionar etapa inicial', icon: 'add', action: () => this.addFirstStep() }];
1440
2929
  // API de entrada
2930
+ stepperId;
2931
+ componentInstanceId;
1441
2932
  set config(c) {
1442
2933
  let next = null;
1443
2934
  if (typeof c === 'string') {
@@ -1454,6 +2945,7 @@ class PraxisStepper {
1454
2945
  this._config.set(next);
1455
2946
  if (next?.selectedIndex != null)
1456
2947
  this._selectedIndex.set(next.selectedIndex);
2948
+ this.persistConfig(next);
1457
2949
  }
1458
2950
  set selectedIndexInput(i) {
1459
2951
  if (i != null)
@@ -1476,9 +2968,22 @@ class PraxisStepper {
1476
2968
  // Emissões
1477
2969
  selectedIndexChange = new EventEmitter();
1478
2970
  widgetEvent = new EventEmitter();
2971
+ stepFormReady = new EventEmitter();
2972
+ stepFormValueChange = new EventEmitter();
1479
2973
  stepperContext;
1480
2974
  settings = inject(SettingsPanelService);
2975
+ storage = inject(ASYNC_CONFIG_STORAGE);
2976
+ componentKeys = inject(ComponentKeyService);
2977
+ logger = inject(LoggerService);
2978
+ route = (() => { try {
2979
+ return inject(ActivatedRoute);
2980
+ }
2981
+ catch {
2982
+ return undefined;
2983
+ } })();
2984
+ warnedMissingId = false;
1481
2985
  animationDone = new EventEmitter();
2986
+ aiAdapter = new StepperAiAdapter(this);
1482
2987
  // Computed getters
1483
2988
  steps = computed(() => this._config()?.steps || [], ...(ngDevMode ? [{ debugName: "steps" }] : []));
1484
2989
  orientation = computed(() => this._config()?.orientation || 'horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
@@ -1500,6 +3005,21 @@ class PraxisStepper {
1500
3005
  navNextLabel = () => this.nav()?.nextLabel || 'Próximo';
1501
3006
  navPrevIcon = () => this.nav()?.prevIcon;
1502
3007
  navNextIcon = () => this.nav()?.nextIcon;
3008
+ stepperClassList = () => {
3009
+ const cfg = this._config();
3010
+ return [
3011
+ 'praxis-stepper',
3012
+ cfg?.stepperClass,
3013
+ cfg?.headerClass,
3014
+ cfg?.appearance?.themeClass,
3015
+ cfg?.appearance?.preset === 'ft-light' ? 'pdx-stepper-ft-light' : null,
3016
+ ].filter(Boolean).join(' ');
3017
+ };
3018
+ contentClassList = () => {
3019
+ const cfg = this._config();
3020
+ return ['pdx-step-content', cfg?.contentClass].filter(Boolean).join(' ');
3021
+ };
3022
+ navActionsClass = () => `pdx-step-actions ${this.navAlignClass()}`;
1503
3023
  navAlignClass = () => {
1504
3024
  const a = this.nav()?.align || 'end';
1505
3025
  switch (a) {
@@ -1562,9 +3082,19 @@ class PraxisStepper {
1562
3082
  onFormReady(stepIndex, ev) {
1563
3083
  this._formGroups.set(stepIndex, ev.formGroup);
1564
3084
  this._formValidity.set(stepIndex, ev.formGroup.valid);
3085
+ this.stepFormReady.emit({
3086
+ stepIndex,
3087
+ stepId: this.steps()[stepIndex]?.id,
3088
+ event: ev,
3089
+ });
1565
3090
  }
1566
3091
  onFormValueChange(stepIndex, ev) {
1567
3092
  this._formValidity.set(stepIndex, ev.isValid);
3093
+ this.stepFormValueChange.emit({
3094
+ stepIndex,
3095
+ stepId: this.steps()[stepIndex]?.id,
3096
+ event: ev,
3097
+ });
1568
3098
  }
1569
3099
  formGroupFor(i) {
1570
3100
  return this._formGroups.get(i);
@@ -1586,13 +3116,15 @@ class PraxisStepper {
1586
3116
  }
1587
3117
  isStepEmpty(step) {
1588
3118
  const hasForm = !!step.form;
3119
+ const hasWidgetsBefore = Array.isArray(step.widgetsBeforeForm) && step.widgetsBeforeForm.length > 0;
1589
3120
  const hasWidgets = Array.isArray(step.widgets) && step.widgets.length > 0;
1590
- return !hasForm && !hasWidgets;
3121
+ return !hasForm && !hasWidgets && !hasWidgetsBefore;
1591
3122
  }
1592
3123
  openEditor() {
1593
3124
  const cfg = this._config() || { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
3125
+ const key = this.storageKey() || this.stepperId || 'default';
1594
3126
  const ref = this.settings.open({
1595
- id: 'praxis-stepper-editor',
3127
+ id: `praxis-stepper-editor:${key}`,
1596
3128
  title: 'Configurar Stepper',
1597
3129
  content: { component: PraxisStepperConfigEditor, inputs: { config: cfg } },
1598
3130
  });
@@ -1605,11 +3137,19 @@ class PraxisStepper {
1605
3137
  // Clamp selection after changes
1606
3138
  const sel = typeof cloned.selectedIndex === 'number' ? cloned.selectedIndex : this._selectedIndex();
1607
3139
  this._selectedIndex.set(this.clampIndex(sel));
3140
+ this.persistConfig(cloned);
1608
3141
  }
1609
3142
  };
1610
3143
  ref.applied$.subscribe(apply);
1611
3144
  ref.saved$.subscribe(apply);
1612
3145
  }
3146
+ applyConfigFromAdapter(next) {
3147
+ const cloned = JSON.parse(JSON.stringify(next));
3148
+ this._config.set(cloned);
3149
+ const sel = typeof cloned.selectedIndex === 'number' ? cloned.selectedIndex : this._selectedIndex();
3150
+ this._selectedIndex.set(this.clampIndex(sel));
3151
+ this.persistConfig(cloned);
3152
+ }
1613
3153
  // CTA helpers
1614
3154
  addFirstStep() {
1615
3155
  const current = this._config() || { steps: [], orientation: 'horizontal', headerPosition: 'top', linear: false };
@@ -1624,11 +3164,17 @@ class PraxisStepper {
1624
3164
  this._config.set(next);
1625
3165
  // Seleciona a primeira etapa
1626
3166
  this._selectedIndex.set(0);
3167
+ this.persistConfig(next);
1627
3168
  }
1628
3169
  // Navegação com validação remota opcional
1629
3170
  async onNext(i) {
1630
3171
  // Em modo linear, bloquear quando inválido
1631
3172
  if (this.linear() && this._formValidity.get(i) === false) {
3173
+ const fg = this._formGroups.get(i);
3174
+ if (fg) {
3175
+ fg.markAllAsTouched();
3176
+ fg.updateValueAndValidity({ emitEvent: true });
3177
+ }
1632
3178
  return;
1633
3179
  }
1634
3180
  const step = this.steps()[i];
@@ -1667,8 +3213,63 @@ class PraxisStepper {
1667
3213
  }
1668
3214
  fg.updateValueAndValidity({ emitEvent: true });
1669
3215
  }
3216
+ persistConfig(config) {
3217
+ const key = this.storageKey();
3218
+ if (!key || !config)
3219
+ return;
3220
+ this.storage.saveConfig(key, config).pipe(take(1)).subscribe({ error: () => { } });
3221
+ }
3222
+ storageKey() {
3223
+ const id = this.componentKeyId();
3224
+ return id ? `stepper-config:${id}` : null;
3225
+ }
3226
+ componentKeyId() {
3227
+ const key = this.componentKeys.buildComponentId({
3228
+ componentType: 'praxis-stepper',
3229
+ componentId: this.stepperId,
3230
+ instanceKey: this.componentInstanceId,
3231
+ componentRef: this,
3232
+ route: this.route,
3233
+ requireComponentId: true,
3234
+ });
3235
+ if (!key)
3236
+ this.warnMissingId();
3237
+ return key;
3238
+ }
3239
+ warnMissingId() {
3240
+ if (this.warnedMissingId)
3241
+ return;
3242
+ this.warnedMissingId = true;
3243
+ this.logger.warnOnce('[PraxisStepper] stepperId is required for config persistence.', {
3244
+ context: {
3245
+ lib: 'praxis-stepper',
3246
+ component: 'PraxisStepper',
3247
+ },
3248
+ data: {
3249
+ stepperId: this.stepperId,
3250
+ componentInstanceId: this.componentInstanceId,
3251
+ },
3252
+ dedupeKey: 'praxis-stepper:missing-stepper-id',
3253
+ });
3254
+ }
3255
+ ngOnInit() {
3256
+ const key = this.storageKey();
3257
+ if (!key)
3258
+ return;
3259
+ this.storage.loadConfig(key).pipe(take(1)).subscribe((stored) => {
3260
+ if (!stored)
3261
+ return;
3262
+ const cloned = JSON.parse(JSON.stringify(stored));
3263
+ this._config.set(cloned);
3264
+ const sel = typeof cloned.selectedIndex === 'number' ? cloned.selectedIndex : this._selectedIndex();
3265
+ this._selectedIndex.set(this.clampIndex(sel));
3266
+ });
3267
+ }
1670
3268
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
1671
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisStepper, isStandalone: true, selector: "praxis-stepper", inputs: { config: "config", selectedIndexInput: "selectedIndexInput", selectedIndex: "selectedIndex", disableRippleInput: "disableRippleInput", editModeEnabled: "editModeEnabled", labelPosition: "labelPosition", color: "color", serverValidate: "serverValidate", stepperContext: "stepperContext" }, outputs: { selectedIndexChange: "selectedIndexChange", widgetEvent: "widgetEvent", animationDone: "animationDone", selectionChange: "selectionChange" }, queries: [{ propertyName: "stepLabelTpl", first: true, predicate: ["stepLabelTpl"], descendants: true, read: TemplateRef }], ngImport: i0, template: `
3269
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisStepper, isStandalone: true, selector: "praxis-stepper", inputs: { stepperId: "stepperId", componentInstanceId: "componentInstanceId", config: "config", selectedIndexInput: "selectedIndexInput", selectedIndex: "selectedIndex", disableRippleInput: "disableRippleInput", editModeEnabled: "editModeEnabled", 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: `
3270
+ <div class="stepper-ai-assistant" *ngIf="editModeEnabled">
3271
+ <praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
3272
+ </div>
1672
3273
  <ng-container *ngIf="steps().length > 0; else emptyState">
1673
3274
  <mat-stepper
1674
3275
  [linear]="linear()"
@@ -1681,8 +3282,7 @@ class PraxisStepper {
1681
3282
  [selectedIndex]="selectedIndexComputed()"
1682
3283
  (selectionChange)="onSelectionChange($event)"
1683
3284
  (animationDone)="onAnimationDone()"
1684
- class="praxis-stepper"
1685
- [ngClass]="[densityClass(), _config()?.stepperClass || '']"
3285
+ [class]="stepperClassList()"
1686
3286
  >
1687
3287
  <!-- Projeção de ícones customizados do header: <ng-template matStepperIcon="done"> ... </ng-template> -->
1688
3288
  <ng-content></ng-content>
@@ -1719,7 +3319,13 @@ class PraxisStepper {
1719
3319
  ></ng-container>
1720
3320
  <ng-template #plainLabel>{{ step.label }}</ng-template>
1721
3321
  </ng-template>
1722
- <div class="pdx-step-content" [ngClass]="_config()?.contentClass || ''">
3322
+ <div [class]="contentClassList()">
3323
+ <ng-container *ngFor="let wd of step.widgetsBeforeForm || []"
3324
+ [dynamicWidgetLoader]="wd"
3325
+ [context]="stepperContext"
3326
+ [strictValidation]="true"
3327
+ [autoWireOutputs]="true"
3328
+ (widgetEvent)="onChildWidgetEvent(i, wd, $event)"></ng-container>
1723
3329
  <praxis-dynamic-form *ngIf="step.form as f"
1724
3330
  [resourcePath]="f.resourcePath"
1725
3331
  [resourceId]="$any(f.resourceId)"
@@ -1746,7 +3352,7 @@ class PraxisStepper {
1746
3352
  ></praxis-empty-state-card>
1747
3353
  </ng-container>
1748
3354
  </div>
1749
- <div class="pdx-step-actions" *ngIf="navVisible()" [ngClass]="navAlignClass()">
3355
+ <div *ngIf="navVisible()" [class]="navActionsClass()">
1750
3356
  <!-- PREV button (hidden on first step) -->
1751
3357
  <ng-container *ngIf="selectedIndexComputed() > 0">
1752
3358
  <ng-container [ngSwitch]="navVariant()">
@@ -1811,11 +3417,16 @@ class PraxisStepper {
1811
3417
  >
1812
3418
  <mat-icon fontIcon="edit"></mat-icon>
1813
3419
  </button>
1814
- `, isInline: true, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%}:host(.density-compact) .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) .mat-step-header{min-height:44px}.pdx-step-content{padding:8px 0}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}.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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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", "mode", "config", "schemaSource", "editModeEnabled", "formId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "editModeEnabledChange", "customAction", "actionConfirmation", "schemaStatusChange"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3420
+ `, 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:hover{background:var(--md-sys-color-primary-container)}::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}::ng-deep .pdx-stepper-ft-light .mat-horizontal-stepper-header-container{margin-bottom:14px;justify-content:flex-start;align-items:center}::ng-deep .pdx-stepper-ft-light .mat-step-header{min-height:28px;font-size:.75rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .pdx-stepper-ft-light .mat-step-label.mat-step-label-active,::ng-deep .pdx-stepper-ft-light .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .pdx-stepper-ft-light .mat-step-icon{height:16px;width:16px;font-size:9px;background:transparent;border:1px solid var(--md-sys-color-outline-variant);color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .pdx-stepper-ft-light .mat-step-icon .mat-icon{display:none}::ng-deep .pdx-stepper-ft-light .mat-step-icon-content{font-weight:600;font-size:9px;line-height:1}::ng-deep .pdx-stepper-ft-light .mat-step-icon-state-done,::ng-deep .pdx-stepper-ft-light .mat-step-icon-selected{background:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));border-color:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));color:var(--praxis-wizard-accent-on, var(--md-sys-color-on-primary, #ffffff))}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant);border-top-width:1px;margin:0 8px;flex:1 1 0}::ng-deep .pdx-stepper-ft-light .mat-step-header{padding:0 6px;flex:0 0 auto}::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-keyboard-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-program-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-mouse-focused{outline:none;box-shadow:none;background:transparent}::ng-deep .pdx-stepper-ft-light .mat-step-header:hover{background:transparent}::ng-deep .ft-stepper{background:transparent}::ng-deep .ft-stepper .mat-horizontal-stepper-header-container{margin-bottom:16px}::ng-deep .ft-stepper .mat-step-header{font-size:.8rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .ft-stepper .mat-step-label.mat-step-label-active,::ng-deep .ft-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .ft-stepper .mat-step-icon{height:22px;width:22px;font-size:11px;background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface));border:2px solid var(--md-sys-color-outline-variant);color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .ft-stepper .mat-step-icon-state-done,::ng-deep .ft-stepper .mat-step-icon-selected{background:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));border-color:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));color:var(--praxis-wizard-accent-on, var(--md-sys-color-on-primary, #ffffff))}::ng-deep .ft-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}.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", "mode", "config", "schemaSource", "editModeEnabled", "formId", "componentInstanceId", "layout", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "editModeEnabledChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent"], 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1815
3421
  }
1816
3422
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisStepper, decorators: [{
1817
3423
  type: Component,
1818
- args: [{ selector: 'praxis-stepper', standalone: true, imports: [CommonModule, ReactiveFormsModule, MatStepperModule, MatButtonModule, MatIconModule, PraxisIconDirective, PraxisDynamicForm, DynamicWidgetLoaderDirective, EmptyStateCardComponent], template: `
3424
+ args: [{ selector: 'praxis-stepper', standalone: true, imports: [CommonModule, ReactiveFormsModule, MatStepperModule, MatButtonModule, MatIconModule, PraxisIconDirective, PraxisDynamicForm, DynamicWidgetLoaderDirective, EmptyStateCardComponent, PraxisAiAssistantComponent], host: {
3425
+ '[class]': 'densityClass()'
3426
+ }, template: `
3427
+ <div class="stepper-ai-assistant" *ngIf="editModeEnabled">
3428
+ <praxis-ai-assistant [adapter]="aiAdapter"></praxis-ai-assistant>
3429
+ </div>
1819
3430
  <ng-container *ngIf="steps().length > 0; else emptyState">
1820
3431
  <mat-stepper
1821
3432
  [linear]="linear()"
@@ -1828,8 +3439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1828
3439
  [selectedIndex]="selectedIndexComputed()"
1829
3440
  (selectionChange)="onSelectionChange($event)"
1830
3441
  (animationDone)="onAnimationDone()"
1831
- class="praxis-stepper"
1832
- [ngClass]="[densityClass(), _config()?.stepperClass || '']"
3442
+ [class]="stepperClassList()"
1833
3443
  >
1834
3444
  <!-- Projeção de ícones customizados do header: <ng-template matStepperIcon="done"> ... </ng-template> -->
1835
3445
  <ng-content></ng-content>
@@ -1866,7 +3476,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1866
3476
  ></ng-container>
1867
3477
  <ng-template #plainLabel>{{ step.label }}</ng-template>
1868
3478
  </ng-template>
1869
- <div class="pdx-step-content" [ngClass]="_config()?.contentClass || ''">
3479
+ <div [class]="contentClassList()">
3480
+ <ng-container *ngFor="let wd of step.widgetsBeforeForm || []"
3481
+ [dynamicWidgetLoader]="wd"
3482
+ [context]="stepperContext"
3483
+ [strictValidation]="true"
3484
+ [autoWireOutputs]="true"
3485
+ (widgetEvent)="onChildWidgetEvent(i, wd, $event)"></ng-container>
1870
3486
  <praxis-dynamic-form *ngIf="step.form as f"
1871
3487
  [resourcePath]="f.resourcePath"
1872
3488
  [resourceId]="$any(f.resourceId)"
@@ -1893,7 +3509,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1893
3509
  ></praxis-empty-state-card>
1894
3510
  </ng-container>
1895
3511
  </div>
1896
- <div class="pdx-step-actions" *ngIf="navVisible()" [ngClass]="navAlignClass()">
3512
+ <div *ngIf="navVisible()" [class]="navActionsClass()">
1897
3513
  <!-- PREV button (hidden on first step) -->
1898
3514
  <ng-container *ngIf="selectedIndexComputed() > 0">
1899
3515
  <ng-container [ngSwitch]="navVariant()">
@@ -1958,10 +3574,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1958
3574
  >
1959
3575
  <mat-icon fontIcon="edit"></mat-icon>
1960
3576
  </button>
1961
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;position:relative}.praxis-stepper{width:100%}:host(.density-compact) .mat-step-header{min-height:36px}:host(.density-compact) .pdx-step-actions{padding-top:4px;gap:6px}:host(.density-comfortable) .mat-step-header{min-height:44px}.pdx-step-content{padding:8px 0}.pdx-step-actions{display:flex;gap:8px;padding-top:8px}.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}\n"] }]
3577
+ `, 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:hover{background:var(--md-sys-color-primary-container)}::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}::ng-deep .pdx-stepper-ft-light .mat-horizontal-stepper-header-container{margin-bottom:14px;justify-content:flex-start;align-items:center}::ng-deep .pdx-stepper-ft-light .mat-step-header{min-height:28px;font-size:.75rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .pdx-stepper-ft-light .mat-step-label.mat-step-label-active,::ng-deep .pdx-stepper-ft-light .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .pdx-stepper-ft-light .mat-step-icon{height:16px;width:16px;font-size:9px;background:transparent;border:1px solid var(--md-sys-color-outline-variant);color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .pdx-stepper-ft-light .mat-step-icon .mat-icon{display:none}::ng-deep .pdx-stepper-ft-light .mat-step-icon-content{font-weight:600;font-size:9px;line-height:1}::ng-deep .pdx-stepper-ft-light .mat-step-icon-state-done,::ng-deep .pdx-stepper-ft-light .mat-step-icon-selected{background:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));border-color:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));color:var(--praxis-wizard-accent-on, var(--md-sys-color-on-primary, #ffffff))}::ng-deep .pdx-stepper-ft-light .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant);border-top-width:1px;margin:0 8px;flex:1 1 0}::ng-deep .pdx-stepper-ft-light .mat-step-header{padding:0 6px;flex:0 0 auto}::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-keyboard-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-program-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-focused,::ng-deep .pdx-stepper-ft-light .mat-step-header.cdk-mouse-focused{outline:none;box-shadow:none;background:transparent}::ng-deep .pdx-stepper-ft-light .mat-step-header:hover{background:transparent}::ng-deep .ft-stepper{background:transparent}::ng-deep .ft-stepper .mat-horizontal-stepper-header-container{margin-bottom:16px}::ng-deep .ft-stepper .mat-step-header{font-size:.8rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .ft-stepper .mat-step-label.mat-step-label-active,::ng-deep .ft-stepper .mat-step-label.mat-step-label-selected{color:var(--md-sys-color-on-surface);font-weight:600}::ng-deep .ft-stepper .mat-step-icon{height:22px;width:22px;font-size:11px;background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface));border:2px solid var(--md-sys-color-outline-variant);color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}::ng-deep .ft-stepper .mat-step-icon-state-done,::ng-deep .ft-stepper .mat-step-icon-selected{background:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));border-color:var(--praxis-wizard-accent, var(--md-sys-color-primary, currentColor));color:var(--praxis-wizard-accent-on, var(--md-sys-color-on-primary, #ffffff))}::ng-deep .ft-stepper .mat-stepper-horizontal-line{border-top-color:var(--md-sys-color-outline-variant)}.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"] }]
1962
3578
  }], propDecorators: { stepLabelTpl: [{
1963
3579
  type: ContentChild,
1964
3580
  args: ['stepLabelTpl', { read: TemplateRef }]
3581
+ }], stepperId: [{
3582
+ type: Input,
3583
+ args: [{ required: true }]
3584
+ }], componentInstanceId: [{
3585
+ type: Input
1965
3586
  }], config: [{
1966
3587
  type: Input
1967
3588
  }], selectedIndexInput: [{
@@ -1982,6 +3603,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1982
3603
  type: Output
1983
3604
  }], widgetEvent: [{
1984
3605
  type: Output
3606
+ }], stepFormReady: [{
3607
+ type: Output
3608
+ }], stepFormValueChange: [{
3609
+ type: Output
1985
3610
  }], stepperContext: [{
1986
3611
  type: Input
1987
3612
  }], animationDone: [{
@@ -1990,6 +3615,178 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
1990
3615
  type: Output
1991
3616
  }] } });
1992
3617
 
3618
+ class PraxisWizardBenefitsGridComponent {
3619
+ blockId;
3620
+ title;
3621
+ items = [];
3622
+ columns;
3623
+ boxed = true;
3624
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardBenefitsGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3625
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PraxisWizardBenefitsGridComponent, isStandalone: true, selector: "praxis-wizard-benefits-grid", inputs: { blockId: "blockId", title: "title", items: "items", columns: "columns", boxed: "boxed" }, host: { properties: { "attr.data-block-id": "blockId || null" } }, ngImport: i0, template: `
3626
+ <section class="pwx-benefits">
3627
+ @if (title) {
3628
+ <h3 class="pwx-benefits-title">{{ title }}</h3>
3629
+ }
3630
+ <div class="pwx-benefits-grid" [class.is-boxed]="boxed" [style.--pwx-columns]="columns || 4">
3631
+ <div class="pwx-benefit" *ngFor="let item of items">
3632
+ <div class="pwx-benefit-icon" *ngIf="item.icon">
3633
+ <mat-icon [fontIcon]="item.icon"></mat-icon>
3634
+ </div>
3635
+ <div class="pwx-benefit-body">
3636
+ <div class="pwx-benefit-title">{{ item.title }}</div>
3637
+ <div class="pwx-benefit-text" *ngIf="item.text">{{ item.text }}</div>
3638
+ </div>
3639
+ </div>
3640
+ </div>
3641
+ </section>
3642
+ `, 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:14px 18px}.pwx-benefits-grid.is-boxed{padding:10px 12px;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}.pwx-benefit-icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;color:var(--praxis-wizard-accent, var(--md-sys-color-primary))}.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 });
3643
+ }
3644
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardBenefitsGridComponent, decorators: [{
3645
+ type: Component,
3646
+ args: [{ selector: 'praxis-wizard-benefits-grid', standalone: true, host: {
3647
+ '[attr.data-block-id]': 'blockId || null',
3648
+ }, imports: [CommonModule, MatIconModule], template: `
3649
+ <section class="pwx-benefits">
3650
+ @if (title) {
3651
+ <h3 class="pwx-benefits-title">{{ title }}</h3>
3652
+ }
3653
+ <div class="pwx-benefits-grid" [class.is-boxed]="boxed" [style.--pwx-columns]="columns || 4">
3654
+ <div class="pwx-benefit" *ngFor="let item of items">
3655
+ <div class="pwx-benefit-icon" *ngIf="item.icon">
3656
+ <mat-icon [fontIcon]="item.icon"></mat-icon>
3657
+ </div>
3658
+ <div class="pwx-benefit-body">
3659
+ <div class="pwx-benefit-title">{{ item.title }}</div>
3660
+ <div class="pwx-benefit-text" *ngIf="item.text">{{ item.text }}</div>
3661
+ </div>
3662
+ </div>
3663
+ </div>
3664
+ </section>
3665
+ `, changeDetection: ChangeDetectionStrategy.OnPush, 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:14px 18px}.pwx-benefits-grid.is-boxed{padding:10px 12px;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}.pwx-benefit-icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;color:var(--praxis-wizard-accent, var(--md-sys-color-primary))}.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"] }]
3666
+ }], propDecorators: { blockId: [{
3667
+ type: Input
3668
+ }], title: [{
3669
+ type: Input
3670
+ }], items: [{
3671
+ type: Input
3672
+ }], columns: [{
3673
+ type: Input
3674
+ }], boxed: [{
3675
+ type: Input
3676
+ }] } });
3677
+
3678
+ class PraxisWizardContentBlockComponent {
3679
+ blockId;
3680
+ title;
3681
+ subtitle;
3682
+ text;
3683
+ caption;
3684
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardContentBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3685
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PraxisWizardContentBlockComponent, isStandalone: true, selector: "praxis-wizard-content-block", inputs: { blockId: "blockId", title: "title", subtitle: "subtitle", text: "text", caption: "caption" }, host: { properties: { "attr.data-block-id": "blockId || null" } }, ngImport: i0, template: `
3686
+ <section class="pwx-content">
3687
+ @if (title) {
3688
+ <h3 class="pwx-content-title">{{ title }}</h3>
3689
+ }
3690
+ @if (subtitle) {
3691
+ <div class="pwx-content-subtitle">{{ subtitle }}</div>
3692
+ }
3693
+ @if (text) {
3694
+ <p class="pwx-content-text">{{ text }}</p>
3695
+ }
3696
+ @if (caption) {
3697
+ <div class="pwx-content-caption">{{ caption }}</div>
3698
+ }
3699
+ </section>
3700
+ `, isInline: true, styles: [":host{display:block}.pwx-content{display:flex;flex-direction:column;gap:6px}.pwx-content-title{margin:0;font-size:1.05rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pwx-content-subtitle{font-size:.95rem;color:var(--md-sys-color-on-surface)}.pwx-content-text{margin:0;font-size:.88rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}.pwx-content-caption{font-size:.78rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3701
+ }
3702
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardContentBlockComponent, decorators: [{
3703
+ type: Component,
3704
+ args: [{ selector: 'praxis-wizard-content-block', standalone: true, host: {
3705
+ '[attr.data-block-id]': 'blockId || null',
3706
+ }, imports: [CommonModule], template: `
3707
+ <section class="pwx-content">
3708
+ @if (title) {
3709
+ <h3 class="pwx-content-title">{{ title }}</h3>
3710
+ }
3711
+ @if (subtitle) {
3712
+ <div class="pwx-content-subtitle">{{ subtitle }}</div>
3713
+ }
3714
+ @if (text) {
3715
+ <p class="pwx-content-text">{{ text }}</p>
3716
+ }
3717
+ @if (caption) {
3718
+ <div class="pwx-content-caption">{{ caption }}</div>
3719
+ }
3720
+ </section>
3721
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.pwx-content{display:flex;flex-direction:column;gap:6px}.pwx-content-title{margin:0;font-size:1.05rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pwx-content-subtitle{font-size:.95rem;color:var(--md-sys-color-on-surface)}.pwx-content-text{margin:0;font-size:.88rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}.pwx-content-caption{font-size:.78rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}\n"] }]
3722
+ }], propDecorators: { blockId: [{
3723
+ type: Input
3724
+ }], title: [{
3725
+ type: Input
3726
+ }], subtitle: [{
3727
+ type: Input
3728
+ }], text: [{
3729
+ type: Input
3730
+ }], caption: [{
3731
+ type: Input
3732
+ }] } });
3733
+
3734
+ class PraxisWizardInlineNoticeComponent {
3735
+ blockId;
3736
+ text = '';
3737
+ tone = 'neutral';
3738
+ get toneClass() {
3739
+ return this.tone !== 'neutral' ? this.tone : '';
3740
+ }
3741
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardInlineNoticeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3742
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisWizardInlineNoticeComponent, isStandalone: true, selector: "praxis-wizard-inline-notice", inputs: { blockId: "blockId", text: "text", tone: "tone" }, host: { properties: { "attr.data-block-id": "blockId || null" } }, ngImport: i0, template: `
3743
+ <div class="pwx-inline" [ngClass]="toneClass">
3744
+ {{ text }}
3745
+ </div>
3746
+ `, isInline: true, styles: [":host{display:block}.pwx-inline{font-size:.82rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));line-height:1.4}.pwx-inline.info{color:var(--md-sys-color-on-surface)}.pwx-inline.warning{color:var(--md-sys-color-error)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3747
+ }
3748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardInlineNoticeComponent, decorators: [{
3749
+ type: Component,
3750
+ args: [{ selector: 'praxis-wizard-inline-notice', standalone: true, host: {
3751
+ '[attr.data-block-id]': 'blockId || null',
3752
+ }, imports: [CommonModule], template: `
3753
+ <div class="pwx-inline" [ngClass]="toneClass">
3754
+ {{ text }}
3755
+ </div>
3756
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.pwx-inline{font-size:.82rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));line-height:1.4}.pwx-inline.info{color:var(--md-sys-color-on-surface)}.pwx-inline.warning{color:var(--md-sys-color-error)}\n"] }]
3757
+ }], propDecorators: { blockId: [{
3758
+ type: Input
3759
+ }], text: [{
3760
+ type: Input
3761
+ }], tone: [{
3762
+ type: Input
3763
+ }] } });
3764
+
3765
+ class PraxisWizardDividerComponent {
3766
+ blockId;
3767
+ label;
3768
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardDividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3769
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisWizardDividerComponent, isStandalone: true, selector: "praxis-wizard-divider", inputs: { blockId: "blockId", label: "label" }, host: { properties: { "attr.data-block-id": "blockId || null" } }, ngImport: i0, template: `
3770
+ <div class="pwx-divider">
3771
+ <span *ngIf="label" class="pwx-divider-label">{{ label }}</span>
3772
+ </div>
3773
+ `, isInline: true, styles: [":host{display:block}.pwx-divider{position:relative;height:1px;background:var(--praxis-wizard-divider, var(--md-sys-color-outline-variant));margin:16px 0}.pwx-divider-label{position:absolute;top:-.65rem;left:50%;transform:translate(-50%);padding:0 8px;font-size:.75rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3774
+ }
3775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardDividerComponent, decorators: [{
3776
+ type: Component,
3777
+ args: [{ selector: 'praxis-wizard-divider', standalone: true, host: {
3778
+ '[attr.data-block-id]': 'blockId || null',
3779
+ }, imports: [CommonModule], template: `
3780
+ <div class="pwx-divider">
3781
+ <span *ngIf="label" class="pwx-divider-label">{{ label }}</span>
3782
+ </div>
3783
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.pwx-divider{position:relative;height:1px;background:var(--praxis-wizard-divider, var(--md-sys-color-outline-variant));margin:16px 0}.pwx-divider-label{position:absolute;top:-.65rem;left:50%;transform:translate(-50%);padding:0 8px;font-size:.75rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant));background:var(--praxis-wizard-card-bg, var(--md-sys-color-surface))}\n"] }]
3784
+ }], propDecorators: { blockId: [{
3785
+ type: Input
3786
+ }], label: [{
3787
+ type: Input
3788
+ }] } });
3789
+
1993
3790
  const PRAXIS_STEPPER_COMPONENT_METADATA = {
1994
3791
  id: 'praxis-stepper',
1995
3792
  selector: 'praxis-stepper',
@@ -1998,10 +3795,13 @@ const PRAXIS_STEPPER_COMPONENT_METADATA = {
1998
3795
  description: 'Stepper configurável (horizontal/vertical/linear) com passos e conteúdo dinâmico.',
1999
3796
  icon: 'format_list_numbered',
2000
3797
  inputs: [
3798
+ { name: 'stepperId', type: 'string', label: 'ID do Stepper', description: 'Identificador para persistência (obrigatório)' },
3799
+ { name: 'componentInstanceId', type: 'string', label: 'ID da instância', description: 'Identificador opcional para múltiplas instâncias na mesma rota' },
2001
3800
  { name: 'config', type: 'StepperMetadata', label: 'Configuração', description: 'Configuração JSON com passos e opções' },
2002
3801
  { name: 'selectedIndex', type: 'number', label: '[(selectedIndex)] Índice selecionado' },
2003
3802
  { name: 'selectedIndexInput', type: 'number', label: 'Índice selecionado (legacy)' },
2004
3803
  { name: 'disableRippleInput', type: 'boolean', default: false, label: 'Desabilitar ripple' },
3804
+ { name: 'editModeEnabled', type: 'boolean', default: false, label: 'Modo de edição', description: 'Exibe controles de edição e assistente AI no runtime' },
2005
3805
  { name: 'labelPosition', type: "'bottom' | 'end'", label: 'Posição do rótulo (horizontal)' },
2006
3806
  { name: 'color', type: 'ThemePalette', label: 'Cor (M2)' },
2007
3807
  { name: 'appearance', type: '{ themeClass?: string; tokens?: Record<string,string>; icons?: { number?: string; done?: string; edit?: string; error?: string }; iconsSet?: string }', label: 'Aparência (tokens, themeClass, ícones, conjunto)' },
@@ -2010,6 +3810,7 @@ const PRAXIS_STEPPER_COMPONENT_METADATA = {
2010
3810
  { name: 'stepperClass', type: 'string', label: 'Classe CSS (stepper)' },
2011
3811
  { name: 'headerClass', type: 'string', label: 'Classe CSS (header)' },
2012
3812
  { name: 'contentClass', type: 'string', label: 'Classe CSS (conteúdo)' },
3813
+ { name: 'stepperContext', type: 'Record<string, any>', label: 'Contexto', description: 'Contexto compartilhado para widgets internos' },
2013
3814
  { name: 'navigation', type: "{ visible?: boolean; prevLabel?: string; nextLabel?: string; prevIcon?: string; nextIcon?: string; variant?: 'basic'|'flat'|'stroked'|'raised'; color?: ThemePalette; align?: 'start'|'center'|'end'|'space-between' }", label: 'Navegação (botões)'
2014
3815
  },
2015
3816
  ],
@@ -2018,22 +3819,998 @@ const PRAXIS_STEPPER_COMPONENT_METADATA = {
2018
3819
  { name: 'selectedIndexChange', type: 'number', label: 'Índice selecionado (change)' },
2019
3820
  { name: 'animationDone', type: 'void', label: 'Animação concluída' },
2020
3821
  { name: 'widgetEvent', type: '{ stepId?: string; stepIndex?: number; sourceId: string; output?: string; payload?: any }', label: 'Evento interno' },
3822
+ { name: 'stepFormReady', type: '{ stepId?: string; stepIndex: number; event: FormReadyEvent }', label: 'Form ready (por etapa)' },
3823
+ { name: 'stepFormValueChange', type: '{ stepId?: string; stepIndex: number; event: FormValueChangeEvent }', label: 'Form value change (por etapa)' },
3824
+ ],
3825
+ actions: [
3826
+ {
3827
+ id: 'select-step',
3828
+ label: 'Selecionar etapa',
3829
+ icon: 'flag',
3830
+ description: 'Emite alteração do índice selecionado',
3831
+ emit: 'selectedIndexChange',
3832
+ payloadSchema: {
3833
+ type: 'number',
3834
+ example: 0,
3835
+ },
3836
+ scope: 'any',
3837
+ },
3838
+ {
3839
+ id: 'step-change',
3840
+ label: 'Troca de etapa',
3841
+ icon: 'swap_vert',
3842
+ description: 'Emite evento ao trocar de etapa',
3843
+ emit: 'selectionChange',
3844
+ payloadSchema: {
3845
+ type: 'object',
3846
+ properties: {
3847
+ selectedIndex: { type: 'number', description: 'Índice selecionado' },
3848
+ previouslySelectedIndex: { type: 'number', description: 'Índice anterior' },
3849
+ },
3850
+ required: ['selectedIndex'],
3851
+ example: { selectedIndex: 1, previouslySelectedIndex: 0 },
3852
+ },
3853
+ scope: 'any',
3854
+ },
2021
3855
  ],
2022
3856
  tags: ['widget', 'container', 'stepper', 'configurable'],
2023
3857
  lib: '@praxisui/stepper',
2024
3858
  layoutHints: { recommendedCols: 8, recommendedRows: 6, minCols: 4, minRows: 4 },
2025
3859
  };
3860
+ const PRAXIS_WIZARD_BENEFITS_METADATA = {
3861
+ id: 'praxis-wizard-benefits',
3862
+ selector: 'praxis-wizard-benefits-grid',
3863
+ component: PraxisWizardBenefitsGridComponent,
3864
+ friendlyName: 'Wizard Benefits Grid',
3865
+ description: 'Grid de benefícios com ícones/títulos/texto (uso editorial).',
3866
+ icon: 'view_module',
3867
+ inputs: [
3868
+ { name: 'blockId', type: 'string', label: 'ID estável (avançado)', description: 'Chave estável para telemetria/e2e.' },
3869
+ { name: 'title', type: 'string', label: 'Título' },
3870
+ { name: 'items', type: 'Array<{ icon?: string; title: string; text?: string }>', label: 'Itens' },
3871
+ { name: 'columns', type: 'number', label: 'Colunas' },
3872
+ { name: 'boxed', type: 'boolean', label: 'Boxed' },
3873
+ ],
3874
+ outputs: [],
3875
+ tags: ['widget', 'wizard', 'content', 'benefits'],
3876
+ lib: '@praxisui/stepper',
3877
+ };
3878
+ const PRAXIS_WIZARD_CONTENT_METADATA = {
3879
+ id: 'praxis-wizard-content',
3880
+ selector: 'praxis-wizard-content-block',
3881
+ component: PraxisWizardContentBlockComponent,
3882
+ friendlyName: 'Wizard Content Block',
3883
+ description: 'Bloco editorial com título/subtítulo/texto.',
3884
+ icon: 'article',
3885
+ inputs: [
3886
+ { name: 'blockId', type: 'string', label: 'ID estável (avançado)', description: 'Chave estável para telemetria/e2e.' },
3887
+ { name: 'title', type: 'string', label: 'Título' },
3888
+ { name: 'subtitle', type: 'string', label: 'Subtítulo' },
3889
+ { name: 'text', type: 'string', label: 'Texto' },
3890
+ { name: 'caption', type: 'string', label: 'Legenda' },
3891
+ ],
3892
+ outputs: [],
3893
+ tags: ['widget', 'wizard', 'content'],
3894
+ lib: '@praxisui/stepper',
3895
+ };
3896
+ const PRAXIS_WIZARD_NOTICE_METADATA = {
3897
+ id: 'praxis-wizard-inline-notice',
3898
+ selector: 'praxis-wizard-inline-notice',
3899
+ component: PraxisWizardInlineNoticeComponent,
3900
+ friendlyName: 'Wizard Inline Notice',
3901
+ description: 'Texto legal/nota inline para wizards.',
3902
+ icon: 'info',
3903
+ inputs: [
3904
+ { name: 'blockId', type: 'string', label: 'ID estável (avançado)', description: 'Chave estável para telemetria/e2e.' },
3905
+ { name: 'text', type: 'string', label: 'Texto' },
3906
+ { name: 'tone', type: "'neutral' | 'info' | 'warning'", label: 'Tom' },
3907
+ ],
3908
+ outputs: [],
3909
+ tags: ['widget', 'wizard', 'notice'],
3910
+ lib: '@praxisui/stepper',
3911
+ };
3912
+ const PRAXIS_WIZARD_DIVIDER_METADATA = {
3913
+ id: 'praxis-wizard-divider',
3914
+ selector: 'praxis-wizard-divider',
3915
+ component: PraxisWizardDividerComponent,
3916
+ friendlyName: 'Wizard Divider',
3917
+ description: 'Separador visual para fluxo.',
3918
+ icon: 'horizontal_rule',
3919
+ inputs: [
3920
+ { name: 'blockId', type: 'string', label: 'ID estável (avançado)', description: 'Chave estável para telemetria/e2e.' },
3921
+ { name: 'label', type: 'string', label: 'Rótulo' },
3922
+ ],
3923
+ outputs: [],
3924
+ tags: ['widget', 'wizard', 'divider'],
3925
+ lib: '@praxisui/stepper',
3926
+ };
2026
3927
  function providePraxisStepperMetadata() {
2027
3928
  return {
2028
3929
  provide: ENVIRONMENT_INITIALIZER,
2029
3930
  multi: true,
2030
3931
  useFactory: (registry) => () => {
2031
3932
  registry.register(PRAXIS_STEPPER_COMPONENT_METADATA);
3933
+ registry.register(PRAXIS_WIZARD_BENEFITS_METADATA);
3934
+ registry.register(PRAXIS_WIZARD_CONTENT_METADATA);
3935
+ registry.register(PRAXIS_WIZARD_NOTICE_METADATA);
3936
+ registry.register(PRAXIS_WIZARD_DIVIDER_METADATA);
2032
3937
  },
2033
3938
  deps: [ComponentMetadataRegistry],
2034
3939
  };
2035
3940
  }
2036
3941
 
3942
+ const FT_WIZARD_JSON = `{
3943
+ "id": "ft-edit-wizard",
3944
+ "brand": "FINANCIAL TIMES",
3945
+ "progress": {
3946
+ "variant": "line",
3947
+ "showLabels": true,
3948
+ "labelPosition": "bottom"
3949
+ },
3950
+ "cta": {
3951
+ "label": "Continue",
3952
+ "action": "next",
3953
+ "secondaryLabel": "Back",
3954
+ "secondaryAction": "prev",
3955
+ "sticky": true
3956
+ },
3957
+ "preferences": {
3958
+ "stepId": "preferences",
3959
+ "storageKey": "praxis:ft-wizard",
3960
+ "persistFields": ["topStories", "invitesOffers", "recommendations"]
3961
+ },
3962
+ "theme": {
3963
+ "praxis-wizard-card-bg": "#fff1e5",
3964
+ "md-sys-color-surface": "#fff1e5",
3965
+ "md-sys-color-on-surface": "#33302e",
3966
+ "praxis-wizard-accent": "#0d7680",
3967
+ "praxis-wizard-border": "#cfcfcf",
3968
+ "md-sys-color-outline-variant": "#cfcfcf",
3969
+ "ft-font-head": "\\\"Financier Display\\\", Georgia, serif",
3970
+ "ft-font-body": "\\\"Metric\\\", \\\"Helvetica Neue\\\", Helvetica, Arial, sans-serif",
3971
+ "ft-radius": "0",
3972
+ "ft-shadow": "none",
3973
+ "ft-header-border": "1px solid #cfcfcf"
3974
+ },
3975
+ "steps": [
3976
+ {
3977
+ "id": "access",
3978
+ "label": "Access",
3979
+ "title": "Create an FT Edit account",
3980
+ "subtitle": "Get access in a couple of steps and upgrade later for the full FT experience.",
3981
+ "zones": {
3982
+ "intro": [
3983
+ {
3984
+ "type": "benefitsGrid",
3985
+ "title": "Why register?",
3986
+ "columns": 4,
3987
+ "boxed": true,
3988
+ "items": [
3989
+ {
3990
+ "icon": "format_quote",
3991
+ "title": "Beyond the headlines",
3992
+ "text": "Insightful news, thought-provoking opinion and fascinating features."
3993
+ },
3994
+ {
3995
+ "icon": "edit_note",
3996
+ "title": "Curated daily editions",
3997
+ "text": "Eight fresh articles a day chosen for you by our senior editors."
3998
+ },
3999
+ {
4000
+ "icon": "bookmarks",
4001
+ "title": "Never miss a great story",
4002
+ "text": "Explore previous editions from the past week."
4003
+ },
4004
+ {
4005
+ "icon": "mail",
4006
+ "title": "Receive the FT Edit newsletter",
4007
+ "text": "A daily round-up delivered straight to your inbox."
4008
+ }
4009
+ ]
4010
+ }
4011
+ ],
4012
+ "footer": [
4013
+ {
4014
+ "type": "inlineNotice",
4015
+ "text": "For more information about how we use your data, please refer to our privacy and cookie policies."
4016
+ }
4017
+ ]
4018
+ },
4019
+ "cta": {
4020
+ "label": "Register with email",
4021
+ "action": "next"
4022
+ },
4023
+ "form": {
4024
+ "config": {
4025
+ "sections": [
4026
+ {
4027
+ "id": "access-section",
4028
+ "rows": [
4029
+ {
4030
+ "columns": [
4031
+ {
4032
+ "fields": ["confirmAge", "editNewsletter"]
4033
+ }
4034
+ ]
4035
+ }
4036
+ ]
4037
+ }
4038
+ ],
4039
+ "fieldMetadata": [
4040
+ {
4041
+ "name": "confirmAge",
4042
+ "label": "",
4043
+ "controlType": "checkbox",
4044
+ "required": true,
4045
+ "layout": "horizontal",
4046
+ "options": [
4047
+ {
4048
+ "label": "I confirm I am 16+ years old and agree to the Terms & Conditions.",
4049
+ "value": true
4050
+ }
4051
+ ]
4052
+ },
4053
+ {
4054
+ "name": "editNewsletter",
4055
+ "label": "FT Edit newsletter",
4056
+ "controlType": "toggle",
4057
+ "defaultValue": true,
4058
+ "hint": "All new members also start receiving our daily FT Edit newsletter."
4059
+ }
4060
+ ],
4061
+ "actions": {
4062
+ "submit": { "visible": false, "label": "Submit" },
4063
+ "cancel": { "visible": false, "label": "Cancel" },
4064
+ "reset": { "visible": false, "label": "Reset" }
4065
+ }
4066
+ }
4067
+ }
4068
+ },
4069
+ {
4070
+ "id": "account",
4071
+ "label": "Account",
4072
+ "title": "Create an FT Edit account",
4073
+ "subtitle": "This address will be used to create your account.",
4074
+ "zones": {
4075
+ "intro": [
4076
+ {
4077
+ "type": "inlineNotice",
4078
+ "text": "All new members also start receiving our daily FT Edit newsletter.",
4079
+ "tone": "info"
4080
+ }
4081
+ ],
4082
+ "footer": [
4083
+ {
4084
+ "type": "inlineNotice",
4085
+ "text": "We will send you service messages about your account, security or legal notifications."
4086
+ }
4087
+ ]
4088
+ },
4089
+ "form": {
4090
+ "config": {
4091
+ "sections": [
4092
+ {
4093
+ "id": "account-section",
4094
+ "rows": [
4095
+ {
4096
+ "columns": [
4097
+ { "fields": ["email", "password"] },
4098
+ { "fields": ["newsletterOptIn"] }
4099
+ ]
4100
+ }
4101
+ ]
4102
+ }
4103
+ ],
4104
+ "fieldMetadata": [
4105
+ {
4106
+ "name": "email",
4107
+ "label": "Email address",
4108
+ "controlType": "email",
4109
+ "required": true,
4110
+ "placeholder": "Enter your email address"
4111
+ },
4112
+ {
4113
+ "name": "password",
4114
+ "label": "Password",
4115
+ "controlType": "password",
4116
+ "required": true,
4117
+ "placeholder": "Enter a password",
4118
+ "hint": "Use 8 or more characters. You can use letters, numbers or symbols.",
4119
+ "validators": {
4120
+ "minLength": 8
4121
+ },
4122
+ "revealToggle": {
4123
+ "enabled": true,
4124
+ "style": "text",
4125
+ "showLabel": "Show password",
4126
+ "hideLabel": "Hide password",
4127
+ "ariaLabel": "Toggle password visibility"
4128
+ }
4129
+ },
4130
+ {
4131
+ "name": "newsletterOptIn",
4132
+ "label": "Stay up to date",
4133
+ "controlType": "toggle",
4134
+ "defaultValue": true,
4135
+ "hint": "All new members also start receiving our daily FT Edit newsletter."
4136
+ }
4137
+ ],
4138
+ "actions": {
4139
+ "submit": { "visible": false, "label": "Submit" },
4140
+ "cancel": { "visible": false, "label": "Cancel" },
4141
+ "reset": { "visible": false, "label": "Reset" }
4142
+ }
4143
+ }
4144
+ }
4145
+ },
4146
+ {
4147
+ "id": "preferences",
4148
+ "label": "Preferences",
4149
+ "title": "Stay up to date",
4150
+ "subtitle": "You can update these any time in your Contact Preferences.",
4151
+ "description": "We will send you service messages about your account, security or legal notifications.",
4152
+ "zones": {
4153
+ "footer": [
4154
+ {
4155
+ "type": "divider"
4156
+ },
4157
+ {
4158
+ "type": "inlineNotice",
4159
+ "text": "We will send you service messages about your account, security or legal notifications."
4160
+ }
4161
+ ]
4162
+ },
4163
+ "cta": {
4164
+ "label": "Create an FT Edit account",
4165
+ "action": "submit",
4166
+ "secondaryLabel": "Back",
4167
+ "secondaryAction": "prev"
4168
+ },
4169
+ "form": {
4170
+ "config": {
4171
+ "sections": [
4172
+ {
4173
+ "id": "prefs-section",
4174
+ "rows": [
4175
+ {
4176
+ "columns": [
4177
+ { "fields": ["topStories"] },
4178
+ { "fields": ["invitesOffers"] },
4179
+ { "fields": ["recommendations"] }
4180
+ ]
4181
+ }
4182
+ ]
4183
+ }
4184
+ ],
4185
+ "fieldMetadata": [
4186
+ {
4187
+ "name": "topStories",
4188
+ "label": "Top stories & features",
4189
+ "controlType": "toggle",
4190
+ "defaultValue": true,
4191
+ "hint": "Get the most from the Financial Times with personalised special reports, recommended reads and latest feature announcements."
4192
+ },
4193
+ {
4194
+ "name": "invitesOffers",
4195
+ "label": "Invites & offers from the FT",
4196
+ "controlType": "toggle",
4197
+ "defaultValue": true,
4198
+ "hint": "Receive exclusive personalised event invitations, carefully-curated offers and promotions from the Financial Times."
4199
+ },
4200
+ {
4201
+ "name": "recommendations",
4202
+ "label": "Personal recommendations",
4203
+ "controlType": "toggle",
4204
+ "defaultValue": false,
4205
+ "hint": "Tailored reading lists based on what you follow."
4206
+ }
4207
+ ],
4208
+ "actions": {
4209
+ "submit": { "visible": false, "label": "Submit" },
4210
+ "cancel": { "visible": false, "label": "Cancel" },
4211
+ "reset": { "visible": false, "label": "Reset" }
4212
+ }
4213
+ }
4214
+ }
4215
+ }
4216
+ ]
4217
+ }`;
4218
+ const FT_WIZARD_CONFIG = JSON.parse(FT_WIZARD_JSON);
4219
+
4220
+ const defaultCardSkin = {
4221
+ type: 'elevated',
4222
+ radius: '12px',
4223
+ border: '1px solid var(--md-sys-color-outline-variant, #e0e0e0)',
4224
+ shadow: '0 1px 2px rgba(0,0,0,0.06)',
4225
+ };
4226
+ const defaultCardLayout = {
4227
+ variant: 'cards',
4228
+ density: 'comfortable',
4229
+ lines: 2,
4230
+ model: 'standard',
4231
+ dividers: 'none',
4232
+ };
4233
+ const defaultCardTemplating = {
4234
+ primary: { type: 'text', expr: '${item.title}', class: 'ft-card-title' },
4235
+ secondary: { type: 'text', expr: '${item.description}', class: 'ft-card-desc' },
4236
+ };
4237
+ function buildStepperConfig(wizard) {
4238
+ const steps = wizard.steps.map((step) => buildStep(step, wizard.id));
4239
+ return {
4240
+ orientation: 'horizontal',
4241
+ linear: true,
4242
+ headerPosition: 'top',
4243
+ labelPosition: wizard.progress?.labelPosition ?? 'bottom',
4244
+ density: 'compact',
4245
+ stepperClass: 'ft-stepper',
4246
+ headerClass: 'ft-stepper-header',
4247
+ contentClass: 'ft-stepper-content',
4248
+ appearance: {
4249
+ preset: 'ft-light',
4250
+ },
4251
+ navigation: { visible: false },
4252
+ steps,
4253
+ };
4254
+ }
4255
+ function buildStep(step, wizardId) {
4256
+ const blocks = buildBlocks(mergeBlocks(step), wizardId, step.id);
4257
+ const beforeWidgets = [
4258
+ ...blocks.before,
4259
+ ...(step.cards?.length ? [buildCardsWidget(step, wizardId)] : []),
4260
+ ];
4261
+ const widgetsBeforeForm = beforeWidgets.length ? beforeWidgets : undefined;
4262
+ const widgetsAfterForm = blocks.after.length ? blocks.after : undefined;
4263
+ return {
4264
+ id: step.id,
4265
+ label: step.label,
4266
+ description: step.subtitle || step.description,
4267
+ optional: step.optional,
4268
+ widgetsBeforeForm,
4269
+ widgets: widgetsAfterForm,
4270
+ form: step.form
4271
+ ? {
4272
+ formId: step.form.formId || `${wizardId}:${step.id}`,
4273
+ config: step.form.config,
4274
+ mode: 'create',
4275
+ }
4276
+ : undefined,
4277
+ };
4278
+ }
4279
+ function buildCardsWidget(step, wizardId) {
4280
+ const cfg = {
4281
+ id: `${wizardId}:${step.id}:cards`,
4282
+ dataSource: { data: step.cards || [] },
4283
+ layout: { ...defaultCardLayout },
4284
+ skin: { ...defaultCardSkin },
4285
+ templating: { ...defaultCardTemplating },
4286
+ ui: { showSearch: false, showSort: false, showRange: false },
4287
+ };
4288
+ return {
4289
+ id: 'praxis-list',
4290
+ inputs: {
4291
+ listId: cfg.id,
4292
+ config: cfg,
4293
+ },
4294
+ };
4295
+ }
4296
+ function mergeBlocks(step) {
4297
+ const out = [];
4298
+ const hasZones = !!(step.zones?.intro?.length || step.zones?.body?.length || step.zones?.footer?.length);
4299
+ if (hasZones) {
4300
+ // Contrato atual: `zones` é o modelo canônico e substitui `blocks` legado
4301
+ // quando ambos coexistem no payload, evitando renderização duplicada.
4302
+ if (step.zones?.intro?.length) {
4303
+ out.push(...step.zones.intro.map((b) => ({ ...b, placement: 'beforeForm' })));
4304
+ }
4305
+ if (step.zones?.body?.length) {
4306
+ out.push(...step.zones.body.map((b) => ({ ...b, placement: 'beforeForm' })));
4307
+ }
4308
+ if (step.zones?.footer?.length) {
4309
+ out.push(...step.zones.footer.map((b) => ({ ...b, placement: 'afterForm' })));
4310
+ }
4311
+ return out;
4312
+ }
4313
+ if (step.blocks?.length)
4314
+ out.push(...step.blocks);
4315
+ return out.length ? out : undefined;
4316
+ }
4317
+ function buildBlocks(blocks, wizardId, stepId) {
4318
+ if (!blocks || blocks.length === 0)
4319
+ return { before: [], after: [] };
4320
+ const before = [];
4321
+ const after = [];
4322
+ blocks.forEach((block, index) => {
4323
+ const placement = block.placement ?? 'beforeForm';
4324
+ const def = toWidget(block, wizardId, stepId, index);
4325
+ if (!def)
4326
+ return;
4327
+ if (placement === 'afterForm')
4328
+ after.push(def);
4329
+ else
4330
+ before.push(def);
4331
+ });
4332
+ return { before, after };
4333
+ }
4334
+ function resolveBlockRuntimeId(block, wizardId, stepId, index) {
4335
+ const explicitId = typeof block.id === 'string' ? block.id.trim() : '';
4336
+ return explicitId
4337
+ ? `${wizardId}:${stepId}:block:${explicitId}`
4338
+ : `${wizardId}:${stepId}:block:${index}`;
4339
+ }
4340
+ function toWidget(block, wizardId, stepId, index) {
4341
+ const baseId = resolveBlockRuntimeId(block, wizardId, stepId, index);
4342
+ switch (block.type) {
4343
+ case 'benefitsGrid':
4344
+ return {
4345
+ id: 'praxis-wizard-benefits',
4346
+ inputs: {
4347
+ blockId: baseId,
4348
+ title: block.title,
4349
+ items: block.items,
4350
+ columns: block.columns,
4351
+ boxed: block.boxed,
4352
+ },
4353
+ };
4354
+ case 'contentBlock':
4355
+ return {
4356
+ id: 'praxis-wizard-content',
4357
+ inputs: {
4358
+ blockId: baseId,
4359
+ title: block.title,
4360
+ subtitle: block.subtitle,
4361
+ text: block.text,
4362
+ caption: block.caption,
4363
+ },
4364
+ };
4365
+ case 'inlineNotice':
4366
+ return {
4367
+ id: 'praxis-wizard-inline-notice',
4368
+ inputs: {
4369
+ blockId: baseId,
4370
+ text: block.text,
4371
+ tone: block.tone,
4372
+ },
4373
+ };
4374
+ case 'divider':
4375
+ return {
4376
+ id: 'praxis-wizard-divider',
4377
+ inputs: {
4378
+ blockId: baseId,
4379
+ label: block.label ?? '',
4380
+ },
4381
+ };
4382
+ default:
4383
+ return null;
4384
+ }
4385
+ }
4386
+
4387
+ class PraxisWizardCtaBarComponent {
4388
+ primaryLabel = 'Continue';
4389
+ primaryDisabled = false;
4390
+ secondaryLabel = 'Back';
4391
+ showSecondary = false;
4392
+ sticky = false;
4393
+ primaryClick = new EventEmitter();
4394
+ secondaryClick = new EventEmitter();
4395
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardCtaBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4396
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisWizardCtaBarComponent, isStandalone: true, selector: "praxis-wizard-cta-bar", inputs: { primaryLabel: "primaryLabel", primaryDisabled: "primaryDisabled", secondaryLabel: "secondaryLabel", showSecondary: "showSecondary", sticky: "sticky" }, outputs: { primaryClick: "primaryClick", secondaryClick: "secondaryClick" }, ngImport: i0, template: `
4397
+ <div class="pwx-cta" [class.is-sticky]="sticky" [class.has-secondary]="showSecondary">
4398
+ <button
4399
+ *ngIf="showSecondary"
4400
+ mat-button
4401
+ type="button"
4402
+ class="pwx-cta-secondary"
4403
+ (click)="secondaryClick.emit()"
4404
+ [attr.aria-label]="secondaryLabel"
4405
+ >
4406
+ {{ secondaryLabel }}
4407
+ </button>
4408
+ <button
4409
+ mat-flat-button
4410
+ color="primary"
4411
+ type="button"
4412
+ class="pwx-cta-primary"
4413
+ [disabled]="primaryDisabled"
4414
+ (click)="primaryClick.emit()"
4415
+ [attr.aria-label]="primaryLabel"
4416
+ >
4417
+ {{ primaryLabel }}
4418
+ </button>
4419
+ </div>
4420
+ `, 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 });
4421
+ }
4422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardCtaBarComponent, decorators: [{
4423
+ type: Component,
4424
+ args: [{ selector: 'praxis-wizard-cta-bar', standalone: true, imports: [CommonModule, MatButtonModule], template: `
4425
+ <div class="pwx-cta" [class.is-sticky]="sticky" [class.has-secondary]="showSecondary">
4426
+ <button
4427
+ *ngIf="showSecondary"
4428
+ mat-button
4429
+ type="button"
4430
+ class="pwx-cta-secondary"
4431
+ (click)="secondaryClick.emit()"
4432
+ [attr.aria-label]="secondaryLabel"
4433
+ >
4434
+ {{ secondaryLabel }}
4435
+ </button>
4436
+ <button
4437
+ mat-flat-button
4438
+ color="primary"
4439
+ type="button"
4440
+ class="pwx-cta-primary"
4441
+ [disabled]="primaryDisabled"
4442
+ (click)="primaryClick.emit()"
4443
+ [attr.aria-label]="primaryLabel"
4444
+ >
4445
+ {{ primaryLabel }}
4446
+ </button>
4447
+ </div>
4448
+ `, changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
4449
+ }], propDecorators: { primaryLabel: [{
4450
+ type: Input
4451
+ }], primaryDisabled: [{
4452
+ type: Input
4453
+ }], secondaryLabel: [{
4454
+ type: Input
4455
+ }], showSecondary: [{
4456
+ type: Input
4457
+ }], sticky: [{
4458
+ type: Input
4459
+ }], primaryClick: [{
4460
+ type: Output
4461
+ }], secondaryClick: [{
4462
+ type: Output
4463
+ }] } });
4464
+
4465
+ const PRAXIS_WIZARD_LOGGER = new LoggerService(createCorporateLoggerConfig(isDevMode() ? 'dev' : 'prod'), [new ConsoleLoggerSink()]);
4466
+ function logWizardConfigIssue(message) {
4467
+ PRAXIS_WIZARD_LOGGER.warnOnce(`[PraxisWizard] ${message}`, {
4468
+ context: {
4469
+ lib: 'praxis-stepper',
4470
+ component: 'PraxisWizardFormComponent',
4471
+ },
4472
+ dedupeKey: `praxis-wizard:config:${message}`,
4473
+ });
4474
+ }
4475
+ function validateWizardConfig(cfg) {
4476
+ if (!cfg)
4477
+ return null;
4478
+ const errors = [];
4479
+ if (!cfg.id)
4480
+ errors.push('config.id is required.');
4481
+ if (!cfg.steps || cfg.steps.length === 0)
4482
+ errors.push('config.steps must have at least one step.');
4483
+ cfg.steps?.forEach((step, idx) => {
4484
+ if (!step.id)
4485
+ errors.push(`steps[${idx}].id is required.`);
4486
+ if (!step.label)
4487
+ errors.push(`steps[${idx}].label is required.`);
4488
+ const hasZones = !!(step.zones?.intro?.length || step.zones?.body?.length || step.zones?.footer?.length);
4489
+ const hasBlocks = !!(step.blocks && step.blocks.length > 0);
4490
+ if (hasZones && hasBlocks) {
4491
+ errors.push(`steps[${idx}] cannot use both 'zones' and 'blocks'.`);
4492
+ }
4493
+ });
4494
+ if (errors.length) {
4495
+ errors.forEach((err) => logWizardConfigIssue(err));
4496
+ if (isDevMode()) {
4497
+ throw new Error(`[PraxisWizard] Invalid configuration:\\n${errors.join('\\n')}`);
4498
+ }
4499
+ }
4500
+ return cfg;
4501
+ }
4502
+ class PraxisWizardFormComponent {
4503
+ el = inject(ElementRef);
4504
+ renderer = inject(Renderer2);
4505
+ storage = inject(CONFIG_STORAGE);
4506
+ constructor() {
4507
+ effect(() => {
4508
+ const cfg = this.wizard();
4509
+ const theme = cfg?.theme;
4510
+ if (theme) {
4511
+ Object.entries(theme).forEach(([key, value]) => {
4512
+ this.renderer.setStyle(this.el.nativeElement, `--${key}`, value);
4513
+ });
4514
+ }
4515
+ });
4516
+ }
4517
+ stepper;
4518
+ wizardId;
4519
+ editModeEnabled = false;
4520
+ set config(cfg) {
4521
+ if (!cfg) {
4522
+ this._config.set(null);
4523
+ return;
4524
+ }
4525
+ if (typeof cfg === 'string') {
4526
+ try {
4527
+ this._config.set(validateWizardConfig(JSON.parse(cfg)));
4528
+ }
4529
+ catch {
4530
+ this._config.set(null);
4531
+ }
4532
+ return;
4533
+ }
4534
+ this._config.set(validateWizardConfig(cfg));
4535
+ }
4536
+ submit = new EventEmitter();
4537
+ _config = signal(null, ...(ngDevMode ? [{ debugName: "_config" }] : []));
4538
+ persistedState = signal(null, ...(ngDevMode ? [{ debugName: "persistedState" }] : []));
4539
+ selectedIndex = signal(0, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : []));
4540
+ wizard = computed(() => {
4541
+ const cfg = this._config();
4542
+ if (!cfg)
4543
+ return null;
4544
+ const persisted = this.persistedState()?.preferences;
4545
+ if (!persisted)
4546
+ return cfg;
4547
+ return applyPreferenceDefaults(cfg, persisted);
4548
+ }, ...(ngDevMode ? [{ debugName: "wizard" }] : []));
4549
+ stepperConfig = computed(() => {
4550
+ const cfg = this.wizard();
4551
+ return cfg ? buildStepperConfig(cfg) : null;
4552
+ }, ...(ngDevMode ? [{ debugName: "stepperConfig" }] : []));
4553
+ activeStep = computed(() => {
4554
+ const w = this.wizard();
4555
+ return w?.steps?.[this.selectedIndex()] || null;
4556
+ }, ...(ngDevMode ? [{ debugName: "activeStep" }] : []));
4557
+ wizardBrand = computed(() => this.wizard()?.brand || 'FINANCIAL TIMES', ...(ngDevMode ? [{ debugName: "wizardBrand" }] : []));
4558
+ activeTitle = computed(() => this.activeStep()?.title || this.wizard()?.title || '', ...(ngDevMode ? [{ debugName: "activeTitle" }] : []));
4559
+ activeSubtitle = computed(() => this.activeStep()?.subtitle || this.wizard()?.subtitle || '', ...(ngDevMode ? [{ debugName: "activeSubtitle" }] : []));
4560
+ activeDescription = computed(() => this.activeStep()?.description || this.wizard()?.description || '', ...(ngDevMode ? [{ debugName: "activeDescription" }] : []));
4561
+ resolvedCta = computed(() => {
4562
+ const stepCta = this.activeStep()?.cta;
4563
+ const globalCta = this.wizard()?.cta;
4564
+ return { ...(globalCta || {}), ...(stepCta || {}) };
4565
+ }, ...(ngDevMode ? [{ debugName: "resolvedCta" }] : []));
4566
+ primaryLabel = computed(() => this.resolvedCta().label ?? 'Continue', ...(ngDevMode ? [{ debugName: "primaryLabel" }] : []));
4567
+ primaryAction = computed(() => this.resolvedCta().action ?? 'next', ...(ngDevMode ? [{ debugName: "primaryAction" }] : []));
4568
+ secondaryLabel = computed(() => this.resolvedCta().secondaryLabel ?? 'Back', ...(ngDevMode ? [{ debugName: "secondaryLabel" }] : []));
4569
+ secondaryAction = computed(() => this.resolvedCta().secondaryAction ?? 'prev', ...(ngDevMode ? [{ debugName: "secondaryAction" }] : []));
4570
+ showSecondaryAction() {
4571
+ const action = this.secondaryAction();
4572
+ if (action === 'cancel')
4573
+ return true;
4574
+ return action === 'prev' && this.selectedIndex() > 0;
4575
+ }
4576
+ isPrimaryDisabled() {
4577
+ const action = this.primaryAction();
4578
+ if (action === 'next')
4579
+ return !!this.stepper?.isNextDisabled(this.selectedIndex());
4580
+ if (action === 'submit')
4581
+ return !!this.stepper?.isNextDisabled(this.selectedIndex());
4582
+ return false;
4583
+ }
4584
+ onPrimaryAction() {
4585
+ this.focusPrimaryAction();
4586
+ const action = this.primaryAction();
4587
+ if (action === 'next') {
4588
+ this.stepper?.next();
4589
+ return;
4590
+ }
4591
+ if (action === 'submit') {
4592
+ this.submit.emit({ wizardId: this.wizardId, values: this.collectValues() });
4593
+ return;
4594
+ }
4595
+ }
4596
+ onSecondaryAction() {
4597
+ this.focusSecondaryAction();
4598
+ if (this.secondaryAction() === 'prev') {
4599
+ this.stepper?.prev();
4600
+ return;
4601
+ }
4602
+ if (this.secondaryAction() === 'cancel') {
4603
+ this.resetProgress();
4604
+ }
4605
+ }
4606
+ onSelectedIndexChange(idx) {
4607
+ this.selectedIndex.set(idx);
4608
+ this.persistState();
4609
+ }
4610
+ onStepFormValueChange(ev) {
4611
+ const wizard = this.wizard();
4612
+ if (!wizard?.preferences)
4613
+ return;
4614
+ const prefStepId = wizard.preferences.stepId;
4615
+ if (!prefStepId || prefStepId !== ev.stepId)
4616
+ return;
4617
+ const values = pickPreferenceValues(ev.event?.formData, wizard.preferences.persistFields);
4618
+ this.persistState({ preferences: values });
4619
+ }
4620
+ ngOnInit() {
4621
+ this.loadPersistedState();
4622
+ }
4623
+ collectValues() {
4624
+ const values = {};
4625
+ const steps = this.wizard()?.steps || [];
4626
+ steps.forEach((step, idx) => {
4627
+ const form = this.stepper?.formGroupFor(idx);
4628
+ if (form)
4629
+ values[step.id] = form.getRawValue();
4630
+ });
4631
+ return values;
4632
+ }
4633
+ loadPersistedState() {
4634
+ if (!this.storageKey())
4635
+ return;
4636
+ const stored = this.storage.loadConfig(this.storageKey());
4637
+ if (!stored)
4638
+ return;
4639
+ this.persistedState.set(stored);
4640
+ if (typeof stored.selectedIndex === 'number') {
4641
+ this.selectedIndex.set(stored.selectedIndex);
4642
+ }
4643
+ }
4644
+ persistState(partial) {
4645
+ if (!this.storageKey())
4646
+ return;
4647
+ const next = {
4648
+ selectedIndex: this.selectedIndex(),
4649
+ preferences: this.persistedState()?.preferences,
4650
+ ...partial,
4651
+ };
4652
+ this.persistedState.set(next);
4653
+ this.storage.saveConfig(this.storageKey(), next);
4654
+ }
4655
+ storageKey() {
4656
+ const cfg = this.wizard();
4657
+ const base = cfg?.preferences?.storageKey || `praxis:wizard:${cfg?.id || this.wizardId}`;
4658
+ return `${base}:state`;
4659
+ }
4660
+ resetProgress() {
4661
+ const key = this.storageKey();
4662
+ if (key)
4663
+ this.storage.clearConfig(key);
4664
+ this.persistedState.set(null);
4665
+ this.selectedIndex.set(0);
4666
+ this.stepper?.reset();
4667
+ }
4668
+ focusPrimaryAction() {
4669
+ if (typeof document === 'undefined')
4670
+ return;
4671
+ const host = document.querySelector(`[data-wizard-id="${this.wizardId}"]`) || document;
4672
+ const el = host.querySelector('.pwx-cta-primary');
4673
+ el?.focus();
4674
+ }
4675
+ focusSecondaryAction() {
4676
+ if (typeof document === 'undefined')
4677
+ return;
4678
+ const host = document.querySelector(`[data-wizard-id="${this.wizardId}"]`) || document;
4679
+ const el = host.querySelector('.pwx-cta-secondary');
4680
+ el?.focus();
4681
+ }
4682
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4683
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: PraxisWizardFormComponent, isStandalone: true, selector: "praxis-wizard-form", inputs: { wizardId: "wizardId", editModeEnabled: "editModeEnabled", config: "config" }, outputs: { submit: "submit" }, viewQueries: [{ propertyName: "stepper", first: true, predicate: ["stepper"], descendants: true, static: true }], ngImport: i0, template: `
4684
+ <section class="ft-wizard-shell" [attr.data-wizard-id]="wizardId">
4685
+ <div class="ft-wizard-header">
4686
+ <div class="ft-brand">{{ wizardBrand() }}</div>
4687
+ </div>
4688
+
4689
+ <mat-card class="ft-wizard-card">
4690
+ <div class="ft-card-header">
4691
+ <h2>{{ activeTitle() }}</h2>
4692
+ @if (activeSubtitle()) {
4693
+ <p>{{ activeSubtitle() }}</p>
4694
+ }
4695
+ @if (activeDescription()) {
4696
+ <p class="ft-card-description">{{ activeDescription() }}</p>
4697
+ }
4698
+ </div>
4699
+
4700
+ <praxis-stepper
4701
+ #stepper
4702
+ [stepperId]="wizardId"
4703
+ [config]="stepperConfig()"
4704
+ [selectedIndex]="selectedIndex()"
4705
+ [editModeEnabled]="editModeEnabled"
4706
+ (selectedIndexChange)="onSelectedIndexChange($event)"
4707
+ (stepFormValueChange)="onStepFormValueChange($event)"
4708
+ ></praxis-stepper>
4709
+
4710
+ <praxis-wizard-cta-bar
4711
+ [primaryLabel]="primaryLabel()"
4712
+ [primaryDisabled]="isPrimaryDisabled()"
4713
+ [secondaryLabel]="secondaryLabel()"
4714
+ [showSecondary]="showSecondaryAction()"
4715
+ [sticky]="resolvedCta().sticky ?? false"
4716
+ (primaryClick)="onPrimaryAction()"
4717
+ (secondaryClick)="onSecondaryAction()"
4718
+ ></praxis-wizard-cta-bar>
4719
+ </mat-card>
4720
+ </section>
4721
+ `, isInline: true, styles: [":host{display:block;min-height:100vh;background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface);font-family:\"Source Sans 3\",Segoe UI,system-ui,-apple-system,sans-serif;--praxis-wizard-accent: var(--md-sys-color-primary);--praxis-wizard-accent-on: var(--md-sys-color-on-primary);--praxis-wizard-muted: var(--md-sys-color-on-surface-variant);--praxis-wizard-card-bg: var(--md-sys-color-surface);--praxis-wizard-border: var(--md-sys-color-outline-variant);--pfx-section-gap: 12px;--pfx-form-section-surface: var(--md-sys-color-surface);--pfx-form-stroke: var(--md-sys-color-outline-variant)}.ft-wizard-shell{max-width:700px;margin:0 auto;padding:28px 16px 64px;display:flex;flex-direction:column;gap:12px}.ft-wizard-header{text-align:center;border-bottom:var(--ft-header-border, none);padding-bottom:var(--ft-header-spacing, 0px);margin-bottom:var(--ft-header-spacing, 0px)}.ft-brand{font-family:Iowan Old Style,Palatino Linotype,Book Antiqua,Palatino,serif;letter-spacing:.22em;font-size:17px;text-transform:uppercase;color:var(--md-sys-color-on-surface)}.ft-wizard-card{padding:20px 22px 16px;border-radius:var(--ft-radius, 10px);box-shadow:var(--ft-shadow, 0 6px 16px rgba(33, 24, 16, .05));border:1px solid var(--praxis-wizard-border);background:var(--praxis-wizard-card-bg)}:host ::ng-deep .ft-stepper{background:transparent}:host ::ng-deep .ft-stepper .mat-stepper-horizontal{background:transparent}:host ::ng-deep .ft-stepper-content{padding-bottom:12px}:host ::ng-deep .ft-stepper-content .form-section{border-radius:var(--ft-radius, 6px);background:var(--pfx-form-section-surface);border-color:var(--pfx-form-stroke)!important;padding:10px 12px;box-shadow:var(--ft-shadow, none)!important}:host ::ng-deep .ft-stepper-content .form-section:focus-within{border-color:var(--pfx-form-stroke);box-shadow:none}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 40px;--mdc-outlined-text-field-container-shape: var(--ft-radius, 4px);--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-focus-outline-color: var(--praxis-wizard-accent)}.ft-card-header h2{margin:0;font-family:var(--ft-font-head, inherit);font-size:1.32rem;font-weight:600;color:var(--md-sys-color-on-surface)}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-infix{min-height:40px;padding-top:8px;padding-bottom:6px}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-subscript-wrapper{margin-top:4px}:host ::ng-deep .ft-stepper-content .mat-mdc-floating-label,:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-label{font-size:.88rem}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-hint,:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-error{font-size:.78rem}:host ::ng-deep .ft-stepper-content .mat-mdc-checkbox,:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle{margin:4px 0}:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle .mdc-form-field,:host ::ng-deep .ft-stepper-content .mat-mdc-checkbox .mdc-form-field{gap:10px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-group-wrapper{display:flex;flex-direction:column;gap:6px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-label{font-size:.82rem;font-weight:600;color:var(--md-sys-color-on-surface);margin-bottom:2px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-options{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-options.pdx-checkbox-horizontal{flex-direction:row;flex-wrap:wrap;gap:12px}:host ::ng-deep .ft-stepper-content .pdx-slide-toggle-wrapper{min-height:40px;padding:2px 0}:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle{--mdc-switch-handle-height: 16px;--mdc-switch-handle-width: 16px;--mdc-switch-track-height: 20px;--mdc-switch-track-width: 36px}:host ::ng-deep .ft-stepper-content .pdx-slide-toggle-wrapper mat-slide-toggle{justify-content:space-between}:host ::ng-deep .ft-stepper-content .pdx-hint,:host ::ng-deep .ft-stepper-content .pdx-error{font-size:.78rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}.ft-card-header{display:flex;flex-direction:column;gap:6px;margin-bottom:6px}:host ::ng-deep .ft-stepper .mat-horizontal-stepper-header-container{margin-bottom:6px}.ft-card-header h2{margin:0;font-size:1.32rem;font-weight:600;color:var(--md-sys-color-on-surface)}.ft-card-header p{margin:0;color:var(--praxis-wizard-muted);font-size:.88rem}.ft-card-description{font-size:.84rem}.ft-card-description{color:var(--praxis-wizard-muted);font-size:.88rem}:host ::ng-deep .ft-card-title{font-weight:600;color:var(--md-sys-color-on-surface)}:host ::ng-deep .ft-card-desc{color:var(--praxis-wizard-muted);font-size:.84rem}@media(max-width:600px){.ft-wizard-shell{padding:22px 12px 48px}.ft-wizard-card{padding:16px 14px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i10.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: PraxisStepper, selector: "praxis-stepper", inputs: ["stepperId", "componentInstanceId", "config", "selectedIndexInput", "selectedIndex", "disableRippleInput", "editModeEnabled", "labelPosition", "color", "serverValidate", "stepperContext"], outputs: ["selectedIndexChange", "widgetEvent", "stepFormReady", "stepFormValueChange", "animationDone", "selectionChange"] }, { kind: "component", type: PraxisWizardCtaBarComponent, selector: "praxis-wizard-cta-bar", inputs: ["primaryLabel", "primaryDisabled", "secondaryLabel", "showSecondary", "sticky"], outputs: ["primaryClick", "secondaryClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4722
+ }
4723
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisWizardFormComponent, decorators: [{
4724
+ type: Component,
4725
+ args: [{ selector: 'praxis-wizard-form', standalone: true, imports: [CommonModule, MatCardModule, MatIconModule, PraxisStepper, PraxisWizardCtaBarComponent], template: `
4726
+ <section class="ft-wizard-shell" [attr.data-wizard-id]="wizardId">
4727
+ <div class="ft-wizard-header">
4728
+ <div class="ft-brand">{{ wizardBrand() }}</div>
4729
+ </div>
4730
+
4731
+ <mat-card class="ft-wizard-card">
4732
+ <div class="ft-card-header">
4733
+ <h2>{{ activeTitle() }}</h2>
4734
+ @if (activeSubtitle()) {
4735
+ <p>{{ activeSubtitle() }}</p>
4736
+ }
4737
+ @if (activeDescription()) {
4738
+ <p class="ft-card-description">{{ activeDescription() }}</p>
4739
+ }
4740
+ </div>
4741
+
4742
+ <praxis-stepper
4743
+ #stepper
4744
+ [stepperId]="wizardId"
4745
+ [config]="stepperConfig()"
4746
+ [selectedIndex]="selectedIndex()"
4747
+ [editModeEnabled]="editModeEnabled"
4748
+ (selectedIndexChange)="onSelectedIndexChange($event)"
4749
+ (stepFormValueChange)="onStepFormValueChange($event)"
4750
+ ></praxis-stepper>
4751
+
4752
+ <praxis-wizard-cta-bar
4753
+ [primaryLabel]="primaryLabel()"
4754
+ [primaryDisabled]="isPrimaryDisabled()"
4755
+ [secondaryLabel]="secondaryLabel()"
4756
+ [showSecondary]="showSecondaryAction()"
4757
+ [sticky]="resolvedCta().sticky ?? false"
4758
+ (primaryClick)="onPrimaryAction()"
4759
+ (secondaryClick)="onSecondaryAction()"
4760
+ ></praxis-wizard-cta-bar>
4761
+ </mat-card>
4762
+ </section>
4763
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;min-height:100vh;background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface);font-family:\"Source Sans 3\",Segoe UI,system-ui,-apple-system,sans-serif;--praxis-wizard-accent: var(--md-sys-color-primary);--praxis-wizard-accent-on: var(--md-sys-color-on-primary);--praxis-wizard-muted: var(--md-sys-color-on-surface-variant);--praxis-wizard-card-bg: var(--md-sys-color-surface);--praxis-wizard-border: var(--md-sys-color-outline-variant);--pfx-section-gap: 12px;--pfx-form-section-surface: var(--md-sys-color-surface);--pfx-form-stroke: var(--md-sys-color-outline-variant)}.ft-wizard-shell{max-width:700px;margin:0 auto;padding:28px 16px 64px;display:flex;flex-direction:column;gap:12px}.ft-wizard-header{text-align:center;border-bottom:var(--ft-header-border, none);padding-bottom:var(--ft-header-spacing, 0px);margin-bottom:var(--ft-header-spacing, 0px)}.ft-brand{font-family:Iowan Old Style,Palatino Linotype,Book Antiqua,Palatino,serif;letter-spacing:.22em;font-size:17px;text-transform:uppercase;color:var(--md-sys-color-on-surface)}.ft-wizard-card{padding:20px 22px 16px;border-radius:var(--ft-radius, 10px);box-shadow:var(--ft-shadow, 0 6px 16px rgba(33, 24, 16, .05));border:1px solid var(--praxis-wizard-border);background:var(--praxis-wizard-card-bg)}:host ::ng-deep .ft-stepper{background:transparent}:host ::ng-deep .ft-stepper .mat-stepper-horizontal{background:transparent}:host ::ng-deep .ft-stepper-content{padding-bottom:12px}:host ::ng-deep .ft-stepper-content .form-section{border-radius:var(--ft-radius, 6px);background:var(--pfx-form-section-surface);border-color:var(--pfx-form-stroke)!important;padding:10px 12px;box-shadow:var(--ft-shadow, none)!important}:host ::ng-deep .ft-stepper-content .form-section:focus-within{border-color:var(--pfx-form-stroke);box-shadow:none}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 40px;--mdc-outlined-text-field-container-shape: var(--ft-radius, 4px);--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-focus-outline-color: var(--praxis-wizard-accent)}.ft-card-header h2{margin:0;font-family:var(--ft-font-head, inherit);font-size:1.32rem;font-weight:600;color:var(--md-sys-color-on-surface)}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-infix{min-height:40px;padding-top:8px;padding-bottom:6px}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-subscript-wrapper{margin-top:4px}:host ::ng-deep .ft-stepper-content .mat-mdc-floating-label,:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-label{font-size:.88rem}:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-hint,:host ::ng-deep .ft-stepper-content .mat-mdc-form-field-error{font-size:.78rem}:host ::ng-deep .ft-stepper-content .mat-mdc-checkbox,:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle{margin:4px 0}:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle .mdc-form-field,:host ::ng-deep .ft-stepper-content .mat-mdc-checkbox .mdc-form-field{gap:10px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-group-wrapper{display:flex;flex-direction:column;gap:6px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-label{font-size:.82rem;font-weight:600;color:var(--md-sys-color-on-surface);margin-bottom:2px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-options{display:flex;flex-direction:column;gap:4px}:host ::ng-deep .ft-stepper-content .pdx-checkbox-options.pdx-checkbox-horizontal{flex-direction:row;flex-wrap:wrap;gap:12px}:host ::ng-deep .ft-stepper-content .pdx-slide-toggle-wrapper{min-height:40px;padding:2px 0}:host ::ng-deep .ft-stepper-content .mat-mdc-slide-toggle{--mdc-switch-handle-height: 16px;--mdc-switch-handle-width: 16px;--mdc-switch-track-height: 20px;--mdc-switch-track-width: 36px}:host ::ng-deep .ft-stepper-content .pdx-slide-toggle-wrapper mat-slide-toggle{justify-content:space-between}:host ::ng-deep .ft-stepper-content .pdx-hint,:host ::ng-deep .ft-stepper-content .pdx-error{font-size:.78rem;color:var(--praxis-wizard-muted, var(--md-sys-color-on-surface-variant))}.ft-card-header{display:flex;flex-direction:column;gap:6px;margin-bottom:6px}:host ::ng-deep .ft-stepper .mat-horizontal-stepper-header-container{margin-bottom:6px}.ft-card-header h2{margin:0;font-size:1.32rem;font-weight:600;color:var(--md-sys-color-on-surface)}.ft-card-header p{margin:0;color:var(--praxis-wizard-muted);font-size:.88rem}.ft-card-description{font-size:.84rem}.ft-card-description{color:var(--praxis-wizard-muted);font-size:.88rem}:host ::ng-deep .ft-card-title{font-weight:600;color:var(--md-sys-color-on-surface)}:host ::ng-deep .ft-card-desc{color:var(--praxis-wizard-muted);font-size:.84rem}@media(max-width:600px){.ft-wizard-shell{padding:22px 12px 48px}.ft-wizard-card{padding:16px 14px}}\n"] }]
4764
+ }], ctorParameters: () => [], propDecorators: { stepper: [{
4765
+ type: ViewChild,
4766
+ args: ['stepper', { static: true }]
4767
+ }], wizardId: [{
4768
+ type: Input,
4769
+ args: [{ required: true }]
4770
+ }], editModeEnabled: [{
4771
+ type: Input
4772
+ }], config: [{
4773
+ type: Input
4774
+ }], submit: [{
4775
+ type: Output
4776
+ }] } });
4777
+ function pickPreferenceValues(value, fields) {
4778
+ if (!value || !fields || fields.length === 0)
4779
+ return value || {};
4780
+ const out = {};
4781
+ fields.forEach((key) => {
4782
+ if (Object.prototype.hasOwnProperty.call(value, key))
4783
+ out[key] = value[key];
4784
+ });
4785
+ return out;
4786
+ }
4787
+ function applyPreferenceDefaults(cfg, values) {
4788
+ const pref = cfg.preferences;
4789
+ if (!pref?.stepId || !values)
4790
+ return cfg;
4791
+ const steps = cfg.steps.map((step) => {
4792
+ if (step.id !== pref.stepId || !step.form?.config?.fieldMetadata)
4793
+ return step;
4794
+ const fieldMetadata = step.form.config.fieldMetadata.map((meta) => {
4795
+ if (meta.name && Object.prototype.hasOwnProperty.call(values, meta.name)) {
4796
+ return { ...meta, defaultValue: values[meta.name] };
4797
+ }
4798
+ return meta;
4799
+ });
4800
+ return {
4801
+ ...step,
4802
+ form: {
4803
+ ...step.form,
4804
+ config: {
4805
+ ...step.form.config,
4806
+ fieldMetadata,
4807
+ },
4808
+ },
4809
+ };
4810
+ });
4811
+ return { ...cfg, steps };
4812
+ }
4813
+
2037
4814
  /*
2038
4815
  * Public API Surface of praxis-stepper
2039
4816
  */
@@ -2042,5 +4819,5 @@ function providePraxisStepperMetadata() {
2042
4819
  * Generated bundle index. Do not edit.
2043
4820
  */
2044
4821
 
2045
- export { PRAXIS_STEPPER_COMPONENT_METADATA, PraxisStepper, PraxisStepperConfigEditor, providePraxisStepperMetadata };
4822
+ export { FT_WIZARD_CONFIG, FT_WIZARD_JSON, 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 };
2046
4823
  //# sourceMappingURL=praxisui-stepper.mjs.map