@praxisui/page-builder 9.0.0-beta.84 → 9.0.0-beta.86

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.
@@ -7,7 +7,7 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
7
7
  import * as i2$1 from '@angular/material/icon';
8
8
  import { MatIconModule } from '@angular/material/icon';
9
9
  import * as i2$2 from '@praxisui/core';
10
- import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, deepMerge, generateId, ComponentMetadataRegistry, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
10
+ import { PraxisIconDirective, BUILTIN_SHELL_PRESETS, PraxisIconButtonComponent, providePraxisI18n, PraxisI18nService, GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, PRAXIS_GLOBAL_ACTION_CATALOG, SurfaceOpenActionEditorComponent, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, deepMerge, generateId, ComponentMetadataRegistry, ObservabilityDashboardService, PraxisRuntimeComponentObservationRegistryService, domainKnowledgeTimelineToRichContentDocument, DomainRuleService, DomainKnowledgeService, SETTINGS_PANEL_BRIDGE, DynamicWidgetPageComponent, DYNAMIC_PAGE_SHELL_EDITOR } from '@praxisui/core';
11
11
  import * as i3 from '@angular/material/tooltip';
12
12
  import { MatTooltipModule } from '@angular/material/tooltip';
13
13
  import * as i3$1 from '@angular/material/form-field';
