@praxisui/core 9.0.35 → 9.0.37

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.
@@ -8,13 +8,13 @@ import * as i1$3 from '@angular/common';
8
8
  import { Location, DOCUMENT, CommonModule } from '@angular/common';
9
9
  import { Router, ActivatedRoute } from '@angular/router';
10
10
  import * as i1$2 from '@angular/forms';
11
- import { Validators, FormGroup, FormControl, FormArray, FormsModule } from '@angular/forms';
11
+ import { Validators, FormGroup, FormControl, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
12
12
  import { MatSnackBar } from '@angular/material/snack-bar';
13
13
  import * as i1$1 from '@angular/material/icon';
14
14
  import { MatIconRegistry, MatIconModule } from '@angular/material/icon';
15
15
  import * as i2 from '@angular/material/button';
16
16
  import { MatButtonModule } from '@angular/material/button';
17
- import * as i3 from '@angular/material/form-field';
17
+ import * as i4 from '@angular/material/form-field';
18
18
  import { MatFormFieldModule } from '@angular/material/form-field';
19
19
  import * as i5 from '@angular/material/input';
20
20
  import { MatInputModule } from '@angular/material/input';
@@ -25,16 +25,19 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
25
25
  import * as i8 from '@angular/material/tooltip';
26
26
  import { MatTooltipModule } from '@angular/material/tooltip';
27
27
  import { DomSanitizer } from '@angular/platform-browser';
28
- import * as i4 from '@angular/material/menu';
28
+ import * as i4$1 from '@angular/material/menu';
29
29
  import { MatMenuModule } from '@angular/material/menu';
30
- import * as i3$1 from '@angular/material/progress-spinner';
30
+ import * as i3 from '@angular/material/progress-spinner';
31
31
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
32
- import * as i2$1 from '@angular/material/card';
33
- import { MatCardModule } from '@angular/material/card';
34
- import * as i8$1 from '@angular/material/chips';
35
- import { MatChipsModule } from '@angular/material/chips';
32
+ import * as i3$1 from '@angular/material/button-toggle';
33
+ import { MatButtonToggleModule } from '@angular/material/button-toggle';
34
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
36
35
  import * as i1$4 from '@angular/material/dialog';
37
36
  import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
37
+ import * as i8$1 from '@angular/material/chips';
38
+ import { MatChipsModule } from '@angular/material/chips';
39
+ import * as i2$1 from '@angular/material/card';
40
+ import { MatCardModule } from '@angular/material/card';
38
41
  import * as i1$5 from '@angular/material/tabs';
39
42
  import { MatTabsModule } from '@angular/material/tabs';
40
43
 
@@ -14488,6 +14491,51 @@ const RELATED_RESOURCE_OUTLET_I18N_CONFIG = {
14488
14491
  'action.delete.label': 'Remover {{noun}}',
14489
14492
  'action.delete.tooltip': 'Remova {{noun}} do contexto selecionado.',
14490
14493
  'status.ready': 'Recurso relacionado pronto',
14494
+ 'editor.title': 'Apresentação do recurso relacionado',
14495
+ 'editor.description': 'Configure somente a moldura visual. A relação e seus dados continuam governados pelos metadados.',
14496
+ 'editor.shell.title': 'Apresentação',
14497
+ 'editor.shell.help': 'Textos e escolhas de exibição desta instância do outlet.',
14498
+ 'editor.field.title': 'Título',
14499
+ 'editor.field.subtitle': 'Subtítulo',
14500
+ 'editor.field.icon': 'Ícone',
14501
+ 'editor.field.icon.choose': 'Escolher ícone do outlet',
14502
+ 'editor.field.mode': 'Modo de exibição',
14503
+ 'editor.field.mode.inline': 'Em linha',
14504
+ 'editor.field.mode.openAction': 'Ação de abertura',
14505
+ 'editor.field.presentation': 'Apresentação ao abrir',
14506
+ 'editor.field.presentation.drawer': 'Painel lateral',
14507
+ 'editor.field.presentation.modal': 'Modal',
14508
+ 'editor.field.compact': 'Usar estados vazios e de carregamento compactos',
14509
+ 'editor.emptyState.title': 'Estado vazio',
14510
+ 'editor.emptyState.help': 'Sobrescreva somente a apresentação. Ações, templates e comportamento contextual permanecem intactos.',
14511
+ 'editor.emptyState.field.title': 'Título',
14512
+ 'editor.emptyState.field.message': 'Mensagem',
14513
+ 'editor.emptyState.field.description': 'Descrição',
14514
+ 'editor.emptyState.field.icon': 'Ícone',
14515
+ 'editor.emptyState.field.icon.choose': 'Escolher ícone do estado vazio',
14516
+ 'editor.emptyState.field.tone': 'Tom',
14517
+ 'editor.emptyState.field.variant': 'Variante',
14518
+ 'editor.emptyState.field.alignment': 'Alinhamento',
14519
+ 'editor.emptyState.field.density': 'Densidade',
14520
+ 'editor.emptyState.field.iconContainer': 'Contêiner do ícone',
14521
+ 'editor.value.derived': 'Usar padrão do runtime',
14522
+ 'editor.value.derived.short': 'Automático',
14523
+ 'editor.value.tone.neutral': 'Neutro',
14524
+ 'editor.value.tone.primary': 'Primário',
14525
+ 'editor.value.tone.secondary': 'Secundário',
14526
+ 'editor.value.variant.inline': 'Em linha',
14527
+ 'editor.value.variant.card': 'Cartão',
14528
+ 'editor.value.variant.panel': 'Painel',
14529
+ 'editor.value.variant.transparent': 'Transparente',
14530
+ 'editor.value.alignment.start': 'Início',
14531
+ 'editor.value.alignment.center': 'Centro',
14532
+ 'editor.value.density.compact': 'Compacta',
14533
+ 'editor.value.density.comfortable': 'Confortável',
14534
+ 'editor.value.iconContainer.none': 'Nenhum',
14535
+ 'editor.value.iconContainer.circle': 'Círculo',
14536
+ 'editor.value.iconContainer.soft': 'Suave',
14537
+ 'editor.boundary.title': 'A relação é somente leitura aqui',
14538
+ 'editor.boundary.description': 'Paths de recursos, vínculos com o pai, operações, filtros e a configuração da tabela filha permanecem com seus donos canônicos.',
14491
14539
  },
14492
14540
  'en-US': {
14493
14541
  'state.idle.title': 'Related resource not selected',
@@ -14514,6 +14562,51 @@ const RELATED_RESOURCE_OUTLET_I18N_CONFIG = {
14514
14562
  'action.delete.label': 'Remove {{noun}}',
14515
14563
  'action.delete.tooltip': 'Remove {{noun}} from the selected context.',
14516
14564
  'status.ready': 'Related resource ready',
14565
+ 'editor.title': 'Related resource presentation',
14566
+ 'editor.description': 'Configure only the visual shell. The relationship and its data remain governed by metadata.',
14567
+ 'editor.shell.title': 'Presentation',
14568
+ 'editor.shell.help': 'Copy and display choices for this outlet instance.',
14569
+ 'editor.field.title': 'Title',
14570
+ 'editor.field.subtitle': 'Subtitle',
14571
+ 'editor.field.icon': 'Icon',
14572
+ 'editor.field.icon.choose': 'Choose outlet icon',
14573
+ 'editor.field.mode': 'Display mode',
14574
+ 'editor.field.mode.inline': 'Inline',
14575
+ 'editor.field.mode.openAction': 'Open action',
14576
+ 'editor.field.presentation': 'Open presentation',
14577
+ 'editor.field.presentation.drawer': 'Drawer',
14578
+ 'editor.field.presentation.modal': 'Modal',
14579
+ 'editor.field.compact': 'Use compact empty and loading states',
14580
+ 'editor.emptyState.title': 'Empty state',
14581
+ 'editor.emptyState.help': 'Override presentation only. Actions, templates and contextual behavior remain untouched.',
14582
+ 'editor.emptyState.field.title': 'Title',
14583
+ 'editor.emptyState.field.message': 'Message',
14584
+ 'editor.emptyState.field.description': 'Description',
14585
+ 'editor.emptyState.field.icon': 'Icon',
14586
+ 'editor.emptyState.field.icon.choose': 'Choose empty-state icon',
14587
+ 'editor.emptyState.field.tone': 'Tone',
14588
+ 'editor.emptyState.field.variant': 'Variant',
14589
+ 'editor.emptyState.field.alignment': 'Alignment',
14590
+ 'editor.emptyState.field.density': 'Density',
14591
+ 'editor.emptyState.field.iconContainer': 'Icon container',
14592
+ 'editor.value.derived': 'Use runtime default',
14593
+ 'editor.value.derived.short': 'Auto',
14594
+ 'editor.value.tone.neutral': 'Neutral',
14595
+ 'editor.value.tone.primary': 'Primary',
14596
+ 'editor.value.tone.secondary': 'Secondary',
14597
+ 'editor.value.variant.inline': 'Inline',
14598
+ 'editor.value.variant.card': 'Card',
14599
+ 'editor.value.variant.panel': 'Panel',
14600
+ 'editor.value.variant.transparent': 'Transparent',
14601
+ 'editor.value.alignment.start': 'Start',
14602
+ 'editor.value.alignment.center': 'Center',
14603
+ 'editor.value.density.compact': 'Compact',
14604
+ 'editor.value.density.comfortable': 'Comfortable',
14605
+ 'editor.value.iconContainer.none': 'None',
14606
+ 'editor.value.iconContainer.circle': 'Circle',
14607
+ 'editor.value.iconContainer.soft': 'Soft',
14608
+ 'editor.boundary.title': 'Relationship is read-only here',
14609
+ 'editor.boundary.description': 'Resource paths, parent bindings, operations, filters and child table configuration stay with their canonical owners.',
14517
14610
  },
14518
14611
  },
14519
14612
  },
@@ -23951,7 +24044,7 @@ function normalizeCompositionLink(link) {
23951
24044
  if (condition !== undefined) {
23952
24045
  normalized.condition = condition;
23953
24046
  }
23954
- const policy = normalizePolicy(link.policy);
24047
+ const policy = normalizePolicy(link.policy, link.id);
23955
24048
  if (policy) {
23956
24049
  normalized.policy = policy;
23957
24050
  }
@@ -24135,15 +24228,27 @@ function normalizeCondition(condition) {
24135
24228
  }
24136
24229
  return clone$1(condition);
24137
24230
  }
24138
- function normalizePolicy(policy) {
24231
+ function normalizePolicy(policy, linkId) {
24139
24232
  if (!policy) {
24140
24233
  return undefined;
24141
24234
  }
24235
+ const rawPolicy = policy;
24236
+ const delivery = rawPolicy['delivery'];
24237
+ const errorPolicy = rawPolicy['errorPolicy'];
24238
+ if (delivery !== undefined && delivery !== 'sync') {
24239
+ throw new Error(`Composition link '${linkId}' uses removed delivery '${String(delivery)}'. Use 'sync' or omit delivery.`);
24240
+ }
24241
+ if (errorPolicy !== undefined
24242
+ && errorPolicy !== 'diagnostic'
24243
+ && errorPolicy !== 'drop'
24244
+ && errorPolicy !== 'halt-page') {
24245
+ throw new Error(`Composition link '${linkId}' uses unsupported errorPolicy '${String(errorPolicy)}'.`);
24246
+ }
24142
24247
  const normalized = {
24143
24248
  ...(policy.debounceMs !== undefined ? { debounceMs: policy.debounceMs } : {}),
24144
24249
  ...(policy.distinct !== undefined ? { distinct: policy.distinct } : {}),
24145
24250
  ...(policy.distinctBy ? { distinctBy: policy.distinctBy } : {}),
24146
- ...(policy.delivery ? { delivery: policy.delivery } : {}),
24251
+ ...(policy.delivery === 'sync' ? { delivery: policy.delivery } : {}),
24147
24252
  ...(policy.missingValuePolicy ? { missingValuePolicy: policy.missingValuePolicy } : {}),
24148
24253
  ...(policy.errorPolicy ? { errorPolicy: policy.errorPolicy } : {}),
24149
24254
  };
@@ -27007,7 +27112,7 @@ class SurfaceOpenActionEditorComponent {
27007
27112
  </mat-form-field>
27008
27113
  </div>
27009
27114
  </div>
27010
- `, isInline: true, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-binding-remove{color:var(--md-sys-color-error)}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$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.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.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.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"] }] });
27115
+ `, isInline: true, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-binding-remove{color:var(--md-sys-color-error)}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$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.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.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.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"] }] });
27011
27116
  }
27012
27117
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SurfaceOpenActionEditorComponent, decorators: [{
27013
27118
  type: Component,
@@ -27372,6 +27477,151 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
27372
27477
  type: Output
27373
27478
  }] } });
27374
27479
 
