@praxisui/core 9.0.0-beta.3 → 9.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, InjectionToken, Injectable, inject, Inject, Optional, makeEnvironmentProviders, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, APP_INITIALIZER, ErrorHandler, EventEmitter, Output, Input, ChangeDetectionStrategy, Directive, SecurityContext, ViewContainerRef, SimpleChange, ContentChild, HostBinding, HostListener, ViewChildren, ViewChild } from '@angular/core';
2
+ import { Component, InjectionToken, Injectable, inject, Inject, Optional, makeEnvironmentProviders, APP_INITIALIZER, signal, computed, DestroyRef, ENVIRONMENT_INITIALIZER, ErrorHandler, EventEmitter, Output, Input, ChangeDetectionStrategy, Directive, SecurityContext, ViewContainerRef, SimpleChange, ContentChild, HostBinding, HostListener, ViewChildren, ViewChild } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
4
  import { HttpHeaders, HttpClient, HttpParams, HttpResponse, HttpContextToken, HTTP_INTERCEPTORS, withInterceptors } from '@angular/common/http';
5
5
  import { of, defer, throwError, from, EMPTY, BehaviorSubject, firstValueFrom, Subject, map as map$1, switchMap as switchMap$1 } from 'rxjs';
@@ -202,9 +202,12 @@ function collectEntityLookupIds(value) {
202
202
  }
203
203
  function buildEntityLookupEntityRef(value, entityType) {
204
204
  const id = extractEntityLookupId(value);
205
- if (id === null || id === undefined || id === '') {
206
- return id;
207
- }
205
+ if (id === null)
206
+ return null;
207
+ if (id === undefined)
208
+ return undefined;
209
+ if (id === '')
210
+ return '';
208
211
  const explicitType = typeof value === 'object' &&
209
212
  value !== null &&
210
213
  !Array.isArray(value) &&
@@ -797,6 +800,82 @@ function resolveControlTypeAlias(value, fallback = FieldControlType.INPUT) {
797
800
  return raw;
798
801
  }
799
802
 
803
+ function normalizeFieldAccessMetadata(value) {
804
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
805
+ return undefined;
806
+ }
807
+ const source = value;
808
+ const visibleForAuthorities = normalizeAuthorityList(source['visibleForAuthorities']);
809
+ const editableForAuthorities = normalizeAuthorityList(source['editableForAuthorities']);
810
+ const reason = typeof source['reason'] === 'string' && source['reason'].trim()
811
+ ? source['reason'].trim()
812
+ : undefined;
813
+ if (!visibleForAuthorities && !editableForAuthorities) {
814
+ return undefined;
815
+ }
816
+ return {
817
+ ...(visibleForAuthorities ? { visibleForAuthorities } : {}),
818
+ ...(editableForAuthorities ? { editableForAuthorities } : {}),
819
+ ...(reason ? { reason } : {}),
820
+ };
821
+ }
822
+ function evaluateFieldAccess(fieldOrAccess, context = {}) {
823
+ const fieldAccess = normalizeFieldAccessMetadata(isFieldAccessMetadata(fieldOrAccess)
824
+ ? fieldOrAccess
825
+ : fieldOrAccess?.fieldAccess);
826
+ if (!fieldAccess) {
827
+ return { evaluated: false, visible: true, editable: true };
828
+ }
829
+ const authorities = normalizeAuthoritySet(context.authorities);
830
+ if (!authorities) {
831
+ return {
832
+ evaluated: false,
833
+ visible: true,
834
+ editable: true,
835
+ ...(fieldAccess.reason ? { reason: fieldAccess.reason } : {}),
836
+ };
837
+ }
838
+ const editableAllowed = matchesAuthority(fieldAccess.editableForAuthorities, authorities);
839
+ const visibleAllowed = matchesAuthority(fieldAccess.visibleForAuthorities, authorities) ||
840
+ editableAllowed;
841
+ return {
842
+ evaluated: true,
843
+ visible: visibleAllowed,
844
+ editable: editableAllowed || !fieldAccess.editableForAuthorities,
845
+ ...(fieldAccess.reason ? { reason: fieldAccess.reason } : {}),
846
+ };
847
+ }
848
+ function isFieldAccessMetadata(value) {
849
+ return !!value && ('visibleForAuthorities' in value ||
850
+ 'editableForAuthorities' in value ||
851
+ 'reason' in value);
852
+ }
853
+ function normalizeAuthorityList(value) {
854
+ if (!Array.isArray(value)) {
855
+ return undefined;
856
+ }
857
+ const normalized = Array.from(new Set(value
858
+ .filter((item) => typeof item === 'string')
859
+ .map((item) => item.trim())
860
+ .filter(Boolean)));
861
+ return normalized.length ? normalized : undefined;
862
+ }
863
+ function normalizeAuthoritySet(authorities) {
864
+ if (!Array.isArray(authorities)) {
865
+ return null;
866
+ }
867
+ return new Set(authorities
868
+ .filter((item) => typeof item === 'string')
869
+ .map((item) => item.trim())
870
+ .filter(Boolean));
871
+ }
872
+ function matchesAuthority(required, actual) {
873
+ if (!required || required.length === 0) {
874
+ return true;
875
+ }
876
+ return required.some((authority) => actual.has(authority));
877
+ }
878
+
800
879
  const VALUE_PRESENTATION_TYPES = new Set([
801
880
  'string',
802
881
  'number',
@@ -1967,6 +2046,10 @@ class SchemaNormalizerService {
1967
2046
  if (ui.editable !== undefined) {
1968
2047
  field.editable = this.parseBoolean(ui.editable);
1969
2048
  }
2049
+ const fieldAccess = normalizeFieldAccessMetadata(ui.fieldAccess);
2050
+ if (fieldAccess) {
2051
+ field.fieldAccess = fieldAccess;
2052
+ }
1970
2053
  if (ui.inlineEditing !== undefined) {
1971
2054
  field.inlineEditing = this.parseBoolean(ui.inlineEditing);
1972
2055
  }
@@ -2020,6 +2103,9 @@ class SchemaNormalizerService {
2020
2103
  if (ui.helpText !== undefined) {
2021
2104
  field.helpText = String(ui.helpText);
2022
2105
  }
2106
+ if (ui.tooltip !== undefined) {
2107
+ field.tooltip = String(ui.tooltip);
2108
+ }
2023
2109
  if (ui.hint !== undefined) {
2024
2110
  field.hint = ui.hint;
2025
2111
  }
@@ -5533,15 +5619,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5533
5619
  }], ctorParameters: () => [] });
5534
5620
 
5535
5621
  function buildBaseColumnFromDef(def) {
5622
+ const type = resolveColumnTypeFromFieldDefinition(def);
5623
+ const format = type === 'string' ? resolveTextMaskFormatFromFieldDefinition(def) : undefined;
5536
5624
  return {
5537
5625
  field: def.name,
5538
5626
  header: def.label || def.name,
5539
- type: inferType(def),
5627
+ type,
5540
5628
  visible: def.tableHidden === true ? false : true,
5541
5629
  sortable: def.sortable !== false,
5542
5630
  filterable: def.filterable === true,
5543
5631
  resizable: true,
5544
5632
  order: typeof def.order === 'number' ? def.order : undefined,
5633
+ ...(format ? { format } : {}),
5545
5634
  };
5546
5635
  }
5547
5636
  function applyLocalCustomizations$2(baseCol, localCol) {
@@ -5575,9 +5664,10 @@ function applyLocalCustomizations$2(baseCol, localCol) {
5575
5664
  result.renderer = localCol.renderer ?? baseCol.renderer;
5576
5665
  }
5577
5666
  else {
5578
- // Keep no format/renderer to avoid conflicts with server type
5579
- result.format = undefined;
5580
- result.valueMapping = undefined;
5667
+ // Drop local presentation that may be incompatible with the new server type,
5668
+ // but keep canonical server presentation for the resolved type.
5669
+ result.format = baseCol.format;
5670
+ result.valueMapping = baseCol.valueMapping;
5581
5671
  result.renderer = undefined;
5582
5672
  }
5583
5673
  return result;
@@ -5603,15 +5693,121 @@ function reconcileTableConfig(layout, serverDefs) {
5603
5693
  };
5604
5694
  return next;
5605
5695
  }