@@ -1560,7 +1560,7 @@ class WidgetShellEditorComponent {
1560
1560
  </div>
1561
1561
  </div>
1562
1562
  <div class="shell-preview-actions">
1563
- @for (action of previewHeaderActions(); track action) {
1563
+ @for (action of previewHeaderActions(); track action.id) {
1564
1564
  <button
1565
1565
  type="button"
1566
1566
  [disabled]="action.disabled"
@@ -1575,31 +1575,37 @@ class WidgetShellEditorComponent {
1575
1575
  }
1576
1576
  @if (previewOverflowCount()) {
1577
1577
  <button
1578
- mat-icon-button
1578
+ praxisIconButton="more_horiz"
1579
+ size="compact"
1579
1580
  type="button"
1580
1581
  aria-label="Mais ações"
1581
- >
1582
- <mat-icon>more_horiz</mat-icon>
1583
- </button>
1582
+ ></button>
1584
1583
  }
1585
- @for (action of previewWindowActions(); track action) {
1586
- <button
1587
- mat-icon-button
1588
- type="button"
1589
- [disabled]="action.disabled"
1590
- [attr.aria-label]="action.label || action.id"
1591
- >
1592
- @if (action.icon) {
1593
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
1594
- }
1595
- </button>
1584
+ @for (action of previewWindowActions(); track action.id) {
1585
+ @if (action.icon) {
1586
+ <button
1587
+ [praxisIconButton]="action.icon"
1588
+ size="compact"
1589
+ type="button"
1590
+ [disabled]="action.disabled"
1591
+ [attr.aria-label]="action.label || action.id"
1592
+ ></button>
1593
+ }
1596
1594
  }
1597
- <button mat-icon-button type="button" (click)="togglePreviewCollapse()" aria-label="Recolher">
1598
- <mat-icon>{{ previewCollapsed ? 'unfold_more' : 'unfold_less' }}</mat-icon>
1599
- </button>
1600
- <button mat-icon-button type="button" (click)="togglePreviewExpand()" aria-label="Expandir">
1601
- <mat-icon>{{ previewExpanded ? 'close_fullscreen' : 'open_in_full' }}</mat-icon>
1602
- </button>
1595
+ <button
1596
+ [praxisIconButton]="previewCollapsed ? 'unfold_more' : 'unfold_less'"
1597
+ size="compact"
1598
+ type="button"
1599
+ (click)="togglePreviewCollapse()"
1600
+ aria-label="Recolher"
1601
+ ></button>
1602
+ <button
1603
+ [praxisIconButton]="previewExpanded ? 'close_fullscreen' : 'open_in_full'"
1604
+ size="compact"
1605
+ type="button"
1606
+ (click)="togglePreviewExpand()"
1607
+ aria-label="Expandir"
1608
+ ></button>
1603
1609
  </div>
1604
1610
  </div>
1605
1611
  }
@@ -1803,7 +1809,7 @@ class WidgetShellEditorComponent {
1803
1809
  }
1804
1810
 
1805
1811
  </div>
1806
- `, isInline: true, styles: [".shell-editor{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.shell-head{display:flex;align-items:center;gap:12px}.shell-title{font-weight:600}.shell-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-section{font-weight:600;margin-top:8px}.shell-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.shell-flags{display:flex;gap:16px;align-items:center}.shell-actions-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.shell-available{display:grid;gap:12px}.shell-available-toolbar{display:grid;gap:12px;grid-template-columns:minmax(200px,1fr)}.shell-available-filters{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.shell-available-list{display:grid;gap:10px}.shell-available-item{display:grid;gap:8px;grid-template-columns:1fr auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;background:var(--md-sys-color-surface-container-low)}.shell-available-title{display:flex;align-items:center;gap:10px}.shell-available-text{display:grid;gap:4px}.shell-available-label{font-weight:600}.shell-available-meta{display:flex;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-available-payload{font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-warning{font-size:11px;color:var(--md-sys-color-error)}.shell-available-actions{display:flex;align-items:flex-start;justify-content:flex-end}.shell-badge{padding:2px 6px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant);font-size:10px}.shell-code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.shell-actions{display:grid;gap:12px}.shell-action{border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;display:grid;gap:8px}.shell-action-row{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.shell-action-actions{display:flex;justify-content:flex-end}.shell-action-hint,.shell-empty{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-hint{align-self:center;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-quick-inputs{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));align-items:end}.shell-input-path{font-size:12px;color:var(--md-sys-color-on-surface-variant);align-self:center}.shell-editor .mat-mdc-form-field{width:100%}.shell-preview{border:1px dashed var(--md-sys-color-outline-variant);border-radius:12px;padding:12px}.shell-preview-card{background:var(--pdx-shell-card-bg, var(--md-sys-color-surface));border:1px solid var(--pdx-shell-card-border, var(--md-sys-color-outline-variant));border-radius:var(--pdx-shell-card-radius, 14px);box-shadow:var(--pdx-shell-card-shadow, var(--mat-elevation-level2));overflow:hidden}.shell-preview-card.no-shell{background:transparent;border:none;box-shadow:none}.shell-preview-card.expanded{box-shadow:var(--pdx-shell-card-shadow, 0 16px 34px rgba(0,0,0,.32));transform:scale(1.01)}.shell-preview-header{display:flex;align-items:center;gap:12px;padding:10px 12px 8px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var(--pdx-shell-header-bg, var(--md-sys-color-surface-container))}.shell-preview-title{display:flex;align-items:center;gap:10px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.shell-preview-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.shell-preview-text{min-width:0}.shell-preview-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 14px);line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-subtitle{font-size:var(--pdx-shell-subtitle-size, 12px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-actions{display:flex;align-items:center;gap:6px}.pdx-preview-text{padding:0 8px}.pdx-preview-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-preview-label{font-size:12px;font-weight:500}.shell-preview-body{padding:var(--pdx-shell-body-padding, 10px 12px 12px 12px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit);font-size:12px}.shell-preview-body.hidden{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5$1.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: MatDividerModule }, { kind: "component", type: i6.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1812
+ `, isInline: true, styles: [".shell-editor{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.shell-head{display:flex;align-items:center;gap:12px}.shell-title{font-weight:600}.shell-subtitle{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-section{font-weight:600;margin-top:8px}.shell-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.shell-flags{display:flex;gap:16px;align-items:center}.shell-actions-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.shell-available{display:grid;gap:12px}.shell-available-toolbar{display:grid;gap:12px;grid-template-columns:minmax(200px,1fr)}.shell-available-filters{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.shell-available-list{display:grid;gap:10px}.shell-available-item{display:grid;gap:8px;grid-template-columns:1fr auto;border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;background:var(--md-sys-color-surface-container-low)}.shell-available-title{display:flex;align-items:center;gap:10px}.shell-available-text{display:grid;gap:4px}.shell-available-label{font-weight:600}.shell-available-meta{display:flex;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-desc{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-available-payload{font-size:11px;color:var(--md-sys-color-on-surface-variant)}.shell-available-warning{font-size:11px;color:var(--md-sys-color-error)}.shell-available-actions{display:flex;align-items:flex-start;justify-content:flex-end}.shell-badge{padding:2px 6px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant);font-size:10px}.shell-code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.shell-actions{display:grid;gap:12px}.shell-action{border:1px solid var(--md-sys-color-outline-variant);border-radius:12px;padding:12px;display:grid;gap:8px}.shell-action-row{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}.shell-action-actions{display:flex;justify-content:flex-end}.shell-action-hint,.shell-empty{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-hint{align-self:center;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.shell-quick-inputs{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));align-items:end}.shell-input-path{font-size:12px;color:var(--md-sys-color-on-surface-variant);align-self:center}.shell-editor .mat-mdc-form-field{width:100%}.shell-preview{border:1px dashed var(--md-sys-color-outline-variant);border-radius:12px;padding:12px}.shell-preview-card{background:var(--pdx-shell-card-bg, var(--md-sys-color-surface));border:1px solid var(--pdx-shell-card-border, var(--md-sys-color-outline-variant));border-radius:var(--pdx-shell-card-radius, 14px);box-shadow:var(--pdx-shell-card-shadow, var(--mat-elevation-level2));overflow:hidden}.shell-preview-card.no-shell{background:transparent;border:none;box-shadow:none}.shell-preview-card.expanded{box-shadow:var(--pdx-shell-card-shadow, 0 16px 34px rgba(0,0,0,.32));transform:scale(1.01)}.shell-preview-header{display:flex;align-items:center;gap:12px;padding:10px 12px 8px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var(--pdx-shell-header-bg, var(--md-sys-color-surface-container))}.shell-preview-title{display:flex;align-items:center;gap:10px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.shell-preview-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.shell-preview-text{min-width:0}.shell-preview-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 14px);line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-subtitle{font-size:var(--pdx-shell-subtitle-size, 12px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.shell-preview-actions{display:flex;align-items:center;gap:6px}.pdx-preview-text{padding:0 8px}.pdx-preview-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-preview-label{font-size:12px;font-weight:500}.shell-preview-body{padding:var(--pdx-shell-body-padding, 10px 12px 12px 12px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit);font-size:12px}.shell-preview-body.hidden{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5$1.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: MatDividerModule }, { kind: "component", type: i6.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1807
1813
  }
1808
1814
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellEditorComponent, decorators: [{
1809
1815
  type: Component,
@@ -1818,6 +1824,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1818
1824
  MatIconModule,
1819
1825
  MatInputModule,
1820
1826
  MatSelectModule,
1827
+ PraxisIconButtonComponent,
1821
1828
  PraxisIconDirective,
1822
1829
  ], template: `
1823
1830
  <div class="shell-editor">
@@ -1967,7 +1974,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1967
1974
  </div>
1968
1975
  </div>
1969
1976
  <div class="shell-preview-actions">
1970
- @for (action of previewHeaderActions(); track action) {
1977
+ @for (action of previewHeaderActions(); track action.id) {
1971
1978
  <button
1972
1979
  type="button"
1973
1980
  [disabled]="action.disabled"
@@ -1982,31 +1989,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
1982
1989
  }
1983
1990
  @if (previewOverflowCount()) {
1984
1991
  <button
1985
- mat-icon-button
1992
+ praxisIconButton="more_horiz"
1993
+ size="compact"
1986
1994
  type="button"
1987
1995
  aria-label="Mais ações"
1988
- >
1989
- <mat-icon>more_horiz</mat-icon>
1990
- </button>
1996
+ ></button>
1991
1997
  }
1992
- @for (action of previewWindowActions(); track action) {
1993
- <button
1994
- mat-icon-button
1995
- type="button"
1996
- [disabled]="action.disabled"
1997
- [attr.aria-label]="action.label || action.id"
1998
- >
1999
- @if (action.icon) {
2000
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
2001
- }
2002
- </button>
1998
+ @for (action of previewWindowActions(); track action.id) {
1999
+ @if (action.icon) {
2000
+ <button
2001
+ [praxisIconButton]="action.icon"
2002
+ size="compact"
2003
+ type="button"
2004
+ [disabled]="action.disabled"
2005
+ [attr.aria-label]="action.label || action.id"
2006
+ ></button>
2007
+ }
2003
2008
  }
2004
- <button mat-icon-button type="button" (click)="togglePreviewCollapse()" aria-label="Recolher">
2005
- <mat-icon>{{ previewCollapsed ? 'unfold_more' : 'unfold_less' }}</mat-icon>
2006
- </button>
2007
- <button mat-icon-button type="button" (click)="togglePreviewExpand()" aria-label="Expandir">
2008
- <mat-icon>{{ previewExpanded ? 'close_fullscreen' : 'open_in_full' }}</mat-icon>
2009
- </button>
2009
+ <button
2010
+ [praxisIconButton]="previewCollapsed ? 'unfold_more' : 'unfold_less'"
2011
+ size="compact"
2012
+ type="button"
2013
+ (click)="togglePreviewCollapse()"
2014
+ aria-label="Recolher"
2015
+ ></button>
2016
+ <button
2017
+ [praxisIconButton]="previewExpanded ? 'close_fullscreen' : 'open_in_full'"
2018
+ size="compact"
2019
+ type="button"
2020
+ (click)="togglePreviewExpand()"
2021
+ aria-label="Expandir"
2022
+ ></button>
2010
2023
  </div>
2011
2024
  </div>
2012
2025
  }
@@ -2751,6 +2764,7 @@ const PRAXIS_PAGE_BUILDER_EN_US = {
2751
2764
  'praxis.pageBuilder.agentic.context.governedDomainContextResolved': 'Available',
2752
2765
  'praxis.pageBuilder.agentic.context.governedDomainContextRequestedUnavailable': 'Requested, but unavailable',
2753
2766
  'praxis.pageBuilder.agentic.context.governedDomainContextNotRequested': 'Not requested',
2767
+ 'praxis.pageBuilder.agentic.context.governedDomainContextUsedInDecision': 'Used in the semantic decision',
2754
2768
  'praxis.pageBuilder.agentic.context.governedDomainContextUnknown': 'unknown',
2755
2769
  'praxis.pageBuilder.agentic.context.governedDomainContextPolicy': 'Policy profile',
2756
2770
  'praxis.pageBuilder.agentic.context.governedDomainContextSource': 'Context source',
@@ -3371,6 +3385,7 @@ const PRAXIS_PAGE_BUILDER_PT_BR = {
3371
3385
  'praxis.pageBuilder.agentic.context.governedDomainContextResolved': 'Disponível',
3372
3386
  'praxis.pageBuilder.agentic.context.governedDomainContextRequestedUnavailable': 'Solicitado, mas indisponível',
3373
3387
  'praxis.pageBuilder.agentic.context.governedDomainContextNotRequested': 'Não solicitado',
3388
+ 'praxis.pageBuilder.agentic.context.governedDomainContextUsedInDecision': 'Usado na decisão semântica',
3374
3389
  'praxis.pageBuilder.agentic.context.governedDomainContextUnknown': 'desconhecido',
3375
3390
  'praxis.pageBuilder.agentic.context.governedDomainContextPolicy': 'Perfil de política',
3376
3391
  'praxis.pageBuilder.agentic.context.governedDomainContextSource': 'Fonte do contexto',
@@ -10417,17 +10432,17 @@ class DynamicPageConfigEditorComponent {
10417
10432
  </div>
10418
10433
  <mat-tab-group [selectedIndex]="selectedTabIndex" (selectedIndexChange)="onSelectedTabIndexChange($event)">
10419
10434
  <mat-tab [label]="tx('editor.tabs.layout', 'Layout')"><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.cols', 'Columns') }}</mat-label><input matInput type="number" min="1" [formControl]="canvasColumnsControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.rowUnit', 'Row unit') }}</mat-label><input matInput [formControl]="canvasRowUnitControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.gap', 'Gap') }}</mat-label><input matInput [formControl]="canvasGapControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.autoRows', 'Auto rows') }}</mat-label><mat-select [formControl]="canvasAutoRowsControl"><mat-option value="fixed">fixed</mat-option><mat-option value="content">content</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.layoutPreset', 'Layout preset') }}</mat-label><mat-select [formControl]="layoutPresetControl"><mat-option value="">{{ tx('editor.layout.none', 'None') }}</mat-option>@for (preset of layoutPresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.themePreset', 'Theme preset') }}</mat-label><mat-select [formControl]="themePresetControl"><mat-option value="">{{ tx('editor.layout.layoutDefault', 'Layout default') }}</mat-option>@for (preset of themePresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.shellPreset', 'Shell visual preset') }}</mat-label><mat-select [formControl]="shellPresetControl"><mat-option value="">{{ tx('editor.layout.none', 'None') }}</mat-option>@for (preset of shellPresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field></div>@if (selectedLayoutPresetEntry; as preset) {<div class="preset-preview"><div class="preset-preview__head"><div><span class="eyebrow">{{ tx('editor.preview.layoutEyebrow', 'Layout template') }} · {{ preset.category }}</span><strong>{{ preset.label }}</strong></div><span>{{ layoutPresetSummary(preset) }}</span></div><p>{{ preset.description || tx('editor.preview.layoutFallbackDescription', 'Page organization preset.') }}</p><div class="preset-preview__chips"><span>{{ slotsSummary(preset) }}</span><span>{{ requiredSlotsSummary(preset) }}</span><span>{{ devicePolicySummary(preset) }}</span></div>@if (recommendedThemePresetEntry; as theme) {<div class="preset-preview__recommendation"><div><span class="eyebrow">{{ tx('editor.preview.inheritedTheme', 'Inherited theme') }}</span><strong>{{ theme.label }}</strong><span>{{ inheritedThemeHelp(theme) }}</span></div><button mat-stroked-button type="button" [disabled]="themePresetControl.value === theme.id" (click)="pinRecommendedThemePreset()">{{ tx('editor.preview.pinTheme', 'Pin theme') }}</button></div>}</div>} @if (selectedThemePresetEntry; as theme) {<div class="preset-preview preset-preview--theme"><div class="preset-preview__head"><div><span class="eyebrow">{{ tx('editor.preview.explicitTheme', 'Explicit theme') }}</span><strong>{{ theme.label }}</strong></div><span>{{ theme.density }} · {{ theme.motion }}</span></div><p>{{ theme.description || tx('editor.preview.themeFallbackDescription', 'Page visual preset.') }}</p><div class="preset-preview__chips"><span>{{ tx('editor.preview.shellChip', 'Shell: {{value}}').replace('{{value}}', theme.shellPreset) }}</span><span>{{ tx('editor.preview.chartsChip', 'Charts: {{value}}').replace('{{value}}', theme.chartThemePreset) }}</span></div></div>}</mat-tab>
10420
- <mat-tab [label]="tx('editor.tabs.grouping', 'Grouping')"><div class="panel"><div class="head"><span>{{ tx('editor.grouping.title', 'Grouping') }}</span><button mat-stroked-button type="button" (click)="addGroupingNode()"><mat-icon>add</mat-icon>{{ tx('editor.grouping.add', 'Add group') }}</button></div>@for (group of groupingNodes.controls; track $index) {<div class="card" [formGroup]="group"><div class="head"><span>{{ groupLabel($index) }}</span><button mat-icon-button type="button" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')" (click)="removeGroupingNode($index)"><mat-icon>delete</mat-icon></button></div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.kind', 'Kind') }}</mat-label><mat-select formControlName="kind"><mat-option value="section">section</mat-option><mat-option value="tabs">tabs</mat-option><mat-option value="hero">hero</mat-option><mat-option value="rail">rail</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.id', 'Id') }}</mat-label><input matInput formControlName="id" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.label', 'Label') }}</mat-label><input matInput formControlName="label" /></mat-form-field>@if (group.controls.kind.value === 'section') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.layout', 'Layout') }}</mat-label><mat-select formControlName="layout"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="stack">stack</mat-option><mat-option value="grid">grid</mat-option><mat-option value="row">row</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'hero') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.emphasis', 'Emphasis') }}</mat-label><mat-select formControlName="emphasis"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="high">high</mat-option><mat-option value="medium">medium</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'rail') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.side', 'Side') }}</mat-label><mat-select formControlName="side"><mat-option value="left">left</mat-option><mat-option value="right">right</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'tabs') {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label><textarea matInput rows="4" formControlName="tabsJson"></textarea></mat-form-field>} @else {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.widgetKeysCsv', 'Widget keys (comma-separated)') }}</mat-label><input matInput formControlName="widgetKeysCsv" /></mat-form-field>}</div></div>}</div></mat-tab>
10435
+ <mat-tab [label]="tx('editor.tabs.grouping', 'Grouping')"><div class="panel"><div class="head"><span>{{ tx('editor.grouping.title', 'Grouping') }}</span><button mat-stroked-button type="button" (click)="addGroupingNode()"><mat-icon>add</mat-icon>{{ tx('editor.grouping.add', 'Add group') }}</button></div>@for (group of groupingNodes.controls; track $index) {<div class="card" [formGroup]="group"><div class="head"><span>{{ groupLabel($index) }}</span><button praxisIconButton="delete" size="compact" type="button" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')" (click)="removeGroupingNode($index)"></button></div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.kind', 'Kind') }}</mat-label><mat-select formControlName="kind"><mat-option value="section">section</mat-option><mat-option value="tabs">tabs</mat-option><mat-option value="hero">hero</mat-option><mat-option value="rail">rail</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.id', 'Id') }}</mat-label><input matInput formControlName="id" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.label', 'Label') }}</mat-label><input matInput formControlName="label" /></mat-form-field>@if (group.controls.kind.value === 'section') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.layout', 'Layout') }}</mat-label><mat-select formControlName="layout"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="stack">stack</mat-option><mat-option value="grid">grid</mat-option><mat-option value="row">row</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'hero') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.emphasis', 'Emphasis') }}</mat-label><mat-select formControlName="emphasis"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="high">high</mat-option><mat-option value="medium">medium</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'rail') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.side', 'Side') }}</mat-label><mat-select formControlName="side"><mat-option value="left">left</mat-option><mat-option value="right">right</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'tabs') {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label><textarea matInput rows="4" formControlName="tabsJson"></textarea></mat-form-field>} @else {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.widgetKeysCsv', 'Widget keys (comma-separated)') }}</mat-label><input matInput formControlName="widgetKeysCsv" /></mat-form-field>}</div></div>}</div></mat-tab>
10421
10436
  <mat-tab [label]="tx('editor.tabs.devices', 'Device Layouts')"><div class="panel">@for (device of deviceKeys; track device) {<div class="card"><div>{{ deviceLabels[device] }}</div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.devices.columns', 'Columns') }}</mat-label><input matInput type="number" min="1" [formControl]="deviceForms[device].controls.columns" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.rowUnit', 'Row unit') }}</mat-label><input matInput [formControl]="deviceForms[device].controls.rowUnit" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.devices.gap', 'Gap') }}</mat-label><input matInput [formControl]="deviceForms[device].controls.gap" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.autoRows', 'Auto rows') }}</mat-label><mat-select [formControl]="deviceForms[device].controls.autoRows"><mat-option value="">{{ tx('editor.devices.orientationDefault', 'Default') }}</mat-option><mat-option value="fixed">fixed</mat-option><mat-option value="content">content</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label><textarea matInput rows="4" [formControl]="deviceForms[device].controls.groupingOverrides"></textarea></mat-form-field><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label><textarea matInput rows="4" [formControl]="deviceForms[device].controls.widgetOverrides"></textarea></mat-form-field></div><div class="hint">{{ tx('editor.preview.deviceCanvasHint', 'Existing canvas item overrides are preserved.') }}</div></div>}</div></mat-tab>
10422
10437
  <mat-tab [label]="tx('editor.tabs.context', 'Context')"><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.context.json', 'Context (JSON)') }}</mat-label><textarea matInput rows="12" [formControl]="contextControl"></textarea></mat-form-field></mat-tab>
10423
10438
  <mat-tab [label]="tx('editor.tabs.state', 'Page State')"><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.state.valuesJson', 'Primary values (JSON)') }}</mat-label><textarea matInput rows="14" [formControl]="stateControl"></textarea></mat-form-field></mat-tab>
10424
10439
  </mat-tab-group>
10425
10440
  </div>
10426
- `, isInline: true, styles: [".editor,.panel{display:grid;gap:16px;color:var(--md-sys-color-on-surface, currentColor)}.head,.summary{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.summary{color:var(--md-sys-color-on-surface-variant, currentColor)}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.card{display:grid;gap:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 18%, transparent));border-radius:8px;background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface-container, transparent));color:var(--md-sys-color-on-surface, currentColor)}.wide{grid-column:1 / -1}.hint{color:var(--md-sys-color-on-surface-variant, currentColor);font-size:12px}.preset-preview{display:grid;gap:12px;margin-top:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 18%, transparent));border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, transparent) 88%,var(--md-sys-color-primary-container, transparent) 12%)}.preset-preview--theme{background:var(--md-sys-color-surface-container-low, transparent)}.preset-preview__head,.preset-preview__recommendation{display:flex;justify-content:space-between;align-items:center;gap:16px}.preset-preview__head>div,.preset-preview__recommendation>div{display:grid;gap:4px;min-width:0}.preset-preview p{margin:0;color:var(--md-sys-color-on-surface-variant, currentColor);line-height:1.45}.preset-preview__chips{display:flex;flex-wrap:wrap;gap:8px}.preset-preview__chips span{padding:5px 9px;border-radius:999px;background:var(--md-sys-color-surface-container, color-mix(in srgb, currentColor 8%, transparent));color:var(--md-sys-color-on-surface-variant, currentColor);font-size:12px;line-height:1.3}.preset-preview__recommendation{padding-top:12px;border-top:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 14%, transparent))}.preset-preview__recommendation span:last-child{color:var(--md-sys-color-on-surface-variant, currentColor);font-size:13px;line-height:1.35}.eyebrow{color:var(--md-sys-color-primary, currentColor);font-size:11px;font-weight:700;letter-spacing:0;text-transform:uppercase}:host ::ng-deep .mat-mdc-tab-body-content{padding-top:12px;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10441
+ `, isInline: true, styles: [".editor,.panel{display:grid;gap:16px;color:var(--md-sys-color-on-surface, currentColor)}.head,.summary{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.summary{color:var(--md-sys-color-on-surface-variant, currentColor)}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.card{display:grid;gap:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 18%, transparent));border-radius:8px;background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface-container, transparent));color:var(--md-sys-color-on-surface, currentColor)}.wide{grid-column:1 / -1}.hint{color:var(--md-sys-color-on-surface-variant, currentColor);font-size:12px}.preset-preview{display:grid;gap:12px;margin-top:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 18%, transparent));border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low, transparent) 88%,var(--md-sys-color-primary-container, transparent) 12%)}.preset-preview--theme{background:var(--md-sys-color-surface-container-low, transparent)}.preset-preview__head,.preset-preview__recommendation{display:flex;justify-content:space-between;align-items:center;gap:16px}.preset-preview__head>div,.preset-preview__recommendation>div{display:grid;gap:4px;min-width:0}.preset-preview p{margin:0;color:var(--md-sys-color-on-surface-variant, currentColor);line-height:1.45}.preset-preview__chips{display:flex;flex-wrap:wrap;gap:8px}.preset-preview__chips span{padding:5px 9px;border-radius:999px;background:var(--md-sys-color-surface-container, color-mix(in srgb, currentColor 8%, transparent));color:var(--md-sys-color-on-surface-variant, currentColor);font-size:12px;line-height:1.3}.preset-preview__recommendation{padding-top:12px;border-top:1px solid var(--md-sys-color-outline-variant, color-mix(in srgb, currentColor 14%, transparent))}.preset-preview__recommendation span:last-child{color:var(--md-sys-color-on-surface-variant, currentColor);font-size:13px;line-height:1.35}.eyebrow{color:var(--md-sys-color-primary, currentColor);font-size:11px;font-weight:700;letter-spacing:0;text-transform:uppercase}:host ::ng-deep .mat-mdc-tab-body-content{padding-top:12px;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.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"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10427
10442
  }
10428
10443
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageConfigEditorComponent, decorators: [{
10429
10444
  type: Component,
10430
- args: [{ selector: 'praxis-dynamic-page-config-editor', standalone: true, imports: [ReactiveFormsModule, MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSelectModule, MatTabsModule], providers: [providePraxisPageBuilderI18n()], template: `
10445
+ args: [{ selector: 'praxis-dynamic-page-config-editor', standalone: true, imports: [ReactiveFormsModule, MatButtonModule, MatFormFieldModule, MatIconModule, MatInputModule, MatSelectModule, MatTabsModule, PraxisIconButtonComponent], providers: [providePraxisPageBuilderI18n()], template: `
10431
10446
  <div class="editor">
10432
10447
  <div class="head">
10433
10448
  <div>{{ tx('editor.title', 'Page settings') }}</div>
@@ -10442,7 +10457,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
10442
10457
  </div>
10443
10458
  <mat-tab-group [selectedIndex]="selectedTabIndex" (selectedIndexChange)="onSelectedTabIndexChange($event)">
10444
10459
  <mat-tab [label]="tx('editor.tabs.layout', 'Layout')"><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.cols', 'Columns') }}</mat-label><input matInput type="number" min="1" [formControl]="canvasColumnsControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.rowUnit', 'Row unit') }}</mat-label><input matInput [formControl]="canvasRowUnitControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.gap', 'Gap') }}</mat-label><input matInput [formControl]="canvasGapControl" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.autoRows', 'Auto rows') }}</mat-label><mat-select [formControl]="canvasAutoRowsControl"><mat-option value="fixed">fixed</mat-option><mat-option value="content">content</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.layoutPreset', 'Layout preset') }}</mat-label><mat-select [formControl]="layoutPresetControl"><mat-option value="">{{ tx('editor.layout.none', 'None') }}</mat-option>@for (preset of layoutPresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.themePreset', 'Theme preset') }}</mat-label><mat-select [formControl]="themePresetControl"><mat-option value="">{{ tx('editor.layout.layoutDefault', 'Layout default') }}</mat-option>@for (preset of themePresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.shellPreset', 'Shell visual preset') }}</mat-label><mat-select [formControl]="shellPresetControl"><mat-option value="">{{ tx('editor.layout.none', 'None') }}</mat-option>@for (preset of shellPresetEntries; track preset.id) {<mat-option [value]="preset.id">{{ preset.label }}</mat-option>}</mat-select></mat-form-field></div>@if (selectedLayoutPresetEntry; as preset) {<div class="preset-preview"><div class="preset-preview__head"><div><span class="eyebrow">{{ tx('editor.preview.layoutEyebrow', 'Layout template') }} · {{ preset.category }}</span><strong>{{ preset.label }}</strong></div><span>{{ layoutPresetSummary(preset) }}</span></div><p>{{ preset.description || tx('editor.preview.layoutFallbackDescription', 'Page organization preset.') }}</p><div class="preset-preview__chips"><span>{{ slotsSummary(preset) }}</span><span>{{ requiredSlotsSummary(preset) }}</span><span>{{ devicePolicySummary(preset) }}</span></div>@if (recommendedThemePresetEntry; as theme) {<div class="preset-preview__recommendation"><div><span class="eyebrow">{{ tx('editor.preview.inheritedTheme', 'Inherited theme') }}</span><strong>{{ theme.label }}</strong><span>{{ inheritedThemeHelp(theme) }}</span></div><button mat-stroked-button type="button" [disabled]="themePresetControl.value === theme.id" (click)="pinRecommendedThemePreset()">{{ tx('editor.preview.pinTheme', 'Pin theme') }}</button></div>}</div>} @if (selectedThemePresetEntry; as theme) {<div class="preset-preview preset-preview--theme"><div class="preset-preview__head"><div><span class="eyebrow">{{ tx('editor.preview.explicitTheme', 'Explicit theme') }}</span><strong>{{ theme.label }}</strong></div><span>{{ theme.density }} · {{ theme.motion }}</span></div><p>{{ theme.description || tx('editor.preview.themeFallbackDescription', 'Page visual preset.') }}</p><div class="preset-preview__chips"><span>{{ tx('editor.preview.shellChip', 'Shell: {{value}}').replace('{{value}}', theme.shellPreset) }}</span><span>{{ tx('editor.preview.chartsChip', 'Charts: {{value}}').replace('{{value}}', theme.chartThemePreset) }}</span></div></div>}</mat-tab>
10445
- <mat-tab [label]="tx('editor.tabs.grouping', 'Grouping')"><div class="panel"><div class="head"><span>{{ tx('editor.grouping.title', 'Grouping') }}</span><button mat-stroked-button type="button" (click)="addGroupingNode()"><mat-icon>add</mat-icon>{{ tx('editor.grouping.add', 'Add group') }}</button></div>@for (group of groupingNodes.controls; track $index) {<div class="card" [formGroup]="group"><div class="head"><span>{{ groupLabel($index) }}</span><button mat-icon-button type="button" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')" (click)="removeGroupingNode($index)"><mat-icon>delete</mat-icon></button></div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.kind', 'Kind') }}</mat-label><mat-select formControlName="kind"><mat-option value="section">section</mat-option><mat-option value="tabs">tabs</mat-option><mat-option value="hero">hero</mat-option><mat-option value="rail">rail</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.id', 'Id') }}</mat-label><input matInput formControlName="id" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.label', 'Label') }}</mat-label><input matInput formControlName="label" /></mat-form-field>@if (group.controls.kind.value === 'section') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.layout', 'Layout') }}</mat-label><mat-select formControlName="layout"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="stack">stack</mat-option><mat-option value="grid">grid</mat-option><mat-option value="row">row</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'hero') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.emphasis', 'Emphasis') }}</mat-label><mat-select formControlName="emphasis"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="high">high</mat-option><mat-option value="medium">medium</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'rail') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.side', 'Side') }}</mat-label><mat-select formControlName="side"><mat-option value="left">left</mat-option><mat-option value="right">right</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'tabs') {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label><textarea matInput rows="4" formControlName="tabsJson"></textarea></mat-form-field>} @else {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.widgetKeysCsv', 'Widget keys (comma-separated)') }}</mat-label><input matInput formControlName="widgetKeysCsv" /></mat-form-field>}</div></div>}</div></mat-tab>
10460
+ <mat-tab [label]="tx('editor.tabs.grouping', 'Grouping')"><div class="panel"><div class="head"><span>{{ tx('editor.grouping.title', 'Grouping') }}</span><button mat-stroked-button type="button" (click)="addGroupingNode()"><mat-icon>add</mat-icon>{{ tx('editor.grouping.add', 'Add group') }}</button></div>@for (group of groupingNodes.controls; track $index) {<div class="card" [formGroup]="group"><div class="head"><span>{{ groupLabel($index) }}</span><button praxisIconButton="delete" size="compact" type="button" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')" (click)="removeGroupingNode($index)"></button></div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.kind', 'Kind') }}</mat-label><mat-select formControlName="kind"><mat-option value="section">section</mat-option><mat-option value="tabs">tabs</mat-option><mat-option value="hero">hero</mat-option><mat-option value="rail">rail</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.id', 'Id') }}</mat-label><input matInput formControlName="id" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.label', 'Label') }}</mat-label><input matInput formControlName="label" /></mat-form-field>@if (group.controls.kind.value === 'section') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.layout', 'Layout') }}</mat-label><mat-select formControlName="layout"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="stack">stack</mat-option><mat-option value="grid">grid</mat-option><mat-option value="row">row</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'hero') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.emphasis', 'Emphasis') }}</mat-label><mat-select formControlName="emphasis"><mat-option value="">{{ tx('editor.grouping.layoutDefault', 'Default') }}</mat-option><mat-option value="high">high</mat-option><mat-option value="medium">medium</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'rail') {<mat-form-field appearance="outline"><mat-label>{{ tx('editor.grouping.side', 'Side') }}</mat-label><mat-select formControlName="side"><mat-option value="left">left</mat-option><mat-option value="right">right</mat-option></mat-select></mat-form-field>}@if (group.controls.kind.value === 'tabs') {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label><textarea matInput rows="4" formControlName="tabsJson"></textarea></mat-form-field>} @else {<mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.grouping.widgetKeysCsv', 'Widget keys (comma-separated)') }}</mat-label><input matInput formControlName="widgetKeysCsv" /></mat-form-field>}</div></div>}</div></mat-tab>
10446
10461
  <mat-tab [label]="tx('editor.tabs.devices', 'Device Layouts')"><div class="panel">@for (device of deviceKeys; track device) {<div class="card"><div>{{ deviceLabels[device] }}</div><div class="grid"><mat-form-field appearance="outline"><mat-label>{{ tx('editor.devices.columns', 'Columns') }}</mat-label><input matInput type="number" min="1" [formControl]="deviceForms[device].controls.columns" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.rowUnit', 'Row unit') }}</mat-label><input matInput [formControl]="deviceForms[device].controls.rowUnit" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.devices.gap', 'Gap') }}</mat-label><input matInput [formControl]="deviceForms[device].controls.gap" /></mat-form-field><mat-form-field appearance="outline"><mat-label>{{ tx('editor.layout.autoRows', 'Auto rows') }}</mat-label><mat-select [formControl]="deviceForms[device].controls.autoRows"><mat-option value="">{{ tx('editor.devices.orientationDefault', 'Default') }}</mat-option><mat-option value="fixed">fixed</mat-option><mat-option value="content">content</mat-option></mat-select></mat-form-field><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label><textarea matInput rows="4" [formControl]="deviceForms[device].controls.groupingOverrides"></textarea></mat-form-field><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label><textarea matInput rows="4" [formControl]="deviceForms[device].controls.widgetOverrides"></textarea></mat-form-field></div><div class="hint">{{ tx('editor.preview.deviceCanvasHint', 'Existing canvas item overrides are preserved.') }}</div></div>}</div></mat-tab>
10447
10462
  <mat-tab [label]="tx('editor.tabs.context', 'Context')"><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.context.json', 'Context (JSON)') }}</mat-label><textarea matInput rows="12" [formControl]="contextControl"></textarea></mat-form-field></mat-tab>
10448
10463
  <mat-tab [label]="tx('editor.tabs.state', 'Page State')"><mat-form-field appearance="outline" class="wide"><mat-label>{{ tx('editor.state.valuesJson', 'Primary values (JSON)') }}</mat-label><textarea matInput rows="14" [formControl]="stateControl"></textarea></mat-form-field></mat-tab>
@@ -11385,9 +11400,7 @@ class PageConfigEditorComponent {
11385
11400
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
11386
11401
  }
11387
11402
  </mat-select>
11388
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="layoutPresetHint" matTooltipPosition="above">
11389
- <mat-icon>help_outline</mat-icon>
11390
- </button>
11403
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="layoutPresetHint" [attr.aria-label]="layoutPresetHint" matTooltipPosition="above"></button>
11391
11404
  </mat-form-field>
11392
11405
  <mat-form-field appearance="outline">
11393
11406
  <mat-label>{{ tx('editor.layout.themePreset', 'Theme preset') }}</mat-label>
@@ -11397,9 +11410,7 @@ class PageConfigEditorComponent {
11397
11410
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
11398
11411
  }
11399
11412
  </mat-select>
11400
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="themePresetHint" matTooltipPosition="above">
11401
- <mat-icon>help_outline</mat-icon>
11402
- </button>
11413
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="themePresetHint" [attr.aria-label]="themePresetHint" matTooltipPosition="above"></button>
11403
11414
  </mat-form-field>
11404
11415
  <mat-form-field appearance="outline">
11405
11416
  <mat-label>{{ tx('editor.layout.shellPreset', 'Shell visual preset') }}</mat-label>
@@ -11409,9 +11420,7 @@ class PageConfigEditorComponent {
11409
11420
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
11410
11421
  }
11411
11422
  </mat-select>
11412
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="shellPresetHint" matTooltipPosition="above">
11413
- <mat-icon>help_outline</mat-icon>
11414
- </button>
11423
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="shellPresetHint" [attr.aria-label]="shellPresetHint" matTooltipPosition="above"></button>
11415
11424
  </mat-form-field>
11416
11425
  </div>
11417
11426
  </div>
@@ -11436,9 +11445,7 @@ class PageConfigEditorComponent {
11436
11445
  <div class="state-card" [formGroup]="group">
11437
11446
  <div class="state-card-head">
11438
11447
  <div class="state-card-title">{{ tx('editor.grouping.groupN', 'Group {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
11439
- <button mat-icon-button type="button" (click)="removeGroupingNode($index)" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')">
11440
- <mat-icon>delete</mat-icon>
11441
- </button>
11448
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeGroupingNode($index)" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')"></button>
11442
11449
  </div>
11443
11450
  <div class="state-card-grid">
11444
11451
  <mat-form-field appearance="outline">
@@ -11491,9 +11498,7 @@ class PageConfigEditorComponent {
11491
11498
  <mat-form-field appearance="outline" class="span-3">
11492
11499
  <mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label>
11493
11500
  <textarea matInput rows="5" formControlName="tabsJson"></textarea>
11494
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="tabsJsonHint" matTooltipPosition="above">
11495
- <mat-icon>help_outline</mat-icon>
11496
- </button>
11501
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="tabsJsonHint" [attr.aria-label]="tabsJsonHint" matTooltipPosition="above"></button>
11497
11502
  </mat-form-field>
11498
11503
  } @else {
11499
11504
  <mat-form-field appearance="outline" class="span-3">
@@ -11539,23 +11544,17 @@ class PageConfigEditorComponent {
11539
11544
  <mat-form-field appearance="outline" class="span-3">
11540
11545
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
11541
11546
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
11542
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
11543
- <mat-icon>help_outline</mat-icon>
11544
- </button>
11547
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
11545
11548
  </mat-form-field>
11546
11549
  <mat-form-field appearance="outline" class="span-3">
11547
11550
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
11548
11551
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
11549
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
11550
- <mat-icon>help_outline</mat-icon>
11551
- </button>
11552
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
11552
11553
  </mat-form-field>
11553
11554
  <mat-form-field appearance="outline" class="span-3">
11554
11555
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
11555
11556
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
11556
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
11557
- <mat-icon>help_outline</mat-icon>
11558
- </button>
11557
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
11559
11558
  </mat-form-field>
11560
11559
  </div>
11561
11560
  </div>
@@ -11581,23 +11580,17 @@ class PageConfigEditorComponent {
11581
11580
  <mat-form-field appearance="outline" class="span-3">
11582
11581
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
11583
11582
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
11584
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
11585
- <mat-icon>help_outline</mat-icon>
11586
- </button>
11583
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
11587
11584
  </mat-form-field>
11588
11585
  <mat-form-field appearance="outline" class="span-3">
11589
11586
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
11590
11587
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
11591
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
11592
- <mat-icon>help_outline</mat-icon>
11593
- </button>
11588
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
11594
11589
  </mat-form-field>
11595
11590
  <mat-form-field appearance="outline" class="span-3">
11596
11591
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
11597
11592
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
11598
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
11599
- <mat-icon>help_outline</mat-icon>
11600
- </button>
11593
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
11601
11594
  </mat-form-field>
11602
11595
  </div>
11603
11596
  </div>
@@ -11623,23 +11616,17 @@ class PageConfigEditorComponent {
11623
11616
  <mat-form-field appearance="outline" class="span-3">
11624
11617
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
11625
11618
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
11626
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
11627
- <mat-icon>help_outline</mat-icon>
11628
- </button>
11619
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
11629
11620
  </mat-form-field>
11630
11621
  <mat-form-field appearance="outline" class="span-3">
11631
11622
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
11632
11623
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
11633
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
11634
- <mat-icon>help_outline</mat-icon>
11635
- </button>
11624
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
11636
11625
  </mat-form-field>
11637
11626
  <mat-form-field appearance="outline" class="span-3">
11638
11627
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
11639
11628
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
11640
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
11641
- <mat-icon>help_outline</mat-icon>
11642
- </button>
11629
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
11643
11630
  </mat-form-field>
11644
11631
  </div>
11645
11632
  </div>
@@ -11658,15 +11645,15 @@ class PageConfigEditorComponent {
11658
11645
  <mat-label>{{ tx('editor.context.json', 'Context (JSON)') }}</mat-label>
11659
11646
  <textarea matInput rows="10" [formControl]="contextControl"></textarea>
11660
11647
  <button
11661
- mat-icon-button
11648
+ praxisIconButton="help_outline"
11649
+ size="dense"
11662
11650
  matSuffix
11663
11651
  class="help-icon-button"
11664
11652
  type="button"
11665
11653
  [matTooltip]="contextExample"
11654
+ [attr.aria-label]="contextExample"
11666
11655
  matTooltipPosition="above"
11667
- >
11668
- <mat-icon>help_outline</mat-icon>
11669
- </button>
11656
+ ></button>
11670
11657
  </mat-form-field>
11671
11658
  @if (contextError()) {
11672
11659
  <div class="page-error" role="alert">{{ contextError() }}</div>
@@ -11682,15 +11669,15 @@ class PageConfigEditorComponent {
11682
11669
  <mat-label>{{ tx('editor.state.valuesJson', 'Primary values (JSON)') }}</mat-label>
11683
11670
  <textarea matInput rows="10" [formControl]="stateValuesControl"></textarea>
11684
11671
  <button
11685
- mat-icon-button
11672
+ praxisIconButton="help_outline"
11673
+ size="dense"
11686
11674
  matSuffix
11687
11675
  class="help-icon-button"
11688
11676
  type="button"
11689
11677
  [matTooltip]="stateValuesExample"
11678
+ [attr.aria-label]="stateValuesExample"
11690
11679
  matTooltipPosition="above"
11691
- >
11692
- <mat-icon>help_outline</mat-icon>
11693
- </button>
11680
+ ></button>
11694
11681
  </mat-form-field>
11695
11682
 
11696
11683
  <div class="state-group">
@@ -11710,9 +11697,7 @@ class PageConfigEditorComponent {
11710
11697
  <div class="state-card" [formGroup]="group">
11711
11698
  <div class="state-card-head">
11712
11699
  <div class="state-card-title">{{ tx('editor.state.nodeN', 'Node {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
11713
- <button mat-icon-button type="button" (click)="removeSchemaNode($index)" [attr.aria-label]="tx('editor.state.removeSchemaAria', 'Remove schema node')">
11714
- <mat-icon>delete</mat-icon>
11715
- </button>
11700
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeSchemaNode($index)" [attr.aria-label]="tx('editor.state.removeSchemaAria', 'Remove schema node')"></button>
11716
11701
  </div>
11717
11702
  <div class="state-card-grid">
11718
11703
  <mat-form-field appearance="outline">
@@ -11752,9 +11737,7 @@ class PageConfigEditorComponent {
11752
11737
  <mat-form-field appearance="outline" class="span-2">
11753
11738
  <mat-label>{{ tx('editor.state.initialJson', 'Initial (JSON)') }}</mat-label>
11754
11739
  <textarea matInput rows="4" formControlName="initialJson"></textarea>
11755
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="schemaInitialHint" matTooltipPosition="above">
11756
- <mat-icon>help_outline</mat-icon>
11757
- </button>
11740
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="schemaInitialHint" [attr.aria-label]="schemaInitialHint" matTooltipPosition="above"></button>
11758
11741
  </mat-form-field>
11759
11742
  } @else if (group.controls.initialMode.value === 'boolean') {
11760
11743
  <mat-form-field appearance="outline" class="span-2">
@@ -11802,9 +11785,7 @@ class PageConfigEditorComponent {
11802
11785
  <div class="state-card" [formGroup]="group">
11803
11786
  <div class="state-card-head">
11804
11787
  <div class="state-card-title">{{ tx('editor.state.derivedN', 'Derived {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
11805
- <button mat-icon-button type="button" (click)="removeDerivedNode($index)" [attr.aria-label]="tx('editor.state.removeDerivedAria', 'Remove derivation')">
11806
- <mat-icon>delete</mat-icon>
11807
- </button>
11788
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeDerivedNode($index)" [attr.aria-label]="tx('editor.state.removeDerivedAria', 'Remove derivation')"></button>
11808
11789
  </div>
11809
11790
  <div class="state-card-grid">
11810
11791
  <mat-form-field appearance="outline">
@@ -11862,9 +11843,7 @@ class PageConfigEditorComponent {
11862
11843
  <mat-form-field appearance="outline" class="span-2">
11863
11844
  <mat-label>{{ tx('editor.state.templateJson', 'Template (JSON)') }}</mat-label>
11864
11845
  <textarea matInput rows="4" formControlName="templateJson"></textarea>
11865
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="templateJsonHint" matTooltipPosition="above">
11866
- <mat-icon>help_outline</mat-icon>
11867
- </button>
11846
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="templateJsonHint" [attr.aria-label]="templateJsonHint" matTooltipPosition="above"></button>
11868
11847
  </mat-form-field>
11869
11848
  } @else if (group.controls.templateMode.value === 'boolean') {
11870
11849
  <mat-form-field appearance="outline" class="span-2">
@@ -11900,9 +11879,7 @@ class PageConfigEditorComponent {
11900
11879
  <mat-form-field appearance="outline" class="span-2">
11901
11880
  <mat-label>{{ tx('editor.state.optionsJson', 'Options (JSON)') }}</mat-label>
11902
11881
  <textarea matInput rows="4" formControlName="options"></textarea>
11903
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="transformerOptionsHint" matTooltipPosition="above">
11904
- <mat-icon>help_outline</mat-icon>
11905
- </button>
11882
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="transformerOptionsHint" [attr.aria-label]="transformerOptionsHint" matTooltipPosition="above"></button>
11906
11883
  </mat-form-field>
11907
11884
  }
11908
11885
  <mat-form-field appearance="outline" class="span-3">
@@ -11928,7 +11905,7 @@ class PageConfigEditorComponent {
11928
11905
  </div>
11929
11906
  }
11930
11907
  </div>
11931
- `, isInline: true, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.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:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.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"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11908
+ `, isInline: true, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{margin-right:-4px}.mat-mdc-form-field-icon-suffix{align-self:center}@media(max-width:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.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: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i7.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"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11932
11909
  }
11933
11910
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PageConfigEditorComponent, decorators: [{
11934
11911
  type: Component,
@@ -11940,7 +11917,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
11940
11917
  MatIconModule,
11941
11918
  MatSelectModule,
11942
11919
  MatTabsModule,
11943
- MatTooltipModule
11920
+ MatTooltipModule,
11921
+ PraxisIconButtonComponent,
11944
11922
  ], providers: [providePraxisPageBuilderI18n()], template: `
11945
11923
  <div class="page-config">
11946
11924
  <div class="page-head">
@@ -12016,9 +11994,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12016
11994
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
12017
11995
  }
12018
11996
  </mat-select>
12019
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="layoutPresetHint" matTooltipPosition="above">
12020
- <mat-icon>help_outline</mat-icon>
12021
- </button>
11997
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="layoutPresetHint" [attr.aria-label]="layoutPresetHint" matTooltipPosition="above"></button>
12022
11998
  </mat-form-field>
12023
11999
  <mat-form-field appearance="outline">
12024
12000
  <mat-label>{{ tx('editor.layout.themePreset', 'Theme preset') }}</mat-label>
@@ -12028,9 +12004,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12028
12004
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
12029
12005
  }
12030
12006
  </mat-select>
12031
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="themePresetHint" matTooltipPosition="above">
12032
- <mat-icon>help_outline</mat-icon>
12033
- </button>
12007
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="themePresetHint" [attr.aria-label]="themePresetHint" matTooltipPosition="above"></button>
12034
12008
  </mat-form-field>
12035
12009
  <mat-form-field appearance="outline">
12036
12010
  <mat-label>{{ tx('editor.layout.shellPreset', 'Shell visual preset') }}</mat-label>
@@ -12040,9 +12014,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12040
12014
  <mat-option [value]="preset.id">{{ preset.label }}</mat-option>
12041
12015
  }
12042
12016
  </mat-select>
12043
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="shellPresetHint" matTooltipPosition="above">
12044
- <mat-icon>help_outline</mat-icon>
12045
- </button>
12017
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="shellPresetHint" [attr.aria-label]="shellPresetHint" matTooltipPosition="above"></button>
12046
12018
  </mat-form-field>
12047
12019
  </div>
12048
12020
  </div>
@@ -12067,9 +12039,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12067
12039
  <div class="state-card" [formGroup]="group">
12068
12040
  <div class="state-card-head">
12069
12041
  <div class="state-card-title">{{ tx('editor.grouping.groupN', 'Group {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
12070
- <button mat-icon-button type="button" (click)="removeGroupingNode($index)" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')">
12071
- <mat-icon>delete</mat-icon>
12072
- </button>
12042
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeGroupingNode($index)" [attr.aria-label]="tx('editor.grouping.removeAria', 'Remove group')"></button>
12073
12043
  </div>
12074
12044
  <div class="state-card-grid">
12075
12045
  <mat-form-field appearance="outline">
@@ -12122,9 +12092,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12122
12092
  <mat-form-field appearance="outline" class="span-3">
12123
12093
  <mat-label>{{ tx('editor.grouping.tabsJson', 'Tabs (JSON)') }}</mat-label>
12124
12094
  <textarea matInput rows="5" formControlName="tabsJson"></textarea>
12125
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="tabsJsonHint" matTooltipPosition="above">
12126
- <mat-icon>help_outline</mat-icon>
12127
- </button>
12095
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="tabsJsonHint" [attr.aria-label]="tabsJsonHint" matTooltipPosition="above"></button>
12128
12096
  </mat-form-field>
12129
12097
  } @else {
12130
12098
  <mat-form-field appearance="outline" class="span-3">
@@ -12170,23 +12138,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12170
12138
  <mat-form-field appearance="outline" class="span-3">
12171
12139
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
12172
12140
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
12173
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
12174
- <mat-icon>help_outline</mat-icon>
12175
- </button>
12141
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
12176
12142
  </mat-form-field>
12177
12143
  <mat-form-field appearance="outline" class="span-3">
12178
12144
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
12179
12145
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
12180
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
12181
- <mat-icon>help_outline</mat-icon>
12182
- </button>
12146
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
12183
12147
  </mat-form-field>
12184
12148
  <mat-form-field appearance="outline" class="span-3">
12185
12149
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
12186
12150
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
12187
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
12188
- <mat-icon>help_outline</mat-icon>
12189
- </button>
12151
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
12190
12152
  </mat-form-field>
12191
12153
  </div>
12192
12154
  </div>
@@ -12212,23 +12174,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12212
12174
  <mat-form-field appearance="outline" class="span-3">
12213
12175
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
12214
12176
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
12215
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
12216
- <mat-icon>help_outline</mat-icon>
12217
- </button>
12177
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
12218
12178
  </mat-form-field>
12219
12179
  <mat-form-field appearance="outline" class="span-3">
12220
12180
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
12221
12181
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
12222
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
12223
- <mat-icon>help_outline</mat-icon>
12224
- </button>
12182
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
12225
12183
  </mat-form-field>
12226
12184
  <mat-form-field appearance="outline" class="span-3">
12227
12185
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
12228
12186
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
12229
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
12230
- <mat-icon>help_outline</mat-icon>
12231
- </button>
12187
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
12232
12188
  </mat-form-field>
12233
12189
  </div>
12234
12190
  </div>
@@ -12254,23 +12210,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12254
12210
  <mat-form-field appearance="outline" class="span-3">
12255
12211
  <mat-label>{{ tx('editor.devices.breakpointsJson', 'Breakpoints (JSON)') }}</mat-label>
12256
12212
  <textarea matInput rows="3" formControlName="breakpointsJson"></textarea>
12257
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" matTooltipPosition="above">
12258
- <mat-icon>help_outline</mat-icon>
12259
- </button>
12213
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="breakpointsHint" [attr.aria-label]="breakpointsHint" matTooltipPosition="above"></button>
12260
12214
  </mat-form-field>
12261
12215
  <mat-form-field appearance="outline" class="span-3">
12262
12216
  <mat-label>{{ tx('editor.devices.groupingOverridesJson', 'Grouping overrides (JSON)') }}</mat-label>
12263
12217
  <textarea matInput rows="4" formControlName="groupingOverridesJson"></textarea>
12264
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" matTooltipPosition="above">
12265
- <mat-icon>help_outline</mat-icon>
12266
- </button>
12218
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="groupingOverridesHint" [attr.aria-label]="groupingOverridesHint" matTooltipPosition="above"></button>
12267
12219
  </mat-form-field>
12268
12220
  <mat-form-field appearance="outline" class="span-3">
12269
12221
  <mat-label>{{ tx('editor.devices.widgetOverridesJson', 'Widget overrides (JSON)') }}</mat-label>
12270
12222
  <textarea matInput rows="4" formControlName="widgetOverridesJson"></textarea>
12271
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" matTooltipPosition="above">
12272
- <mat-icon>help_outline</mat-icon>
12273
- </button>
12223
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="widgetOverridesHint" [attr.aria-label]="widgetOverridesHint" matTooltipPosition="above"></button>
12274
12224
  </mat-form-field>
12275
12225
  </div>
12276
12226
  </div>
@@ -12289,15 +12239,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12289
12239
  <mat-label>{{ tx('editor.context.json', 'Context (JSON)') }}</mat-label>
12290
12240
  <textarea matInput rows="10" [formControl]="contextControl"></textarea>
12291
12241
  <button
12292
- mat-icon-button
12242
+ praxisIconButton="help_outline"
12243
+ size="dense"
12293
12244
  matSuffix
12294
12245
  class="help-icon-button"
12295
12246
  type="button"
12296
12247
  [matTooltip]="contextExample"
12248
+ [attr.aria-label]="contextExample"
12297
12249
  matTooltipPosition="above"
12298
- >
12299
- <mat-icon>help_outline</mat-icon>
12300
- </button>
12250
+ ></button>
12301
12251
  </mat-form-field>
12302
12252
  @if (contextError()) {
12303
12253
  <div class="page-error" role="alert">{{ contextError() }}</div>
@@ -12313,15 +12263,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12313
12263
  <mat-label>{{ tx('editor.state.valuesJson', 'Primary values (JSON)') }}</mat-label>
12314
12264
  <textarea matInput rows="10" [formControl]="stateValuesControl"></textarea>
12315
12265
  <button
12316
- mat-icon-button
12266
+ praxisIconButton="help_outline"
12267
+ size="dense"
12317
12268
  matSuffix
12318
12269
  class="help-icon-button"
12319
12270
  type="button"
12320
12271
  [matTooltip]="stateValuesExample"
12272
+ [attr.aria-label]="stateValuesExample"
12321
12273
  matTooltipPosition="above"
12322
- >
12323
- <mat-icon>help_outline</mat-icon>
12324
- </button>
12274
+ ></button>
12325
12275
  </mat-form-field>
12326
12276
 
12327
12277
  <div class="state-group">
@@ -12341,9 +12291,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12341
12291
  <div class="state-card" [formGroup]="group">
12342
12292
  <div class="state-card-head">
12343
12293
  <div class="state-card-title">{{ tx('editor.state.nodeN', 'Node {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
12344
- <button mat-icon-button type="button" (click)="removeSchemaNode($index)" [attr.aria-label]="tx('editor.state.removeSchemaAria', 'Remove schema node')">
12345
- <mat-icon>delete</mat-icon>
12346
- </button>
12294
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeSchemaNode($index)" [attr.aria-label]="tx('editor.state.removeSchemaAria', 'Remove schema node')"></button>
12347
12295
  </div>
12348
12296
  <div class="state-card-grid">
12349
12297
  <mat-form-field appearance="outline">
@@ -12383,9 +12331,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12383
12331
  <mat-form-field appearance="outline" class="span-2">
12384
12332
  <mat-label>{{ tx('editor.state.initialJson', 'Initial (JSON)') }}</mat-label>
12385
12333
  <textarea matInput rows="4" formControlName="initialJson"></textarea>
12386
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="schemaInitialHint" matTooltipPosition="above">
12387
- <mat-icon>help_outline</mat-icon>
12388
- </button>
12334
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="schemaInitialHint" [attr.aria-label]="schemaInitialHint" matTooltipPosition="above"></button>
12389
12335
  </mat-form-field>
12390
12336
  } @else if (group.controls.initialMode.value === 'boolean') {
12391
12337
  <mat-form-field appearance="outline" class="span-2">
@@ -12433,9 +12379,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12433
12379
  <div class="state-card" [formGroup]="group">
12434
12380
  <div class="state-card-head">
12435
12381
  <div class="state-card-title">{{ tx('editor.state.derivedN', 'Derived {{index}}').replace('{{index}}', '' + ($index + 1)) }}</div>
12436
- <button mat-icon-button type="button" (click)="removeDerivedNode($index)" [attr.aria-label]="tx('editor.state.removeDerivedAria', 'Remove derivation')">
12437
- <mat-icon>delete</mat-icon>
12438
- </button>
12382
+ <button praxisIconButton="delete" size="compact" type="button" (click)="removeDerivedNode($index)" [attr.aria-label]="tx('editor.state.removeDerivedAria', 'Remove derivation')"></button>
12439
12383
  </div>
12440
12384
  <div class="state-card-grid">
12441
12385
  <mat-form-field appearance="outline">
@@ -12493,9 +12437,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12493
12437
  <mat-form-field appearance="outline" class="span-2">
12494
12438
  <mat-label>{{ tx('editor.state.templateJson', 'Template (JSON)') }}</mat-label>
12495
12439
  <textarea matInput rows="4" formControlName="templateJson"></textarea>
12496
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="templateJsonHint" matTooltipPosition="above">
12497
- <mat-icon>help_outline</mat-icon>
12498
- </button>
12440
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="templateJsonHint" [attr.aria-label]="templateJsonHint" matTooltipPosition="above"></button>
12499
12441
  </mat-form-field>
12500
12442
  } @else if (group.controls.templateMode.value === 'boolean') {
12501
12443
  <mat-form-field appearance="outline" class="span-2">
@@ -12531,9 +12473,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12531
12473
  <mat-form-field appearance="outline" class="span-2">
12532
12474
  <mat-label>{{ tx('editor.state.optionsJson', 'Options (JSON)') }}</mat-label>
12533
12475
  <textarea matInput rows="4" formControlName="options"></textarea>
12534
- <button mat-icon-button matSuffix class="help-icon-button" type="button" [matTooltip]="transformerOptionsHint" matTooltipPosition="above">
12535
- <mat-icon>help_outline</mat-icon>
12536
- </button>
12476
+ <button praxisIconButton="help_outline" size="dense" matSuffix class="help-icon-button" type="button" [matTooltip]="transformerOptionsHint" [attr.aria-label]="transformerOptionsHint" matTooltipPosition="above"></button>
12537
12477
  </mat-form-field>
12538
12478
  }
12539
12479
  <mat-form-field appearance="outline" class="span-3">
@@ -12559,7 +12499,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
12559
12499
  </div>
12560
12500
  }
12561
12501
  </div>
12562
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.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:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"] }]
12502
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".page-config{display:grid;gap:12px;padding:16px;background:var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:12px}.page-head{display:flex;align-items:flex-start;gap:12px}.page-head__copy{display:grid;gap:4px}.page-title{font-weight:600;font-size:18px;line-height:1.2}.page-subtitle{max-width:72ch;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.spacer{flex:1}.page-summary{display:flex;flex-wrap:wrap;gap:8px}.page-tabs{border-radius:16px;overflow:hidden;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent)}.page-tabs ::ng-deep .mdc-tab{min-width:120px}.page-tabs ::ng-deep .mdc-tab__text-label{font-size:13px;font-weight:600}.page-tab-panel{display:grid;gap:12px;padding:16px 4px 4px}.page-chip{display:inline-flex;align-items:center;gap:8px;min-height:36px;padding:0 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 88%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 82%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:500}.page-chip mat-icon{width:18px;height:18px;font-size:18px}.page-chip--accent{border-color:color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 30%,transparent)}.page-chip--warning{border-color:color-mix(in srgb,var(--md-sys-color-error) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 35%,transparent)}.page-identity{display:grid;gap:4px;padding:12px 14px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 70%,transparent);font-size:13px;color:var(--md-sys-color-on-surface-variant)}.page-section{font-weight:600;margin-top:8px}.page-section-help{margin-top:-4px;color:var(--md-sys-color-on-surface-variant);font-size:13px;line-height:1.45}.grid-form{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.state-grid{display:grid;gap:16px}.state-values,.state-group{padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:14px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface-container-low) 92%,transparent),transparent),var(--md-sys-color-surface-container-lowest, var(--md-sys-color-surface))}.state-group{display:grid;gap:12px}.state-group-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-group-title{font-weight:600}.state-group-help{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-list{display:grid;gap:12px}.state-card{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container) 84%,transparent)}.state-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px}.state-card-title{font-weight:600}.state-card-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:1 / -1}.state-empty{color:var(--md-sys-color-on-surface-variant);font-size:13px}.state-operator-hint{display:flex;align-items:center;gap:8px;min-height:48px;padding:0 12px;border-radius:12px;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-secondary-container) 35%,transparent)}.state-operator-hint mat-icon{color:var(--md-sys-color-secondary)}.page-actions{display:flex;justify-content:flex-end}.page-error{color:var(--md-sys-color-error);font-size:13px}.page-config .mat-mdc-form-field{width:100%;--mdc-outlined-text-field-container-height: 48px;--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-outline);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-error-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-focus-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-error-hover-outline-color: var(--md-sys-color-error);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-supporting-text-color: var(--md-sys-color-on-surface-variant)}.help-icon-button{margin-right:-4px}.mat-mdc-form-field-icon-suffix{align-self:center}@media(max-width:720px){.span-2,.span-3{grid-column:auto}.page-head{flex-direction:column}.state-group-head{align-items:stretch;flex-direction:column}}\n"] }]
12563
12503
  }], ctorParameters: () => [], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }], identity: [{ type: i0.Input, args: [{ isSignal: true, alias: "identity", required: false }] }], layoutCompatOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "layoutCompatOptions", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }] } });