27480
+ class ComponentAuthoringManifestProjectionError extends Error {
27481
+ name = 'ComponentAuthoringManifestProjectionError';
27482
+ code;
27483
+ path;
27484
+ constructor(code, path, message) {
27485
+ super(message);
27486
+ this.code = code;
27487
+ this.path = path;
27488
+ }
27489
+ }
27490
+ /**
27491
+ * Materializa um manifesto filho sem copiar ou redefinir operações do owner.
27492
+ *
27493
+ * A função é deliberadamente fail-closed: toda referência deve existir na fonte,
27494
+ * e a closure de targets, validators e examples precisa permanecer executável.
27495
+ */
27496
+ function projectComponentAuthoringManifest(source, projection) {
27497
+ assertProjectionIdentity(source, projection);
27498
+ assertSourceIdentitiesUnique(source);
27499
+ assertReferenceListNotEmpty(projection.runtimeInputNames, 'runtimeInputNames');
27500
+ assertReferenceListNotEmpty(projection.operationIds, 'operationIds');
27501
+ assertUniqueReferences(projection.runtimeInputNames, 'runtimeInputNames');
27502
+ assertUniqueReferences(projection.operationIds, 'operationIds');
27503
+ assertUniqueReferences(projection.roundTripRequirements ?? [], 'roundTripRequirements');
27504
+ const runtimeInputs = selectByStableId(source.runtimeInputs, projection.runtimeInputNames, (input) => input.name, 'runtimeInputNames', 'AUTHORING_MANIFEST_PROJECTION_RUNTIME_INPUT_MISSING');
27505
+ const operations = selectByStableId(source.operations, projection.operationIds, (operation) => operation.operationId, 'operationIds', 'AUTHORING_MANIFEST_PROJECTION_OPERATION_MISSING');
27506
+ const editableTargets = closeEditableTargets(source.editableTargets, operations);
27507
+ const validators = closeValidators(source.validators, operations);
27508
+ const examples = closeExamples(source.examples, operations);
27509
+ const roundTripRequirements = selectRoundTripRequirements(source.roundTripRequirements ?? [], projection.roundTripRequirements ?? []);
27510
+ return cloneManifestValue({
27511
+ schemaVersion: source.schemaVersion,
27512
+ componentId: projection.componentId.trim(),
27513
+ ownerPackage: source.ownerPackage,
27514
+ configSchemaId: source.configSchemaId,
27515
+ manifestVersion: projection.manifestVersion.trim(),
27516
+ runtimeInputs,
27517
+ editableTargets,
27518
+ operations,
27519
+ validators,
27520
+ ...(roundTripRequirements.length ? { roundTripRequirements } : {}),
27521
+ examples,
27522
+ });
27523
+ }
27524
+ function assertSourceIdentitiesUnique(source) {
27525
+ assertSourceCollectionIdentitiesUnique(source.runtimeInputs, (input) => input.name, 'source.runtimeInputs', 'name');
27526
+ assertSourceCollectionIdentitiesUnique(source.operations, (operation) => operation.operationId, 'source.operations', 'operationId');
27527
+ assertSourceCollectionIdentitiesUnique(source.editableTargets, (target) => target.kind, 'source.editableTargets', 'kind');
27528
+ assertSourceCollectionIdentitiesUnique(source.validators, (validator) => validator.validatorId, 'source.validators', 'validatorId');
27529
+ assertSourceCollectionIdentitiesUnique(source.examples, (example) => example.id, 'source.examples', 'id');
27530
+ }
27531
+ function assertSourceCollectionIdentitiesUnique(items, identity, path, identityProperty) {
27532
+ const seen = new Set();
27533
+ items.forEach((item, index) => {
27534
+ const stableId = identity(item)?.trim();
27535
+ if (!stableId) {
27536
+ fail('AUTHORING_MANIFEST_PROJECTION_ID_INVALID', `${path}[${index}].${identityProperty}`, 'Source manifest stable identities must be non-empty.');
27537
+ }
27538
+ if (seen.has(stableId)) {
27539
+ fail('AUTHORING_MANIFEST_PROJECTION_SOURCE_ID_DUPLICATE', `${path}[${index}].${identityProperty}`, `Duplicate source manifest identity ${stableId}.`);
27540
+ }
27541
+ seen.add(stableId);
27542
+ });
27543
+ }
27544
+ function assertReferenceListNotEmpty(references, path) {
27545
+ if (!references.length) {
27546
+ fail('AUTHORING_MANIFEST_PROJECTION_EMPTY_REFERENCE_LIST', path, 'Required projection reference lists must not be empty.');
27547
+ }
27548
+ }
27549
+ function assertProjectionIdentity(source, projection) {
27550
+ if (projection.sourceComponentId !== source.componentId) {
27551
+ fail('AUTHORING_MANIFEST_PROJECTION_SOURCE_MISMATCH', 'sourceComponentId', `Expected sourceComponentId ${source.componentId}, received ${projection.sourceComponentId}.`);
27552
+ }
27553
+ if (!projection.componentId?.trim()) {
27554
+ fail('AUTHORING_MANIFEST_PROJECTION_ID_INVALID', 'componentId', 'Projected componentId must be a non-empty canonical id.');
27555
+ }
27556
+ if (!projection.manifestVersion?.trim()) {
27557
+ fail('AUTHORING_MANIFEST_PROJECTION_ID_INVALID', 'manifestVersion', 'Projected manifestVersion must be non-empty.');
27558
+ }
27559
+ }
27560
+ function assertUniqueReferences(references, path) {
27561
+ const seen = new Set();
27562
+ references.forEach((reference, index) => {
27563
+ const normalized = reference?.trim();
27564
+ if (!normalized || seen.has(normalized)) {
27565
+ fail('AUTHORING_MANIFEST_PROJECTION_DUPLICATE_REFERENCE', `${path}[${index}]`, normalized
27566
+ ? `Duplicate stable reference ${normalized}.`
27567
+ : 'Stable references must be non-empty.');
27568
+ }
27569
+ seen.add(normalized);
27570
+ });
27571
+ }
27572
+ function selectByStableId(source, references, identity, path, missingCode) {
27573
+ const sourceById = new Map(source.map((item) => [identity(item), item]));
27574
+ return references.map((reference, index) => {
27575
+ const resolved = sourceById.get(reference);
27576
+ if (!resolved) {
27577
+ fail(missingCode, `${path}[${index}]`, `Stable reference ${reference} does not exist in the source manifest.`);
27578
+ }
27579
+ return resolved;
27580
+ });
27581
+ }
27582
+ function closeEditableTargets(sourceTargets, operations) {
27583
+ const targetKinds = unique(operations
27584
+ .map((operation) => operation.target?.kind ?? operation.targetKind)
27585
+ .filter((kind) => !!kind));
27586
+ return selectByStableId(sourceTargets, targetKinds, (target) => target.kind, 'source.editableTargets', 'AUTHORING_MANIFEST_PROJECTION_TARGET_MISSING');
27587
+ }
27588
+ function closeValidators(sourceValidators, operations) {
27589
+ const validatorIds = unique(operations.flatMap((operation) => operation.validators ?? []));
27590
+ return selectByStableId(sourceValidators, validatorIds, (validator) => validator.validatorId, 'source.validators', 'AUTHORING_MANIFEST_PROJECTION_VALIDATOR_MISSING');
27591
+ }
27592
+ function closeExamples(sourceExamples, operations) {
27593
+ const operationIds = new Set(operations.map((operation) => operation.operationId));
27594
+ const examples = sourceExamples.filter((example) => operationIds.has(example.operationId));
27595
+ if (!examples.length) {
27596
+ fail('AUTHORING_MANIFEST_PROJECTION_EXAMPLE_MISSING', 'source.examples', 'The projected operations have no source examples.');
27597
+ }
27598
+ if (!examples.some((example) => example.isPositive !== false)) {
27599
+ fail('AUTHORING_MANIFEST_PROJECTION_POSITIVE_EXAMPLE_MISSING', 'source.examples', 'The projected operations require at least one positive source example.');
27600
+ }
27601
+ if (!examples.some((example) => example.isPositive === false)) {
27602
+ fail('AUTHORING_MANIFEST_PROJECTION_NEGATIVE_EXAMPLE_MISSING', 'source.examples', 'The projected operations require at least one negative source example.');
27603
+ }
27604
+ return examples;
27605
+ }
27606
+ function selectRoundTripRequirements(sourceRequirements, projectedRequirements) {
27607
+ return selectByStableId(sourceRequirements, projectedRequirements, (requirement) => requirement, 'roundTripRequirements', 'AUTHORING_MANIFEST_PROJECTION_ROUND_TRIP_REQUIREMENT_MISSING');
27608
+ }
27609
+ function unique(values) {
27610
+ return [...new Set(values)];
27611
+ }
27612
+ function fail(code, path, message) {
27613
+ throw new ComponentAuthoringManifestProjectionError(code, path, message);
27614
+ }
27615
+ function cloneManifestValue(value) {
27616
+ if (Array.isArray(value)) {
27617
+ return value.map((item) => cloneManifestValue(item));
27618
+ }
27619
+ if (value && typeof value === 'object') {
27620
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, cloneManifestValue(item)]));
27621
+ }
27622
+ return value;
27623
+ }
27624
+
27375
27625
  /**
27376
27626
  * Catálogo de capacidades genéricas de FieldMetadata para uso da IA.
27377
27627
  * Baseado em projects/praxis-core/src/lib/models/component-metadata.interface.ts
@@ -32971,7 +33221,7 @@ class WidgetShellComponent {
32971
33221
  @if (expanded || fullscreen) {
32972
33222
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
32973
33223
  }
32974
- `, isInline: true, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var(--pdx-shell-card-bg, var(--pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low)));border:1px solid var(--pdx-shell-card-border, var(--pdx-dashboard-card-border, var(--md-sys-color-outline-variant)));border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var(--pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06));overflow:hidden}.pdx-shell-header{display:flex;align-items:center;gap:10px;padding:8px 10px 7px;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))}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;align-items:center;gap:4px}.pdx-shell-window-actions{margin-left:auto}@media(max-width:640px){.pdx-shell-header,.pdx-shell-title{align-items:flex-start}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical}.pdx-shell-title-text,.pdx-shell-subtitle{-webkit-line-clamp:2}.pdx-shell-actions{flex:0 0 auto}}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.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"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33224
+ `, isInline: true, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var(--pdx-shell-card-bg, var(--pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low)));border:1px solid var(--pdx-shell-card-border, var(--pdx-dashboard-card-border, var(--md-sys-color-outline-variant)));border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var(--pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06));overflow:hidden}.pdx-shell-header{display:flex;align-items:center;gap:10px;padding:8px 10px 7px;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))}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;align-items:center;gap:4px}.pdx-shell-window-actions{margin-left:auto}@media(max-width:640px){.pdx-shell-header,.pdx-shell-title{align-items:flex-start}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical}.pdx-shell-title-text,.pdx-shell-subtitle{-webkit-line-clamp:2}.pdx-shell-actions{flex:0 0 auto}}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.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"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
32975
33225
  }
32976
33226
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, decorators: [{
32977
33227
  type: Component,
@@ -34396,6 +34646,17 @@ class CompositionValidatorService {
34396
34646
  this.nestedPortCatalog = nestedPortCatalog;
34397
34647
  this.jsonLogic = jsonLogic;
34398
34648
  }
34649
+ validatePage(page, context = {}) {
34650
+ const links = context.links ?? [];
34651
+ return [
34652
+ ...this.validateRegisteredComponents(page, context.registry),
34653
+ ...this.validateLinks(links, {
34654
+ ...context,
34655
+ page,
34656
+ links,
34657
+ }),
34658
+ ];
34659
+ }
34399
34660
  validateLinks(links, context = {}) {
34400
34661
  const linkDiagnostics = links.flatMap((link) => this.validateLink(link, {
34401
34662
  ...context,
@@ -34409,6 +34670,7 @@ class CompositionValidatorService {
34409
34670
  validateLink(link, context = {}) {
34410
34671
  const diagnostics = [];
34411
34672
  this.validateEndpointDirections(link, diagnostics);
34673
+ this.validateRegisteredTopLevelPorts(link, diagnostics, context);
34412
34674
  this.validateNestedComponentEndpoints(link, diagnostics);
34413
34675
  this.validateNestedPortCatalog(link, diagnostics, context);
34414
34676
  this.validateNestedWidgetEventCoexistence(link, diagnostics, context);
@@ -34420,6 +34682,114 @@ class CompositionValidatorService {
34420
34682
  this.validateSemanticCompatibility(link, diagnostics);
34421
34683
  return diagnostics;
34422
34684
  }
34685
+ validateRegisteredComponents(page, registry) {
34686
+ if (!registry) {
34687
+ return [];
34688
+ }
34689
+ return (page.widgets || []).flatMap((widget) => {
34690
+ const componentId = widget.definition?.id?.trim();
34691
+ if (!componentId) {
34692
+ return [];
34693
+ }
34694
+ const metadata = registry.get(componentId);
34695
+ if (!metadata) {
34696
+ return [this.createPageDiagnostic(`widget:${widget.key}:SEMANTIC_COMPONENT_NOT_REGISTERED`, 'SEMANTIC_COMPONENT_NOT_REGISTERED', 'error', `O componente ${componentId} do widget ${widget.key} nao esta registrado no host-alvo.`, {
34697
+ kind: 'widget',
34698
+ widgetKey: widget.key,
34699
+ widgetType: componentId,
34700
+ path: `widgets.${widget.key}.definition.id`,
34701
+ }, { componentId })];
34702
+ }
34703
+ if (metadata.component == null) {
34704
+ return [this.createPageDiagnostic(`widget:${widget.key}:SEMANTIC_COMPONENT_NOT_MATERIALIZABLE`, 'SEMANTIC_COMPONENT_NOT_MATERIALIZABLE', 'error', `O componente ${componentId} esta no catalogo, mas nao possui tipo Angular materializavel no host-alvo.`, {
34705
+ kind: 'widget',
34706
+ widgetKey: widget.key,
34707
+ widgetType: componentId,
34708
+ path: `widgets.${widget.key}.definition.id`,
34709
+ }, { componentId })];
34710
+ }
34711
+ return [];
34712
+ });
34713
+ }
34714
+ validateRegisteredTopLevelPorts(link, diagnostics, context) {
34715
+ if (!context.page || !context.registry) {
34716
+ return;
34717
+ }
34718
+ const endpoints = [link.from, link.to].filter((endpoint) => endpoint.kind === 'component-port' && !endpoint.ref.nestedPath?.length);
34719
+ const resolvedPorts = new Map();
34720
+ for (const endpoint of endpoints) {
34721
+ const side = endpoint === link.from ? 'from' : 'to';
34722
+ const widget = (context.page.widgets || []).find((candidate) => candidate.key === endpoint.ref.widget);
34723
+ if (!widget) {
34724
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_ENDPOINT_WIDGET_MISSING', 'error', `O widget ${endpoint.ref.widget} referenciado pelo link ${link.id} nao existe.`, this.topLevelEndpointSubject(link, endpoint), { endpoint: side }));
34725
+ continue;
34726
+ }
34727
+ const componentId = widget.definition.id;
34728
+ if (endpoint.ref.componentType && endpoint.ref.componentType !== componentId) {
34729
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_ENDPOINT_COMPONENT_TYPE_MISMATCH', 'error', `O componentType do endpoint ${side} do link ${link.id} nao corresponde ao widget resolvido.`, this.topLevelEndpointSubject(link, endpoint), {
34730
+ endpoint: side,
34731
+ expectedComponentType: endpoint.ref.componentType,
34732
+ actualComponentType: componentId,
34733
+ }));
34734
+ }
34735
+ const metadata = context.registry.get(componentId);
34736
+ if (!metadata) {
34737
+ continue;
34738
+ }
34739
+ const matchingPorts = (metadata.ports || []).filter((port) => port.id === endpoint.ref.port);
34740
+ if (!matchingPorts.length) {
34741
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_NOT_REGISTERED', 'error', `A porta ${endpoint.ref.port} do componente ${componentId} nao esta registrada no host-alvo.`, this.topLevelEndpointSubject(link, endpoint), {
34742
+ endpoint: side,
34743
+ componentId,
34744
+ availablePorts: (metadata.ports || []).map((port) => port.id),
34745
+ }));
34746
+ continue;
34747
+ }
34748
+ const port = matchingPorts.find((candidate) => candidate.direction === endpoint.ref.direction);
34749
+ if (!port) {
34750
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_REGISTERED_DIRECTION_MISMATCH', 'error', `A porta ${endpoint.ref.port} do componente ${componentId} existe, mas com direcao diferente.`, this.topLevelEndpointSubject(link, endpoint), {
34751
+ endpoint: side,
34752
+ componentId,
34753
+ expectedDirection: endpoint.ref.direction,
34754
+ availableDirections: matchingPorts.map((candidate) => candidate.direction),
34755
+ }));
34756
+ continue;
34757
+ }
34758
+ resolvedPorts.set(side, port);
34759
+ }
34760
+ const sourcePort = resolvedPorts.get('from');
34761
+ const targetPort = resolvedPorts.get('to');
34762
+ if (sourcePort && targetPort) {
34763
+ this.validateRegisteredPortCompatibility(link, sourcePort, targetPort, diagnostics);
34764
+ }
34765
+ }
34766
+ validateRegisteredPortCompatibility(link, source, target, diagnostics) {
34767
+ const effectiveSourceKind = link.transform?.output?.semanticKind ?? source.semanticKind;
34768
+ const compatibility = target.compatibility;
34769
+ const knownSourceKind = effectiveSourceKind in COMPATIBLE_TARGET_KINDS;
34770
+ const genericallyIncompatible = knownSourceKind
34771
+ && !COMPATIBLE_TARGET_KINDS[effectiveSourceKind]
34772
+ .includes(target.semanticKind);
34773
+ const rejectsKind = compatibility?.rejectsSemanticKinds?.includes(effectiveSourceKind);
34774
+ const rejectsCardinality = !!(source.cardinality
34775
+ && compatibility?.acceptsCardinality?.length
34776
+ && !compatibility.acceptsCardinality.includes(source.cardinality));
34777
+ const doesNotAcceptKind = !!(compatibility?.acceptsSemanticKinds?.length
34778
+ && !compatibility.acceptsSemanticKinds.includes(effectiveSourceKind));
34779
+ if (!genericallyIncompatible && !rejectsKind && !rejectsCardinality && !doesNotAcceptKind) {
34780
+ return;
34781
+ }
34782
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_CONTRACT_INCOMPATIBLE', 'error', `As portas ${source.id} e ${target.id} do link ${link.id} nao sao semanticamente compativeis.`, {
34783
+ kind: 'link',
34784
+ linkId: link.id,
34785
+ }, {
34786
+ sourceSemanticKind: source.semanticKind,
34787
+ effectiveSourceKind,
34788
+ targetSemanticKind: target.semanticKind,
34789
+ sourceCardinality: source.cardinality,
34790
+ targetCompatibility: compatibility,
34791
+ }));
34792
+ }
34423
34793
  validateEndpointDirections(link, diagnostics) {
34424
34794
  if (link.from.kind === 'component-port' && link.from.ref.direction !== 'output') {
34425
34795
  diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_DIRECTION_INVALID_SOURCE', 'error', `A origem do link ${link.id} precisa apontar para uma porta de saida.`, {
@@ -34806,6 +35176,30 @@ class CompositionValidatorService {
34806
35176
  createdAt: new Date().toISOString(),
34807
35177
  };
34808
35178
  }
35179
+ createPageDiagnostic(id, code, severity, message, subject, details) {
35180
+ return {
35181
+ id,
35182
+ code,
35183
+ severity,
35184
+ phase: 'semantic-validation',
35185
+ message,
35186
+ summary: message,
35187
+ subject,
35188
+ details,
35189
+ source: 'semantic-validator',
35190
+ blocking: true,
35191
+ createdAt: new Date().toISOString(),
35192
+ };
35193
+ }
35194
+ topLevelEndpointSubject(link, endpoint) {
35195
+ return {
35196
+ kind: 'port',
35197
+ widgetKey: endpoint.ref.widget,
35198
+ widgetType: endpoint.ref.componentType,
35199
+ portId: endpoint.ref.port,
35200
+ linkId: link.id,
35201
+ };
35202
+ }
34809
35203
  formatNestedPath(nestedPath) {
34810
35204
  return JSON.stringify(nestedPath);
34811
35205
  }
@@ -35494,12 +35888,31 @@ class LinkExecutorService {
35494
35888
  this.jsonLogic = jsonLogic;
35495
35889
  }
35496
35890
  executeLink(link, context) {
35497
- const diagnostics = [];
35498
35891
  const snapshot = this.cloneSnapshot(context.snapshot.state);
35892
+ const stateBeforeExecution = this.cloneSnapshot(snapshot);
35893
+ try {
35894
+ return this.executeLinkInternal(link, context, snapshot);
35895
+ }
35896
+ catch (error) {
35897
+ const diagnostic = this.createDiagnostic(link, 'RUNTIME_LINK_EXECUTION_FAILED', 'error', 'A execucao do link falhou antes de concluir a entrega.', {
35898
+ errorName: error instanceof Error ? error.name : 'UnknownError',
35899
+ });
35900
+ return this.applyErrorPolicy(link, {
35901
+ status: 'failed',
35902
+ value: undefined,
35903
+ diagnostics: [diagnostic],
35904
+ snapshot,
35905
+ skippedReason: 'runtime-exception',
35906
+ }, stateBeforeExecution);
35907
+ }
35908
+ }
35909
+ executeLinkInternal(link, context, snapshot) {
35910
+ const stateBeforeExecution = this.cloneSnapshot(snapshot);
35911
+ const diagnostics = [];
35499
35912
  const now = context.now || new Date().toISOString();
35500
35913
  const sourceValue = this.resolveSourceValue(link.from, context, snapshot);
35501
35914
  if (!this.matchesCondition(link, sourceValue, context, snapshot, diagnostics)) {
35502
- return {
35915
+ const result = {
35503
35916
  status: diagnostics.some((item) => item.severity === 'error' || item.severity === 'fatal')
35504
35917
  ? 'failed'
35505
35918
  : 'skipped',
@@ -35508,19 +35921,22 @@ class LinkExecutorService {
35508
35921
  snapshot,
35509
35922
  skippedReason: diagnostics.length ? 'condition-error' : 'condition-not-matched',
35510
35923
  };
35924
+ return diagnostics.length
35925
+ ? this.applyErrorPolicy(link, result, stateBeforeExecution)
35926
+ : result;
35511
35927
  }
35512
35928
  const transformResult = link.transform
35513
35929
  ? this.transforms.executePipeline(link.transform, this.buildTransformContext(context, snapshot, sourceValue))
35514
35930
  : { value: sourceValue, diagnostics: [], failed: false };
35515
35931
  diagnostics.push(...transformResult.diagnostics);
35516
35932
  if (transformResult.failed) {
35517
- return {
35933
+ return this.applyErrorPolicy(link, {
35518
35934
  status: 'failed',
35519
35935
  value: transformResult.value,
35520
35936
  diagnostics,
35521
35937
  snapshot,
35522
35938
  skippedReason: 'transform-failed',
35523
- };
35939
+ }, stateBeforeExecution);
35524
35940
  }
35525
35941
  let value = transformResult.value;
35526
35942
  const missingResolution = this.resolveMissingValuePolicy(link, value);
@@ -35546,7 +35962,7 @@ class LinkExecutorService {
35546
35962
  }
35547
35963
  const delivery = this.deliverValue(link, value, snapshot, diagnostics);
35548
35964
  if (!delivery) {
35549
- return {
35965
+ return this.applyErrorPolicy(link, {
35550
35966
  status: diagnostics.some((item) => item.severity === 'error' || item.severity === 'fatal')
35551
35967
  ? 'failed'
35552
35968
  : 'skipped',
@@ -35554,7 +35970,7 @@ class LinkExecutorService {
35554
35970
  diagnostics,
35555
35971
  snapshot,
35556
35972
  skippedReason: 'delivery-blocked',
35557
- };
35973
+ }, stateBeforeExecution);
35558
35974
  }
35559
35975
  return {
35560
35976
  status: diagnostics.some((item) => item.severity === 'error' || item.severity === 'fatal')
@@ -35566,6 +35982,64 @@ class LinkExecutorService {
35566
35982
  delivery,
35567
35983
  };
35568
35984
  }
35985
+ applyErrorPolicy(link, result, stateBeforeDelivery) {
35986
+ const errorPolicy = link.policy?.errorPolicy ?? 'diagnostic';
35987
+ const causeCodes = result.diagnostics.map((diagnostic) => diagnostic.code);
35988
+ const causeNames = Array.from(new Set(result.diagnostics
35989
+ .map((diagnostic) => diagnostic.details?.['errorName'])
35990
+ .filter((name) => typeof name === 'string' && name.length > 0)));
35991
+ if (result.status !== 'failed') {
35992
+ return result;
35993
+ }
35994
+ if (errorPolicy === 'drop') {
35995
+ return {
35996
+ status: 'skipped',
35997
+ value: result.value,
35998
+ diagnostics: [
35999
+ this.createDiagnostic(link, 'RUNTIME_LINK_ERROR_DROPPED', 'warning', 'A entrega com falha foi descartada pela politica do link.', {
36000
+ errorPolicy,
36001
+ causeCodes,
36002
+ ...(causeNames.length ? { causeNames } : {}),
36003
+ failedPhase: result.skippedReason,
36004
+ }),
36005
+ ],
36006
+ snapshot: this.cloneSnapshot(stateBeforeDelivery),
36007
+ skippedReason: 'error-policy-drop',
36008
+ };
36009
+ }
36010
+ if (errorPolicy === 'halt-page') {
36011
+ const haltDiagnostic = this.createDiagnostic(link, 'RUNTIME_LINK_ERROR_HALTED_PAGE', 'fatal', 'A falha interrompeu a pagina conforme a politica do link.', {
36012
+ errorPolicy,
36013
+ causeCodes,
36014
+ ...(causeNames.length ? { causeNames } : {}),
36015
+ failedPhase: result.skippedReason,
36016
+ });
36017
+ return {
36018
+ ...result,
36019
+ status: 'failed',
36020
+ diagnostics: [...this.annotateDiagnostics(result.diagnostics, errorPolicy), haltDiagnostic],
36021
+ snapshot: this.cloneSnapshot(stateBeforeDelivery),
36022
+ delivery: undefined,
36023
+ skippedReason: 'error-policy-halt-page',
36024
+ };
36025
+ }
36026
+ return {
36027
+ ...result,
36028
+ diagnostics: this.annotateDiagnostics(result.diagnostics, errorPolicy),
36029
+ snapshot: this.cloneSnapshot(stateBeforeDelivery),
36030
+ delivery: undefined,
36031
+ skippedReason: result.skippedReason,
36032
+ };
36033
+ }
36034
+ annotateDiagnostics(diagnostics, errorPolicy) {
36035
+ return diagnostics.map((diagnostic) => ({
36036
+ ...diagnostic,
36037
+ details: {
36038
+ ...(diagnostic.details || {}),
36039
+ errorPolicy,
36040
+ },
36041
+ }));
36042
+ }
35569
36043
  resolveSourceValue(endpoint, context, snapshot) {
35570
36044
  if (endpoint.kind === 'state') {
35571
36045
  return this.readStatePath(snapshot, endpoint.ref.path, endpoint.ref.layer);
@@ -35627,9 +36101,9 @@ class LinkExecutorService {
35627
36101
  details['jsonLogicCode'] = error.code;
35628
36102
  }
35629
36103
  else if (error instanceof Error) {
35630
- details['error'] = error.message;
36104
+ details['errorName'] = error.name;
35631
36105
  }
35632
- diagnostics.push(this.createDiagnostic(link, 'RUNTIME_LINK_CONDITION_INVALID', 'warning', 'A condicao Json Logic do link falhou em runtime e foi tratada como falsa.', details));
36106
+ diagnostics.push(this.createDiagnostic(link, 'RUNTIME_LINK_CONDITION_INVALID', 'error', 'A condicao Json Logic do link falhou em runtime e foi tratada como falsa.', details));
35633
36107
  return false;
35634
36108
  }
35635
36109
  }
@@ -35956,6 +36430,7 @@ class CompositionRuntimeEngine {
35956
36430
  pathAccessor = new ConnectionManagerService();
35957
36431
  nestedWidgetAccessor = new NestedWidgetConfigAccessor();
35958
36432
  definition = null;
36433
+ haltedByLinkId = null;
35959
36434
  now;
35960
36435
  constructor(options = {}) {
35961
36436
  this.now = options.now ?? (() => new Date().toISOString());
@@ -35966,6 +36441,7 @@ class CompositionRuntimeEngine {
35966
36441
  this.compositionValidator = options.compositionValidator ?? new CompositionValidatorService();
35967
36442
  }
35968
36443
  bootstrap(definition) {
36444
+ this.haltedByLinkId = null;
35969
36445
  this.definition = definition;
35970
36446
  const generatedAt = this.now();
35971
36447
  const stateSnapshot = this.materializeDerivedState(definition.state.primaryValues, definition);
@@ -36025,7 +36501,16 @@ class CompositionRuntimeEngine {
36025
36501
  const matchedLinks = this.definition.links.filter((link) => matchesEndpoint(link.from, event.source));
36026
36502
  const matchedLinkIds = matchedLinks.map((link) => link.id);
36027
36503
  let workingState = cloneStateSnapshot(this.store.getSnapshot().state);
36028
- const runtimeDiagnostics = this.createNestedWidgetEventBridgeDiagnostics(event, matchedLinks, occurredAt);
36504
+ const persistentBootstrapDiagnostics = this.store.getSnapshot().diagnostics.filter((diagnostic) => isBlockingDiagnostic(diagnostic)
36505
+ && (diagnostic.phase === 'semantic-validation'
36506
+ || diagnostic.phase === 'runtime-bootstrap'));
36507
+ const runtimeDiagnostics = [
36508
+ ...persistentBootstrapDiagnostics,
36509
+ ...this.createNestedWidgetEventBridgeDiagnostics(event, matchedLinks, occurredAt),
36510
+ ];
36511
+ if (this.haltedByLinkId && matchedLinks.length === 0) {
36512
+ runtimeDiagnostics.push(this.createPageHaltedDiagnostic(undefined, occurredAt));
36513
+ }
36029
36514
  const blockedFeedbackDiagnostics = this.createFeedbackCycleBlockedDiagnostics(matchedLinks, occurredAt);
36030
36515
  runtimeDiagnostics.push(...blockedFeedbackDiagnostics.values());
36031
36516
  const linkResults = new Map();
@@ -36065,6 +36550,40 @@ class CompositionRuntimeEngine {
36065
36550
  ...endpointTraceDetails('target', link.to),
36066
36551
  },
36067
36552
  }));
36553
+ if (this.haltedByLinkId) {
36554
+ const haltedDiagnostic = this.createPageHaltedDiagnostic(link, occurredAt);
36555
+ const result = {
36556
+ status: 'skipped',
36557
+ value: event.payload,
36558
+ diagnostics: [haltedDiagnostic],
36559
+ snapshot: cloneStateSnapshot(workingState),
36560
+ skippedReason: 'page-halted',
36561
+ };
36562
+ runtimeDiagnostics.push(haltedDiagnostic);
36563
+ linkResults.set(link.id, result);
36564
+ trace.push(this.traceService.createEntry(event.eventId, sequence++, {
36565
+ timestamp: occurredAt,
36566
+ phase: 'delivery-skipped',
36567
+ linkId: link.id,
36568
+ subject: {
36569
+ kind: 'link',
36570
+ linkId: link.id,
36571
+ label: link.metadata?.label,
36572
+ },
36573
+ inputSnapshot: stateBefore,
36574
+ outputSnapshot: workingState,
36575
+ details: {
36576
+ status: 'skipped',
36577
+ skippedReason: 'page-halted',
36578
+ haltedByLinkId: this.haltedByLinkId,
36579
+ ...endpointTraceDetails('source', link.from),
36580
+ ...endpointTraceDetails('target', link.to),
36581
+ },
36582
+ diagnostics: [haltedDiagnostic.code],
36583
+ }));
36584
+ sequence = this.appendDiagnosticTraceEntries(trace, emittedDiagnosticIds, event.eventId, sequence, [haltedDiagnostic], link.id);
36585
+ continue;
36586
+ }
36068
36587
  if (blockedFeedbackDiagnostic) {
36069
36588
  trace.push(this.traceService.createEntry(event.eventId, sequence++, {
36070
36589
  timestamp: occurredAt,
@@ -36120,6 +36639,9 @@ class CompositionRuntimeEngine {
36120
36639
  workingState = cloneStateSnapshot(result.snapshot);
36121
36640
  runtimeDiagnostics.push(...result.diagnostics);
36122
36641
  linkResults.set(link.id, result);
36642
+ if (link.policy?.errorPolicy === 'halt-page' && result.status === 'failed') {
36643
+ this.haltedByLinkId = link.id;
36644
+ }
36123
36645
  if (link.transform) {
36124
36646
  trace.push(this.traceService.createEntry(event.eventId, sequence++, {
36125
36647
  timestamp: occurredAt,
@@ -36184,22 +36706,28 @@ class CompositionRuntimeEngine {
36184
36706
  sequence = this.appendDiagnosticTraceEntries(trace, emittedDiagnosticIds, event.eventId, sequence, materializedState.diagnostics.filter((item) => !runtimeDiagnostics.some((runtimeItem) => runtimeItem.id === item.id)));
36185
36707
  const snapshot = this.store.applyCycle({
36186
36708
  generatedAt: occurredAt,
36187
- status: diagnostics.some(isBlockingDiagnostic)
36188
- ? 'degraded'
36189
- : 'ready',
36709
+ status: this.haltedByLinkId
36710
+ ? 'failed'
36711
+ : diagnostics.some(isBlockingDiagnostic)
36712
+ ? 'degraded'
36713
+ : 'ready',
36190
36714
  stateSnapshot: materializedState,
36191
36715
  linkPatches: matchedLinks.map((link) => ({
36192
36716
  linkId: link.id,
36193
36717
  status: blockedFeedbackDiagnostics.has(link.id)
36194
36718
  ? 'skipped'
36195
36719
  : linkResults.get(link.id)?.status,
36196
- lastEventAt: linkResults.has(link.id) || blockedFeedbackDiagnostics.has(link.id)
36197
- ? occurredAt
36198
- : undefined,
36199
36720
  lastDispatchTraceId: linkResults.has(link.id) || blockedFeedbackDiagnostics.has(link.id)
36200
36721
  ? event.eventId
36201
36722
  : undefined,
36202
- lastDeliveredValuePreview: linkResults.get(link.id)?.value,
36723
+ lastEventAt: linkResults.has(link.id) || blockedFeedbackDiagnostics.has(link.id)
36724
+ ? occurredAt
36725
+ : undefined,
36726
+ ...(!discardsDeliveryTelemetry(linkResults.get(link.id))
36727
+ ? {
36728
+ lastDeliveredValuePreview: linkResults.get(link.id)?.value,
36729
+ }
36730
+ : {}),
36203
36731
  diagnostics: blockedFeedbackDiagnostics.has(link.id)
36204
36732
  ? [blockedFeedbackDiagnostics.get(link.id)]
36205
36733
  : linkResults.get(link.id)?.diagnostics,
@@ -36309,6 +36837,9 @@ class CompositionRuntimeEngine {
36309
36837
  workingState = cloneStateSnapshot(result.snapshot);
36310
36838
  linkResults.set(link.id, result);
36311
36839
  diagnostics.push(...result.diagnostics);
36840
+ if (link.policy?.errorPolicy === 'halt-page' && result.status === 'failed') {
36841
+ this.haltedByLinkId = link.id;
36842
+ }
36312
36843
  trace.push(this.traceService.createEntry('bootstrap', sequence++, {
36313
36844
  timestamp: occurredAt,
36314
36845
  phase: 'source-resolved',
@@ -36367,22 +36898,35 @@ class CompositionRuntimeEngine {
36367
36898
  diagnostics: result.diagnostics.map((item) => item.code),
36368
36899
  }));
36369
36900
  sequence = this.appendDiagnosticTraceEntries(trace, emittedDiagnosticIds, 'bootstrap', sequence, result.diagnostics, link.id);
36901
+ if (this.haltedByLinkId) {
36902
+ break;
36903
+ }
36370
36904
  }
36371
36905
  const dedupedDiagnostics = uniqueDiagnosticsById(diagnostics);
36372
36906
  return this.store.applyCycle({
36373
36907
  generatedAt: occurredAt,
36374
- status: dedupedDiagnostics.some(isBlockingDiagnostic) ? 'degraded' : 'ready',
36908
+ status: this.haltedByLinkId
36909
+ ? 'failed'
36910
+ : dedupedDiagnostics.some(isBlockingDiagnostic)
36911
+ ? 'degraded'
36912
+ : 'ready',
36375
36913
  stateSnapshot: {
36376
36914
  ...workingState,
36377
36915
  changedPaths: [],
36378
36916
  diagnostics: cloneDiagnostics(snapshot.state.diagnostics),
36379
36917
  },
36380
- linkPatches: hydrationLinks.map((link) => ({
36918
+ linkPatches: hydrationLinks
36919
+ .filter((link) => linkResults.has(link.id))
36920
+ .map((link) => ({
36381
36921
  linkId: link.id,
36382
36922
  status: linkResults.get(link.id)?.status ?? 'idle',
36383
36923
  lastEventAt: occurredAt,
36384
36924
  lastDispatchTraceId: 'bootstrap',
36385
- lastDeliveredValuePreview: linkResults.get(link.id)?.value,
36925
+ ...(!discardsDeliveryTelemetry(linkResults.get(link.id))
36926
+ ? {
36927
+ lastDeliveredValuePreview: linkResults.get(link.id)?.value,
36928
+ }
36929
+ : {}),
36386
36930
  diagnostics: linkResults.get(link.id)?.diagnostics,
36387
36931
  })),
36388
36932
  diagnostics: dedupedDiagnostics,
@@ -36563,6 +37107,42 @@ class CompositionRuntimeEngine {
36563
37107
  }
36564
37108
  return blocked;
36565
37109
  }
37110
+ createPageHaltedDiagnostic(link, occurredAt) {
37111
+ const linkId = link?.id;
37112
+ return {
37113
+ id: `${linkId || 'runtime'}:RUNTIME_PAGE_HALTED:${this.haltedByLinkId}`,
37114
+ code: 'RUNTIME_PAGE_HALTED',
37115
+ severity: 'fatal',
37116
+ phase: 'runtime-dispatch',
37117
+ message: 'A pagina permanece interrompida por uma falha de composicao. Um novo bootstrap e necessario.',
37118
+ summary: 'Dispatch bloqueado porque a pagina esta interrompida.',
37119
+ subject: link
37120
+ ? {
37121
+ kind: 'link',
37122
+ linkId,
37123
+ label: link.metadata?.label,
37124
+ }
37125
+ : {
37126
+ kind: 'runtime-snapshot',
37127
+ label: 'page-halted',
37128
+ },
37129
+ related: this.haltedByLinkId
37130
+ ? [{ kind: 'link', linkId: this.haltedByLinkId }]
37131
+ : undefined,
37132
+ details: {
37133
+ haltedByLinkId: this.haltedByLinkId,
37134
+ },
37135
+ source: 'runtime-engine',
37136
+ blocking: true,
37137
+ transient: true,
37138
+ createdAt: occurredAt,
37139
+ };
37140
+ }
37141
+ }
37142
+ function discardsDeliveryTelemetry(result) {
37143
+ return result?.skippedReason === 'error-policy-drop'
37144
+ || result?.skippedReason === 'error-policy-halt-page'
37145
+ || result?.skippedReason === 'page-halted';
36566
37146
  }
36567
37147
  function isComponentPortEndpoint(endpoint) {
36568
37148
  return endpoint.kind === 'component-port';
@@ -37144,7 +37724,7 @@ class DynamicWidgetContextToolbarComponent {
37144
37724
  </mat-menu>
37145
37725
  }
37146
37726
  </div>
37147
- `, isInline: true, styles: [".pdx-widget-context-toolbar{position:absolute;top:-19px;right:12px;z-index:4;display:inline-flex;align-items:center;gap:4px;min-height:34px;padding:2px 4px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 88%,transparent);box-shadow:0 10px 28px #0f172a38,0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.pdx-widget-context-toolbar--with-context{border-radius:18px}.pdx-widget-context-toolbar__context{display:inline-flex;align-items:center;align-self:stretch;max-width:180px;padding:0 8px 0 10px;border-right:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 64%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;letter-spacing:.01em;line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
37727
+ `, isInline: true, styles: [".pdx-widget-context-toolbar{position:absolute;top:-19px;right:12px;z-index:4;display:inline-flex;align-items:center;gap:4px;min-height:34px;padding:2px 4px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 88%,transparent);box-shadow:0 10px 28px #0f172a38,0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.pdx-widget-context-toolbar--with-context{border-radius:18px}.pdx-widget-context-toolbar__context{display:inline-flex;align-items:center;align-self:stretch;max-width:180px;padding:0 8px 0 10px;border-right:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 64%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:11px;font-weight:700;letter-spacing:.01em;line-height:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
37148
37728
  }
37149
37729
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicWidgetContextToolbarComponent, decorators: [{
37150
37730
  type: Component,
@@ -37373,6 +37953,7 @@ class WidgetPageCompositionFactory {
37373
37953
  const condition = rawLink['condition'];
37374
37954
  const conditions = rawLink['conditions'];
37375
37955
  const meta = rawLink['meta'];
37956
+ const policy = rawLink['policy'];
37376
37957
  if (typeof condition === 'string') {
37377
37958
  throw new Error(`WidgetPageCompositionFactory no longer accepts string condition in composition.links for '${id}'. Use canonical Json Logic in condition.`);
37378
37959
  }
@@ -37390,6 +37971,20 @@ class WidgetPageCompositionFactory {
37390
37971
  if (condition && !this.isJsonLogicLike(condition)) {
37391
37972
  throw new Error(`WidgetPageCompositionFactory requires composition.links[].condition to be a canonical Json Logic expression for '${id}'.`);
37392
37973
  }
37974
+ if (policy && typeof policy === 'object' && !Array.isArray(policy)) {
37975
+ const rawPolicy = policy;
37976
+ const delivery = rawPolicy['delivery'];
37977
+ const errorPolicy = rawPolicy['errorPolicy'];
37978
+ if (delivery !== undefined && delivery !== 'sync') {
37979
+ throw new Error(`WidgetPageCompositionFactory no longer accepts non-executable delivery '${String(delivery)}' for '${id}'. Composition dispatch is synchronously ordered; use delivery 'sync' or omit it.`);
37980
+ }
37981
+ if (errorPolicy !== undefined
37982
+ && errorPolicy !== 'diagnostic'
37983
+ && errorPolicy !== 'drop'
37984
+ && errorPolicy !== 'halt-page') {
37985
+ throw new Error(`WidgetPageCompositionFactory requires a supported errorPolicy for '${id}': diagnostic, drop, or halt-page.`);
37986
+ }
37987
+ }
37393
37988
  }
37394
37989
  }
37395
37990
  isJsonLogicLike(condition) {
@@ -39343,7 +39938,7 @@ class DynamicWidgetPageComponent {
39343
39938
  this.dispatchWidgetComponentSettingsToRuntime(key);
39344
39939
  return;
39345
39940
  }
39346
- const page = this.materializeRuntimeInputsForWidget(this.ensurePageDefinition(), key);
39941
+ const page = this.ensurePageDefinition();
39347
39942
  const widget = page.widgets.find((w) => w.key === key);
39348
39943
  if (!widget)
39349
39944
  return;
@@ -39354,9 +39949,12 @@ class DynamicWidgetPageComponent {
39354
39949
  return;
39355
39950
  }
39356
39951
  const persistedInputs = this.cloneStateValues(widget.definition.inputs || {});
39952
+ const materializedInputs = metadata.configEditor?.contextResolver
39953
+ ? this.readMaterializedInputsForWidget(metadata, key)
39954
+ : undefined;
39357
39955
  const requestId = ++this.nextConfigEditorContextRequestId;
39358
39956
  this.configEditorContextRequests.set(key, requestId);
39359
- const contextResult = await this.resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs);
39957
+ const contextResult = await this.resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs, materializedInputs);
39360
39958
  if (this.configEditorContextRequests.get(key) !== requestId) {
39361
39959
  return;
39362
39960
  }
@@ -39379,7 +39977,7 @@ class DynamicWidgetPageComponent {
39379
39977
  ref.applied$.subscribe((result) => this.applyWidgetComponentInputs(key, result, false));
39380
39978
  ref.saved$.subscribe((result) => this.applyWidgetComponentInputs(key, result, true));
39381
39979
  }
39382
- async resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs) {
39980
+ async resolveWidgetConfigEditorContext(metadata, page, widget, key, persistedInputs, materializedInputs) {
39383
39981
  const resolver = metadata.configEditor?.contextResolver;
39384
39982
  if (!resolver) {
39385
39983
  return {};
@@ -39390,6 +39988,11 @@ class DynamicWidgetPageComponent {
39390
39988
  widgetKey: key,
39391
39989
  widgetType: widget.definition?.id,
39392
39990
  persistedInputs: this.cloneStateValues(persistedInputs),
39991
+ ...(materializedInputs
39992
+ ? {
39993
+ materializedInputs: this.cloneStateValues(materializedInputs),
39994
+ }
39995
+ : {}),
39393
39996
  page: this.cloneStateValues(page),
39394
39997
  widget: this.cloneStateValues(widget),
39395
39998
  metadata,
@@ -39426,39 +40029,22 @@ class DynamicWidgetPageComponent {
39426
40029
  !Array.isArray(value) &&
39427
40030
  ('context' in value || 'diagnostics' in value));
39428
40031
  }
39429
- materializeRuntimeInputsForWidget(page, key) {
40032
+ readMaterializedInputsForWidget(metadata, key) {
39430
40033
  const normalizedKey = String(key || '').trim();
39431
40034
  if (!normalizedKey) {
39432
- return page;
39433
- }
39434
- const widget = page.widgets?.find((candidate) => candidate.key === normalizedKey);
39435
- if (!widget) {
39436
- return page;
40035
+ return undefined;
39437
40036
  }
39438
- const inputNames = this.componentMetadata
39439
- ?.get(widget.definition?.id || '')
39440
- ?.inputs?.map((input) => input.name)
40037
+ const inputNames = metadata.inputs
40038
+ ?.map((input) => input.name)
39441
40039
  ?.filter((name) => typeof name === 'string' && !!name.trim()) || [];
39442
40040
  if (!inputNames.length) {
39443
- return page;
40041
+ return undefined;
39444
40042
  }
39445
40043
  const loader = this.findWidgetLoader(normalizedKey);
39446
- const materializedInputs = loader?.materializedInputSnapshot(inputNames) || {};
39447
- if (!Object.keys(materializedInputs).length) {
39448
- return page;
39449
- }
39450
- const result = this.applyWidgetInputPatchToPage(page, normalizedKey, {
39451
- sourceComponentId: widget.definition?.id,
39452
- output: 'runtimeInputSnapshot',
39453
- payload: {
39454
- inputPatch: materializedInputs,
39455
- },
39456
- });
39457
- if (!result.changed) {
39458
- return page;
40044
+ if (!loader) {
40045
+ return undefined;
39459
40046
  }
39460
- this.applyPageUpdate(result.page, true, undefined, true, true);
39461
- return result.page;
40047
+ return this.cloneStateValues(loader.materializedInputSnapshot(inputNames));
39462
40048
  }
39463
40049
  findWidgetLoader(key) {
39464
40050
  return this.widgetLoaders?.find((loader) => loader.ownerWidgetKey === key);
@@ -43013,7 +43599,7 @@ class PraxisRelatedResourceOutletComponent {
43013
43599
  </div>
43014
43600
  }
43015
43601
  </section>
43016
- `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
43602
+ `, isInline: true, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"], dependencies: [{ kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] });
43017
43603
  }
43018
43604
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRelatedResourceOutletComponent, decorators: [{
43019
43605
  type: Component,
@@ -43067,424 +43653,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
43067
43653
  `, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"] }]
43068
43654
  }], ctorParameters: () => [], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: false }] }], surfaceCatalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceCatalog", required: false }] }], discoverySource: [{ type: i0.Input, args: [{ isSignal: true, alias: "discoverySource", required: false }] }], parentLinks: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentLinks", required: false }] }], apiEndpointKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiEndpointKey", required: false }] }], apiUrlEntry: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiUrlEntry", required: false }] }], parentRecord: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentRecord", required: false }] }], parentResourceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentResourceId", required: false }] }], parentIdentity: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentIdentity", required: false }] }], parentResourcePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentResourcePath", required: false }] }], presentation: [{ type: i0.Input, args: [{ isSignal: true, alias: "presentation", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tableId: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableId", required: false }] }], tableConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableConfig", required: false }] }], enableCustomization: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCustomization", required: false }] }], authoringCapability: [{ type: i0.Input, args: [{ isSignal: true, alias: "authoringCapability", required: false }] }], emptyState: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyState", required: false }] }], queryContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryContext", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], stateReason: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateReason", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], strictValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "strictValidation", required: false }] }], ownerWidgetKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ownerWidgetKey", required: false }] }], surfaceOpen: [{ type: i0.Output, args: ["surfaceOpen"] }], widgetEvent: [{ type: i0.Output, args: ["widgetEvent"] }], resourceEvent: [{ type: i0.Output, args: ["resourceEvent"] }] } });
43069
43655
 
43070
- const PRAXIS_RELATED_RESOURCE_OUTLET_PORTS = [
43071
- {
43072
- id: 'parentResourceId',
43073
- label: 'Identificador do recurso pai',
43074
- direction: 'input',
43075
- semanticKind: 'value',
43076
- schema: {
43077
- id: 'string | number | null',
43078
- kind: 'ts-type',
43079
- ref: 'string | number | null',
43080
- },
43081
- description: 'Seleção canônica que governa a resolução da coleção filha.',
43082
- exposure: { public: true, group: 'context' },
43083
- },
43084
- {
43085
- id: 'parentIdentity',
43086
- label: 'Identidade visual do recurso pai',
43087
- direction: 'input',
43088
- semanticKind: 'view-context',
43089
- schema: {
43090
- id: 'MaterializedResourceIdentity | null',
43091
- kind: 'ts-type',
43092
- ref: 'MaterializedResourceIdentity | null',
43093
- },
43094
- description: 'Identidade somente leitura do taskScope, sem transportar o registro pai.',
43095
- exposure: { public: true, group: 'context' },
43096
- },
43097
- {
43098
- id: 'queryContext',
43099
- label: 'Contexto de consulta',
43100
- direction: 'input',
43101
- semanticKind: 'query-context',
43102
- schema: {
43103
- id: 'RelatedResourceQueryContext',
43104
- kind: 'ts-type',
43105
- ref: 'RelatedResourceQueryContext',
43106
- },
43107
- description: 'Contexto adicional mesclado ao filtro pai-filho publicado pela surface.',
43108
- exposure: { public: true, advanced: true, group: 'context' },
43109
- },
43110
- {
43111
- id: 'surfaceOpen',
43112
- label: 'Abertura da superfície relacionada',
43113
- direction: 'output',
43114
- semanticKind: 'event',
43115
- schema: {
43116
- id: 'SurfaceOpenPayload',
43117
- kind: 'ts-type',
43118
- ref: 'SurfaceOpenPayload',
43119
- },
43120
- cardinality: 'stream',
43121
- description: 'Solicita ao host a abertura mediada da superfície no modo open-action.',
43122
- exposure: { public: true, group: 'events' },
43123
- },
43124
- {
43125
- id: 'widgetEvent',
43126
- label: 'Evento do widget relacionado',
43127
- direction: 'output',
43128
- semanticKind: 'event',
43129
- schema: {
43130
- id: 'WidgetEventEnvelope',
43131
- kind: 'ts-type',
43132
- ref: 'WidgetEventEnvelope',
43133
- },
43134
- cardinality: 'stream',
43135
- description: 'Reemite eventos do widget filho com identidade de ownership.',
43136
- exposure: { public: true, advanced: true, group: 'events' },
43137
- },
43138
- {
43139
- id: 'resourceEvent',
43140
- label: 'Evento canônico do recurso relacionado',
43141
- direction: 'output',
43142
- semanticKind: 'event',
43143
- schema: {
43144
- id: 'PraxisResourceEvent',
43145
- kind: 'ts-type',
43146
- ref: 'PraxisResourceEvent',
43147
- },
43148
- cardinality: 'stream',
43149
- description: 'Promove seleção, mutação e lifecycle do recurso filho para a composição.',
43150
- exposure: { public: true, group: 'events' },
43151
- },
43656
+ const DEFAULT_ICONS = [
43657
+ 'search', 'close', 'check', 'add', 'remove', 'delete', 'edit', 'save', 'cancel', 'warning', 'error', 'info', 'help',
43658
+ 'face', 'person', 'account_circle', 'people', 'group', 'settings', 'home', 'menu', 'more_horiz', 'more_vert', 'refresh', 'arrow_back', 'arrow_forward', 'expand_more', 'expand_less', 'open_in_full', 'fullscreen', 'open_in_new',
43659
+ 'star', 'star_half', 'star_border', 'favorite', 'favorite_border', 'thumb_up', 'thumb_down', 'share', 'send', 'ios_share', 'download', 'upload', 'file_upload', 'file_download',
43660
+ 'shopping_cart', 'shopping_bag', 'store', 'storefront', 'local_mall', 'local_offer', 'attach_money', 'money', 'payments', 'price_change', 'receipt', 'receipt_long', 'request_quote', 'point_of_sale', 'credit_card', 'payment',
43661
+ 'event', 'date_range', 'schedule', 'alarm', 'watch_later', 'pending_actions',
43662
+ 'location_on', 'location_city', 'map', 'public', 'language', 'place', 'pin_drop', 'route', 'near_me', 'navigation', 'layers', 'terrain',
43663
+ 'email', 'call', 'phone', 'chat', 'forum', 'mark_email_unread', 'mark_chat_unread',
43664
+ 'wifi', 'bluetooth', 'cloud', 'cloud_upload', 'cloud_download', 'cloud_done', 'cloud_queue', 'cloud_sync', 'backup', 'bolt', 'lock', 'lock_open', 'visibility', 'visibility_off', 'vpn_key', 'key', 'fingerprint', 'shield', 'security', 'admin_panel_settings', 'privacy_tip', 'policy', 'verified',
43665
+ 'label', 'bookmark', 'book', 'description', 'article', 'note', 'assignment', 'assignment_turned_in', 'assignment_ind', 'grading', 'subject',
43666
+ 'home_max', 'home_work', 'dashboard', 'analytics', 'assessment', 'insert_chart', 'bar_chart', 'show_chart', 'timeline', 'insights', 'pie_chart', 'donut_large', 'donut_small',
43667
+ 'inventory', 'inventory_2', 'list', 'reorder', 'filter_list', 'sort', 'tune', 'settings_applications', 'build', 'build_circle', 'construction', 'bug_report', 'code', 'terminal', 'data_object', 'dataset', 'storage',
43668
+ 'rule', 'rule_folder', 'folder', 'folder_open', 'create_new_folder', 'drive_file_move', 'drive_file_rename_outline',
43669
+ 'text_fields', 'title', 'format_bold', 'format_italic', 'format_underlined', 'format_list_bulleted', 'format_list_numbered', 'insert_link', 'link', 'attach_file', 'attachment',
43670
+ 'image', 'photo', 'photo_camera', 'collections', 'slideshow', 'movie', 'videocam', 'play_arrow', 'pause', 'stop', 'fast_forward', 'fast_rewind', 'skip_next', 'skip_previous', 'volume_up', 'volume_off', 'equalizer', 'music_note', 'library_music',
43671
+ 'notifications', 'notifications_active', 'notifications_off', 'do_not_disturb',
43672
+ 'airplanemode_active', 'train', 'directions_car', 'directions_bus', 'directions_bike', 'directions_walk', 'directions_boat', 'local_taxi',
43152
43673
  ];
43153
- const PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA = {
43154
- id: 'praxis-related-resource-outlet',
43155
- selector: 'praxis-related-resource-outlet',
43156
- component: PraxisRelatedResourceOutletComponent,
43157
- friendlyName: 'Related Resource Outlet',
43158
- description: 'Runtime genérico para materializar surface.relatedResource como tabela filha governada por metadata.',
43159
- icon: 'hub',
43160
- inputs: [
43161
- { name: 'surfaceId', type: 'string | null', description: 'Identidade declarativa da surface quando o outlet deve descobri-la no catálogo do recurso.' },
43162
- { name: 'surfaceCatalog', type: 'ResourceSurfaceCatalogResponse | null', description: 'Catálogo de surfaces já carregado pelo host; evita nova consulta quando disponível.' },
43163
- { name: 'discoverySource', type: 'ResourceLinkSource | null', description: 'Resposta HATEOAS ou mapa de links usado para seguir rel surfaces quando surface não foi fornecida.' },
43164
- { name: 'parentLinks', type: 'RestApiLinks | RestApiResponse<unknown> | null', description: 'Atalho para links do registro pai; tem o mesmo papel de discoverySource para rel surfaces.' },
43165
- { name: 'apiEndpointKey', type: 'ApiEndpoint | null', description: 'Endpoint Praxis usado pelo ResourceDiscoveryService ao resolver links ou fallback do catálogo.' },
43166
- { name: 'apiUrlEntry', type: 'ApiUrlEntry | null', description: 'Entrada de API já resolvida para hosts destacados ou integrações remotas.' },
43167
- { name: 'surface', type: 'ResourceSurfaceCatalogItem | null', description: 'Surface de catálogo que pode publicar relatedResource.' },
43168
- { name: 'parentRecord', type: 'Record<string, unknown> | null', description: 'Registro pai usado para resolver parentIdPathVariable.' },
43169
- { name: 'parentResourceId', type: 'string | number | null', description: 'Identificador explícito do registro pai quando não vem do record.' },
43170
- { name: 'parentIdentity', type: 'MaterializedResourceIdentity | null', description: 'Identidade visual somente leitura do recurso pai para continuidade de contexto.' },
43171
- { name: 'parentResourcePath', type: 'string | null', description: 'ResourcePath do recurso pai para contexto da surface.' },
43172
- { name: 'presentation', type: 'SurfacePresentation', description: 'Apresentação usada no payload de abertura host-mediated.', default: 'drawer' },
43173
- { name: 'title', type: 'string | null', description: 'Título opcional que substitui o título publicado pela surface.' },
43174
- { name: 'subtitle', type: 'string | null', description: 'Subtítulo opcional que substitui a descrição publicada pela surface.' },
43175
- { name: 'icon', type: 'string | null', description: 'Ícone opcional da superfície relacionada.' },
43176
- { name: 'queryContext', type: 'RelatedResourceQueryContext | null', description: 'QueryContext base mesclado com o filtro canônico da relação filha.' },
43177
- { name: 'tableId', type: 'string | null', description: 'Identidade estável da tabela filha para persistência, observabilidade e testes.' },
43178
- { name: 'tableConfig', type: 'Record<string, unknown> | null', description: 'Configuração parcial mesclada ao preset canônico. Ações CRUD com ids create, edit e delete aceitam somente overrides visuais (label, tooltip, icon, color, appearance, type, position e order); semântica, alvo, formulários, confirmação e disponibilidade permanecem governados pelo materializador.' },
43179
- { name: 'emptyState', type: 'Record<string, unknown> | null', description: 'Override opcional para behavior.emptyState da tabela filha. Quando omitido, o outlet deriva texto, icone, layout e ação create a partir de surface.relatedResource e dos metadados da surface.' },
43180
- { name: 'enableCustomization', type: 'boolean', description: 'Opt-in explicito para authoring governado da tabela filha.', default: false },
43181
- { name: 'authoringCapability', type: 'string | null', description: 'Capability publica do EnterpriseRuntimeContext exigida quando o authoring da tabela filha estiver habilitado.' },
43182
- { name: 'mode', type: "'inline' | 'open-action'", description: 'Renderiza a tabela filha inline ou emite payload para abertura host-mediated.', default: 'inline' },
43183
- { name: 'state', type: 'RelatedResourceResolutionState | null', description: 'Override de estado para hosts/outlets que estejam carregando discovery remoto.' },
43184
- { name: 'stateReason', type: 'string | null', description: 'Motivo governado associado ao override de estado.' },
43185
- { name: 'compact', type: 'boolean', description: 'Reduz densidade visual dos estados não materializados.', default: false },
43186
- { name: 'strictValidation', type: 'boolean', description: 'Validação estrita do widget materializado pelo DynamicWidgetLoader.', default: false },
43187
- { name: 'ownerWidgetKey', type: 'string', description: 'Identidade do owner usada para correlacionar eventos do widget filho.', default: 'related-resource.outlet' },
43188
- ],
43189
- outputs: [
43190
- { name: 'surfaceOpen', type: 'SurfaceOpenPayload', description: 'Emitido em modo open-action com o payload pronto de surface.open.' },
43191
- { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos do widget filho materializado.' },
43192
- { name: 'resourceEvent', type: 'PraxisResourceEvent', description: 'Promove eventos canonicos emitidos pelo widget filho materializado.' },
43193
- ],
43194
- ports: PRAXIS_RELATED_RESOURCE_OUTLET_PORTS,
43195
- tags: ['resource', 'surface', 'related-resource', 'runtime', 'metadata-driven'],
43196
- lib: '@praxisui/core',
43197
- };
43198
- function providePraxisRelatedResourceOutletMetadata() {
43199
- return {
43200
- provide: ENVIRONMENT_INITIALIZER,
43201
- multi: true,
43202
- useFactory: (registry) => () => {
43203
- registry.register(PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA);
43204
- },
43205
- deps: [ComponentMetadataRegistry],
43206
- };
43207
- }
43208
-
43209
- class EmptyStateCardComponent {
43210
- icon = 'tab';
43211
- title = 'Sem configuração disponível';
43212
- description;
43213
- primaryAction;
43214
- secondaryActions = [];
43215
- inline = false;
43216
- tone = 'neutral';
43217
- variant = 'card';
43218
- alignment = 'start';
43219
- density = 'comfortable';
43220
- iconContainer = 'none';
43221
- effectiveVariant() {
43222
- return this.inline && this.variant === 'card' ? 'inline' : this.variant;
43223
- }
43224
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyStateCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
43225
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: EmptyStateCardComponent, isStandalone: true, selector: "praxis-empty-state-card", inputs: { icon: "icon", title: "title", description: "description", primaryAction: "primaryAction", secondaryActions: "secondaryActions", inline: "inline", tone: "tone", variant: "variant", alignment: "alignment", density: "density", iconContainer: "iconContainer" }, ngImport: i0, template: `
43226
- <mat-card
43227
- class="empty-card"
43228
- [class.empty-inline]="inline"
43229
- [class.tone-primary]="tone === 'primary'"
43230
- [class.tone-secondary]="tone === 'secondary'"
43231
- [class.variant-inline]="effectiveVariant() === 'inline'"
43232
- [class.variant-panel]="effectiveVariant() === 'panel'"
43233
- [class.variant-transparent]="effectiveVariant() === 'transparent'"
43234
- [class.align-center]="alignment === 'center'"
43235
- [class.density-compact]="density === 'compact'"
43236
- [class.icon-circle]="iconContainer === 'circle'"
43237
- [class.icon-soft]="iconContainer === 'soft'"
43238
- appearance="outlined"
43239
- >
43240
- <mat-card-content>
43241
- <div class="content">
43242
- @if (icon) {
43243
- <mat-icon class="icon" [fontIcon]="icon"></mat-icon>
43244
- }
43245
- <div class="texts">
43246
- <h3 class="title">{{ title }}</h3>
43247
- @if (description) {
43248
- <p class="desc">{{ description }}</p>
43249
- }
43250
- </div>
43251
- </div>
43252
- <div class="actions">
43253
- @if (primaryAction) {
43254
- <button type="button" mat-flat-button color="primary" (click)="primaryAction.action()">
43255
- @if (primaryAction.icon) {
43256
- <mat-icon [fontIcon]="primaryAction.icon"></mat-icon>
43257
- }
43258
- {{ primaryAction.label }}
43259
- </button>
43260
- }
43261
- @for (a of secondaryActions; track a) {
43262
- <button type="button" mat-stroked-button [color]="a.color" (click)="a.action()">
43263
- @if (a.icon) {
43264
- <mat-icon [fontIcon]="a.icon"></mat-icon>
43265
- }
43266
- {{ a.label }}
43267
- </button>
43268
- }
43269
- </div>
43270
- </mat-card-content>
43271
- </mat-card>
43272
- `, isInline: true, styles: [".empty-card{display:block;margin:var(--pdx-empty-state-margin, 12px);border-color:var(--pdx-empty-state-border-color, var(--md-sys-color-outline-variant));border-radius:var(--pdx-empty-state-radius, 8px);background:var(--pdx-empty-state-bg, var(--md-sys-color-surface));color:var(--pdx-empty-state-fg, var(--md-sys-color-on-surface));--empty-icon-color: var(--pdx-empty-state-icon-color, var(--md-sys-color-on-surface-variant))}.empty-card.empty-inline,.empty-card.variant-inline{margin:var(--pdx-empty-state-inline-margin, 8px 0)}.empty-card.variant-panel{margin:var(--pdx-empty-state-panel-margin, 0)}.empty-card.variant-transparent{margin:var(--pdx-empty-state-transparent-margin, 0);border-color:transparent;background:transparent;box-shadow:none}.content{display:flex;align-items:center;gap:var(--pdx-empty-state-gap, 12px)}.align-center .content{flex-direction:column;justify-content:center;text-align:center}.icon{display:inline-grid;place-items:center;flex:0 0 auto;font-size:var(--pdx-empty-state-icon-size, 32px);width:var(--pdx-empty-state-icon-box-size, 32px);height:var(--pdx-empty-state-icon-box-size, 32px);color:var(--empty-icon-color)}.icon-circle .icon,.icon-soft .icon{width:var(--pdx-empty-state-icon-container-size, 44px);height:var(--pdx-empty-state-icon-container-size, 44px);border-radius:var(--pdx-empty-state-icon-container-radius, 999px);font-size:var(--pdx-empty-state-icon-container-icon-size, 22px)}.icon-circle .icon{border:1px solid var(--pdx-empty-state-icon-container-border-color, color-mix(in srgb, var(--empty-icon-color) 24%, transparent));background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.icon-soft .icon{background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.texts{display:grid;gap:var(--pdx-empty-state-text-gap, 4px)}.align-center .texts{justify-items:center}.title{margin:0;font-family:var(--pdx-empty-state-title-font-family, var(--md-sys-typescale-title-small-font-family, inherit));font-size:var(--pdx-empty-state-title-font-size, 16px);font-weight:var(--pdx-empty-state-title-font-weight, 600);line-height:var(--pdx-empty-state-title-line-height, 1.3);color:var(--pdx-empty-state-title-color, var(--md-sys-color-on-surface))}.desc{margin:0;max-width:var(--pdx-empty-state-description-max-width, none);font-family:var(--pdx-empty-state-description-font-family, var(--md-sys-typescale-body-medium-font-family, inherit));font-size:var(--pdx-empty-state-description-font-size, inherit);line-height:var(--pdx-empty-state-description-line-height, 1.4);color:var(--pdx-empty-state-description-color, var(--md-sys-color-on-surface-variant))}.actions{display:flex;justify-content:var(--pdx-empty-state-actions-justify, flex-start);gap:var(--pdx-empty-state-actions-gap, 8px);margin-top:var(--pdx-empty-state-actions-margin-top, 12px);flex-wrap:wrap}.actions .mat-mdc-button-base{width:fit-content;max-width:100%;height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));padding-inline:var(--pdx-empty-state-action-padding-inline, var(--praxis-action-control-padding-inline, 12px));border-radius:var(--pdx-empty-state-action-radius, var(--praxis-action-control-radius, 8px));gap:var(--pdx-empty-state-action-gap, var(--praxis-action-control-gap, 8px));font-size:var(--pdx-empty-state-action-font-size, var(--praxis-action-control-font-size, .875rem));font-weight:var(--pdx-empty-state-action-font-weight, var(--praxis-action-control-font-weight, 500));line-height:var(--pdx-empty-state-action-line-height, var(--praxis-action-control-line-height, 1.25rem));white-space:nowrap}.actions .mat-mdc-button-base mat-icon{width:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));margin:0;font-size:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));line-height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px))}.actions .mat-mdc-button-base:focus-visible{outline:2px solid var(--pdx-empty-state-action-focus-ring, var(--praxis-action-control-focus-ring, var(--md-sys-color-primary)));outline-offset:2px}.actions .mat-mdc-button-base:disabled{opacity:var(--pdx-empty-state-action-disabled-opacity, var(--praxis-action-control-disabled-opacity, .62))}.align-center .actions{justify-content:var(--pdx-empty-state-actions-justify, center)}.density-compact .content{gap:var(--pdx-empty-state-compact-gap, 8px)}.density-compact .actions .mat-mdc-button-base{height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px))}.density-compact .icon{font-size:var(--pdx-empty-state-compact-icon-size, 24px);width:var(--pdx-empty-state-compact-icon-box-size, 24px);height:var(--pdx-empty-state-compact-icon-box-size, 24px)}.density-compact.icon-circle .icon,.density-compact.icon-soft .icon{width:var(--pdx-empty-state-compact-icon-container-size, 36px);height:var(--pdx-empty-state-compact-icon-container-size, 36px);font-size:var(--pdx-empty-state-compact-icon-container-icon-size, 20px)}.empty-card.tone-primary{--empty-icon-color: var(--md-sys-color-primary)}.empty-card.tone-secondary{--empty-icon-color: var(--md-sys-color-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$1.MatCardContent, selector: "mat-card-content" }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
43273
- }
43274
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyStateCardComponent, decorators: [{
43275
- type: Component,
43276
- args: [{ selector: 'praxis-empty-state-card', standalone: true, imports: [MatCardModule, MatButtonModule, MatIconModule], template: `
43277
- <mat-card
43278
- class="empty-card"
43279
- [class.empty-inline]="inline"
43280
- [class.tone-primary]="tone === 'primary'"
43281
- [class.tone-secondary]="tone === 'secondary'"
43282
- [class.variant-inline]="effectiveVariant() === 'inline'"
43283
- [class.variant-panel]="effectiveVariant() === 'panel'"
43284
- [class.variant-transparent]="effectiveVariant() === 'transparent'"
43285
- [class.align-center]="alignment === 'center'"
43286
- [class.density-compact]="density === 'compact'"
43287
- [class.icon-circle]="iconContainer === 'circle'"
43288
- [class.icon-soft]="iconContainer === 'soft'"
43289
- appearance="outlined"
43290
- >
43291
- <mat-card-content>
43292
- <div class="content">
43293
- @if (icon) {
43294
- <mat-icon class="icon" [fontIcon]="icon"></mat-icon>
43295
- }
43296
- <div class="texts">
43297
- <h3 class="title">{{ title }}</h3>
43298
- @if (description) {
43299
- <p class="desc">{{ description }}</p>
43300
- }
43301
- </div>
43302
- </div>
43303
- <div class="actions">
43304
- @if (primaryAction) {
43305
- <button type="button" mat-flat-button color="primary" (click)="primaryAction.action()">
43306
- @if (primaryAction.icon) {
43307
- <mat-icon [fontIcon]="primaryAction.icon"></mat-icon>
43308
- }
43309
- {{ primaryAction.label }}
43310
- </button>
43311
- }
43312
- @for (a of secondaryActions; track a) {
43313
- <button type="button" mat-stroked-button [color]="a.color" (click)="a.action()">
43314
- @if (a.icon) {
43315
- <mat-icon [fontIcon]="a.icon"></mat-icon>
43316
- }
43317
- {{ a.label }}
43318
- </button>
43319
- }
43320
- </div>
43321
- </mat-card-content>
43322
- </mat-card>
43323
- `, styles: [".empty-card{display:block;margin:var(--pdx-empty-state-margin, 12px);border-color:var(--pdx-empty-state-border-color, var(--md-sys-color-outline-variant));border-radius:var(--pdx-empty-state-radius, 8px);background:var(--pdx-empty-state-bg, var(--md-sys-color-surface));color:var(--pdx-empty-state-fg, var(--md-sys-color-on-surface));--empty-icon-color: var(--pdx-empty-state-icon-color, var(--md-sys-color-on-surface-variant))}.empty-card.empty-inline,.empty-card.variant-inline{margin:var(--pdx-empty-state-inline-margin, 8px 0)}.empty-card.variant-panel{margin:var(--pdx-empty-state-panel-margin, 0)}.empty-card.variant-transparent{margin:var(--pdx-empty-state-transparent-margin, 0);border-color:transparent;background:transparent;box-shadow:none}.content{display:flex;align-items:center;gap:var(--pdx-empty-state-gap, 12px)}.align-center .content{flex-direction:column;justify-content:center;text-align:center}.icon{display:inline-grid;place-items:center;flex:0 0 auto;font-size:var(--pdx-empty-state-icon-size, 32px);width:var(--pdx-empty-state-icon-box-size, 32px);height:var(--pdx-empty-state-icon-box-size, 32px);color:var(--empty-icon-color)}.icon-circle .icon,.icon-soft .icon{width:var(--pdx-empty-state-icon-container-size, 44px);height:var(--pdx-empty-state-icon-container-size, 44px);border-radius:var(--pdx-empty-state-icon-container-radius, 999px);font-size:var(--pdx-empty-state-icon-container-icon-size, 22px)}.icon-circle .icon{border:1px solid var(--pdx-empty-state-icon-container-border-color, color-mix(in srgb, var(--empty-icon-color) 24%, transparent));background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.icon-soft .icon{background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.texts{display:grid;gap:var(--pdx-empty-state-text-gap, 4px)}.align-center .texts{justify-items:center}.title{margin:0;font-family:var(--pdx-empty-state-title-font-family, var(--md-sys-typescale-title-small-font-family, inherit));font-size:var(--pdx-empty-state-title-font-size, 16px);font-weight:var(--pdx-empty-state-title-font-weight, 600);line-height:var(--pdx-empty-state-title-line-height, 1.3);color:var(--pdx-empty-state-title-color, var(--md-sys-color-on-surface))}.desc{margin:0;max-width:var(--pdx-empty-state-description-max-width, none);font-family:var(--pdx-empty-state-description-font-family, var(--md-sys-typescale-body-medium-font-family, inherit));font-size:var(--pdx-empty-state-description-font-size, inherit);line-height:var(--pdx-empty-state-description-line-height, 1.4);color:var(--pdx-empty-state-description-color, var(--md-sys-color-on-surface-variant))}.actions{display:flex;justify-content:var(--pdx-empty-state-actions-justify, flex-start);gap:var(--pdx-empty-state-actions-gap, 8px);margin-top:var(--pdx-empty-state-actions-margin-top, 12px);flex-wrap:wrap}.actions .mat-mdc-button-base{width:fit-content;max-width:100%;height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));padding-inline:var(--pdx-empty-state-action-padding-inline, var(--praxis-action-control-padding-inline, 12px));border-radius:var(--pdx-empty-state-action-radius, var(--praxis-action-control-radius, 8px));gap:var(--pdx-empty-state-action-gap, var(--praxis-action-control-gap, 8px));font-size:var(--pdx-empty-state-action-font-size, var(--praxis-action-control-font-size, .875rem));font-weight:var(--pdx-empty-state-action-font-weight, var(--praxis-action-control-font-weight, 500));line-height:var(--pdx-empty-state-action-line-height, var(--praxis-action-control-line-height, 1.25rem));white-space:nowrap}.actions .mat-mdc-button-base mat-icon{width:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));margin:0;font-size:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));line-height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px))}.actions .mat-mdc-button-base:focus-visible{outline:2px solid var(--pdx-empty-state-action-focus-ring, var(--praxis-action-control-focus-ring, var(--md-sys-color-primary)));outline-offset:2px}.actions .mat-mdc-button-base:disabled{opacity:var(--pdx-empty-state-action-disabled-opacity, var(--praxis-action-control-disabled-opacity, .62))}.align-center .actions{justify-content:var(--pdx-empty-state-actions-justify, center)}.density-compact .content{gap:var(--pdx-empty-state-compact-gap, 8px)}.density-compact .actions .mat-mdc-button-base{height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px))}.density-compact .icon{font-size:var(--pdx-empty-state-compact-icon-size, 24px);width:var(--pdx-empty-state-compact-icon-box-size, 24px);height:var(--pdx-empty-state-compact-icon-box-size, 24px)}.density-compact.icon-circle .icon,.density-compact.icon-soft .icon{width:var(--pdx-empty-state-compact-icon-container-size, 36px);height:var(--pdx-empty-state-compact-icon-container-size, 36px);font-size:var(--pdx-empty-state-compact-icon-container-icon-size, 20px)}.empty-card.tone-primary{--empty-icon-color: var(--md-sys-color-primary)}.empty-card.tone-secondary{--empty-icon-color: var(--md-sys-color-secondary)}\n"] }]
43324
- }], propDecorators: { icon: [{
43325
- type: Input
43326
- }], title: [{
43327
- type: Input
43328
- }], description: [{
43329
- type: Input
43330
- }], primaryAction: [{
43331
- type: Input
43332
- }], secondaryActions: [{
43333
- type: Input
43334
- }], inline: [{
43335
- type: Input
43336
- }], tone: [{
43337
- type: Input
43338
- }], variant: [{
43339
- type: Input
43340
- }], alignment: [{
43341
- type: Input
43342
- }], density: [{
43343
- type: Input
43344
- }], iconContainer: [{
43345
- type: Input
43346
- }] } });
43347
-
43348
- class ResourceQuickConnectComponent {
43349
- resourcePath = '';
43350
- isDirty$ = new BehaviorSubject(false);
43351
- isValid$ = new BehaviorSubject(false);
43352
- isBusy$ = new BehaviorSubject(false);
43353
- // Values are provided via Inputs by the opener; no DI data coupling required.
43354
- // When used standalone, consumers can bind [(resourcePath)].
43355
- ngOnInit() {
43356
- this.updateValidity();
43357
- }
43358
- ngOnChanges() {
43359
- this.updateValidity();
43360
- }
43361
- updateState() {
43362
- this.isDirty$.next(true);
43363
- this.updateValidity();
43364
- }
43365
- updateValidity() {
43366
- const trimmed = this.resourcePath?.trim() || '';
43367
- this.isValid$.next(!!trimmed && this.isValidPath(trimmed));
43368
- }
43369
- getSettingsValue() {
43370
- return { resourcePath: this.normalizedPath() };
43371
- }
43372
- onSave() {
43373
- return this.getSettingsValue();
43374
- }
43375
- showInvalid() {
43376
- const trimmed = this.resourcePath?.trim() || '';
43377
- return !!trimmed && !this.isValidPath(trimmed);
43378
- }
43379
- normalizedPath() {
43380
- const trimmed = this.resourcePath?.trim() || '';
43381
- if (!trimmed)
43382
- return '';
43383
- if (trimmed.startsWith('/'))
43384
- return trimmed;
43385
- if (trimmed.startsWith('http://') || trimmed.startsWith('https://'))
43386
- return trimmed;
43387
- return `/${trimmed}`;
43388
- }
43389
- isValidPath(value) {
43390
- if (value.startsWith('http://') || value.startsWith('https://'))
43391
- return true;
43392
- return /^\/?[a-zA-Z0-9][a-zA-Z0-9/_-]*$/.test(value);
43393
- }
43394
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
43395
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ResourceQuickConnectComponent, isStandalone: true, selector: "praxis-resource-quick-connect", inputs: { resourcePath: "resourcePath" }, usesOnChanges: true, ngImport: i0, template: `
43396
- <div class="pdx-quick-connect">
43397
- <mat-form-field appearance="outline">
43398
- <mat-label>Rota do recurso (API)</mat-label>
43399
- <input
43400
- matInput
43401
- [(ngModel)]="resourcePath"
43402
- (ngModelChange)="updateState()"
43403
- placeholder="ex.: human-resources/departamentos"
43404
- />
43405
- <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
43406
- @if (showInvalid()) {
43407
- <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
43408
- }
43409
- </mat-form-field>
43410
- <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
43411
- @if (normalizedPath() && normalizedPath() !== resourcePath) {
43412
- <small class="pdx-quick-connect__hint">
43413
- Rota normalizada: {{ normalizedPath() }}
43414
- </small>
43415
- }
43416
- </div>
43417
- `, isInline: true, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
43418
- }
43419
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, decorators: [{
43420
- type: Component,
43421
- args: [{ selector: 'praxis-resource-quick-connect', standalone: true, imports: [FormsModule, MatFormFieldModule, MatInputModule, MatIconModule, PraxisIconDirective], template: `
43422
- <div class="pdx-quick-connect">
43423
- <mat-form-field appearance="outline">
43424
- <mat-label>Rota do recurso (API)</mat-label>
43425
- <input
43426
- matInput
43427
- [(ngModel)]="resourcePath"
43428
- (ngModelChange)="updateState()"
43429
- placeholder="ex.: human-resources/departamentos"
43430
- />
43431
- <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
43432
- @if (showInvalid()) {
43433
- <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
43434
- }
43435
- </mat-form-field>
43436
- <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
43437
- @if (normalizedPath() && normalizedPath() !== resourcePath) {
43438
- <small class="pdx-quick-connect__hint">
43439
- Rota normalizada: {{ normalizedPath() }}
43440
- </small>
43441
- }
43442
- </div>
43443
- `, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"] }]
43444
- }], propDecorators: { resourcePath: [{
43445
- type: Input
43446
- }] } });
43447
-
43448
- const DEFAULT_ICONS = [
43449
- 'search', 'close', 'check', 'add', 'remove', 'delete', 'edit', 'save', 'cancel', 'warning', 'error', 'info', 'help',
43450
- 'face', 'person', 'account_circle', 'people', 'group', 'settings', 'home', 'menu', 'more_horiz', 'more_vert', 'refresh', 'arrow_back', 'arrow_forward', 'expand_more', 'expand_less', 'open_in_full', 'fullscreen', 'open_in_new',
43451
- 'star', 'star_half', 'star_border', 'favorite', 'favorite_border', 'thumb_up', 'thumb_down', 'share', 'send', 'ios_share', 'download', 'upload', 'file_upload', 'file_download',
43452
- 'shopping_cart', 'shopping_bag', 'store', 'storefront', 'local_mall', 'local_offer', 'attach_money', 'money', 'payments', 'price_change', 'receipt', 'receipt_long', 'request_quote', 'point_of_sale', 'credit_card', 'payment',
43453
- 'event', 'date_range', 'schedule', 'alarm', 'watch_later', 'pending_actions',
43454
- 'location_on', 'location_city', 'map', 'public', 'language', 'place', 'pin_drop', 'route', 'near_me', 'navigation', 'layers', 'terrain',
43455
- 'email', 'call', 'phone', 'chat', 'forum', 'mark_email_unread', 'mark_chat_unread',
43456
- 'wifi', 'bluetooth', 'cloud', 'cloud_upload', 'cloud_download', 'cloud_done', 'cloud_queue', 'cloud_sync', 'backup', 'bolt', 'lock', 'lock_open', 'visibility', 'visibility_off', 'vpn_key', 'key', 'fingerprint', 'shield', 'security', 'admin_panel_settings', 'privacy_tip', 'policy', 'verified',
43457
- 'label', 'bookmark', 'book', 'description', 'article', 'note', 'assignment', 'assignment_turned_in', 'assignment_ind', 'grading', 'subject',
43458
- 'home_max', 'home_work', 'dashboard', 'analytics', 'assessment', 'insert_chart', 'bar_chart', 'show_chart', 'timeline', 'insights', 'pie_chart', 'donut_large', 'donut_small',
43459
- 'inventory', 'inventory_2', 'list', 'reorder', 'filter_list', 'sort', 'tune', 'settings_applications', 'build', 'build_circle', 'construction', 'bug_report', 'code', 'terminal', 'data_object', 'dataset', 'storage',
43460
- 'rule', 'rule_folder', 'folder', 'folder_open', 'create_new_folder', 'drive_file_move', 'drive_file_rename_outline',
43461
- 'text_fields', 'title', 'format_bold', 'format_italic', 'format_underlined', 'format_list_bulleted', 'format_list_numbered', 'insert_link', 'link', 'attach_file', 'attachment',
43462
- 'image', 'photo', 'photo_camera', 'collections', 'slideshow', 'movie', 'videocam', 'play_arrow', 'pause', 'stop', 'fast_forward', 'fast_rewind', 'skip_next', 'skip_previous', 'volume_up', 'volume_off', 'equalizer', 'music_note', 'library_music',
43463
- 'notifications', 'notifications_active', 'notifications_off', 'do_not_disturb',
43464
- 'airplanemode_active', 'train', 'directions_car', 'directions_bus', 'directions_bike', 'directions_walk', 'directions_boat', 'local_taxi',
43465
- ];
43466
- class PraxisIconPickerComponent {
43467
- data;
43468
- dialogRef;
43469
- value;
43470
- icons = DEFAULT_ICONS;
43471
- selected = new EventEmitter();
43472
- cancel = new EventEmitter();
43473
- searchInput;
43474
- query = '';
43475
- filtered = [];
43476
- selectedFamily = 'mi';
43477
- constructor(data, dialogRef) {
43478
- this.data = data;
43479
- this.dialogRef = dialogRef;
43480
- if (data) {
43481
- this.value = data.value;
43482
- if (Array.isArray(data.icons) && data.icons.length)
43483
- this.icons = data.icons;
43484
- const fam = this.familyFromValue(this.value);
43485
- if (fam) {
43486
- this.selectedFamily = fam.family;
43487
- this.value = fam.name;
43674
+ class PraxisIconPickerComponent {
43675
+ data;
43676
+ dialogRef;
43677
+ value;
43678
+ icons = DEFAULT_ICONS;
43679
+ selected = new EventEmitter();
43680
+ cancel = new EventEmitter();
43681
+ searchInput;
43682
+ query = '';
43683
+ filtered = [];
43684
+ selectedFamily = 'mi';
43685
+ constructor(data, dialogRef) {
43686
+ this.data = data;
43687
+ this.dialogRef = dialogRef;
43688
+ if (data) {
43689
+ this.value = data.value;
43690
+ if (Array.isArray(data.icons) && data.icons.length)
43691
+ this.icons = data.icons;
43692
+ const fam = this.familyFromValue(this.value);
43693
+ if (fam) {
43694
+ this.selectedFamily = fam.family;
43695
+ this.value = fam.name;
43488
43696
  }
43489
43697
  }
43490
43698
  this.query = (this.value || '').trim();
@@ -43654,7 +43862,7 @@ class PraxisIconPickerComponent {
43654
43862
  }
43655
43863
  </div>
43656
43864
  </div>
43657
- `, isInline: true, styles: [".pip-root{display:flex;flex-direction:column;min-width:340px;max-width:760px;max-height:80vh;overflow:hidden;padding:16px;color:var(--md-sys-color-on-surface)}.pip-head{display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap}.pip-search{flex:1;min-width:180px}.pip-spacer{flex:1}.pip-body{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;padding:4px}.pip-item{display:flex;gap:10px;align-items:center;justify-content:flex-start;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);color:inherit;cursor:pointer;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pip-item:hover{background:var(--md-sys-color-surface-container)}.pip-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pip-item.selected{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px var(--md-sys-color-primary)}.pip-name{font-size:12px;color:var(--md-sys-color-on-surface-variant);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pip-hint{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin:-6px 0 8px}.pip-stats{display:flex;justify-content:space-between;gap:8px;font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:8px}.pip-shortcut{opacity:.9}.pip-empty{padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:10px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container);margin-top:8px}.pip-footer{display:flex;gap:12px;align-items:center;margin-top:10px}.pip-typed{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;color:var(--md-sys-color-on-surface)}.pip-family{display:flex;align-items:center}.pip-family .mat-mdc-chip-listbox{min-width:260px}.pip-root .mat-icon{font-family:Material Icons,Material Symbols Outlined,Material Symbols Rounded,Material Symbols Sharp!important;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24;color:currentColor}.material-symbols-outlined{font-family:Material Symbols Outlined;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-sharp{font-family:Material Symbols Sharp;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatChipsModule }, { kind: "component", type: i8$1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i8$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
43865
+ `, isInline: true, styles: [".pip-root{display:flex;flex-direction:column;min-width:340px;max-width:760px;max-height:80vh;overflow:hidden;padding:16px;color:var(--md-sys-color-on-surface)}.pip-head{display:flex;gap:12px;align-items:center;margin-bottom:12px;flex-wrap:wrap}.pip-search{flex:1;min-width:180px}.pip-spacer{flex:1}.pip-body{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:10px;padding:4px}.pip-item{display:flex;gap:10px;align-items:center;justify-content:flex-start;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;background:var(--md-sys-color-surface);color:inherit;cursor:pointer;transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.pip-item:hover{background:var(--md-sys-color-surface-container)}.pip-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pip-item.selected{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px var(--md-sys-color-primary)}.pip-name{font-size:12px;color:var(--md-sys-color-on-surface-variant);white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pip-hint{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin:-6px 0 8px}.pip-stats{display:flex;justify-content:space-between;gap:8px;font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:8px}.pip-shortcut{opacity:.9}.pip-empty{padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:10px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container);margin-top:8px}.pip-footer{display:flex;gap:12px;align-items:center;margin-top:10px}.pip-typed{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;color:var(--md-sys-color-on-surface)}.pip-family{display:flex;align-items:center}.pip-family .mat-mdc-chip-listbox{min-width:260px}.pip-root .mat-icon{font-family:Material Icons,Material Symbols Outlined,Material Symbols Rounded,Material Symbols Sharp!important;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24;color:currentColor}.material-symbols-outlined{font-family:Material Symbols Outlined;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-rounded{font-family:Material Symbols Rounded;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}.material-symbols-sharp{font-family:Material Symbols Sharp;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-webkit-font-feature-settings:\"liga\";-webkit-font-smoothing:antialiased;font-variation-settings:\"FILL\" 0,\"wght\" 400,\"GRAD\" 0,\"opsz\" 24}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { 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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: MatChipsModule }, { kind: "component", type: i8$1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i8$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
43658
43866
  }
43659
43867
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisIconPickerComponent, decorators: [{
43660
43868
  type: Component,
@@ -43788,6 +43996,1480 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
43788
43996
  args: [{ providedIn: 'root' }]
43789
43997
  }] });
43790
43998
 
43999
+ const EMPTY_FORM_VALUE = {
44000
+ title: '',
44001
+ subtitle: '',
44002
+ icon: '',
44003
+ mode: 'inline',
44004
+ presentation: 'drawer',
44005
+ compact: false,
44006
+ emptyState: {
44007
+ title: '',
44008
+ message: '',
44009
+ description: '',
44010
+ icon: '',
44011
+ tone: '',
44012
+ variant: '',
44013
+ alignment: '',
44014
+ density: '',
44015
+ iconContainer: '',
44016
+ },
44017
+ };
44018
+ const EMPTY_STATE_TEXT_FIELDS = ['title', 'message', 'description', 'icon'];
44019
+ const EMPTY_STATE_ENUM_FIELDS = [
44020
+ 'tone',
44021
+ 'variant',
44022
+ 'alignment',
44023
+ 'density',
44024
+ 'iconContainer',
44025
+ ];
44026
+ class PraxisRelatedResourceOutletConfigEditorComponent {
44027
+ inputs = input(null, ...(ngDevMode ? [{ debugName: "inputs" }] : /* istanbul ignore next */ []));
44028
+ widgetKey = input(undefined, ...(ngDevMode ? [{ debugName: "widgetKey" }] : /* istanbul ignore next */ []));
44029
+ widgetType = input(undefined, ...(ngDevMode ? [{ debugName: "widgetType" }] : /* istanbul ignore next */ []));
44030
+ form = new FormGroup({
44031
+ title: new FormControl('', { nonNullable: true }),
44032
+ subtitle: new FormControl('', { nonNullable: true }),
44033
+ icon: new FormControl('', { nonNullable: true }),
44034
+ mode: new FormControl('inline', { nonNullable: true }),
44035
+ presentation: new FormControl('drawer', { nonNullable: true }),
44036
+ compact: new FormControl(false, { nonNullable: true }),
44037
+ emptyState: new FormGroup({
44038
+ title: new FormControl('', { nonNullable: true }),
44039
+ message: new FormControl('', { nonNullable: true }),
44040
+ description: new FormControl('', { nonNullable: true }),
44041
+ icon: new FormControl('', { nonNullable: true }),
44042
+ tone: new FormControl('', { nonNullable: true }),
44043
+ variant: new FormControl('', { nonNullable: true }),
44044
+ alignment: new FormControl('', { nonNullable: true }),
44045
+ density: new FormControl('', { nonNullable: true }),
44046
+ iconContainer: new FormControl('', { nonNullable: true }),
44047
+ }),
44048
+ });
44049
+ isDirty$ = new BehaviorSubject(false);
44050
+ isValid$ = new BehaviorSubject(true);
44051
+ isBusy$ = new BehaviorSubject(false);
44052
+ i18n = inject(PraxisI18nService);
44053
+ iconPicker = inject(IconPickerService);
44054
+ persistedInputs = {};
44055
+ baselineFormValue = structuredClone(EMPTY_FORM_VALUE);
44056
+ constructor() {
44057
+ this.form.valueChanges
44058
+ .pipe(takeUntilDestroyed())
44059
+ .subscribe(() => this.publishState());
44060
+ effect(() => {
44061
+ this.initialize(this.inputs());
44062
+ });
44063
+ }
44064
+ getSettingsValue() {
44065
+ return { inputs: this.buildInputs() };
44066
+ }
44067
+ onSave() {
44068
+ return this.getSettingsValue();
44069
+ }
44070
+ reset() {
44071
+ this.form.reset(structuredClone(this.baselineFormValue), { emitEvent: false });
44072
+ this.publishState();
44073
+ }
44074
+ async selectIcon(target) {
44075
+ const control = target === 'outlet'
44076
+ ? this.form.controls.icon
44077
+ : this.form.controls.emptyState.controls.icon;
44078
+ const selected = await this.iconPicker.openDialog({ value: control.value });
44079
+ if (selected !== undefined) {
44080
+ control.setValue(selected);
44081
+ }
44082
+ }
44083
+ t(key, fallback) {
44084
+ return this.i18n.t(key, undefined, fallback, RELATED_RESOURCE_OUTLET_I18N_NAMESPACE);
44085
+ }
44086
+ initialize(inputs) {
44087
+ this.persistedInputs = structuredClone(inputs ?? {});
44088
+ this.baselineFormValue = this.readFormValue(this.persistedInputs);
44089
+ this.form.reset(structuredClone(this.baselineFormValue), { emitEvent: false });
44090
+ this.publishState();
44091
+ }
44092
+ readFormValue(inputs) {
44093
+ const emptyState = this.objectValue(inputs['emptyState']);
44094
+ return {
44095
+ title: this.stringValue(inputs['title']),
44096
+ subtitle: this.stringValue(inputs['subtitle']),
44097
+ icon: this.stringValue(inputs['icon']),
44098
+ mode: inputs['mode'] === 'open-action' ? 'open-action' : 'inline',
44099
+ presentation: inputs['presentation'] === 'modal' ? 'modal' : 'drawer',
44100
+ compact: inputs['compact'] === true,
44101
+ emptyState: {
44102
+ title: this.stringValue(emptyState['title']),
44103
+ message: this.stringValue(emptyState['message']),
44104
+ description: this.stringValue(emptyState['description']),
44105
+ icon: this.stringValue(emptyState['icon']),
44106
+ tone: this.enumValue(emptyState['tone'], ['neutral', 'primary', 'secondary']),
44107
+ variant: this.enumValue(emptyState['variant'], ['card', 'inline', 'panel', 'transparent']),
44108
+ alignment: this.enumValue(emptyState['alignment'], ['start', 'center']),
44109
+ density: this.enumValue(emptyState['density'], ['compact', 'comfortable']),
44110
+ iconContainer: this.enumValue(emptyState['iconContainer'], ['none', 'circle', 'soft']),
44111
+ },
44112
+ };
44113
+ }
44114
+ buildInputs() {
44115
+ const next = structuredClone(this.persistedInputs);
44116
+ const current = this.form.getRawValue();
44117
+ this.applyTextChange(next, 'title', current.title, this.baselineFormValue.title);
44118
+ this.applyTextChange(next, 'subtitle', current.subtitle, this.baselineFormValue.subtitle);
44119
+ this.applyTextChange(next, 'icon', current.icon, this.baselineFormValue.icon);
44120
+ this.applyDefaultedChange(next, 'mode', current.mode, this.baselineFormValue.mode, 'inline');
44121
+ this.applyDefaultedChange(next, 'presentation', current.presentation, this.baselineFormValue.presentation, 'drawer');
44122
+ this.applyDefaultedChange(next, 'compact', current.compact, this.baselineFormValue.compact, false);
44123
+ this.applyEmptyStateChanges(next, current.emptyState);
44124
+ return next;
44125
+ }
44126
+ applyEmptyStateChanges(inputs, current) {
44127
+ const baseline = this.baselineFormValue.emptyState;
44128
+ const changed = EMPTY_STATE_TEXT_FIELDS.some((field) => current[field] !== baseline[field])
44129
+ || EMPTY_STATE_ENUM_FIELDS.some((field) => current[field] !== baseline[field]);
44130
+ if (!changed) {
44131
+ return;
44132
+ }
44133
+ const existing = this.objectValue(inputs['emptyState']);
44134
+ const next = structuredClone(existing);
44135
+ for (const field of EMPTY_STATE_TEXT_FIELDS) {
44136
+ this.applyTextChange(next, field, current[field], baseline[field]);
44137
+ }
44138
+ for (const field of EMPTY_STATE_ENUM_FIELDS) {
44139
+ if (current[field] === baseline[field]) {
44140
+ continue;
44141
+ }
44142
+ if (current[field]) {
44143
+ next[field] = current[field];
44144
+ }
44145
+ else {
44146
+ delete next[field];
44147
+ }
44148
+ }
44149
+ if (Object.keys(next).length > 0) {
44150
+ inputs['emptyState'] = next;
44151
+ }
44152
+ else {
44153
+ delete inputs['emptyState'];
44154
+ }
44155
+ }
44156
+ applyTextChange(target, field, current, baseline) {
44157
+ if (current === baseline) {
44158
+ return;
44159
+ }
44160
+ const value = current.trim();
44161
+ if (value) {
44162
+ target[field] = value;
44163
+ }
44164
+ else {
44165
+ delete target[field];
44166
+ }
44167
+ }
44168
+ applyDefaultedChange(target, field, current, baseline, defaultValue) {
44169
+ if (current === baseline) {
44170
+ return;
44171
+ }
44172
+ if (current === defaultValue && !Object.prototype.hasOwnProperty.call(this.persistedInputs, field)) {
44173
+ delete target[field];
44174
+ return;
44175
+ }
44176
+ target[field] = current;
44177
+ }
44178
+ publishState() {
44179
+ this.isDirty$.next(JSON.stringify(this.form.getRawValue()) !== JSON.stringify(this.baselineFormValue));
44180
+ this.isValid$.next(this.form.valid);
44181
+ }
44182
+ objectValue(value) {
44183
+ return value && typeof value === 'object' && !Array.isArray(value)
44184
+ ? value
44185
+ : {};
44186
+ }
44187
+ stringValue(value) {
44188
+ return typeof value === 'string' ? value : '';
44189
+ }
44190
+ enumValue(value, allowed) {
44191
+ return typeof value === 'string' && allowed.includes(value) ? value : '';
44192
+ }
44193
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRelatedResourceOutletConfigEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
44194
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.14", type: PraxisRelatedResourceOutletConfigEditorComponent, isStandalone: true, selector: "praxis-related-resource-outlet-config-editor", inputs: { inputs: { classPropertyName: "inputs", publicName: "inputs", isSignal: true, isRequired: false, transformFunction: null }, widgetKey: { classPropertyName: "widgetKey", publicName: "widgetKey", isSignal: true, isRequired: false, transformFunction: null }, widgetType: { classPropertyName: "widgetType", publicName: "widgetType", isSignal: true, isRequired: false, transformFunction: null } }, providers: [providePraxisI18nConfig(RELATED_RESOURCE_OUTLET_I18N_CONFIG)], ngImport: i0, template: `
44195
+ <form
44196
+ class="pdx-related-outlet-editor"
44197
+ [formGroup]="form"
44198
+ data-testid="related-resource-outlet-config-editor"
44199
+ >
44200
+ <header class="pdx-related-outlet-editor__header">
44201
+ <span class="pdx-related-outlet-editor__header-icon" aria-hidden="true">
44202
+ <mat-icon fontIcon="account_tree" />
44203
+ </span>
44204
+ <span>
44205
+ <strong>{{ t('editor.title', 'Related resource presentation') }}</strong>
44206
+ <small>
44207
+ {{
44208
+ t(
44209
+ 'editor.description',
44210
+ 'Configure only the visual shell. The relationship and its data remain governed by metadata.'
44211
+ )
44212
+ }}
44213
+ </small>
44214
+ </span>
44215
+ </header>
44216
+
44217
+ <section class="pdx-related-outlet-editor__section" aria-labelledby="related-outlet-shell-title">
44218
+ <div class="pdx-related-outlet-editor__section-heading">
44219
+ <h3 id="related-outlet-shell-title">{{ t('editor.shell.title', 'Presentation') }}</h3>
44220
+ <p>{{ t('editor.shell.help', 'Copy and display choices for this outlet instance.') }}</p>
44221
+ </div>
44222
+
44223
+ <div class="pdx-related-outlet-editor__fields">
44224
+ <mat-form-field appearance="outline">
44225
+ <mat-label>{{ t('editor.field.title', 'Title') }}</mat-label>
44226
+ <input matInput formControlName="title" />
44227
+ </mat-form-field>
44228
+
44229
+ <mat-form-field appearance="outline">
44230
+ <mat-label>{{ t('editor.field.icon', 'Icon') }}</mat-label>
44231
+ <input matInput formControlName="icon" />
44232
+ <button
44233
+ mat-icon-button
44234
+ matSuffix
44235
+ type="button"
44236
+ (click)="selectIcon('outlet')"
44237
+ [attr.aria-label]="t('editor.field.icon.choose', 'Choose outlet icon')"
44238
+ >
44239
+ <mat-icon fontIcon="apps" />
44240
+ </button>
44241
+ </mat-form-field>
44242
+
44243
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44244
+ <mat-label>{{ t('editor.field.subtitle', 'Subtitle') }}</mat-label>
44245
+ <textarea matInput formControlName="subtitle" rows="2"></textarea>
44246
+ </mat-form-field>
44247
+ </div>
44248
+
44249
+ <div class="pdx-related-outlet-editor__choice-grid">
44250
+ <fieldset>
44251
+ <legend>{{ t('editor.field.mode', 'Display mode') }}</legend>
44252
+ <mat-button-toggle-group
44253
+ formControlName="mode"
44254
+ hideSingleSelectionIndicator
44255
+ [attr.aria-label]="t('editor.field.mode', 'Display mode')"
44256
+ >
44257
+ <mat-button-toggle value="inline">
44258
+ <mat-icon fontIcon="table_rows" aria-hidden="true" />
44259
+ {{ t('editor.field.mode.inline', 'Inline') }}
44260
+ </mat-button-toggle>
44261
+ <mat-button-toggle value="open-action">
44262
+ <mat-icon fontIcon="open_in_new" aria-hidden="true" />
44263
+ {{ t('editor.field.mode.openAction', 'Open action') }}
44264
+ </mat-button-toggle>
44265
+ </mat-button-toggle-group>
44266
+ </fieldset>
44267
+
44268
+ <fieldset>
44269
+ <legend>{{ t('editor.field.presentation', 'Open presentation') }}</legend>
44270
+ <mat-button-toggle-group
44271
+ formControlName="presentation"
44272
+ hideSingleSelectionIndicator
44273
+ [attr.aria-label]="t('editor.field.presentation', 'Open presentation')"
44274
+ >
44275
+ <mat-button-toggle value="drawer">
44276
+ <mat-icon fontIcon="view_sidebar" aria-hidden="true" />
44277
+ {{ t('editor.field.presentation.drawer', 'Drawer') }}
44278
+ </mat-button-toggle>
44279
+ <mat-button-toggle value="modal">
44280
+ <mat-icon fontIcon="web_asset" aria-hidden="true" />
44281
+ {{ t('editor.field.presentation.modal', 'Modal') }}
44282
+ </mat-button-toggle>
44283
+ </mat-button-toggle-group>
44284
+ </fieldset>
44285
+ </div>
44286
+
44287
+ </section>
44288
+
44289
+ <section
44290
+ class="pdx-related-outlet-editor__section"
44291
+ formGroupName="emptyState"
44292
+ aria-labelledby="related-outlet-empty-state-title"
44293
+ >
44294
+ <div class="pdx-related-outlet-editor__section-heading">
44295
+ <h3 id="related-outlet-empty-state-title">{{ t('editor.emptyState.title', 'Empty state') }}</h3>
44296
+ <p>
44297
+ {{
44298
+ t(
44299
+ 'editor.emptyState.help',
44300
+ 'Override presentation only. Actions, templates and contextual behavior remain untouched.'
44301
+ )
44302
+ }}
44303
+ </p>
44304
+ </div>
44305
+
44306
+ <div class="pdx-related-outlet-editor__fields">
44307
+ <mat-form-field appearance="outline">
44308
+ <mat-label>{{ t('editor.emptyState.field.title', 'Title') }}</mat-label>
44309
+ <input matInput formControlName="title" />
44310
+ </mat-form-field>
44311
+
44312
+ <mat-form-field appearance="outline">
44313
+ <mat-label>{{ t('editor.emptyState.field.icon', 'Icon') }}</mat-label>
44314
+ <input matInput formControlName="icon" />
44315
+ <button
44316
+ mat-icon-button
44317
+ matSuffix
44318
+ type="button"
44319
+ (click)="selectIcon('emptyState')"
44320
+ [attr.aria-label]="t('editor.emptyState.field.icon.choose', 'Choose empty-state icon')"
44321
+ >
44322
+ <mat-icon fontIcon="apps" />
44323
+ </button>
44324
+ </mat-form-field>
44325
+
44326
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44327
+ <mat-label>{{ t('editor.emptyState.field.message', 'Message') }}</mat-label>
44328
+ <input matInput formControlName="message" />
44329
+ </mat-form-field>
44330
+
44331
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44332
+ <mat-label>{{ t('editor.emptyState.field.description', 'Description') }}</mat-label>
44333
+ <textarea matInput formControlName="description" rows="2"></textarea>
44334
+ </mat-form-field>
44335
+
44336
+ </div>
44337
+
44338
+ <div class="pdx-related-outlet-editor__appearance-grid">
44339
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44340
+ <legend>{{ t('editor.emptyState.field.tone', 'Tone') }}</legend>
44341
+ <mat-button-toggle-group
44342
+ formControlName="tone"
44343
+ hideSingleSelectionIndicator
44344
+ [attr.aria-label]="t('editor.emptyState.field.tone', 'Tone')"
44345
+ >
44346
+ <mat-button-toggle value="">
44347
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44348
+ {{ t('editor.value.derived.short', 'Auto') }}
44349
+ </mat-button-toggle>
44350
+ <mat-button-toggle value="neutral">
44351
+ <mat-icon fontIcon="contrast" aria-hidden="true" />
44352
+ {{ t('editor.value.tone.neutral', 'Neutral') }}
44353
+ </mat-button-toggle>
44354
+ <mat-button-toggle value="primary">
44355
+ <mat-icon fontIcon="stars" aria-hidden="true" />
44356
+ {{ t('editor.value.tone.primary', 'Primary') }}
44357
+ </mat-button-toggle>
44358
+ <mat-button-toggle value="secondary">
44359
+ <mat-icon fontIcon="palette" aria-hidden="true" />
44360
+ {{ t('editor.value.tone.secondary', 'Secondary') }}
44361
+ </mat-button-toggle>
44362
+ </mat-button-toggle-group>
44363
+ </fieldset>
44364
+
44365
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster pdx-related-outlet-editor__appearance-cluster--wide">
44366
+ <legend>{{ t('editor.emptyState.field.variant', 'Variant') }}</legend>
44367
+ <mat-button-toggle-group
44368
+ formControlName="variant"
44369
+ hideSingleSelectionIndicator
44370
+ [attr.aria-label]="t('editor.emptyState.field.variant', 'Variant')"
44371
+ >
44372
+ <mat-button-toggle value="">
44373
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44374
+ {{ t('editor.value.derived.short', 'Auto') }}
44375
+ </mat-button-toggle>
44376
+ <mat-button-toggle value="inline">
44377
+ <mat-icon fontIcon="view_stream" aria-hidden="true" />
44378
+ {{ t('editor.value.variant.inline', 'Inline') }}
44379
+ </mat-button-toggle>
44380
+ <mat-button-toggle value="card">
44381
+ <mat-icon fontIcon="crop_square" aria-hidden="true" />
44382
+ {{ t('editor.value.variant.card', 'Card') }}
44383
+ </mat-button-toggle>
44384
+ <mat-button-toggle value="panel">
44385
+ <mat-icon fontIcon="view_agenda" aria-hidden="true" />
44386
+ {{ t('editor.value.variant.panel', 'Panel') }}
44387
+ </mat-button-toggle>
44388
+ <mat-button-toggle value="transparent">
44389
+ <mat-icon fontIcon="layers_clear" aria-hidden="true" />
44390
+ {{ t('editor.value.variant.transparent', 'Transparent') }}
44391
+ </mat-button-toggle>
44392
+ </mat-button-toggle-group>
44393
+ </fieldset>
44394
+
44395
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44396
+ <legend>{{ t('editor.emptyState.field.alignment', 'Alignment') }}</legend>
44397
+ <mat-button-toggle-group
44398
+ formControlName="alignment"
44399
+ hideSingleSelectionIndicator
44400
+ [attr.aria-label]="t('editor.emptyState.field.alignment', 'Alignment')"
44401
+ >
44402
+ <mat-button-toggle value="">
44403
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44404
+ {{ t('editor.value.derived.short', 'Auto') }}
44405
+ </mat-button-toggle>
44406
+ <mat-button-toggle value="start">
44407
+ <mat-icon fontIcon="format_align_left" aria-hidden="true" />
44408
+ {{ t('editor.value.alignment.start', 'Start') }}
44409
+ </mat-button-toggle>
44410
+ <mat-button-toggle value="center">
44411
+ <mat-icon fontIcon="format_align_center" aria-hidden="true" />
44412
+ {{ t('editor.value.alignment.center', 'Center') }}
44413
+ </mat-button-toggle>
44414
+ </mat-button-toggle-group>
44415
+ </fieldset>
44416
+
44417
+ <div class="pdx-related-outlet-editor__appearance-cluster pdx-related-outlet-editor__density-cluster">
44418
+ <fieldset>
44419
+ <legend>{{ t('editor.emptyState.field.density', 'Density') }}</legend>
44420
+ <mat-button-toggle-group
44421
+ formControlName="density"
44422
+ hideSingleSelectionIndicator
44423
+ [attr.aria-label]="t('editor.emptyState.field.density', 'Density')"
44424
+ >
44425
+ <mat-button-toggle value="">
44426
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44427
+ {{ t('editor.value.derived.short', 'Auto') }}
44428
+ </mat-button-toggle>
44429
+ <mat-button-toggle value="compact">
44430
+ <mat-icon fontIcon="density_small" aria-hidden="true" />
44431
+ {{ t('editor.value.density.compact', 'Compact') }}
44432
+ </mat-button-toggle>
44433
+ <mat-button-toggle value="comfortable">
44434
+ <mat-icon fontIcon="density_medium" aria-hidden="true" />
44435
+ {{ t('editor.value.density.comfortable', 'Comfortable') }}
44436
+ </mat-button-toggle>
44437
+ </mat-button-toggle-group>
44438
+ </fieldset>
44439
+ <mat-slide-toggle [formControl]="form.controls.compact">
44440
+ {{ t('editor.field.compact', 'Use compact empty and loading states') }}
44441
+ </mat-slide-toggle>
44442
+ </div>
44443
+
44444
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44445
+ <legend>{{ t('editor.emptyState.field.iconContainer', 'Icon container') }}</legend>
44446
+ <mat-button-toggle-group
44447
+ formControlName="iconContainer"
44448
+ hideSingleSelectionIndicator
44449
+ [attr.aria-label]="t('editor.emptyState.field.iconContainer', 'Icon container')"
44450
+ >
44451
+ <mat-button-toggle value="">
44452
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44453
+ {{ t('editor.value.derived.short', 'Auto') }}
44454
+ </mat-button-toggle>
44455
+ <mat-button-toggle value="none">
44456
+ <mat-icon fontIcon="block" aria-hidden="true" />
44457
+ {{ t('editor.value.iconContainer.none', 'None') }}
44458
+ </mat-button-toggle>
44459
+ <mat-button-toggle value="circle">
44460
+ <mat-icon fontIcon="circle" aria-hidden="true" />
44461
+ {{ t('editor.value.iconContainer.circle', 'Circle') }}
44462
+ </mat-button-toggle>
44463
+ <mat-button-toggle value="soft">
44464
+ <mat-icon fontIcon="blur_on" aria-hidden="true" />
44465
+ {{ t('editor.value.iconContainer.soft', 'Soft') }}
44466
+ </mat-button-toggle>
44467
+ </mat-button-toggle-group>
44468
+ </fieldset>
44469
+ </div>
44470
+ </section>
44471
+
44472
+ <aside class="pdx-related-outlet-editor__boundary" role="note">
44473
+ <mat-icon fontIcon="lock" aria-hidden="true" />
44474
+ <span>
44475
+ <strong>{{ t('editor.boundary.title', 'Relationship is read-only here') }}</strong>
44476
+ <small>
44477
+ {{
44478
+ t(
44479
+ 'editor.boundary.description',
44480
+ 'Resource paths, parent bindings, operations, filters and child table configuration stay with their canonical owners.'
44481
+ )
44482
+ }}
44483
+ </small>
44484
+ </span>
44485
+ </aside>
44486
+ </form>
44487
+ `, isInline: true, styles: [":host{display:block;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet-editor{display:grid;gap:var(--pdx-spacing-lg, 24px);padding:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__header,.pdx-related-outlet-editor__boundary{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__header-icon{display:inline-grid;place-items:center;width:40px;height:40px;border-radius:var(--md-sys-shape-corner-medium, 12px);color:var(--md-sys-color-primary, currentColor);background:var(--md-sys-color-primary-container, transparent)}.pdx-related-outlet-editor__header strong,.pdx-related-outlet-editor__boundary strong,.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small{display:block}.pdx-related-outlet-editor__header strong{font:var(--md-sys-typescale-title-medium, 600 1rem/1.4 system-ui)}.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small,.pdx-related-outlet-editor__section-heading p{color:var(--md-sys-color-on-surface-variant, currentColor)}.pdx-related-outlet-editor__section{display:grid;gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__section-heading h3,.pdx-related-outlet-editor__section-heading p{margin:0}.pdx-related-outlet-editor__section-heading h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.3 system-ui)}.pdx-related-outlet-editor__section-heading p{margin-top:4px;font:var(--md-sys-typescale-body-small, 400 .82rem/1.35 system-ui)}.pdx-related-outlet-editor__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__wide{grid-column:1 / -1}.pdx-related-outlet-editor__choice-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__appearance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__appearance-cluster{display:grid;align-content:start;gap:var(--pdx-spacing-sm, 12px);min-width:0}.pdx-related-outlet-editor__appearance-cluster--wide{grid-column:1 / -1}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,132px),1fr))}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle{min-height:44px}.pdx-related-outlet-editor__density-cluster{gap:var(--pdx-spacing-md, 16px)}fieldset{min-width:0;margin:0;padding:0;border:0}legend{margin-bottom:8px;font:var(--md-sys-typescale-label-large, 500 .88rem/1.2 system-ui)}mat-button-toggle-group{width:100%}mat-button-toggle{flex:1 1 0}mat-button-toggle mat-icon{margin-right:6px}.pdx-related-outlet-editor__boundary{padding:var(--pdx-spacing-sm, 12px);border:1px solid var(--md-sys-color-outline-variant, currentColor);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low, transparent)}.pdx-related-outlet-editor__boundary mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:640px){.pdx-related-outlet-editor__fields,.pdx-related-outlet-editor__choice-grid{grid-template-columns:minmax(0,1fr)}.pdx-related-outlet-editor__wide{grid-column:auto}mat-button-toggle-group{display:grid}}@media(max-width:420px){.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$1.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$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: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
44488
+ }
44489
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisRelatedResourceOutletConfigEditorComponent, decorators: [{
44490
+ type: Component,
44491
+ args: [{ selector: 'praxis-related-resource-outlet-config-editor', imports: [
44492
+ ReactiveFormsModule,
44493
+ MatButtonModule,
44494
+ MatButtonToggleModule,
44495
+ MatFormFieldModule,
44496
+ MatIconModule,
44497
+ MatInputModule,
44498
+ MatSlideToggleModule,
44499
+ ], providers: [providePraxisI18nConfig(RELATED_RESOURCE_OUTLET_I18N_CONFIG)], changeDetection: ChangeDetectionStrategy.OnPush, template: `
44500
+ <form
44501
+ class="pdx-related-outlet-editor"
44502
+ [formGroup]="form"
44503
+ data-testid="related-resource-outlet-config-editor"
44504
+ >
44505
+ <header class="pdx-related-outlet-editor__header">
44506
+ <span class="pdx-related-outlet-editor__header-icon" aria-hidden="true">
44507
+ <mat-icon fontIcon="account_tree" />
44508
+ </span>
44509
+ <span>
44510
+ <strong>{{ t('editor.title', 'Related resource presentation') }}</strong>
44511
+ <small>
44512
+ {{
44513
+ t(
44514
+ 'editor.description',
44515
+ 'Configure only the visual shell. The relationship and its data remain governed by metadata.'
44516
+ )
44517
+ }}
44518
+ </small>
44519
+ </span>
44520
+ </header>
44521
+
44522
+ <section class="pdx-related-outlet-editor__section" aria-labelledby="related-outlet-shell-title">
44523
+ <div class="pdx-related-outlet-editor__section-heading">
44524
+ <h3 id="related-outlet-shell-title">{{ t('editor.shell.title', 'Presentation') }}</h3>
44525
+ <p>{{ t('editor.shell.help', 'Copy and display choices for this outlet instance.') }}</p>
44526
+ </div>
44527
+
44528
+ <div class="pdx-related-outlet-editor__fields">
44529
+ <mat-form-field appearance="outline">
44530
+ <mat-label>{{ t('editor.field.title', 'Title') }}</mat-label>
44531
+ <input matInput formControlName="title" />
44532
+ </mat-form-field>
44533
+
44534
+ <mat-form-field appearance="outline">
44535
+ <mat-label>{{ t('editor.field.icon', 'Icon') }}</mat-label>
44536
+ <input matInput formControlName="icon" />
44537
+ <button
44538
+ mat-icon-button
44539
+ matSuffix
44540
+ type="button"
44541
+ (click)="selectIcon('outlet')"
44542
+ [attr.aria-label]="t('editor.field.icon.choose', 'Choose outlet icon')"
44543
+ >
44544
+ <mat-icon fontIcon="apps" />
44545
+ </button>
44546
+ </mat-form-field>
44547
+
44548
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44549
+ <mat-label>{{ t('editor.field.subtitle', 'Subtitle') }}</mat-label>
44550
+ <textarea matInput formControlName="subtitle" rows="2"></textarea>
44551
+ </mat-form-field>
44552
+ </div>
44553
+
44554
+ <div class="pdx-related-outlet-editor__choice-grid">
44555
+ <fieldset>
44556
+ <legend>{{ t('editor.field.mode', 'Display mode') }}</legend>
44557
+ <mat-button-toggle-group
44558
+ formControlName="mode"
44559
+ hideSingleSelectionIndicator
44560
+ [attr.aria-label]="t('editor.field.mode', 'Display mode')"
44561
+ >
44562
+ <mat-button-toggle value="inline">
44563
+ <mat-icon fontIcon="table_rows" aria-hidden="true" />
44564
+ {{ t('editor.field.mode.inline', 'Inline') }}
44565
+ </mat-button-toggle>
44566
+ <mat-button-toggle value="open-action">
44567
+ <mat-icon fontIcon="open_in_new" aria-hidden="true" />
44568
+ {{ t('editor.field.mode.openAction', 'Open action') }}
44569
+ </mat-button-toggle>
44570
+ </mat-button-toggle-group>
44571
+ </fieldset>
44572
+
44573
+ <fieldset>
44574
+ <legend>{{ t('editor.field.presentation', 'Open presentation') }}</legend>
44575
+ <mat-button-toggle-group
44576
+ formControlName="presentation"
44577
+ hideSingleSelectionIndicator
44578
+ [attr.aria-label]="t('editor.field.presentation', 'Open presentation')"
44579
+ >
44580
+ <mat-button-toggle value="drawer">
44581
+ <mat-icon fontIcon="view_sidebar" aria-hidden="true" />
44582
+ {{ t('editor.field.presentation.drawer', 'Drawer') }}
44583
+ </mat-button-toggle>
44584
+ <mat-button-toggle value="modal">
44585
+ <mat-icon fontIcon="web_asset" aria-hidden="true" />
44586
+ {{ t('editor.field.presentation.modal', 'Modal') }}
44587
+ </mat-button-toggle>
44588
+ </mat-button-toggle-group>
44589
+ </fieldset>
44590
+ </div>
44591
+
44592
+ </section>
44593
+
44594
+ <section
44595
+ class="pdx-related-outlet-editor__section"
44596
+ formGroupName="emptyState"
44597
+ aria-labelledby="related-outlet-empty-state-title"
44598
+ >
44599
+ <div class="pdx-related-outlet-editor__section-heading">
44600
+ <h3 id="related-outlet-empty-state-title">{{ t('editor.emptyState.title', 'Empty state') }}</h3>
44601
+ <p>
44602
+ {{
44603
+ t(
44604
+ 'editor.emptyState.help',
44605
+ 'Override presentation only. Actions, templates and contextual behavior remain untouched.'
44606
+ )
44607
+ }}
44608
+ </p>
44609
+ </div>
44610
+
44611
+ <div class="pdx-related-outlet-editor__fields">
44612
+ <mat-form-field appearance="outline">
44613
+ <mat-label>{{ t('editor.emptyState.field.title', 'Title') }}</mat-label>
44614
+ <input matInput formControlName="title" />
44615
+ </mat-form-field>
44616
+
44617
+ <mat-form-field appearance="outline">
44618
+ <mat-label>{{ t('editor.emptyState.field.icon', 'Icon') }}</mat-label>
44619
+ <input matInput formControlName="icon" />
44620
+ <button
44621
+ mat-icon-button
44622
+ matSuffix
44623
+ type="button"
44624
+ (click)="selectIcon('emptyState')"
44625
+ [attr.aria-label]="t('editor.emptyState.field.icon.choose', 'Choose empty-state icon')"
44626
+ >
44627
+ <mat-icon fontIcon="apps" />
44628
+ </button>
44629
+ </mat-form-field>
44630
+
44631
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44632
+ <mat-label>{{ t('editor.emptyState.field.message', 'Message') }}</mat-label>
44633
+ <input matInput formControlName="message" />
44634
+ </mat-form-field>
44635
+
44636
+ <mat-form-field appearance="outline" class="pdx-related-outlet-editor__wide">
44637
+ <mat-label>{{ t('editor.emptyState.field.description', 'Description') }}</mat-label>
44638
+ <textarea matInput formControlName="description" rows="2"></textarea>
44639
+ </mat-form-field>
44640
+
44641
+ </div>
44642
+
44643
+ <div class="pdx-related-outlet-editor__appearance-grid">
44644
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44645
+ <legend>{{ t('editor.emptyState.field.tone', 'Tone') }}</legend>
44646
+ <mat-button-toggle-group
44647
+ formControlName="tone"
44648
+ hideSingleSelectionIndicator
44649
+ [attr.aria-label]="t('editor.emptyState.field.tone', 'Tone')"
44650
+ >
44651
+ <mat-button-toggle value="">
44652
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44653
+ {{ t('editor.value.derived.short', 'Auto') }}
44654
+ </mat-button-toggle>
44655
+ <mat-button-toggle value="neutral">
44656
+ <mat-icon fontIcon="contrast" aria-hidden="true" />
44657
+ {{ t('editor.value.tone.neutral', 'Neutral') }}
44658
+ </mat-button-toggle>
44659
+ <mat-button-toggle value="primary">
44660
+ <mat-icon fontIcon="stars" aria-hidden="true" />
44661
+ {{ t('editor.value.tone.primary', 'Primary') }}
44662
+ </mat-button-toggle>
44663
+ <mat-button-toggle value="secondary">
44664
+ <mat-icon fontIcon="palette" aria-hidden="true" />
44665
+ {{ t('editor.value.tone.secondary', 'Secondary') }}
44666
+ </mat-button-toggle>
44667
+ </mat-button-toggle-group>
44668
+ </fieldset>
44669
+
44670
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster pdx-related-outlet-editor__appearance-cluster--wide">
44671
+ <legend>{{ t('editor.emptyState.field.variant', 'Variant') }}</legend>
44672
+ <mat-button-toggle-group
44673
+ formControlName="variant"
44674
+ hideSingleSelectionIndicator
44675
+ [attr.aria-label]="t('editor.emptyState.field.variant', 'Variant')"
44676
+ >
44677
+ <mat-button-toggle value="">
44678
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44679
+ {{ t('editor.value.derived.short', 'Auto') }}
44680
+ </mat-button-toggle>
44681
+ <mat-button-toggle value="inline">
44682
+ <mat-icon fontIcon="view_stream" aria-hidden="true" />
44683
+ {{ t('editor.value.variant.inline', 'Inline') }}
44684
+ </mat-button-toggle>
44685
+ <mat-button-toggle value="card">
44686
+ <mat-icon fontIcon="crop_square" aria-hidden="true" />
44687
+ {{ t('editor.value.variant.card', 'Card') }}
44688
+ </mat-button-toggle>
44689
+ <mat-button-toggle value="panel">
44690
+ <mat-icon fontIcon="view_agenda" aria-hidden="true" />
44691
+ {{ t('editor.value.variant.panel', 'Panel') }}
44692
+ </mat-button-toggle>
44693
+ <mat-button-toggle value="transparent">
44694
+ <mat-icon fontIcon="layers_clear" aria-hidden="true" />
44695
+ {{ t('editor.value.variant.transparent', 'Transparent') }}
44696
+ </mat-button-toggle>
44697
+ </mat-button-toggle-group>
44698
+ </fieldset>
44699
+
44700
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44701
+ <legend>{{ t('editor.emptyState.field.alignment', 'Alignment') }}</legend>
44702
+ <mat-button-toggle-group
44703
+ formControlName="alignment"
44704
+ hideSingleSelectionIndicator
44705
+ [attr.aria-label]="t('editor.emptyState.field.alignment', 'Alignment')"
44706
+ >
44707
+ <mat-button-toggle value="">
44708
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44709
+ {{ t('editor.value.derived.short', 'Auto') }}
44710
+ </mat-button-toggle>
44711
+ <mat-button-toggle value="start">
44712
+ <mat-icon fontIcon="format_align_left" aria-hidden="true" />
44713
+ {{ t('editor.value.alignment.start', 'Start') }}
44714
+ </mat-button-toggle>
44715
+ <mat-button-toggle value="center">
44716
+ <mat-icon fontIcon="format_align_center" aria-hidden="true" />
44717
+ {{ t('editor.value.alignment.center', 'Center') }}
44718
+ </mat-button-toggle>
44719
+ </mat-button-toggle-group>
44720
+ </fieldset>
44721
+
44722
+ <div class="pdx-related-outlet-editor__appearance-cluster pdx-related-outlet-editor__density-cluster">
44723
+ <fieldset>
44724
+ <legend>{{ t('editor.emptyState.field.density', 'Density') }}</legend>
44725
+ <mat-button-toggle-group
44726
+ formControlName="density"
44727
+ hideSingleSelectionIndicator
44728
+ [attr.aria-label]="t('editor.emptyState.field.density', 'Density')"
44729
+ >
44730
+ <mat-button-toggle value="">
44731
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44732
+ {{ t('editor.value.derived.short', 'Auto') }}
44733
+ </mat-button-toggle>
44734
+ <mat-button-toggle value="compact">
44735
+ <mat-icon fontIcon="density_small" aria-hidden="true" />
44736
+ {{ t('editor.value.density.compact', 'Compact') }}
44737
+ </mat-button-toggle>
44738
+ <mat-button-toggle value="comfortable">
44739
+ <mat-icon fontIcon="density_medium" aria-hidden="true" />
44740
+ {{ t('editor.value.density.comfortable', 'Comfortable') }}
44741
+ </mat-button-toggle>
44742
+ </mat-button-toggle-group>
44743
+ </fieldset>
44744
+ <mat-slide-toggle [formControl]="form.controls.compact">
44745
+ {{ t('editor.field.compact', 'Use compact empty and loading states') }}
44746
+ </mat-slide-toggle>
44747
+ </div>
44748
+
44749
+ <fieldset class="pdx-related-outlet-editor__appearance-cluster">
44750
+ <legend>{{ t('editor.emptyState.field.iconContainer', 'Icon container') }}</legend>
44751
+ <mat-button-toggle-group
44752
+ formControlName="iconContainer"
44753
+ hideSingleSelectionIndicator
44754
+ [attr.aria-label]="t('editor.emptyState.field.iconContainer', 'Icon container')"
44755
+ >
44756
+ <mat-button-toggle value="">
44757
+ <mat-icon fontIcon="auto_awesome" aria-hidden="true" />
44758
+ {{ t('editor.value.derived.short', 'Auto') }}
44759
+ </mat-button-toggle>
44760
+ <mat-button-toggle value="none">
44761
+ <mat-icon fontIcon="block" aria-hidden="true" />
44762
+ {{ t('editor.value.iconContainer.none', 'None') }}
44763
+ </mat-button-toggle>
44764
+ <mat-button-toggle value="circle">
44765
+ <mat-icon fontIcon="circle" aria-hidden="true" />
44766
+ {{ t('editor.value.iconContainer.circle', 'Circle') }}
44767
+ </mat-button-toggle>
44768
+ <mat-button-toggle value="soft">
44769
+ <mat-icon fontIcon="blur_on" aria-hidden="true" />
44770
+ {{ t('editor.value.iconContainer.soft', 'Soft') }}
44771
+ </mat-button-toggle>
44772
+ </mat-button-toggle-group>
44773
+ </fieldset>
44774
+ </div>
44775
+ </section>
44776
+
44777
+ <aside class="pdx-related-outlet-editor__boundary" role="note">
44778
+ <mat-icon fontIcon="lock" aria-hidden="true" />
44779
+ <span>
44780
+ <strong>{{ t('editor.boundary.title', 'Relationship is read-only here') }}</strong>
44781
+ <small>
44782
+ {{
44783
+ t(
44784
+ 'editor.boundary.description',
44785
+ 'Resource paths, parent bindings, operations, filters and child table configuration stay with their canonical owners.'
44786
+ )
44787
+ }}
44788
+ </small>
44789
+ </span>
44790
+ </aside>
44791
+ </form>
44792
+ `, styles: [":host{display:block;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet-editor{display:grid;gap:var(--pdx-spacing-lg, 24px);padding:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__header,.pdx-related-outlet-editor__boundary{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__header-icon{display:inline-grid;place-items:center;width:40px;height:40px;border-radius:var(--md-sys-shape-corner-medium, 12px);color:var(--md-sys-color-primary, currentColor);background:var(--md-sys-color-primary-container, transparent)}.pdx-related-outlet-editor__header strong,.pdx-related-outlet-editor__boundary strong,.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small{display:block}.pdx-related-outlet-editor__header strong{font:var(--md-sys-typescale-title-medium, 600 1rem/1.4 system-ui)}.pdx-related-outlet-editor__header small,.pdx-related-outlet-editor__boundary small,.pdx-related-outlet-editor__section-heading p{color:var(--md-sys-color-on-surface-variant, currentColor)}.pdx-related-outlet-editor__section{display:grid;gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__section-heading h3,.pdx-related-outlet-editor__section-heading p{margin:0}.pdx-related-outlet-editor__section-heading h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.3 system-ui)}.pdx-related-outlet-editor__section-heading p{margin-top:4px;font:var(--md-sys-typescale-body-small, 400 .82rem/1.35 system-ui)}.pdx-related-outlet-editor__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__wide{grid-column:1 / -1}.pdx-related-outlet-editor__choice-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pdx-spacing-md, 16px)}.pdx-related-outlet-editor__appearance-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:var(--pdx-spacing-sm, 12px)}.pdx-related-outlet-editor__appearance-cluster{display:grid;align-content:start;gap:var(--pdx-spacing-sm, 12px);min-width:0}.pdx-related-outlet-editor__appearance-cluster--wide{grid-column:1 / -1}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,132px),1fr))}.pdx-related-outlet-editor__appearance-cluster mat-button-toggle{min-height:44px}.pdx-related-outlet-editor__density-cluster{gap:var(--pdx-spacing-md, 16px)}fieldset{min-width:0;margin:0;padding:0;border:0}legend{margin-bottom:8px;font:var(--md-sys-typescale-label-large, 500 .88rem/1.2 system-ui)}mat-button-toggle-group{width:100%}mat-button-toggle{flex:1 1 0}mat-button-toggle mat-icon{margin-right:6px}.pdx-related-outlet-editor__boundary{padding:var(--pdx-spacing-sm, 12px);border:1px solid var(--md-sys-color-outline-variant, currentColor);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low, transparent)}.pdx-related-outlet-editor__boundary mat-icon{color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:640px){.pdx-related-outlet-editor__fields,.pdx-related-outlet-editor__choice-grid{grid-template-columns:minmax(0,1fr)}.pdx-related-outlet-editor__wide{grid-column:auto}mat-button-toggle-group{display:grid}}@media(max-width:420px){.pdx-related-outlet-editor__appearance-cluster mat-button-toggle-group{grid-template-columns:minmax(0,1fr)}}\n"] }]
44793
+ }], ctorParameters: () => [], propDecorators: { inputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputs", required: false }] }], widgetKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetKey", required: false }] }], widgetType: [{ type: i0.Input, args: [{ isSignal: true, alias: "widgetType", required: false }] }] } });
44794
+
44795
+ const PRAXIS_RELATED_RESOURCE_OUTLET_PORTS = [
44796
+ {
44797
+ id: 'parentResourceId',
44798
+ label: 'Identificador do recurso pai',
44799
+ direction: 'input',
44800
+ semanticKind: 'value',
44801
+ schema: {
44802
+ id: 'string | number | null',
44803
+ kind: 'ts-type',
44804
+ ref: 'string | number | null',
44805
+ },
44806
+ description: 'Seleção canônica que governa a resolução da coleção filha.',
44807
+ exposure: { public: true, group: 'context' },
44808
+ },
44809
+ {
44810
+ id: 'parentIdentity',
44811
+ label: 'Identidade visual do recurso pai',
44812
+ direction: 'input',
44813
+ semanticKind: 'view-context',
44814
+ schema: {
44815
+ id: 'MaterializedResourceIdentity | null',
44816
+ kind: 'ts-type',
44817
+ ref: 'MaterializedResourceIdentity | null',
44818
+ },
44819
+ description: 'Identidade somente leitura do taskScope, sem transportar o registro pai.',
44820
+ exposure: { public: true, group: 'context' },
44821
+ },
44822
+ {
44823
+ id: 'queryContext',
44824
+ label: 'Contexto de consulta',
44825
+ direction: 'input',
44826
+ semanticKind: 'query-context',
44827
+ schema: {
44828
+ id: 'RelatedResourceQueryContext',
44829
+ kind: 'ts-type',
44830
+ ref: 'RelatedResourceQueryContext',
44831
+ },
44832
+ description: 'Contexto adicional mesclado ao filtro pai-filho publicado pela surface.',
44833
+ exposure: { public: true, advanced: true, group: 'context' },
44834
+ },
44835
+ {
44836
+ id: 'surfaceOpen',
44837
+ label: 'Abertura da superfície relacionada',
44838
+ direction: 'output',
44839
+ semanticKind: 'event',
44840
+ schema: {
44841
+ id: 'SurfaceOpenPayload',
44842
+ kind: 'ts-type',
44843
+ ref: 'SurfaceOpenPayload',
44844
+ },
44845
+ cardinality: 'stream',
44846
+ description: 'Solicita ao host a abertura mediada da superfície no modo open-action.',
44847
+ exposure: { public: true, group: 'events' },
44848
+ },
44849
+ {
44850
+ id: 'widgetEvent',
44851
+ label: 'Evento do widget relacionado',
44852
+ direction: 'output',
44853
+ semanticKind: 'event',
44854
+ schema: {
44855
+ id: 'WidgetEventEnvelope',
44856
+ kind: 'ts-type',
44857
+ ref: 'WidgetEventEnvelope',
44858
+ },
44859
+ cardinality: 'stream',
44860
+ description: 'Reemite eventos do widget filho com identidade de ownership.',
44861
+ exposure: { public: true, advanced: true, group: 'events' },
44862
+ },
44863
+ {
44864
+ id: 'resourceEvent',
44865
+ label: 'Evento canônico do recurso relacionado',
44866
+ direction: 'output',
44867
+ semanticKind: 'event',
44868
+ schema: {
44869
+ id: 'PraxisResourceEvent',
44870
+ kind: 'ts-type',
44871
+ ref: 'PraxisResourceEvent',
44872
+ },
44873
+ cardinality: 'stream',
44874
+ description: 'Promove seleção, mutação e lifecycle do recurso filho para a composição.',
44875
+ exposure: { public: true, group: 'events' },
44876
+ },
44877
+ ];
44878
+ const PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA = {
44879
+ id: 'praxis-related-resource-outlet',
44880
+ selector: 'praxis-related-resource-outlet',
44881
+ component: PraxisRelatedResourceOutletComponent,
44882
+ friendlyName: 'Related Resource Outlet',
44883
+ description: 'Runtime genérico para materializar surface.relatedResource como tabela filha governada por metadata.',
44884
+ icon: 'hub',
44885
+ inputs: [
44886
+ { name: 'surfaceId', type: 'string | null', description: 'Identidade declarativa da surface quando o outlet deve descobri-la no catálogo do recurso.' },
44887
+ { name: 'surfaceCatalog', type: 'ResourceSurfaceCatalogResponse | null', description: 'Catálogo de surfaces já carregado pelo host; evita nova consulta quando disponível.' },
44888
+ { name: 'discoverySource', type: 'ResourceLinkSource | null', description: 'Resposta HATEOAS ou mapa de links usado para seguir rel surfaces quando surface não foi fornecida.' },
44889
+ { name: 'parentLinks', type: 'RestApiLinks | RestApiResponse<unknown> | null', description: 'Atalho para links do registro pai; tem o mesmo papel de discoverySource para rel surfaces.' },
44890
+ { name: 'apiEndpointKey', type: 'ApiEndpoint | null', description: 'Endpoint Praxis usado pelo ResourceDiscoveryService ao resolver links ou fallback do catálogo.' },
44891
+ { name: 'apiUrlEntry', type: 'ApiUrlEntry | null', description: 'Entrada de API já resolvida para hosts destacados ou integrações remotas.' },
44892
+ { name: 'surface', type: 'ResourceSurfaceCatalogItem | null', description: 'Surface de catálogo que pode publicar relatedResource.' },
44893
+ { name: 'parentRecord', type: 'Record<string, unknown> | null', description: 'Registro pai usado para resolver parentIdPathVariable.' },
44894
+ { name: 'parentResourceId', type: 'string | number | null', description: 'Identificador explícito do registro pai quando não vem do record.' },
44895
+ { name: 'parentIdentity', type: 'MaterializedResourceIdentity | null', description: 'Identidade visual somente leitura do recurso pai para continuidade de contexto.' },
44896
+ { name: 'parentResourcePath', type: 'string | null', description: 'ResourcePath do recurso pai para contexto da surface.' },
44897
+ { name: 'presentation', type: 'SurfacePresentation', description: 'Apresentação usada no payload de abertura host-mediated.', default: 'drawer' },
44898
+ { name: 'title', type: 'string | null', description: 'Título opcional que substitui o título publicado pela surface.' },
44899
+ { name: 'subtitle', type: 'string | null', description: 'Subtítulo opcional que substitui a descrição publicada pela surface.' },
44900
+ { name: 'icon', type: 'string | null', description: 'Ícone opcional da superfície relacionada.' },
44901
+ { name: 'queryContext', type: 'RelatedResourceQueryContext | null', description: 'QueryContext base mesclado com o filtro canônico da relação filha.' },
44902
+ { name: 'tableId', type: 'string | null', description: 'Identidade estável da tabela filha para persistência, observabilidade e testes.' },
44903
+ { name: 'tableConfig', type: 'Record<string, unknown> | null', description: 'Configuração parcial mesclada ao preset canônico. Ações CRUD com ids create, edit e delete aceitam somente overrides visuais (label, tooltip, icon, color, appearance, type, position e order); semântica, alvo, formulários, confirmação e disponibilidade permanecem governados pelo materializador.' },
44904
+ { name: 'emptyState', type: 'Record<string, unknown> | null', description: 'Override opcional para behavior.emptyState da tabela filha. Quando omitido, o outlet deriva texto, icone, layout e ação create a partir de surface.relatedResource e dos metadados da surface.' },
44905
+ { name: 'enableCustomization', type: 'boolean', description: 'Opt-in explicito para authoring governado da tabela filha.', default: false },
44906
+ { name: 'authoringCapability', type: 'string | null', description: 'Capability publica do EnterpriseRuntimeContext exigida quando o authoring da tabela filha estiver habilitado.' },
44907
+ { name: 'mode', type: "'inline' | 'open-action'", description: 'Renderiza a tabela filha inline ou emite payload para abertura host-mediated.', default: 'inline' },
44908
+ { name: 'state', type: 'RelatedResourceResolutionState | null', description: 'Override de estado para hosts/outlets que estejam carregando discovery remoto.' },
44909
+ { name: 'stateReason', type: 'string | null', description: 'Motivo governado associado ao override de estado.' },
44910
+ { name: 'compact', type: 'boolean', description: 'Reduz densidade visual dos estados não materializados.', default: false },
44911
+ { name: 'strictValidation', type: 'boolean', description: 'Validação estrita do widget materializado pelo DynamicWidgetLoader.', default: false },
44912
+ { name: 'ownerWidgetKey', type: 'string', description: 'Identidade do owner usada para correlacionar eventos do widget filho.', default: 'related-resource.outlet' },
44913
+ ],
44914
+ outputs: [
44915
+ { name: 'surfaceOpen', type: 'SurfaceOpenPayload', description: 'Emitido em modo open-action com o payload pronto de surface.open.' },
44916
+ { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos do widget filho materializado.' },
44917
+ { name: 'resourceEvent', type: 'PraxisResourceEvent', description: 'Promove eventos canonicos emitidos pelo widget filho materializado.' },
44918
+ ],
44919
+ ports: PRAXIS_RELATED_RESOURCE_OUTLET_PORTS,
44920
+ configEditor: {
44921
+ component: PraxisRelatedResourceOutletConfigEditorComponent,
44922
+ title: 'Related resource presentation',
44923
+ },
44924
+ authoringManifestRef: {
44925
+ componentId: 'praxis-related-resource-outlet',
44926
+ version: '1.0.0',
44927
+ source: 'PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST',
44928
+ },
44929
+ tags: ['resource', 'surface', 'related-resource', 'runtime', 'metadata-driven'],
44930
+ lib: '@praxisui/core',
44931
+ };
44932
+ function providePraxisRelatedResourceOutletMetadata() {
44933
+ return {
44934
+ provide: ENVIRONMENT_INITIALIZER,
44935
+ multi: true,
44936
+ useFactory: (registry) => () => {
44937
+ registry.register(PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA);
44938
+ },
44939
+ deps: [ComponentMetadataRegistry],
44940
+ };
44941
+ }
44942
+
44943
+ const nullableTextSchema = {
44944
+ oneOf: [{ type: 'string' }, { type: 'null' }],
44945
+ };
44946
+ const presentationValidators = [
44947
+ 'component-config-editor-respected',
44948
+ 'editor-round-trip-preserve',
44949
+ ];
44950
+ const PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST = {
44951
+ schemaVersion: '1.0.0',
44952
+ componentId: 'praxis-related-resource-outlet',
44953
+ ownerPackage: '@praxisui/core',
44954
+ configSchemaId: 'PraxisRelatedResourceOutletPresentationInputs',
44955
+ manifestVersion: '1.0.0',
44956
+ runtimeInputs: [
44957
+ { name: 'title', type: 'string | null', description: 'Optional visual title override.' },
44958
+ { name: 'subtitle', type: 'string | null', description: 'Optional visual subtitle override.' },
44959
+ { name: 'icon', type: 'string | null', description: 'Optional visual icon override.' },
44960
+ { name: 'mode', type: "'inline' | 'open-action'", allowedValues: ['inline', 'open-action'], description: 'Outlet display mode.' },
44961
+ { name: 'presentation', type: "'drawer' | 'modal'", allowedValues: ['drawer', 'modal'], description: 'Host-mediated presentation used by open-action mode.' },
44962
+ { name: 'compact', type: 'boolean', allowedValues: [true, false], description: 'Compact visual density for non-materialized states.' },
44963
+ {
44964
+ name: 'emptyState',
44965
+ type: 'PraxisRelatedResourceOutletEmptyStatePresentation',
44966
+ description: 'Closed presentation-only empty-state subset. Actions, templates and contexts are not authorable here.',
44967
+ },
44968
+ ],
44969
+ editableTargets: [
44970
+ {
44971
+ kind: 'relatedResourceOutletPresentation',
44972
+ resolver: 'component-config',
44973
+ description: 'Persisted visual shell inputs owned by the Related Resource Outlet config editor.',
44974
+ },
44975
+ {
44976
+ kind: 'relatedResourceOutletEmptyStatePresentation',
44977
+ resolver: 'component-config',
44978
+ description: 'Persisted presentation-only emptyState subset; opaque empty-state fields are preserved unchanged.',
44979
+ },
44980
+ ],
44981
+ operations: [
44982
+ {
44983
+ operationId: 'related-resource-outlet.presentation.set-title',
44984
+ title: 'Set related-resource title',
44985
+ description: 'Sets only the persisted visual title; relationship metadata and runtime context remain unchanged.',
44986
+ scope: 'global',
44987
+ targetKind: 'relatedResourceOutletPresentation',
44988
+ target: {
44989
+ kind: 'relatedResourceOutletPresentation',
44990
+ resolver: 'component-config',
44991
+ ambiguityPolicy: 'fail',
44992
+ required: false,
44993
+ },
44994
+ inputSchema: {
44995
+ type: 'object',
44996
+ additionalProperties: false,
44997
+ required: ['value'],
44998
+ properties: { value: nullableTextSchema },
44999
+ },
45000
+ effects: [{ kind: 'set-value', path: 'title', inputPath: 'value' }],
45001
+ destructive: false,
45002
+ requiresConfirmation: false,
45003
+ validators: presentationValidators,
45004
+ affectedPaths: ['title'],
45005
+ submissionImpact: 'visual-only',
45006
+ preconditions: ['component-config-loaded'],
45007
+ },
45008
+ {
45009
+ operationId: 'related-resource-outlet.presentation.set-subtitle',
45010
+ title: 'Set related-resource subtitle',
45011
+ description: 'Sets only the persisted visual subtitle; relationship metadata and runtime context remain unchanged.',
45012
+ scope: 'global',
45013
+ targetKind: 'relatedResourceOutletPresentation',
45014
+ target: {
45015
+ kind: 'relatedResourceOutletPresentation',
45016
+ resolver: 'component-config',
45017
+ ambiguityPolicy: 'fail',
45018
+ required: false,
45019
+ },
45020
+ inputSchema: {
45021
+ type: 'object',
45022
+ additionalProperties: false,
45023
+ required: ['value'],
45024
+ properties: { value: nullableTextSchema },
45025
+ },
45026
+ effects: [{ kind: 'set-value', path: 'subtitle', inputPath: 'value' }],
45027
+ destructive: false,
45028
+ requiresConfirmation: false,
45029
+ validators: presentationValidators,
45030
+ affectedPaths: ['subtitle'],
45031
+ submissionImpact: 'visual-only',
45032
+ preconditions: ['component-config-loaded'],
45033
+ },
45034
+ {
45035
+ operationId: 'related-resource-outlet.presentation.set-icon',
45036
+ title: 'Set related-resource icon',
45037
+ description: 'Sets only the persisted visual icon; relationship metadata and runtime context remain unchanged.',
45038
+ scope: 'global',
45039
+ targetKind: 'relatedResourceOutletPresentation',
45040
+ target: {
45041
+ kind: 'relatedResourceOutletPresentation',
45042
+ resolver: 'component-config',
45043
+ ambiguityPolicy: 'fail',
45044
+ required: false,
45045
+ },
45046
+ inputSchema: {
45047
+ type: 'object',
45048
+ additionalProperties: false,
45049
+ required: ['value'],
45050
+ properties: { value: nullableTextSchema },
45051
+ },
45052
+ effects: [{ kind: 'set-value', path: 'icon', inputPath: 'value' }],
45053
+ destructive: false,
45054
+ requiresConfirmation: false,
45055
+ validators: presentationValidators,
45056
+ affectedPaths: ['icon'],
45057
+ submissionImpact: 'visual-only',
45058
+ preconditions: ['component-config-loaded'],
45059
+ },
45060
+ {
45061
+ operationId: 'related-resource-outlet.presentation.set-mode',
45062
+ title: 'Set related-resource display mode',
45063
+ description: 'Selects inline rendering or a host-mediated open action without changing the relationship or its operation.',
45064
+ scope: 'global',
45065
+ targetKind: 'relatedResourceOutletPresentation',
45066
+ target: {
45067
+ kind: 'relatedResourceOutletPresentation',
45068
+ resolver: 'component-config',
45069
+ ambiguityPolicy: 'fail',
45070
+ required: false,
45071
+ },
45072
+ inputSchema: {
45073
+ type: 'object',
45074
+ additionalProperties: false,
45075
+ required: ['value'],
45076
+ properties: { value: { enum: ['inline', 'open-action'] } },
45077
+ },
45078
+ effects: [{ kind: 'set-value', path: 'mode', inputPath: 'value' }],
45079
+ destructive: false,
45080
+ requiresConfirmation: false,
45081
+ validators: presentationValidators,
45082
+ affectedPaths: ['mode'],
45083
+ submissionImpact: 'visual-only',
45084
+ preconditions: ['component-config-loaded'],
45085
+ },
45086
+ {
45087
+ operationId: 'related-resource-outlet.presentation.set-open-presentation',
45088
+ title: 'Set related-resource open presentation',
45089
+ description: 'Selects drawer or modal for the host-mediated open payload without changing target resource semantics.',
45090
+ scope: 'global',
45091
+ targetKind: 'relatedResourceOutletPresentation',
45092
+ target: {
45093
+ kind: 'relatedResourceOutletPresentation',
45094
+ resolver: 'component-config',
45095
+ ambiguityPolicy: 'fail',
45096
+ required: false,
45097
+ },
45098
+ inputSchema: {
45099
+ type: 'object',
45100
+ additionalProperties: false,
45101
+ required: ['value'],
45102
+ properties: { value: { enum: ['drawer', 'modal'] } },
45103
+ },
45104
+ effects: [{ kind: 'set-value', path: 'presentation', inputPath: 'value' }],
45105
+ destructive: false,
45106
+ requiresConfirmation: false,
45107
+ validators: presentationValidators,
45108
+ affectedPaths: ['presentation'],
45109
+ submissionImpact: 'visual-only',
45110
+ preconditions: ['component-config-loaded'],
45111
+ },
45112
+ {
45113
+ operationId: 'related-resource-outlet.presentation.set-compact',
45114
+ title: 'Set compact related-resource states',
45115
+ description: 'Changes only the visual density of non-materialized outlet states.',
45116
+ scope: 'global',
45117
+ targetKind: 'relatedResourceOutletPresentation',
45118
+ target: {
45119
+ kind: 'relatedResourceOutletPresentation',
45120
+ resolver: 'component-config',
45121
+ ambiguityPolicy: 'fail',
45122
+ required: false,
45123
+ },
45124
+ inputSchema: {
45125
+ type: 'object',
45126
+ additionalProperties: false,
45127
+ required: ['value'],
45128
+ properties: { value: { type: 'boolean' } },
45129
+ },
45130
+ effects: [{ kind: 'set-value', path: 'compact', inputPath: 'value' }],
45131
+ destructive: false,
45132
+ requiresConfirmation: false,
45133
+ validators: presentationValidators,
45134
+ affectedPaths: ['compact'],
45135
+ submissionImpact: 'visual-only',
45136
+ preconditions: ['component-config-loaded'],
45137
+ },
45138
+ {
45139
+ operationId: 'related-resource-outlet.presentation.configure-empty-state',
45140
+ title: 'Configure related-resource empty-state presentation',
45141
+ description: 'Merges only the closed presentation subset; actions, contexts, images, templates and unknown fields remain opaque.',
45142
+ scope: 'global',
45143
+ targetKind: 'relatedResourceOutletEmptyStatePresentation',
45144
+ target: {
45145
+ kind: 'relatedResourceOutletEmptyStatePresentation',
45146
+ resolver: 'component-config',
45147
+ ambiguityPolicy: 'fail',
45148
+ required: false,
45149
+ },
45150
+ inputSchema: {
45151
+ type: 'object',
45152
+ additionalProperties: false,
45153
+ minProperties: 1,
45154
+ properties: {
45155
+ title: nullableTextSchema,
45156
+ message: nullableTextSchema,
45157
+ description: nullableTextSchema,
45158
+ icon: nullableTextSchema,
45159
+ tone: { oneOf: [{ enum: ['neutral', 'primary', 'secondary'] }, { type: 'null' }] },
45160
+ variant: { oneOf: [{ enum: ['card', 'inline', 'panel', 'transparent'] }, { type: 'null' }] },
45161
+ alignment: { oneOf: [{ enum: ['start', 'center'] }, { type: 'null' }] },
45162
+ density: { oneOf: [{ enum: ['compact', 'comfortable'] }, { type: 'null' }] },
45163
+ iconContainer: { oneOf: [{ enum: ['none', 'circle', 'soft'] }, { type: 'null' }] },
45164
+ },
45165
+ },
45166
+ effects: [{ kind: 'merge-object', path: 'emptyState' }],
45167
+ destructive: false,
45168
+ requiresConfirmation: false,
45169
+ validators: presentationValidators,
45170
+ affectedPaths: [
45171
+ 'emptyState.title',
45172
+ 'emptyState.message',
45173
+ 'emptyState.description',
45174
+ 'emptyState.icon',
45175
+ 'emptyState.tone',
45176
+ 'emptyState.variant',
45177
+ 'emptyState.alignment',
45178
+ 'emptyState.density',
45179
+ 'emptyState.iconContainer',
45180
+ ],
45181
+ submissionImpact: 'visual-only',
45182
+ preconditions: ['component-config-loaded'],
45183
+ },
45184
+ ],
45185
+ validators: [
45186
+ {
45187
+ validatorId: 'component-config-editor-respected',
45188
+ level: 'error',
45189
+ code: 'RELATED_RESOURCE_OUTLET_CONFIG_EDITOR_RESPECTED',
45190
+ description: 'Only paths owned by the published config editor may be authored.',
45191
+ },
45192
+ {
45193
+ validatorId: 'editor-round-trip-preserve',
45194
+ level: 'error',
45195
+ code: 'RELATED_RESOURCE_OUTLET_EDITOR_ROUND_TRIP_PRESERVE',
45196
+ description: 'Save and reopen must preserve runtime, relationship, Table-owned and unknown persisted inputs without drift.',
45197
+ },
45198
+ ],
45199
+ roundTripRequirements: [
45200
+ 'Opening the editor must never materialize runtime inputs or mutate the persisted widget definition.',
45201
+ 'Apply, Save, Reset and Reopen must preserve every input outside the presentation-only editor boundary byte-for-byte.',
45202
+ 'parentResourceId, surfaceId, surface, parentRecord, queryContext, state, relationship semantics and tableConfig are never authorable by this manifest.',
45203
+ 'Unknown root inputs and unknown or behavior-bearing emptyState fields remain opaque and are preserved unchanged.',
45204
+ ],
45205
+ examples: [
45206
+ {
45207
+ id: 'set-related-resource-shell',
45208
+ request: 'Show the related participants inline with the title Participants and compact states.',
45209
+ operationId: 'related-resource-outlet.presentation.set-title',
45210
+ params: { value: 'Participants' },
45211
+ isPositive: true,
45212
+ },
45213
+ {
45214
+ id: 'set-related-resource-empty-state-copy',
45215
+ request: 'Use No participants yet as the empty-state title.',
45216
+ operationId: 'related-resource-outlet.presentation.configure-empty-state',
45217
+ params: { title: 'No participants yet' },
45218
+ isPositive: true,
45219
+ },
45220
+ {
45221
+ id: 'reject-related-resource-relationship-authoring',
45222
+ request: 'Change the child resource path, parent field, filter operation and tableConfig from this outlet editor.',
45223
+ operationId: 'related-resource-outlet.presentation.configure-empty-state',
45224
+ params: {
45225
+ childResourcePath: 'operations/participants',
45226
+ childParentField: 'missionId',
45227
+ tableConfig: { columns: [] },
45228
+ },
45229
+ isPositive: false,
45230
+ },
45231
+ ],
45232
+ };
45233
+
45234
+ class EmptyStateCardComponent {
45235
+ icon = 'tab';
45236
+ title = 'Sem configuração disponível';
45237
+ description;
45238
+ primaryAction;
45239
+ secondaryActions = [];
45240
+ inline = false;
45241
+ tone = 'neutral';
45242
+ variant = 'card';
45243
+ alignment = 'start';
45244
+ density = 'comfortable';
45245
+ iconContainer = 'none';
45246
+ effectiveVariant() {
45247
+ return this.inline && this.variant === 'card' ? 'inline' : this.variant;
45248
+ }
45249
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyStateCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
45250
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: EmptyStateCardComponent, isStandalone: true, selector: "praxis-empty-state-card", inputs: { icon: "icon", title: "title", description: "description", primaryAction: "primaryAction", secondaryActions: "secondaryActions", inline: "inline", tone: "tone", variant: "variant", alignment: "alignment", density: "density", iconContainer: "iconContainer" }, ngImport: i0, template: `
45251
+ <mat-card
45252
+ class="empty-card"
45253
+ [class.empty-inline]="inline"
45254
+ [class.tone-primary]="tone === 'primary'"
45255
+ [class.tone-secondary]="tone === 'secondary'"
45256
+ [class.variant-inline]="effectiveVariant() === 'inline'"
45257
+ [class.variant-panel]="effectiveVariant() === 'panel'"
45258
+ [class.variant-transparent]="effectiveVariant() === 'transparent'"
45259
+ [class.align-center]="alignment === 'center'"
45260
+ [class.density-compact]="density === 'compact'"
45261
+ [class.icon-circle]="iconContainer === 'circle'"
45262
+ [class.icon-soft]="iconContainer === 'soft'"
45263
+ appearance="outlined"
45264
+ >
45265
+ <mat-card-content>
45266
+ <div class="content">
45267
+ @if (icon) {
45268
+ <mat-icon class="icon" [fontIcon]="icon"></mat-icon>
45269
+ }
45270
+ <div class="texts">
45271
+ <h3 class="title">{{ title }}</h3>
45272
+ @if (description) {
45273
+ <p class="desc">{{ description }}</p>
45274
+ }
45275
+ </div>
45276
+ </div>
45277
+ <div class="actions">
45278
+ @if (primaryAction) {
45279
+ <button type="button" mat-flat-button color="primary" (click)="primaryAction.action()">
45280
+ @if (primaryAction.icon) {
45281
+ <mat-icon [fontIcon]="primaryAction.icon"></mat-icon>
45282
+ }
45283
+ {{ primaryAction.label }}
45284
+ </button>
45285
+ }
45286
+ @for (a of secondaryActions; track a) {
45287
+ <button type="button" mat-stroked-button [color]="a.color" (click)="a.action()">
45288
+ @if (a.icon) {
45289
+ <mat-icon [fontIcon]="a.icon"></mat-icon>
45290
+ }
45291
+ {{ a.label }}
45292
+ </button>
45293
+ }
45294
+ </div>
45295
+ </mat-card-content>
45296
+ </mat-card>
45297
+ `, isInline: true, styles: [".empty-card{display:block;margin:var(--pdx-empty-state-margin, 12px);border-color:var(--pdx-empty-state-border-color, var(--md-sys-color-outline-variant));border-radius:var(--pdx-empty-state-radius, 8px);background:var(--pdx-empty-state-bg, var(--md-sys-color-surface));color:var(--pdx-empty-state-fg, var(--md-sys-color-on-surface));--empty-icon-color: var(--pdx-empty-state-icon-color, var(--md-sys-color-on-surface-variant))}.empty-card.empty-inline,.empty-card.variant-inline{margin:var(--pdx-empty-state-inline-margin, 8px 0)}.empty-card.variant-panel{margin:var(--pdx-empty-state-panel-margin, 0)}.empty-card.variant-transparent{margin:var(--pdx-empty-state-transparent-margin, 0);border-color:transparent;background:transparent;box-shadow:none}.content{display:flex;align-items:center;gap:var(--pdx-empty-state-gap, 12px)}.align-center .content{flex-direction:column;justify-content:center;text-align:center}.icon{display:inline-grid;place-items:center;flex:0 0 auto;font-size:var(--pdx-empty-state-icon-size, 32px);width:var(--pdx-empty-state-icon-box-size, 32px);height:var(--pdx-empty-state-icon-box-size, 32px);color:var(--empty-icon-color)}.icon-circle .icon,.icon-soft .icon{width:var(--pdx-empty-state-icon-container-size, 44px);height:var(--pdx-empty-state-icon-container-size, 44px);border-radius:var(--pdx-empty-state-icon-container-radius, 999px);font-size:var(--pdx-empty-state-icon-container-icon-size, 22px)}.icon-circle .icon{border:1px solid var(--pdx-empty-state-icon-container-border-color, color-mix(in srgb, var(--empty-icon-color) 24%, transparent));background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.icon-soft .icon{background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.texts{display:grid;gap:var(--pdx-empty-state-text-gap, 4px)}.align-center .texts{justify-items:center}.title{margin:0;font-family:var(--pdx-empty-state-title-font-family, var(--md-sys-typescale-title-small-font-family, inherit));font-size:var(--pdx-empty-state-title-font-size, 16px);font-weight:var(--pdx-empty-state-title-font-weight, 600);line-height:var(--pdx-empty-state-title-line-height, 1.3);color:var(--pdx-empty-state-title-color, var(--md-sys-color-on-surface))}.desc{margin:0;max-width:var(--pdx-empty-state-description-max-width, none);font-family:var(--pdx-empty-state-description-font-family, var(--md-sys-typescale-body-medium-font-family, inherit));font-size:var(--pdx-empty-state-description-font-size, inherit);line-height:var(--pdx-empty-state-description-line-height, 1.4);color:var(--pdx-empty-state-description-color, var(--md-sys-color-on-surface-variant))}.actions{display:flex;justify-content:var(--pdx-empty-state-actions-justify, flex-start);gap:var(--pdx-empty-state-actions-gap, 8px);margin-top:var(--pdx-empty-state-actions-margin-top, 12px);flex-wrap:wrap}.actions .mat-mdc-button-base{width:fit-content;max-width:100%;height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));padding-inline:var(--pdx-empty-state-action-padding-inline, var(--praxis-action-control-padding-inline, 12px));border-radius:var(--pdx-empty-state-action-radius, var(--praxis-action-control-radius, 8px));gap:var(--pdx-empty-state-action-gap, var(--praxis-action-control-gap, 8px));font-size:var(--pdx-empty-state-action-font-size, var(--praxis-action-control-font-size, .875rem));font-weight:var(--pdx-empty-state-action-font-weight, var(--praxis-action-control-font-weight, 500));line-height:var(--pdx-empty-state-action-line-height, var(--praxis-action-control-line-height, 1.25rem));white-space:nowrap}.actions .mat-mdc-button-base mat-icon{width:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));margin:0;font-size:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));line-height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px))}.actions .mat-mdc-button-base:focus-visible{outline:2px solid var(--pdx-empty-state-action-focus-ring, var(--praxis-action-control-focus-ring, var(--md-sys-color-primary)));outline-offset:2px}.actions .mat-mdc-button-base:disabled{opacity:var(--pdx-empty-state-action-disabled-opacity, var(--praxis-action-control-disabled-opacity, .62))}.align-center .actions{justify-content:var(--pdx-empty-state-actions-justify, center)}.density-compact .content{gap:var(--pdx-empty-state-compact-gap, 8px)}.density-compact .actions .mat-mdc-button-base{height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px))}.density-compact .icon{font-size:var(--pdx-empty-state-compact-icon-size, 24px);width:var(--pdx-empty-state-compact-icon-box-size, 24px);height:var(--pdx-empty-state-compact-icon-box-size, 24px)}.density-compact.icon-circle .icon,.density-compact.icon-soft .icon{width:var(--pdx-empty-state-compact-icon-container-size, 36px);height:var(--pdx-empty-state-compact-icon-container-size, 36px);font-size:var(--pdx-empty-state-compact-icon-container-icon-size, 20px)}.empty-card.tone-primary{--empty-icon-color: var(--md-sys-color-primary)}.empty-card.tone-secondary{--empty-icon-color: var(--md-sys-color-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i2$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i2$1.MatCardContent, selector: "mat-card-content" }, { 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: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
45298
+ }
45299
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EmptyStateCardComponent, decorators: [{
45300
+ type: Component,
45301
+ args: [{ selector: 'praxis-empty-state-card', standalone: true, imports: [MatCardModule, MatButtonModule, MatIconModule], template: `
45302
+ <mat-card
45303
+ class="empty-card"
45304
+ [class.empty-inline]="inline"
45305
+ [class.tone-primary]="tone === 'primary'"
45306
+ [class.tone-secondary]="tone === 'secondary'"
45307
+ [class.variant-inline]="effectiveVariant() === 'inline'"
45308
+ [class.variant-panel]="effectiveVariant() === 'panel'"
45309
+ [class.variant-transparent]="effectiveVariant() === 'transparent'"
45310
+ [class.align-center]="alignment === 'center'"
45311
+ [class.density-compact]="density === 'compact'"
45312
+ [class.icon-circle]="iconContainer === 'circle'"
45313
+ [class.icon-soft]="iconContainer === 'soft'"
45314
+ appearance="outlined"
45315
+ >
45316
+ <mat-card-content>
45317
+ <div class="content">
45318
+ @if (icon) {
45319
+ <mat-icon class="icon" [fontIcon]="icon"></mat-icon>
45320
+ }
45321
+ <div class="texts">
45322
+ <h3 class="title">{{ title }}</h3>
45323
+ @if (description) {
45324
+ <p class="desc">{{ description }}</p>
45325
+ }
45326
+ </div>
45327
+ </div>
45328
+ <div class="actions">
45329
+ @if (primaryAction) {
45330
+ <button type="button" mat-flat-button color="primary" (click)="primaryAction.action()">
45331
+ @if (primaryAction.icon) {
45332
+ <mat-icon [fontIcon]="primaryAction.icon"></mat-icon>
45333
+ }
45334
+ {{ primaryAction.label }}
45335
+ </button>
45336
+ }
45337
+ @for (a of secondaryActions; track a) {
45338
+ <button type="button" mat-stroked-button [color]="a.color" (click)="a.action()">
45339
+ @if (a.icon) {
45340
+ <mat-icon [fontIcon]="a.icon"></mat-icon>
45341
+ }
45342
+ {{ a.label }}
45343
+ </button>
45344
+ }
45345
+ </div>
45346
+ </mat-card-content>
45347
+ </mat-card>
45348
+ `, styles: [".empty-card{display:block;margin:var(--pdx-empty-state-margin, 12px);border-color:var(--pdx-empty-state-border-color, var(--md-sys-color-outline-variant));border-radius:var(--pdx-empty-state-radius, 8px);background:var(--pdx-empty-state-bg, var(--md-sys-color-surface));color:var(--pdx-empty-state-fg, var(--md-sys-color-on-surface));--empty-icon-color: var(--pdx-empty-state-icon-color, var(--md-sys-color-on-surface-variant))}.empty-card.empty-inline,.empty-card.variant-inline{margin:var(--pdx-empty-state-inline-margin, 8px 0)}.empty-card.variant-panel{margin:var(--pdx-empty-state-panel-margin, 0)}.empty-card.variant-transparent{margin:var(--pdx-empty-state-transparent-margin, 0);border-color:transparent;background:transparent;box-shadow:none}.content{display:flex;align-items:center;gap:var(--pdx-empty-state-gap, 12px)}.align-center .content{flex-direction:column;justify-content:center;text-align:center}.icon{display:inline-grid;place-items:center;flex:0 0 auto;font-size:var(--pdx-empty-state-icon-size, 32px);width:var(--pdx-empty-state-icon-box-size, 32px);height:var(--pdx-empty-state-icon-box-size, 32px);color:var(--empty-icon-color)}.icon-circle .icon,.icon-soft .icon{width:var(--pdx-empty-state-icon-container-size, 44px);height:var(--pdx-empty-state-icon-container-size, 44px);border-radius:var(--pdx-empty-state-icon-container-radius, 999px);font-size:var(--pdx-empty-state-icon-container-icon-size, 22px)}.icon-circle .icon{border:1px solid var(--pdx-empty-state-icon-container-border-color, color-mix(in srgb, var(--empty-icon-color) 24%, transparent));background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.icon-soft .icon{background:var(--pdx-empty-state-icon-container-bg, color-mix(in srgb, var(--empty-icon-color) 10%, transparent))}.texts{display:grid;gap:var(--pdx-empty-state-text-gap, 4px)}.align-center .texts{justify-items:center}.title{margin:0;font-family:var(--pdx-empty-state-title-font-family, var(--md-sys-typescale-title-small-font-family, inherit));font-size:var(--pdx-empty-state-title-font-size, 16px);font-weight:var(--pdx-empty-state-title-font-weight, 600);line-height:var(--pdx-empty-state-title-line-height, 1.3);color:var(--pdx-empty-state-title-color, var(--md-sys-color-on-surface))}.desc{margin:0;max-width:var(--pdx-empty-state-description-max-width, none);font-family:var(--pdx-empty-state-description-font-family, var(--md-sys-typescale-body-medium-font-family, inherit));font-size:var(--pdx-empty-state-description-font-size, inherit);line-height:var(--pdx-empty-state-description-line-height, 1.4);color:var(--pdx-empty-state-description-color, var(--md-sys-color-on-surface-variant))}.actions{display:flex;justify-content:var(--pdx-empty-state-actions-justify, flex-start);gap:var(--pdx-empty-state-actions-gap, 8px);margin-top:var(--pdx-empty-state-actions-margin-top, 12px);flex-wrap:wrap}.actions .mat-mdc-button-base{width:fit-content;max-width:100%;height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-height, 40px));padding-inline:var(--pdx-empty-state-action-padding-inline, var(--praxis-action-control-padding-inline, 12px));border-radius:var(--pdx-empty-state-action-radius, var(--praxis-action-control-radius, 8px));gap:var(--pdx-empty-state-action-gap, var(--praxis-action-control-gap, 8px));font-size:var(--pdx-empty-state-action-font-size, var(--praxis-action-control-font-size, .875rem));font-weight:var(--pdx-empty-state-action-font-weight, var(--praxis-action-control-font-weight, 500));line-height:var(--pdx-empty-state-action-line-height, var(--praxis-action-control-line-height, 1.25rem));white-space:nowrap}.actions .mat-mdc-button-base mat-icon{width:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));margin:0;font-size:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px));line-height:var(--pdx-empty-state-action-icon-size, var(--praxis-action-control-icon-size, 18px))}.actions .mat-mdc-button-base:focus-visible{outline:2px solid var(--pdx-empty-state-action-focus-ring, var(--praxis-action-control-focus-ring, var(--md-sys-color-primary)));outline-offset:2px}.actions .mat-mdc-button-base:disabled{opacity:var(--pdx-empty-state-action-disabled-opacity, var(--praxis-action-control-disabled-opacity, .62))}.align-center .actions{justify-content:var(--pdx-empty-state-actions-justify, center)}.density-compact .content{gap:var(--pdx-empty-state-compact-gap, 8px)}.density-compact .actions .mat-mdc-button-base{height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px));min-height:var(--pdx-empty-state-action-height, var(--praxis-action-control-compact-height, 36px))}.density-compact .icon{font-size:var(--pdx-empty-state-compact-icon-size, 24px);width:var(--pdx-empty-state-compact-icon-box-size, 24px);height:var(--pdx-empty-state-compact-icon-box-size, 24px)}.density-compact.icon-circle .icon,.density-compact.icon-soft .icon{width:var(--pdx-empty-state-compact-icon-container-size, 36px);height:var(--pdx-empty-state-compact-icon-container-size, 36px);font-size:var(--pdx-empty-state-compact-icon-container-icon-size, 20px)}.empty-card.tone-primary{--empty-icon-color: var(--md-sys-color-primary)}.empty-card.tone-secondary{--empty-icon-color: var(--md-sys-color-secondary)}\n"] }]
45349
+ }], propDecorators: { icon: [{
45350
+ type: Input
45351
+ }], title: [{
45352
+ type: Input
45353
+ }], description: [{
45354
+ type: Input
45355
+ }], primaryAction: [{
45356
+ type: Input
45357
+ }], secondaryActions: [{
45358
+ type: Input
45359
+ }], inline: [{
45360
+ type: Input
45361
+ }], tone: [{
45362
+ type: Input
45363
+ }], variant: [{
45364
+ type: Input
45365
+ }], alignment: [{
45366
+ type: Input
45367
+ }], density: [{
45368
+ type: Input
45369
+ }], iconContainer: [{
45370
+ type: Input
45371
+ }] } });
45372
+
45373
+ class ResourceQuickConnectComponent {
45374
+ resourcePath = '';
45375
+ isDirty$ = new BehaviorSubject(false);
45376
+ isValid$ = new BehaviorSubject(false);
45377
+ isBusy$ = new BehaviorSubject(false);
45378
+ // Values are provided via Inputs by the opener; no DI data coupling required.
45379
+ // When used standalone, consumers can bind [(resourcePath)].
45380
+ ngOnInit() {
45381
+ this.updateValidity();
45382
+ }
45383
+ ngOnChanges() {
45384
+ this.updateValidity();
45385
+ }
45386
+ updateState() {
45387
+ this.isDirty$.next(true);
45388
+ this.updateValidity();
45389
+ }
45390
+ updateValidity() {
45391
+ const trimmed = this.resourcePath?.trim() || '';
45392
+ this.isValid$.next(!!trimmed && this.isValidPath(trimmed));
45393
+ }
45394
+ getSettingsValue() {
45395
+ return { resourcePath: this.normalizedPath() };
45396
+ }
45397
+ onSave() {
45398
+ return this.getSettingsValue();
45399
+ }
45400
+ showInvalid() {
45401
+ const trimmed = this.resourcePath?.trim() || '';
45402
+ return !!trimmed && !this.isValidPath(trimmed);
45403
+ }
45404
+ normalizedPath() {
45405
+ const trimmed = this.resourcePath?.trim() || '';
45406
+ if (!trimmed)
45407
+ return '';
45408
+ if (trimmed.startsWith('/'))
45409
+ return trimmed;
45410
+ if (trimmed.startsWith('http://') || trimmed.startsWith('https://'))
45411
+ return trimmed;
45412
+ return `/${trimmed}`;
45413
+ }
45414
+ isValidPath(value) {
45415
+ if (value.startsWith('http://') || value.startsWith('https://'))
45416
+ return true;
45417
+ return /^\/?[a-zA-Z0-9][a-zA-Z0-9/_-]*$/.test(value);
45418
+ }
45419
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
45420
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: ResourceQuickConnectComponent, isStandalone: true, selector: "praxis-resource-quick-connect", inputs: { resourcePath: "resourcePath" }, usesOnChanges: true, ngImport: i0, template: `
45421
+ <div class="pdx-quick-connect">
45422
+ <mat-form-field appearance="outline">
45423
+ <mat-label>Rota do recurso (API)</mat-label>
45424
+ <input
45425
+ matInput
45426
+ [(ngModel)]="resourcePath"
45427
+ (ngModelChange)="updateState()"
45428
+ placeholder="ex.: human-resources/departamentos"
45429
+ />
45430
+ <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
45431
+ @if (showInvalid()) {
45432
+ <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
45433
+ }
45434
+ </mat-form-field>
45435
+ <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
45436
+ @if (normalizedPath() && normalizedPath() !== resourcePath) {
45437
+ <small class="pdx-quick-connect__hint">
45438
+ Rota normalizada: {{ normalizedPath() }}
45439
+ </small>
45440
+ }
45441
+ </div>
45442
+ `, isInline: true, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.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$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4.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: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
45443
+ }
45444
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: ResourceQuickConnectComponent, decorators: [{
45445
+ type: Component,
45446
+ args: [{ selector: 'praxis-resource-quick-connect', standalone: true, imports: [FormsModule, MatFormFieldModule, MatInputModule, MatIconModule, PraxisIconDirective], template: `
45447
+ <div class="pdx-quick-connect">
45448
+ <mat-form-field appearance="outline">
45449
+ <mat-label>Rota do recurso (API)</mat-label>
45450
+ <input
45451
+ matInput
45452
+ [(ngModel)]="resourcePath"
45453
+ (ngModelChange)="updateState()"
45454
+ placeholder="ex.: human-resources/departamentos"
45455
+ />
45456
+ <mat-icon matSuffix [praxisIcon]="'link'"></mat-icon>
45457
+ @if (showInvalid()) {
45458
+ <mat-error>Use apenas letras, números, /, - ou _.</mat-error>
45459
+ }
45460
+ </mat-form-field>
45461
+ <small class="pdx-quick-connect__hint">Conecte o componente à fonte de dados (ex.: /api/&lt;rota-do-recurso&gt;)</small>
45462
+ @if (normalizedPath() && normalizedPath() !== resourcePath) {
45463
+ <small class="pdx-quick-connect__hint">
45464
+ Rota normalizada: {{ normalizedPath() }}
45465
+ </small>
45466
+ }
45467
+ </div>
45468
+ `, styles: [".pdx-quick-connect{display:grid;gap:12px;padding:12px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.pdx-quick-connect__hint{color:var(--md-sys-color-on-surface-variant);font-size:.9rem}\n"] }]
45469
+ }], propDecorators: { resourcePath: [{
45470
+ type: Input
45471
+ }] } });
45472
+
43791
45473
  /** Optional DI token used by SchemaViewer when input is not provided. */
43792
45474
  const SCHEMA_VIEWER_CONTEXT = new InjectionToken('SCHEMA_VIEWER_CONTEXT');
43793
45475
 
@@ -44702,4 +46384,4 @@ function provideHookWhitelist(allowed) {
44702
46384
  * Generated bundle index. Do not edit.
44703
46385
  */
44704
46386
 
44705
- export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
46387
+ export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentAuthoringManifestProjectionError, ComponentKeyService, ComponentMetadataRegistry, ComponentRuntimeProfileService, CompositionRuntimeFacade, CompositionValidatorService, ConsoleLoggerSink, CrudOperationResolutionService, DEFAULT_FIELD_SELECTOR_CONTROL_TYPE_MAP, DEFAULT_JSON_LOGIC_OPERATORS, DEFAULT_TABLE_CONFIG, DOMAIN_CATALOG_COMPONENT_CONTEXT_PACK, DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION, DYNAMIC_PAGE_AI_CAPABILITIES, DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK, DYNAMIC_PAGE_CONFIG_EDITOR, DYNAMIC_PAGE_SHELL_EDITOR, DefaultLoadingRenderer, DeferredAsyncConfigStorage, DomainCatalogService, DomainKnowledgeService, DomainRuleService, DynamicFormService, DynamicWidgetLoaderDirective, DynamicWidgetPageComponent, EDITORIAL_ALLOWED_CONTENT_FORMATS, EDITORIAL_COMPLIANCE_PRESETS, EDITORIAL_EXTERNAL_LINK_REL, EDITORIAL_FORM_TEMPLATE_CATALOG, EDITORIAL_HTML_ENABLED, EDITORIAL_MARKDOWN_IMAGES_ENABLED, EDITORIAL_SOLUTION_CATALOG, EDITORIAL_SOLUTION_PRESETS, EDITORIAL_THEME_PRESETS, EDITORIAL_WIDGET_CONVENTION_INPUTS, EDITORIAL_WIDGET_TAG, EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_SOLUTION, EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE, EVENT_REGISTRATION_EDITORIAL_SOLUTION, EVENT_REGISTRATION_EDITORIAL_TEMPLATE, EmptyStateCardComponent, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_ACTION_CONTROL_DEFAULTS, PRAXIS_ACTION_CONTROL_VARS, PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_COLLECTION_SEARCH_DEFAULTS, PRAXIS_COLLECTION_SEARCH_VARS, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_RELATED_RESOURCE_OUTLET_AUTHORING_MANIFEST, PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisRelatedResourceOutletConfigEditorComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_DRAWER_CONTENT_DATA, SURFACE_DRAWER_REF, SURFACE_NAVIGATION_I18N_CONFIG, SURFACE_NAVIGATION_I18N_NAMESPACE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceNavigationError, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisActionControlCss, buildPraxisCollectionSearchCss, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isDomainRuleSnapshotProblemResponse, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isSurfaceNavigationError, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeReactiveDeterminations, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, normalizeStart, normalizeSurfaceOperationContext, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, projectComponentAuthoringManifest, projectGroupedCommandPartialRows, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveGroupedCommandPartialRowSpans, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateSurfaceNavigationRejected, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };