@praxisui/core 8.0.0-beta.20 → 8.0.0-beta.22

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.
@@ -10,7 +10,7 @@ import { Router, ActivatedRoute } from '@angular/router';
10
10
  import * as i1$1 from '@angular/forms';
11
11
  import { Validators, FormGroup, FormControl, FormArray, FormsModule } from '@angular/forms';
12
12
  import { MatSnackBar } from '@angular/material/snack-bar';
13
- import * as i3$1 from '@angular/material/icon';
13
+ import * as i2$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';
@@ -22,18 +22,18 @@ import * as i6 from '@angular/material/select';
22
22
  import { MatSelectModule } from '@angular/material/select';
23
23
  import * as i7 from '@angular/material/slide-toggle';
24
24
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
25
- import * as i8 from '@angular/material/tooltip';
25
+ import * as i4 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$2 from '@angular/material/card';
30
+ import * as i3$1 from '@angular/material/card';
31
31
  import { MatCardModule } from '@angular/material/card';
32
- import * as i8$1 from '@angular/material/chips';
32
+ import * as i8 from '@angular/material/chips';
33
33
  import { MatChipsModule } from '@angular/material/chips';
34
34
  import * as i1$3 from '@angular/material/dialog';
35
35
  import { MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
36
- import * as i2$1 from '@angular/material/tabs';
36
+ import * as i2$2 from '@angular/material/tabs';
37
37
  import { MatTabsModule } from '@angular/material/tabs';
38
38
 
39
39
  class PraxisCore {
@@ -829,6 +829,7 @@ const LOOKUP_OPEN_DETAIL_MODES = new Set([
829
829
  'newTab',
830
830
  'drawer',
831
831
  'modal',
832
+ 'route',
832
833
  ]);
833
834
  const LOOKUP_FILTER_FIELD_TYPES = new Set([
834
835
  'text',
@@ -4395,7 +4396,7 @@ class GenericCrudService {
4395
4396
  return Number.isFinite(parsed) ? parsed : null;
4396
4397
  }
4397
4398
  tryParseDateMillis(value) {
4398
- if (value instanceof Date) {
4399
+ if (this.isDateValue(value)) {
4399
4400
  const ms = value.getTime();
4400
4401
  return Number.isNaN(ms) ? null : ms;
4401
4402
  }
@@ -4455,11 +4456,52 @@ class GenericCrudService {
4455
4456
  if (value === null || value === undefined) {
4456
4457
  return null;
4457
4458
  }
4458
- if (typeof value === 'string' && value.trim() === '') {
4459
- return null;
4459
+ if (this.isDateValue(value)) {
4460
+ return this.formatDateOnly(value);
4461
+ }
4462
+ if (typeof value === 'string') {
4463
+ const text = value.trim();
4464
+ if (text === '') {
4465
+ return null;
4466
+ }
4467
+ const numeric = this.tryParseLocalizedRangeNumber(text);
4468
+ if (numeric !== null) {
4469
+ return numeric;
4470
+ }
4471
+ return text;
4460
4472
  }
4461
4473
  return value;
4462
4474
  }
4475
+ isDateValue(value) {
4476
+ return Object.prototype.toString.call(value) === '[object Date]'
4477
+ && typeof value.getTime === 'function'
4478
+ && typeof value.getFullYear === 'function'
4479
+ && typeof value.getMonth === 'function'
4480
+ && typeof value.getDate === 'function';
4481
+ }
4482
+ formatDateOnly(value) {
4483
+ if (Number.isNaN(value.getTime())) {
4484
+ return value;
4485
+ }
4486
+ const year = value.getFullYear();
4487
+ const month = String(value.getMonth() + 1).padStart(2, '0');
4488
+ const day = String(value.getDate()).padStart(2, '0');
4489
+ return `${year}-${month}-${day}`;
4490
+ }
4491
+ tryParseLocalizedRangeNumber(text) {
4492
+ const compact = text.replace(/\s+/g, '');
4493
+ const numericText = compact.replace(/[^\d,.\-+]/g, '');
4494
+ if (!numericText) {
4495
+ return null;
4496
+ }
4497
+ const hasCurrencyMarker = /[R$€£¥]/.test(text);
4498
+ const hasDecimalComma = numericText.includes(',');
4499
+ const hasThousandsDot = /^[+-]?\d{1,3}(?:\.\d{3})+(?:,\d+)?$/.test(numericText);
4500
+ if (!hasCurrencyMarker && !hasDecimalComma && !hasThousandsDot) {
4501
+ return null;
4502
+ }
4503
+ return this.tryParseNumeric(numericText);
4504
+ }
4463
4505
  isRangeValue(value) {
4464
4506
  return value !== null && value !== undefined && !(typeof value === 'string' && value.trim() === '');
4465
4507
  }
@@ -6357,7 +6399,7 @@ function getGlobalActionUiSchema(id) {
6357
6399
  return GLOBAL_ACTION_UI_SCHEMAS.find((schema) => schema.id === id);
6358
6400
  }
6359
6401
 
6360
- function normalizeGlobalActionRef(ref) {
6402
+ function normalizeGlobalActionRef$1(ref) {
6361
6403
  const actionId = String(ref?.actionId || '').trim();
6362
6404
  if (!actionId)
6363
6405
  return null;
@@ -6445,7 +6487,7 @@ function getGlobalActionPayloadTypeIssue(ref, catalogEntry) {
6445
6487
  function validateGlobalActionRef(ref, catalogEntry, path) {
6446
6488
  if (!ref)
6447
6489
  return [];
6448
- const normalized = normalizeGlobalActionRef(ref);
6490
+ const normalized = normalizeGlobalActionRef$1(ref);
6449
6491
  if (!normalized) {
6450
6492
  return [{ code: 'globalAction.actionId.required', path }];
6451
6493
  }
@@ -6536,7 +6578,7 @@ class GlobalActionService {
6536
6578
  }
6537
6579
  }
6538
6580
  async executeRef(ref, context) {
6539
- const normalized = normalizeGlobalActionRef(ref);
6581
+ const normalized = normalizeGlobalActionRef$1(ref);
6540
6582
  if (!normalized) {
6541
6583
  return { success: false, error: 'Global action ref requires actionId' };
6542
6584
  }
@@ -8904,6 +8946,23 @@ function normalizeOptionSource(optionSource) {
8904
8946
  }
8905
8947
  return normalized;
8906
8948
  }
8949
+ function normalizeIconName(icon) {
8950
+ const value = String(icon ?? '').trim();
8951
+ return value.length ? value : undefined;
8952
+ }
8953
+ function normalizeIconPosition(position) {
8954
+ const value = String(position ?? '').trim().toLowerCase();
8955
+ if (!value) {
8956
+ return undefined;
8957
+ }
8958
+ if (['start', 'left', 'before', 'prefix', 'leading'].includes(value)) {
8959
+ return 'start';
8960
+ }
8961
+ if (['end', 'right', 'after', 'suffix', 'trailing'].includes(value)) {
8962
+ return 'end';
8963
+ }
8964
+ return undefined;
8965
+ }
8907
8966
  /**
8908
8967
  * Converte um FieldDefinition em FieldMetadata.
8909
8968
  *
@@ -8992,6 +9051,7 @@ function mapFieldDefinitionToMetadata(field) {
8992
9051
  'iconClass',
8993
9052
  'iconStyle',
8994
9053
  'iconFontSize',
9054
+ 'iconSize',
8995
9055
  'filterField',
8996
9056
  'dialog',
8997
9057
  'detailActionLabel',
@@ -9006,6 +9066,27 @@ function mapFieldDefinitionToMetadata(field) {
9006
9066
  metadata[prop] = value;
9007
9067
  }
9008
9068
  }
9069
+ const explicitPrefixIcon = normalizeIconName(field.prefixIcon);
9070
+ const explicitSuffixIcon = normalizeIconName(field.suffixIcon);
9071
+ const backendIcon = normalizeIconName(field.icon);
9072
+ const iconPosition = normalizeIconPosition(field.iconPosition);
9073
+ if (explicitPrefixIcon) {
9074
+ metadata.prefixIcon = explicitPrefixIcon;
9075
+ }
9076
+ if (explicitSuffixIcon) {
9077
+ metadata.suffixIcon = explicitSuffixIcon;
9078
+ }
9079
+ if (backendIcon && !explicitPrefixIcon && !explicitSuffixIcon) {
9080
+ if (iconPosition === 'end') {
9081
+ metadata.suffixIcon = backendIcon;
9082
+ }
9083
+ else {
9084
+ metadata.prefixIcon = backendIcon;
9085
+ }
9086
+ }
9087
+ if (iconPosition) {
9088
+ metadata.iconPosition = iconPosition;
9089
+ }
9009
9090
  const normalizedOptionSource = normalizeOptionSource(field.optionSource);
9010
9091
  if (normalizedOptionSource) {
9011
9092
  metadata.optionSource = normalizedOptionSource;
@@ -9044,9 +9125,6 @@ function mapFieldDefinitionToMetadata(field) {
9044
9125
  }
9045
9126
  }
9046
9127
  const hasOptionsFilterEndpoint = isOptionsFilterEndpoint(field.endpoint);
9047
- if (field.endpoint) {
9048
- metadata.endpoint = field.endpoint;
9049
- }
9050
9128
  const endpointPath = normalizeEndpoint$1(normalizedOptionSource?.resourcePath ?? field.resourcePath ?? field.endpoint);
9051
9129
  if (endpointPath) {
9052
9130
  // Canonicalize: only expose resourcePath; do not write legacy alias
@@ -14610,6 +14688,69 @@ function clampPrecision(value) {
14610
14688
  return Math.floor(value);
14611
14689
  }
14612
14690
 
14691
+ function isPraxisRuntimeGlobalActionEffect(value) {
14692
+ const candidate = value;
14693
+ return (!!candidate &&
14694
+ candidate.kind === 'global-action' &&
14695
+ !!candidate.globalAction &&
14696
+ typeof candidate.globalAction.actionId === 'string' &&
14697
+ candidate.globalAction.actionId.trim().length > 0);
14698
+ }
14699
+ function normalizePraxisEffectPolicy(policy) {
14700
+ return {
14701
+ trigger: policy?.trigger || 'on-condition-enter',
14702
+ ...(policy?.distinct !== undefined ? { distinct: policy.distinct } : {}),
14703
+ ...(policy?.distinctBy ? { distinctBy: policy.distinctBy } : {}),
14704
+ ...(typeof policy?.debounceMs === 'number' ? { debounceMs: policy.debounceMs } : {}),
14705
+ ...(policy?.missingValuePolicy ? { missingValuePolicy: policy.missingValuePolicy } : {}),
14706
+ ...(policy?.errorPolicy ? { errorPolicy: policy.errorPolicy } : {}),
14707
+ ...(policy?.runOnInitialEvaluation !== undefined
14708
+ ? { runOnInitialEvaluation: policy.runOnInitialEvaluation }
14709
+ : {}),
14710
+ };
14711
+ }
14712
+ function buildPraxisEffectDistinctKey(input) {
14713
+ return [
14714
+ input.componentId || 'component',
14715
+ input.ruleId || 'rule',
14716
+ input.effectId || 'effect',
14717
+ input.actionId || 'action',
14718
+ input.contextKey || 'context',
14719
+ input.distinctBy || 'condition',
14720
+ stableSerializePraxisEffectValue(input.value),
14721
+ ].join('|');
14722
+ }
14723
+ function stableSerializePraxisEffectValue(value) {
14724
+ if (value === undefined)
14725
+ return 'undefined';
14726
+ if (value === null)
14727
+ return 'null';
14728
+ if (typeof value !== 'object') {
14729
+ const serialized = JSON.stringify(value);
14730
+ return serialized === undefined ? String(value) : serialized;
14731
+ }
14732
+ try {
14733
+ return JSON.stringify(sortPraxisEffectObject(value));
14734
+ }
14735
+ catch {
14736
+ return String(value);
14737
+ }
14738
+ }
14739
+ function sortPraxisEffectObject(value) {
14740
+ if (Array.isArray(value)) {
14741
+ return value.map((item) => sortPraxisEffectObject(item));
14742
+ }
14743
+ if (!value || typeof value !== 'object') {
14744
+ return value;
14745
+ }
14746
+ return Object.keys(value)
14747
+ .sort()
14748
+ .reduce((acc, key) => {
14749
+ acc[key] = sortPraxisEffectObject(value[key]);
14750
+ return acc;
14751
+ }, {});
14752
+ }
14753
+
14613
14754
  /**
14614
14755
  * Enum que define os tipos de dados (`TYPE`) disponíveis para configuração dos campos de formulário.
14615
14756
  */
@@ -16199,6 +16340,7 @@ const RULE_PROPERTY_SCHEMA = {
16199
16340
  { value: 'end', label: 'Fim' },
16200
16341
  ],
16201
16342
  },
16343
+ { name: 'value', type: 'object', label: 'Valor calculado' },
16202
16344
  { name: 'validators', type: 'object', label: 'Validadores' },
16203
16345
  ],
16204
16346
  section: [
@@ -17388,6 +17530,12 @@ function normalizeEndpoint(endpoint) {
17388
17530
  },
17389
17531
  };
17390
17532
  }
17533
+ if (endpoint.kind === 'global-action') {
17534
+ return {
17535
+ kind: 'global-action',
17536
+ ref: normalizeGlobalActionRef(endpoint.ref),
17537
+ };
17538
+ }
17391
17539
  return {
17392
17540
  kind: 'state',
17393
17541
  ref: {
@@ -17396,6 +17544,14 @@ function normalizeEndpoint(endpoint) {
17396
17544
  },
17397
17545
  };
17398
17546
  }
17547
+ function normalizeGlobalActionRef(ref) {
17548
+ return {
17549
+ actionId: String(ref.actionId || '').trim(),
17550
+ ...(ref.payload !== undefined ? { payload: clone$1(ref.payload) } : {}),
17551
+ ...(ref.payloadExpr ? { payloadExpr: String(ref.payloadExpr).trim() } : {}),
17552
+ ...(ref.meta && typeof ref.meta === 'object' ? { meta: { ...ref.meta } } : {}),
17553
+ };
17554
+ }
17399
17555
  function normalizeNestedPath(nestedPath) {
17400
17556
  if (!nestedPath?.length) {
17401
17557
  return [];
@@ -17496,6 +17652,14 @@ function endpointSortKey(endpoint) {
17496
17652
  JSON.stringify(normalizeNestedPath(endpoint.ref.nestedPath)),
17497
17653
  ].join('|');
17498
17654
  }
17655
+ if (endpoint.kind === 'global-action') {
17656
+ return [
17657
+ endpoint.kind,
17658
+ endpoint.ref.actionId,
17659
+ endpoint.ref.payloadExpr || '',
17660
+ JSON.stringify(endpoint.ref.payload ?? null),
17661
+ ].join('|');
17662
+ }
17499
17663
  return [
17500
17664
  endpoint.kind,
17501
17665
  endpoint.ref.path,
@@ -19134,7 +19298,7 @@ class SurfaceOpenActionEditorComponent {
19134
19298
  </mat-form-field>
19135
19299
  </div>
19136
19300
  </div>
19137
- `, isInline: true, styles: [".surface-editor{display:grid;gap:16px}.surface-section{padding:12px 14px;border:1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, .18));border-radius:10px;background:var(--md-sys-color-surface-container-lowest, #fff)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.surface-section-title{font-size:12px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant, #5f6368);margin-bottom:10px}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px 16px}.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%}.surface-component-meta{display:grid;gap:4px}.surface-component-title{font-weight:600}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant, #5f6368);font-size:12px}.surface-bindings{display:grid;gap:12px}.surface-binding-row{display:grid;grid-template-columns:minmax(200px,1.2fr) minmax(220px,1.4fr) minmax(140px,.8fr) minmax(180px,1fr) auto;gap:12px;align-items:start}mat-form-field{width:100%}@media(max-width:960px){.surface-binding-row{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.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: i3$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"] }] });
19301
+ `, isInline: true, styles: [".surface-editor{display:grid;gap:16px}.surface-section{padding:12px 14px;border:1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, .18));border-radius:10px;background:var(--md-sys-color-surface-container-lowest, #fff)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.surface-section-title{font-size:12px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant, #5f6368);margin-bottom:10px}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px 16px}.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%}.surface-component-meta{display:grid;gap:4px}.surface-component-title{font-weight:600}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant, #5f6368);font-size:12px}.surface-bindings{display:grid;gap:12px}.surface-binding-row{display:grid;grid-template-columns:minmax(200px,1.2fr) minmax(220px,1.4fr) minmax(140px,.8fr) minmax(180px,1fr) auto;gap:12px;align-items:start}mat-form-field{width:100%}@media(max-width:960px){.surface-binding-row{grid-template-columns:minmax(0,1fr)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
19138
19302
  }
19139
19303
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SurfaceOpenActionEditorComponent, decorators: [{
19140
19304
  type: Component,
@@ -20529,7 +20693,7 @@ const CAPS = [
20529
20693
  { path: 'page.state.derived.<token>.cache', category: 'state', valueKind: 'boolean', description: 'Permite cache futuro do valor derivado.' },
20530
20694
  { path: 'page.composition', category: 'connections', valueKind: 'object', description: 'Envelope canonico da composicao persistida.' },
20531
20695
  { path: 'page.composition.version', category: 'connections', valueKind: 'string', description: 'Versao do envelope de composicao.' },
20532
- { path: 'page.composition.links', category: 'connections', valueKind: 'array', description: 'Links canonicos entre widgets e estado.' },
20696
+ { path: 'page.composition.links', category: 'connections', valueKind: 'array', description: 'Links canonicos entre widgets, estado e actions globais.' },
20533
20697
  { path: 'page.composition.links[].id', category: 'connections', valueKind: 'string', description: 'Identificador estavel do link.' },
20534
20698
  { path: 'page.composition.links[].from', category: 'connections', valueKind: 'object', description: 'Endpoint de origem do link.' },
20535
20699
  { path: 'page.composition.links[].from.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de origem, como component-port ou state.' },
@@ -20544,8 +20708,11 @@ const CAPS = [
20544
20708
  { path: 'page.composition.links[].from.ref.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Indice auxiliar para diagnostico visual; nao use como identidade primaria.' },
20545
20709
  { path: 'page.composition.links[].from.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de origem.' },
20546
20710
  { path: 'page.composition.links[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino do link.' },
20547
- { path: 'page.composition.links[].to.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de destino, como component-port ou state.' },
20711
+ { path: 'page.composition.links[].to.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de destino, como component-port, state ou global-action.' },
20548
20712
  { path: 'page.composition.links[].to.ref', category: 'connections', valueKind: 'object', description: 'Referencia estruturada do endpoint de destino.' },
20713
+ { path: 'page.composition.links[].to.ref.[actionId]', category: 'connections', valueKind: 'string', description: 'ID da action global quando to.kind = global-action.' },
20714
+ { path: 'page.composition.links[].to.ref.payload', category: 'connections', valueKind: 'object', description: 'Payload fixo opcional da action global; quando omitido, o runtime entrega o valor transformado do link.' },
20715
+ { path: 'page.composition.links[].to.ref.payloadExpr', category: 'connections', valueKind: 'expression', description: 'Expressao opcional de payload da action global suportada pelo GlobalActionService.' },
20549
20716
  { path: 'page.composition.links[].to.ref.widget', category: 'connections', valueKind: 'string', description: 'Widget top-level dono do endpoint de destino.' },
20550
20717
  { path: 'page.composition.links[].to.ref.port', category: 'connections', valueKind: 'string', description: 'Porta de destino do componente.' },
20551
20718
  { path: 'page.composition.links[].to.ref.direction', category: 'connections', valueKind: 'string', description: 'Direcao da porta de destino.' },
@@ -20772,7 +20939,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
20772
20939
  requiresExistingTarget: true,
20773
20940
  scope: 'ROW',
20774
20941
  params: [
20775
- { name: 'linkId', type: 'STRING' },
20942
+ { name: 'id', type: 'STRING' },
20776
20943
  ],
20777
20944
  patchTemplate: {
20778
20945
  page: {
@@ -20781,7 +20948,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
20781
20948
  links: [
20782
20949
  {
20783
20950
  _beforeKey: '{{target}}',
20784
- id: '{{params.linkId}}',
20951
+ id: '{{params.id}}',
20785
20952
  _remove: true,
20786
20953
  },
20787
20954
  ],
@@ -22329,7 +22496,7 @@ class PraxisRichTextBlockComponent {
22329
22496
 
22330
22497
  <div class="prt-content" [innerHTML]="renderedContent"></div>
22331
22498
  </section>
22332
- `, isInline: true, styles: [":host{display:block;--prt-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 72%, transparent);--prt-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container-lowest) 4%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 92%, var(--md-sys-color-surface) 8%) );--prt-emphasis-border: color-mix(in srgb, var(--md-sys-color-primary) 32%, var(--md-sys-color-outline-variant));--prt-emphasis-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary-container) 36%, var(--md-sys-color-surface) 64%), color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-primary-container) 4%) );--prt-subtle-bg: color-mix(in srgb, var(--md-sys-color-surface-container-low) 82%, transparent);--prt-icon-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 64%, transparent);--prt-code-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--prt-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--prt-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-low) 92%, var(--md-sys-color-surface) 8%), color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-surface-container-high) 10%) );--prt-emphasis-border: color-mix(in srgb, var(--md-sys-color-primary) 42%, var(--md-sys-color-outline-variant));--prt-emphasis-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary-container) 28%, var(--md-sys-color-surface-container-low) 72%), color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-primary-container) 8%) );--prt-subtle-bg: color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, transparent);--prt-icon-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 42%, transparent);--prt-code-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, transparent)}.prt-block{display:grid;gap:12px;padding:16px 18px;border-radius:16px;border:1px solid var(--prt-border);background:var(--prt-bg);color:var(--md-sys-color-on-surface)}.prt-block-emphasis{border-color:var(--prt-emphasis-border);background:var(--prt-emphasis-bg)}.prt-block-subtle{background:var(--prt-subtle-bg);border-style:dashed}.prt-block-plain{padding:0;border:0;border-radius:0;background:transparent}.prt-head{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.prt-icon{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:12px;background:var(--prt-icon-bg);color:var(--md-sys-color-primary);font-size:20px;line-height:1}.prt-title-wrap{display:grid;gap:4px}.prt-title{margin:0;font-size:1rem;font-weight:700;line-height:1.3}.prt-subtitle{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.86rem;line-height:1.4}.prt-content{color:var(--md-sys-color-on-surface);font-size:.94rem;line-height:1.6}.prt-content :where(p,ul){margin:0}.prt-content :where(p+p,p+ul,ul+p,ul+ul){margin-top:10px}.prt-content ul{padding-left:18px}.prt-content a{color:var(--md-sys-color-primary);text-decoration:underline;text-underline-offset:2px}.prt-content strong{font-weight:700}.prt-content em{font-style:italic}.prt-content code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em;padding:.1em .35em;border-radius:6px;background:var(--prt-code-bg)}.prt-block-plain .prt-icon{width:32px;height:32px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 80%,transparent)}.prt-block-plain .prt-content{font-size:.92rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
22499
+ `, isInline: true, styles: [":host{display:block;--prt-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 72%, transparent);--prt-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-surface-container-lowest) 4%), color-mix(in srgb, var(--md-sys-color-surface-container-low) 92%, var(--md-sys-color-surface) 8%) );--prt-emphasis-border: color-mix(in srgb, var(--md-sys-color-primary) 32%, var(--md-sys-color-outline-variant));--prt-emphasis-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary-container) 36%, var(--md-sys-color-surface) 64%), color-mix(in srgb, var(--md-sys-color-surface) 96%, var(--md-sys-color-primary-container) 4%) );--prt-subtle-bg: color-mix(in srgb, var(--md-sys-color-surface-container-low) 82%, transparent);--prt-icon-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 64%, transparent);--prt-code-bg: color-mix(in srgb, var(--md-sys-color-surface-container-highest) 82%, transparent)}:host-context(.mdc-theme-dark),:host-context(.theme-dark){--prt-border: color-mix(in srgb, var(--md-sys-color-outline-variant) 84%, transparent);--prt-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-surface-container-low) 92%, var(--md-sys-color-surface) 8%), color-mix(in srgb, var(--md-sys-color-surface-container) 90%, var(--md-sys-color-surface-container-high) 10%) );--prt-emphasis-border: color-mix(in srgb, var(--md-sys-color-primary) 42%, var(--md-sys-color-outline-variant));--prt-emphasis-bg: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary-container) 28%, var(--md-sys-color-surface-container-low) 72%), color-mix(in srgb, var(--md-sys-color-surface-container) 92%, var(--md-sys-color-primary-container) 8%) );--prt-subtle-bg: color-mix(in srgb, var(--md-sys-color-surface-container-low) 88%, transparent);--prt-icon-bg: color-mix(in srgb, var(--md-sys-color-primary-container) 42%, transparent);--prt-code-bg: color-mix(in srgb, var(--md-sys-color-surface-container-high) 88%, transparent)}.prt-block{display:grid;gap:12px;padding:16px 18px;border-radius:16px;border:1px solid var(--prt-border);background:var(--prt-bg);color:var(--md-sys-color-on-surface)}.prt-block-emphasis{border-color:var(--prt-emphasis-border);background:var(--prt-emphasis-bg)}.prt-block-subtle{background:var(--prt-subtle-bg);border-style:dashed}.prt-block-plain{padding:0;border:0;border-radius:0;background:transparent}.prt-head{display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start}.prt-icon{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:12px;background:var(--prt-icon-bg);color:var(--md-sys-color-primary);font-size:20px;line-height:1}.prt-title-wrap{display:grid;gap:4px}.prt-title{margin:0;font-size:1rem;font-weight:700;line-height:1.3}.prt-subtitle{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.86rem;line-height:1.4}.prt-content{color:var(--md-sys-color-on-surface);font-size:.94rem;line-height:1.6}.prt-content :where(p,ul){margin:0}.prt-content :where(p+p,p+ul,ul+p,ul+ul){margin-top:10px}.prt-content ul{padding-left:18px}.prt-content a{color:var(--md-sys-color-primary);text-decoration:underline;text-underline-offset:2px}.prt-content strong{font-weight:700}.prt-content em{font-style:italic}.prt-content code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em;padding:.1em .35em;border-radius:6px;background:var(--prt-code-bg)}.prt-block-plain .prt-icon{width:32px;height:32px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 80%,transparent)}.prt-block-plain .prt-content{font-size:.92rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
22333
22500
  }
22334
22501
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisRichTextBlockComponent, decorators: [{
22335
22502
  type: Component,
@@ -23620,7 +23787,7 @@ class WidgetShellComponent {
23620
23787
  @if (expanded || fullscreen) {
23621
23788
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
23622
23789
  }
23623
- `, 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}.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-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;top:50%;left:50%;width:95vw;height:95vh;transform:translate(-50%,-50%);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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23790
+ `, 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}.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-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;top:50%;left:50%;width:95vw;height:95vh;transform:translate(-50%,-50%);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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23624
23791
  }
23625
23792
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: WidgetShellComponent, decorators: [{
23626
23793
  type: Component,
@@ -24673,187 +24840,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
24673
24840
  args: [{ providedIn: 'root' }]
24674
24841
  }], ctorParameters: () => [{ type: PraxisJsonLogicService }] });
24675
24842
 
24676
- class CompositionRuntimeStore {
24677
- snapshot;
24678
- listeners = new Set();
24679
- constructor(init) {
24680
- this.snapshot = freezeSnapshot(createSnapshot(init));
24681
- }
24682
- getSnapshot() {
24683
- return this.snapshot;
24684
- }
24685
- subscribe(listener) {
24686
- this.listeners.add(listener);
24687
- listener(this.snapshot);
24688
- return () => {
24689
- this.listeners.delete(listener);
24690
- };
24691
- }
24692
- reset(init) {
24693
- this.snapshot = freezeSnapshot(createSnapshot(init));
24694
- this.emit();
24695
- return this.snapshot;
24696
- }
24697
- applyCycle(update) {
24698
- const nextState = update.stateSnapshot
24699
- ? cloneStateSnapshot$1(update.stateSnapshot)
24700
- : applyStatePatch(this.snapshot.state, update);
24701
- const nextLinks = applyLinkPatches(this.snapshot.links, update.linkPatches);
24702
- this.snapshot = freezeSnapshot({
24703
- pageId: this.snapshot.pageId,
24704
- status: update.status ?? this.snapshot.status,
24705
- generatedAt: update.generatedAt ?? this.snapshot.generatedAt,
24706
- links: nextLinks,
24707
- state: nextState,
24708
- diagnostics: cloneDiagnostics$1(update.diagnostics ?? this.snapshot.diagnostics),
24709
- traceTail: cloneTraceTail(update.traceTail ?? this.snapshot.traceTail),
24710
- });
24711
- this.emit();
24712
- return this.snapshot;
24713
- }
24714
- emit() {
24715
- for (const listener of this.listeners) {
24716
- listener(this.snapshot);
24717
- }
24718
- }
24719
- }
24720
- function createSnapshot(init) {
24721
- return {
24722
- pageId: init?.pageId,
24723
- status: init?.status ?? 'booting',
24724
- generatedAt: init?.generatedAt ?? new Date(0).toISOString(),
24725
- links: cloneLinks(init?.links ?? []),
24726
- state: {
24727
- primaryValues: cloneRecord$1(init?.state?.primaryValues),
24728
- derivedValues: cloneRecord$1(init?.state?.derivedValues),
24729
- transientValues: init?.state?.transientValues
24730
- ? cloneRecord$1(init.state.transientValues)
24731
- : undefined,
24732
- changedPaths: init?.state?.changedPaths ? [...init.state.changedPaths] : [],
24733
- diagnostics: cloneDiagnostics$1(init?.state?.diagnostics ?? []),
24734
- },
24735
- diagnostics: cloneDiagnostics$1(init?.diagnostics ?? []),
24736
- traceTail: cloneTraceTail(init?.traceTail ?? []),
24737
- };
24738
- }
24739
- function applyStatePatch(current, update) {
24740
- return {
24741
- primaryValues: {
24742
- ...current.primaryValues,
24743
- ...cloneRecord$1(update.primaryValuesPatch),
24744
- },
24745
- derivedValues: {
24746
- ...current.derivedValues,
24747
- ...cloneRecord$1(update.derivedValuesPatch),
24748
- },
24749
- transientValues: mergeTransientValues(current.transientValues, update.transientValuesPatch),
24750
- changedPaths: update.changedPaths ? [...update.changedPaths] : [...(current.changedPaths ?? [])],
24751
- diagnostics: cloneDiagnostics$1(current.diagnostics),
24752
- };
24753
- }
24754
- function cloneStateSnapshot$1(state) {
24755
- return {
24756
- primaryValues: cloneRecord$1(state.primaryValues),
24757
- derivedValues: cloneRecord$1(state.derivedValues),
24758
- transientValues: state.transientValues ? cloneRecord$1(state.transientValues) : undefined,
24759
- changedPaths: state.changedPaths ? [...state.changedPaths] : [],
24760
- diagnostics: cloneDiagnostics$1(state.diagnostics),
24761
- };
24762
- }
24763
- function mergeTransientValues(current, patch) {
24764
- if (!current && !patch) {
24765
- return undefined;
24766
- }
24767
- return {
24768
- ...cloneRecord$1(current),
24769
- ...cloneRecord$1(patch),
24770
- };
24771
- }
24772
- function applyLinkPatches(current, patches) {
24773
- const patchMap = new Map((patches ?? []).map((patch) => [patch.linkId, patch]));
24774
- return current.map((link) => {
24775
- const patch = patchMap.get(link.linkId);
24776
- if (!patch) {
24777
- return cloneLink(link);
24778
- }
24779
- const next = cloneLink(link);
24780
- next.status = patch.status ?? link.status;
24781
- setOptionalLinkValue(next, 'lastEventAt', pickPatchedValue(patch, 'lastEventAt', link.lastEventAt));
24782
- setOptionalLinkValue(next, 'lastDispatchTraceId', pickPatchedValue(patch, 'lastDispatchTraceId', link.lastDispatchTraceId));
24783
- setOptionalLinkValue(next, 'lastDeliveredValuePreview', pickPatchedValue(patch, 'lastDeliveredValuePreview', link.lastDeliveredValuePreview));
24784
- next.diagnostics = cloneDiagnostics$1(patch.diagnostics ?? link.diagnostics);
24785
- return next;
24786
- });
24787
- }
24788
- function pickPatchedValue(patch, key, fallback) {
24789
- return Object.prototype.hasOwnProperty.call(patch, key)
24790
- ? patch[key]
24791
- : fallback;
24792
- }
24793
- function cloneLinks(links) {
24794
- return links.map((link) => cloneLink(link));
24795
- }
24796
- function cloneLink(link) {
24797
- const next = {
24798
- linkId: link.linkId,
24799
- status: link.status,
24800
- source: { ...link.source },
24801
- target: { ...link.target },
24802
- diagnostics: cloneDiagnostics$1(link.diagnostics),
24803
- };
24804
- setOptionalLinkValue(next, 'lastEventAt', link.lastEventAt);
24805
- setOptionalLinkValue(next, 'lastDispatchTraceId', link.lastDispatchTraceId);
24806
- setOptionalLinkValue(next, 'lastDeliveredValuePreview', link.lastDeliveredValuePreview);
24807
- return next;
24808
- }
24809
- function setOptionalLinkValue(link, key, value) {
24810
- if (value === undefined) {
24811
- delete link[key];
24812
- return;
24813
- }
24814
- link[key] = value;
24815
- }
24816
- function cloneDiagnostics$1(diagnostics) {
24817
- return diagnostics.map((diagnostic) => ({
24818
- ...diagnostic,
24819
- subject: { ...diagnostic.subject },
24820
- related: diagnostic.related?.map((item) => ({ ...item })),
24821
- details: diagnostic.details ? { ...diagnostic.details } : undefined,
24822
- }));
24823
- }
24824
- function cloneTraceTail(traceTail) {
24825
- return traceTail.map((entry) => ({
24826
- ...entry,
24827
- subject: { ...entry.subject },
24828
- payloadSummary: entry.payloadSummary
24829
- ? {
24830
- ...entry.payloadSummary,
24831
- keys: entry.payloadSummary.keys ? [...entry.payloadSummary.keys] : undefined,
24832
- }
24833
- : undefined,
24834
- details: entry.details ? { ...entry.details } : undefined,
24835
- diagnostics: entry.diagnostics ? [...entry.diagnostics] : undefined,
24836
- }));
24837
- }
24838
- function cloneRecord$1(value) {
24839
- return value ? { ...value } : {};
24840
- }
24841
- function freezeSnapshot(snapshot) {
24842
- return deepFreeze(snapshot);
24843
- }
24844
- function deepFreeze(value) {
24845
- if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
24846
- return value;
24847
- }
24848
- Object.freeze(value);
24849
- for (const nested of Object.values(value)) {
24850
- if (nested && typeof nested === 'object') {
24851
- deepFreeze(nested);
24852
- }
24853
- }
24854
- return value;
24855
- }
24856
-
24857
24843
  const TRANSFORM_CATALOG = [
24858
24844
  {
24859
24845
  kind: 'identity',
@@ -24954,12 +24940,611 @@ function isSupportedTransformKind(kind) {
24954
24940
  return TRANSFORM_CATALOG_MAP.has(kind);
24955
24941
  }
24956
24942
 
24957
- const DEFAULT_PATH_ACCESSOR$1 = new ConnectionManagerService();
24958
- const DEFAULT_TEMPLATE_RESOLVER = new SurfaceBindingRuntimeService();
24959
- const DEFAULT_JSON_LOGIC$1 = new PraxisJsonLogicService(null);
24960
- const TRANSFORM_RULE_OPTIONS = {
24961
- availableRoots: ['event', 'payload', 'state', 'context', 'source'],
24962
- defaultRoot: 'source',
24943
+ class NestedPortCatalogService {
24944
+ accessor;
24945
+ constructor(accessor = new NestedWidgetConfigAccessor()) {
24946
+ this.accessor = accessor;
24947
+ }
24948
+ resolve(page, registry) {
24949
+ const ports = [];
24950
+ const diagnostics = [];
24951
+ for (const owner of page.widgets || []) {
24952
+ const nestedWidgets = this.accessor.listNestedWidgets(owner);
24953
+ for (const nested of nestedWidgets) {
24954
+ if (!this.hasStableTerminalKey(nested.nestedPath)) {
24955
+ diagnostics.push({
24956
+ code: 'NESTED_WIDGET_KEY_MISSING',
24957
+ severity: 'error',
24958
+ ownerWidgetKey: owner.key,
24959
+ nestedPath: this.clone(nested.nestedPath),
24960
+ componentId: nested.componentId,
24961
+ message: `Nested widget inside '${owner.key}' must declare a stable childWidgetKey.`,
24962
+ });
24963
+ continue;
24964
+ }
24965
+ const meta = registry.get(nested.componentId);
24966
+ if (!meta?.ports?.length) {
24967
+ diagnostics.push({
24968
+ code: 'NESTED_WIDGET_METADATA_MISSING',
24969
+ severity: 'warning',
24970
+ ownerWidgetKey: owner.key,
24971
+ nestedPath: this.clone(nested.nestedPath),
24972
+ componentId: nested.componentId,
24973
+ message: `No component metadata ports found for nested widget '${nested.componentId}'.`,
24974
+ });
24975
+ continue;
24976
+ }
24977
+ for (const port of meta.ports) {
24978
+ ports.push({
24979
+ ownerWidgetKey: owner.key,
24980
+ ownerComponentId: owner.definition.id,
24981
+ nestedPath: this.clone(nested.nestedPath),
24982
+ containerPath: this.containerPath(nested.nestedPath),
24983
+ port: this.clone(port),
24984
+ componentId: nested.componentId,
24985
+ childWidgetKey: nested.childWidgetKey,
24986
+ });
24987
+ }
24988
+ }
24989
+ }
24990
+ return { ports, diagnostics };
24991
+ }
24992
+ resolveEndpoint(page, registry, options) {
24993
+ return this.resolve(page, registry).ports.find((port) => port.ownerWidgetKey === options.ownerWidgetKey
24994
+ && port.port.id === options.portId
24995
+ && port.port.direction === options.direction
24996
+ && this.isSamePath(port.nestedPath, options.nestedPath));
24997
+ }
24998
+ hasStableTerminalKey(nestedPath) {
24999
+ const terminal = nestedPath[nestedPath.length - 1];
25000
+ return terminal?.kind === 'widget'
25001
+ && typeof terminal.key === 'string'
25002
+ && terminal.key.trim().length > 0;
25003
+ }
25004
+ containerPath(nestedPath) {
25005
+ return nestedPath.slice(0, -1).map((segment) => this.clone(segment));
25006
+ }
25007
+ isSamePath(left, right) {
25008
+ return JSON.stringify(left) === JSON.stringify(right);
25009
+ }
25010
+ clone(value) {
25011
+ if (value == null || typeof value !== 'object') {
25012
+ return value;
25013
+ }
25014
+ return JSON.parse(JSON.stringify(value));
25015
+ }
25016
+ }
25017
+
25018
+ const COMPOSITION_RULE_ROOTS$1 = ['source', 'event', 'payload', 'state', 'context', 'meta'];
25019
+ const COMPATIBLE_TARGET_KINDS = {
25020
+ event: ['event'],
25021
+ value: ['value', 'selection', 'query-context', 'view-context', 'config-fragment'],
25022
+ selection: ['selection', 'value'],
25023
+ collection: ['collection'],
25024
+ 'query-context': ['query-context', 'value'],
25025
+ 'view-context': ['view-context', 'value'],
25026
+ 'config-fragment': ['config-fragment', 'value'],
25027
+ status: ['status', 'value'],
25028
+ diagnostic: ['diagnostic'],
25029
+ };
25030
+ class CompositionValidatorService {
25031
+ nestedPortCatalog;
25032
+ jsonLogic;
25033
+ constructor(nestedPortCatalog = new NestedPortCatalogService(), jsonLogic = new PraxisJsonLogicService(null)) {
25034
+ this.nestedPortCatalog = nestedPortCatalog;
25035
+ this.jsonLogic = jsonLogic;
25036
+ }
25037
+ validateLink(link, context = {}) {
25038
+ const diagnostics = [];
25039
+ this.validateEndpointDirections(link, diagnostics);
25040
+ this.validateNestedComponentEndpoints(link, diagnostics);
25041
+ this.validateNestedPortCatalog(link, diagnostics, context);
25042
+ this.validateNestedWidgetEventCoexistence(link, diagnostics, context);
25043
+ this.validateBindingPathBridge(link, diagnostics);
25044
+ this.validateStateWrites(link, diagnostics);
25045
+ this.validateGlobalActionTarget(link, diagnostics);
25046
+ this.validateCondition(link, diagnostics);
25047
+ this.validateTransformCatalog(link, diagnostics);
25048
+ this.validateSemanticCompatibility(link, diagnostics);
25049
+ return diagnostics;
25050
+ }
25051
+ validateEndpointDirections(link, diagnostics) {
25052
+ if (link.from.kind === 'component-port' && link.from.ref.direction !== 'output') {
25053
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_DIRECTION_INVALID_SOURCE', 'error', `A origem do link ${link.id} precisa apontar para uma porta de saida.`, {
25054
+ kind: 'port',
25055
+ widgetKey: link.from.ref.widget,
25056
+ widgetType: link.from.ref.componentType,
25057
+ portId: link.from.ref.port,
25058
+ linkId: link.id,
25059
+ }, { expectedDirection: 'output', actualDirection: link.from.ref.direction }));
25060
+ }
25061
+ if (link.to.kind === 'component-port' && link.to.ref.direction !== 'input') {
25062
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_PORT_DIRECTION_INVALID_TARGET', 'error', `O destino do link ${link.id} precisa apontar para uma porta de entrada.`, {
25063
+ kind: 'port',
25064
+ widgetKey: link.to.ref.widget,
25065
+ widgetType: link.to.ref.componentType,
25066
+ portId: link.to.ref.port,
25067
+ linkId: link.id,
25068
+ }, { expectedDirection: 'input', actualDirection: link.to.ref.direction }));
25069
+ }
25070
+ }
25071
+ validateBindingPathBridge(link, diagnostics) {
25072
+ const componentEndpoints = [link.from, link.to].filter((endpoint) => endpoint.kind === 'component-port');
25073
+ for (const endpoint of componentEndpoints) {
25074
+ if (!endpoint.ref.bindingPath || endpoint.ref.nestedPath?.length) {
25075
+ continue;
25076
+ }
25077
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_BINDING_PATH_BRIDGE', 'warning', `O link ${link.id} ainda depende de bindingPath como bridge temporaria.`, {
25078
+ kind: 'port',
25079
+ widgetKey: endpoint.ref.widget,
25080
+ widgetType: endpoint.ref.componentType,
25081
+ portId: endpoint.ref.port,
25082
+ linkId: link.id,
25083
+ path: endpoint.ref.bindingPath,
25084
+ }, { bindingPath: endpoint.ref.bindingPath }, false));
25085
+ }
25086
+ }
25087
+ validateNestedComponentEndpoints(link, diagnostics) {
25088
+ const componentEndpoints = [link.from, link.to].filter((endpoint) => endpoint.kind === 'component-port');
25089
+ for (const endpoint of componentEndpoints) {
25090
+ const nestedPath = endpoint.ref.nestedPath || [];
25091
+ if (!nestedPath.length) {
25092
+ continue;
25093
+ }
25094
+ const terminal = nestedPath[nestedPath.length - 1];
25095
+ if (terminal?.kind !== 'widget'
25096
+ || typeof terminal.key !== 'string'
25097
+ || terminal.key.trim().length === 0) {
25098
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_PORT_TERMINAL_WIDGET_KEY_REQUIRED', 'error', `O endpoint nested do link ${link.id} precisa terminar em widget.key estavel.`, {
25099
+ kind: 'port',
25100
+ widgetKey: endpoint.ref.widget,
25101
+ widgetType: endpoint.ref.componentType,
25102
+ portId: endpoint.ref.port,
25103
+ linkId: link.id,
25104
+ path: this.formatNestedPath(nestedPath),
25105
+ }, { nestedPath }));
25106
+ }
25107
+ if (!endpoint.ref.bindingPath) {
25108
+ continue;
25109
+ }
25110
+ const isLegacyLink = link.metadata?.source === 'legacy-widget-connection';
25111
+ diagnostics.push(this.createDiagnostic(link, isLegacyLink
25112
+ ? 'SEMANTIC_NESTED_BINDING_PATH_LEGACY_BRIDGE'
25113
+ : 'SEMANTIC_NESTED_BINDING_PATH_CONFLICT', isLegacyLink ? 'warning' : 'error', isLegacyLink
25114
+ ? `O link legado ${link.id} mantem bindingPath junto de nestedPath durante migracao.`
25115
+ : `O link ${link.id} nao pode combinar bindingPath com nestedPath.`, {
25116
+ kind: 'port',
25117
+ widgetKey: endpoint.ref.widget,
25118
+ widgetType: endpoint.ref.componentType,
25119
+ portId: endpoint.ref.port,
25120
+ linkId: link.id,
25121
+ path: this.formatNestedPath(nestedPath),
25122
+ }, {
25123
+ bindingPath: endpoint.ref.bindingPath,
25124
+ nestedPath,
25125
+ }, !isLegacyLink));
25126
+ }
25127
+ }
25128
+ validateNestedPortCatalog(link, diagnostics, context) {
25129
+ if (!context.page || !context.registry) {
25130
+ return;
25131
+ }
25132
+ const catalog = this.nestedPortCatalog.resolve(context.page, context.registry);
25133
+ const componentEndpoints = [link.from, link.to].filter((endpoint) => endpoint.kind === 'component-port' && !!endpoint.ref.nestedPath?.length);
25134
+ for (const endpoint of componentEndpoints) {
25135
+ const nestedPath = endpoint.ref.nestedPath || [];
25136
+ const terminal = nestedPath[nestedPath.length - 1];
25137
+ if (terminal?.kind !== 'widget' || !terminal.key?.trim()) {
25138
+ continue;
25139
+ }
25140
+ const ownerExists = (context.page.widgets || []).some((widget) => widget.key === endpoint.ref.widget);
25141
+ if (!ownerExists) {
25142
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_OWNER_WIDGET_MISSING', 'error', `O owner top-level ${endpoint.ref.widget} do endpoint nested do link ${link.id} nao existe.`, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25143
+ ownerWidgetKey: endpoint.ref.widget,
25144
+ nestedPath,
25145
+ }));
25146
+ continue;
25147
+ }
25148
+ this.projectCatalogDiagnostics(link, endpoint, nestedPath, catalog, diagnostics);
25149
+ const matchingPathPorts = catalog.ports.filter((port) => port.ownerWidgetKey === endpoint.ref.widget
25150
+ && this.isSameNestedPath(port.nestedPath, nestedPath));
25151
+ if (!matchingPathPorts.length) {
25152
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_WIDGET_MISSING', 'error', `O nestedPath do link ${link.id} nao resolve um widget interno conectavel.`, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25153
+ ownerWidgetKey: endpoint.ref.widget,
25154
+ nestedPath,
25155
+ }));
25156
+ continue;
25157
+ }
25158
+ const samePort = matchingPathPorts.filter((port) => port.port.id === endpoint.ref.port);
25159
+ if (!samePort.length) {
25160
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_PORT_MISSING', 'error', `A porta nested ${endpoint.ref.port} do link ${link.id} nao existe no componente filho.`, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25161
+ ownerWidgetKey: endpoint.ref.widget,
25162
+ nestedPath,
25163
+ portId: endpoint.ref.port,
25164
+ availablePorts: matchingPathPorts.map((port) => port.port.id),
25165
+ }));
25166
+ continue;
25167
+ }
25168
+ const resolved = samePort.find((port) => port.port.direction === endpoint.ref.direction);
25169
+ if (!resolved) {
25170
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_PORT_DIRECTION_MISMATCH', 'error', `A porta nested ${endpoint.ref.port} do link ${link.id} existe, mas com direcao diferente.`, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25171
+ ownerWidgetKey: endpoint.ref.widget,
25172
+ nestedPath,
25173
+ portId: endpoint.ref.port,
25174
+ expectedDirection: endpoint.ref.direction,
25175
+ availableDirections: samePort.map((port) => port.port.direction),
25176
+ }));
25177
+ continue;
25178
+ }
25179
+ if (endpoint.ref.componentType && endpoint.ref.componentType !== resolved.componentId) {
25180
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_COMPONENT_TYPE_MISMATCH', 'error', `O componentType do endpoint nested do link ${link.id} nao corresponde ao componente filho resolvido.`, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25181
+ ownerWidgetKey: endpoint.ref.widget,
25182
+ nestedPath,
25183
+ expectedComponentType: endpoint.ref.componentType,
25184
+ actualComponentType: resolved.componentId,
25185
+ }));
25186
+ }
25187
+ }
25188
+ }
25189
+ projectCatalogDiagnostics(link, endpoint, nestedPath, catalog, diagnostics) {
25190
+ for (const diagnostic of catalog.diagnostics) {
25191
+ if (diagnostic.ownerWidgetKey !== endpoint.ref.widget
25192
+ || !this.isSameNestedPath(diagnostic.nestedPath, nestedPath)) {
25193
+ continue;
25194
+ }
25195
+ diagnostics.push(this.createDiagnostic(link, diagnostic.code === 'NESTED_WIDGET_KEY_MISSING'
25196
+ ? 'SEMANTIC_NESTED_WIDGET_KEY_MISSING'
25197
+ : 'SEMANTIC_NESTED_WIDGET_METADATA_MISSING', diagnostic.severity, diagnostic.message, this.nestedEndpointSubject(link, endpoint, nestedPath), {
25198
+ ownerWidgetKey: endpoint.ref.widget,
25199
+ nestedPath,
25200
+ componentId: diagnostic.componentId,
25201
+ }, diagnostic.severity === 'error'));
25202
+ }
25203
+ }
25204
+ validateNestedWidgetEventCoexistence(link, diagnostics, context) {
25205
+ if (link.from.kind !== 'component-port'
25206
+ || link.from.ref.direction !== 'output'
25207
+ || !link.from.ref.nestedPath?.length
25208
+ || link.from.ref.port === 'widgetEvent'
25209
+ || !context.links?.length) {
25210
+ return;
25211
+ }
25212
+ const sourceRef = link.from.ref;
25213
+ const legacyLinks = context.links.filter((candidate) => candidate.id !== link.id
25214
+ && candidate.from.kind === 'component-port'
25215
+ && candidate.from.ref.widget === sourceRef.widget
25216
+ && candidate.from.ref.port === 'widgetEvent'
25217
+ && candidate.from.ref.direction === 'output'
25218
+ && !candidate.from.ref.nestedPath?.length);
25219
+ if (!legacyLinks.length) {
25220
+ return;
25221
+ }
25222
+ const nestedPath = sourceRef.nestedPath || [];
25223
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_NESTED_WIDGET_EVENT_BRIDGE_COEXISTS', 'warning', `O link nested ${link.id} coexiste com link legado owner.widgetEvent no mesmo owner; o runtime deduplica, mas a composicao deve migrar para nestedPath canonico.`, this.nestedEndpointSubject(link, link.from, nestedPath), {
25224
+ ownerWidgetKey: sourceRef.widget,
25225
+ portId: sourceRef.port,
25226
+ nestedPath,
25227
+ legacyLinkIds: legacyLinks.map((candidate) => candidate.id),
25228
+ }, false));
25229
+ }
25230
+ validateStateWrites(link, diagnostics) {
25231
+ if (link.to.kind !== 'state') {
25232
+ return;
25233
+ }
25234
+ const layer = link.to.ref.layer || 'values';
25235
+ const writable = link.to.ref.writable ?? layer !== 'derived';
25236
+ if (layer === 'derived' || !writable) {
25237
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_STATE_WRITE_INVALID', 'error', `O link ${link.id} nao pode escrever no state ${link.to.ref.path}.`, {
25238
+ kind: layer === 'derived' ? 'derived-state' : 'state',
25239
+ statePath: link.to.ref.path,
25240
+ linkId: link.id,
25241
+ }, { layer, writable }));
25242
+ }
25243
+ }
25244
+ validateGlobalActionTarget(link, diagnostics) {
25245
+ if (link.to.kind !== 'global-action') {
25246
+ return;
25247
+ }
25248
+ const issues = validateGlobalActionRef(link.to.ref, null, 'to.ref');
25249
+ for (const issue of issues) {
25250
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_GLOBAL_ACTION_TARGET_INVALID', 'error', `O destino global-action do link ${link.id} esta invalido.`, {
25251
+ kind: 'global-action',
25252
+ actionId: issue.actionId || link.to.ref.actionId,
25253
+ linkId: link.id,
25254
+ path: issue.path,
25255
+ }, { issue }));
25256
+ }
25257
+ }
25258
+ validateCondition(link, diagnostics) {
25259
+ if (!link.condition) {
25260
+ return;
25261
+ }
25262
+ const result = this.jsonLogic.validateResult(link.condition, {
25263
+ availableRoots: [...COMPOSITION_RULE_ROOTS$1],
25264
+ defaultRoot: null,
25265
+ allowImplicitRoot: false,
25266
+ requireExpressionObject: true,
25267
+ });
25268
+ for (const issue of result.issues) {
25269
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_LINK_CONDITION_INVALID', 'error', `A condicao Json Logic do link ${link.id} esta invalida.`, {
25270
+ kind: 'link',
25271
+ linkId: link.id,
25272
+ path: `condition${issue.path === '$' ? '' : issue.path.slice(1)}`,
25273
+ }, { issue }));
25274
+ }
25275
+ }
25276
+ validateTransformCatalog(link, diagnostics) {
25277
+ for (const [index, step] of (link.transform?.steps || []).entries()) {
25278
+ if (getTransformCatalogEntry(step.kind)) {
25279
+ continue;
25280
+ }
25281
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_TRANSFORM_UNSUPPORTED', 'error', `O transform ${step.kind} nao pertence ao catalogo inicial suportado da Fase 2A.`, {
25282
+ kind: 'transform-step',
25283
+ linkId: link.id,
25284
+ transformIndex: index,
25285
+ label: step.id,
25286
+ }, { transformKind: step.kind }));
25287
+ }
25288
+ }
25289
+ validateSemanticCompatibility(link, diagnostics) {
25290
+ const sourceKind = this.endpointSemanticKind(link.from);
25291
+ const targetKind = this.endpointSemanticKind(link.to);
25292
+ if (!sourceKind || !targetKind) {
25293
+ return;
25294
+ }
25295
+ if (this.areSemanticKindsCompatible(sourceKind, targetKind, link.transform)) {
25296
+ return;
25297
+ }
25298
+ if (!link.transform?.steps?.length) {
25299
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_TRANSFORM_REQUIRED', 'error', `O link ${link.id} exige transform explicita para converter ${sourceKind} em ${targetKind}.`, {
25300
+ kind: 'link',
25301
+ linkId: link.id,
25302
+ }, { sourceKind, targetKind }));
25303
+ return;
25304
+ }
25305
+ diagnostics.push(this.createDiagnostic(link, 'SEMANTIC_KIND_INCOMPATIBLE', 'error', `O link ${link.id} continua semanticamente incompativel mesmo com transform declarada.`, {
25306
+ kind: 'link',
25307
+ linkId: link.id,
25308
+ }, {
25309
+ sourceKind,
25310
+ targetKind,
25311
+ transformOutputKind: link.transform.output?.semanticKind,
25312
+ transformKinds: link.transform.steps.map((step) => step.kind),
25313
+ }));
25314
+ }
25315
+ endpointSemanticKind(endpoint) {
25316
+ return endpoint.ref.semanticKind;
25317
+ }
25318
+ areSemanticKindsCompatible(sourceKind, targetKind, transform) {
25319
+ const transformOutputKind = transform?.output?.semanticKind;
25320
+ if (transformOutputKind) {
25321
+ return this.areKindsDirectlyCompatible(transformOutputKind, targetKind);
25322
+ }
25323
+ return this.areKindsDirectlyCompatible(sourceKind, targetKind);
25324
+ }
25325
+ areKindsDirectlyCompatible(sourceKind, targetKind) {
25326
+ return (COMPATIBLE_TARGET_KINDS[sourceKind] || []).includes(targetKind);
25327
+ }
25328
+ createDiagnostic(link, code, severity, message, subject, details, blocking = true) {
25329
+ return {
25330
+ id: `${link.id}:${code}`,
25331
+ code,
25332
+ severity,
25333
+ phase: 'semantic-validation',
25334
+ message,
25335
+ summary: message,
25336
+ subject,
25337
+ details,
25338
+ source: 'semantic-validator',
25339
+ blocking,
25340
+ createdAt: new Date().toISOString(),
25341
+ };
25342
+ }
25343
+ formatNestedPath(nestedPath) {
25344
+ return JSON.stringify(nestedPath);
25345
+ }
25346
+ nestedEndpointSubject(link, endpoint, nestedPath) {
25347
+ return {
25348
+ kind: 'port',
25349
+ widgetKey: endpoint.ref.widget,
25350
+ widgetType: endpoint.ref.componentType,
25351
+ portId: endpoint.ref.port,
25352
+ linkId: link.id,
25353
+ path: this.formatNestedPath(nestedPath),
25354
+ };
25355
+ }
25356
+ isSameNestedPath(left, right) {
25357
+ return JSON.stringify(left) === JSON.stringify(right);
25358
+ }
25359
+ }
25360
+
25361
+ class CompositionRuntimeStore {
25362
+ snapshot;
25363
+ listeners = new Set();
25364
+ constructor(init) {
25365
+ this.snapshot = freezeSnapshot(createSnapshot(init));
25366
+ }
25367
+ getSnapshot() {
25368
+ return this.snapshot;
25369
+ }
25370
+ subscribe(listener) {
25371
+ this.listeners.add(listener);
25372
+ listener(this.snapshot);
25373
+ return () => {
25374
+ this.listeners.delete(listener);
25375
+ };
25376
+ }
25377
+ reset(init) {
25378
+ this.snapshot = freezeSnapshot(createSnapshot(init));
25379
+ this.emit();
25380
+ return this.snapshot;
25381
+ }
25382
+ applyCycle(update) {
25383
+ const nextState = update.stateSnapshot
25384
+ ? cloneStateSnapshot$1(update.stateSnapshot)
25385
+ : applyStatePatch(this.snapshot.state, update);
25386
+ const nextLinks = applyLinkPatches(this.snapshot.links, update.linkPatches);
25387
+ this.snapshot = freezeSnapshot({
25388
+ pageId: this.snapshot.pageId,
25389
+ status: update.status ?? this.snapshot.status,
25390
+ generatedAt: update.generatedAt ?? this.snapshot.generatedAt,
25391
+ links: nextLinks,
25392
+ state: nextState,
25393
+ diagnostics: cloneDiagnostics$1(update.diagnostics ?? this.snapshot.diagnostics),
25394
+ traceTail: cloneTraceTail(update.traceTail ?? this.snapshot.traceTail),
25395
+ });
25396
+ this.emit();
25397
+ return this.snapshot;
25398
+ }
25399
+ emit() {
25400
+ for (const listener of this.listeners) {
25401
+ listener(this.snapshot);
25402
+ }
25403
+ }
25404
+ }
25405
+ function createSnapshot(init) {
25406
+ return {
25407
+ pageId: init?.pageId,
25408
+ status: init?.status ?? 'booting',
25409
+ generatedAt: init?.generatedAt ?? new Date(0).toISOString(),
25410
+ links: cloneLinks(init?.links ?? []),
25411
+ state: {
25412
+ primaryValues: cloneRecord$1(init?.state?.primaryValues),
25413
+ derivedValues: cloneRecord$1(init?.state?.derivedValues),
25414
+ transientValues: init?.state?.transientValues
25415
+ ? cloneRecord$1(init.state.transientValues)
25416
+ : undefined,
25417
+ changedPaths: init?.state?.changedPaths ? [...init.state.changedPaths] : [],
25418
+ diagnostics: cloneDiagnostics$1(init?.state?.diagnostics ?? []),
25419
+ },
25420
+ diagnostics: cloneDiagnostics$1(init?.diagnostics ?? []),
25421
+ traceTail: cloneTraceTail(init?.traceTail ?? []),
25422
+ };
25423
+ }
25424
+ function applyStatePatch(current, update) {
25425
+ return {
25426
+ primaryValues: {
25427
+ ...current.primaryValues,
25428
+ ...cloneRecord$1(update.primaryValuesPatch),
25429
+ },
25430
+ derivedValues: {
25431
+ ...current.derivedValues,
25432
+ ...cloneRecord$1(update.derivedValuesPatch),
25433
+ },
25434
+ transientValues: mergeTransientValues(current.transientValues, update.transientValuesPatch),
25435
+ changedPaths: update.changedPaths ? [...update.changedPaths] : [...(current.changedPaths ?? [])],
25436
+ diagnostics: cloneDiagnostics$1(current.diagnostics),
25437
+ };
25438
+ }
25439
+ function cloneStateSnapshot$1(state) {
25440
+ return {
25441
+ primaryValues: cloneRecord$1(state.primaryValues),
25442
+ derivedValues: cloneRecord$1(state.derivedValues),
25443
+ transientValues: state.transientValues ? cloneRecord$1(state.transientValues) : undefined,
25444
+ changedPaths: state.changedPaths ? [...state.changedPaths] : [],
25445
+ diagnostics: cloneDiagnostics$1(state.diagnostics),
25446
+ };
25447
+ }
25448
+ function mergeTransientValues(current, patch) {
25449
+ if (!current && !patch) {
25450
+ return undefined;
25451
+ }
25452
+ return {
25453
+ ...cloneRecord$1(current),
25454
+ ...cloneRecord$1(patch),
25455
+ };
25456
+ }
25457
+ function applyLinkPatches(current, patches) {
25458
+ const patchMap = new Map((patches ?? []).map((patch) => [patch.linkId, patch]));
25459
+ return current.map((link) => {
25460
+ const patch = patchMap.get(link.linkId);
25461
+ if (!patch) {
25462
+ return cloneLink(link);
25463
+ }
25464
+ const next = cloneLink(link);
25465
+ next.status = patch.status ?? link.status;
25466
+ setOptionalLinkValue(next, 'lastEventAt', pickPatchedValue(patch, 'lastEventAt', link.lastEventAt));
25467
+ setOptionalLinkValue(next, 'lastDispatchTraceId', pickPatchedValue(patch, 'lastDispatchTraceId', link.lastDispatchTraceId));
25468
+ setOptionalLinkValue(next, 'lastDeliveredValuePreview', pickPatchedValue(patch, 'lastDeliveredValuePreview', link.lastDeliveredValuePreview));
25469
+ next.diagnostics = cloneDiagnostics$1(patch.diagnostics ?? link.diagnostics);
25470
+ return next;
25471
+ });
25472
+ }
25473
+ function pickPatchedValue(patch, key, fallback) {
25474
+ return Object.prototype.hasOwnProperty.call(patch, key)
25475
+ ? patch[key]
25476
+ : fallback;
25477
+ }
25478
+ function cloneLinks(links) {
25479
+ return links.map((link) => cloneLink(link));
25480
+ }
25481
+ function cloneLink(link) {
25482
+ const next = {
25483
+ linkId: link.linkId,
25484
+ status: link.status,
25485
+ source: { ...link.source },
25486
+ target: { ...link.target },
25487
+ diagnostics: cloneDiagnostics$1(link.diagnostics),
25488
+ };
25489
+ setOptionalLinkValue(next, 'lastEventAt', link.lastEventAt);
25490
+ setOptionalLinkValue(next, 'lastDispatchTraceId', link.lastDispatchTraceId);
25491
+ setOptionalLinkValue(next, 'lastDeliveredValuePreview', link.lastDeliveredValuePreview);
25492
+ return next;
25493
+ }
25494
+ function setOptionalLinkValue(link, key, value) {
25495
+ if (value === undefined) {
25496
+ delete link[key];
25497
+ return;
25498
+ }
25499
+ link[key] = value;
25500
+ }
25501
+ function cloneDiagnostics$1(diagnostics) {
25502
+ return diagnostics.map((diagnostic) => ({
25503
+ ...diagnostic,
25504
+ subject: { ...diagnostic.subject },
25505
+ related: diagnostic.related?.map((item) => ({ ...item })),
25506
+ details: diagnostic.details ? { ...diagnostic.details } : undefined,
25507
+ }));
25508
+ }
25509
+ function cloneTraceTail(traceTail) {
25510
+ return traceTail.map((entry) => ({
25511
+ ...entry,
25512
+ subject: { ...entry.subject },
25513
+ payloadSummary: entry.payloadSummary
25514
+ ? {
25515
+ ...entry.payloadSummary,
25516
+ keys: entry.payloadSummary.keys ? [...entry.payloadSummary.keys] : undefined,
25517
+ }
25518
+ : undefined,
25519
+ details: entry.details ? { ...entry.details } : undefined,
25520
+ diagnostics: entry.diagnostics ? [...entry.diagnostics] : undefined,
25521
+ }));
25522
+ }
25523
+ function cloneRecord$1(value) {
25524
+ return value ? { ...value } : {};
25525
+ }
25526
+ function freezeSnapshot(snapshot) {
25527
+ return deepFreeze(snapshot);
25528
+ }
25529
+ function deepFreeze(value) {
25530
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
25531
+ return value;
25532
+ }
25533
+ Object.freeze(value);
25534
+ for (const nested of Object.values(value)) {
25535
+ if (nested && typeof nested === 'object') {
25536
+ deepFreeze(nested);
25537
+ }
25538
+ }
25539
+ return value;
25540
+ }
25541
+
25542
+ const DEFAULT_PATH_ACCESSOR$1 = new ConnectionManagerService();
25543
+ const DEFAULT_TEMPLATE_RESOLVER = new SurfaceBindingRuntimeService();
25544
+ const DEFAULT_JSON_LOGIC$1 = new PraxisJsonLogicService(null);
25545
+ const TRANSFORM_RULE_OPTIONS = {
25546
+ availableRoots: ['event', 'payload', 'state', 'context', 'source'],
25547
+ defaultRoot: 'source',
24963
25548
  allowImplicitRoot: true,
24964
25549
  };
24965
25550
  class TransformRuntimeService {
@@ -25519,6 +26104,9 @@ class LinkExecutorService {
25519
26104
  if (endpoint.kind === 'state') {
25520
26105
  return this.readStatePath(snapshot, endpoint.ref.path, endpoint.ref.layer);
25521
26106
  }
26107
+ if (endpoint.kind === 'global-action') {
26108
+ return this.clone(context.payload ?? context.event);
26109
+ }
25522
26110
  const payload = context.payload !== undefined
25523
26111
  ? context.payload
25524
26112
  : (context.event && typeof context.event === 'object' && 'payload' in context.event)
@@ -25680,6 +26268,14 @@ class LinkExecutorService {
25680
26268
  stateLayer: layer,
25681
26269
  };
25682
26270
  }
26271
+ if (link.to.kind === 'global-action') {
26272
+ return {
26273
+ kind: 'global-action',
26274
+ value,
26275
+ actionId: link.to.ref.actionId,
26276
+ actionRef: this.clone(link.to.ref),
26277
+ };
26278
+ }
25683
26279
  return {
25684
26280
  kind: 'component-port',
25685
26281
  value,
@@ -25883,6 +26479,7 @@ class CompositionRuntimeEngine {
25883
26479
  linkExecutor;
25884
26480
  stateRuntime;
25885
26481
  traceService;
26482
+ compositionValidator;
25886
26483
  pathAccessor = new ConnectionManagerService();
25887
26484
  nestedWidgetAccessor = new NestedWidgetConfigAccessor();
25888
26485
  definition = null;
@@ -25893,12 +26490,17 @@ class CompositionRuntimeEngine {
25893
26490
  this.linkExecutor = options.linkExecutor ?? createDefaultLinkExecutor();
25894
26491
  this.stateRuntime = options.stateRuntime ?? createDefaultStateRuntime();
25895
26492
  this.traceService = options.traceService ?? new RuntimeTraceService();
26493
+ this.compositionValidator = options.compositionValidator ?? new CompositionValidatorService();
25896
26494
  }
25897
26495
  bootstrap(definition) {
25898
26496
  this.definition = definition;
25899
26497
  const generatedAt = this.now();
25900
26498
  const stateSnapshot = this.materializeDerivedState(definition.state.primaryValues, definition);
25901
- const bootstrapDiagnostics = uniqueDiagnosticsById(stateSnapshot.diagnostics);
26499
+ const semanticDiagnostics = this.validateComposition(definition);
26500
+ const bootstrapDiagnostics = uniqueDiagnosticsById([
26501
+ ...semanticDiagnostics,
26502
+ ...stateSnapshot.diagnostics,
26503
+ ]);
25902
26504
  const init = {
25903
26505
  status: bootstrapDiagnostics.some(isBlockingDiagnostic) ? 'degraded' : 'ready',
25904
26506
  generatedAt,
@@ -26294,6 +26896,18 @@ class CompositionRuntimeEngine {
26294
26896
  diagnostics: derivedSnapshot.diagnostics.map((message, index) => this.createDerivedDiagnostic(definition, message, index)),
26295
26897
  };
26296
26898
  }
26899
+ validateComposition(definition) {
26900
+ const page = {
26901
+ widgets: definition.widgetOrder
26902
+ .map((widgetKey) => definition.widgetsByKey[widgetKey])
26903
+ .filter((widget) => !!widget),
26904
+ };
26905
+ const links = definition.links;
26906
+ return links.flatMap((link) => this.compositionValidator.validateLink(link, {
26907
+ page,
26908
+ links,
26909
+ }));
26910
+ }
26297
26911
  createDerivedDiagnostic(definition, message, index) {
26298
26912
  const nodeKey = this.extractDerivedNodeKey(message);
26299
26913
  const classification = classifyDerivedDiagnosticMessage(message);
@@ -26410,6 +27024,9 @@ class CompositionRuntimeEngine {
26410
27024
  function isComponentPortEndpoint(endpoint) {
26411
27025
  return endpoint.kind === 'component-port';
26412
27026
  }
27027
+ function isGlobalActionEndpoint(endpoint) {
27028
+ return endpoint.kind === 'global-action';
27029
+ }
26413
27030
  function createDefaultLinkExecutor() {
26414
27031
  const connections = new ConnectionManagerService();
26415
27032
  const transforms = new TransformRuntimeService(connections, new SurfaceBindingRuntimeService());
@@ -26538,6 +27155,9 @@ function matchesEndpoint(expected, actual) {
26538
27155
  return expected.ref.path === actual.ref.path
26539
27156
  && (expected.ref.layer ?? 'values') === (actual.ref.layer ?? 'values');
26540
27157
  }
27158
+ if (isGlobalActionEndpoint(expected) && isGlobalActionEndpoint(actual)) {
27159
+ return expected.ref.actionId === actual.ref.actionId;
27160
+ }
26541
27161
  return false;
26542
27162
  }
26543
27163
  function areNestedPathsEqual(expected, actual) {
@@ -26567,6 +27187,14 @@ function toSubjectRef(endpoint) {
26567
27187
  : endpoint.ref.bindingPath,
26568
27188
  };
26569
27189
  }
27190
+ if (endpoint.kind === 'global-action') {
27191
+ return {
27192
+ kind: 'global-action',
27193
+ actionId: endpoint.ref.actionId,
27194
+ path: endpoint.ref.actionId,
27195
+ label: endpoint.ref.actionId,
27196
+ };
27197
+ }
26570
27198
  return {
26571
27199
  kind: endpoint.ref.layer === 'derived' ? 'derived-state' : 'state',
26572
27200
  statePath: endpoint.ref.path,
@@ -26580,6 +27208,11 @@ function endpointTraceDetails(prefix, endpoint) {
26580
27208
  [`${prefix}StateLayer`]: endpoint.ref.layer ?? 'values',
26581
27209
  };
26582
27210
  }
27211
+ if (endpoint.kind === 'global-action') {
27212
+ return {
27213
+ [`${prefix}ActionId`]: endpoint.ref.actionId,
27214
+ };
27215
+ }
26583
27216
  const details = {
26584
27217
  [`${prefix}WidgetKey`]: endpoint.ref.widget,
26585
27218
  [`${prefix}PortId`]: endpoint.ref.port,
@@ -26600,6 +27233,11 @@ function deliveryTraceDetails(delivery) {
26600
27233
  targetStateLayer: delivery.stateLayer ?? 'values',
26601
27234
  };
26602
27235
  }
27236
+ if (delivery.kind === 'global-action') {
27237
+ return {
27238
+ targetActionId: delivery.actionId,
27239
+ };
27240
+ }
26603
27241
  const details = {
26604
27242
  targetWidgetKey: delivery.widgetKey,
26605
27243
  targetPortId: delivery.portId,
@@ -26847,105 +27485,244 @@ function looksLikePath(value) {
26847
27485
  return /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[\d+\])*$/.test(value);
26848
27486
  }
26849
27487
  function toJsonLogicValue(value) {
26850
- switch (typeof value) {
26851
- case 'string':
26852
- case 'number':
26853
- case 'boolean':
26854
- return value;
26855
- case 'undefined':
26856
- return null;
26857
- default:
26858
- break;
26859
- }
26860
- if (value === null) {
26861
- return null;
26862
- }
26863
- if (Array.isArray(value) || (value && typeof value === 'object')) {
26864
- return clone(value);
26865
- }
26866
- return String(value);
26867
- }
26868
- function clone(value) {
26869
- if (value == null || typeof value !== 'object') {
26870
- return value;
26871
- }
26872
- return JSON.parse(JSON.stringify(value));
26873
- }
26874
-
26875
- class NestedPortCatalogService {
26876
- accessor;
26877
- constructor(accessor = new NestedWidgetConfigAccessor()) {
26878
- this.accessor = accessor;
26879
- }
26880
- resolve(page, registry) {
26881
- const ports = [];
26882
- const diagnostics = [];
26883
- for (const owner of page.widgets || []) {
26884
- const nestedWidgets = this.accessor.listNestedWidgets(owner);
26885
- for (const nested of nestedWidgets) {
26886
- if (!this.hasStableTerminalKey(nested.nestedPath)) {
26887
- diagnostics.push({
26888
- code: 'NESTED_WIDGET_KEY_MISSING',
26889
- severity: 'error',
26890
- ownerWidgetKey: owner.key,
26891
- nestedPath: this.clone(nested.nestedPath),
26892
- componentId: nested.componentId,
26893
- message: `Nested widget inside '${owner.key}' must declare a stable childWidgetKey.`,
26894
- });
26895
- continue;
26896
- }
26897
- const meta = registry.get(nested.componentId);
26898
- if (!meta?.ports?.length) {
26899
- diagnostics.push({
26900
- code: 'NESTED_WIDGET_METADATA_MISSING',
26901
- severity: 'warning',
26902
- ownerWidgetKey: owner.key,
26903
- nestedPath: this.clone(nested.nestedPath),
26904
- componentId: nested.componentId,
26905
- message: `No component metadata ports found for nested widget '${nested.componentId}'.`,
26906
- });
26907
- continue;
26908
- }
26909
- for (const port of meta.ports) {
26910
- ports.push({
26911
- ownerWidgetKey: owner.key,
26912
- ownerComponentId: owner.definition.id,
26913
- nestedPath: this.clone(nested.nestedPath),
26914
- containerPath: this.containerPath(nested.nestedPath),
26915
- port: this.clone(port),
26916
- componentId: nested.componentId,
26917
- childWidgetKey: nested.childWidgetKey,
26918
- });
26919
- }
26920
- }
26921
- }
26922
- return { ports, diagnostics };
26923
- }
26924
- resolveEndpoint(page, registry, options) {
26925
- return this.resolve(page, registry).ports.find((port) => port.ownerWidgetKey === options.ownerWidgetKey
26926
- && port.port.id === options.portId
26927
- && port.port.direction === options.direction
26928
- && this.isSamePath(port.nestedPath, options.nestedPath));
26929
- }
26930
- hasStableTerminalKey(nestedPath) {
26931
- const terminal = nestedPath[nestedPath.length - 1];
26932
- return terminal?.kind === 'widget'
26933
- && typeof terminal.key === 'string'
26934
- && terminal.key.trim().length > 0;
27488
+ switch (typeof value) {
27489
+ case 'string':
27490
+ case 'number':
27491
+ case 'boolean':
27492
+ return value;
27493
+ case 'undefined':
27494
+ return null;
27495
+ default:
27496
+ break;
26935
27497
  }
26936
- containerPath(nestedPath) {
26937
- return nestedPath.slice(0, -1).map((segment) => this.clone(segment));
27498
+ if (value === null) {
27499
+ return null;
26938
27500
  }
26939
- isSamePath(left, right) {
26940
- return JSON.stringify(left) === JSON.stringify(right);
27501
+ if (Array.isArray(value) || (value && typeof value === 'object')) {
27502
+ return clone(value);
26941
27503
  }
26942
- clone(value) {
26943
- if (value == null || typeof value !== 'object') {
26944
- return value;
26945
- }
26946
- return JSON.parse(JSON.stringify(value));
27504
+ return String(value);
27505
+ }
27506
+ function clone(value) {
27507
+ if (value == null || typeof value !== 'object') {
27508
+ return value;
26947
27509
  }
27510
+ return JSON.parse(JSON.stringify(value));
27511
+ }
27512
+
27513
+ class DynamicWidgetContextToolbarComponent {
27514
+ toolbarLabel = '';
27515
+ contextLabel = '';
27516
+ contextTooltip = '';
27517
+ showAssistant = false;
27518
+ assistantLabel = '';
27519
+ assistantTooltip = '';
27520
+ showComponentSettings = false;
27521
+ componentSettingsLabel = '';
27522
+ componentSettingsTooltip = '';
27523
+ showShellSettings = false;
27524
+ shellSettingsLabel = '';
27525
+ shellSettingsTooltip = '';
27526
+ moreActionsLabel = '';
27527
+ removeLabel = '';
27528
+ assistant = new EventEmitter();
27529
+ componentSettings = new EventEmitter();
27530
+ shellSettings = new EventEmitter();
27531
+ remove = new EventEmitter();
27532
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicWidgetContextToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
27533
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: DynamicWidgetContextToolbarComponent, isStandalone: true, selector: "praxis-dynamic-widget-context-toolbar", inputs: { toolbarLabel: "toolbarLabel", contextLabel: "contextLabel", contextTooltip: "contextTooltip", showAssistant: "showAssistant", assistantLabel: "assistantLabel", assistantTooltip: "assistantTooltip", showComponentSettings: "showComponentSettings", componentSettingsLabel: "componentSettingsLabel", componentSettingsTooltip: "componentSettingsTooltip", showShellSettings: "showShellSettings", shellSettingsLabel: "shellSettingsLabel", shellSettingsTooltip: "shellSettingsTooltip", moreActionsLabel: "moreActionsLabel", removeLabel: "removeLabel" }, outputs: { assistant: "assistant", componentSettings: "componentSettings", shellSettings: "shellSettings", remove: "remove" }, ngImport: i0, template: `
27534
+ <div
27535
+ class="pdx-widget-context-toolbar"
27536
+ [class.pdx-widget-context-toolbar--with-context]="!!contextLabel"
27537
+ data-testid="dynamic-widget-context-toolbar"
27538
+ role="toolbar"
27539
+ [attr.aria-label]="toolbarLabel"
27540
+ (click)="$event.stopPropagation()"
27541
+ (pointerdown)="$event.stopPropagation()"
27542
+ >
27543
+ @if (contextLabel) {
27544
+ <span
27545
+ class="pdx-widget-context-toolbar__context"
27546
+ data-testid="dynamic-widget-context-label"
27547
+ [matTooltip]="contextTooltip || contextLabel"
27548
+ >
27549
+ {{ contextLabel }}
27550
+ </span>
27551
+ }
27552
+ @if (showAssistant) {
27553
+ <button
27554
+ mat-icon-button
27555
+ type="button"
27556
+ data-testid="dynamic-widget-assistant"
27557
+ [matTooltip]="assistantTooltip"
27558
+ [attr.aria-label]="assistantLabel"
27559
+ (click)="assistant.emit()"
27560
+ >
27561
+ <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
27562
+ </button>
27563
+ }
27564
+ @if (showComponentSettings) {
27565
+ <button
27566
+ mat-icon-button
27567
+ type="button"
27568
+ data-testid="dynamic-widget-component-settings"
27569
+ [matTooltip]="componentSettingsTooltip"
27570
+ [attr.aria-label]="componentSettingsLabel"
27571
+ (click)="componentSettings.emit()"
27572
+ >
27573
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
27574
+ </button>
27575
+ }
27576
+ @if (showShellSettings) {
27577
+ <button
27578
+ mat-icon-button
27579
+ type="button"
27580
+ data-testid="dynamic-widget-shell-settings"
27581
+ [matTooltip]="shellSettingsTooltip"
27582
+ [attr.aria-label]="shellSettingsLabel"
27583
+ (click)="shellSettings.emit()"
27584
+ >
27585
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
27586
+ </button>
27587
+ }
27588
+ <button
27589
+ mat-icon-button
27590
+ type="button"
27591
+ data-testid="dynamic-widget-more-actions"
27592
+ [matTooltip]="moreActionsLabel"
27593
+ [attr.aria-label]="moreActionsLabel"
27594
+ [matMenuTriggerFor]="widgetContextMenu"
27595
+ >
27596
+ <mat-icon praxisIcon="ms:more_horiz"></mat-icon>
27597
+ </button>
27598
+ <mat-menu #widgetContextMenu="matMenu">
27599
+ <button mat-menu-item type="button" data-testid="dynamic-widget-remove" (click)="remove.emit()">
27600
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
27601
+ <span>{{ removeLabel }}</span>
27602
+ </button>
27603
+ </mat-menu>
27604
+ </div>
27605
+ `, 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}.pdx-widget-context-toolbar button{--mdc-icon-button-state-layer-size: 30px;--mat-icon-button-state-layer-size: 30px;display:inline-grid;place-items:center;flex:0 0 auto;width:30px;height:30px;padding:0;line-height:1;vertical-align:middle}.pdx-widget-context-toolbar mat-icon{width:18px;height:18px;font-size:18px;line-height:18px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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: MatIconModule }, { kind: "component", type: i2$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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
26948
27606
  }
27607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicWidgetContextToolbarComponent, decorators: [{
27608
+ type: Component,
27609
+ args: [{ selector: 'praxis-dynamic-widget-context-toolbar', standalone: true, imports: [
27610
+ CommonModule,
27611
+ MatButtonModule,
27612
+ MatIconModule,
27613
+ MatMenuModule,
27614
+ MatTooltipModule,
27615
+ PraxisIconDirective,
27616
+ ], template: `
27617
+ <div
27618
+ class="pdx-widget-context-toolbar"
27619
+ [class.pdx-widget-context-toolbar--with-context]="!!contextLabel"
27620
+ data-testid="dynamic-widget-context-toolbar"
27621
+ role="toolbar"
27622
+ [attr.aria-label]="toolbarLabel"
27623
+ (click)="$event.stopPropagation()"
27624
+ (pointerdown)="$event.stopPropagation()"
27625
+ >
27626
+ @if (contextLabel) {
27627
+ <span
27628
+ class="pdx-widget-context-toolbar__context"
27629
+ data-testid="dynamic-widget-context-label"
27630
+ [matTooltip]="contextTooltip || contextLabel"
27631
+ >
27632
+ {{ contextLabel }}
27633
+ </span>
27634
+ }
27635
+ @if (showAssistant) {
27636
+ <button
27637
+ mat-icon-button
27638
+ type="button"
27639
+ data-testid="dynamic-widget-assistant"
27640
+ [matTooltip]="assistantTooltip"
27641
+ [attr.aria-label]="assistantLabel"
27642
+ (click)="assistant.emit()"
27643
+ >
27644
+ <mat-icon [praxisIcon]="'auto_awesome'"></mat-icon>
27645
+ </button>
27646
+ }
27647
+ @if (showComponentSettings) {
27648
+ <button
27649
+ mat-icon-button
27650
+ type="button"
27651
+ data-testid="dynamic-widget-component-settings"
27652
+ [matTooltip]="componentSettingsTooltip"
27653
+ [attr.aria-label]="componentSettingsLabel"
27654
+ (click)="componentSettings.emit()"
27655
+ >
27656
+ <mat-icon [praxisIcon]="'tune'"></mat-icon>
27657
+ </button>
27658
+ }
27659
+ @if (showShellSettings) {
27660
+ <button
27661
+ mat-icon-button
27662
+ type="button"
27663
+ data-testid="dynamic-widget-shell-settings"
27664
+ [matTooltip]="shellSettingsTooltip"
27665
+ [attr.aria-label]="shellSettingsLabel"
27666
+ (click)="shellSettings.emit()"
27667
+ >
27668
+ <mat-icon [praxisIcon]="'settings'"></mat-icon>
27669
+ </button>
27670
+ }
27671
+ <button
27672
+ mat-icon-button
27673
+ type="button"
27674
+ data-testid="dynamic-widget-more-actions"
27675
+ [matTooltip]="moreActionsLabel"
27676
+ [attr.aria-label]="moreActionsLabel"
27677
+ [matMenuTriggerFor]="widgetContextMenu"
27678
+ >
27679
+ <mat-icon praxisIcon="ms:more_horiz"></mat-icon>
27680
+ </button>
27681
+ <mat-menu #widgetContextMenu="matMenu">
27682
+ <button mat-menu-item type="button" data-testid="dynamic-widget-remove" (click)="remove.emit()">
27683
+ <mat-icon [praxisIcon]="'delete'"></mat-icon>
27684
+ <span>{{ removeLabel }}</span>
27685
+ </button>
27686
+ </mat-menu>
27687
+ </div>
27688
+ `, changeDetection: ChangeDetectionStrategy.OnPush, 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}.pdx-widget-context-toolbar button{--mdc-icon-button-state-layer-size: 30px;--mat-icon-button-state-layer-size: 30px;display:inline-grid;place-items:center;flex:0 0 auto;width:30px;height:30px;padding:0;line-height:1;vertical-align:middle}.pdx-widget-context-toolbar mat-icon{width:18px;height:18px;font-size:18px;line-height:18px}\n"] }]
27689
+ }], propDecorators: { toolbarLabel: [{
27690
+ type: Input
27691
+ }], contextLabel: [{
27692
+ type: Input
27693
+ }], contextTooltip: [{
27694
+ type: Input
27695
+ }], showAssistant: [{
27696
+ type: Input
27697
+ }], assistantLabel: [{
27698
+ type: Input
27699
+ }], assistantTooltip: [{
27700
+ type: Input
27701
+ }], showComponentSettings: [{
27702
+ type: Input
27703
+ }], componentSettingsLabel: [{
27704
+ type: Input
27705
+ }], componentSettingsTooltip: [{
27706
+ type: Input
27707
+ }], showShellSettings: [{
27708
+ type: Input
27709
+ }], shellSettingsLabel: [{
27710
+ type: Input
27711
+ }], shellSettingsTooltip: [{
27712
+ type: Input
27713
+ }], moreActionsLabel: [{
27714
+ type: Input
27715
+ }], removeLabel: [{
27716
+ type: Input
27717
+ }], assistant: [{
27718
+ type: Output
27719
+ }], componentSettings: [{
27720
+ type: Output
27721
+ }], shellSettings: [{
27722
+ type: Output
27723
+ }], remove: [{
27724
+ type: Output
27725
+ }] } });
26949
27726
 
26950
27727
  const DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE = 'dynamicWidgetPage';
26951
27728
  const DYNAMIC_WIDGET_PAGE_I18N_CONFIG = {
@@ -26953,9 +27730,22 @@ const DYNAMIC_WIDGET_PAGE_I18N_CONFIG = {
26953
27730
  [DYNAMIC_WIDGET_PAGE_I18N_NAMESPACE]: {
26954
27731
  'pt-BR': {
26955
27732
  'controls.pageSettings': 'Configurar página',
27733
+ 'controls.componentSettings': 'Configurar conteúdo',
27734
+ 'controls.componentSettingsTooltip': 'Abrir configurações do componente',
26956
27735
  'controls.widgetSettings': 'Configurar widget',
26957
27736
  'controls.widgetSettingsTooltip': 'Abrir configurações do widget',
27737
+ 'controls.widgetAssistant': 'Abrir assistente do widget',
27738
+ 'controls.widgetAssistantTooltip': 'Abrir o assistente Praxis com contexto deste widget',
27739
+ 'controls.widgetRemove': 'Excluir widget',
27740
+ 'controls.widgetRemoveTooltip': 'Excluir este widget e limpar conexões vinculadas',
27741
+ 'controls.widgetRemoveConfirmTitle': 'Excluir widget?',
27742
+ 'controls.widgetRemoveConfirmMessage': 'O widget "{{widget}}" será removido da página. Conexões e posições vinculadas também serão limpas.',
27743
+ 'controls.widgetRemoveConfirm': 'Excluir widget',
27744
+ 'controls.cancel': 'Cancelar',
26958
27745
  'controls.cardSettings': 'Configurar card',
27746
+ 'controls.moreWidgetActions': 'Mais ações do widget',
27747
+ 'controls.widgetContextToolbar': 'Ações do widget {{widget}}',
27748
+ 'controls.widgetContextTooltip': 'Editando {{widget}}',
26959
27749
  'controls.widgetLayoutToolbar': 'Ações de layout do widget',
26960
27750
  'controls.dragWidget': 'Arrastar widget',
26961
27751
  'controls.resizeWidget': 'Redimensionar widget',
@@ -26976,9 +27766,22 @@ const DYNAMIC_WIDGET_PAGE_I18N_CONFIG = {
26976
27766
  },
26977
27767
  'en-US': {
26978
27768
  'controls.pageSettings': 'Configure page',
27769
+ 'controls.componentSettings': 'Configure content',
27770
+ 'controls.componentSettingsTooltip': 'Open component settings',
26979
27771
  'controls.widgetSettings': 'Configure widget',
26980
27772
  'controls.widgetSettingsTooltip': 'Open widget settings',
27773
+ 'controls.widgetAssistant': 'Open widget assistant',
27774
+ 'controls.widgetAssistantTooltip': 'Open the Praxis assistant with this widget context',
27775
+ 'controls.widgetRemove': 'Delete widget',
27776
+ 'controls.widgetRemoveTooltip': 'Delete this widget and clean linked connections',
27777
+ 'controls.widgetRemoveConfirmTitle': 'Delete widget?',
27778
+ 'controls.widgetRemoveConfirmMessage': 'The widget "{{widget}}" will be removed from the page. Linked connections and positions will also be cleaned.',
27779
+ 'controls.widgetRemoveConfirm': 'Delete widget',
27780
+ 'controls.cancel': 'Cancel',
26981
27781
  'controls.cardSettings': 'Configure card',
27782
+ 'controls.moreWidgetActions': 'More widget actions',
27783
+ 'controls.widgetContextToolbar': 'Widget {{widget}} actions',
27784
+ 'controls.widgetContextTooltip': 'Editing {{widget}}',
26982
27785
  'controls.widgetLayoutToolbar': 'Widget layout actions',
26983
27786
  'controls.dragWidget': 'Drag widget',
26984
27787
  'controls.resizeWidget': 'Resize widget',
@@ -27158,8 +27961,12 @@ class DynamicWidgetPageComponent {
27158
27961
  pageIdentity;
27159
27962
  /** Optional instance key for pages rendered multiple times. */
27160
27963
  componentInstanceId;
27964
+ /** Enables a contextual authoring assistant entrypoint for the selected widget. */
27965
+ showWidgetAssistantButton = false;
27161
27966
  pageChange = new EventEmitter();
27162
27967
  widgetEvent = new EventEmitter();
27968
+ widgetSelectionChange = new EventEmitter();
27969
+ widgetAssistantRequested = new EventEmitter();
27163
27970
  widgetDiagnosticsChange = new EventEmitter();
27164
27971
  widgets = signal([], ...(ngDevMode ? [{ debugName: "widgets" }] : []));
27165
27972
  renderedGroups = signal([], ...(ngDevMode ? [{ debugName: "renderedGroups" }] : []));
@@ -27184,7 +27991,7 @@ class DynamicWidgetPageComponent {
27184
27991
  pageColumnCount = 1;
27185
27992
  activeTabs = {};
27186
27993
  widgetDiagnostics = {};
27187
- selectedCanvasWidgetKey = null;
27994
+ selectedWidgetKey = null;
27188
27995
  blockedCanvasWidgetKey = null;
27189
27996
  canvasPreviewState = signal(null, ...(ngDevMode ? [{ debugName: "canvasPreviewState" }] : []));
27190
27997
  canvasPreviewInvalidState = signal(false, ...(ngDevMode ? [{ debugName: "canvasPreviewInvalidState" }] : []));
@@ -27195,6 +28002,7 @@ class DynamicWidgetPageComponent {
27195
28002
  persistenceReady = false;
27196
28003
  warnedMissingKey = false;
27197
28004
  runtimeEventSequence = 0;
28005
+ widgetShellRenderCache = new Map();
27198
28006
  compositionFactory = new WidgetPageCompositionFactory();
27199
28007
  compositionRuntime = new CompositionRuntimeFacade();
27200
28008
  compositionDefinition;
@@ -27233,6 +28041,7 @@ class DynamicWidgetPageComponent {
27233
28041
  if (changes['page'] ||
27234
28042
  changes['context'] ||
27235
28043
  changes['enableCustomization']) {
28044
+ this.widgetShellRenderCache.clear();
27236
28045
  const parsed = this.parsePage(this.page);
27237
28046
  const resolvedPage = parsed ? this.resolvePagePresets(parsed) : parsed;
27238
28047
  this.assertNoLegacyConnections(resolvedPage);
@@ -27298,6 +28107,11 @@ class DynamicWidgetPageComponent {
27298
28107
  }
27299
28108
  return;
27300
28109
  }
28110
+ this.executeCompositionGlobalActionDeliveries(cycle, {
28111
+ fromKey,
28112
+ event: evt,
28113
+ page: pageWithPatchedInputs,
28114
+ });
27301
28115
  const state = this.stateFromCompositionSnapshot(pageWithPatchedInputs.state, cycle.snapshot.state.primaryValues);
27302
28116
  const runtimeStatePaths = Array.from(new Set((cycle.snapshot.state.changedPaths || []).filter((path) => typeof path === 'string')));
27303
28117
  const updatedPrimaryStatePaths = runtimeStatePaths.filter((path) => !this.areStateValuesEqual(this.conn.extractByPath(this.stateRuntime.normalizeState(page.state).values || {}, path), this.conn.extractByPath(state.values || {}, path)));
@@ -27386,52 +28200,7 @@ class DynamicWidgetPageComponent {
27386
28200
  return this.compositionRuntime.bootstrap(this.compositionDefinition);
27387
28201
  }
27388
28202
  applyEditShellActions(widgets) {
27389
- return this.cloneWidgets(widgets).map((widget) => {
27390
- if (!this.shouldInjectEditShellActions(widget)) {
27391
- return widget;
27392
- }
27393
- const existingActions = widget.shell?.actions || [];
27394
- const metadata = this.componentMetadata?.get(widget.definition?.id || '');
27395
- const nextActions = [...existingActions];
27396
- if (metadata?.configEditor &&
27397
- !nextActions.some((action) => action.id === 'component-settings')) {
27398
- nextActions.push({
27399
- id: 'component-settings',
27400
- icon: 'tune',
27401
- variant: 'icon',
27402
- placement: 'header',
27403
- label: this.t('controls.componentSettings', 'Configurar conteudo'),
27404
- tooltip: this.t('controls.componentSettingsTooltip', 'Abrir configuracoes do componente'),
27405
- });
27406
- }
27407
- if (nextActions.some((action) => action.id === 'widget-settings') ||
27408
- !this.canOpenWidgetShellSettings()) {
27409
- return this.withShellActions(widget, nextActions);
27410
- }
27411
- const widgetSettingsAction = {
27412
- id: 'widget-settings',
27413
- icon: 'settings',
27414
- variant: 'icon',
27415
- placement: 'header',
27416
- label: this.t('controls.widgetSettings', 'Configurar widget'),
27417
- tooltip: this.t('controls.widgetSettingsTooltip', 'Abrir configurações do widget'),
27418
- };
27419
- return this.withShellActions(widget, [...nextActions, widgetSettingsAction]);
27420
- });
27421
- }
27422
- withShellActions(widget, actions) {
27423
- const existingActions = widget.shell?.actions || [];
27424
- if (existingActions.length === actions.length &&
27425
- existingActions.every((action, index) => action === actions[index])) {
27426
- return widget;
27427
- }
27428
- return {
27429
- ...widget,
27430
- shell: {
27431
- ...(widget.shell || {}),
27432
- actions,
27433
- },
27434
- };
28203
+ return this.cloneWidgets(widgets);
27435
28204
  }
27436
28205
  applyBootstrapCompositionHydration(widgets, bootstrapSnapshot) {
27437
28206
  if (!this.compositionDefinition || !bootstrapSnapshot) {
@@ -27579,6 +28348,50 @@ class DynamicWidgetPageComponent {
27579
28348
  }
27580
28349
  return { widgets: nextWidgets, changed };
27581
28350
  }
28351
+ executeCompositionGlobalActionDeliveries(cycle, options) {
28352
+ if (!this.compositionDefinition) {
28353
+ return;
28354
+ }
28355
+ const linksById = new Map(this.compositionDefinition.links.map((link) => [link.id, link]));
28356
+ const runtimeLinks = cycle.snapshot.links.filter((link) => link.lastDispatchTraceId === cycle.cycleId &&
28357
+ link.status === 'delivered');
28358
+ for (const runtimeLink of runtimeLinks) {
28359
+ const link = linksById.get(runtimeLink.linkId);
28360
+ if (!link || link.to.kind !== 'global-action') {
28361
+ continue;
28362
+ }
28363
+ const deliveredValue = this.cloneStateValues(runtimeLink.lastDeliveredValuePreview);
28364
+ const actionRef = this.resolveCompositionGlobalActionRef(link.to.ref, deliveredValue);
28365
+ void this.globalActions.executeRef(actionRef, {
28366
+ sourceId: options.fromKey,
28367
+ widgetKey: options.event.ownerWidgetKey || options.fromKey,
28368
+ output: options.event.output,
28369
+ payload: deliveredValue,
28370
+ pageContext: options.page.context || null,
28371
+ runtime: {
28372
+ value: deliveredValue,
28373
+ state: this.cloneStateValues(cycle.snapshot.state.primaryValues),
28374
+ },
28375
+ meta: {
28376
+ origin: 'dynamic-page.composition-link',
28377
+ componentId: 'praxis-dynamic-page',
28378
+ linkId: link.id,
28379
+ intent: link.intent,
28380
+ },
28381
+ });
28382
+ }
28383
+ }
28384
+ resolveCompositionGlobalActionRef(ref, deliveredValue) {
28385
+ const hasConfiguredPayload = Object.prototype.hasOwnProperty.call(ref, 'payload') ||
28386
+ String(ref.payloadExpr || '').trim().length > 0;
28387
+ if (hasConfiguredPayload) {
28388
+ return this.cloneStateValues(ref);
28389
+ }
28390
+ return {
28391
+ ...this.cloneStateValues(ref),
28392
+ payload: deliveredValue,
28393
+ };
28394
+ }
27582
28395
  buildStateContext(pageContext) {
27583
28396
  return {
27584
28397
  ...(this.cloneStateValues(pageContext) || {}),
@@ -27705,7 +28518,7 @@ class DynamicWidgetPageComponent {
27705
28518
  case 'page.autoPersist.disabled':
27706
28519
  return !this.autoPersist;
27707
28520
  case 'page.widget.selected':
27708
- return this.selectedCanvasWidgetKey === widgetKey;
28521
+ return this.selectedWidgetKey === widgetKey;
27709
28522
  case 'page.widget.configurable': {
27710
28523
  const widget = this.widgets().find((candidate) => candidate.key === widgetKey);
27711
28524
  const widgetType = widget?.definition?.id || '';
@@ -27746,14 +28559,185 @@ class DynamicWidgetPageComponent {
27746
28559
  }
27747
28560
  return `widget:${fromKey}:${output}:${timestamp}:${sequence}`;
27748
28561
  }
27749
- shouldInjectEditShellActions(widget) {
27750
- if (!this.enableCustomization || !this.settingsPanel) {
28562
+ canOpenWidgetShellSettings() {
28563
+ return !!(this.shellEditorComponent || this.defaultShellEditor);
28564
+ }
28565
+ canOpenWidgetComponentSettings(key) {
28566
+ const page = this.pageDefinition || this.parsePage(this.page);
28567
+ const widget = page?.widgets?.find((candidate) => candidate.key === key);
28568
+ if (!widget)
28569
+ return false;
28570
+ const metadata = this.componentMetadata?.get(widget.definition?.id || '');
28571
+ return !!metadata?.configEditor?.component;
28572
+ }
28573
+ componentSettingsLabel() {
28574
+ return this.t('controls.componentSettings', 'Configurar conteúdo');
28575
+ }
28576
+ componentSettingsTooltip() {
28577
+ return this.t('controls.componentSettingsTooltip', 'Abrir configurações do componente');
28578
+ }
28579
+ widgetSettingsLabel() {
28580
+ return this.t('controls.widgetSettings', 'Configurar widget');
28581
+ }
28582
+ widgetSettingsTooltip() {
28583
+ return this.t('controls.widgetSettingsTooltip', 'Abrir configurações do widget');
28584
+ }
28585
+ widgetAssistantLabel() {
28586
+ return this.t('controls.widgetAssistant', 'Abrir assistente do widget');
28587
+ }
28588
+ widgetAssistantTooltip() {
28589
+ return this.t('controls.widgetAssistantTooltip', 'Abrir o assistente Praxis com contexto deste widget');
28590
+ }
28591
+ requestWidgetAssistant(widgetKey) {
28592
+ this.selectWidget(widgetKey);
28593
+ this.widgetAssistantRequested.emit(widgetKey);
28594
+ }
28595
+ widgetRemoveLabel() {
28596
+ return this.t('controls.widgetRemove', 'Excluir widget');
28597
+ }
28598
+ moreWidgetActionsLabel() {
28599
+ return this.t('controls.moreWidgetActions', 'Mais ações do widget');
28600
+ }
28601
+ widgetContextToolbarLabel(widgetKey) {
28602
+ return this.t('controls.widgetContextToolbar', 'Ações do widget {{widget}}', {
28603
+ widget: widgetKey,
28604
+ });
28605
+ }
28606
+ widgetContextLabel(widget) {
28607
+ return this.resolveWidgetDisplayName(widget);
28608
+ }
28609
+ widgetContextTooltip(widget) {
28610
+ const label = this.resolveWidgetDisplayName(widget);
28611
+ return this.t('controls.widgetContextTooltip', 'Editando {{widget}}', {
28612
+ widget: label,
28613
+ });
28614
+ }
28615
+ shouldRenderWidgetContextOverlay(widget) {
28616
+ return (this.enableCustomization &&
28617
+ this.isWidgetSelected(widget.key) &&
28618
+ !this.hasVisibleWidgetShellHeader(widget));
28619
+ }
28620
+ widgetShellForRender(widget) {
28621
+ if (!this.shouldProjectWidgetHeaderActions(widget)) {
28622
+ return widget.shell;
28623
+ }
28624
+ const projectedActions = this.buildProjectedWidgetShellActions(widget);
28625
+ if (!projectedActions.length) {
28626
+ return widget.shell;
28627
+ }
28628
+ const signature = this.widgetShellActionSignature(projectedActions);
28629
+ const cached = this.widgetShellRenderCache.get(widget.key);
28630
+ if (cached &&
28631
+ cached.source === widget.shell &&
28632
+ cached.signature === signature) {
28633
+ return cached.shell;
28634
+ }
28635
+ const existingActions = widget.shell?.actions || [];
28636
+ const existingIds = new Set(existingActions.map((action) => action.id));
28637
+ const shell = {
28638
+ ...widget.shell,
28639
+ actions: [
28640
+ ...existingActions,
28641
+ ...projectedActions.filter((action) => !existingIds.has(action.id)),
28642
+ ],
28643
+ };
28644
+ this.widgetShellRenderCache.set(widget.key, {
28645
+ source: widget.shell,
28646
+ signature,
28647
+ shell,
28648
+ });
28649
+ return shell;
28650
+ }
28651
+ resolveWidgetDisplayName(widget) {
28652
+ const shellTitle = String(widget.shell?.title || '').trim();
28653
+ if (shellTitle)
28654
+ return shellTitle;
28655
+ const componentId = widget.definition?.id || '';
28656
+ const metadata = componentId ? this.componentMetadata?.get(componentId) : undefined;
28657
+ return metadata?.friendlyName || componentId || widget.key;
28658
+ }
28659
+ shouldProjectWidgetHeaderActions(widget) {
28660
+ return (this.enableCustomization &&
28661
+ this.isWidgetSelected(widget.key) &&
28662
+ this.hasVisibleWidgetShellHeader(widget));
28663
+ }
28664
+ hasVisibleWidgetShellHeader(widget) {
28665
+ const shell = widget.shell;
28666
+ if (!shell || shell.kind === 'none')
27751
28667
  return false;
28668
+ if (shell.showHeader != null)
28669
+ return !!shell.showHeader;
28670
+ return !!(shell.title ||
28671
+ shell.subtitle ||
28672
+ shell.icon ||
28673
+ this.hasVisibleShellActions(shell) ||
28674
+ this.hasVisibleWindowActions(shell));
28675
+ }
28676
+ hasVisibleShellActions(shell) {
28677
+ return (shell.actions || []).some((action) => this.isVisibleShellAction(action));
28678
+ }
28679
+ hasVisibleWindowActions(shell) {
28680
+ return ((shell.windowActions?.collapsible !== false ||
28681
+ shell.windowActions?.fullscreen !== false) ||
28682
+ (shell.actions || []).some((action) => this.isVisibleShellAction(action) &&
28683
+ (action.placement || 'header') === 'window'));
28684
+ }
28685
+ buildProjectedWidgetShellActions(widget) {
28686
+ const actions = [];
28687
+ if (this.showWidgetAssistantButton) {
28688
+ actions.push({
28689
+ id: 'widget-assistant',
28690
+ label: this.widgetAssistantLabel(),
28691
+ tooltip: this.widgetAssistantTooltip(),
28692
+ icon: 'auto_awesome',
28693
+ variant: 'icon',
28694
+ placement: 'header',
28695
+ });
28696
+ }
28697
+ if (this.canOpenWidgetComponentSettings(widget.key)) {
28698
+ actions.push({
28699
+ id: 'component-settings',
28700
+ label: this.componentSettingsLabel(),
28701
+ tooltip: this.componentSettingsTooltip(),
28702
+ icon: 'tune',
28703
+ variant: 'icon',
28704
+ placement: 'header',
28705
+ });
28706
+ }
28707
+ if (this.canOpenWidgetShellSettings()) {
28708
+ actions.push({
28709
+ id: 'widget-settings',
28710
+ label: this.widgetSettingsLabel(),
28711
+ tooltip: this.widgetSettingsTooltip(),
28712
+ icon: 'settings',
28713
+ variant: 'icon',
28714
+ placement: 'header',
28715
+ });
27752
28716
  }
27753
- return !!widget.shell && widget.shell.kind !== 'none';
28717
+ actions.push({
28718
+ id: 'widget-remove',
28719
+ label: this.widgetRemoveLabel(),
28720
+ tooltip: this.widgetRemoveLabel(),
28721
+ icon: 'delete',
28722
+ variant: 'icon',
28723
+ placement: 'header',
28724
+ });
28725
+ return actions;
27754
28726
  }
27755
- canOpenWidgetShellSettings() {
27756
- return !!(this.shellEditorComponent || this.defaultShellEditor);
28727
+ widgetShellActionSignature(actions) {
28728
+ return actions
28729
+ .map((action) => [
28730
+ action.id,
28731
+ action.label || '',
28732
+ action.tooltip || '',
28733
+ action.icon || '',
28734
+ action.variant || '',
28735
+ action.placement || '',
28736
+ ].join(':'))
28737
+ .join('|');
28738
+ }
28739
+ isVisibleShellAction(action) {
28740
+ return action.visible == null || !!action.visible;
27757
28741
  }
27758
28742
  areStateValuesEqual(left, right) {
27759
28743
  if (left === right)
@@ -27791,6 +28775,10 @@ class DynamicWidgetPageComponent {
27791
28775
  this.widgetDiagnosticsChange.emit({ ...this.widgetDiagnostics });
27792
28776
  }
27793
28777
  onShellAction(fromKey, evt) {
28778
+ if (evt.id === 'widget-assistant') {
28779
+ this.requestWidgetAssistant(fromKey);
28780
+ return;
28781
+ }
27794
28782
  if (evt.id === 'component-settings') {
27795
28783
  this.openWidgetComponentSettings(fromKey);
27796
28784
  return;
@@ -27799,6 +28787,10 @@ class DynamicWidgetPageComponent {
27799
28787
  this.openWidgetShellSettings(fromKey);
27800
28788
  return;
27801
28789
  }
28790
+ if (evt.id === 'widget-remove') {
28791
+ void this.confirmAndRemoveWidget(fromKey);
28792
+ return;
28793
+ }
27802
28794
  if (this.handleSetInputCommand(fromKey, evt))
27803
28795
  return;
27804
28796
  const output = evt?.emit || (evt?.id ? `shell:${evt.id}` : undefined);
@@ -27968,6 +28960,124 @@ class DynamicWidgetPageComponent {
27968
28960
  : w);
27969
28961
  this.applyPageUpdate({ ...page, widgets }, persist);
27970
28962
  }
28963
+ async confirmAndRemoveWidget(widgetKey) {
28964
+ const page = this.ensurePageDefinition();
28965
+ const widget = page.widgets.find((item) => item.key === widgetKey);
28966
+ if (!widget) {
28967
+ return;
28968
+ }
28969
+ const title = widget.shell?.title || widget.definition?.id || widgetKey;
28970
+ const confirmation = await this.globalActions.execute('dialog.confirm', {
28971
+ title: this.t('controls.widgetRemoveConfirmTitle', 'Excluir widget?'),
28972
+ message: this.t('controls.widgetRemoveConfirmMessage', 'O widget "{{widget}}" será removido da página. Conexões e posições vinculadas também serão limpas.', { widget: title }),
28973
+ confirmLabel: this.t('controls.widgetRemoveConfirm', 'Excluir widget'),
28974
+ cancelLabel: this.t('controls.cancel', 'Cancelar'),
28975
+ type: 'danger',
28976
+ });
28977
+ if (!confirmation.success || confirmation.data !== true) {
28978
+ return;
28979
+ }
28980
+ this.applyPageUpdate(this.removeWidgetReferences(page, widgetKey), true);
28981
+ if (this.selectedWidgetKey === widgetKey) {
28982
+ this.selectedWidgetKey = null;
28983
+ this.widgetSelectionChange.emit(null);
28984
+ }
28985
+ }
28986
+ removeSelectedWidget() {
28987
+ if (!this.selectedWidgetKey) {
28988
+ return;
28989
+ }
28990
+ void this.confirmAndRemoveWidget(this.selectedWidgetKey);
28991
+ }
28992
+ removeSelectedCanvasWidget() {
28993
+ this.removeSelectedWidget();
28994
+ }
28995
+ removeWidgetReferences(page, widgetKey) {
28996
+ const source = this.cloneStateValues(page);
28997
+ const next = {
28998
+ ...source,
28999
+ widgets: (source.widgets || []).filter((widget) => widget.key !== widgetKey),
29000
+ };
29001
+ if (next.canvas?.items) {
29002
+ const items = { ...next.canvas.items };
29003
+ delete items[widgetKey];
29004
+ next.canvas = { ...next.canvas, items };
29005
+ }
29006
+ if (next.composition?.links) {
29007
+ next.composition = {
29008
+ ...next.composition,
29009
+ links: next.composition.links.filter((link) => !this.linkReferencesWidget(link, widgetKey)),
29010
+ };
29011
+ }
29012
+ if (next.grouping) {
29013
+ next.grouping = next.grouping.map((group) => {
29014
+ if (group.kind === 'tabs') {
29015
+ return {
29016
+ ...group,
29017
+ tabs: group.tabs.map((tab) => ({
29018
+ ...tab,
29019
+ widgetKeys: tab.widgetKeys.filter((key) => key !== widgetKey),
29020
+ })),
29021
+ };
29022
+ }
29023
+ return {
29024
+ ...group,
29025
+ widgetKeys: group.widgetKeys.filter((key) => key !== widgetKey),
29026
+ };
29027
+ });
29028
+ }
29029
+ if (next.slotAssignments?.[widgetKey] !== undefined) {
29030
+ const slotAssignments = { ...next.slotAssignments };
29031
+ delete slotAssignments[widgetKey];
29032
+ next.slotAssignments = slotAssignments;
29033
+ }
29034
+ if (next.deviceLayouts) {
29035
+ const deviceLayouts = {};
29036
+ for (const [device, variant] of Object.entries(next.deviceLayouts)) {
29037
+ const canvasItems = variant.canvas?.items
29038
+ ? { ...variant.canvas.items }
29039
+ : undefined;
29040
+ if (canvasItems) {
29041
+ delete canvasItems[widgetKey];
29042
+ }
29043
+ const widgetOverrides = variant.widgetOverrides
29044
+ ? { ...variant.widgetOverrides }
29045
+ : undefined;
29046
+ if (widgetOverrides) {
29047
+ delete widgetOverrides[widgetKey];
29048
+ }
29049
+ const groupingOverrides = variant.groupingOverrides?.map((override) => ({
29050
+ ...override,
29051
+ ...(override.widgetKeys
29052
+ ? { widgetKeys: override.widgetKeys.filter((key) => key !== widgetKey) }
29053
+ : {}),
29054
+ ...(override.tabs
29055
+ ? {
29056
+ tabs: override.tabs.map((tab) => ({
29057
+ ...tab,
29058
+ widgetKeys: tab.widgetKeys.filter((key) => key !== widgetKey),
29059
+ })),
29060
+ }
29061
+ : {}),
29062
+ }));
29063
+ deviceLayouts[device] = {
29064
+ ...variant,
29065
+ ...(variant.canvas ? { canvas: { ...variant.canvas, ...(canvasItems ? { items: canvasItems } : {}) } } : {}),
29066
+ ...(widgetOverrides ? { widgetOverrides } : {}),
29067
+ ...(groupingOverrides ? { groupingOverrides } : {}),
29068
+ };
29069
+ }
29070
+ next.deviceLayouts = deviceLayouts;
29071
+ }
29072
+ return next;
29073
+ }
29074
+ linkReferencesWidget(link, widgetKey) {
29075
+ return this.endpointReferencesWidget(link.from, widgetKey)
29076
+ || this.endpointReferencesWidget(link.to, widgetKey);
29077
+ }
29078
+ endpointReferencesWidget(endpoint, widgetKey) {
29079
+ return endpoint.kind === 'component-port' && endpoint.ref.widget === widgetKey;
29080
+ }
27971
29081
  openPageSettings() {
27972
29082
  if (!this.settingsPanel)
27973
29083
  return;
@@ -28372,11 +29482,12 @@ class DynamicWidgetPageComponent {
28372
29482
  }
28373
29483
  return widget?.definition?.inputs?.['enableCustomization'] === true;
28374
29484
  }
28375
- selectCanvasWidget(widgetKey) {
29485
+ selectWidget(widgetKey) {
28376
29486
  if (!this.enableCustomization)
28377
29487
  return;
28378
- if (this.selectedCanvasWidgetKey !== widgetKey) {
28379
- this.selectedCanvasWidgetKey = widgetKey;
29488
+ if (this.selectedWidgetKey !== widgetKey) {
29489
+ this.selectedWidgetKey = widgetKey;
29490
+ this.widgetSelectionChange.emit(widgetKey);
28380
29491
  }
28381
29492
  if (this.blockedCanvasWidgetKey &&
28382
29493
  this.blockedCanvasWidgetKey !== widgetKey) {
@@ -28384,7 +29495,13 @@ class DynamicWidgetPageComponent {
28384
29495
  }
28385
29496
  }
28386
29497
  isCanvasWidgetSelected(widgetKey) {
28387
- return this.selectedCanvasWidgetKey === widgetKey;
29498
+ return this.isWidgetSelected(widgetKey);
29499
+ }
29500
+ isWidgetSelected(widgetKey) {
29501
+ return this.selectedWidgetKey === widgetKey;
29502
+ }
29503
+ selectCanvasWidget(widgetKey) {
29504
+ this.selectWidget(widgetKey);
28388
29505
  }
28389
29506
  isCanvasWidgetBlocked(widgetKey) {
28390
29507
  return this.blockedCanvasWidgetKey === widgetKey;
@@ -29232,7 +30349,7 @@ class DynamicWidgetPageComponent {
29232
30349
  throw new Error('DynamicWidgetPageComponent no longer accepts `page.connections`. Use `composition.links` only.');
29233
30350
  }
29234
30351
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicWidgetPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29235
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: DynamicWidgetPageComponent, isStandalone: true, selector: "praxis-dynamic-page", inputs: { page: "page", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", showPageSettingsButton: "showPageSettingsButton", shellEditorComponent: "shellEditorComponent", pageEditorComponent: "pageEditorComponent", autoPersist: "autoPersist", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", widgetDiagnosticsChange: "widgetDiagnosticsChange" }, host: { listeners: { "window:resize": "onWindowResize()", "window:pointermove": "onCanvasPointerMove($event)", "window:pointerup": "onCanvasPointerUp($event)", "window:pointercancel": "onCanvasPointerCancel($event)" } }, providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], viewQueries: [{ propertyName: "pageCanvasHost", first: true, predicate: ["pageCanvasHost"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
30352
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: DynamicWidgetPageComponent, isStandalone: true, selector: "praxis-dynamic-page", inputs: { page: "page", context: "context", strictValidation: "strictValidation", enableCustomization: "enableCustomization", showPageSettingsButton: "showPageSettingsButton", shellEditorComponent: "shellEditorComponent", pageEditorComponent: "pageEditorComponent", autoPersist: "autoPersist", pageIdentity: "pageIdentity", componentInstanceId: "componentInstanceId", showWidgetAssistantButton: "showWidgetAssistantButton" }, outputs: { pageChange: "pageChange", widgetEvent: "widgetEvent", widgetSelectionChange: "widgetSelectionChange", widgetAssistantRequested: "widgetAssistantRequested", widgetDiagnosticsChange: "widgetDiagnosticsChange" }, host: { listeners: { "window:resize": "onWindowResize()", "window:pointermove": "onCanvasPointerMove($event)", "window:pointerup": "onCanvasPointerUp($event)", "window:pointercancel": "onCanvasPointerCancel($event)" } }, providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], viewQueries: [{ propertyName: "pageCanvasHost", first: true, predicate: ["pageCanvasHost"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
29236
30353
  <div class="pdx-page-wrapper" [class.editing]="enableCustomization">
29237
30354
  @if (enableCustomization && showPageSettingsButton) {
29238
30355
  <button
@@ -29260,8 +30377,11 @@ class DynamicWidgetPageComponent {
29260
30377
  <div
29261
30378
  class="pdx-widget pdx-widget--canvas"
29262
30379
  [class.pdx-widget--interactive]="enableCustomization"
30380
+ [class.pdx-widget--selected]="
30381
+ enableCustomization && isWidgetSelected(w.key)
30382
+ "
29263
30383
  [class.pdx-widget--canvas-selected]="
29264
- enableCustomization && isCanvasWidgetSelected(w.key)
30384
+ enableCustomization && isWidgetSelected(w.key)
29265
30385
  "
29266
30386
  [class.pdx-widget--canvas-blocked]="
29267
30387
  enableCustomization && isCanvasWidgetBlocked(w.key)
@@ -29270,8 +30390,8 @@ class DynamicWidgetPageComponent {
29270
30390
  [style.gridColumn]="widgetGridColumn(w)"
29271
30391
  [style.gridRow]="widgetGridRow(w)"
29272
30392
  [style.zIndex]="widgetZIndex(w)"
29273
- (click)="selectCanvasWidget(w.key)"
29274
- (focusin)="selectCanvasWidget(w.key)"
30393
+ (click)="selectWidget(w.key)"
30394
+ (focusin)="selectWidget(w.key)"
29275
30395
  >
29276
30396
  @if (enableCustomization) {
29277
30397
  @for (handle of canvasResizeHandles; track handle.id) {
@@ -29292,7 +30412,7 @@ class DynamicWidgetPageComponent {
29292
30412
  }
29293
30413
  }
29294
30414
  <praxis-widget-shell
29295
- [shell]="w.shell"
30415
+ [shell]="widgetShellForRender(w)"
29296
30416
  [context]="mergedContext"
29297
30417
  [dragSurfaceEnabled]="enableCustomization && isCanvasMode()"
29298
30418
  [dragSurfaceLabel]="dragWidgetLabel()"
@@ -29312,6 +30432,28 @@ class DynamicWidgetPageComponent {
29312
30432
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29313
30433
  ></ng-container>
29314
30434
  </praxis-widget-shell>
30435
+ @if (shouldRenderWidgetContextOverlay(w)) {
30436
+ <praxis-dynamic-widget-context-toolbar
30437
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30438
+ [contextLabel]="widgetContextLabel(w)"
30439
+ [contextTooltip]="widgetContextTooltip(w)"
30440
+ [showAssistant]="showWidgetAssistantButton"
30441
+ [assistantLabel]="widgetAssistantLabel()"
30442
+ [assistantTooltip]="widgetAssistantTooltip()"
30443
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30444
+ [componentSettingsLabel]="componentSettingsLabel()"
30445
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30446
+ [showShellSettings]="canOpenWidgetShellSettings()"
30447
+ [shellSettingsLabel]="widgetSettingsLabel()"
30448
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30449
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30450
+ [removeLabel]="widgetRemoveLabel()"
30451
+ (assistant)="requestWidgetAssistant(w.key)"
30452
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30453
+ (shellSettings)="openWidgetShellSettings(w.key)"
30454
+ (remove)="confirmAndRemoveWidget(w.key)"
30455
+ />
30456
+ }
29315
30457
  </div>
29316
30458
  }
29317
30459
  @if (canvasPreviewItem()) {
@@ -29370,11 +30512,17 @@ class DynamicWidgetPageComponent {
29370
30512
  @for (w of tab.widgets; track w.key) {
29371
30513
  <div
29372
30514
  class="pdx-widget"
30515
+ [class.pdx-widget--interactive]="enableCustomization"
30516
+ [class.pdx-widget--selected]="
30517
+ enableCustomization && isWidgetSelected(w.key)
30518
+ "
29373
30519
  [class]="w.renderClassName || w.className || ''"
29374
30520
  [style.gridColumn]="widgetGridColumn(w)"
30521
+ (click)="selectWidget(w.key)"
30522
+ (focusin)="selectWidget(w.key)"
29375
30523
  >
29376
30524
  <praxis-widget-shell
29377
- [shell]="w.shell"
30525
+ [shell]="widgetShellForRender(w)"
29378
30526
  [context]="mergedContext"
29379
30527
  (action)="onShellAction(w.key, $event)"
29380
30528
  >
@@ -29390,6 +30538,28 @@ class DynamicWidgetPageComponent {
29390
30538
  "
29391
30539
  ></ng-container>
29392
30540
  </praxis-widget-shell>
30541
+ @if (shouldRenderWidgetContextOverlay(w)) {
30542
+ <praxis-dynamic-widget-context-toolbar
30543
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30544
+ [contextLabel]="widgetContextLabel(w)"
30545
+ [contextTooltip]="widgetContextTooltip(w)"
30546
+ [showAssistant]="showWidgetAssistantButton"
30547
+ [assistantLabel]="widgetAssistantLabel()"
30548
+ [assistantTooltip]="widgetAssistantTooltip()"
30549
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30550
+ [componentSettingsLabel]="componentSettingsLabel()"
30551
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30552
+ [showShellSettings]="canOpenWidgetShellSettings()"
30553
+ [shellSettingsLabel]="widgetSettingsLabel()"
30554
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30555
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30556
+ [removeLabel]="widgetRemoveLabel()"
30557
+ (assistant)="requestWidgetAssistant(w.key)"
30558
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30559
+ (shellSettings)="openWidgetShellSettings(w.key)"
30560
+ (remove)="confirmAndRemoveWidget(w.key)"
30561
+ />
30562
+ }
29393
30563
  </div>
29394
30564
  }
29395
30565
  </div>
@@ -29406,11 +30576,17 @@ class DynamicWidgetPageComponent {
29406
30576
  @for (w of group.widgets; track w.key) {
29407
30577
  <div
29408
30578
  class="pdx-widget"
30579
+ [class.pdx-widget--interactive]="enableCustomization"
30580
+ [class.pdx-widget--selected]="
30581
+ enableCustomization && isWidgetSelected(w.key)
30582
+ "
29409
30583
  [class]="widgetClassName(w)"
29410
30584
  [style.gridColumn]="widgetGridColumn(w)"
30585
+ (click)="selectWidget(w.key)"
30586
+ (focusin)="selectWidget(w.key)"
29411
30587
  >
29412
30588
  <praxis-widget-shell
29413
- [shell]="w.shell"
30589
+ [shell]="widgetShellForRender(w)"
29414
30590
  [context]="mergedContext"
29415
30591
  (action)="onShellAction(w.key, $event)"
29416
30592
  >
@@ -29424,6 +30600,28 @@ class DynamicWidgetPageComponent {
29424
30600
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29425
30601
  ></ng-container>
29426
30602
  </praxis-widget-shell>
30603
+ @if (shouldRenderWidgetContextOverlay(w)) {
30604
+ <praxis-dynamic-widget-context-toolbar
30605
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30606
+ [contextLabel]="widgetContextLabel(w)"
30607
+ [contextTooltip]="widgetContextTooltip(w)"
30608
+ [showAssistant]="showWidgetAssistantButton"
30609
+ [assistantLabel]="widgetAssistantLabel()"
30610
+ [assistantTooltip]="widgetAssistantTooltip()"
30611
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30612
+ [componentSettingsLabel]="componentSettingsLabel()"
30613
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30614
+ [showShellSettings]="canOpenWidgetShellSettings()"
30615
+ [shellSettingsLabel]="widgetSettingsLabel()"
30616
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30617
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30618
+ [removeLabel]="widgetRemoveLabel()"
30619
+ (assistant)="requestWidgetAssistant(w.key)"
30620
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30621
+ (shellSettings)="openWidgetShellSettings(w.key)"
30622
+ (remove)="confirmAndRemoveWidget(w.key)"
30623
+ />
30624
+ }
29427
30625
  </div>
29428
30626
  }
29429
30627
  </div>
@@ -29434,11 +30632,17 @@ class DynamicWidgetPageComponent {
29434
30632
  @for (w of widgets(); track w.key) {
29435
30633
  <div
29436
30634
  class="pdx-widget"
30635
+ [class.pdx-widget--interactive]="enableCustomization"
30636
+ [class.pdx-widget--selected]="
30637
+ enableCustomization && isWidgetSelected(w.key)
30638
+ "
29437
30639
  [class]="widgetClassName(w)"
29438
30640
  [style.gridColumn]="widgetGridColumn(w)"
30641
+ (click)="selectWidget(w.key)"
30642
+ (focusin)="selectWidget(w.key)"
29439
30643
  >
29440
30644
  <praxis-widget-shell
29441
- [shell]="w.shell"
30645
+ [shell]="widgetShellForRender(w)"
29442
30646
  [context]="mergedContext"
29443
30647
  (action)="onShellAction(w.key, $event)"
29444
30648
  >
@@ -29452,6 +30656,28 @@ class DynamicWidgetPageComponent {
29452
30656
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29453
30657
  ></ng-container>
29454
30658
  </praxis-widget-shell>
30659
+ @if (shouldRenderWidgetContextOverlay(w)) {
30660
+ <praxis-dynamic-widget-context-toolbar
30661
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30662
+ [contextLabel]="widgetContextLabel(w)"
30663
+ [contextTooltip]="widgetContextTooltip(w)"
30664
+ [showAssistant]="showWidgetAssistantButton"
30665
+ [assistantLabel]="widgetAssistantLabel()"
30666
+ [assistantTooltip]="widgetAssistantTooltip()"
30667
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30668
+ [componentSettingsLabel]="componentSettingsLabel()"
30669
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30670
+ [showShellSettings]="canOpenWidgetShellSettings()"
30671
+ [shellSettingsLabel]="widgetSettingsLabel()"
30672
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30673
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30674
+ [removeLabel]="widgetRemoveLabel()"
30675
+ (assistant)="requestWidgetAssistant(w.key)"
30676
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30677
+ (shellSettings)="openWidgetShellSettings(w.key)"
30678
+ (remove)="confirmAndRemoveWidget(w.key)"
30679
+ />
30680
+ }
29455
30681
  </div>
29456
30682
  }
29457
30683
  }
@@ -29462,7 +30688,7 @@ class DynamicWidgetPageComponent {
29462
30688
  </div>
29463
30689
  }
29464
30690
  </div>
29465
- `, isInline: true, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-horizontal: linear-gradient( 90deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-vertical: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-sw: linear-gradient( 225deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-selected:before{border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
30691
+ `, isInline: true, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-horizontal: linear-gradient( 90deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-vertical: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-sw: linear-gradient( 225deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: DynamicWidgetContextToolbarComponent, selector: "praxis-dynamic-widget-context-toolbar", inputs: ["toolbarLabel", "contextLabel", "contextTooltip", "showAssistant", "assistantLabel", "assistantTooltip", "showComponentSettings", "componentSettingsLabel", "componentSettingsTooltip", "showShellSettings", "shellSettingsLabel", "shellSettingsTooltip", "moreActionsLabel", "removeLabel"], outputs: ["assistant", "componentSettings", "shellSettings", "remove"] }, { kind: "directive", type: DynamicWidgetLoaderDirective, selector: "[dynamicWidgetLoader]", inputs: ["dynamicWidgetLoader", "ownerWidgetKey", "context", "strictValidation", "autoWireOutputs"], outputs: ["widgetEvent", "widgetDiagnostic"], exportAs: ["dynamicWidgetLoader"] }, { kind: "component", type: WidgetShellComponent, selector: "praxis-widget-shell", inputs: ["shell", "context", "dragSurfaceEnabled", "dragSurfaceLabel"], outputs: ["action", "dragSurfacePointerDown", "dragSurfaceKeydown"] }] });
29466
30692
  }
29467
30693
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicWidgetPageComponent, decorators: [{
29468
30694
  type: Component,
@@ -29471,6 +30697,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29471
30697
  MatButtonModule,
29472
30698
  MatIconModule,
29473
30699
  MatTooltipModule,
30700
+ DynamicWidgetContextToolbarComponent,
29474
30701
  DynamicWidgetLoaderDirective,
29475
30702
  WidgetShellComponent,
29476
30703
  ], providers: [providePraxisI18nConfig(DYNAMIC_WIDGET_PAGE_I18N_CONFIG)], template: `
@@ -29501,8 +30728,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29501
30728
  <div
29502
30729
  class="pdx-widget pdx-widget--canvas"
29503
30730
  [class.pdx-widget--interactive]="enableCustomization"
30731
+ [class.pdx-widget--selected]="
30732
+ enableCustomization && isWidgetSelected(w.key)
30733
+ "
29504
30734
  [class.pdx-widget--canvas-selected]="
29505
- enableCustomization && isCanvasWidgetSelected(w.key)
30735
+ enableCustomization && isWidgetSelected(w.key)
29506
30736
  "
29507
30737
  [class.pdx-widget--canvas-blocked]="
29508
30738
  enableCustomization && isCanvasWidgetBlocked(w.key)
@@ -29511,8 +30741,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29511
30741
  [style.gridColumn]="widgetGridColumn(w)"
29512
30742
  [style.gridRow]="widgetGridRow(w)"
29513
30743
  [style.zIndex]="widgetZIndex(w)"
29514
- (click)="selectCanvasWidget(w.key)"
29515
- (focusin)="selectCanvasWidget(w.key)"
30744
+ (click)="selectWidget(w.key)"
30745
+ (focusin)="selectWidget(w.key)"
29516
30746
  >
29517
30747
  @if (enableCustomization) {
29518
30748
  @for (handle of canvasResizeHandles; track handle.id) {
@@ -29533,7 +30763,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29533
30763
  }
29534
30764
  }
29535
30765
  <praxis-widget-shell
29536
- [shell]="w.shell"
30766
+ [shell]="widgetShellForRender(w)"
29537
30767
  [context]="mergedContext"
29538
30768
  [dragSurfaceEnabled]="enableCustomization && isCanvasMode()"
29539
30769
  [dragSurfaceLabel]="dragWidgetLabel()"
@@ -29553,6 +30783,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29553
30783
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29554
30784
  ></ng-container>
29555
30785
  </praxis-widget-shell>
30786
+ @if (shouldRenderWidgetContextOverlay(w)) {
30787
+ <praxis-dynamic-widget-context-toolbar
30788
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30789
+ [contextLabel]="widgetContextLabel(w)"
30790
+ [contextTooltip]="widgetContextTooltip(w)"
30791
+ [showAssistant]="showWidgetAssistantButton"
30792
+ [assistantLabel]="widgetAssistantLabel()"
30793
+ [assistantTooltip]="widgetAssistantTooltip()"
30794
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30795
+ [componentSettingsLabel]="componentSettingsLabel()"
30796
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30797
+ [showShellSettings]="canOpenWidgetShellSettings()"
30798
+ [shellSettingsLabel]="widgetSettingsLabel()"
30799
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30800
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30801
+ [removeLabel]="widgetRemoveLabel()"
30802
+ (assistant)="requestWidgetAssistant(w.key)"
30803
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30804
+ (shellSettings)="openWidgetShellSettings(w.key)"
30805
+ (remove)="confirmAndRemoveWidget(w.key)"
30806
+ />
30807
+ }
29556
30808
  </div>
29557
30809
  }
29558
30810
  @if (canvasPreviewItem()) {
@@ -29611,11 +30863,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29611
30863
  @for (w of tab.widgets; track w.key) {
29612
30864
  <div
29613
30865
  class="pdx-widget"
30866
+ [class.pdx-widget--interactive]="enableCustomization"
30867
+ [class.pdx-widget--selected]="
30868
+ enableCustomization && isWidgetSelected(w.key)
30869
+ "
29614
30870
  [class]="w.renderClassName || w.className || ''"
29615
30871
  [style.gridColumn]="widgetGridColumn(w)"
30872
+ (click)="selectWidget(w.key)"
30873
+ (focusin)="selectWidget(w.key)"
29616
30874
  >
29617
30875
  <praxis-widget-shell
29618
- [shell]="w.shell"
30876
+ [shell]="widgetShellForRender(w)"
29619
30877
  [context]="mergedContext"
29620
30878
  (action)="onShellAction(w.key, $event)"
29621
30879
  >
@@ -29631,6 +30889,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29631
30889
  "
29632
30890
  ></ng-container>
29633
30891
  </praxis-widget-shell>
30892
+ @if (shouldRenderWidgetContextOverlay(w)) {
30893
+ <praxis-dynamic-widget-context-toolbar
30894
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30895
+ [contextLabel]="widgetContextLabel(w)"
30896
+ [contextTooltip]="widgetContextTooltip(w)"
30897
+ [showAssistant]="showWidgetAssistantButton"
30898
+ [assistantLabel]="widgetAssistantLabel()"
30899
+ [assistantTooltip]="widgetAssistantTooltip()"
30900
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30901
+ [componentSettingsLabel]="componentSettingsLabel()"
30902
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30903
+ [showShellSettings]="canOpenWidgetShellSettings()"
30904
+ [shellSettingsLabel]="widgetSettingsLabel()"
30905
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30906
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30907
+ [removeLabel]="widgetRemoveLabel()"
30908
+ (assistant)="requestWidgetAssistant(w.key)"
30909
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30910
+ (shellSettings)="openWidgetShellSettings(w.key)"
30911
+ (remove)="confirmAndRemoveWidget(w.key)"
30912
+ />
30913
+ }
29634
30914
  </div>
29635
30915
  }
29636
30916
  </div>
@@ -29647,11 +30927,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29647
30927
  @for (w of group.widgets; track w.key) {
29648
30928
  <div
29649
30929
  class="pdx-widget"
30930
+ [class.pdx-widget--interactive]="enableCustomization"
30931
+ [class.pdx-widget--selected]="
30932
+ enableCustomization && isWidgetSelected(w.key)
30933
+ "
29650
30934
  [class]="widgetClassName(w)"
29651
30935
  [style.gridColumn]="widgetGridColumn(w)"
30936
+ (click)="selectWidget(w.key)"
30937
+ (focusin)="selectWidget(w.key)"
29652
30938
  >
29653
30939
  <praxis-widget-shell
29654
- [shell]="w.shell"
30940
+ [shell]="widgetShellForRender(w)"
29655
30941
  [context]="mergedContext"
29656
30942
  (action)="onShellAction(w.key, $event)"
29657
30943
  >
@@ -29665,6 +30951,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29665
30951
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29666
30952
  ></ng-container>
29667
30953
  </praxis-widget-shell>
30954
+ @if (shouldRenderWidgetContextOverlay(w)) {
30955
+ <praxis-dynamic-widget-context-toolbar
30956
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
30957
+ [contextLabel]="widgetContextLabel(w)"
30958
+ [contextTooltip]="widgetContextTooltip(w)"
30959
+ [showAssistant]="showWidgetAssistantButton"
30960
+ [assistantLabel]="widgetAssistantLabel()"
30961
+ [assistantTooltip]="widgetAssistantTooltip()"
30962
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
30963
+ [componentSettingsLabel]="componentSettingsLabel()"
30964
+ [componentSettingsTooltip]="componentSettingsTooltip()"
30965
+ [showShellSettings]="canOpenWidgetShellSettings()"
30966
+ [shellSettingsLabel]="widgetSettingsLabel()"
30967
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
30968
+ [moreActionsLabel]="moreWidgetActionsLabel()"
30969
+ [removeLabel]="widgetRemoveLabel()"
30970
+ (assistant)="requestWidgetAssistant(w.key)"
30971
+ (componentSettings)="openWidgetComponentSettings(w.key)"
30972
+ (shellSettings)="openWidgetShellSettings(w.key)"
30973
+ (remove)="confirmAndRemoveWidget(w.key)"
30974
+ />
30975
+ }
29668
30976
  </div>
29669
30977
  }
29670
30978
  </div>
@@ -29675,11 +30983,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29675
30983
  @for (w of widgets(); track w.key) {
29676
30984
  <div
29677
30985
  class="pdx-widget"
30986
+ [class.pdx-widget--interactive]="enableCustomization"
30987
+ [class.pdx-widget--selected]="
30988
+ enableCustomization && isWidgetSelected(w.key)
30989
+ "
29678
30990
  [class]="widgetClassName(w)"
29679
30991
  [style.gridColumn]="widgetGridColumn(w)"
30992
+ (click)="selectWidget(w.key)"
30993
+ (focusin)="selectWidget(w.key)"
29680
30994
  >
29681
30995
  <praxis-widget-shell
29682
- [shell]="w.shell"
30996
+ [shell]="widgetShellForRender(w)"
29683
30997
  [context]="mergedContext"
29684
30998
  (action)="onShellAction(w.key, $event)"
29685
30999
  >
@@ -29693,6 +31007,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29693
31007
  (widgetDiagnostic)="onWidgetDiagnostic(w.key, $event)"
29694
31008
  ></ng-container>
29695
31009
  </praxis-widget-shell>
31010
+ @if (shouldRenderWidgetContextOverlay(w)) {
31011
+ <praxis-dynamic-widget-context-toolbar
31012
+ [toolbarLabel]="widgetContextToolbarLabel(w.key)"
31013
+ [contextLabel]="widgetContextLabel(w)"
31014
+ [contextTooltip]="widgetContextTooltip(w)"
31015
+ [showAssistant]="showWidgetAssistantButton"
31016
+ [assistantLabel]="widgetAssistantLabel()"
31017
+ [assistantTooltip]="widgetAssistantTooltip()"
31018
+ [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
31019
+ [componentSettingsLabel]="componentSettingsLabel()"
31020
+ [componentSettingsTooltip]="componentSettingsTooltip()"
31021
+ [showShellSettings]="canOpenWidgetShellSettings()"
31022
+ [shellSettingsLabel]="widgetSettingsLabel()"
31023
+ [shellSettingsTooltip]="widgetSettingsTooltip()"
31024
+ [moreActionsLabel]="moreWidgetActionsLabel()"
31025
+ [removeLabel]="widgetRemoveLabel()"
31026
+ (assistant)="requestWidgetAssistant(w.key)"
31027
+ (componentSettings)="openWidgetComponentSettings(w.key)"
31028
+ (shellSettings)="openWidgetShellSettings(w.key)"
31029
+ (remove)="confirmAndRemoveWidget(w.key)"
31030
+ />
31031
+ }
29696
31032
  </div>
29697
31033
  }
29698
31034
  }
@@ -29703,7 +31039,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29703
31039
  </div>
29704
31040
  }
29705
31041
  </div>
29706
- `, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-horizontal: linear-gradient( 90deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-vertical: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-sw: linear-gradient( 225deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-selected:before{border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
31042
+ `, styles: [".pdx-page-wrapper{position:relative;display:block}.pdx-page{display:grid;gap:12px;grid-template-columns:minmax(0,1fr)}.pdx-page--canvas{align-items:start;grid-auto-flow:dense}.pdx-page-settings{position:sticky;top:8px;z-index:2;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);color:inherit;border-radius:12px;width:36px;height:36px;margin-bottom:6px}.pdx-widget{position:relative;background:var(--pfx-surface, transparent);border-radius:6px;min-width:0;min-height:0}.pdx-widget--interactive{cursor:pointer}.pdx-widget--selected:before{content:\"\";position:absolute;inset:0;border:1px dashed color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent);border-radius:14px;pointer-events:none;z-index:1;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent),0 8px 20px color-mix(in srgb,var(--md-sys-color-primary) 6%,transparent)}.pdx-widget--canvas{align-self:stretch;--pdx-resize-gradient-horizontal: linear-gradient( 90deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-vertical: linear-gradient( 180deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-se: linear-gradient( 135deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-resize-gradient-diagonal-sw: linear-gradient( 225deg, color-mix(in srgb, var(--md-sys-color-primary) 94%, white 6%), color-mix(in srgb, var(--md-sys-color-tertiary) 90%, white 10%), color-mix(in srgb, var(--md-sys-color-secondary) 88%, white 12%) );--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-widget--canvas:after{content:\"\";position:absolute;inset:0;padding:2px;border-radius:14px;background:var(--pdx-active-resize-gradient);opacity:0;pointer-events:none;transition:opacity .14s ease,filter .14s ease;filter:saturate(1.02) drop-shadow(0 0 5px color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent));-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}.pdx-widget--canvas-selected:before,.pdx-widget--canvas-blocked:before{content:\"\";position:absolute;inset:0;border-radius:14px;pointer-events:none;z-index:1;transition:opacity .14s ease,box-shadow .14s ease,border-color .14s ease}.pdx-widget--canvas-blocked:before{border:1px solid color-mix(in srgb,var(--md-sys-color-error) 74%,transparent);box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 20%,transparent),0 10px 24px color-mix(in srgb,var(--md-sys-color-error) 12%,transparent)}.pdx-widget--canvas:has(.pdx-canvas-resize:hover):after,.pdx-widget--canvas:has(.pdx-canvas-resize:focus-visible):after{opacity:.82}.pdx-widget--canvas:has(.pdx-canvas-resize--north:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-horizontal)}.pdx-widget--canvas:has(.pdx-canvas-resize--east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-vertical)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-east:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-west:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-sw)}.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--north-west:focus-visible),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:hover),.pdx-widget--canvas:has(.pdx-canvas-resize--south-east:focus-visible){--pdx-active-resize-gradient: var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize{position:absolute;z-index:7;border:0;padding:0;margin:0;background:transparent;touch-action:none;cursor:pointer;opacity:0;pointer-events:none;transform:scale(.94);transition:opacity .14s ease,transform .14s ease,filter .14s ease;filter:saturate(.9)}.pdx-widget--canvas:hover .pdx-canvas-resize,.pdx-widget--canvas:focus-within .pdx-canvas-resize,.pdx-widget--canvas-selected .pdx-canvas-resize{opacity:.88;pointer-events:auto;transform:scale(1);filter:saturate(1)}.pdx-canvas-resize-grip{display:block;width:9px;height:9px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant) 58%);background:color-mix(in srgb,var(--md-sys-color-surface) 92%,var(--md-sys-color-primary) 8%);box-shadow:0 1px 4px color-mix(in srgb,var(--md-sys-color-shadow) 10%,transparent);transition:transform .14s ease,border-color .14s ease,background .14s ease,box-shadow .14s ease}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant) 42%);background:color-mix(in srgb,var(--md-sys-color-surface) 84%,var(--md-sys-color-primary) 16%);box-shadow:0 2px 7px color-mix(in srgb,var(--md-sys-color-primary) 14%,transparent);transform:scale(1.04)}.pdx-canvas-resize--north,.pdx-canvas-resize--south{left:50%;width:40px;height:18px;margin-left:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north{top:-8px;cursor:ns-resize}.pdx-canvas-resize--south{bottom:-8px;cursor:ns-resize}.pdx-canvas-resize--east,.pdx-canvas-resize--west{top:50%;width:18px;height:40px;margin-top:-20px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--east{right:-8px;cursor:ew-resize}.pdx-canvas-resize--west{left:-8px;cursor:ew-resize}.pdx-canvas-resize--north-east,.pdx-canvas-resize--north-west,.pdx-canvas-resize--south-east,.pdx-canvas-resize--south-west{width:18px;height:18px;display:flex;align-items:center;justify-content:center}.pdx-canvas-resize--north-east{top:-8px;right:-8px;cursor:nesw-resize}.pdx-canvas-resize--north-west{top:-8px;left:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-east{bottom:-8px;right:-8px;cursor:nwse-resize}.pdx-canvas-resize--south-west{bottom:-8px;left:-8px;cursor:nesw-resize}.pdx-canvas-snap-preview{position:relative;align-self:stretch;border-radius:12px;pointer-events:none;z-index:0;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent),color-mix(in srgb,var(--md-sys-color-tertiary) 12%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 42%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 55%,transparent);animation:pdx-snap-preview-pulse .48s ease-out infinite alternate}.pdx-canvas-snap-preview:before,.pdx-canvas-snap-preview:after{content:\"\";position:absolute;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary) 82%,var(--md-sys-color-tertiary) 18%);opacity:.72}.pdx-canvas-snap-preview:before{inset:0 auto 0 0;width:3px}.pdx-canvas-snap-preview:after{inset:0 0 auto;height:3px}.pdx-canvas-snap-preview--invalid{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-error) 18%,transparent),color-mix(in srgb,var(--md-sys-color-error-container) 22%,transparent));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 58%,transparent),inset 0 0 0 2px color-mix(in srgb,var(--md-sys-color-surface) 40%,transparent)}.pdx-canvas-snap-preview--invalid:before,.pdx-canvas-snap-preview--invalid:after{background:color-mix(in srgb,var(--md-sys-color-error) 86%,var(--md-sys-color-error-container) 14%)}.pdx-canvas-resize:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{border-color:transparent;box-shadow:0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 20%,transparent),var(--mat-elevation-level3)}.pdx-canvas-resize--north:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-horizontal)}.pdx-canvas-resize--east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-vertical)}.pdx-canvas-resize--north-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-east:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-west:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-sw)}.pdx-canvas-resize--north-west:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--north-west:focus-visible .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:hover .pdx-canvas-resize-grip,.pdx-canvas-resize--south-east:focus-visible .pdx-canvas-resize-grip{background:var(--pdx-resize-gradient-diagonal-se)}.pdx-canvas-resize:hover .pdx-canvas-resize-grip,.pdx-canvas-resize:focus-visible .pdx-canvas-resize-grip{transform:scale(1.08)}@keyframes pdx-snap-preview-pulse{0%{opacity:.72;transform:scale(.996)}to{opacity:1;transform:scale(1)}}.pdx-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pdx-group{display:grid;gap:12px;grid-column:1 / -1;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container-low) 76%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent)}.pdx-group--hero{padding:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 42%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low) 86%,transparent))}.pdx-group--rail{align-self:start}.pdx-group-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.pdx-group-title{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface)}.pdx-group-content{display:grid;gap:12px}.pdx-group-content--stack{grid-template-columns:minmax(0,1fr)}.pdx-group-content--row{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}.pdx-group-content--grid{grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.pdx-group-tabs{display:grid;gap:12px}.pdx-tabs-header{display:flex;flex-wrap:wrap;gap:8px}.pdx-tab-chip{appearance:none;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-lowest);color:var(--md-sys-color-on-surface);border-radius:999px;padding:8px 12px;font:inherit;cursor:pointer}.pdx-tab-chip.active{border-color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 78%,transparent);color:var(--md-sys-color-on-primary-container)}.pdx-page-wrapper.editing .pdx-widget-settings{opacity:1}\n"] }]
29707
31043
  }], ctorParameters: () => [], propDecorators: { pageCanvasHost: [{
29708
31044
  type: ViewChild,
29709
31045
  args: ['pageCanvasHost']
@@ -29727,10 +31063,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
29727
31063
  type: Input
29728
31064
  }], componentInstanceId: [{
29729
31065
  type: Input
31066
+ }], showWidgetAssistantButton: [{
31067
+ type: Input
29730
31068
  }], pageChange: [{
29731
31069
  type: Output
29732
31070
  }], widgetEvent: [{
29733
31071
  type: Output
31072
+ }], widgetSelectionChange: [{
31073
+ type: Output
31074
+ }], widgetAssistantRequested: [{
31075
+ type: Output
29734
31076
  }], widgetDiagnosticsChange: [{
29735
31077
  type: Output
29736
31078
  }], onWindowResize: [{
@@ -29912,7 +31254,7 @@ class EmptyStateCardComponent {
29912
31254
  </div>
29913
31255
  </mat-card-content>
29914
31256
  </mat-card>
29915
- `, isInline: true, styles: [".empty-card{display:block;margin:12px;border-color:var(--md-sys-color-outline-variant);--empty-icon-color: var(--md-sys-color-on-surface-variant)}.empty-card.empty-inline{margin:8px 0}.content{display:flex;align-items:center;gap:12px}.icon{font-size:32px;width:32px;height:32px;color:var(--empty-icon-color)}.texts{display:grid;gap:4px}.title{margin:0;font-size:16px;font-weight:600;color:var(--md-sys-color-on-surface)}.desc{margin:0;color:var(--md-sys-color-on-surface-variant)}.actions{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}.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: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$2.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: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
31257
+ `, isInline: true, styles: [".empty-card{display:block;margin:12px;border-color:var(--md-sys-color-outline-variant);--empty-icon-color: var(--md-sys-color-on-surface-variant)}.empty-card.empty-inline{margin:8px 0}.content{display:flex;align-items:center;gap:12px}.icon{font-size:32px;width:32px;height:32px;color:var(--empty-icon-color)}.texts{display:grid;gap:4px}.title{margin:0;font-size:16px;font-weight:600;color:var(--md-sys-color-on-surface)}.desc{margin:0;color:var(--md-sys-color-on-surface-variant)}.actions{display:flex;gap:8px;margin-top:12px;flex-wrap:wrap}.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: CommonModule }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
29916
31258
  }
29917
31259
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: EmptyStateCardComponent, decorators: [{
29918
31260
  type: Component,
@@ -30017,7 +31359,7 @@ class ResourceQuickConnectComponent {
30017
31359
  Rota normalizada: {{ normalizedPath() }}
30018
31360
  </small>
30019
31361
  </div>
30020
- `, 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: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
31362
+ `, 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: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
30021
31363
  }
30022
31364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ResourceQuickConnectComponent, decorators: [{
30023
31365
  type: Component,
@@ -30245,7 +31587,7 @@ class PraxisIconPickerComponent {
30245
31587
  <span class="pip-typed" *ngIf="query.trim()">{{ previewValue() }}</span>
30246
31588
  </div>
30247
31589
  </div>
30248
- `, 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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: i3$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"] }] });
31590
+ `, 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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.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: i2$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.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i8.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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
30249
31591
  }
30250
31592
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisIconPickerComponent, decorators: [{
30251
31593
  type: Component,
@@ -30589,7 +31931,7 @@ class SchemaViewerComponent {
30589
31931
  </mat-tab-group>
30590
31932
  </mat-card-content>
30591
31933
  </mat-card>
30592
- `, isInline: true, styles: [".schema-viewer{display:block;border-color:var(--md-sys-color-outline-variant)}.header{display:flex;align-items:center;justify-content:space-between;gap:8px}.title{display:flex;align-items:center;gap:8px}.title h3{margin:0;font-weight:600;color:var(--md-sys-color-on-surface)}.notes{margin-top:6px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.copy-status{margin-top:6px;font-size:12px;color:var(--md-sys-color-primary)}.section{padding:12px}.section-actions{display:flex;justify-content:flex-end;margin-bottom:8px}.sub{font-weight:600;margin:12px 0 4px;color:var(--md-sys-color-on-surface)}.pretty{background:var(--md-sys-color-surface-container);padding:10px;border-radius:8px;overflow:auto;border:1px solid var(--md-sys-color-outline-variant)}.kv{display:grid;grid-template-columns:140px 1fr;align-items:baseline;gap:8px;margin:2px 0}.kv>span{color:var(--md-sys-color-on-surface-variant)}.kv>code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.muted{color:var(--md-sys-color-on-surface-variant)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i2$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i2$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$2.MatCardHeader, selector: "mat-card-header" }, { 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: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
31934
+ `, isInline: true, styles: [".schema-viewer{display:block;border-color:var(--md-sys-color-outline-variant)}.header{display:flex;align-items:center;justify-content:space-between;gap:8px}.title{display:flex;align-items:center;gap:8px}.title h3{margin:0;font-weight:600;color:var(--md-sys-color-on-surface)}.notes{margin-top:6px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.copy-status{margin-top:6px;font-size:12px;color:var(--md-sys-color-primary)}.section{padding:12px}.section-actions{display:flex;justify-content:flex-end;margin-bottom:8px}.sub{font-weight:600;margin:12px 0 4px;color:var(--md-sys-color-on-surface)}.pretty{background:var(--md-sys-color-surface-container);padding:10px;border-radius:8px;overflow:auto;border:1px solid var(--md-sys-color-outline-variant)}.kv{display:grid;grid-template-columns:140px 1fr;align-items:baseline;gap:8px;margin:2px 0}.kv>span{color:var(--md-sys-color-on-surface-variant)}.kv>code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.muted{color:var(--md-sys-color-on-surface-variant)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i2$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i2$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3$1.MatCardHeader, selector: "mat-card-header" }, { 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: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
30593
31935
  }
30594
31936
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SchemaViewerComponent, decorators: [{
30595
31937
  type: Component,
@@ -30776,11 +32118,10 @@ function reconcileFormConfig(layout, serverDefs) {
30776
32118
  for (const [name, serverField] of serverByName) {
30777
32119
  const localField = localByName.get(name);
30778
32120
  if (localField) {
30779
- const base = buildBaseFormField(serverField);
30780
- merged.push(applyLocalCustomizations$1(base, localField));
32121
+ merged.push(applyLocalCustomizations$1(serverField, localField));
30781
32122
  }
30782
32123
  else {
30783
- merged.push(buildBaseFormField(serverField));
32124
+ merged.push(serverField);
30784
32125
  }
30785
32126
  }
30786
32127
  // Orphans: preserve explicit local fields; hide legacy schema fields that no
@@ -31212,4 +32553,4 @@ function provideHookWhitelist(allowed) {
31212
32553
  * Generated bundle index. Do not edit.
31213
32554
  */
31214
32555
 
31215
- 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, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, 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, 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_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, 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_RICH_TEXT_BLOCK_METADATA, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRichTextBlockComponent, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, 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, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldConstraints, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizeResourceAvailabilityReasonCode, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, removeDiacritics, reportTelemetryHookFactory, requiredCheckedValidator, resolveBuiltinPresets, resolveControlTypeAlias, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToJson, slugify, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withMessage, withPraxisHttpLoading };
32556
+ 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, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, 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, 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_COLLECTION_EXPORT_HTTP_OPTIONS, PRAXIS_COLLECTION_EXPORT_PROVIDER, PRAXIS_CORPORATE_SENSITIVE_KEYS, PRAXIS_DEFAULT_EXPORT_SECURITY_POLICY, PRAXIS_DEFAULT_OBSERVABILITY_ALERT_RULES, PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA, 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_RICH_TEXT_BLOCK_METADATA, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRichTextBlockComponent, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, 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, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisRuntimeGlobalActionEffect, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldConstraints, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizeResourceAvailabilityReasonCode, normalizeStart, normalizeUnknownError, normalizeWidgetEventPath, notifySuccessHook, parseJsonResponseOrEmpty, praxisLoadingInterceptorFn, prefillFromContextHook, provideDefaultFormHooks, provideFieldSelectorRegistryBase, provideFieldSelectorRegistryOverride, provideFieldSelectorRegistryRuntime, provideFormHookPresets, provideFormHooks, provideGlobalActionCatalog, provideGlobalActionHandler, provideGlobalConfig, provideGlobalConfigReady, provideGlobalConfigSeed, provideGlobalConfigTenant, provideHookResolvers, provideHookWhitelist, provideOverlayDecisionMatrix, providePraxisAnalyticsGlobalActions, providePraxisCollectionExportProvider, providePraxisDynamicPageMetadata, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, removeDiacritics, reportTelemetryHookFactory, requiredCheckedValidator, resolveBuiltinPresets, resolveControlTypeAlias, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToJson, slugify, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withMessage, withPraxisHttpLoading };