12564
12504
 
12565
12505
  /**
@@ -14806,10 +14746,12 @@ class PageBuilderAiAdapter {
14806
14746
  const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
14807
14747
  const widgets = (cloned.widgets || [])
14808
14748
  .map((w) => normalizePageBuilderRuntimeWidget(this.stripLegacyLayoutFields(w)));
14749
+ const canvas = this.ensureCanvasLayout(cloned);
14809
14750
  return {
14810
14751
  ...rest,
14811
14752
  widgets,
14812
- canvas: this.ensureCanvasLayout(cloned),
14753
+ canvas,
14754
+ deviceLayouts: this.ensureDeviceLayouts(cloned.deviceLayouts, canvas),
14813
14755
  };
14814
14756
  }
14815
14757
  normalizeConfigForRuntime(config, warnings) {
@@ -14827,10 +14769,12 @@ class PageBuilderAiAdapter {
14827
14769
  const { [LEGACY_OPTIONS_KEY]: _legacyOptions, ...rest } = cloned;
14828
14770
  const widgets = (cloned.widgets || [])
14829
14771
  .map((w) => normalizePageBuilderRuntimeWidget(this.stripLegacyLayoutFields(w)));
14772
+ const canvas = this.ensureCanvasLayout(cloned, warnings);
14830
14773
  return {
14831
14774
  ...rest,
14832
14775
  widgets,
14833
- canvas: this.ensureCanvasLayout(cloned, warnings),
14776
+ canvas,
14777
+ deviceLayouts: this.ensureDeviceLayouts(cloned.deviceLayouts, canvas, warnings),
14834
14778
  };
14835
14779
  }
14836
14780
  normalizePatch(patch, base, warnings) {
@@ -15049,16 +14993,123 @@ class PageBuilderAiAdapter {
15049
14993
  nextRow = items[key].row + items[key].rowSpan - 1;
15050
14994
  warnings.push(`Widget "${key}" missing canvas placement; using defaults.`);
15051
14995
  }
14996
+ const columns = Math.max(1, this.coerceInteger(baseCanvas.columns, legacyOptions?.cols || 12));
14997
+ const normalizedItems = this.resolveCanvasCollisions(items, columns, warnings, 'base');
15052
14998
  return {
15053
14999
  mode: 'grid',
15054
- columns: baseCanvas.columns || legacyOptions?.cols || 12,
15000
+ columns,
15055
15001
  rowUnit: baseCanvas.rowUnit || (typeof legacyOptions?.rowHeight === 'number' ? `${legacyOptions.rowHeight}px` : '80px'),
15056
15002
  gap: baseCanvas.gap || (typeof legacyOptions?.gap === 'number' ? `${legacyOptions.gap}px` : '16px'),
15057
15003
  autoRows: baseCanvas.autoRows || 'fixed',
15058
15004
  collisionPolicy: baseCanvas.collisionPolicy,
15059
- items,
15005
+ items: normalizedItems,
15060
15006
  };
15061
15007
  }
15008
+ ensureDeviceLayouts(deviceLayouts, baseCanvas, warnings = []) {
15009
+ if (!deviceLayouts)
15010
+ return deviceLayouts;
15011
+ const normalized = this.clone(deviceLayouts);
15012
+ for (const device of ['desktop', 'tablet', 'mobile']) {
15013
+ const variant = normalized[device];
15014
+ if (!variant?.canvas)
15015
+ continue;
15016
+ const columns = Math.max(1, this.coerceInteger(variant.canvas.columns, baseCanvas.columns));
15017
+ const overrides = variant.canvas.items || {};
15018
+ const effectiveItems = {};
15019
+ for (const [key, baseItem] of Object.entries(baseCanvas.items)) {
15020
+ const override = overrides[key];
15021
+ if (override?.hidden)
15022
+ continue;
15023
+ effectiveItems[key] = {
15024
+ ...baseItem,
15025
+ ...(override || {}),
15026
+ col: this.coerceInteger(override?.col, baseItem.col),
15027
+ row: this.coerceInteger(override?.row, baseItem.row),
15028
+ colSpan: this.coerceInteger(override?.colSpan, baseItem.colSpan),
15029
+ rowSpan: this.coerceInteger(override?.rowSpan, baseItem.rowSpan),
15030
+ };
15031
+ }
15032
+ const resolvedItems = this.resolveCanvasCollisions(effectiveItems, columns, warnings, device);
15033
+ const nextOverrides = this.clone(overrides);
15034
+ for (const [key, item] of Object.entries(resolvedItems)) {
15035
+ const baseItem = baseCanvas.items[key];
15036
+ const currentOverride = overrides[key];
15037
+ const differsFromBase = !baseItem
15038
+ || item.col !== baseItem.col
15039
+ || item.row !== baseItem.row
15040
+ || item.colSpan !== baseItem.colSpan
15041
+ || item.rowSpan !== baseItem.rowSpan;
15042
+ if (!currentOverride && !differsFromBase)
15043
+ continue;
15044
+ nextOverrides[key] = {
15045
+ ...(currentOverride || {}),
15046
+ col: item.col,
15047
+ row: item.row,
15048
+ colSpan: item.colSpan,
15049
+ rowSpan: item.rowSpan,
15050
+ };
15051
+ }
15052
+ variant.canvas = {
15053
+ ...variant.canvas,
15054
+ columns,
15055
+ items: nextOverrides,
15056
+ };
15057
+ }
15058
+ return normalized;
15059
+ }
15060
+ resolveCanvasCollisions(items, columns, warnings, scope) {
15061
+ const candidates = Object.entries(items)
15062
+ .map(([key, source], index) => {
15063
+ const colSpan = Math.min(columns, Math.max(1, this.coerceInteger(source.colSpan, 1)));
15064
+ return {
15065
+ key,
15066
+ index,
15067
+ source,
15068
+ desired: {
15069
+ col: Math.min(Math.max(1, this.coerceInteger(source.col, 1)), Math.max(1, columns - colSpan + 1)),
15070
+ row: Math.max(1, this.coerceInteger(source.row, 1)),
15071
+ colSpan,
15072
+ rowSpan: Math.max(1, this.coerceInteger(source.rowSpan, 1)),
15073
+ },
15074
+ };
15075
+ })
15076
+ .sort((left, right) => left.desired.row - right.desired.row
15077
+ || left.desired.col - right.desired.col
15078
+ || left.index - right.index);
15079
+ const placed = [];
15080
+ const resolved = {};
15081
+ for (const candidate of candidates) {
15082
+ const item = this.findAvailableCanvasPosition(candidate.desired, placed, columns);
15083
+ resolved[candidate.key] = { ...candidate.source, ...item };
15084
+ placed.push({ key: candidate.key, item: resolved[candidate.key] });
15085
+ if (item.col !== candidate.desired.col || item.row !== candidate.desired.row) {
15086
+ warnings.push(`Widget "${candidate.key}" overlapped another widget in the ${scope} canvas; moved to row ${item.row}, column ${item.col}.`);
15087
+ }
15088
+ }
15089
+ return resolved;
15090
+ }
15091
+ findAvailableCanvasPosition(desired, placed, columns) {
15092
+ const maxCol = Math.max(1, columns - desired.colSpan + 1);
15093
+ const candidateCols = [
15094
+ desired.col,
15095
+ ...Array.from({ length: maxCol }, (_, index) => index + 1)
15096
+ .filter((col) => col !== desired.col),
15097
+ ];
15098
+ for (let row = desired.row;; row += 1) {
15099
+ for (const col of candidateCols) {
15100
+ const candidate = { ...desired, col, row };
15101
+ const collides = placed.some(({ item }) => this.canvasItemsOverlap(candidate, item));
15102
+ if (!collides)
15103
+ return candidate;
15104
+ }
15105
+ }
15106
+ }
15107
+ canvasItemsOverlap(left, right) {
15108
+ return left.col < right.col + right.colSpan
15109
+ && left.col + left.colSpan > right.col
15110
+ && left.row < right.row + right.rowSpan
15111
+ && left.row + left.rowSpan > right.row;
15112
+ }
15062
15113
  stripLegacyLayoutFields(widget) {
15063
15114
  const { x: _x, y: _y, cols: _cols, rows: _rows, minItemCols: _minItemCols, minItemRows: _minItemRows, maxItemCols: _maxItemCols, maxItemRows: _maxItemRows, ...rest } = widget;
15064
15115
  delete rest[LEGACY_LAYOUT_KEY];
@@ -15178,6 +15229,10 @@ class PageBuilderAiAdapter {
15178
15229
  coerceNumber(value, fallback) {
15179
15230
  return typeof value === 'number' && !Number.isNaN(value) ? value : fallback;
15180
15231
  }
15232
+ coerceInteger(value, fallback) {
15233
+ const numeric = this.coerceNumber(value, fallback);
15234
+ return Number.isFinite(numeric) ? Math.trunc(numeric) : fallback;
15235
+ }
15181
15236
  parsePixelValue(value) {
15182
15237
  if (typeof value !== 'string')
15183
15238
  return undefined;
@@ -15216,6 +15271,11 @@ class PageBuilderAgenticAuthoringTurnFlow {
15216
15271
  phase: 'capture',
15217
15272
  });
15218
15273
  }
15274
+ if (this.context.enableTurnStream?.() === true && this.service.streamTurn) {
15275
+ if (this.hasCanonicalSemanticDecision(request)) {
15276
+ return this.submitWithTurnStream(request, prompt);
15277
+ }
15278
+ }
15219
15279
  const contextualActionContext = this.contextualPreviewActionContextFromRequest(request);
15220
15280
  if (contextualActionContext) {
15221
15281
  return from(this.submitContextualPreviewAction(request, prompt, contextualActionContext));
@@ -15413,6 +15473,9 @@ class PageBuilderAgenticAuthoringTurnFlow {
15413
15473
  clientTurnId: request.clientTurnId ?? event.turnId,
15414
15474
  })))), share());
15415
15475
  return merge(of(this.toTurnStreamPreparationStatusResult()), preparedRequest$.pipe(map(({ diagnostics }) => this.toTurnStreamPreparedStatusResult(diagnostics))), timer(TURN_STREAM_PREPARATION_WAITING_MS).pipe(map(() => this.toTurnStreamPreparationWaitingResult()), takeUntil(stream$)), stream$).pipe(catchError((error) => {
15476
+ if (this.hasCanonicalSemanticDecision(request)) {
15477
+ return of(this.toTurnStreamTransportErrorResult(error));
15478
+ }
15416
15479
  if (this.shouldFailClosedFromTurnStreamError(request, prompt, error)) {
15417
15480
  return of(this.toGovernedRouteFailClosedResult(request, prompt, error));
15418
15481
  }
@@ -16121,10 +16184,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
16121
16184
  queryContext: { filters: {} },
16122
16185
  enableCustomization: true,
16123
16186
  chartDocument: {
16124
- version: '1.0.0',
16187
+ version: '0.1.0',
16125
16188
  chartId: chartKey,
16126
16189
  kind: 'bar',
16127
- preset: 'dashboard-breakdown',
16190
+ preset: 'distribution',
16128
16191
  title: `Distribuicao por ${this.humanizeFieldName(categoryField)}`,
16129
16192
  subtitle: 'Clique em uma barra para refinar os detalhes',
16130
16193
  source: {
@@ -16132,14 +16195,12 @@ class PageBuilderAgenticAuthoringTurnFlow {
16132
16195
  resource: resourcePath,
16133
16196
  operation: 'group-by',
16134
16197
  options: {
16135
- groupBy: categoryField,
16136
- metric: 'count',
16137
16198
  orderBy: 'value-desc',
16138
16199
  limit: 12,
16139
16200
  },
16140
16201
  },
16141
16202
  dimensions: [{ field: categoryField, label: this.humanizeFieldName(categoryField), role: 'category' }],
16142
- metrics: [{ field: 'count', label: 'Registros', aggregation: 'count', seriesKind: 'bar' }],
16203
+ metrics: [{ field: 'total', label: 'Registros', aggregation: 'count', seriesKind: 'bar' }],
16143
16204
  legend: false,
16144
16205
  labels: true,
16145
16206
  tooltip: true,
@@ -16413,11 +16474,11 @@ class PageBuilderAgenticAuthoringTurnFlow {
16413
16474
  if (reservedKpiKey) {
16414
16475
  return reservedKpiKey;
16415
16476
  }
16416
- const resourceSegment = this.dashboardRepairResourcePath(contextHints)
16477
+ const resourcePathSegments = this.dashboardRepairResourcePath(contextHints)
16417
16478
  .split('?')[0]
16418
16479
  .split('/')
16419
- .filter(Boolean)
16420
- .at(-1)
16480
+ .filter(Boolean);
16481
+ const resourceSegment = resourcePathSegments[resourcePathSegments.length - 1]
16421
16482
  ?.normalize('NFD')
16422
16483
  .replace(/[\u0300-\u036f]/g, '')
16423
16484
  .toLowerCase()
@@ -17047,7 +17108,13 @@ class PageBuilderAgenticAuthoringTurnFlow {
17047
17108
  const contextualExecutableIntent = request
17048
17109
  ? this.toExecutableContextualComponentIntent(intentResolution, request)
17049
17110
  : null;
17050
- if (!backendCanApply && contextualExecutableIntent && request && prompt) {
17111
+ if (!backendCanApply
17112
+ && contextualExecutableIntent
17113
+ && request
17114
+ && prompt
17115
+ && (!this.hasCanonicalSemanticDecision(request)
17116
+ && !this.hasStructuredContinuationAction(request)
17117
+ || this.hasMaterializablePreview(preview))) {
17051
17118
  return this.completeExecutableStreamPreview(request, prompt, contextualExecutableIntent, preview, preparedContextHints);
17052
17119
  }
17053
17120
  if (!canApply) {
@@ -17103,7 +17170,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
17103
17170
  || (!!prompt && this.shouldAutoGenerateGuidedPreview(intentResolution, quickReplies, prompt)))
17104
17171
  && !this.hasBlockingResourceQuickReply(quickReplies)
17105
17172
  && request
17106
- && prompt) {
17173
+ && prompt
17174
+ && (!this.hasCanonicalSemanticDecision(request)
17175
+ && !this.hasStructuredContinuationAction(request)
17176
+ || this.hasMaterializablePreview(preview))) {
17107
17177
  return this.completeExecutableStreamPreview(request, prompt, intentResolution, preview, preparedContextHints);
17108
17178
  }
17109
17179
  const requiresChoice = quickReplies.length > 0 && !this.isConsultativeCatalogIntent(intentResolution);
@@ -18002,7 +18072,7 @@ class PageBuilderAgenticAuthoringTurnFlow {
18002
18072
  return status;
18003
18073
  }
18004
18074
  const suffix = this.context
18005
- .tx('agentic.dashboardQuality.degraded', 'Dashboard created with quality warnings: {warnings}. Review diagnostics before saving.')
18075
+ .tx('agentic.dashboardQuality.degraded', 'A prévia está pronta para revisão. Antes de salvar, recomendo completar: {warnings}. Você pode pedir esse ajuste agora pelas ações sugeridas.')
18006
18076
  .replace('{warnings}', labels.join(', '));
18007
18077
  const normalized = status.trim();
18008
18078
  return normalized ? `${normalized} ${suffix}` : suffix;
@@ -18484,6 +18554,15 @@ class PageBuilderAgenticAuthoringTurnFlow {
18484
18554
  return this.shouldFallbackFromTurnStreamError(error)
18485
18555
  && this.isGovernedSemanticDecisionRequest(request, prompt);
18486
18556
  }
18557
+ hasCanonicalSemanticDecision(request) {
18558
+ return this.toJsonObject(request.activeSemanticDecision) !== null;
18559
+ }
18560
+ hasStructuredContinuationAction(request) {
18561
+ const action = this.toJsonObject(request.action);
18562
+ return action !== null
18563
+ && !!this.readString(action, 'id')
18564
+ && !!this.readString(action, 'kind');
18565
+ }
18487
18566
  isGovernedSemanticDecisionRequest(request, prompt) {
18488
18567
  const contextHints = this.buildContextHints(request);
18489
18568
  const domainCatalog = this.toJsonObject(contextHints?.['domainCatalog']);
@@ -19327,8 +19406,10 @@ class PageBuilderAgenticAuthoringTurnFlow {
19327
19406
  description: reply.description,
19328
19407
  icon: reply.icon,
19329
19408
  tone: reply.tone,
19330
- presentation: null,
19409
+ presentation: this.toJsonObject(reply.presentation)
19410
+ ?? this.toJsonObject(this.toJsonObject(reply.contextHints)?.['presentation']),
19331
19411
  contextHints: this.toJsonObject(reply.contextHints),
19412
+ canonicalAction: this.toJsonObject(reply.canonicalAction),
19332
19413
  semanticDecision: this.toJsonObject(reply.semanticDecision),
19333
19414
  value: reply.value,
19334
19415
  }));
@@ -20063,7 +20144,7 @@ function projectKnowledgeTarget(changeSet, conceptKey) {
20063
20144
  };
20064
20145
  }
20065
20146
 
20066
- const AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS = 90_000;
20147
+ const AGENTIC_AUTHORING_TURN_INACTIVITY_TIMEOUT_MS = 180_000;
20067
20148
  const AGENTIC_PAGE_COMPOSITION_REQUEST_OUTPUT = 'agenticPageCompositionRequested';
20068
20149
  class DynamicPageBuilderComponent {
20069
20150
  dialog;
@@ -20100,6 +20181,7 @@ class DynamicPageBuilderComponent {
20100
20181
  agenticAuthoringEtag;
20101
20182
  agenticAuthoringIncludeLlmDiagnostics = false;
20102
20183
  agenticAuthoringEnableStreaming = false;
20184
+ agenticAuthoringVoiceInputMode = 'disabled';
20103
20185
  agenticAuthoringContextHints;
20104
20186
  showPageLifecycleActions = false;
20105
20187
  canDeleteSavedPage = false;
@@ -20170,7 +20252,7 @@ class DynamicPageBuilderComponent {
20170
20252
  agenticTurnController;
20171
20253
  agenticTurnCancel$ = new Subject();
20172
20254
  agenticTurnRunId = 0;
20173
- agenticAuthoringTurnTerminalTimeoutMs = AGENTIC_AUTHORING_TURN_TERMINAL_TIMEOUT_MS;
20255
+ agenticAuthoringTurnInactivityTimeoutMs = AGENTIC_AUTHORING_TURN_INACTIVITY_TIMEOUT_MS;
20174
20256
  sharedRuleHandoffRevision = 0;
20175
20257
  agenticAuthoringPanelLayoutTouched = false;
20176
20258
  observabilityMetricsSubscription;
@@ -21514,7 +21596,18 @@ class DynamicPageBuilderComponent {
21514
21596
  this.clearProjectKnowledgeCockpitState();
21515
21597
  this.agenticAuthoringStatus.set(this.tx('agentic.status.resolvingIntent', 'Entendendo o pedido...'));
21516
21598
  try {
21517
- const contextHints = action.contextHints ? { ...action.contextHints } : undefined;
21599
+ const actionContextHints = action.contextHints
21600
+ ? this.toRecord(this.cloneValue(action.contextHints)) ?? undefined
21601
+ : undefined;
21602
+ const contextHints = actionContextHints
21603
+ ? {
21604
+ ...actionContextHints,
21605
+ recommendedIntent: {
21606
+ id: intent.id,
21607
+ ...actionContextHints,
21608
+ },
21609
+ }
21610
+ : undefined;
21518
21611
  await this.consumeAgenticTurn(this.ensureAgenticTurnController().submitPrompt(prompt, {
21519
21612
  kind: 'recommended-intent',
21520
21613
  id: intent.id,
@@ -21548,6 +21641,9 @@ class DynamicPageBuilderComponent {
21548
21641
  return;
21549
21642
  }
21550
21643
  const contextHints = reply.contextHints ? { ...reply.contextHints } : undefined;
21644
+ const canonicalAction = reply.canonicalAction
21645
+ ? { ...reply.canonicalAction }
21646
+ : undefined;
21551
21647
  const activeSemanticDecision = reply.semanticDecision
21552
21648
  ? { ...reply.semanticDecision }
21553
21649
  : undefined;
@@ -21581,16 +21677,21 @@ class DynamicPageBuilderComponent {
21581
21677
  && !this.isGovernedConfirmationQuickReply(reply, contextHints)
21582
21678
  ? 'clarify'
21583
21679
  : replyKind || 'quick-reply';
21584
- await this.consumeAgenticTurn(controller.submitPrompt(submittedPrompt, {
21680
+ const turnStates$ = controller.submitPrompt(submittedPrompt, {
21585
21681
  kind: actionKind,
21586
21682
  id: reply.id,
21587
- value: reply.prompt,
21683
+ value: this.cloneValue(reply.value ?? reply.prompt),
21588
21684
  displayPrompt: visiblePrompt,
21589
- contextHints: activeSemanticDecision
21590
- ? { ...(contextHints ?? {}), semanticDecision: activeSemanticDecision }
21685
+ contextHints: canonicalAction || activeSemanticDecision
21686
+ ? {
21687
+ ...(contextHints ?? {}),
21688
+ ...(canonicalAction ? { canonicalAction } : {}),
21689
+ ...(activeSemanticDecision ? { semanticDecision: activeSemanticDecision } : {}),
21690
+ }
21591
21691
  : contextHints,
21592
21692
  activeSemanticDecision,
21593
- }), turnRunId);
21693
+ });
21694
+ await this.consumeAgenticTurn(turnStates$, turnRunId);
21594
21695
  this.agenticAuthoringPrompt.set('');
21595
21696
  }
21596
21697
  catch (error) {
@@ -21616,10 +21717,7 @@ class DynamicPageBuilderComponent {
21616
21717
  return (reply.label || prompt || this.tx('agentic.quickReplies.confirm', 'Confirm')).trim();
21617
21718
  }
21618
21719
  if (!this.isResourceQuickReply(reply, contextHints)) {
21619
- return prompt;
21620
- }
21621
- if (this.isHumanSafeResourceQuickReplyPrompt(prompt, contextHints)) {
21622
- return prompt;
21720
+ return (reply.label || prompt).trim();
21623
21721
  }
21624
21722
  const label = (reply.label || this.describeResourceContext(contextHints) || reply.prompt).trim();
21625
21723
  return this.tx('agentic.quickReplies.resourceSelectionPrompt', 'Usar {label} como fonte de dados.')
@@ -23122,10 +23220,10 @@ class DynamicPageBuilderComponent {
23122
23220
  return of(state);
23123
23221
  }
23124
23222
  return from(this.applyAgenticTurnState(state)).pipe(map(() => state));
23125
- }), filter((state) => this.isAgenticTurnTerminalState(state)), timeout({
23126
- first: this.agenticAuthoringTurnTerminalTimeoutMs,
23223
+ }), timeout({
23224
+ each: this.agenticAuthoringTurnInactivityTimeoutMs,
23127
23225
  with: () => of(this.createAgenticTurnTimeoutState()),
23128
- }), take(1))).then(async (state) => {
23226
+ }), filter((state) => this.isAgenticTurnTerminalState(state)), take(1))).then(async (state) => {
23129
23227
  if (this.isCurrentAgenticTurn(turnRunId) && this.isAgenticTurnTimeoutState(state)) {
23130
23228
  await this.applyAgenticTurnState(state);
23131
23229
  }
@@ -23175,7 +23273,8 @@ class DynamicPageBuilderComponent {
23175
23273
  timeout: {
23176
23274
  schemaVersion: 'praxis-page-builder-agentic-turn-timeout.v1',
23177
23275
  source: 'dynamic-page-builder',
23178
- elapsedMs: this.agenticAuthoringTurnTerminalTimeoutMs,
23276
+ elapsedMs: this.agenticAuthoringTurnInactivityTimeoutMs,
23277
+ timeoutKind: 'inactivity',
23179
23278
  },
23180
23279
  },
23181
23280
  };
@@ -23340,6 +23439,9 @@ class DynamicPageBuilderComponent {
23340
23439
  if (normalized === 'not_requested') {
23341
23440
  return this.tx('agentic.context.governedDomainContextNotRequested', 'Not requested');
23342
23441
  }
23442
+ if (normalized === 'not_recaptured_for_diagnostics') {
23443
+ return this.tx('agentic.context.governedDomainContextUsedInDecision', 'Used in the semantic decision');
23444
+ }
23343
23445
  return this.tx('agentic.context.governedDomainContextUnknown', 'unknown');
23344
23446
  }
23345
23447
  trimmedString(value) {
@@ -23526,7 +23628,7 @@ class DynamicPageBuilderComponent {
23526
23628
  case 'rejected-duplicate-field':
23527
23629
  return this.tx('agentic.errors.duplicateField', 'Este campo já existe no formulário selecionado.');
23528
23630
  case 'rejected-non-local-field-removal':
23529
- return this.tx('agentic.errors.nonLocalFieldRemoval', ' posso remover, por aqui, campos que foram criados nesta própria prévia.');
23631
+ return this.tx('agentic.errors.nonLocalFieldRemoval', 'Somente campos locais criados pela IA podem ser removidos neste fluxo.');
23530
23632
  default:
23531
23633
  break;
23532
23634
  }
@@ -23621,7 +23723,7 @@ class DynamicPageBuilderComponent {
23621
23723
  return resolvePraxisPageBuilderText(this.i18n, key, fallback);
23622
23724
  }
23623
23725
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicPageBuilderComponent, deps: [{ token: i1.MatDialog }, { token: SETTINGS_PANEL_BRIDGE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
23624
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
23726
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicPageBuilderComponent, isStandalone: true, selector: "praxis-dynamic-page-builder", inputs: { page: "page", context: "context", strictValidation: "strictValidation", autoPersist: "autoPersist", enableCustomization: "enableCustomization", showSettingsButton: "showSettingsButton", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", pageEditorComponent: "pageEditorComponent", componentPaletteAllowedWidgetIds: "componentPaletteAllowedWidgetIds", componentPaletteAllowedWidgetTags: "componentPaletteAllowedWidgetTags", componentPaletteAllowedPresetIds: "componentPaletteAllowedPresetIds", enableAgenticAuthoring: "enableAgenticAuthoring", agenticAuthoringProvider: "agenticAuthoringProvider", agenticAuthoringModel: "agenticAuthoringModel", agenticAuthoringApiKey: "agenticAuthoringApiKey", agenticAuthoringComponentId: "agenticAuthoringComponentId", agenticAuthoringScope: "agenticAuthoringScope", agenticAuthoringEtag: "agenticAuthoringEtag", agenticAuthoringIncludeLlmDiagnostics: "agenticAuthoringIncludeLlmDiagnostics", agenticAuthoringEnableStreaming: "agenticAuthoringEnableStreaming", agenticAuthoringVoiceInputMode: "agenticAuthoringVoiceInputMode", agenticAuthoringContextHints: "agenticAuthoringContextHints", showPageLifecycleActions: "showPageLifecycleActions", canDeleteSavedPage: "canDeleteSavedPage", pageLifecycleBusy: "pageLifecycleBusy", pageLifecycleResetRevision: "pageLifecycleResetRevision" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", pageSaveRequested: "pageSaveRequested", agenticAuthoringApplied: "agenticAuthoringApplied", agenticAuthoringSharedRuleHandoff: "agenticAuthoringSharedRuleHandoff", pageRestart: "pageRestart", savedPageDeleteRequested: "savedPageDeleteRequested" }, providers: [
23625
23727
  providePraxisPageBuilderI18n(),
23626
23728
  { provide: DYNAMIC_PAGE_SHELL_EDITOR, useValue: WidgetShellEditorComponent },
23627
23729
  ], viewQueries: [{ propertyName: "runtime", first: true, predicate: ["runtime"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -23719,6 +23821,7 @@ class DynamicPageBuilderComponent {
23719
23821
  [primaryAction]="agenticAuthoringSubmitAction()"
23720
23822
  [showAttachAction]="false"
23721
23823
  [enablePastedAttachments]="false"
23824
+ [voiceInputMode]="agenticAuthoringVoiceInputMode"
23722
23825
  [layout]="agenticAuthoringPanelLayout()"
23723
23826
  [minWidth]="320"
23724
23827
  [minHeight]="280"
@@ -24273,6 +24376,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
24273
24376
  [primaryAction]="agenticAuthoringSubmitAction()"
24274
24377
  [showAttachAction]="false"
24275
24378
  [enablePastedAttachments]="false"
24379
+ [voiceInputMode]="agenticAuthoringVoiceInputMode"
24276
24380
  [layout]="agenticAuthoringPanelLayout()"
24277
24381
  [minWidth]="320"
24278
24382
  [minHeight]="280"
@@ -24767,6 +24871,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
24767
24871
  type: Input
24768
24872
  }], agenticAuthoringEnableStreaming: [{
24769
24873
  type: Input
24874
+ }], agenticAuthoringVoiceInputMode: [{
24875
+ type: Input
24770
24876
  }], agenticAuthoringContextHints: [{
24771
24877
  type: Input
24772
24878
  }], showPageLifecycleActions: [{