5606
- function inferType(def) {
5607
- const t = (def.type || '').toLowerCase();
5608
- if (t.includes('date'))
5696
+ function resolveColumnTypeFromFieldDefinition(def, fallback) {
5697
+ const semanticType = resolveSemanticColumnTypeFromFieldDefinition(def);
5698
+ if (resolveTextMaskFormatFromFieldDefinition(def) &&
5699
+ shouldUseTextMaskForColumn(def, semanticType)) {
5700
+ return 'string';
5701
+ }
5702
+ if (semanticType)
5703
+ return semanticType;
5704
+ if (fallback)
5705
+ return fallback;
5706
+ return 'string';
5707
+ }
5708
+ function resolveSemanticColumnTypeFromFieldDefinition(def) {
5709
+ const controlType = normalizePresentationToken(def.controlType);
5710
+ const numericFormat = normalizePresentationToken(def.numericFormat ?? def.format);
5711
+ const valuePresentationType = normalizePresentationToken(def.valuePresentation?.type);
5712
+ const dataType = normalizePresentationToken(def.type);
5713
+ if (valuePresentationType === 'currency')
5714
+ return 'currency';
5715
+ if (valuePresentationType === 'percent' || valuePresentationType === 'percentage')
5716
+ return 'percentage';
5717
+ if (valuePresentationType === 'date' || valuePresentationType === 'datetime' || valuePresentationType === 'time')
5609
5718
  return 'date';
5610
- if (t.includes('bool'))
5719
+ if (valuePresentationType === 'boolean')
5611
5720
  return 'boolean';
5612
- if (t.includes('number') || t.includes('int') || t.includes('decimal'))
5721
+ if (valuePresentationType === 'number')
5613
5722
  return 'number';
5614
- return 'string';
5723
+ if (valuePresentationType === 'string')
5724
+ return 'string';
5725
+ if (numericFormat === 'currency' || controlType === 'currency')
5726
+ return 'currency';
5727
+ if (numericFormat === 'percent' || numericFormat === 'percentage')
5728
+ return 'percentage';
5729
+ if (numericFormat === 'date' || numericFormat === 'datetime')
5730
+ return 'date';
5731
+ if (controlType === 'numerictextbox' || controlType === 'inlinenumber')
5732
+ return 'number';
5733
+ if (controlType === 'checkbox' || controlType === 'toggle' || controlType === 'inlinetoggle')
5734
+ return 'boolean';
5735
+ if (controlType.includes('date') || controlType === 'time' || controlType === 'timepicker')
5736
+ return 'date';
5737
+ if (isColumnType(dataType))
5738
+ return dataType;
5739
+ if (dataType === 'text' || dataType === 'email' || dataType === 'url' || dataType === 'password')
5740
+ return 'string';
5741
+ if (dataType.includes('date') || dataType === 'time')
5742
+ return 'date';
5743
+ if (dataType.includes('bool'))
5744
+ return 'boolean';
5745
+ if (dataType.includes('number') ||
5746
+ dataType.includes('int') ||
5747
+ dataType.includes('decimal') ||
5748
+ dataType.includes('double') ||
5749
+ dataType.includes('float')) {
5750
+ return 'number';
5751
+ }
5752
+ if (isTextualControlType(controlType))
5753
+ return 'string';
5754
+ return undefined;
5755
+ }
5756
+ function shouldUseTextMaskForColumn(def, semanticType) {
5757
+ if (!semanticType || semanticType === 'string')
5758
+ return true;
5759
+ const controlType = normalizePresentationToken(def.controlType);
5760
+ if (isTextualControlType(controlType))
5761
+ return true;
5762
+ if (['date', 'boolean', 'currency', 'percentage', 'custom'].includes(semanticType)) {
5763
+ return false;
5764
+ }
5765
+ const valuePresentationType = normalizePresentationToken(def.valuePresentation?.type);
5766
+ const numericFormat = normalizePresentationToken(def.numericFormat ?? def.format);
5767
+ return !valuePresentationType && !numericFormat;
5768
+ }
5769
+ function resolveTextMaskFormatFromFieldDefinition(def) {
5770
+ return resolveTextMaskFormat(def.mask ??
5771
+ def.displayMask ??
5772
+ def.inputMask ??
5773
+ def.extraProperties?.mask);
5774
+ }
5775
+ function resolveTextMaskFormat(value) {
5776
+ if (typeof value !== 'string')
5777
+ return undefined;
5778
+ const format = value.trim();
5779
+ if (!format)
5780
+ return undefined;
5781
+ const hasMaskTokens = /[0#9Xx]/.test(format);
5782
+ const hasInvalidMaskLetters = /[A-WYZa-wyz]/.test(format);
5783
+ return hasMaskTokens && !hasInvalidMaskLetters ? format : undefined;
5784
+ }
5785
+ function normalizePresentationToken(value) {
5786
+ return String(value ?? '').trim().toLowerCase().replace(/[\s_-]+/g, '');
5787
+ }
5788
+ function isColumnType(value) {
5789
+ return [
5790
+ 'string',
5791
+ 'number',
5792
+ 'date',
5793
+ 'boolean',
5794
+ 'currency',
5795
+ 'percentage',
5796
+ 'custom',
5797
+ ].includes(value);
5798
+ }
5799
+ function isTextualControlType(value) {
5800
+ return [
5801
+ 'input',
5802
+ 'inlineinput',
5803
+ 'textarea',
5804
+ 'search',
5805
+ 'email',
5806
+ 'url',
5807
+ 'phone',
5808
+ 'cpfcnpjinput',
5809
+ 'password',
5810
+ ].includes(value);
5615
5811
  }
5616
5812
 
5617
5813
  const PRAXIS_I18N_CONFIG = new InjectionToken('PRAXIS_I18N_CONFIG', {
@@ -6331,7 +6527,7 @@ const GLOBAL_SURFACE_SERVICE = new InjectionToken('GLOBAL_SURFACE_SERVICE');
6331
6527
 
6332
6528
  const dialogBaseFields = [
6333
6529
  { key: 'message', label: 'Mensagem', type: 'textarea', rows: 2, placeholder: 'Texto principal' },
6334
- { key: 'title', label: 'Titulo', type: 'text', placeholder: 'Titulo do dialogo' },
6530
+ { key: 'title', label: 'Título', type: 'text', placeholder: 'Título do diálogo' },
6335
6531
  {
6336
6532
  key: 'themeColor',
6337
6533
  label: 'Tema',
@@ -6342,13 +6538,13 @@ const dialogBaseFields = [
6342
6538
  { value: 'dark', label: 'Dark' },
6343
6539
  ],
6344
6540
  },
6345
- { key: 'positionTop', label: 'Posicao topo', type: 'text', placeholder: '12px' },
6346
- { key: 'positionRight', label: 'Posicao direita', type: 'text', placeholder: '12px' },
6347
- { key: 'positionBottom', label: 'Posicao base', type: 'text', placeholder: '12px' },
6348
- { key: 'positionLeft', label: 'Posicao esquerda', type: 'text', placeholder: '12px' },
6541
+ { key: 'positionTop', label: 'Posição topo', type: 'text', placeholder: '12px' },
6542
+ { key: 'positionRight', label: 'Posição direita', type: 'text', placeholder: '12px' },
6543
+ { key: 'positionBottom', label: 'Posição base', type: 'text', placeholder: '12px' },
6544
+ { key: 'positionLeft', label: 'Posição esquerda', type: 'text', placeholder: '12px' },
6349
6545
  {
6350
6546
  key: 'actionsLayout',
6351
- label: 'Layout das acoes',
6547
+ label: 'Layout das ações',
6352
6548
  type: 'select',
6353
6549
  options: [
6354
6550
  { value: 'start', label: 'Start' },
@@ -6359,7 +6555,7 @@ const dialogBaseFields = [
6359
6555
  },
6360
6556
  {
6361
6557
  key: 'animationType',
6362
- label: 'Animacao',
6558
+ label: 'Animação',
6363
6559
  type: 'select',
6364
6560
  options: [
6365
6561
  { value: 'translate', label: 'Translate' },
@@ -6371,7 +6567,7 @@ const dialogBaseFields = [
6371
6567
  },
6372
6568
  {
6373
6569
  key: 'animationDirection',
6374
- label: 'Direcao animacao',
6570
+ label: 'Direção animação',
6375
6571
  type: 'select',
6376
6572
  options: [
6377
6573
  { value: 'up', label: 'Up' },
@@ -6380,13 +6576,13 @@ const dialogBaseFields = [
6380
6576
  { value: 'right', label: 'Right' },
6381
6577
  ],
6382
6578
  },
6383
- { key: 'animationDuration', label: 'Duracao (ms)', type: 'number', placeholder: '300' },
6579
+ { key: 'animationDuration', label: 'Duração (ms)', type: 'number', placeholder: '300' },
6384
6580
  { key: 'width', label: 'Largura', type: 'text', placeholder: '480px' },
6385
6581
  { key: 'height', label: 'Altura', type: 'text', placeholder: 'auto' },
6386
- { key: 'minWidth', label: 'Largura minima', type: 'text', placeholder: '280px' },
6387
- { key: 'maxWidth', label: 'Largura maxima', type: 'text', placeholder: '90vw' },
6388
- { key: 'minHeight', label: 'Altura minima', type: 'text', placeholder: '120px' },
6389
- { key: 'maxHeight', label: 'Altura maxima', type: 'text', placeholder: '90vh' },
6582
+ { key: 'minWidth', label: 'Largura mínima', type: 'text', placeholder: '280px' },
6583
+ { key: 'maxWidth', label: 'Largura máxima', type: 'text', placeholder: '90vw' },
6584
+ { key: 'minHeight', label: 'Altura mínima', type: 'text', placeholder: '120px' },
6585
+ { key: 'maxHeight', label: 'Altura máxima', type: 'text', placeholder: '90vh' },
6390
6586
  { key: 'disableClose', label: 'Bloquear fechar', type: 'toggle' },
6391
6587
  { key: 'hasBackdrop', label: 'Backdrop', type: 'toggle' },
6392
6588
  { key: 'closeOnBackdropClick', label: 'Fechar ao clicar no backdrop', type: 'toggle' },
@@ -6414,7 +6610,7 @@ const dialogFieldsWithModeDependency = dialogFieldsWithoutMessage.map((field) =>
6414
6610
  ...field,
6415
6611
  dependsOnKey: field.dependsOnKey ?? 'mode',
6416
6612
  dependsOnValue: field.dependsOnValue ?? 'true',
6417
- hint: field.hint ?? 'Disponivel quando "Usar dialogo" estiver ativo.',
6613
+ hint: field.hint ?? 'Disponível quando "Usar diálogo" estiver ativo.',
6418
6614
  }));
6419
6615
  const GLOBAL_ACTION_UI_SCHEMAS = [
6420
6616
  {
@@ -6462,7 +6658,7 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6462
6658
  required: true,
6463
6659
  placeholder: 'Texto exibido no alerta simples',
6464
6660
  },
6465
- { key: 'mode', label: 'Usar dialogo (avancado)', type: 'toggle' },
6661
+ { key: 'mode', label: 'Usar diálogo (avançado)', type: 'toggle' },
6466
6662
  ...dialogFieldsWithModeDependency,
6467
6663
  ],
6468
6664
  },
@@ -6481,19 +6677,19 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6481
6677
  fields: [
6482
6678
  ...dialogBaseFields,
6483
6679
  { key: 'placeholder', label: 'Placeholder', type: 'text' },
6484
- { key: 'defaultValue', label: 'Valor padrao', type: 'text' },
6680
+ { key: 'defaultValue', label: 'Valor padrão', type: 'text' },
6485
6681
  { key: 'okLabel', label: 'Texto OK', type: 'text' },
6486
6682
  { key: 'cancelLabel', label: 'Texto cancelar', type: 'text' },
6487
6683
  ],
6488
6684
  },
6489
6685
  {
6490
6686
  id: 'dialog.open',
6491
- label: 'Abrir dialogo',
6687
+ label: 'Abrir diálogo',
6492
6688
  fields: [
6493
6689
  ...dialogBaseFields,
6494
6690
  {
6495
6691
  key: 'contentType',
6496
- label: 'Tipo de conteudo',
6692
+ label: 'Tipo de conteúdo',
6497
6693
  type: 'select',
6498
6694
  options: [
6499
6695
  { value: 'template', label: 'Template' },
@@ -6514,7 +6710,7 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6514
6710
  { key: 'message', label: 'Mensagem', type: 'text' },
6515
6711
  {
6516
6712
  key: 'level',
6517
- label: 'Nivel',
6713
+ label: 'Nível',
6518
6714
  type: 'select',
6519
6715
  options: [
6520
6716
  { value: 'log', label: 'log' },
@@ -8474,6 +8670,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
8474
8670
  const ALL_RULE_CONTEXT_ROOTS = [
8475
8671
  'form',
8476
8672
  'row',
8673
+ 'rowData',
8477
8674
  'computed',
8478
8675
  'meta',
8479
8676
  'source',
@@ -9332,6 +9529,7 @@ function mapFieldDefinitionToMetadata(field) {
9332
9529
  'displayOrientation',
9333
9530
  'disabled',
9334
9531
  'readOnly',
9532
+ 'fieldAccess',
9335
9533
  'hidden',
9336
9534
  'formHidden',
9337
9535
  'tableHidden',
@@ -9496,9 +9694,25 @@ function mapFieldDefinitionToMetadata(field) {
9496
9694
  metadata.maxLength = field.maxLength;
9497
9695
  if (field.pattern !== undefined)
9498
9696
  metadata.pattern = field.pattern;
9697
+ if (field.helpText !== undefined) {
9698
+ metadata.helpText = field.helpText;
9699
+ }
9499
9700
  if (field.hint || field.helpText) {
9500
9701
  metadata.hint = field.hint ?? field.helpText;
9501
9702
  }
9703
+ if (field.tooltipOnHover !== undefined) {
9704
+ metadata.tooltipOnHover = field.tooltipOnHover;
9705
+ const tooltip = field.tooltip ??
9706
+ (field.tooltipOnHover === true
9707
+ ? field.description ?? field.helpText ?? field.hint
9708
+ : undefined);
9709
+ if (tooltip !== undefined && tooltip !== null) {
9710
+ metadata.tooltip = String(tooltip);
9711
+ }
9712
+ }
9713
+ else if (field.tooltip !== undefined) {
9714
+ metadata.tooltip = String(field.tooltip);
9715
+ }
9502
9716
  if (field.hiddenCondition !== undefined) {
9503
9717
  metadata.hiddenCondition = field.hiddenCondition;
9504
9718
  }
@@ -11562,7 +11776,7 @@ class ResourceDiscoveryService {
11562
11776
  throw new Error('ResourceDiscoveryService cannot resolve an empty href.');
11563
11777
  }
11564
11778
  if (/^https?:\/\//i.test(normalizedHref)) {
11565
- return normalizedHref;
11779
+ return this.resolveTrustedAbsoluteHref(normalizedHref, options);
11566
11780
  }
11567
11781
  const apiBaseUrl = this.resolveApiBaseHref(options);
11568
11782
  if (!apiBaseUrl) {
@@ -11615,6 +11829,69 @@ class ResourceDiscoveryService {
11615
11829
  const entry = this.resolveApiEntry(options);
11616
11830
  return String(buildApiUrl(entry) || '').trim();
11617
11831
  }
11832
+ resolveTrustedAbsoluteHref(href, options) {
11833
+ const runtimeOrigin = this.getRuntimeOrigin();
11834
+ const baseUrl = this.resolveApiBaseUrl(options);
11835
+ if (!runtimeOrigin || !baseUrl || this.isAbsoluteHttpUrl(baseUrl)) {
11836
+ return href;
11837
+ }
11838
+ let parsed;
11839
+ try {
11840
+ parsed = new URL(href);
11841
+ }
11842
+ catch {
11843
+ return href;
11844
+ }
11845
+ if (!this.isTrustedOrigin(parsed.origin, options)) {
11846
+ return href;
11847
+ }
11848
+ if (!this.isProxyableApiPath(parsed.pathname, baseUrl)) {
11849
+ return href;
11850
+ }
11851
+ return new URL(`${parsed.pathname}${parsed.search}${parsed.hash}`, `${runtimeOrigin}/`).toString();
11852
+ }
11853
+ isTrustedOrigin(origin, options) {
11854
+ const normalizedOrigin = this.normalizeOrigin(origin);
11855
+ if (!normalizedOrigin) {
11856
+ return false;
11857
+ }
11858
+ return this.getTrustedOrigins(options).some((trustedOrigin) => trustedOrigin === normalizedOrigin);
11859
+ }
11860
+ getTrustedOrigins(options) {
11861
+ const origins = this.resolveApiEntry(options).trustedOrigins || [];
11862
+ return origins
11863
+ .map((origin) => this.normalizeOrigin(origin))
11864
+ .filter((origin) => !!origin);
11865
+ }
11866
+ normalizeOrigin(origin) {
11867
+ try {
11868
+ return new URL(origin).origin;
11869
+ }
11870
+ catch {
11871
+ return null;
11872
+ }
11873
+ }
11874
+ isProxyableApiPath(pathname, baseUrl) {
11875
+ const basePath = this.normalizePathPrefix(baseUrl);
11876
+ if (basePath && (pathname === basePath || pathname.startsWith(`${basePath}/`))) {
11877
+ return true;
11878
+ }
11879
+ return pathname === '/schemas'
11880
+ || pathname.startsWith('/schemas/')
11881
+ || pathname === '/v3/api-docs'
11882
+ || pathname.startsWith('/v3/api-docs/');
11883
+ }
11884
+ normalizePathPrefix(baseUrl) {
11885
+ const path = String(baseUrl || '').split(/[?#]/u)[0]?.trim() || '';
11886
+ if (!path.startsWith('/')) {
11887
+ return '';
11888
+ }
11889
+ const normalized = `/${path.replace(/^\/+|\/+$/g, '')}`;
11890
+ return normalized === '/' ? '' : normalized;
11891
+ }
11892
+ isAbsoluteHttpUrl(value) {
11893
+ return /^https?:\/\//i.test(String(value || '').trim());
11894
+ }
11618
11895
  resolveApiBaseHref(options) {
11619
11896
  const baseUrl = this.resolveApiBaseUrl(options);
11620
11897
  if (!baseUrl) {
@@ -11922,6 +12199,209 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
11922
12199
  args: [{ providedIn: 'any' }]
11923
12200
  }] });
11924
12201
 
12202
+ const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS');
12203
+ const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY');
12204
+ function providePraxisEnterpriseRuntimeContext(options = {}) {
12205
+ const normalized = {
12206
+ ...options,
12207
+ includeGlobalFetchHeaders: options.includeGlobalFetchHeaders ?? true,
12208
+ blocking: options.blocking ?? false,
12209
+ errorPolicy: options.errorPolicy ?? 'ignore',
12210
+ };
12211
+ return [
12212
+ { provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, useValue: normalized },
12213
+ {
12214
+ provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY,
12215
+ useFactory: (service) => {
12216
+ let promise = null;
12217
+ return () => {
12218
+ if (promise)
12219
+ return promise;
12220
+ promise = service.ready().then(() => undefined);
12221
+ return promise;
12222
+ };
12223
+ },
12224
+ deps: [EnterpriseRuntimeContextService],
12225
+ },
12226
+ {
12227
+ provide: APP_INITIALIZER,
12228
+ multi: true,
12229
+ useFactory: (ready) => () => normalized.blocking ? ready() : undefined,
12230
+ deps: [PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY],
12231
+ },
12232
+ ];
12233
+ }
12234
+
12235
+ class EnterpriseRuntimeContextService {
12236
+ http = inject(HttpClient);
12237
+ apiUrl = inject(API_URL, { optional: true });
12238
+ options = inject(PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, {
12239
+ optional: true,
12240
+ });
12241
+ contextSubject = new BehaviorSubject(null);
12242
+ loadPromise = null;
12243
+ contextChanges$ = this.contextSubject.asObservable();
12244
+ get snapshot() {
12245
+ return this.contextSubject.value;
12246
+ }
12247
+ ready() {
12248
+ if (this.contextSubject.value) {
12249
+ return Promise.resolve(this.contextSubject.value);
12250
+ }
12251
+ if (this.loadPromise) {
12252
+ return this.loadPromise;
12253
+ }
12254
+ this.loadPromise = this.load()
12255
+ .catch((error) => {
12256
+ if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
12257
+ throw error;
12258
+ }
12259
+ return null;
12260
+ })
12261
+ .finally(() => {
12262
+ this.loadPromise = null;
12263
+ });
12264
+ return this.loadPromise;
12265
+ }
12266
+ refresh() {
12267
+ this.loadPromise = null;
12268
+ return this.load().catch((error) => {
12269
+ if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
12270
+ throw error;
12271
+ }
12272
+ return null;
12273
+ });
12274
+ }
12275
+ tenants() {
12276
+ return this.getRuntimeSurface('tenants');
12277
+ }
12278
+ navigation() {
12279
+ return this.getRuntimeSurface('navigation');
12280
+ }
12281
+ securityEvents() {
12282
+ return this.getRuntimeSurface('securityEvents');
12283
+ }
12284
+ async switchContext(command) {
12285
+ const response = await firstValueFrom(this.http.put(this.endpoint('context'), command, {
12286
+ headers: this.requestHeaders({ includeSnapshot: true }),
12287
+ }));
12288
+ if (response?.effectiveContext) {
12289
+ this.contextSubject.next(response.effectiveContext);
12290
+ }
12291
+ return response;
12292
+ }
12293
+ headers(fallback) {
12294
+ return {
12295
+ ...this.normalizeHeaders(fallback ?? {}),
12296
+ ...this.normalizeHeaders(this.headersFromSnapshot(this.contextSubject.value)),
12297
+ };
12298
+ }
12299
+ async load() {
12300
+ const context = await firstValueFrom(this.http.get(this.endpoint('context'), {
12301
+ headers: this.requestHeaders(),
12302
+ }));
12303
+ this.contextSubject.next(context ?? null);
12304
+ return context ?? null;
12305
+ }
12306
+ async getRuntimeSurface(surface) {
12307
+ return firstValueFrom(this.http.get(this.endpoint(surface), {
12308
+ headers: this.requestHeaders({ includeSnapshot: true }),
12309
+ }));
12310
+ }
12311
+ endpoint(surface) {
12312
+ const configured = this.configuredEndpoint(surface);
12313
+ if (configured) {
12314
+ return configured;
12315
+ }
12316
+ return `${this.runtimeRoot()}/${this.surfacePath(surface)}`;
12317
+ }
12318
+ configuredEndpoint(surface) {
12319
+ const configured = surface === 'context'
12320
+ ? (this.options?.endpoints?.context ?? this.options?.endpoint)
12321
+ : this.options?.endpoints?.[surface];
12322
+ const normalized = configured?.trim().replace(/\/+$/, '');
12323
+ return normalized || null;
12324
+ }
12325
+ runtimeRoot() {
12326
+ const configuredContext = this.configuredEndpoint('context');
12327
+ if (configuredContext?.endsWith('/context')) {
12328
+ return configuredContext.slice(0, -'/context'.length);
12329
+ }
12330
+ const defaultEntry = this.apiUrl?.['default'];
12331
+ const base = defaultEntry ? buildApiUrl(defaultEntry) : '';
12332
+ return base ? `${base}/praxis/runtime` : '/api/praxis/runtime';
12333
+ }
12334
+ surfacePath(surface) {
12335
+ switch (surface) {
12336
+ case 'context':
12337
+ return 'context';
12338
+ case 'tenants':
12339
+ return 'tenants';
12340
+ case 'navigation':
12341
+ return 'navigation';
12342
+ case 'securityEvents':
12343
+ return 'security-events';
12344
+ }
12345
+ }
12346
+ requestHeaders(options = {}) {
12347
+ const merged = this.normalizeHeaders({
12348
+ ...(this.options?.includeGlobalFetchHeaders ?? true ? this.globalFetchHeaders() : {}),
12349
+ ...(this.options?.headersFactory?.() ?? {}),
12350
+ ...(options.includeSnapshot ? this.headersFromSnapshot(this.contextSubject.value) : {}),
12351
+ });
12352
+ let headers = new HttpHeaders();
12353
+ for (const [key, value] of Object.entries(merged)) {
12354
+ if (value) {
12355
+ headers = headers.set(key, value);
12356
+ }
12357
+ }
12358
+ return headers;
12359
+ }
12360
+ globalFetchHeaders() {
12361
+ try {
12362
+ const factory = globalThis.PAX_FETCH_HEADERS;
12363
+ return factory?.() ?? {};
12364
+ }
12365
+ catch {
12366
+ return {};
12367
+ }
12368
+ }
12369
+ headersFromSnapshot(context) {
12370
+ if (!context) {
12371
+ return {};
12372
+ }
12373
+ return {
12374
+ 'X-Tenant-ID': context.activeTenant?.tenantId,
12375
+ 'X-User-ID': context.user?.userId,
12376
+ 'X-Env': context.environment ?? undefined,
12377
+ 'Accept-Language': context.locale ?? undefined,
12378
+ 'X-Timezone': context.timezone ?? undefined,
12379
+ 'X-Praxis-Profile-ID': context.activeProfileId ?? undefined,
12380
+ 'X-Praxis-Module-Key': context.activeModuleKey ?? undefined,
12381
+ };
12382
+ }
12383
+ normalizeHeaders(headers) {
12384
+ const normalized = {};
12385
+ for (const [key, value] of Object.entries(headers)) {
12386
+ if (typeof value !== 'string') {
12387
+ continue;
12388
+ }
12389
+ const trimmed = value.trim();
12390
+ if (!trimmed) {
12391
+ continue;
12392
+ }
12393
+ normalized[key] = trimmed;
12394
+ }
12395
+ return normalized;
12396
+ }
12397
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12398
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, providedIn: 'root' });
12399
+ }
12400
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, decorators: [{
12401
+ type: Injectable,
12402
+ args: [{ providedIn: 'root' }]
12403
+ }] });
12404
+
11925
12405
  function clonePraxisRuntimeComponentObservation(observation) {
11926
12406
  assertPraxisRuntimeComponentObservationSerializable(observation);
11927
12407
  return JSON.parse(JSON.stringify(observation));
@@ -12444,9 +12924,10 @@ class SurfaceOpenMaterializerService {
12444
12924
  : null;
12445
12925
  if (collectionData) {
12446
12926
  if (this.shouldPreserveCollectionPresentation(payload)) {
12927
+ const preservedPayload = this.ensureCollectionTableSelectionContract(payload);
12447
12928
  return {
12448
- ...payload,
12449
- context: this.mergeMaterializationContext(payload, {
12929
+ ...preservedPayload,
12930
+ context: this.mergeMaterializationContext(preservedPayload, {
12450
12931
  readUrl,
12451
12932
  dataShape: 'array',
12452
12933
  recordCount: collectionData.length,
@@ -12470,18 +12951,24 @@ class SurfaceOpenMaterializerService {
12470
12951
  if (data && typeof data === 'object' && !Array.isArray(data)) {
12471
12952
  const objectData = data;
12472
12953
  if (payload.widget.id === 'praxis-dynamic-form') {
12473
- const schemaFields = await this.resolveSchemaFields(payload, discoveryOptions);
12474
12954
  return {
12475
12955
  ...payload,
12476
12956
  widget: {
12477
12957
  ...payload.widget,
12478
12958
  inputs: {
12479
12959
  ...this.projectMaterializedFormInputs(payload.widget.inputs || {}),
12480
- configPersistenceStrategy: 'input-first',
12481
12960
  mode: payload.widget.inputs?.['mode'] || 'view',
12482
12961
  initialValue: objectData,
12483
12962
  resourceId,
12484
- config: this.buildLocalFormConfig(objectData, schemaFields),
12963
+ layoutPolicy: payload.widget.inputs?.['layoutPolicy'] || {
12964
+ source: 'schema',
12965
+ intent: 'detail',
12966
+ preset: 'compactPresentation',
12967
+ lifecycle: 'live',
12968
+ persistence: 'transient',
12969
+ schemaOperation: 'detail',
12970
+ schemaType: 'response',
12971
+ },
12485
12972
  },
12486
12973
  },
12487
12974
  context: this.mergeMaterializationContext(payload, {
@@ -12519,11 +13006,14 @@ class SurfaceOpenMaterializerService {
12519
13006
  'resourceId',
12520
13007
  'apiEndpointKey',
12521
13008
  'apiUrlEntry',
13009
+ 'schemaUrl',
13010
+ 'readUrl',
12522
13011
  'submitUrl',
12523
13012
  'submitMethod',
12524
13013
  'responseSchemaUrl',
12525
13014
  'customEndpoints',
12526
13015
  'configPersistenceStrategy',
13016
+ 'layoutPolicy',
12527
13017
  'mode',
12528
13018
  'actions',
12529
13019
  'enableCustomization',
@@ -12531,6 +13021,7 @@ class SurfaceOpenMaterializerService {
12531
13021
  'readonlyModeGlobal',
12532
13022
  'disabledModeGlobal',
12533
13023
  'presentationModeGlobal',
13024
+ 'fieldIconPolicy',
12534
13025
  'visibleGlobal',
12535
13026
  'layout',
12536
13027
  'backConfig',
@@ -12544,186 +13035,6 @@ class SurfaceOpenMaterializerService {
12544
13035
  ]);
12545
13036
  return Object.fromEntries(Object.entries(inputs).filter(([key]) => supported.has(key)));
12546
13037
  }
12547
- buildLocalFormConfig(data, schemaFields = []) {
12548
- const fields = this.buildMaterializedFormFields(data, schemaFields);
12549
- const sections = this.buildMaterializedFormSections(fields);
12550
- return {
12551
- sections,
12552
- fieldMetadata: fields,
12553
- };
12554
- }
12555
- buildMaterializedFormFields(data, schemaFields) {
12556
- const schemaByName = new Map(schemaFields
12557
- .filter((field) => !!field?.name)
12558
- .map((field) => [field.name, field]));
12559
- const orderedNames = schemaFields.length
12560
- ? [
12561
- ...schemaFields
12562
- .filter((field) => field?.name && Object.prototype.hasOwnProperty.call(data, field.name))
12563
- .sort((left, right) => (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER))
12564
- .map((field) => field.name),
12565
- ...Object.keys(data).filter((key) => !schemaByName.has(key)),
12566
- ]
12567
- : Object.keys(data);
12568
- return orderedNames
12569
- .filter((key, index, keys) => keys.indexOf(key) === index)
12570
- .filter((key) => this.shouldRenderMaterializedFormField(key, data[key], schemaByName.get(key), data))
12571
- .map((key) => {
12572
- const field = schemaByName.get(key);
12573
- if (field) {
12574
- return {
12575
- ...mapFieldDefinitionToMetadata({
12576
- ...field,
12577
- hidden: false,
12578
- formHidden: false,
12579
- readOnly: true,
12580
- }),
12581
- readOnly: true,
12582
- };
12583
- }
12584
- return {
12585
- name: key,
12586
- label: this.humanizeFieldName(key),
12587
- controlType: this.inferFormControlType(data[key]),
12588
- readOnly: true,
12589
- };
12590
- });
12591
- }
12592
- buildMaterializedFormSections(fields) {
12593
- const groups = new Map();
12594
- for (const field of fields) {
12595
- const group = String(field.group || '').trim() || 'Detalhes';
12596
- groups.set(group, [...(groups.get(group) || []), field]);
12597
- }
12598
- return Array.from(groups.entries()).map(([group, groupFields], sectionIndex) => {
12599
- const fieldNames = groupFields.map((field) => field.name);
12600
- const rows = this.chunk(fieldNames, 2).map((names, rowIndex) => ({
12601
- id: `row-${sectionIndex + 1}-${rowIndex + 1}`,
12602
- columns: names.map((name) => ({
12603
- id: `col-${name}`,
12604
- fields: [name],
12605
- })),
12606
- }));
12607
- return {
12608
- id: this.stableSectionId(group, sectionIndex),
12609
- title: group,
12610
- rows,
12611
- };
12612
- });
12613
- }
12614
- shouldRenderMaterializedFormField(key, value, field, data) {
12615
- if (!key || key.startsWith('_'))
12616
- return false;
12617
- if (field?.hidden === true)
12618
- return false;
12619
- if (this.isTechnicalRelationIdField(key, field, data))
12620
- return false;
12621
- if (this.isDuplicateMediaUrlField(key, value, field, data))
12622
- return false;
12623
- if (field?.formHidden === true && !this.isResolvedDisplayCompanionField(key, data)) {
12624
- return false;
12625
- }
12626
- if (value == null)
12627
- return true;
12628
- return typeof value !== 'object' || value instanceof Date;
12629
- }
12630
- isTechnicalRelationIdField(key, field, data) {
12631
- if (key === 'id' || !/Id$/.test(key))
12632
- return false;
12633
- const base = key.slice(0, -2);
12634
- const hasDisplayCompanion = this.hasDisplayCompanion(base, data);
12635
- if (!hasDisplayCompanion)
12636
- return false;
12637
- const controlType = String(field?.controlType || '').toLowerCase();
12638
- return Boolean(field?.endpoint
12639
- || field?.resourcePath
12640
- || field?.optionSource
12641
- || controlType.includes('select')
12642
- || field?.tableHidden === true);
12643
- }
12644
- isResolvedDisplayCompanionField(key, data) {
12645
- const base = this.resolveDisplayCompanionBase(key);
12646
- return !!base && Object.prototype.hasOwnProperty.call(data, `${base}Id`);
12647
- }
12648
- resolveDisplayCompanionBase(key) {
12649
- const suffixes = ['Nome', 'Name', 'Label', 'Descricao', 'Description', 'Title', 'Text'];
12650
- const suffix = suffixes.find((candidate) => key.endsWith(candidate));
12651
- return suffix ? key.slice(0, -suffix.length) : null;
12652
- }
12653
- hasDisplayCompanion(base, data) {
12654
- const suffixes = ['Nome', 'Name', 'Label', 'Descricao', 'Description', 'Title', 'Text'];
12655
- return suffixes.some((suffix) => {
12656
- const value = data[`${base}${suffix}`];
12657
- return value != null && String(value).trim().length > 0;
12658
- });
12659
- }
12660
- isDuplicateMediaUrlField(key, value, field, data) {
12661
- if (typeof value !== 'string' || !this.looksLikeMediaUrlField(key, field)) {
12662
- return false;
12663
- }
12664
- return Object.entries(data).some(([candidateKey, candidateValue]) => {
12665
- if (candidateKey === key || candidateValue !== value) {
12666
- return false;
12667
- }
12668
- return this.looksLikeAvatarFieldName(candidateKey);
12669
- });
12670
- }
12671
- looksLikeMediaUrlField(key, field) {
12672
- const type = String(field?.type || '').toLowerCase();
12673
- const controlType = String(field?.controlType || '').toLowerCase();
12674
- const normalized = key.toLowerCase();
12675
- return Boolean(type === 'url'
12676
- || controlType.includes('url')
12677
- || normalized.includes('url')
12678
- || normalized.includes('foto')
12679
- || normalized.includes('photo')
12680
- || normalized.includes('image')
12681
- || normalized.includes('imagem'));
12682
- }
12683
- looksLikeAvatarFieldName(key) {
12684
- const normalized = key.toLowerCase();
12685
- return normalized.includes('avatar') || normalized.includes('portrait');
12686
- }
12687
- inferFormControlType(value) {
12688
- if (typeof value === 'boolean')
12689
- return 'checkbox';
12690
- if (typeof value === 'number')
12691
- return 'numericTextBox';
12692
- if (typeof value === 'string') {
12693
- if (/^\d{4}-\d{2}-\d{2}$/.test(value))
12694
- return 'dateInput';
12695
- if (/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value))
12696
- return 'email';
12697
- }
12698
- return 'input';
12699
- }
12700
- humanizeFieldName(key) {
12701
- return key
12702
- .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
12703
- .replace(/[_-]+/g, ' ')
12704
- .replace(/\s+/g, ' ')
12705
- .trim()
12706
- .replace(/^./, (char) => char.toUpperCase());
12707
- }
12708
- stableSectionId(group, index) {
12709
- if (group === 'Detalhes') {
12710
- return 'details';
12711
- }
12712
- const normalized = group
12713
- .normalize('NFD')
12714
- .replace(/[\u0300-\u036f]/g, '')
12715
- .toLowerCase()
12716
- .replace(/[^a-z0-9]+/g, '-')
12717
- .replace(/^-+|-+$/g, '');
12718
- return normalized || `details-${index + 1}`;
12719
- }
12720
- chunk(items, size) {
12721
- const result = [];
12722
- for (let index = 0; index < items.length; index += size) {
12723
- result.push(items.slice(index, index + size));
12724
- }
12725
- return result;
12726
- }
12727
13038
  shouldMaterializeItemReadProjection(payload) {
12728
13039
  const surface = payload.context?.['surface'];
12729
13040
  const kind = String(surface?.['kind'] || '').toUpperCase();
@@ -12806,6 +13117,8 @@ class SurfaceOpenMaterializerService {
12806
13117
  bindingOrder: [
12807
13118
  'tableId',
12808
13119
  'componentInstanceId',
13120
+ 'configPersistenceStrategy',
13121
+ 'resourcePath',
12809
13122
  'title',
12810
13123
  'subtitle',
12811
13124
  'icon',
@@ -12813,11 +13126,17 @@ class SurfaceOpenMaterializerService {
12813
13126
  'config',
12814
13127
  'enableCustomization',
12815
13128
  ],
13129
+ outputs: {
13130
+ rowClick: 'emit',
13131
+ selectionChange: 'emit',
13132
+ widgetEvent: 'emit',
13133
+ },
12816
13134
  inputs: {
12817
13135
  ...tableInputOverrides,
12818
13136
  resourcePath: '',
12819
13137
  tableId: String(previousInputs['tableId'] || this.stableSurfaceId(payload)),
12820
13138
  componentInstanceId: `${this.stableSurfaceId(payload)}.${resourceId}`,
13139
+ configPersistenceStrategy: previousInputs['configPersistenceStrategy'] ?? 'volatile',
12821
13140
  title: payload.title,
12822
13141
  subtitle: payload.subtitle,
12823
13142
  icon: payload.icon,
@@ -12833,6 +13152,52 @@ class SurfaceOpenMaterializerService {
12833
13152
  }),
12834
13153
  };
12835
13154
  }
13155
+ ensureCollectionTableSelectionContract(payload) {
13156
+ if (payload.widget?.id !== 'praxis-table') {
13157
+ return payload;
13158
+ }
13159
+ const inputs = payload.widget.inputs || {};
13160
+ return {
13161
+ ...payload,
13162
+ widget: {
13163
+ ...payload.widget,
13164
+ outputs: {
13165
+ ...(payload.widget.outputs || {}),
13166
+ rowClick: 'emit',
13167
+ selectionChange: 'emit',
13168
+ widgetEvent: 'emit',
13169
+ },
13170
+ inputs: {
13171
+ ...inputs,
13172
+ config: this.ensureTableSelectionConfig(inputs['config']),
13173
+ },
13174
+ },
13175
+ };
13176
+ }
13177
+ ensureTableSelectionConfig(config) {
13178
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
13179
+ return config;
13180
+ }
13181
+ const tableConfig = config;
13182
+ const rawBehavior = tableConfig['behavior'];
13183
+ const behavior = (rawBehavior && typeof rawBehavior === 'object' && !Array.isArray(rawBehavior)
13184
+ ? rawBehavior
13185
+ : {});
13186
+ if (behavior['selection'] && typeof behavior['selection'] === 'object') {
13187
+ return config;
13188
+ }
13189
+ return {
13190
+ ...tableConfig,
13191
+ behavior: {
13192
+ ...behavior,
13193
+ selection: {
13194
+ enabled: true,
13195
+ type: 'single',
13196
+ mode: 'both',
13197
+ },
13198
+ },
13199
+ };
13200
+ }
12836
13201
  projectTableInputs(inputs) {
12837
13202
  const supported = new Set([
12838
13203
  'tableId',
@@ -12869,6 +13234,11 @@ class SurfaceOpenMaterializerService {
12869
13234
  behavior: {
12870
13235
  localDataMode: { enabled: true },
12871
13236
  pagination: { enabled: true, pageSize: 10 },
13237
+ selection: {
13238
+ enabled: true,
13239
+ type: 'single',
13240
+ mode: 'both',
13241
+ },
12872
13242
  },
12873
13243
  };
12874
13244
  }
@@ -16016,6 +16386,743 @@ const FieldDataType = {
16016
16386
  * - Angular Material 3 native support
16017
16387
  */
16018
16388
 
16389
+ const VISUALIZATION_KINDS = new Set([
16390
+ 'line',
16391
+ 'area',
16392
+ 'column',
16393
+ 'comparison',
16394
+ 'stackedBar',
16395
+ 'radial',
16396
+ 'harveyBall',
16397
+ 'bullet',
16398
+ 'delta',
16399
+ 'processFlow',
16400
+ ]);
16401
+ const VISUALIZATION_SURFACES = new Set([
16402
+ 'table-cell',
16403
+ 'list-item',
16404
+ 'object-header',
16405
+ 'card-summary',
16406
+ 'form-presentation',
16407
+ ]);
16408
+ const VISUALIZATION_SIZES = new Set([
16409
+ 'xs',
16410
+ 'sm',
16411
+ 'md',
16412
+ 'lg',
16413
+ 'responsive',
16414
+ ]);
16415
+ const VISUALIZATION_TONES = new Set([
16416
+ 'neutral',
16417
+ 'info',
16418
+ 'success',
16419
+ 'warning',
16420
+ 'danger',
16421
+ 'critical',
16422
+ ]);
16423
+ const TABLE_SAFE_KINDS = new Set([
16424
+ 'line',
16425
+ 'area',
16426
+ 'column',
16427
+ 'comparison',
16428
+ 'stackedBar',
16429
+ 'radial',
16430
+ 'harveyBall',
16431
+ 'bullet',
16432
+ 'delta',
16433
+ 'processFlow',
16434
+ ]);
16435
+ function normalizePraxisPresentationVisualization(value) {
16436
+ if (!value || typeof value !== 'object') {
16437
+ return undefined;
16438
+ }
16439
+ const kind = normalizeEnum$1(value.kind, VISUALIZATION_KINDS);
16440
+ const fallbackText = normalizeText$1(value.fallbackText);
16441
+ if (!kind || !fallbackText) {
16442
+ return undefined;
16443
+ }
16444
+ const surface = normalizeEnum$1(value.surface, VISUALIZATION_SURFACES);
16445
+ const size = normalizeEnum$1(value.size, VISUALIZATION_SIZES);
16446
+ const tone = normalizeEnum$1(value.tone, VISUALIZATION_TONES);
16447
+ const ariaLabel = normalizeText$1(value.ariaLabel);
16448
+ const valueSuffix = normalizeText$1(value.valueSuffix);
16449
+ return {
16450
+ kind,
16451
+ fallbackText,
16452
+ ...(surface ? { surface } : {}),
16453
+ ...(size ? { size } : {}),
16454
+ ...(tone ? { tone } : {}),
16455
+ ...(ariaLabel ? { ariaLabel } : {}),
16456
+ ...(valueSuffix ? { valueSuffix } : {}),
16457
+ ...(Object.prototype.hasOwnProperty.call(value, 'value') ? { value: value.value } : {}),
16458
+ ...(normalizeExpression(value.valueExpr, 'valueExpr') ?? {}),
16459
+ ...(normalizeExpression(value.valueSuffixExpr, 'valueSuffixExpr') ?? {}),
16460
+ ...(normalizeNumber(value.total, 'total') ?? {}),
16461
+ ...(normalizeExpression(value.totalExpr, 'totalExpr') ?? {}),
16462
+ ...(normalizeNumber(value.target, 'target') ?? {}),
16463
+ ...(normalizeExpression(value.targetExpr, 'targetExpr') ?? {}),
16464
+ ...(normalizeNumber(value.baseline, 'baseline') ?? {}),
16465
+ ...(normalizeExpression(value.baselineExpr, 'baselineExpr') ?? {}),
16466
+ ...(normalizePoints(value.points) ?? {}),
16467
+ ...(normalizeExpression(value.pointsExpr, 'pointsExpr') ?? {}),
16468
+ ...(normalizeSegments(value.segments) ?? {}),
16469
+ ...(normalizeExpression(value.segmentsExpr, 'segmentsExpr') ?? {}),
16470
+ ...(normalizeThresholds(value.thresholds) ?? {}),
16471
+ ...(normalizeExpression(value.thresholdsExpr, 'thresholdsExpr') ?? {}),
16472
+ ...(normalizeItems(value.items) ?? {}),
16473
+ ...(normalizeExpression(value.itemsExpr, 'itemsExpr') ?? {}),
16474
+ ...(normalizeExpression(value.toneExpr, 'toneExpr') ?? {}),
16475
+ ...(normalizeExpression(value.ariaLabelExpr, 'ariaLabelExpr') ?? {}),
16476
+ ...(normalizeExpression(value.fallbackTextExpr, 'fallbackTextExpr') ?? {}),
16477
+ };
16478
+ }
16479
+ function isPraxisPresentationVisualizationTableSafe(value) {
16480
+ const normalized = normalizePraxisPresentationVisualization(value);
16481
+ return !!normalized && TABLE_SAFE_KINDS.has(normalized.kind);
16482
+ }
16483
+ function renderPraxisPresentationVisualizationHtml(value, options = {}) {
16484
+ const visualization = normalizePraxisPresentationVisualization(value);
16485
+ if (!visualization) {
16486
+ return '';
16487
+ }
16488
+ switch (visualization.kind) {
16489
+ case 'comparison':
16490
+ return renderComparisonVisualizationHtml(visualization, options);
16491
+ case 'stackedBar':
16492
+ return renderStackedBarVisualizationHtml(visualization, options);
16493
+ case 'bullet':
16494
+ return renderBulletVisualizationHtml(visualization, options);
16495
+ case 'delta':
16496
+ return renderDeltaVisualizationHtml(visualization, options);
16497
+ case 'radial':
16498
+ return renderRadialVisualizationHtml(visualization, options);
16499
+ case 'harveyBall':
16500
+ return renderHarveyBallVisualizationHtml(visualization, options);
16501
+ case 'line':
16502
+ return renderLineVisualizationHtml(visualization, options);
16503
+ case 'area':
16504
+ return renderAreaVisualizationHtml(visualization, options);
16505
+ case 'column':
16506
+ return renderColumnVisualizationHtml(visualization, options);
16507
+ case 'processFlow':
16508
+ return renderProcessFlowVisualizationHtml(visualization, options);
16509
+ default:
16510
+ return `<span class="pfx-micro-viz__fallback">${escapeHtml$1(visualization.fallbackText)}</span>`;
16511
+ }
16512
+ }
16513
+ function renderComparisonVisualizationHtml(visualization, options) {
16514
+ const points = visualization.points ?? [];
16515
+ const max = Math.max(1, ...points.map((point) => Math.max(0, point.value)));
16516
+ const rows = points
16517
+ .map((point) => {
16518
+ const width = percent(point.value, max);
16519
+ return `
16520
+ <span class="pfx-micro-viz__row" data-tone="${escapeHtml$1(point.tone ?? visualization.tone ?? 'info')}">
16521
+ <span class="pfx-micro-viz__label">${escapeHtml$1(point.label ?? '')}</span>
16522
+ <span class="pfx-micro-viz__track">
16523
+ <span class="pfx-micro-viz__bar" style="width:${width}%"></span>
16524
+ </span>
16525
+ <span class="pfx-micro-viz__value">${escapeHtml$1(formatMicroNumber(point.value, options.locale))}</span>
16526
+ </span>`;
16527
+ })
16528
+ .join('');
16529
+ return `<span class="pfx-micro-viz" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">${rows}</span>`;
16530
+ }
16531
+ function renderStackedBarVisualizationHtml(visualization, options) {
16532
+ const segments = visualization.segments ?? [];
16533
+ const total = visualization.total && visualization.total > 0
16534
+ ? visualization.total
16535
+ : Math.max(1, segments.reduce((sum, segment) => sum + Math.max(0, segment.value), 0));
16536
+ const bars = segments
16537
+ .map((segment) => `
16538
+ <span
16539
+ class="pfx-micro-viz__segment"
16540
+ data-tone="${escapeHtml$1(segment.tone ?? visualization.tone ?? 'info')}"
16541
+ style="width:${percent(segment.value, total)}%"
16542
+ title="${escapeHtml$1(`${segment.label ?? ''} ${formatMicroNumber(segment.value, options.locale)}`.trim())}"
16543
+ ></span>`)
16544
+ .join('');
16545
+ const meta = segments
16546
+ .slice(0, 3)
16547
+ .map((segment) => `<span>${escapeHtml$1(segment.label ?? '')}: ${escapeHtml$1(formatMicroNumber(segment.value, options.locale))}</span>`)
16548
+ .join('');
16549
+ return `
16550
+ <span class="pfx-micro-viz" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16551
+ <span class="pfx-micro-viz__segments">${bars}</span>
16552
+ <span class="pfx-micro-viz__meta">${meta}</span>
16553
+ </span>`;
16554
+ }
16555
+ function resolveBulletMax(visualization) {
16556
+ const thresholds = visualization.thresholds ?? [];
16557
+ const values = [
16558
+ toFiniteNumber(visualization.value) ?? 0,
16559
+ visualization.target ?? 0,
16560
+ visualization.total ?? 0,
16561
+ ...thresholds.map(t => t.value)
16562
+ ].filter(v => Number.isFinite(v) && v > 0);
16563
+ return Math.max(...values, 100);
16564
+ }
16565
+ function renderBulletVisualizationHtml(visualization, options) {
16566
+ const currentValue = toFiniteNumber(visualization.value) ?? 0;
16567
+ const max = resolveBulletMax(visualization);
16568
+ const target = toFiniteNumber(visualization.target);
16569
+ const targetLeft = target === undefined ? null : percent(target, max);
16570
+ const isTable = visualization.surface === 'table-cell';
16571
+ // thresholds
16572
+ const thresholds = visualization.thresholds ?? [];
16573
+ let previous = 0;
16574
+ const bands = thresholds.map(t => {
16575
+ const current = Math.max(t.value, previous);
16576
+ const left = max > 0 ? percent(previous, max) : '0';
16577
+ const width = max > 0 ? percent(current - previous, max) : '0';
16578
+ previous = current;
16579
+ return { left, width, tone: t.tone ?? 'info' };
16580
+ }).filter(b => parseFloat(b.width) > 0);
16581
+ const bandsHtml = bands.map(b => `<span class="pfx-micro-bullet__range" data-tone="${escapeHtml$1(b.tone)}" style="left: ${b.left}%; width: ${b.width}%;"></span>`).join('');
16582
+ const topHtml = isTable ? '' : `
16583
+ <div class="pfx-micro-bullet__top">
16584
+ <span class="pfx-micro-bullet__label">${escapeHtml$1(visualization.fallbackText)}</span>
16585
+ <span class="pfx-micro-bullet__value">
16586
+ ${escapeHtml$1(formatMicroNumber(currentValue, options.locale))}
16587
+ ${target === undefined ? '' : `<span class="pfx-micro-bullet__target-val">/ Target: ${escapeHtml$1(formatMicroNumber(target, options.locale))}</span>`}
16588
+ </span>
16589
+ </div>`;
16590
+ const bottomHtml = isTable ? '' : `
16591
+ <div class="pfx-micro-bullet__bottom">
16592
+ <span>${escapeHtml$1(formatMicroNumber(visualization.baseline ?? 0, options.locale))}</span>
16593
+ <span>${escapeHtml$1(formatMicroNumber(max, options.locale))}</span>
16594
+ </div>`;
16595
+ return `
16596
+ <span class="pfx-micro-viz pfx-micro-viz__bullet" data-tone="${escapeHtml$1(visualization.tone ?? 'info')}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16597
+ ${topHtml}
16598
+ <span class="pfx-micro-bullet__track">
16599
+ ${bandsHtml}
16600
+ <span class="pfx-micro-bullet__actual" data-tone="${escapeHtml$1(visualization.tone ?? 'info')}" style="width: ${percent(currentValue, max)}%;"></span>
16601
+ ${targetLeft === null ? '' : `<span class="pfx-micro-bullet__target" style="left: ${targetLeft}%;"></span>`}
16602
+ </span>
16603
+ ${bottomHtml}
16604
+ </span>`;
16605
+ }
16606
+ function renderDeltaVisualizationHtml(visualization, options) {
16607
+ const value = toFiniteNumber(visualization.value);
16608
+ const direction = value === undefined ? 'neutral' : value < 0 ? 'down' : value > 0 ? 'up' : 'neutral';
16609
+ const symbol = direction === 'up' ? '&#9650;' : direction === 'down' ? '&#9660;' : '&rarr;';
16610
+ const tone = visualization.tone ??
16611
+ (value === undefined
16612
+ ? 'neutral'
16613
+ : value < 0
16614
+ ? 'danger'
16615
+ : value > 0
16616
+ ? 'success'
16617
+ : 'neutral');
16618
+ const valueSuffix = visualization.valueSuffix ?? '';
16619
+ const text = value === undefined
16620
+ ? visualization.fallbackText
16621
+ : `${formatMicroNumber(Math.abs(value), options.locale)}${valueSuffix}`;
16622
+ const directionLabel = direction === 'up'
16623
+ ? 'up'
16624
+ : direction === 'down'
16625
+ ? 'down'
16626
+ : 'stable';
16627
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText}: ${directionLabel} ${text}`;
16628
+ return `
16629
+ <span class="pfx-micro-viz pfx-micro-viz__delta" data-tone="${escapeHtml$1(tone)}" data-direction="${escapeHtml$1(direction)}" role="img" aria-label="${escapeHtml$1(aria)}">
16630
+ <span class="pfx-micro-viz__delta-symbol" aria-hidden="true">${symbol}</span>
16631
+ <span>${escapeHtml$1(text)}</span>
16632
+ </span>`;
16633
+ }
16634
+ function percent(value, total) {
16635
+ if (!Number.isFinite(value) || !Number.isFinite(total) || total <= 0) {
16636
+ return '0';
16637
+ }
16638
+ return Math.max(0, Math.min(100, (value / total) * 100)).toFixed(2);
16639
+ }
16640
+ function toFiniteNumber(value) {
16641
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
16642
+ }
16643
+ function formatMicroNumber(value, locale) {
16644
+ return new Intl.NumberFormat(locale || undefined, {
16645
+ maximumFractionDigits: Math.abs(value) < 10 ? 2 : 0,
16646
+ }).format(value);
16647
+ }
16648
+ function escapeHtml$1(value) {
16649
+ return String(value ?? '')
16650
+ .replace(/&/g, '&amp;')
16651
+ .replace(/</g, '&lt;')
16652
+ .replace(/>/g, '&gt;')
16653
+ .replace(/"/g, '&quot;')
16654
+ .replace(/'/g, '&#39;');
16655
+ }
16656
+ function normalizePoints(value) {
16657
+ const points = normalizeNumericEntries(value);
16658
+ return points.length ? { points } : undefined;
16659
+ }
16660
+ function normalizeSegments(value) {
16661
+ const segments = normalizeNumericEntries(value);
16662
+ return segments.length ? { segments } : undefined;
16663
+ }
16664
+ function normalizeThresholds(value) {
16665
+ const thresholds = normalizeNumericEntries(value);
16666
+ return thresholds.length ? { thresholds } : undefined;
16667
+ }
16668
+ function normalizeItems(value) {
16669
+ if (!Array.isArray(value)) {
16670
+ return undefined;
16671
+ }
16672
+ const items = value
16673
+ .map((item) => normalizeVisualizationItem(item))
16674
+ .filter((item) => !!item);
16675
+ return items.length ? { items } : undefined;
16676
+ }
16677
+ function normalizeExpression(value, key) {
16678
+ if (typeof value === 'string') {
16679
+ const normalized = value.trim();
16680
+ return normalized ? { [key]: normalized } : undefined;
16681
+ }
16682
+ if (value && typeof value === 'object') {
16683
+ return { [key]: value };
16684
+ }
16685
+ return undefined;
16686
+ }
16687
+ function normalizeNumericEntries(value) {
16688
+ if (!Array.isArray(value)) {
16689
+ return [];
16690
+ }
16691
+ return value
16692
+ .map((item) => {
16693
+ if (!item || typeof item !== 'object' || !Number.isFinite(item.value)) {
16694
+ return null;
16695
+ }
16696
+ const label = normalizeText$1(item.label);
16697
+ const tone = normalizeEnum$1(item.tone, VISUALIZATION_TONES);
16698
+ return {
16699
+ value: item.value,
16700
+ ...(label ? { label } : {}),
16701
+ ...(tone ? { tone } : {}),
16702
+ };
16703
+ })
16704
+ .filter((item) => !!item);
16705
+ }
16706
+ function normalizeVisualizationItem(item) {
16707
+ if (!item || typeof item !== 'object') {
16708
+ return null;
16709
+ }
16710
+ const id = normalizeText$1(item.id);
16711
+ const label = normalizeText$1(item.label);
16712
+ const icon = normalizeText$1(item.icon);
16713
+ const state = normalizeText$1(item.state);
16714
+ const tone = normalizeEnum$1(item.tone, VISUALIZATION_TONES);
16715
+ const normalizedValue = Number.isFinite(item.value) ? item.value : undefined;
16716
+ if (!id && !label && normalizedValue === undefined && !icon && !state && !tone) {
16717
+ return null;
16718
+ }
16719
+ return {
16720
+ ...(id ? { id } : {}),
16721
+ ...(label ? { label } : {}),
16722
+ ...(normalizedValue !== undefined ? { value: normalizedValue } : {}),
16723
+ ...(icon ? { icon } : {}),
16724
+ ...(state ? { state } : {}),
16725
+ ...(tone ? { tone } : {}),
16726
+ };
16727
+ }
16728
+ function normalizeNumber(value, key) {
16729
+ return Number.isFinite(value) ? { [key]: value } : undefined;
16730
+ }
16731
+ function normalizeEnum$1(value, allowed) {
16732
+ if (typeof value !== 'string') {
16733
+ return undefined;
16734
+ }
16735
+ const normalized = value.trim();
16736
+ return allowed.has(normalized) ? normalized : undefined;
16737
+ }
16738
+ function normalizeText$1(value) {
16739
+ if (typeof value !== 'string') {
16740
+ return undefined;
16741
+ }
16742
+ const trimmed = value.trim();
16743
+ return trimmed.length ? trimmed : undefined;
16744
+ }
16745
+ function renderRadialVisualizationHtml(visualization, options) {
16746
+ const value = toFiniteNumber(visualization.value) ?? 0;
16747
+ const total = visualization.total && visualization.total > 0 ? visualization.total : 100;
16748
+ const pct = Math.max(0, Math.min(100, (value / total) * 100));
16749
+ const tone = visualization.tone ?? 'info';
16750
+ const dashArray = `${pct.toFixed(1)}, 100`;
16751
+ const pctText = `${Math.round(pct)}%`;
16752
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText} (${pctText})`;
16753
+ const isTable = visualization.surface === 'table-cell';
16754
+ const svgText = isTable
16755
+ ? ''
16756
+ : `<text x="18" y="21" class="pfx-micro-radial-svg__text">${escapeHtml$1(pctText)}</text>`;
16757
+ const externalText = isTable
16758
+ ? `<span class="pfx-micro-radial-value">${escapeHtml$1(pctText)}</span>`
16759
+ : '';
16760
+ return `
16761
+ <span class="pfx-micro-viz pfx-micro-viz__radial" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(aria)}">
16762
+ <svg class="pfx-micro-radial-svg" viewBox="0 0 36 36">
16763
+ <circle class="pfx-micro-radial-svg__track" cx="18" cy="18" r="15.9155" />
16764
+ <circle class="pfx-micro-radial-svg__bar" cx="18" cy="18" r="15.9155" stroke-dasharray="${dashArray}" transform="rotate(-90 18 18)" />
16765
+ ${svgText}
16766
+ </svg>
16767
+ ${externalText}
16768
+ </span>`;
16769
+ }
16770
+ function renderHarveyBallVisualizationHtml(visualization, options) {
16771
+ const value = toFiniteNumber(visualization.value) ?? 0;
16772
+ const total = visualization.total && visualization.total > 0 ? visualization.total : 100;
16773
+ const pct = Math.max(0, Math.min(100, (value / total) * 100));
16774
+ const tone = visualization.tone ?? 'info';
16775
+ const strokeLength = pct * 0.50265;
16776
+ const dashArray = `${strokeLength.toFixed(3)} 50.265`;
16777
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText} (${Math.round(pct)}%)`;
16778
+ return `
16779
+ <span class="pfx-micro-viz pfx-micro-viz__harvey" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(aria)}">
16780
+ <svg class="pfx-micro-harvey-svg" viewBox="0 0 36 36">
16781
+ <circle class="pfx-micro-harvey-svg__track" cx="18" cy="18" r="16" />
16782
+ <circle class="pfx-micro-harvey-svg__bar" cx="18" cy="18" r="8" stroke-dasharray="${dashArray}" transform="rotate(-90 18 18)" />
16783
+ </svg>
16784
+ <span class="pfx-micro-harvey-fraction">
16785
+ <strong>${escapeHtml$1(formatMicroNumber(value, options.locale))}</strong>
16786
+ <span class="pfx-separator">/</span>
16787
+ <span class="pfx-total">${escapeHtml$1(formatMicroNumber(total, options.locale))}</span>
16788
+ </span>
16789
+ </span>`;
16790
+ }
16791
+ function getPointsCoordinates(points, width, height, padding) {
16792
+ if (points.length < 2)
16793
+ return [];
16794
+ const values = points.map(p => p.value);
16795
+ const minVal = Math.min(...values);
16796
+ const maxVal = Math.max(...values);
16797
+ const valRange = maxVal - minVal === 0 ? 1 : maxVal - minVal;
16798
+ return points.map((p, index) => {
16799
+ const x = padding + (index / (points.length - 1)) * (width - 2 * padding);
16800
+ const y = height - padding - ((p.value - minVal) / valRange) * (height - 2 * padding);
16801
+ return { x, y };
16802
+ });
16803
+ }
16804
+ function renderLineVisualizationHtml(visualization, options) {
16805
+ const points = visualization.points ?? [];
16806
+ const tone = visualization.tone ?? 'info';
16807
+ if (points.length < 2) {
16808
+ return renderFallbackVisualizationHtml(visualization, tone);
16809
+ }
16810
+ const width = 100;
16811
+ const height = 30;
16812
+ const padding = 4;
16813
+ const coords = getPointsCoordinates(points, width, height, padding);
16814
+ const pathD = coords.map((c, i) => `${i === 0 ? 'M' : 'L'} ${c.x.toFixed(1)} ${c.y.toFixed(1)}`).join(' ');
16815
+ // Highlight extreme/boundary values
16816
+ let minIdx = 0;
16817
+ let maxIdx = 0;
16818
+ for (let i = 1; i < points.length; i++) {
16819
+ if (points[i].value < points[minIdx].value)
16820
+ minIdx = i;
16821
+ if (points[i].value > points[maxIdx].value)
16822
+ maxIdx = i;
16823
+ }
16824
+ const markers = [
16825
+ { x: coords[0].x, y: coords[0].y, tone: points[0].tone ?? tone },
16826
+ { x: coords[coords.length - 1].x, y: coords[coords.length - 1].y, tone: points[points.length - 1].tone ?? tone }
16827
+ ];
16828
+ if (minIdx !== 0 && minIdx !== coords.length - 1) {
16829
+ markers.push({ x: coords[minIdx].x, y: coords[minIdx].y, tone: points[minIdx].tone ?? 'danger' });
16830
+ }
16831
+ if (maxIdx !== 0 && maxIdx !== coords.length - 1) {
16832
+ markers.push({ x: coords[maxIdx].x, y: coords[maxIdx].y, tone: points[maxIdx].tone ?? 'success' });
16833
+ }
16834
+ const circlesHtml = markers.map(c => `<circle cx="${c.x.toFixed(1)}" cy="${c.y.toFixed(1)}" r="2.5" class="pfx-micro-trend__marker" data-tone="${escapeHtml$1(c.tone)}" />`).join('');
16835
+ const isTable = visualization.surface === 'table-cell';
16836
+ const firstPoint = points[0];
16837
+ const lastPoint = points[points.length - 1];
16838
+ const leftHtml = isTable ? '' : `
16839
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16840
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16841
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16842
+ </div>`;
16843
+ const rightHtml = isTable ? '' : `
16844
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16845
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16846
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16847
+ </div>`;
16848
+ return `
16849
+ <span class="pfx-micro-viz-container">
16850
+ ${leftHtml}
16851
+ <span class="pfx-micro-viz pfx-micro-viz__line" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16852
+ <svg class="pfx-micro-line__svg" viewBox="0 0 100 30">
16853
+ <path class="pfx-micro-line__path" d="${pathD}" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
16854
+ ${circlesHtml}
16855
+ </svg>
16856
+ </span>
16857
+ ${rightHtml}
16858
+ </span>`;
16859
+ }
16860
+ function renderAreaVisualizationHtml(visualization, options) {
16861
+ const points = visualization.points ?? [];
16862
+ const tone = visualization.tone ?? 'info';
16863
+ if (points.length < 2) {
16864
+ return renderFallbackVisualizationHtml(visualization, tone);
16865
+ }
16866
+ const width = 100;
16867
+ const height = 30;
16868
+ const padding = 4;
16869
+ const coords = getPointsCoordinates(points, width, height, padding);
16870
+ const lineD = coords.map((c, i) => `${i === 0 ? 'M' : 'L'} ${c.x.toFixed(1)} ${c.y.toFixed(1)}`).join(' ');
16871
+ const firstX = coords[0].x.toFixed(1);
16872
+ const lastX = coords[coords.length - 1].x.toFixed(1);
16873
+ const areaD = `${lineD} L ${lastX} ${height} L ${firstX} ${height} Z`;
16874
+ // Highlight extreme/boundary values
16875
+ let minIdx = 0;
16876
+ let maxIdx = 0;
16877
+ for (let i = 1; i < points.length; i++) {
16878
+ if (points[i].value < points[minIdx].value)
16879
+ minIdx = i;
16880
+ if (points[i].value > points[maxIdx].value)
16881
+ maxIdx = i;
16882
+ }
16883
+ const markers = [
16884
+ { x: coords[0].x, y: coords[0].y, tone: points[0].tone ?? tone },
16885
+ { x: coords[coords.length - 1].x, y: coords[coords.length - 1].y, tone: points[points.length - 1].tone ?? tone }
16886
+ ];
16887
+ if (minIdx !== 0 && minIdx !== coords.length - 1) {
16888
+ markers.push({ x: coords[minIdx].x, y: coords[minIdx].y, tone: points[minIdx].tone ?? 'danger' });
16889
+ }
16890
+ if (maxIdx !== 0 && maxIdx !== coords.length - 1) {
16891
+ markers.push({ x: coords[maxIdx].x, y: coords[maxIdx].y, tone: points[maxIdx].tone ?? 'success' });
16892
+ }
16893
+ const circlesHtml = markers.map(c => `<circle cx="${c.x.toFixed(1)}" cy="${c.y.toFixed(1)}" r="2.5" class="pfx-micro-trend__marker" data-tone="${escapeHtml$1(c.tone)}" />`).join('');
16894
+ const isTable = visualization.surface === 'table-cell';
16895
+ const firstPoint = points[0];
16896
+ const lastPoint = points[points.length - 1];
16897
+ const leftHtml = isTable ? '' : `
16898
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16899
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16900
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16901
+ </div>`;
16902
+ const rightHtml = isTable ? '' : `
16903
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16904
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16905
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16906
+ </div>`;
16907
+ return `
16908
+ <span class="pfx-micro-viz-container">
16909
+ ${leftHtml}
16910
+ <span class="pfx-micro-viz pfx-micro-viz__area" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16911
+ <svg class="pfx-micro-area__svg" viewBox="0 0 100 30">
16912
+ <path class="pfx-micro-area__fill" d="${areaD}" fill="currentColor" fill-opacity="0.15" />
16913
+ <path class="pfx-micro-area__path" d="${lineD}" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
16914
+ ${circlesHtml}
16915
+ </svg>
16916
+ </span>
16917
+ ${rightHtml}
16918
+ </span>`;
16919
+ }
16920
+ function renderColumnVisualizationHtml(visualization, options) {
16921
+ const points = visualization.points ?? [];
16922
+ const tone = visualization.tone ?? 'info';
16923
+ if (points.length === 0) {
16924
+ return renderFallbackVisualizationHtml(visualization, tone);
16925
+ }
16926
+ const width = 100;
16927
+ const height = 30;
16928
+ const padding = 4;
16929
+ const values = points.map(p => p.value);
16930
+ const maxVal = Math.max(...values, 0);
16931
+ const minVal = Math.min(...values, 0);
16932
+ const valRange = maxVal - minVal === 0 ? 1 : maxVal - minVal;
16933
+ const colWidth = Math.max(2, (width - 2 * padding) / points.length - 2);
16934
+ const columnsHtml = points.map((p, i) => {
16935
+ const x = padding + i * ((width - 2 * padding) / points.length) + 1;
16936
+ const rectHeight = Math.max(2, ((p.value - minVal) / valRange) * (height - 2 * padding));
16937
+ const rectY = height - padding - rectHeight;
16938
+ const itemTone = p.tone ?? tone;
16939
+ return `<rect class="pfx-micro-column__bar" x="${x.toFixed(1)}" y="${rectY.toFixed(1)}" width="${colWidth.toFixed(1)}" height="${rectHeight.toFixed(1)}" fill="currentColor" data-tone="${escapeHtml$1(itemTone)}" />`;
16940
+ }).join('');
16941
+ const isTable = visualization.surface === 'table-cell';
16942
+ const firstPoint = points[0];
16943
+ const lastPoint = points[points.length - 1];
16944
+ const leftHtml = isTable ? '' : `
16945
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16946
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16947
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16948
+ </div>`;
16949
+ const rightHtml = isTable ? '' : `
16950
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16951
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16952
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16953
+ </div>`;
16954
+ return `
16955
+ <span class="pfx-micro-viz-container">
16956
+ ${leftHtml}
16957
+ <span class="pfx-micro-viz pfx-micro-viz__column" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16958
+ <svg class="pfx-micro-column__svg" viewBox="0 0 100 30">
16959
+ ${columnsHtml}
16960
+ </svg>
16961
+ </span>
16962
+ ${rightHtml}
16963
+ </span>`;
16964
+ }
16965
+ function renderProcessFlowVisualizationHtml(visualization, options) {
16966
+ const items = visualization.items ?? [];
16967
+ if (items.length === 0) {
16968
+ return renderFallbackVisualizationHtml(visualization, visualization.tone ?? 'neutral');
16969
+ }
16970
+ const isTable = visualization.surface === 'table-cell';
16971
+ const stepLabels = items.map((item, index) => item.label ?? item.id ?? `${index + 1}`);
16972
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText}: ${stepLabels.join(' > ')}`;
16973
+ const stepsHtml = items.map((item, index) => {
16974
+ const itemTone = item.tone ?? 'neutral';
16975
+ const itemState = item.state ?? '';
16976
+ const isLast = index === items.length - 1;
16977
+ const itemLabel = stepLabels[index];
16978
+ const label = !isTable && item.label ? `<span class="pfx-micro-step__label">${escapeHtml$1(item.label)}</span>` : '';
16979
+ const connector = !isLast ? `<span class="pfx-micro-step__connector" data-tone="${escapeHtml$1(itemTone)}"></span>` : '';
16980
+ const stepCircle = `
16981
+ <span class="pfx-micro-step__node" data-tone="${escapeHtml$1(itemTone)}" aria-hidden="true">
16982
+ ${item.icon ? `<span class="material-icons pfx-micro-step__icon" aria-hidden="true">${escapeHtml$1(item.icon)}</span>` : `${index + 1}`}
16983
+ </span>`;
16984
+ return `
16985
+ <div class="pfx-micro-step" data-state="${escapeHtml$1(itemState)}" data-tone="${escapeHtml$1(itemTone)}">
16986
+ <div class="pfx-micro-step__node-wrapper" title="${escapeHtml$1(itemLabel)}">
16987
+ ${stepCircle}
16988
+ ${label}
16989
+ </div>
16990
+ ${connector}
16991
+ </div>`;
16992
+ }).join('');
16993
+ return `
16994
+ <span class="pfx-micro-viz pfx-micro-viz__process" role="img" aria-label="${escapeHtml$1(aria)}">
16995
+ ${stepsHtml}
16996
+ </span>`;
16997
+ }
16998
+ function renderFallbackVisualizationHtml(visualization, tone) {
16999
+ return `
17000
+ <span
17001
+ class="pfx-micro-viz pfx-micro-viz__fallback"
17002
+ data-tone="${escapeHtml$1(tone)}"
17003
+ role="img"
17004
+ aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}"
17005
+ >${escapeHtml$1(visualization.fallbackText)}</span>`;
17006
+ }
17007
+
17008
+ const TONES = new Set([
17009
+ 'neutral',
17010
+ 'info',
17011
+ 'success',
17012
+ 'warning',
17013
+ 'danger',
17014
+ ]);
17015
+ const APPEARANCES = new Set([
17016
+ 'plain',
17017
+ 'soft',
17018
+ 'outlined',
17019
+ 'filled',
17020
+ ]);
17021
+ const PRESENTERS = new Set([
17022
+ 'text',
17023
+ 'badge',
17024
+ 'chip',
17025
+ 'status',
17026
+ 'iconValue',
17027
+ 'progress',
17028
+ 'rating',
17029
+ 'microVisualization',
17030
+ ]);
17031
+ /**
17032
+ * Resolves readonly field presentation from a base semantic config plus ordered
17033
+ * Json Logic rules. Later matching rules override earlier presentation values.
17034
+ */
17035
+ function resolveFieldPresentation(base, rules, context = {}, options = {}) {
17036
+ let resolved = normalizeFieldPresentation(base);
17037
+ let matchedRule = false;
17038
+ if (!Array.isArray(rules) || !options.jsonLogic) {
17039
+ return resolved;
17040
+ }
17041
+ for (const rule of rules) {
17042
+ if (!rule?.when || !matchesPresentationRule(rule, context, options.jsonLogic)) {
17043
+ continue;
17044
+ }
17045
+ const effect = normalizeFieldPresentation(rule.set ?? rule.effect);
17046
+ resolved = {
17047
+ ...resolved,
17048
+ ...effect,
17049
+ };
17050
+ matchedRule = true;
17051
+ }
17052
+ return matchedRule ? { ...resolved, matchedRule } : resolved;
17053
+ }
17054
+ function normalizeFieldPresentation(value) {
17055
+ if (!value || typeof value !== 'object') {
17056
+ return {};
17057
+ }
17058
+ const presenter = normalizePresenter(value.presenter ?? value.variant);
17059
+ const tone = normalizeTone(value.tone);
17060
+ const appearance = normalizeAppearance(value.appearance);
17061
+ const icon = normalizeText(value.icon);
17062
+ const label = normalizeText(value.label);
17063
+ const badge = normalizeText(value.badge);
17064
+ const tooltip = normalizeText(value.tooltip);
17065
+ const visualization = normalizePraxisPresentationVisualization(value.visualization);
17066
+ return {
17067
+ ...(presenter ? { presenter } : {}),
17068
+ ...(tone ? { tone } : {}),
17069
+ ...(appearance ? { appearance } : {}),
17070
+ ...(icon ? { icon } : {}),
17071
+ ...(label ? { label } : {}),
17072
+ ...(badge ? { badge } : {}),
17073
+ ...(tooltip ? { tooltip } : {}),
17074
+ ...(value.valuePresentation && typeof value.valuePresentation === 'object'
17075
+ ? { valuePresentation: value.valuePresentation }
17076
+ : {}),
17077
+ ...(visualization ? { visualization } : {}),
17078
+ ...(value.interactions && typeof value.interactions === 'object'
17079
+ ? { interactions: normalizeInteractions(value.interactions) }
17080
+ : {}),
17081
+ };
17082
+ }
17083
+ function matchesPresentationRule(rule, context, jsonLogic) {
17084
+ try {
17085
+ const result = jsonLogic.evaluate(rule.when, context);
17086
+ return typeof jsonLogic.truthy === 'function'
17087
+ ? jsonLogic.truthy(result)
17088
+ : Boolean(result);
17089
+ }
17090
+ catch {
17091
+ return false;
17092
+ }
17093
+ }
17094
+ function normalizePresenter(value) {
17095
+ return normalizeEnum(value, PRESENTERS);
17096
+ }
17097
+ function normalizeTone(value) {
17098
+ return normalizeEnum(value, TONES);
17099
+ }
17100
+ function normalizeAppearance(value) {
17101
+ return normalizeEnum(value, APPEARANCES);
17102
+ }
17103
+ function normalizeEnum(value, allowed) {
17104
+ if (typeof value !== 'string') {
17105
+ return undefined;
17106
+ }
17107
+ const normalized = value.trim();
17108
+ return allowed.has(normalized) ? normalized : undefined;
17109
+ }
17110
+ function normalizeText(value) {
17111
+ if (typeof value !== 'string') {
17112
+ return undefined;
17113
+ }
17114
+ const trimmed = value.trim();
17115
+ return trimmed.length ? trimmed : undefined;
17116
+ }
17117
+ function normalizeInteractions(value) {
17118
+ return {
17119
+ ...(value.copy === true ? { copy: true } : {}),
17120
+ ...(value.details === true ? { details: true } : {}),
17121
+ ...(value.expand === true ? { expand: true } : {}),
17122
+ ...(value.link === true ? { link: true } : {}),
17123
+ };
17124
+ }
17125
+
16019
17126
  /**
16020
17127
  * @fileoverview Specialized metadata interfaces for Angular Material components
16021
17128
  *
@@ -16392,6 +17499,37 @@ function normalizeSelectLike(meta) {
16392
17499
  return m;
16393
17500
  }
16394
17501
 
17502
+ const SERVER_OWNED_FIELD_SEMANTIC_KEYS = [
17503
+ 'label',
17504
+ 'hint',
17505
+ 'helpText',
17506
+ 'description',
17507
+ 'tooltip',
17508
+ 'tooltipOnHover',
17509
+ 'icon',
17510
+ 'prefixIcon',
17511
+ 'suffixIcon',
17512
+ 'iconPosition',
17513
+ 'iconSize',
17514
+ 'iconColor',
17515
+ 'iconClass',
17516
+ 'iconStyle',
17517
+ 'iconFontSize',
17518
+ ];
17519
+ function applyServerOwnedFieldSemantics(merged, serverField) {
17520
+ const next = { ...merged };
17521
+ const server = serverField;
17522
+ for (const key of SERVER_OWNED_FIELD_SEMANTIC_KEYS) {
17523
+ if (server[key] === undefined) {
17524
+ delete next[key];
17525
+ }
17526
+ else {
17527
+ next[key] = server[key];
17528
+ }
17529
+ }
17530
+ return next;
17531
+ }
17532
+
16395
17533
  function createDefaultFormConfig() {
16396
17534
  const config = {
16397
17535
  sections: [
@@ -16554,7 +17692,7 @@ function syncWithServerMetadata(localConfig, serverMetadata) {
16554
17692
  toggleOptions: pick('toggleOptions'),
16555
17693
  nodes: pick('nodes'),
16556
17694
  };
16557
- mergedOverlapping.push(merged);
17695
+ mergedOverlapping.push(applyServerOwnedFieldSemantics(merged, serverField));
16558
17696
  // Track simple modifications for diagnostics
16559
17697
  ['label', 'required', 'maxLength', 'minLength', 'dataType', 'controlType'].forEach((prop) => {
16560
17698
  if (loc[prop] !== base[prop]) {
@@ -16894,7 +18032,7 @@ const EVENT_REGISTRATION_EDITORIAL_TEMPLATE = {
16894
18032
  content: [
16895
18033
  {
16896
18034
  type: 'text',
16897
- text: 'Ao enviar a inscricao, o participante reconhece o tratamento dos dados para credenciamento, comunicacoes e operacao do evento.',
18035
+ text: 'Ao enviar a inscrição, o participante reconhece o tratamento dos dados para credenciamento, comunicações e operação do evento.',
16898
18036
  },
16899
18037
  ],
16900
18038
  }),
@@ -17035,7 +18173,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17035
18173
  wrap: true,
17036
18174
  items: [
17037
18175
  { type: 'badge', label: 'onboarding' },
17038
- { type: 'text', text: 'Admissao, conferencia e preferencias iniciais' },
18176
+ { type: 'text', text: 'Admissão, conferência e preferências iniciais' },
17039
18177
  ],
17040
18178
  },
17041
18179
  }, {
@@ -17044,7 +18182,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17044
18182
  subtitle: 'Resumo do fluxo',
17045
18183
  content: [
17046
18184
  { type: 'text', text: 'Dados pessoais e de contato.' },
17047
- { type: 'text', text: 'Preferencias operacionais iniciais.' },
18185
+ { type: 'text', text: 'Preferências operacionais iniciais.' },
17048
18186
  { type: 'text', text: 'Anexos e termos obrigatorios.' },
17049
18187
  ],
17050
18188
  }),
@@ -17076,7 +18214,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17076
18214
  id: 'operations',
17077
18215
  appearance: 'step',
17078
18216
  stepLabel: '2',
17079
- title: 'Operacao inicial',
18217
+ title: 'Operação inicial',
17080
18218
  description: 'Dados para preparacao do ambiente e comunicacao inicial.',
17081
18219
  rows: [
17082
18220
  {
@@ -17102,7 +18240,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17102
18240
  title: 'Uso interno',
17103
18241
  subtitle: 'Antes do envio',
17104
18242
  badge: 'info',
17105
- description: 'As informacoes deste fluxo sao usadas exclusivamente para cadastro interno, provisionamento e comunicacao de onboarding.',
18243
+ description: 'As informações deste fluxo são usadas exclusivamente para cadastro interno, provisionamento e comunicação de onboarding.',
17106
18244
  }),
17107
18245
  formBlocksBeforeActionsPlacement: 'afterSections',
17108
18246
  actions: {
@@ -17151,7 +18289,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17151
18289
  required: true,
17152
18290
  options: [
17153
18291
  { text: 'Presencial', value: 'ONSITE' },
17154
- { text: 'Hibrido', value: 'HYBRID' },
18292
+ { text: 'Híbrido', value: 'HYBRID' },
17155
18293
  { text: 'Remoto', value: 'REMOTE' },
17156
18294
  ],
17157
18295
  },
@@ -17162,22 +18300,22 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17162
18300
  required: true,
17163
18301
  options: [
17164
18302
  { text: 'Sim', value: 'YES' },
17165
- { text: 'Nao', value: 'NO' },
18303
+ { text: 'Não', value: 'NO' },
17166
18304
  ],
17167
18305
  },
17168
18306
  {
17169
18307
  name: 'shippingAddress',
17170
- label: 'Endereco para envio',
18308
+ label: 'Endereço para envio',
17171
18309
  controlType: 'textarea',
17172
18310
  },
17173
18311
  {
17174
18312
  name: 'accessibilityNotes',
17175
- label: 'Observacoes de acessibilidade ou preferencias',
18313
+ label: 'Observações de acessibilidade ou preferências',
17176
18314
  controlType: 'textarea',
17177
18315
  },
17178
18316
  {
17179
18317
  name: 'privacyConsent',
17180
- label: 'Confirmo ciencia sobre o tratamento dos meus dados no processo de onboarding.',
18318
+ label: 'Confirmo ciência sobre o tratamento dos meus dados no processo de onboarding.',
17181
18319
  controlType: 'checkbox',
17182
18320
  selectionMode: 'boolean',
17183
18321
  variant: 'consent',
@@ -17250,7 +18388,7 @@ const EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE = {
17250
18388
  id: 'operations',
17251
18389
  appearance: 'step',
17252
18390
  stepLabel: '2',
17253
- title: 'Operacao inicial',
18391
+ title: 'Operação inicial',
17254
18392
  description: 'Configure os recursos necessarios para o primeiro dia.',
17255
18393
  rows: [
17256
18394
  {
@@ -17360,17 +18498,17 @@ const EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE = {
17360
18498
  options: [
17361
18499
  { text: 'Presencial', value: 'Presencial' },
17362
18500
  { text: 'Remoto', value: 'Remoto' },
17363
- { text: 'Hibrido', value: 'Hibrido' },
18501
+ { text: 'Híbrido', value: 'Híbrido' },
17364
18502
  ],
17365
18503
  },
17366
18504
  {
17367
18505
  name: 'accessibilityNotes',
17368
- label: 'Observacoes adicionais',
18506
+ label: 'Observações adicionais',
17369
18507
  controlType: 'textarea',
17370
18508
  },
17371
18509
  {
17372
18510
  name: 'privacyConsent',
17373
- label: 'Confirmo ciencia sobre o tratamento dos meus dados no processo de onboarding.',
18511
+ label: 'Confirmo ciência sobre o tratamento dos meus dados no processo de onboarding.',
17374
18512
  controlType: 'checkbox',
17375
18513
  selectionMode: 'boolean',
17376
18514
  variant: 'consent',
@@ -17386,7 +18524,7 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17386
18524
  version: '1.0.0',
17387
18525
  metadata: {
17388
18526
  title: 'Privacy Consent',
17389
- description: 'Template focado em aceite explicito, base legal, preferencias de comunicacao e registro de consentimento.',
18527
+ description: 'Template focado em aceite explícito, base legal, preferências de comunicação e registro de consentimento.',
17390
18528
  category: 'consent',
17391
18529
  tags: ['privacy', 'consent', 'compliance', 'legal'],
17392
18530
  source: 'catalog',
@@ -17408,13 +18546,13 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17408
18546
  title: 'Consentimento e tratamento de dados',
17409
18547
  subtitle: 'Template regulatorio',
17410
18548
  badge: 'info',
17411
- description: 'Use este template quando o objetivo principal do fluxo for registrar ciencia, aceite e preferencias relacionadas a privacidade.',
18549
+ description: 'Use este template quando o objetivo principal do fluxo for registrar ciência, aceite e preferências relacionadas a privacidade.',
17412
18550
  }),
17413
18551
  sections: [
17414
18552
  {
17415
18553
  id: 'consent',
17416
18554
  appearance: 'card',
17417
- title: 'Preferencias e consentimentos',
18555
+ title: 'Preferências e consentimentos',
17418
18556
  description: 'Aceites explicitos e canais opcionais de comunicacao.',
17419
18557
  rows: [
17420
18558
  {
@@ -17497,7 +18635,7 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17497
18635
  },
17498
18636
  {
17499
18637
  name: 'consentNotes',
17500
- label: 'Observacoes adicionais',
18638
+ label: 'Observações adicionais',
17501
18639
  controlType: 'textarea',
17502
18640
  },
17503
18641
  ],
@@ -17533,6 +18671,8 @@ const RULE_PROPERTY_SCHEMA = {
17533
18671
  { name: 'tooltip', type: 'string', label: 'Tooltip' },
17534
18672
  { name: 'prefixIcon', type: 'string', label: 'Ícone prefixo' },
17535
18673
  { name: 'suffixIcon', type: 'string', label: 'Ícone sufixo' },
18674
+ { name: 'presentation', type: 'object', label: 'Apresentação', category: 'appearance' },
18675
+ { name: 'presentationRules', type: 'array', label: 'Regras de apresentação', category: 'appearance' },
17536
18676
  { name: 'prefixText', type: 'string', label: 'Texto prefixo' },
17537
18677
  { name: 'suffixText', type: 'string', label: 'Texto sufixo' },
17538
18678
  { name: 'defaultValue', type: 'object', label: 'Valor padrão' },
@@ -18256,8 +19396,8 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION = {
18256
19396
  fields: [
18257
19397
  { key: 'selectedEquipment', label: 'Equipamentos', valuePath: 'formData.selectedEquipment', hideWhenEmpty: true },
18258
19398
  { key: 'needsEquipment', label: 'Necessita envio de equipamento', valuePath: 'formData.needsEquipment', hideWhenEmpty: true },
18259
- { key: 'shippingAddress', label: 'Endereco para envio', valuePath: 'formData.shippingAddress', hideWhenEmpty: true },
18260
- { key: 'accessibilityNotes', label: 'Observacoes adicionais', valuePath: 'formData.accessibilityNotes', hideWhenEmpty: true },
19399
+ { key: 'shippingAddress', label: 'Endereço para envio', valuePath: 'formData.shippingAddress', hideWhenEmpty: true },
19400
+ { key: 'accessibilityNotes', label: 'Observações adicionais', valuePath: 'formData.accessibilityNotes', hideWhenEmpty: true },
18261
19401
  ],
18262
19402
  },
18263
19403
  ],
@@ -19566,6 +20706,274 @@ const ValidationPattern = {
19566
20706
  CUSTOM: '',
19567
20707
  };
19568
20708
 
20709
+ function materializeFormLayoutFromMetadata(fields, options = {}) {
20710
+ const policy = normalizeLayoutPolicy(options.policy);
20711
+ const visibleFields = normalizeFields(fields, options.includeHidden === true);
20712
+ const groupedFields = groupFields(visibleFields);
20713
+ const sections = groupedFields.map(([groupKey, groupFields], sectionIndex) => createSection(groupKey, groupFields, sectionIndex, policy, options));
20714
+ return ensureIds({
20715
+ sections,
20716
+ fieldMetadata: fieldsForPolicy(visibleFields, policy),
20717
+ metadata: {
20718
+ version: '1.0.0',
20719
+ lastUpdated: new Date(),
20720
+ source: 'schema',
20721
+ generatedLayoutPreset: policy.preset,
20722
+ schemaLayoutPolicy: policy,
20723
+ ...(policy.preset === 'compactPresentation'
20724
+ ? { presentationDensity: 'compact' }
20725
+ : {}),
20726
+ },
20727
+ });
20728
+ }
20729
+ function normalizeLayoutPolicy(policy) {
20730
+ const intent = policy?.intent ?? (policy?.preset === 'groupedCommand' ? 'command' : 'detail');
20731
+ const preset = policy?.preset ?? (intent === 'command' ? 'groupedCommand' : 'compactPresentation');
20732
+ return {
20733
+ source: policy?.source ?? 'authored',
20734
+ preset,
20735
+ intent,
20736
+ lifecycle: policy?.lifecycle ?? 'initial',
20737
+ persistence: policy?.persistence ?? 'authorable',
20738
+ detachBehavior: policy?.detachBehavior ?? 'none',
20739
+ schemaOperation: policy?.schemaOperation,
20740
+ schemaType: policy?.schemaType,
20741
+ };
20742
+ }
20743
+ function normalizeFields(fields, includeHidden) {
20744
+ return (fields || [])
20745
+ .filter((field) => !!field?.name)
20746
+ .filter((field) => includeHidden || !isFormHidden(field))
20747
+ .sort(compareFields);
20748
+ }
20749
+ function isFormHidden(field) {
20750
+ const anyField = field;
20751
+ return anyField.formHidden === true || anyField.hidden === true || anyField.visible === false;
20752
+ }
20753
+ function groupFields(fields) {
20754
+ const groups = new Map();
20755
+ for (const field of fields) {
20756
+ const groupKey = normalizeGroupLabel(field.group);
20757
+ groups.set(groupKey, [...(groups.get(groupKey) || []), field]);
20758
+ }
20759
+ return Array.from(groups.entries()).sort(([, left], [, right]) => compareGroupFields(left, right));
20760
+ }
20761
+ function createSection(groupKey, groupFields, sectionIndex, policy, options) {
20762
+ const title = groupKey === 'default'
20763
+ ? options.defaultSectionTitle || 'Informacoes'
20764
+ : groupKey;
20765
+ const sectionId = stableSectionId(groupKey);
20766
+ const presentationRole = resolvePresentationRole(groupKey, groupFields, options.presentationRoleMap);
20767
+ return {
20768
+ id: sectionId,
20769
+ title,
20770
+ ...(policy.preset === 'compactPresentation'
20771
+ ? {
20772
+ icon: resolvePresentationSectionIcon(presentationRole),
20773
+ sectionHeader: {
20774
+ mode: 'icon',
20775
+ size: 'sm',
20776
+ fallbackIcon: resolvePresentationSectionIcon(presentationRole),
20777
+ },
20778
+ className: [
20779
+ 'pdx-presentation-section',
20780
+ `pdx-presentation-section--${presentationRole}`,
20781
+ ].join(' '),
20782
+ presentationRole,
20783
+ appearance: 'plain',
20784
+ }
20785
+ : {}),
20786
+ rows: policy.preset === 'groupedCommand'
20787
+ ? createCommandRows(groupFields, sectionId)
20788
+ : createPresentationRows(groupFields, sectionId),
20789
+ };
20790
+ }
20791
+ function createPresentationRows(fields, sectionId) {
20792
+ const rows = [];
20793
+ let pending = [];
20794
+ let pendingSpan = 0;
20795
+ let rowIndex = 0;
20796
+ const flush = () => {
20797
+ if (!pending.length)
20798
+ return;
20799
+ rows.push({ id: `${sectionId}-row-${++rowIndex}`, columns: pending });
20800
+ pending = [];
20801
+ pendingSpan = 0;
20802
+ };
20803
+ for (const field of fields) {
20804
+ const span = hasExplicitWidth(field)
20805
+ ? resolveCommandSpan(field)
20806
+ : { xs: 12, sm: 12, md: 12, lg: 12, xl: 12 };
20807
+ const mdSpan = span.md ?? 12;
20808
+ const column = {
20809
+ id: `${sectionId}-col-${field.name}`,
20810
+ fields: [field.name],
20811
+ items: [{ id: `${sectionId}-item-${field.name}`, kind: 'field', fieldName: field.name }],
20812
+ span,
20813
+ };
20814
+ if (mdSpan >= 12) {
20815
+ flush();
20816
+ pending = [column];
20817
+ flush();
20818
+ continue;
20819
+ }
20820
+ if (pendingSpan + mdSpan > 12) {
20821
+ flush();
20822
+ }
20823
+ pending.push(column);
20824
+ pendingSpan += mdSpan;
20825
+ }
20826
+ flush();
20827
+ return rows;
20828
+ }
20829
+ function createCommandRows(fields, sectionId) {
20830
+ const rows = [];
20831
+ let pending = [];
20832
+ let pendingSpan = 0;
20833
+ let rowIndex = 0;
20834
+ const flush = () => {
20835
+ if (!pending.length)
20836
+ return;
20837
+ rows.push({ id: `${sectionId}-row-${++rowIndex}`, columns: pending });
20838
+ pending = [];
20839
+ pendingSpan = 0;
20840
+ };
20841
+ for (const field of fields) {
20842
+ const span = resolveCommandSpan(field);
20843
+ const mdSpan = span.md ?? 12;
20844
+ const column = {
20845
+ id: `${sectionId}-col-${field.name}`,
20846
+ fields: [field.name],
20847
+ items: [{ id: `${sectionId}-item-${field.name}`, kind: 'field', fieldName: field.name }],
20848
+ span,
20849
+ };
20850
+ if (mdSpan >= 12) {
20851
+ flush();
20852
+ pending = [column];
20853
+ flush();
20854
+ continue;
20855
+ }
20856
+ if (pendingSpan + mdSpan > 12) {
20857
+ flush();
20858
+ }
20859
+ pending.push(column);
20860
+ pendingSpan += mdSpan;
20861
+ }
20862
+ flush();
20863
+ return rows;
20864
+ }
20865
+ function resolveCommandSpan(field) {
20866
+ const rawWidth = field.width;
20867
+ const numericWidth = typeof rawWidth === 'number'
20868
+ ? rawWidth
20869
+ : typeof rawWidth === 'string' && /^\d+$/.test(rawWidth.trim())
20870
+ ? Number(rawWidth.trim())
20871
+ : null;
20872
+ if (numericWidth != null && Number.isFinite(numericWidth)) {
20873
+ const span = Math.max(1, Math.min(12, Math.round(numericWidth)));
20874
+ return {
20875
+ xs: 12,
20876
+ sm: span >= 6 ? 12 : 6,
20877
+ md: span,
20878
+ lg: span,
20879
+ xl: span,
20880
+ };
20881
+ }
20882
+ const width = String(rawWidth || '').toLowerCase();
20883
+ const controlType = String(field.controlType || field.type || '').toLowerCase();
20884
+ if (width === 'full' ||
20885
+ width === 'xl' ||
20886
+ controlType.includes('textarea') ||
20887
+ controlType.includes('rich') ||
20888
+ controlType.includes('file') ||
20889
+ controlType.includes('autocomplete') ||
20890
+ controlType.includes('lookup')) {
20891
+ return { xs: 12, sm: 12, md: 12, lg: 12, xl: 12 };
20892
+ }
20893
+ if (width === 'lg')
20894
+ return { xs: 12, sm: 12, md: 8, lg: 8, xl: 8 };
20895
+ if (width === 'md')
20896
+ return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
20897
+ if (width === 'sm')
20898
+ return { xs: 12, sm: 6, md: 4, lg: 4, xl: 4 };
20899
+ if (width === 'xs' || controlType.includes('checkbox') || controlType.includes('toggle')) {
20900
+ return { xs: 12, sm: 6, md: 3, lg: 3, xl: 3 };
20901
+ }
20902
+ return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
20903
+ }
20904
+ function hasExplicitWidth(field) {
20905
+ const rawWidth = field.width;
20906
+ return rawWidth !== undefined && rawWidth !== null && String(rawWidth).trim() !== '';
20907
+ }
20908
+ function fieldsForPolicy(fields, policy) {
20909
+ if (policy.preset !== 'compactPresentation') {
20910
+ return fields;
20911
+ }
20912
+ return fields.map((field) => ({
20913
+ ...field,
20914
+ readOnly: true,
20915
+ presentationMode: field.presentationMode ?? true,
20916
+ valuePresentation: {
20917
+ ...(field.valuePresentation || {}),
20918
+ density: (field.valuePresentation || {}).density ?? 'compact',
20919
+ },
20920
+ }));
20921
+ }
20922
+ function compareGroupFields(left, right) {
20923
+ return compareFields(left[0], right[0]);
20924
+ }
20925
+ function compareFields(left, right) {
20926
+ const leftOrder = typeof left?.order === 'number' ? left.order : Number.MAX_SAFE_INTEGER;
20927
+ const rightOrder = typeof right?.order === 'number' ? right.order : Number.MAX_SAFE_INTEGER;
20928
+ if (leftOrder !== rightOrder)
20929
+ return leftOrder - rightOrder;
20930
+ return String(left?.name || '').localeCompare(String(right?.name || ''));
20931
+ }
20932
+ function normalizeGroupLabel(group) {
20933
+ const value = String(group || '').trim();
20934
+ return value || 'default';
20935
+ }
20936
+ function resolvePresentationRole(groupName, fields, map) {
20937
+ const direct = map?.[groupName];
20938
+ if (direct)
20939
+ return direct;
20940
+ const normalized = stableToken(groupName);
20941
+ if (normalized.includes('ident'))
20942
+ return 'identity';
20943
+ if (normalized.includes('marc') || normalized.includes('status'))
20944
+ return 'markers';
20945
+ if (normalized.includes('regra') || normalized.includes('rule'))
20946
+ return 'rules';
20947
+ if (fields.some((field) => String(field.controlType || '').toLowerCase().includes('checkbox'))) {
20948
+ return 'markers';
20949
+ }
20950
+ return 'default';
20951
+ }
20952
+ function resolvePresentationSectionIcon(role) {
20953
+ switch (role) {
20954
+ case 'identity':
20955
+ return 'badge';
20956
+ case 'rules':
20957
+ return 'rule';
20958
+ case 'markers':
20959
+ return 'fact_check';
20960
+ default:
20961
+ return 'info';
20962
+ }
20963
+ }
20964
+ function stableSectionId(groupName) {
20965
+ const token = stableToken(groupName) || 'default';
20966
+ return `section-${token}`;
20967
+ }
20968
+ function stableToken(value) {
20969
+ return String(value || '')
20970
+ .normalize('NFD')
20971
+ .replace(/[\u0300-\u036f]/g, '')
20972
+ .toLowerCase()
20973
+ .replace(/[^a-z0-9]+/g, '-')
20974
+ .replace(/^-+|-+$/g, '');
20975
+ }
20976
+
19569
20977
  function resolveSpan(span) {
19570
20978
  const xs = clamp(span?.xs ?? 12, 'xs');
19571
20979
  const sm = clamp(span?.sm ?? xs, 'sm');
@@ -20346,7 +21754,7 @@ class SurfaceOpenActionEditorComponent {
20346
21754
  .filter(Boolean)));
20347
21755
  }
20348
21756
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SurfaceOpenActionEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20349
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: SurfaceOpenActionEditorComponent, isStandalone: true, selector: "praxis-surface-open-action-editor", inputs: { value: "value", hostKind: "hostKind" }, outputs: { valueChange: "valueChange" }, providers: [providePraxisI18nConfig(SURFACE_OPEN_I18N_CONFIG)], usesOnChanges: true, ngImport: i0, template: `
21757
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: SurfaceOpenActionEditorComponent, isStandalone: true, selector: "praxis-surface-open-action-editor", inputs: { value: "value", hostKind: "hostKind" }, outputs: { valueChange: "valueChange" }, host: { attributes: { "data-praxis-surface-open-action-editor": "core" } }, providers: [providePraxisI18nConfig(SURFACE_OPEN_I18N_CONFIG)], usesOnChanges: true, ngImport: i0, template: `
20350
21758
  <div class="surface-editor">
20351
21759
  <div class="surface-section">
20352
21760
  <div class="surface-section-title">{{ t('editor.presets.title', 'Presets') }}</div>
@@ -20643,17 +22051,17 @@ class SurfaceOpenActionEditorComponent {
20643
22051
  {{ t('editor.bindings.empty', 'No bindings configured yet.') }}
20644
22052
  </div>
20645
22053
  }
20646
- <div class="surface-empty">
22054
+ <div class="surface-guidance">
20647
22055
  @if (bindingSourceSuggestionsPreview) {
20648
- <div>
22056
+ <div class="surface-guidance__item">
20649
22057
  {{ t('editor.bindings.suggestedSources', 'Suggested sources: {{value}}', { value: bindingSourceSuggestionsPreview }) }}
20650
22058
  </div>
20651
22059
  }
20652
- <div>
22060
+ <div class="surface-guidance__item surface-guidance__item--primary">
20653
22061
  {{ t('editor.bindings.sourceSemantics', 'Use payload.* for the canonical event envelope and runtime.* for direct host state when the source component exposes it.') }}
20654
22062
  </div>
20655
22063
  @if (bindingTargetSuggestionsPreview) {
20656
- <div>
22064
+ <div class="surface-guidance__item">
20657
22065
  {{ t('editor.bindings.suggestedTargets', 'Suggested targets: {{value}}', { value: bindingTargetSuggestionsPreview }) }}
20658
22066
  </div>
20659
22067
  }
@@ -20689,11 +22097,11 @@ class SurfaceOpenActionEditorComponent {
20689
22097
  </mat-form-field>
20690
22098
  </div>
20691
22099
  </div>
20692
- `, 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: 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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
22100
+ `, isInline: true, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$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: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
20693
22101
  }
20694
22102
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SurfaceOpenActionEditorComponent, decorators: [{
20695
22103
  type: Component,
20696
- args: [{ selector: 'praxis-surface-open-action-editor', standalone: true, providers: [providePraxisI18nConfig(SURFACE_OPEN_I18N_CONFIG)], imports: [
22104
+ args: [{ selector: 'praxis-surface-open-action-editor', standalone: true, host: { 'data-praxis-surface-open-action-editor': 'core' }, providers: [providePraxisI18nConfig(SURFACE_OPEN_I18N_CONFIG)], imports: [
20697
22105
  FormsModule,
20698
22106
  MatButtonModule,
20699
22107
  MatFormFieldModule,
@@ -20999,17 +22407,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20999
22407
  {{ t('editor.bindings.empty', 'No bindings configured yet.') }}
21000
22408
  </div>
21001
22409
  }
21002
- <div class="surface-empty">
22410
+ <div class="surface-guidance">
21003
22411
  @if (bindingSourceSuggestionsPreview) {
21004
- <div>
22412
+ <div class="surface-guidance__item">
21005
22413
  {{ t('editor.bindings.suggestedSources', 'Suggested sources: {{value}}', { value: bindingSourceSuggestionsPreview }) }}
21006
22414
  </div>
21007
22415
  }
21008
- <div>
22416
+ <div class="surface-guidance__item surface-guidance__item--primary">
21009
22417
  {{ t('editor.bindings.sourceSemantics', 'Use payload.* for the canonical event envelope and runtime.* for direct host state when the source component exposes it.') }}
21010
22418
  </div>
21011
22419
  @if (bindingTargetSuggestionsPreview) {
21012
- <div>
22420
+ <div class="surface-guidance__item">
21013
22421
  {{ t('editor.bindings.suggestedTargets', 'Suggested targets: {{value}}', { value: bindingTargetSuggestionsPreview }) }}
21014
22422
  </div>
21015
22423
  }
@@ -21045,7 +22453,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21045
22453
  </mat-form-field>
21046
22454
  </div>
21047
22455
  </div>
21048
- `, 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"] }]
22456
+ `, styles: [".surface-editor{display:grid;gap:14px;min-width:0}.surface-section{display:grid;gap:10px;min-width:0;padding:14px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.surface-section-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:0}.surface-section-title{font-size:12px;font-weight:700;letter-spacing:0;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);margin-bottom:0}.surface-section-header .surface-section-title{margin-bottom:0}.surface-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px 16px;min-width:0}.surface-preset-row{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.surface-span-2{grid-column:span 2}.surface-span-all{width:100%;min-width:0}.surface-component-meta{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-component-title{font-weight:600;color:var(--md-sys-color-on-surface)}.surface-component-description,.surface-empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-bindings{display:grid;gap:10px;min-width:0}.surface-binding-row{display:grid;grid-template-columns:minmax(min(220px,100%),1.15fr) minmax(min(240px,100%),1.25fr) minmax(128px,.55fr) auto;gap:10px;align-items:start;min-width:0;padding:10px;border-radius:8px;background:var(--md-sys-color-surface-container)}.surface-binding-row mat-form-field:nth-child(4){grid-column:1 / -2}.surface-guidance{display:grid;gap:4px;padding:10px 12px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 18%,transparent);color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.surface-guidance__item{overflow-wrap:anywhere}.surface-guidance__item--primary{color:var(--md-sys-color-on-surface)}mat-form-field{width:100%;min-width:0}@media(max-width:960px){.surface-section{padding:12px}.surface-span-2{grid-column:1 / -1}.surface-binding-row{grid-template-columns:minmax(0,1fr)}.surface-binding-row mat-form-field:nth-child(4){grid-column:auto}}\n"] }]
21049
22457
  }], propDecorators: { value: [{
21050
22458
  type: Input
21051
22459
  }], hostKind: [{
@@ -21072,6 +22480,12 @@ const ENUMS$1 = {
21072
22480
  textTransformApply: ['displayOnly', 'saveOnly', 'both'],
21073
22481
  fieldSource: ['schema', 'local'],
21074
22482
  fieldSubmitPolicy: ['include', 'omit', 'includeWhenDirty'],
22483
+ fieldPresentationTone: ['neutral', 'info', 'success', 'warning', 'danger'],
22484
+ fieldPresentationAppearance: ['plain', 'soft', 'outlined', 'filled'],
22485
+ fieldPresenterKind: ['text', 'badge', 'chip', 'status', 'iconValue', 'progress', 'rating', 'microVisualization'],
22486
+ presentationVisualizationKind: ['line', 'area', 'column', 'comparison', 'stackedBar', 'radial', 'harveyBall', 'bullet', 'delta', 'processFlow'],
22487
+ presentationVisualizationSurface: ['table-cell', 'list-item', 'object-header', 'card-summary', 'form-presentation'],
22488
+ presentationVisualizationSize: ['xs', 'sm', 'md', 'lg', 'responsive'],
21075
22489
  visibleIn: ['form', 'filter', 'table', 'dialog'],
21076
22490
  appearance: ['fill', 'outline'],
21077
22491
  color: ['primary', 'accent', 'warn'],
@@ -21082,7 +22496,7 @@ const ENUMS$1 = {
21082
22496
  sectionDescriptionStyle: ['bodyLarge', 'bodyMedium', 'bodySmall'],
21083
22497
  };
21084
22498
  const FIELD_METADATA_CAPABILITIES = {
21085
- version: 'v1.4',
22499
+ version: 'v1.5',
21086
22500
  enums: ENUMS$1,
21087
22501
  notes: [
21088
22502
  'Condições booleanas declarativas devem usar Json Logic canônico. Funções permanecem restritas a escapes host-level como transforms e validators customizados.',
@@ -21091,8 +22505,11 @@ const FIELD_METADATA_CAPABILITIES = {
21091
22505
  'Detalhes específicos de cada controle (ex: opções de datepicker, máscaras específicas) devem ser consultados nos catálogos de microcomponentes.',
21092
22506
  'POLICY: Arrays e objetos (ex: options, validators) devem sofrer merge/append, nunca substituição completa sem confirmação.',
21093
22507
  'Não gere função para conditionalDisplay/conditionalRequired. Use Json Logic serializável; funções ficam restritas a transforms e validators customizados.',
21094
- 'POLICY: Campos auxiliares do host devem usar source=local ou transient=true em FieldMetadata; nao invente campos no DTO/backend quando eles nao devem participar do payload persistido.',
22508
+ 'POLICY: Campos auxiliares do host devem usar source=local ou transient=true em FieldMetadata; não invente campos no DTO/backend quando eles não devem participar do payload persistido.',
21095
22509
  'POLICY: formSubmit.formData e o payload filtrado para backend; formSubmit.rawFormData preserva os valores completos da UI, incluindo campos locais/transient.',
22510
+ 'POLICY: fieldAccess e metadata-driven UX; nao trate como seguranca frontend. Use somente authorities explicitas, nunca capabilities como sinonimo implicito.',
22511
+ 'POLICY: presentation/presentationRules descrevem somente estado visual semantico em modo leitura. Nao gere CSS, HTML, comandos ou mutacoes por Json Logic.',
22512
+ 'POLICY: presentation.visualization e renderer-neutral. Nao gere EChartsOption, SVG, HTML ou CSS; use kind/surface/size/fallbackText e dados semanticos.',
21096
22513
  ],
21097
22514
  capabilities: [
21098
22515
  // =============================================================================
@@ -21194,6 +22611,13 @@ const FIELD_METADATA_CAPABILITIES = {
21194
22611
  description: 'Texto de ajuda exibido abaixo do campo.',
21195
22612
  intentExamples: ['colocar dica', 'ajuda no rodapé do campo'],
21196
22613
  },
22614
+ {
22615
+ path: 'helpText',
22616
+ category: 'identity',
22617
+ valueKind: 'string',
22618
+ description: 'Texto semântico de ajuda publicado pelo schema/DTO.',
22619
+ intentExamples: ['explicar regra de negócio do campo', 'ajuda vinda do backend'],
22620
+ },
21197
22621
  {
21198
22622
  path: 'tooltip',
21199
22623
  category: 'identity',
@@ -21201,6 +22625,13 @@ const FIELD_METADATA_CAPABILITIES = {
21201
22625
  description: 'Texto exibido ao passar o mouse.',
21202
22626
  intentExamples: ['adicionar tooltip'],
21203
22627
  },
22628
+ {
22629
+ path: 'tooltipOnHover',
22630
+ category: 'identity',
22631
+ valueKind: 'boolean',
22632
+ description: 'Habilita apresentação do tooltip no hover quando suportado pelo renderer.',
22633
+ intentExamples: ['mostrar tooltip ao passar o mouse', 'ativar dica no hover'],
22634
+ },
21204
22635
  {
21205
22636
  path: 'description',
21206
22637
  category: 'identity',
@@ -21292,24 +22723,24 @@ const FIELD_METADATA_CAPABILITIES = {
21292
22723
  category: 'data',
21293
22724
  valueKind: 'enum',
21294
22725
  allowedValues: ENUMS$1.fieldSource,
21295
- description: 'Origem semantica do campo. Use local para campos do host que nao vem do schema backend.',
21296
- intentExamples: ['campo local', 'campo auxiliar do host', 'campo que nao vem do schema'],
21297
- safetyNotes: 'Nao marque como local um campo que exista no schema backend; remova a semantica local quando houver colisao com campo server-backed.',
22726
+ description: 'Origem semântica do campo. Use local para campos do host que não vêm do schema backend.',
22727
+ intentExamples: ['campo local', 'campo auxiliar do host', 'campo que não vem do schema'],
22728
+ safetyNotes: 'Não marque como local um campo que exista no schema backend; remova a semântica local quando houver colisão com campo server-backed.',
21298
22729
  },
21299
22730
  {
21300
22731
  path: 'transient',
21301
22732
  category: 'data',
21302
22733
  valueKind: 'boolean',
21303
- description: 'Marca o campo como temporario/local para preenchimento. O dynamic-form omite do submit por padrao.',
21304
- intentExamples: ['campo temporario', 'campo transient', 'nao enviar no payload', 'usar apenas na UI'],
21305
- safetyNotes: 'Campos transient continuam participando de UI, validacao, regras, visibilidade e valueChange; eles apenas saem do payload persistido por padrao.',
22734
+ description: 'Marca o campo como temporário/local para preenchimento. O dynamic-form omite do submit por padrão.',
22735
+ intentExamples: ['campo temporário', 'campo transient', 'não enviar no payload', 'usar apenas na UI'],
22736
+ safetyNotes: 'Campos transient continuam participando de UI, validação, regras, visibilidade e valueChange; eles apenas saem do payload persistido por padrão.',
21306
22737
  },
21307
22738
  {
21308
22739
  path: 'submitPolicy',
21309
22740
  category: 'behavior',
21310
22741
  valueKind: 'enum',
21311
22742
  allowedValues: ENUMS$1.fieldSubmitPolicy,
21312
- description: 'Politica de submit para sobrescrever o padrao de campos locais/transient.',
22743
+ description: 'Política de submit para sobrescrever o padrão de campos locais/transient.',
21313
22744
  intentExamples: ['omitir do submit', 'enviar mesmo sendo local', 'enviar apenas se alterado'],
21314
22745
  safetyNotes: 'Use omit para nunca persistir, include para enviar sempre e includeWhenDirty apenas quando o controle estiver dirty.',
21315
22746
  },
@@ -21412,6 +22843,166 @@ const FIELD_METADATA_CAPABILITIES = {
21412
22843
  description: 'Tamanho do ícone.',
21413
22844
  intentExamples: ['ícone pequeno', 'aumentar tamanho do ícone', 'ícone grande'],
21414
22845
  },
22846
+ {
22847
+ path: 'iconColor',
22848
+ category: 'appearance',
22849
+ valueKind: 'string',
22850
+ description: 'Cor semântica ou token de cor aplicado ao ícone principal.',
22851
+ intentExamples: ['ícone em cor primária', 'usar token do tema no ícone'],
22852
+ },
22853
+ {
22854
+ path: 'iconClass',
22855
+ category: 'appearance',
22856
+ valueKind: 'string',
22857
+ description: 'Classe CSS controlada pelo host para o ícone principal.',
22858
+ intentExamples: ['usar classe de ícone outlined', 'aplicar classe corporativa'],
22859
+ },
22860
+ {
22861
+ path: 'iconStyle',
22862
+ category: 'appearance',
22863
+ valueKind: 'string',
22864
+ description: 'Estilo visual semântico do ícone quando o renderer suportar variações.',
22865
+ intentExamples: ['usar ícone arredondado', 'aplicar estilo filled'],
22866
+ },
22867
+ {
22868
+ path: 'iconFontSize',
22869
+ category: 'appearance',
22870
+ valueKind: 'string',
22871
+ description: 'Tamanho tipográfico do ícone principal.',
22872
+ intentExamples: ['ícone com 18px', 'ajustar tamanho do ícone'],
22873
+ },
22874
+ // =============================================================================
22875
+ // PRESENTATION MODE
22876
+ // =============================================================================
22877
+ {
22878
+ path: 'valuePresentation',
22879
+ category: 'appearance',
22880
+ valueKind: 'object',
22881
+ description: 'Formato canonico de exibicao em superficies readonly/display, como moeda, numero, percentual, data, datetime, time e boolean.',
22882
+ safetyNotes: 'Preferir este contrato a formatadores legados quando a intencao for apresentacao de valor.',
22883
+ intentExamples: ['mostrar como moeda', 'formatar como data longa', 'exibir percentual'],
22884
+ },
22885
+ {
22886
+ path: 'presentation',
22887
+ category: 'appearance',
22888
+ valueKind: 'object',
22889
+ description: 'Estado visual semantico base para presentationMode, incluindo presenter, tone, icon, label, badge, tooltip, appearance e formatter opcional.',
22890
+ safetyNotes: 'Use apenas semantica declarativa; nao incluir CSS arbitrario, HTML, comandos ou efeitos mutaveis.',
22891
+ intentExamples: ['status com icone', 'badge de pendente', 'campo em tom warning'],
22892
+ },
22893
+ {
22894
+ path: 'presentation.presenter',
22895
+ category: 'appearance',
22896
+ valueKind: 'enum',
22897
+ allowedValues: ENUMS$1.fieldPresenterKind,
22898
+ description: 'Tipo semantico de renderizacao em modo apresentacao.',
22899
+ intentExamples: ['renderizar como status', 'usar chip', 'mostrar icone com valor'],
22900
+ },
22901
+ {
22902
+ path: 'presentation.tone',
22903
+ category: 'appearance',
22904
+ valueKind: 'enum',
22905
+ allowedValues: ENUMS$1.fieldPresentationTone,
22906
+ description: 'Tom semantico mapeado pelo consumidor para tokens de tema.',
22907
+ intentExamples: ['tom de sucesso', 'tom de alerta', 'tom de erro'],
22908
+ },
22909
+ {
22910
+ path: 'presentation.appearance',
22911
+ category: 'appearance',
22912
+ valueKind: 'enum',
22913
+ allowedValues: ENUMS$1.fieldPresentationAppearance,
22914
+ description: 'Nivel de enfase visual do apresentador.',
22915
+ intentExamples: ['status preenchido', 'badge contornado', 'chip suave'],
22916
+ },
22917
+ {
22918
+ path: 'presentation.icon',
22919
+ category: 'appearance',
22920
+ valueKind: 'string',
22921
+ description: 'Nome de icone Material Symbols usado pelo apresentador semantico.',
22922
+ intentExamples: ['icone lock', 'icone payments', 'icone schedule'],
22923
+ },
22924
+ {
22925
+ path: 'presentation.label',
22926
+ category: 'identity',
22927
+ valueKind: 'string',
22928
+ description: 'Rotulo semantico exibido por apresentadores como status, badge ou chip.',
22929
+ intentExamples: ['rotulo Bloqueado', 'texto Aprovado', 'status Aguardando aprovacao'],
22930
+ },
22931
+ {
22932
+ path: 'presentation.badge',
22933
+ category: 'appearance',
22934
+ valueKind: 'string',
22935
+ description: 'Marcador secundario opcional exibido junto ao valor em superficies de apresentacao.',
22936
+ intentExamples: ['badge alto valor', 'marcador D+35', 'sinalizar revisao executiva'],
22937
+ },
22938
+ {
22939
+ path: 'presentation.valuePresentation',
22940
+ category: 'appearance',
22941
+ valueKind: 'object',
22942
+ description: 'Override de formatacao aplicado apenas pela superficie de apresentacao.',
22943
+ safetyNotes: 'Nao altera o valor real do FormControl nem o payload de submit.',
22944
+ },
22945
+ {
22946
+ path: 'presentation.visualization',
22947
+ category: 'appearance',
22948
+ valueKind: 'object',
22949
+ description: 'Micro visualizacao renderer-neutral para superficies compactas como tabela, lista, header, card e form read-only.',
22950
+ safetyNotes: 'Exige fallback textual e nao pode conter opcoes de ECharts, HTML, SVG bruto, CSS ou comandos.',
22951
+ intentExamples: ['micro chart de SLA', 'barra empilhada em celula', 'bullet chart de orcamento', 'fluxo compacto de aprovacao'],
22952
+ },
22953
+ {
22954
+ path: 'presentation.visualization.kind',
22955
+ category: 'appearance',
22956
+ valueKind: 'enum',
22957
+ allowedValues: ENUMS$1.presentationVisualizationKind,
22958
+ description: 'Tipo semantico da micro visualizacao de apresentacao.',
22959
+ intentExamples: ['comparison', 'stackedBar', 'bullet', 'processFlow'],
22960
+ },
22961
+ {
22962
+ path: 'presentation.visualization.surface',
22963
+ category: 'layout',
22964
+ valueKind: 'enum',
22965
+ allowedValues: ENUMS$1.presentationVisualizationSurface,
22966
+ description: 'Superficie alvo usada para aplicar regras de densidade e fallback.',
22967
+ intentExamples: ['table-cell', 'list-item', 'form-presentation'],
22968
+ },
22969
+ {
22970
+ path: 'presentation.visualization.size',
22971
+ category: 'layout',
22972
+ valueKind: 'enum',
22973
+ allowedValues: ENUMS$1.presentationVisualizationSize,
22974
+ description: 'Tamanho semantico da micro visualizacao.',
22975
+ intentExamples: ['xs em tabela', 'md em header', 'responsive em card'],
22976
+ },
22977
+ {
22978
+ path: 'presentation.visualization.fallbackText',
22979
+ category: 'accessibility',
22980
+ valueKind: 'string',
22981
+ description: 'Texto equivalente obrigatorio para fallback, exportacao e leitores de tela.',
22982
+ safetyNotes: 'Deve explicar valor, unidade, meta, tendencia ou estado quando aplicavel.',
22983
+ },
22984
+ {
22985
+ path: 'presentationRules',
22986
+ category: 'appearance',
22987
+ valueKind: 'array',
22988
+ description: 'Regras Json Logic ordenadas que sobrescrevem presentation em modo readonly/display; regras posteriores que casam vencem.',
22989
+ safetyNotes: 'As regras devem produzir apenas set/effect semantico. Nao use para alterar valor, executar acao, navegar ou injetar HTML/CSS.',
22990
+ intentExamples: ['se status for BLOQUEADO, usar tone danger', 'se valor maior que limite, mostrar badge de revisao'],
22991
+ },
22992
+ {
22993
+ path: 'presentationRules[].when',
22994
+ category: 'behavior',
22995
+ valueKind: 'object',
22996
+ description: 'Guarda Json Logic avaliada contra o contexto de apresentacao do campo.',
22997
+ safetyNotes: 'Use Json Logic serializavel; funcoes nao sao aceitas.',
22998
+ },
22999
+ {
23000
+ path: 'presentationRules[].set',
23001
+ category: 'appearance',
23002
+ valueKind: 'object',
23003
+ description: 'Patch semantico aplicado sobre presentation quando a guarda for verdadeira.',
23004
+ safetyNotes: 'Somente presenter, tone, icon, label, badge, tooltip, appearance, valuePresentation e interactions seguras.',
23005
+ },
21415
23006
  // =============================================================================
21416
23007
  // MASK / FORMAT
21417
23008
  // =============================================================================
@@ -21451,8 +23042,8 @@ const FIELD_METADATA_CAPABILITIES = {
21451
23042
  path: 'required',
21452
23043
  category: 'validation',
21453
23044
  valueKind: 'boolean',
21454
- description: 'Campo obrigatorio (alias rapido do validators.required).',
21455
- intentExamples: ['campo obrigatorio', 'exigir preenchimento'],
23045
+ description: 'Campo obrigatório (alias rápido do validators.required).',
23046
+ intentExamples: ['campo obrigatório', 'exigir preenchimento'],
21456
23047
  },
21457
23048
  {
21458
23049
  path: 'validators.requiredMessage',
@@ -21471,7 +23062,7 @@ const FIELD_METADATA_CAPABILITIES = {
21471
23062
  path: 'validators.emailMessage',
21472
23063
  category: 'validation',
21473
23064
  valueKind: 'string',
21474
- description: 'Mensagem customizada para validacao de email.',
23065
+ description: 'Mensagem customizada para validação de email.',
21475
23066
  },
21476
23067
  {
21477
23068
  path: 'validators.minLength',
@@ -21611,15 +23202,15 @@ const FIELD_METADATA_CAPABILITIES = {
21611
23202
  path: 'validators.customValidator',
21612
23203
  category: 'validation',
21613
23204
  valueKind: 'expression',
21614
- description: 'Validador customizado (funcao).',
21615
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23205
+ description: 'Validador customizado (função).',
23206
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21616
23207
  },
21617
23208
  {
21618
23209
  path: 'validators.asyncValidator',
21619
23210
  category: 'validation',
21620
23211
  valueKind: 'expression',
21621
- description: 'Validador async customizado (funcao).',
21622
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23212
+ description: 'Validador async customizado (função).',
23213
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21623
23214
  },
21624
23215
  {
21625
23216
  path: 'validators.matchField',
@@ -21637,8 +23228,8 @@ const FIELD_METADATA_CAPABILITIES = {
21637
23228
  path: 'validators.uniqueValidator',
21638
23229
  category: 'validation',
21639
23230
  valueKind: 'expression',
21640
- description: 'Validador de unicidade via API (funcao).',
21641
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23231
+ description: 'Validador de unicidade via API (função).',
23232
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21642
23233
  },
21643
23234
  {
21644
23235
  path: 'validators.uniqueMessage',
@@ -21650,8 +23241,8 @@ const FIELD_METADATA_CAPABILITIES = {
21650
23241
  path: 'validators.conditionalValidation',
21651
23242
  category: 'validation',
21652
23243
  valueKind: 'array',
21653
- description: 'Regras de validacao condicional.',
21654
- safetyNotes: 'Use regras declarativas com Json Logic serializavel; nao gere funcoes aqui.',
23244
+ description: 'Regras de validação condicional.',
23245
+ safetyNotes: 'Use regras declarativas com Json Logic serializável; não gere funções aqui.',
21655
23246
  },
21656
23247
  {
21657
23248
  path: 'validators.conditionalValidation[].condition',
@@ -21671,13 +23262,13 @@ const FIELD_METADATA_CAPABILITIES = {
21671
23262
  category: 'validation',
21672
23263
  valueKind: 'enum',
21673
23264
  allowedValues: ENUMS$1.validatorTrigger,
21674
- description: 'Gatilho de validacao no validator.',
23265
+ description: 'Gatilho de validação no validator.',
21675
23266
  },
21676
23267
  {
21677
23268
  path: 'validators.validationDebounce',
21678
23269
  category: 'validation',
21679
23270
  valueKind: 'number',
21680
- description: 'Debounce de validacao no validator (ms).',
23271
+ description: 'Debounce de validação no validator (ms).',
21681
23272
  },
21682
23273
  {
21683
23274
  path: 'validators.showInlineErrors',
@@ -21800,6 +23391,35 @@ const FIELD_METADATA_CAPABILITIES = {
21800
23391
  description: 'Oculta apenas no filtro.',
21801
23392
  intentExamples: ['esconder na busca', 'remover do filtro'],
21802
23393
  },
23394
+ {
23395
+ path: 'fieldAccess',
23396
+ category: 'behavior',
23397
+ valueKind: 'object',
23398
+ description: 'Politica canonica de UX para visibilidade/edicao por authorities publicadas pelo backend.',
23399
+ safetyNotes: 'Nao e barreira de seguranca. O backend continua responsavel por filtrar dados sensiveis e validar payloads.',
23400
+ intentExamples: ['campo visivel somente para RH', 'bloquear edicao por perfil corporativo'],
23401
+ },
23402
+ {
23403
+ path: 'fieldAccess.visibleForAuthorities',
23404
+ category: 'behavior',
23405
+ valueKind: 'array',
23406
+ description: 'Authorities que podem ver o campo no runtime quando a UX tiver claims explicitas.',
23407
+ safetyNotes: 'Nao inferir a partir de capabilities sem mapeamento canonico publicado.',
23408
+ },
23409
+ {
23410
+ path: 'fieldAccess.editableForAuthorities',
23411
+ category: 'behavior',
23412
+ valueKind: 'array',
23413
+ description: 'Authorities que podem editar o campo no runtime quando a UX tiver claims explicitas.',
23414
+ safetyNotes: 'Edicao concedida implica materializacao visivel no runtime; a validacao final permanece no backend.',
23415
+ },
23416
+ {
23417
+ path: 'fieldAccess.reason',
23418
+ category: 'misc',
23419
+ valueKind: 'string',
23420
+ description: 'Justificativa explicativa/auditavel da politica de acesso do campo.',
23421
+ safetyNotes: 'Reason sozinho nao deve decidir acesso nem revelar detalhes sensiveis para usuarios sem permissao.',
23422
+ },
21803
23423
  // =============================================================================
21804
23424
  // DEPENDENCIES
21805
23425
  // =============================================================================
@@ -22004,12 +23624,12 @@ const ENUMS = {
22004
23624
  actionPlacement: ['header', 'window'],
22005
23625
  };
22006
23626
  const CAPS = [
22007
- { path: 'page', category: 'page', valueKind: 'object', description: 'Definicao da pagina dinamica.' },
23627
+ { path: 'page', category: 'page', valueKind: 'object', description: 'Definição da página dinâmica.' },
22008
23628
  { path: 'page.context', category: 'context', valueKind: 'object', description: 'Contexto compartilhado entre widgets.' },
22009
- { path: 'page.layoutPreset', category: 'layout', valueKind: 'string', description: 'ID canonico opcional do preset estrutural da pagina.' },
22010
- { path: 'page.layoutPresetOptions', category: 'layout', valueKind: 'object', description: 'Opcoes especificas do preset estrutural consumidas por builders e runtimes futuros.' },
22011
- { path: 'page.themePreset', category: 'appearance', valueKind: 'string', description: 'ID opcional do preset de tema para shell, graficos, densidade e defaults visuais.' },
22012
- { path: 'page.layout', category: 'layout', valueKind: 'object', description: 'Layout base da pagina.' },
23629
+ { path: 'page.layoutPreset', category: 'layout', valueKind: 'string', description: 'ID canônico opcional do preset estrutural da página.' },
23630
+ { path: 'page.layoutPresetOptions', category: 'layout', valueKind: 'object', description: 'Opções específicas do preset estrutural consumidas por builders e runtimes futuros.' },
23631
+ { path: 'page.themePreset', category: 'appearance', valueKind: 'string', description: 'ID opcional do preset de tema para shell, gráficos, densidade e defaults visuais.' },
23632
+ { path: 'page.layout', category: 'layout', valueKind: 'object', description: 'Layout base da página.' },
22013
23633
  { path: 'page.layout.orientation', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.layoutOrientation, description: 'Orientacao do grid (vertical/columns).' },
22014
23634
  { path: 'page.layout.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas (quando orientation=columns).' },
22015
23635
  { path: 'page.layout.gap', category: 'layout', valueKind: 'string', description: 'Gap entre widgets (ex: 16px).' },
@@ -22018,7 +23638,7 @@ const CAPS = [
22018
23638
  { path: 'page.layout.breakpoints.md', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint md.' },
22019
23639
  { path: 'page.layout.breakpoints.lg', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint lg.' },
22020
23640
  { path: 'page.layout.breakpoints.xl', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint xl.' },
22021
- { path: 'page.canvas', category: 'layout', valueKind: 'object', description: 'Canvas espacial canonico da pagina quando houver geometria explicita.' },
23641
+ { path: 'page.canvas', category: 'layout', valueKind: 'object', description: 'Canvas espacial canônico da página quando houver geometria explícita.' },
22022
23642
  { path: 'page.canvas.mode', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.canvasMode, description: 'Modo canonico do canvas. Valor atual: grid.' },
22023
23643
  { path: 'page.canvas.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas do canvas espacial.' },
22024
23644
  { path: 'page.canvas.rowUnit', category: 'layout', valueKind: 'string', description: 'Altura base das linhas do canvas, como 80px.' },
@@ -22032,10 +23652,10 @@ const CAPS = [
22032
23652
  { path: 'page.canvas.items.<widgetKey>.rowSpan', category: 'layout', valueKind: 'number', description: 'Quantidade de linhas ocupadas pelo widget.' },
22033
23653
  { path: 'page.canvas.items.<widgetKey>.zIndex', category: 'layout', valueKind: 'number', description: 'Camada opcional do item no canvas.' },
22034
23654
  { path: 'page.canvas.items.<widgetKey>.constraints', category: 'layout', valueKind: 'object', description: 'Restricoes opcionais de posicao e tamanho do item no canvas.' },
22035
- { path: 'page.canvas.items.<widgetKey>.constraints.minColSpan', category: 'layout', valueKind: 'number', description: 'Span minimo de colunas permitido.' },
22036
- { path: 'page.canvas.items.<widgetKey>.constraints.minRowSpan', category: 'layout', valueKind: 'number', description: 'Span minimo de linhas permitido.' },
22037
- { path: 'page.canvas.items.<widgetKey>.constraints.maxColSpan', category: 'layout', valueKind: 'number', description: 'Span maximo de colunas permitido.' },
22038
- { path: 'page.canvas.items.<widgetKey>.constraints.maxRowSpan', category: 'layout', valueKind: 'number', description: 'Span maximo de linhas permitido.' },
23655
+ { path: 'page.canvas.items.<widgetKey>.constraints.minColSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de colunas permitido.' },
23656
+ { path: 'page.canvas.items.<widgetKey>.constraints.minRowSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de linhas permitido.' },
23657
+ { path: 'page.canvas.items.<widgetKey>.constraints.maxColSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de colunas permitido.' },
23658
+ { path: 'page.canvas.items.<widgetKey>.constraints.maxRowSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de linhas permitido.' },
22039
23659
  { path: 'page.canvas.items.<widgetKey>.constraints.lockPosition', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de posicao do item no canvas.' },
22040
23660
  { path: 'page.canvas.items.<widgetKey>.constraints.lockSize', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de tamanho do item no canvas.' },
22041
23661
  { path: 'page.widgets', category: 'widgets', valueKind: 'array', description: 'Lista de widgets renderizados.' },
@@ -22043,32 +23663,32 @@ const CAPS = [
22043
23663
  { path: 'page.widgets[].className', category: 'widgets', valueKind: 'string', description: 'Classe CSS opcional do widget.' },
22044
23664
  { path: 'page.widgets[].definition.id', category: 'widgets', valueKind: 'string', description: 'ID do componente do widget (ex: praxis-table).' },
22045
23665
  { path: 'page.widgets[].definition.inputs', category: 'widgets', valueKind: 'object', description: 'Inputs iniciais do widget.' },
22046
- { path: 'page.widgets[].definition.inputs.hostCapabilities', category: 'widgets', valueKind: 'object', description: 'Capacidades runtime mediadas pelo host quando definition.id = praxis-rich-content. Nao pertence ao JSON persistido.' },
22047
- { path: 'page.widgets[].definition.inputs.hostCapabilities.dispatchAction', category: 'widgets', valueKind: 'object', description: 'Dispatcher runtime para actionButton e actions declarativas de rich content hospedado na pagina.' },
22048
- { path: 'page.widgets[].definition.inputs.hostCapabilities.isActionAvailable', category: 'widgets', valueKind: 'object', description: 'Resolver runtime de disponibilidade de actionId para rich content hospedado na pagina.' },
22049
- { path: 'page.widgets[].definition.inputs.hostCapabilities.hasCapability', category: 'widgets', valueKind: 'object', description: 'Resolver runtime de capabilities como page.customization.enabled e page.widget.selected para rich content hospedado na pagina.' },
23666
+ { path: 'page.widgets[].definition.inputs.hostCapabilities', category: 'widgets', valueKind: 'object', description: 'Capacidades runtime mediadas pelo host quando definition.id = praxis-rich-content. Não pertence ao JSON persistido.' },
23667
+ { path: 'page.widgets[].definition.inputs.hostCapabilities.dispatchAction', category: 'widgets', valueKind: 'object', description: 'Dispatcher runtime para actionButton e actions declarativas de rich content hospedado na página.' },
23668
+ { path: 'page.widgets[].definition.inputs.hostCapabilities.isActionAvailable', category: 'widgets', valueKind: 'object', description: 'Resolver runtime de disponibilidade de actionId para rich content hospedado na página.' },
23669
+ { path: 'page.widgets[].definition.inputs.hostCapabilities.hasCapability', category: 'widgets', valueKind: 'object', description: 'Resolver runtime de capabilities como page.customization.enabled e page.widget.selected para rich content hospedado na página.' },
22050
23670
  { path: 'page.widgets[].definition.bindingOrder', category: 'widgets', valueKind: 'array', description: 'Ordem de binding de inputs.' },
22051
- { path: 'page.widgets[].shell', category: 'shell', valueKind: 'object', description: 'Configuracao do shell do widget.' },
23671
+ { path: 'page.widgets[].shell', category: 'shell', valueKind: 'object', description: 'Configuração do shell do widget.' },
22052
23672
  { path: 'page.widgets[].shell.kind', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.shellKind, description: 'Tipo de shell.' },
22053
- { path: 'page.widgets[].shell.title', category: 'shell', valueKind: 'string', description: 'Titulo do shell.' },
22054
- { path: 'page.widgets[].shell.subtitle', category: 'shell', valueKind: 'string', description: 'Subtitulo do shell.' },
22055
- { path: 'page.widgets[].shell.icon', category: 'shell', valueKind: 'string', description: 'Icone do shell.' },
23673
+ { path: 'page.widgets[].shell.title', category: 'shell', valueKind: 'string', description: 'Título do shell.' },
23674
+ { path: 'page.widgets[].shell.subtitle', category: 'shell', valueKind: 'string', description: 'Subtítulo do shell.' },
23675
+ { path: 'page.widgets[].shell.icon', category: 'shell', valueKind: 'string', description: 'Ícone do shell.' },
22056
23676
  { path: 'page.widgets[].shell.showHeader', category: 'shell', valueKind: 'boolean', description: 'Exibe o header do shell.' },
22057
- { path: 'page.widgets[].shell.actions', category: 'shell', valueKind: 'array', description: 'Acoes do shell.' },
22058
- { path: 'page.widgets[].shell.actions[].id', category: 'shell', valueKind: 'string', description: 'ID da acao.' },
22059
- { path: 'page.widgets[].shell.actions[].label', category: 'shell', valueKind: 'string', description: 'Label da acao.' },
22060
- { path: 'page.widgets[].shell.actions[].icon', category: 'shell', valueKind: 'string', description: 'Icone da acao.' },
22061
- { path: 'page.widgets[].shell.actions[].variant', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionVariant, description: 'Estilo visual da acao.' },
22062
- { path: 'page.widgets[].shell.actions[].placement', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionPlacement, description: 'Posicionamento da acao.' },
22063
- { path: 'page.widgets[].shell.actions[].emit', category: 'shell', valueKind: 'string', description: 'Evento emitido ao acionar a acao.' },
23677
+ { path: 'page.widgets[].shell.actions', category: 'shell', valueKind: 'array', description: 'Ações do shell.' },
23678
+ { path: 'page.widgets[].shell.actions[].id', category: 'shell', valueKind: 'string', description: 'ID da ação.' },
23679
+ { path: 'page.widgets[].shell.actions[].label', category: 'shell', valueKind: 'string', description: 'Label da ação.' },
23680
+ { path: 'page.widgets[].shell.actions[].icon', category: 'shell', valueKind: 'string', description: 'Ícone da ação.' },
23681
+ { path: 'page.widgets[].shell.actions[].variant', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionVariant, description: 'Estilo visual da ação.' },
23682
+ { path: 'page.widgets[].shell.actions[].placement', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionPlacement, description: 'Posicionamento da ação.' },
23683
+ { path: 'page.widgets[].shell.actions[].emit', category: 'shell', valueKind: 'string', description: 'Evento emitido ao acionar a ação.' },
22064
23684
  { path: 'page.state', category: 'state', valueKind: 'object', description: 'Estado declarativo opcional compartilhado por widgets e composicao.' },
22065
23685
  { path: 'page.state.values', category: 'state', valueKind: 'object', description: 'Valores primarios mutaveis escritos por widgets, defaults ou host.' },
22066
23686
  { path: 'page.state.schema', category: 'state', valueKind: 'object', description: 'Descritores dos paths primarios de estado.' },
22067
23687
  { path: 'page.state.schema.<token>.type', category: 'state', valueKind: 'string', description: 'Tipo semantico opcional do path de estado.' },
22068
23688
  { path: 'page.state.schema.<token>.initial', category: 'state', valueKind: 'object', description: 'Valor inicial usado quando page.state.values omite o path.' },
22069
- { path: 'page.state.schema.<token>.persist', category: 'state', valueKind: 'boolean', description: 'Indica se o path primario deve ser persistido com a pagina.' },
23689
+ { path: 'page.state.schema.<token>.persist', category: 'state', valueKind: 'boolean', description: 'Indica se o path primário deve ser persistido com a página.' },
22070
23690
  { path: 'page.state.schema.<token>.mergeStrategy', category: 'state', valueKind: 'enum', allowedValues: ENUMS.stateMergeStrategy, description: 'Como escritas de widget/estado combinam com o valor atual.' },
22071
- { path: 'page.state.schema.<token>.description', category: 'state', valueKind: 'string', description: 'Descricao opcional do path para builders e catalogos AI.' },
23691
+ { path: 'page.state.schema.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do path para builders e catálogos AI.' },
22072
23692
  { path: 'page.state.schema.<token>.tags', category: 'state', valueKind: 'array', description: 'Tags opcionais para busca e governanca do estado.' },
22073
23693
  { path: 'page.state.derived', category: 'state', valueKind: 'object', description: 'Descritores de estado derivado recomputado pelo runtime.' },
22074
23694
  { path: 'page.state.derived.<token>.dependsOn', category: 'state', valueKind: 'array', description: 'Paths de estado que alimentam o valor derivado.' },
@@ -22077,9 +23697,9 @@ const CAPS = [
22077
23697
  { path: 'page.state.derived.<token>.compute.expression', category: 'state', valueKind: 'expression', description: 'Expressao Json Logic para compute.kind=json-logic.' },
22078
23698
  { path: 'page.state.derived.<token>.compute.value', category: 'state', valueKind: 'object', description: 'Valor template para compute.kind=template.' },
22079
23699
  { path: 'page.state.derived.<token>.compute.operator', category: 'state', valueKind: 'string', description: 'Operador para compute.kind=operator.' },
22080
- { path: 'page.state.derived.<token>.compute.options', category: 'state', valueKind: 'object', description: 'Opcoes do operador ou transformer.' },
23700
+ { path: 'page.state.derived.<token>.compute.options', category: 'state', valueKind: 'object', description: 'Opções do operador ou transformer.' },
22081
23701
  { path: 'page.state.derived.<token>.compute.transformerId', category: 'state', valueKind: 'string', description: 'Identificador do transformer para compute.kind=transformer.' },
22082
- { path: 'page.state.derived.<token>.description', category: 'state', valueKind: 'string', description: 'Descricao opcional do estado derivado.' },
23702
+ { path: 'page.state.derived.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do estado derivado.' },
22083
23703
  { path: 'page.state.derived.<token>.cache', category: 'state', valueKind: 'boolean', description: 'Permite cache futuro do valor derivado.' },
22084
23704
  { path: 'page.composition', category: 'connections', valueKind: 'object', description: 'Envelope canonico da composicao persistida.' },
22085
23705
  { path: 'page.composition.version', category: 'connections', valueKind: 'string', description: 'Versao do envelope de composicao.' },
@@ -22095,7 +23715,7 @@ const CAPS = [
22095
23715
  { path: 'page.composition.links[].from.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de origem.' },
22096
23716
  { path: 'page.composition.links[].from.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de origem.' },
22097
23717
  { path: 'page.composition.links[].from.ref.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal de origem.', critical: true },
22098
- { path: 'page.composition.links[].from.ref.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Indice auxiliar para diagnostico visual; nao use como identidade primaria.' },
23718
+ { path: 'page.composition.links[].from.ref.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Índice auxiliar para diagnóstico visual; não use como identidade primária.' },
22099
23719
  { path: 'page.composition.links[].from.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de origem.' },
22100
23720
  { path: 'page.composition.links[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino do link.' },
22101
23721
  { path: 'page.composition.links[].to.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de destino, como component-port, state ou global-action.' },
@@ -22110,11 +23730,11 @@ const CAPS = [
22110
23730
  { path: 'page.composition.links[].to.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de destino.' },
22111
23731
  { path: 'page.composition.links[].to.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de destino.' },
22112
23732
  { path: 'page.composition.links[].to.ref.nestedPath[].key', category: 'connections', valueKind: 'string', description: 'Chave estavel do widget filho no segmento terminal de destino.', critical: true },
22113
- { path: 'page.composition.links[].to.ref.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Indice auxiliar para diagnostico visual; nao use como identidade primaria.' },
23733
+ { path: 'page.composition.links[].to.ref.nestedPath[].index', category: 'connections', valueKind: 'number', description: 'Índice auxiliar para diagnóstico visual; não use como identidade primária.' },
22114
23734
  { path: 'page.composition.links[].to.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de destino.' },
22115
- { path: 'page.composition.links[].intent', category: 'connections', valueKind: 'string', description: 'Intencao semantica do link.' },
23735
+ { path: 'page.composition.links[].intent', category: 'connections', valueKind: 'string', description: 'Intenção semântica do link.' },
22116
23736
  { path: 'page.composition.links[].transform', category: 'connections', valueKind: 'object', description: 'Pipeline de transformacao do link.' },
22117
- { path: 'page.composition.links[].condition', category: 'connections', valueKind: 'expression', description: 'Guarda semantica opcional do link, expressa como um unico AST Json Logic canonico.' },
23737
+ { path: 'page.composition.links[].condition', category: 'connections', valueKind: 'expression', description: 'Guarda semântica opcional do link, expressa como um único AST Json Logic canônico.' },
22118
23738
  { path: 'page.composition.links[].policy', category: 'connections', valueKind: 'object', description: 'Politicas operacionais opcionais do link, como debounce, distinct e missing-value.' },
22119
23739
  { path: 'page.composition.links[].metadata', category: 'connections', valueKind: 'object', description: 'Metadados opcionais do link.' },
22120
23740
  { path: 'page.grouping', category: 'layout', valueKind: 'array', description: 'Modelo semantico opcional de secoes, abas, areas hero e rails.' },
@@ -22155,15 +23775,15 @@ const DYNAMIC_PAGE_AI_CAPABILITIES = {
22155
23775
  enums: ENUMS,
22156
23776
  targets: ['praxis-dynamic-page'],
22157
23777
  notes: [
22158
- 'Este catalogo e especifico para o runtime praxis-dynamic-page; operacoes de authoring/mutacao pertencem ao manifesto do praxis-page-builder.',
23778
+ 'Este catálogo é específico para o runtime praxis-dynamic-page; operações de authoring/mutação pertencem ao manifesto do praxis-page-builder.',
22159
23779
  'WidgetPageDefinition e o contrato canonico persistido: widgets, composition.links, state, context, layout, canvas, presets, grouping, slotAssignments, deviceLayouts e themePreset.',
22160
23780
  'Widgets e page.composition.links sao arrays; ferramentas de patch legadas fazem merge por key estavel e id estavel.',
22161
- 'page.canvas.items e um mapa por widget key; nao modele canvas.items como array.',
22162
- 'Taxonomia editorial: condition usa Json Logic canonico; transform usa pipeline declarativo; nao trate ambos como a mesma "expression".',
23781
+ 'page.canvas.items é um mapa por widget key; não modele canvas.items como array.',
23782
+ 'Taxonomia editorial: condition usa Json Logic canônico; transform usa pipeline declarativo; não trate ambos como a mesma "expression".',
22163
23783
  'Para remocao/replace, use flags {_remove:true} ou {_replace:true} no item.',
22164
23784
  'Para renomear um link, inclua {_beforeKey:"link-id-anterior"} no item.',
22165
- 'Inputs de widgets dependem do componente (ex: praxis-table, praxis-dynamic-form). Evite inventar campos; prefira pedir confirmacao.',
22166
- 'Quando page.widgets[].definition.id for praxis-rich-content, o host praxis-dynamic-page injeta hostCapabilities em runtime para actions e capability gating; nao serialize funcoes nem tente persistir page.widgets[].definition.inputs.hostCapabilities.',
23785
+ 'Inputs de widgets dependem do componente (ex: praxis-table, praxis-dynamic-form). Evite inventar campos; prefira pedir confirmação.',
23786
+ 'Quando page.widgets[].definition.id for praxis-rich-content, o host praxis-dynamic-page injeta hostCapabilities em runtime para actions e capability gating; não serialize funções nem tente persistir page.widgets[].definition.inputs.hostCapabilities.',
22167
23787
  'Use ids estaveis para links e keys estaveis para widgets.',
22168
23788
  'Nested component ports usam endpoint component-port com nestedPath; o owner em ref.widget continua sendo o widget top-level.',
22169
23789
  'Objetivo: compor widgets e relacionamentos canonicos (ex.: master-detail).',
@@ -22192,7 +23812,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22192
23812
  mode: 'enum',
22193
23813
  options: [
22194
23814
  { value: 'fixed', label: 'Linhas fixas' },
22195
- { value: 'content', label: 'Conteudo' },
23815
+ { value: 'content', label: 'Conteúdo' },
22196
23816
  ],
22197
23817
  },
22198
23818
  'page.canvas.collisionPolicy': {
@@ -22261,7 +23881,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22261
23881
  'page.widgets[].shell.actions[].variant': {
22262
23882
  mode: 'enum',
22263
23883
  options: [
22264
- { value: 'icon', label: 'Icone' },
23884
+ { value: 'icon', label: 'Ícone' },
22265
23885
  { value: 'text', label: 'Texto' },
22266
23886
  { value: 'outlined', label: 'Outlined' },
22267
23887
  ],
@@ -22291,7 +23911,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22291
23911
  mode: 'suggested',
22292
23912
  options: [
22293
23913
  { value: 'rowClick', label: 'Clique na linha (praxis-table)', example: 'Usar table.rowClick -> form.resourceId via transform pick-path payload.row.id' },
22294
- { value: 'rowAction', label: 'Acao da linha (praxis-table)' },
23914
+ { value: 'rowAction', label: 'Ação da linha (praxis-table)' },
22295
23915
  { value: 'formSubmit', label: 'Submit do formulario (praxis-dynamic-form)' },
22296
23916
  ],
22297
23917
  },
@@ -22305,7 +23925,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22305
23925
  'page.composition.links[].transform.steps[].config.path': {
22306
23926
  mode: 'suggested',
22307
23927
  options: [
22308
- { value: 'payload.row.id', label: 'ID padrao do registro', example: 'rowClick -> resourceId' },
23928
+ { value: 'payload.row.id', label: 'ID padrão do registro', example: 'rowClick -> resourceId' },
22309
23929
  ],
22310
23930
  },
22311
23931
  },
@@ -22617,7 +24237,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22617
24237
  { name: 'toInput', type: 'STRING' },
22618
24238
  { name: 'map', type: 'STRING' },
22619
24239
  ],
22620
- safetyNotes: 'Use transform pick-path payload.row.id para master-detail padrao.',
24240
+ safetyNotes: 'Use transform pick-path payload.row.id para master-detail padrão.',
22621
24241
  patchTemplate: {
22622
24242
  page: {
22623
24243
  composition: {
@@ -22668,7 +24288,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22668
24288
  { name: 'fromWidget', type: 'STRING' },
22669
24289
  { name: 'toWidget', type: 'STRING' },
22670
24290
  ],
22671
- safetyNotes: 'Padrao master-detail: rowClick -> resourceId com transform pick-path payload.row.id.',
24291
+ safetyNotes: 'Padrão master-detail: rowClick -> resourceId com transform pick-path payload.row.id.',
22672
24292
  patchTemplate: {
22673
24293
  page: {
22674
24294
  composition: {
@@ -22711,7 +24331,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22711
24331
  },
22712
24332
  {
22713
24333
  id: 'page.template.applyMasterDetail',
22714
- intentExamples: ['criar pagina master detail', 'setup master detail', 'tabela e formulario', 'master-detail'],
24334
+ intentExamples: ['criar página master detail', 'setup master detail', 'tabela e formulário', 'master-detail'],
22715
24335
  operation: 'create',
22716
24336
  scope: 'GLOBAL',
22717
24337
  valueType: 'OBJECT',
@@ -22720,7 +24340,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22720
24340
  { name: 'formId', type: 'STRING' },
22721
24341
  { name: 'resourcePath', type: 'STRING' },
22722
24342
  ],
22723
- safetyNotes: 'Padrao master-detail: tabela (rowClick) -> formulario (resourceId) com transform pick-path payload.row.id.',
24343
+ safetyNotes: 'Padrão master-detail: tabela (rowClick) -> formulario (resourceId) com transform pick-path payload.row.id.',
22724
24344
  patchTemplate: {
22725
24345
  page: {
22726
24346
  widgets: [
@@ -22796,30 +24416,30 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22796
24416
  },
22797
24417
  hints: [
22798
24418
  'praxis-dynamic-page e runtime de composicao: consome WidgetPageDefinition, renderiza widgets e mantem relacoes em page.composition.links.',
22799
- 'Mutacoes agentic de pagina pertencem ao manifesto do praxis-page-builder; use este context pack como descoberta/runtime guidance.',
24419
+ 'Mutações agentic de página pertencem ao manifesto do praxis-page-builder; use este context pack como descoberta/runtime guidance.',
22800
24420
  'WidgetPageDefinition inclui widgets, composition.links, state, context, layout, canvas, layoutPreset, layoutPresetOptions, grouping, slotAssignments, deviceLayouts e themePreset.',
22801
- 'page.canvas.items e um mapa por widget key, nao um array; cada entrada guarda col, row, colSpan, rowSpan, zIndex e constraints opcionais.',
24421
+ 'page.canvas.items é um mapa por widget key, não um array; cada entrada guarda col, row, colSpan, rowSpan, zIndex e constraints opcionais.',
22802
24422
  'Widgets e composition.links sao arrays; o patching deve fazer merge por key (widgets) e por id (links).',
22803
- 'Preferir mudancas incrementais: alterar/estender em vez de substituir toda a pagina.',
24423
+ 'Preferir mudanças incrementais: alterar/estender em vez de substituir toda a página.',
22804
24424
  'Para remover um item, envie {_remove: true} junto ao widget/link.',
22805
24425
  'Para substituir um item inteiro, envie {_replace: true}.',
22806
24426
  'Para alterar origem/destino de link, use {_beforeKey} com o id antigo.',
22807
24427
  'Use keys estaveis para widgets e ids estaveis para links ao criar composicoes.',
22808
24428
  'resourcePath sempre e o path base do recurso (sem /filter, /all).',
22809
- 'Praxis Table gera colunas dinamicamente a partir do resourcePath quando columns nao forem definidas.',
22810
- 'Praxis Dynamic Form gera campos dinamicamente a partir do resourcePath quando config nao for definida.',
22811
- 'Quando um widget praxis-rich-content estiver hospedado na pagina, definition.inputs.document continua sendo o contrato persistido; hostCapabilities e injetado somente em runtime pelo praxis-dynamic-page para actions e capability gating.',
24429
+ 'Praxis Table gera colunas dinamicamente a partir do resourcePath quando columns não forem definidas.',
24430
+ 'Praxis Dynamic Form gera campos dinamicamente a partir do resourcePath quando config não for definida.',
24431
+ 'Quando um widget praxis-rich-content estiver hospedado na página, definition.inputs.document continua sendo o contrato persistido; hostCapabilities é injetado somente em runtime pelo praxis-dynamic-page para actions e capability gating.',
22812
24432
  'Praxis List pode filtrar via config.dataSource.query (enviado para /filter).',
22813
24433
  'Quando houver recursos secundarios (ex.: enderecos), use contextHints.addressResourcePath.',
22814
24434
  'Exemplo master-detail: tabela emite rowClick -> form.resourceId via transform pick-path payload.row.id.',
22815
24435
  'Pattern Master-Detail: { "id":"master.rowClick->detail.resourceId", "from":{"kind":"component-port","ref":{"port":"rowClick","direction":"output"}}, "to":{"kind":"component-port","ref":{"port":"resourceId","direction":"input"}}, "transform":{"steps":[{"kind":"pick-path","config":{"path":"payload.row.id"}}]}}',
22816
24436
  'Ao criar widgets, use inputs minimos e complemente depois (evite inventar campos).',
22817
24437
  'Quando widgets ja existem, interpretar ports de origem/destino antes de conectar.',
22818
- 'Intencao comum: criar pagina master-detail = criar tabela + criar formulario + conectar selecao via composition.links.',
22819
- 'Intencao comum: ajustar pagina existente = modificar apenas widgets/inputs necessarios.',
24438
+ 'Intenção comum: criar página master-detail = criar tabela + criar formulário + conectar seleção via composition.links.',
24439
+ 'Intenção comum: ajustar página existente = modificar apenas widgets/inputs necessários.',
22820
24440
  'Exemplo de link canonico (master-detail): { id:"masterTable.rowClick->detailForm.resourceId", from:{kind:"component-port",ref:{widget:"masterTable",port:"rowClick",direction:"output"}}, to:{kind:"component-port",ref:{widget:"detailForm",port:"resourceId",direction:"input"}}, intent:"event-propagation", transform:{version:"2.0",phase:"link-propagation",mode:"single-value",steps:[{kind:"pick-path",phase:"link-propagation",input:{source:"event"},config:{path:"payload.row.id"}}]}}',
22821
- 'Exemplo de widget tabela (minimo): { key:"masterTable", definition:{ id:"praxis-table", inputs:{ resourcePath:"/api/x" }}}',
22822
- 'Exemplo de widget formulario (minimo): { key:"detailForm", definition:{ id:"praxis-dynamic-form", inputs:{ resourcePath:"/api/x", mode:"view" }}}',
24441
+ 'Exemplo de widget tabela (mínimo): { key:"masterTable", definition:{ id:"praxis-table", inputs:{ resourcePath:"/api/x" }}}',
24442
+ 'Exemplo de widget formulário (mínimo): { key:"detailForm", definition:{ id:"praxis-dynamic-form", inputs:{ resourcePath:"/api/x", mode:"view" }}}',
22823
24443
  'Se houver idField conhecido, use transform pick-path payload.row.{idField} em links canonicos.',
22824
24444
  ],
22825
24445
  };
@@ -24945,9 +26565,21 @@ class DynamicWidgetLoaderDirective {
24945
26565
  const defaultOrderMap = {
24946
26566
  'praxis-table': ['tableId', 'componentInstanceId', 'configPersistenceStrategy', 'resourcePath', 'data', 'config'],
24947
26567
  'praxis-crud': ['crudId', 'componentInstanceId', 'metadata'],
24948
- 'praxis-dynamic-form': ['formId', 'componentInstanceId', 'resourcePath'],
26568
+ 'praxis-dynamic-form': [
26569
+ 'formId',
26570
+ 'componentInstanceId',
26571
+ 'resourcePath',
26572
+ 'schemaUrl',
26573
+ 'submitUrl',
26574
+ 'submitMethod',
26575
+ 'apiEndpointKey',
26576
+ 'apiUrlEntry',
26577
+ 'initialValue',
26578
+ 'mode',
26579
+ 'layoutPolicy',
26580
+ ],
24949
26581
  'praxis-tabs': ['tabsId', 'componentInstanceId', 'configPersistenceStrategy', 'config'],
24950
- 'praxis-list': ['listId', 'componentInstanceId', 'config'],
26582
+ 'praxis-list': ['listId', 'componentInstanceId', 'enableCustomization', 'config'],
24951
26583
  'praxis-expansion': ['expansionId', 'componentInstanceId', 'config'],
24952
26584
  'praxis-stepper': ['stepperId', 'componentInstanceId', 'config'],
24953
26585
  'praxis-files-upload': ['filesUploadId', 'componentInstanceId', 'config'],
@@ -25307,28 +26939,160 @@ const BUILTIN_SHELL_PRESETS = {
25307
26939
  },
25308
26940
  'light-neutral': {
25309
26941
  card: {
25310
- background: '#f8fafc',
25311
- borderColor: '#d7dfeb',
26942
+ background: 'var(--md-sys-color-surface)',
26943
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 82%, transparent)',
25312
26944
  borderRadius: '12px',
25313
- shadow: '0 4px 12px rgba(15, 23, 42, 0.06)',
26945
+ shadow: '0 4px 14px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
25314
26946
  },
25315
26947
  header: {
25316
- titleColor: '#1f2937',
25317
- subtitleColor: '#6b7280',
25318
- iconColor: '#0f172a',
26948
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 72%, transparent)',
26949
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 70%, transparent)',
26950
+ titleColor: 'var(--md-sys-color-on-surface)',
26951
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
26952
+ iconColor: 'var(--md-sys-color-primary)',
26953
+ },
26954
+ body: {
26955
+ background: 'var(--md-sys-color-surface)',
26956
+ textColor: 'var(--md-sys-color-on-surface)',
25319
26957
  },
25320
26958
  },
25321
26959
  graphite: {
25322
26960
  card: {
25323
- background: '#1c1f24',
25324
- borderColor: 'rgba(255,255,255,0.08)',
25325
- borderRadius: '14px',
25326
- shadow: '0 10px 22px rgba(0,0,0,0.28)',
26961
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-surface-container-high) 6%)',
26962
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 74%, transparent)',
26963
+ borderRadius: '12px',
26964
+ shadow: '0 8px 22px color-mix(in srgb, var(--md-sys-color-shadow, #000) 11%, transparent)',
26965
+ },
26966
+ header: {
26967
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 76%, transparent)',
26968
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 62%, transparent)',
26969
+ titleColor: 'var(--md-sys-color-on-surface)',
26970
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
26971
+ iconColor: 'var(--md-sys-color-primary)',
26972
+ },
26973
+ body: {
26974
+ background: 'var(--md-sys-color-surface)',
26975
+ textColor: 'var(--md-sys-color-on-surface)',
26976
+ },
26977
+ },
26978
+ frameless: {
26979
+ card: {
26980
+ background: 'transparent',
26981
+ borderColor: 'transparent',
26982
+ borderRadius: '0',
26983
+ shadow: 'none',
26984
+ },
26985
+ header: {
26986
+ background: 'transparent',
26987
+ borderColor: 'transparent',
26988
+ titleColor: 'var(--md-sys-color-on-surface)',
26989
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
26990
+ iconColor: 'var(--md-sys-color-primary)',
26991
+ },
26992
+ body: {
26993
+ background: 'transparent',
26994
+ textColor: 'var(--md-sys-color-on-surface)',
26995
+ padding: '0',
26996
+ },
26997
+ },
26998
+ 'data-panel': {
26999
+ card: {
27000
+ background: 'var(--md-sys-color-surface)',
27001
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 76%, transparent)',
27002
+ borderRadius: '10px',
27003
+ shadow: '0 5px 16px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
27004
+ },
27005
+ header: {
27006
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 64%, transparent)',
27007
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 58%, transparent)',
27008
+ titleColor: 'var(--md-sys-color-on-surface)',
27009
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27010
+ iconColor: 'var(--md-sys-color-primary)',
27011
+ },
27012
+ body: {
27013
+ background: 'var(--md-sys-color-surface)',
27014
+ textColor: 'var(--md-sys-color-on-surface)',
27015
+ padding: '12px',
27016
+ },
27017
+ },
27018
+ 'chart-panel': {
27019
+ card: {
27020
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%)',
27021
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-outline-variant) 62%)',
27022
+ borderRadius: '12px',
27023
+ shadow: '0 10px 24px color-mix(in srgb, var(--md-sys-color-shadow, #000) 9%, transparent)',
27024
+ },
27025
+ header: {
27026
+ background: 'color-mix(in srgb, var(--md-sys-color-primary-container) 22%, transparent)',
27027
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 20%, transparent)',
27028
+ titleColor: 'var(--md-sys-color-on-surface)',
27029
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27030
+ iconColor: 'var(--md-sys-color-primary)',
27031
+ },
27032
+ body: {
27033
+ background: 'transparent',
27034
+ textColor: 'var(--md-sys-color-on-surface)',
27035
+ padding: '12px',
27036
+ },
27037
+ },
27038
+ 'metric-panel': {
27039
+ card: {
27040
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 78%, var(--md-sys-color-primary-container) 22%)',
27041
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 24%, transparent)',
27042
+ borderRadius: '10px',
27043
+ shadow: '0 8px 18px color-mix(in srgb, var(--md-sys-color-shadow, #000) 8%, transparent)',
27044
+ },
27045
+ header: {
27046
+ background: 'transparent',
27047
+ borderColor: 'transparent',
27048
+ titleColor: 'var(--md-sys-color-on-surface)',
27049
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27050
+ iconColor: 'var(--md-sys-color-primary)',
27051
+ },
27052
+ body: {
27053
+ background: 'transparent',
27054
+ textColor: 'var(--md-sys-color-on-surface)',
27055
+ padding: '10px 12px',
27056
+ },
27057
+ },
27058
+ 'executive-card': {
27059
+ card: {
27060
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 88%, var(--md-sys-color-surface-container-high) 12%)',
27061
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 28%, var(--md-sys-color-outline-variant) 50%)',
27062
+ borderRadius: '10px',
27063
+ shadow: '0 12px 28px color-mix(in srgb, var(--md-sys-color-shadow, #000) 13%, transparent)',
27064
+ },
27065
+ header: {
27066
+ background: 'color-mix(in srgb, var(--md-sys-color-primary-container) 18%, transparent)',
27067
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent)',
27068
+ titleColor: 'var(--md-sys-color-on-surface)',
27069
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27070
+ iconColor: 'var(--md-sys-color-primary)',
27071
+ },
27072
+ body: {
27073
+ background: 'transparent',
27074
+ textColor: 'var(--md-sys-color-on-surface)',
27075
+ padding: '14px',
27076
+ },
27077
+ },
27078
+ 'filter-bar': {
27079
+ card: {
27080
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 74%, var(--md-sys-color-secondary-container) 26%)',
27081
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-secondary) 24%, transparent)',
27082
+ borderRadius: '999px',
27083
+ shadow: '0 6px 18px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
25327
27084
  },
25328
27085
  header: {
25329
- titleColor: '#f3f4f6',
25330
- subtitleColor: '#9ca3af',
25331
- iconColor: '#cbd5f5',
27086
+ background: 'transparent',
27087
+ borderColor: 'transparent',
27088
+ titleColor: 'var(--md-sys-color-on-surface)',
27089
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27090
+ iconColor: 'var(--md-sys-color-secondary)',
27091
+ },
27092
+ body: {
27093
+ background: 'transparent',
27094
+ textColor: 'var(--md-sys-color-on-surface)',
27095
+ padding: '10px 14px',
25332
27096
  },
25333
27097
  },
25334
27098
  };
@@ -25404,6 +27168,11 @@ class WidgetShellComponent {
25404
27168
  const builtins = this.buildWindowActions(custom);
25405
27169
  return [...builtins, ...custom];
25406
27170
  }
27171
+ displayActionIcon(action) {
27172
+ return action.pressed === true && action.pressedIcon
27173
+ ? action.pressedIcon
27174
+ : action.icon;
27175
+ }
25407
27176
  onAction(action, ev) {
25408
27177
  ev.stopPropagation();
25409
27178
  const handled = this.handleWindowAction(action);
@@ -25413,6 +27182,7 @@ class WidgetShellComponent {
25413
27182
  command: action.command,
25414
27183
  emit: action.emit,
25415
27184
  payload,
27185
+ pressed: action.pressed,
25416
27186
  action,
25417
27187
  };
25418
27188
  this.loader?.dispatchAction(event);
@@ -25603,14 +27373,16 @@ class WidgetShellComponent {
25603
27373
  <button
25604
27374
  [disabled]="action.disabled"
25605
27375
  [matTooltip]="action.tooltip || ''"
25606
- matTooltipPosition="below"
27376
+ matTooltipPosition="above"
25607
27377
  [ngClass]="action.variant === 'outlined' ? 'pdx-action-outlined' : 'pdx-action-text'"
27378
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25608
27379
  mat-button
25609
27380
  type="button"
27381
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25610
27382
  (click)="onAction(action, $event)"
25611
27383
  >
25612
- @if (action.icon) {
25613
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27384
+ @if (displayActionIcon(action); as actionIcon) {
27385
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25614
27386
  }
25615
27387
  <span class="pdx-action-label">{{ action.label }}</span>
25616
27388
  </button>
@@ -25620,13 +27392,15 @@ class WidgetShellComponent {
25620
27392
  mat-icon-button
25621
27393
  [disabled]="action.disabled"
25622
27394
  [matTooltip]="action.tooltip || action.label || ''"
25623
- matTooltipPosition="below"
27395
+ matTooltipPosition="above"
25624
27396
  [attr.aria-label]="action.label || action.tooltip || action.id"
27397
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27398
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25625
27399
  type="button"
25626
27400
  (click)="onAction(action, $event)"
25627
27401
  >
25628
- @if (action.icon) {
25629
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27402
+ @if (displayActionIcon(action); as actionIcon) {
27403
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25630
27404
  }
25631
27405
  </button>
25632
27406
  }
@@ -25637,7 +27411,7 @@ class WidgetShellComponent {
25637
27411
  mat-icon-button
25638
27412
  type="button"
25639
27413
  [matTooltip]="moreActionsLabel()"
25640
- matTooltipPosition="below"
27414
+ matTooltipPosition="above"
25641
27415
  [attr.aria-label]="moreActionsLabel()"
25642
27416
  [matMenuTriggerFor]="overflowMenu"
25643
27417
  (click)="$event.stopPropagation()"
@@ -25653,13 +27427,15 @@ class WidgetShellComponent {
25653
27427
  mat-icon-button
25654
27428
  [disabled]="action.disabled"
25655
27429
  [matTooltip]="action.tooltip || action.label || ''"
25656
- matTooltipPosition="below"
27430
+ matTooltipPosition="above"
25657
27431
  [attr.aria-label]="action.label || action.tooltip || action.id"
27432
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27433
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25658
27434
  type="button"
25659
27435
  (click)="onAction(action, $event)"
25660
27436
  >
25661
- @if (action.icon) {
25662
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27437
+ @if (displayActionIcon(action); as actionIcon) {
27438
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25663
27439
  }
25664
27440
  </button>
25665
27441
  }
@@ -25670,10 +27446,11 @@ class WidgetShellComponent {
25670
27446
  @for (action of overflowHeaderActions; track action.id) {
25671
27447
  <button
25672
27448
  mat-menu-item
27449
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25673
27450
  (click)="onAction(action, $event)"
25674
27451
  >
25675
- @if (action.icon) {
25676
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27452
+ @if (displayActionIcon(action); as actionIcon) {
27453
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25677
27454
  }
25678
27455
  <span>{{ action.label || action.id }}</span>
25679
27456
  </button>
@@ -25688,7 +27465,7 @@ class WidgetShellComponent {
25688
27465
  @if (expanded || fullscreen) {
25689
27466
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
25690
27467
  }
25691
- `, 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;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "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$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 });
27468
+ `, 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-shell-action--pressed{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "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$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 });
25692
27469
  }
25693
27470
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, decorators: [{
25694
27471
  type: Component,
@@ -25747,14 +27524,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25747
27524
  <button
25748
27525
  [disabled]="action.disabled"
25749
27526
  [matTooltip]="action.tooltip || ''"
25750
- matTooltipPosition="below"
27527
+ matTooltipPosition="above"
25751
27528
  [ngClass]="action.variant === 'outlined' ? 'pdx-action-outlined' : 'pdx-action-text'"
27529
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25752
27530
  mat-button
25753
27531
  type="button"
27532
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25754
27533
  (click)="onAction(action, $event)"
25755
27534
  >
25756
- @if (action.icon) {
25757
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27535
+ @if (displayActionIcon(action); as actionIcon) {
27536
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25758
27537
  }
25759
27538
  <span class="pdx-action-label">{{ action.label }}</span>
25760
27539
  </button>
@@ -25764,13 +27543,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25764
27543
  mat-icon-button
25765
27544
  [disabled]="action.disabled"
25766
27545
  [matTooltip]="action.tooltip || action.label || ''"
25767
- matTooltipPosition="below"
27546
+ matTooltipPosition="above"
25768
27547
  [attr.aria-label]="action.label || action.tooltip || action.id"
27548
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27549
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25769
27550
  type="button"
25770
27551
  (click)="onAction(action, $event)"
25771
27552
  >
25772
- @if (action.icon) {
25773
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27553
+ @if (displayActionIcon(action); as actionIcon) {
27554
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25774
27555
  }
25775
27556
  </button>
25776
27557
  }
@@ -25781,7 +27562,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25781
27562
  mat-icon-button
25782
27563
  type="button"
25783
27564
  [matTooltip]="moreActionsLabel()"
25784
- matTooltipPosition="below"
27565
+ matTooltipPosition="above"
25785
27566
  [attr.aria-label]="moreActionsLabel()"
25786
27567
  [matMenuTriggerFor]="overflowMenu"
25787
27568
  (click)="$event.stopPropagation()"
@@ -25797,13 +27578,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25797
27578
  mat-icon-button
25798
27579
  [disabled]="action.disabled"
25799
27580
  [matTooltip]="action.tooltip || action.label || ''"
25800
- matTooltipPosition="below"
27581
+ matTooltipPosition="above"
25801
27582
  [attr.aria-label]="action.label || action.tooltip || action.id"
27583
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27584
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25802
27585
  type="button"
25803
27586
  (click)="onAction(action, $event)"
25804
27587
  >
25805
- @if (action.icon) {
25806
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27588
+ @if (displayActionIcon(action); as actionIcon) {
27589
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25807
27590
  }
25808
27591
  </button>
25809
27592
  }
@@ -25814,10 +27597,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25814
27597
  @for (action of overflowHeaderActions; track action.id) {
25815
27598
  <button
25816
27599
  mat-menu-item
27600
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25817
27601
  (click)="onAction(action, $event)"
25818
27602
  >
25819
- @if (action.icon) {
25820
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27603
+ @if (displayActionIcon(action); as actionIcon) {
27604
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25821
27605
  }
25822
27606
  <span>{{ action.label || action.id }}</span>
25823
27607
  </button>
@@ -25832,7 +27616,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25832
27616
  @if (expanded || fullscreen) {
25833
27617
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
25834
27618
  }
25835
- `, changeDetection: ChangeDetectionStrategy.OnPush, 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;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
27619
+ `, changeDetection: ChangeDetectionStrategy.OnPush, 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-shell-action--pressed{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
25836
27620
  }], propDecorators: { hostCollapsed: [{
25837
27621
  type: HostBinding,
25838
27622
  args: ['class.pdx-widget-shell-collapsed']
@@ -26010,7 +27794,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26010
27794
  id: 'analytics-calm',
26011
27795
  label: 'Analytics Calm',
26012
27796
  description: 'Superfícies leves, ênfase clara em dados e motion sutil.',
26013
- shellPreset: 'light-neutral',
27797
+ shellPreset: 'chart-panel',
26014
27798
  chartThemePreset: 'executive',
26015
27799
  density: 'comfortable',
26016
27800
  motion: 'subtle',
@@ -26027,7 +27811,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26027
27811
  id: 'workspace-balanced',
26028
27812
  label: 'Workspace Balanced',
26029
27813
  description: 'Equilíbrio entre densidade operacional e clareza visual.',
26030
- shellPreset: 'light-neutral',
27814
+ shellPreset: 'data-panel',
26031
27815
  chartThemePreset: 'default',
26032
27816
  density: 'comfortable',
26033
27817
  motion: 'subtle',
@@ -26044,7 +27828,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26044
27828
  id: 'ops-monitoring',
26045
27829
  label: 'Ops Monitoring',
26046
27830
  description: 'Contraste um pouco maior para leitura rápida de status, filas e alertas.',
26047
- shellPreset: 'graphite',
27831
+ shellPreset: 'data-panel',
26048
27832
  chartThemePreset: 'compact',
26049
27833
  density: 'compact',
26050
27834
  motion: 'subtle',
@@ -26061,7 +27845,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26061
27845
  id: 'executive-command-center',
26062
27846
  label: 'Executive Command Center',
26063
27847
  description: 'Superfície premium para dashboards corporativos com hierarquia executiva, dados densos e ações de decisão.',
26064
- shellPreset: 'graphite',
27848
+ shellPreset: 'executive-card',
26065
27849
  chartThemePreset: 'executive',
26066
27850
  density: 'compact',
26067
27851
  motion: 'subtle',
@@ -31033,9 +32817,18 @@ class DynamicWidgetPageComponent {
31033
32817
  if (!widget.shell) {
31034
32818
  return runtimeEnrichedWidget;
31035
32819
  }
32820
+ const widgetTemplateContext = {
32821
+ ...templateContext,
32822
+ widget: {
32823
+ key: widget.key,
32824
+ definition: this.cloneStateValues(widget.definition),
32825
+ inputs: this.cloneStateValues(widget.definition?.inputs || {}),
32826
+ shell: this.cloneStateValues(widget.shell || {}),
32827
+ },
32828
+ };
31036
32829
  return {
31037
32830
  ...runtimeEnrichedWidget,
31038
- shell: this.resolveTemplate(widget.shell, templateContext),
32831
+ shell: this.resolveTemplate(widget.shell, widgetTemplateContext),
31039
32832
  };
31040
32833
  });
31041
32834
  }
@@ -31088,9 +32881,16 @@ class DynamicWidgetPageComponent {
31088
32881
  origin: 'dynamic-page.rich-content',
31089
32882
  componentId: 'praxis-dynamic-page',
31090
32883
  },
32884
+ }).then((result) => {
32885
+ if (!result?.success) {
32886
+ this.emitRichContentCustomAction(widgetKey, actionId, payload);
32887
+ }
31091
32888
  });
31092
32889
  return;
31093
32890
  }
32891
+ this.emitRichContentCustomAction(widgetKey, actionId, payload);
32892
+ }
32893
+ emitRichContentCustomAction(widgetKey, actionId, payload) {
31094
32894
  this.onWidgetEvent(widgetKey, {
31095
32895
  ownerWidgetKey: widgetKey,
31096
32896
  sourceComponentId: 'praxis-rich-content',
@@ -31412,6 +33212,8 @@ class DynamicWidgetPageComponent {
31412
33212
  void this.confirmAndRemoveWidget(fromKey);
31413
33213
  return;
31414
33214
  }
33215
+ if (this.handleToggleInputCommand(fromKey, evt))
33216
+ return;
31415
33217
  if (this.handleSetInputCommand(fromKey, evt))
31416
33218
  return;
31417
33219
  const output = evt?.emit || (evt?.id ? `shell:${evt.id}` : undefined);
@@ -31436,6 +33238,32 @@ class DynamicWidgetPageComponent {
31436
33238
  this.widgets.set(widgets);
31437
33239
  return true;
31438
33240
  }
33241
+ handleToggleInputCommand(fromKey, evt) {
33242
+ if (evt?.command !== 'pdx:toggle-input')
33243
+ return false;
33244
+ const payload = evt?.payload;
33245
+ const input = typeof payload?.input === 'string' ? payload.input.trim() : '';
33246
+ if (!input)
33247
+ return true;
33248
+ const page = this.ensurePageDefinition();
33249
+ const widget = (page.widgets || []).find((candidate) => candidate.key === fromKey);
33250
+ const currentValue = this.lookup(widget?.definition?.inputs || {}, input);
33251
+ const nextValue = !Boolean(currentValue);
33252
+ const result = this.applyWidgetInputPatchToPage(page, fromKey, {
33253
+ ownerWidgetKey: fromKey,
33254
+ sourceComponentId: 'widget-shell',
33255
+ output: evt.emit || `shell:${evt.id}`,
33256
+ payload: {
33257
+ inputPatch: {
33258
+ [input]: nextValue,
33259
+ },
33260
+ },
33261
+ });
33262
+ if (result.changed) {
33263
+ this.applyPageUpdate(result.page, true, undefined, false, true);
33264
+ }
33265
+ return true;
33266
+ }
31439
33267
  mergeOrder(keys) {
31440
33268
  const seen = new Set();
31441
33269
  const out = [];
@@ -33974,24 +35802,24 @@ const PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA = {
33974
35802
  selector: 'praxis-dynamic-page',
33975
35803
  component: DynamicWidgetPageComponent,
33976
35804
  friendlyName: 'Dynamic Page',
33977
- description: 'Pagina dinamica com widgets e composition.links em layout responsivo, incluindo mediacao runtime para rich-content hospedado.',
35805
+ description: 'Página dinâmica com widgets e composition.links em layout responsivo, incluindo mediação runtime para rich-content hospedado.',
33978
35806
  icon: 'dashboard',
33979
35807
  inputs: [
33980
- { name: 'page', type: 'WidgetPageDefinition', description: 'Definicao da pagina (widgets, layout e composition.links).' },
35808
+ { name: 'page', type: 'WidgetPageDefinition', description: 'Definição da página (widgets, layout e composition.links).' },
33981
35809
  { name: 'context', type: 'Record<string, any>', description: 'Contexto adicional compartilhado entre widgets.' },
33982
- { name: 'strictValidation', type: 'boolean', description: 'Habilita validacao estrita de inputs.' },
33983
- { name: 'enableCustomization', type: 'boolean', description: 'Habilita affordances de edicao na pagina.' },
33984
- { name: 'showPageSettingsButton', type: 'boolean', description: 'Exibe botao de configuracao da pagina.' },
35810
+ { name: 'strictValidation', type: 'boolean', description: 'Habilita validação estrita de inputs.' },
35811
+ { name: 'enableCustomization', type: 'boolean', description: 'Habilita affordances de edição na página.' },
35812
+ { name: 'showPageSettingsButton', type: 'boolean', description: 'Exibe botão de configuração da página.' },
33985
35813
  { name: 'shellEditorComponent', type: 'Type<any>', description: 'Override do editor de shell dos widgets.' },
33986
- { name: 'pageEditorComponent', type: 'Type<any>', description: 'Override do editor de configuracao da pagina.' },
33987
- { name: 'autoPersist', type: 'boolean', description: 'Ativa persistencia automatica (load/save) da pagina.' },
33988
- { name: 'pageIdentity', type: 'PageIdentity', description: 'Identidade de persistencia (tenant/usuario/rota/locale).' },
33989
- { name: 'componentInstanceId', type: 'string', description: 'Identificador opcional para multiplas instancias na mesma rota.' },
35814
+ { name: 'pageEditorComponent', type: 'Type<any>', description: 'Override do editor de configuração da página.' },
35815
+ { name: 'autoPersist', type: 'boolean', description: 'Ativa persistência automática (load/save) da página.' },
35816
+ { name: 'pageIdentity', type: 'PageIdentity', description: 'Identidade de persistência (tenant/usuário/rota/locale).' },
35817
+ { name: 'componentInstanceId', type: 'string', description: 'Identificador opcional para múltiplas instâncias na mesma rota.' },
33990
35818
  ],
33991
35819
  outputs: [
33992
- { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitido ao alterar a definicao da pagina.' },
33993
- { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos dos widgets filhos com ownerWidgetKey para integracoes do host.' },
33994
- { name: 'widgetDiagnosticsChange', type: 'Record<string, WidgetResolutionDiagnostic>', description: 'Emitido quando o runtime detecta widgets resolvidos ou falhos durante o carregamento dinamico.' },
35820
+ { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitido ao alterar a definição da página.' },
35821
+ { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos dos widgets filhos com ownerWidgetKey para integrações do host.' },
35822
+ { name: 'widgetDiagnosticsChange', type: 'Record<string, WidgetResolutionDiagnostic>', description: 'Emitido quando o runtime detecta widgets resolvidos ou falhos durante o carregamento dinâmico.' },
33995
35823
  ],
33996
35824
  tags: ['widget', 'page', 'dynamic', 'layout'],
33997
35825
  lib: '@praxisui/core',
@@ -34026,6 +35854,8 @@ class PraxisSurfaceHostComponent {
34026
35854
  */
34027
35855
  renderTitleInsideBody = false;
34028
35856
  widgetEvent = new EventEmitter();
35857
+ rowClick = new EventEmitter();
35858
+ selectionChange = new EventEmitter();
34029
35859
  beforeWidgetLoader;
34030
35860
  mainWidgetLoader;
34031
35861
  afterWidgetLoader;
@@ -34139,13 +35969,19 @@ class PraxisSurfaceHostComponent {
34139
35969
  }
34140
35970
  }
34141
35971
  onSlotWidgetEvent(ownerWidgetKey, event) {
35972
+ if (event.output === 'rowClick') {
35973
+ this.rowClick.emit(event.payload);
35974
+ }
35975
+ if (event.output === 'selectionChange') {
35976
+ this.selectionChange.emit(event.payload);
35977
+ }
34142
35978
  this.widgetEvent.emit({
34143
35979
  ...event,
34144
35980
  ownerWidgetKey: event.ownerWidgetKey || ownerWidgetKey,
34145
35981
  });
34146
35982
  }
34147
35983
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisSurfaceHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
34148
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisSurfaceHostComponent, isStandalone: true, selector: "praxis-surface-host", inputs: { title: "title", subtitle: "subtitle", icon: "icon", beforeWidget: "beforeWidget", widget: "widget", afterWidget: "afterWidget", context: "context", strictValidation: "strictValidation", renderTitleInsideBody: "renderTitleInsideBody" }, outputs: { widgetEvent: "widgetEvent" }, viewQueries: [{ propertyName: "beforeWidgetLoader", first: true, predicate: ["beforeWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "mainWidgetLoader", first: true, predicate: ["mainWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "afterWidgetLoader", first: true, predicate: ["afterWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }], usesOnChanges: true, ngImport: i0, template: `
35984
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisSurfaceHostComponent, isStandalone: true, selector: "praxis-surface-host", inputs: { title: "title", subtitle: "subtitle", icon: "icon", beforeWidget: "beforeWidget", widget: "widget", afterWidget: "afterWidget", context: "context", strictValidation: "strictValidation", renderTitleInsideBody: "renderTitleInsideBody" }, outputs: { widgetEvent: "widgetEvent", rowClick: "rowClick", selectionChange: "selectionChange" }, viewQueries: [{ propertyName: "beforeWidgetLoader", first: true, predicate: ["beforeWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "mainWidgetLoader", first: true, predicate: ["mainWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }, { propertyName: "afterWidgetLoader", first: true, predicate: ["afterWidgetLoader"], descendants: true, read: DynamicWidgetLoaderDirective }], usesOnChanges: true, ngImport: i0, template: `
34149
35985
  <div class="pdx-surface-host">
34150
35986
  @if (subtitle || (title && renderTitleInsideBody)) {
34151
35987
  <header class="pdx-surface-host__header">
@@ -34172,6 +36008,7 @@ class PraxisSurfaceHostComponent {
34172
36008
  [ownerWidgetKey]="beforeWidgetKey"
34173
36009
  [context]="context"
34174
36010
  [strictValidation]="strictValidation"
36011
+ [autoWireOutputs]="true"
34175
36012
  (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34176
36013
  ></ng-container>
34177
36014
  </div>
@@ -34184,6 +36021,7 @@ class PraxisSurfaceHostComponent {
34184
36021
  [ownerWidgetKey]="mainWidgetKey"
34185
36022
  [context]="context"
34186
36023
  [strictValidation]="strictValidation"
36024
+ [autoWireOutputs]="true"
34187
36025
  (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
34188
36026
  ></ng-container>
34189
36027
  }
@@ -34196,6 +36034,7 @@ class PraxisSurfaceHostComponent {
34196
36034
  [ownerWidgetKey]="afterWidgetKey"
34197
36035
  [context]="context"
34198
36036
  [strictValidation]="strictValidation"
36037
+ [autoWireOutputs]="true"
34199
36038
  (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34200
36039
  ></ng-container>
34201
36040
  </div>
@@ -34233,6 +36072,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34233
36072
  [ownerWidgetKey]="beforeWidgetKey"
34234
36073
  [context]="context"
34235
36074
  [strictValidation]="strictValidation"
36075
+ [autoWireOutputs]="true"
34236
36076
  (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34237
36077
  ></ng-container>
34238
36078
  </div>
@@ -34245,6 +36085,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34245
36085
  [ownerWidgetKey]="mainWidgetKey"
34246
36086
  [context]="context"
34247
36087
  [strictValidation]="strictValidation"
36088
+ [autoWireOutputs]="true"
34248
36089
  (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
34249
36090
  ></ng-container>
34250
36091
  }
@@ -34257,6 +36098,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34257
36098
  [ownerWidgetKey]="afterWidgetKey"
34258
36099
  [context]="context"
34259
36100
  [strictValidation]="strictValidation"
36101
+ [autoWireOutputs]="true"
34260
36102
  (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34261
36103
  ></ng-container>
34262
36104
  </div>
@@ -34284,6 +36126,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34284
36126
  type: Input
34285
36127
  }], widgetEvent: [{
34286
36128
  type: Output
36129
+ }], rowClick: [{
36130
+ type: Output
36131
+ }], selectionChange: [{
36132
+ type: Output
34287
36133
  }], beforeWidgetLoader: [{
34288
36134
  type: ViewChild,
34289
36135
  args: ['beforeWidgetLoader', { read: DynamicWidgetLoaderDirective }]
@@ -35244,15 +37090,9 @@ function applyLocalCustomizations$1(base, local) {
35244
37090
  // Server authority on identity/core props
35245
37091
  const authoritative = {
35246
37092
  name: base.name,
35247
- label: base.label,
35248
37093
  type: base.type,
35249
37094
  controlType: base.controlType,
35250
37095
  required: base.required,
35251
- hint: base.hint,
35252
- helpText: base.helpText,
35253
- description: base.description,
35254
- icon: base.icon,
35255
- iconPosition: base.iconPosition,
35256
37096
  endpoint: base.endpoint,
35257
37097
  resourcePath: base.resourcePath,
35258
37098
  optionSource: base.optionSource,
@@ -35288,12 +37128,13 @@ function applyLocalCustomizations$1(base, local) {
35288
37128
  ? serverBackedLocal.queryParams
35289
37129
  : base.queryParams,
35290
37130
  };
35291
- return {
37131
+ const merged = {
35292
37132
  ...base,
35293
37133
  ...serverBackedLocal,
35294
37134
  ...authoritative,
35295
37135
  ...preserved,
35296
37136
  };
37137
+ return applyServerOwnedFieldSemantics(merged, base);
35297
37138
  }
35298
37139
  function mergeServerVisibilityFlag(serverValue) {
35299
37140
  return serverValue === true ? true : undefined;
@@ -35758,4 +37599,4 @@ function provideHookWhitelist(allowed) {
35758
37599
  * Generated bundle index. Do not edit.
35759
37600
  */
35760
37601
 
35761
- 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_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, 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, PraxisRuntimeComponentObservationRegistryService, 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, SurfaceOpenMaterializerService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, 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, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, 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, registerPraxisRuntimeComponentObservation, removeDiacritics, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, 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 };
37602
+ 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, EnterpriseRuntimeContextService, ErrorMessageService, FIELD_METADATA_CAPABILITIES, FIELD_SELECTOR_REGISTRY_BASE, FIELD_SELECTOR_REGISTRY_DISABLE_DEFAULTS, FIELD_SELECTOR_REGISTRY_OVERRIDES, FORM_HOOKS, FORM_HOOKS_PRESETS, FORM_HOOKS_WHITELIST, FORM_HOOK_RESOLVERS, FieldControlType, FieldDataType, FieldSelectorRegistry, FormHooksRegistry, GLOBAL_ACTION_CATALOG, GLOBAL_ACTION_HANDLERS, GLOBAL_ACTION_UI_SCHEMAS, GLOBAL_ANALYTICS_SERVICE, GLOBAL_API_CLIENT, GLOBAL_CONFIG, GLOBAL_DIALOG_SERVICE, GLOBAL_ROUTE_GUARD_RESOLVER, GLOBAL_SURFACE_SERVICE, GLOBAL_TOAST_SERVICE, GenericCrudService, GlobalActionService, GlobalConfigService, INLINE_FILTER_ALIAS_TOKENS, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_SET, INLINE_FILTER_CONTROL_TYPE_VALUES, INLINE_FILTER_TOKEN_TO_BASE_CONTROL_TYPE, INLINE_FILTER_TOKEN_TO_CONTROL_TYPE, IconPickerService, IconPosition, IconSize, LOGGER_LEVEL_BY_ENV, LOGGER_LEVEL_PRIORITY, LoadingOrchestrator, LocalConnectionStorage, LocalStorageAsyncAdapter, LocalStorageCacheAdapter, LocalStorageConfigService, LoggerService, LoggerThrottleTracker, LoggerWarnOnceTracker, MemoryCacheAdapter, NestedPortCatalogService, NestedWidgetConfigAccessor, NumericFormat, OVERLAY_DECIDER_DEBUG, OVERLAY_DECISION_MATRIX, ObservabilityDashboardService, OverlayDeciderService, PRAXIS_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_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY, PRAXIS_EXPORT_FORMULA_PREFIXES, PRAXIS_EXPORT_SECURITY_POLICY, PRAXIS_FOOTER_LINKS_METADATA, PRAXIS_GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_OPTIONS, PRAXIS_GLOBAL_CONFIG_BOOTSTRAP_READY, PRAXIS_GLOBAL_CONFIG_TENANT_RESOLVER, PRAXIS_HERO_BANNER_METADATA, PRAXIS_I18N_CONFIG, PRAXIS_I18N_TRANSLATOR, PRAXIS_JSON_LOGIC_OPERATORS, PRAXIS_LAYER_SCALE_DEFAULTS, PRAXIS_LAYER_SCALE_VARS, PRAXIS_LEGAL_NOTICE_METADATA, PRAXIS_LOADING_CTX, PRAXIS_LOADING_RENDERER, PRAXIS_LOGGER_CONFIG, PRAXIS_LOGGER_SINKS, PRAXIS_OBSERVABILITY_DASHBOARD_OPTIONS, PRAXIS_QUERY_FILTER_EXPRESSION_SCHEMA_VERSION, PRAXIS_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, PraxisRuntimeComponentObservationRegistryService, 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, SurfaceOpenMaterializerService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, 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, providePraxisEnterpriseRuntimeContext, providePraxisFooterLinksMetadata, providePraxisGlobalActionCatalog, providePraxisGlobalActions, providePraxisGlobalConfigBootstrap, providePraxisHeroBannerMetadata, providePraxisHttpCollectionExportProvider, providePraxisHttpLoading, providePraxisI18n, providePraxisI18nConfig, providePraxisI18nTranslator, providePraxisIconDefaults, providePraxisJsonLogicOperator, providePraxisJsonLogicOperatorOverride, providePraxisLegalNoticeMetadata, providePraxisLoadingDefaults, providePraxisLogging, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, 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 };