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

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,85 @@ 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 hasExplicitEditablePolicy = !!fieldAccess.editableForAuthorities?.length;
839
+ const editableAllowed = hasExplicitEditablePolicy
840
+ ? matchesAuthority(fieldAccess.editableForAuthorities, authorities)
841
+ : false;
842
+ const visibleAllowed = matchesAuthority(fieldAccess.visibleForAuthorities, authorities) ||
843
+ editableAllowed;
844
+ return {
845
+ evaluated: true,
846
+ visible: visibleAllowed,
847
+ editable: editableAllowed || !hasExplicitEditablePolicy,
848
+ ...(fieldAccess.reason ? { reason: fieldAccess.reason } : {}),
849
+ };
850
+ }
851
+ function isFieldAccessMetadata(value) {
852
+ return !!value && ('visibleForAuthorities' in value ||
853
+ 'editableForAuthorities' in value ||
854
+ 'reason' in value);
855
+ }
856
+ function normalizeAuthorityList(value) {
857
+ if (!Array.isArray(value)) {
858
+ return undefined;
859
+ }
860
+ const normalized = Array.from(new Set(value
861
+ .filter((item) => typeof item === 'string')
862
+ .map((item) => item.trim())
863
+ .filter(Boolean)));
864
+ return normalized.length ? normalized : undefined;
865
+ }
866
+ function normalizeAuthoritySet(authorities) {
867
+ if (!Array.isArray(authorities)) {
868
+ return null;
869
+ }
870
+ return new Set(authorities
871
+ .filter((item) => typeof item === 'string')
872
+ .map((item) => item.trim())
873
+ .filter(Boolean));
874
+ }
875
+ function matchesAuthority(required, actual) {
876
+ if (!required || required.length === 0) {
877
+ return true;
878
+ }
879
+ return required.some((authority) => actual.has(authority));
880
+ }
881
+
800
882
  const VALUE_PRESENTATION_TYPES = new Set([
801
883
  'string',
802
884
  'number',
@@ -1967,6 +2049,10 @@ class SchemaNormalizerService {
1967
2049
  if (ui.editable !== undefined) {
1968
2050
  field.editable = this.parseBoolean(ui.editable);
1969
2051
  }
2052
+ const fieldAccess = normalizeFieldAccessMetadata(ui.fieldAccess);
2053
+ if (fieldAccess) {
2054
+ field.fieldAccess = fieldAccess;
2055
+ }
1970
2056
  if (ui.inlineEditing !== undefined) {
1971
2057
  field.inlineEditing = this.parseBoolean(ui.inlineEditing);
1972
2058
  }
@@ -2020,6 +2106,9 @@ class SchemaNormalizerService {
2020
2106
  if (ui.helpText !== undefined) {
2021
2107
  field.helpText = String(ui.helpText);
2022
2108
  }
2109
+ if (ui.tooltip !== undefined) {
2110
+ field.tooltip = String(ui.tooltip);
2111
+ }
2023
2112
  if (ui.hint !== undefined) {
2024
2113
  field.hint = ui.hint;
2025
2114
  }
@@ -3121,13 +3210,17 @@ class GenericCrudService {
3121
3210
  if (!this.schemaCacheReady) {
3122
3211
  this.schemaCacheReady = (async () => {
3123
3212
  try {
3124
- await Promise.race([
3125
- this.globalConfig.ready(),
3126
- new Promise((resolve) => setTimeout(resolve, SCHEMA_CACHE_GLOBAL_CONFIG_READY_TIMEOUT_MS)),
3127
- ]);
3213
+ if (typeof this.globalConfig?.ready === 'function') {
3214
+ await Promise.race([
3215
+ this.globalConfig.ready(),
3216
+ new Promise((resolve) => setTimeout(resolve, SCHEMA_CACHE_GLOBAL_CONFIG_READY_TIMEOUT_MS)),
3217
+ ]);
3218
+ }
3128
3219
  }
3129
3220
  catch { }
3130
- const disableCache = this.globalConfig.get('cache.disableSchemaCache');
3221
+ const disableCache = typeof this.globalConfig?.get === 'function'
3222
+ ? this.globalConfig.get('cache.disableSchemaCache')
3223
+ : false;
3131
3224
  if (disableCache) {
3132
3225
  console.debug('[CRUD:Service] Schema cache persistence is disabled by config (using MemoryCacheAdapter).');
3133
3226
  this._schemaCache = new MemoryCacheAdapter();
@@ -5533,15 +5626,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5533
5626
  }], ctorParameters: () => [] });
5534
5627
 
5535
5628
  function buildBaseColumnFromDef(def) {
5629
+ const type = resolveColumnTypeFromFieldDefinition(def);
5630
+ const format = type === 'string' ? resolveTextMaskFormatFromFieldDefinition(def) : undefined;
5536
5631
  return {
5537
5632
  field: def.name,
5538
5633
  header: def.label || def.name,
5539
- type: inferType(def),
5634
+ type,
5540
5635
  visible: def.tableHidden === true ? false : true,
5541
5636
  sortable: def.sortable !== false,
5542
5637
  filterable: def.filterable === true,
5543
5638
  resizable: true,
5544
5639
  order: typeof def.order === 'number' ? def.order : undefined,
5640
+ ...(format ? { format } : {}),
5545
5641
  };
5546
5642
  }
5547
5643
  function applyLocalCustomizations$2(baseCol, localCol) {
@@ -5575,9 +5671,10 @@ function applyLocalCustomizations$2(baseCol, localCol) {
5575
5671
  result.renderer = localCol.renderer ?? baseCol.renderer;
5576
5672
  }
5577
5673
  else {
5578
- // Keep no format/renderer to avoid conflicts with server type
5579
- result.format = undefined;
5580
- result.valueMapping = undefined;
5674
+ // Drop local presentation that may be incompatible with the new server type,
5675
+ // but keep canonical server presentation for the resolved type.
5676
+ result.format = baseCol.format;
5677
+ result.valueMapping = baseCol.valueMapping;
5581
5678
  result.renderer = undefined;
5582
5679
  }
5583
5680
  return result;
@@ -5603,15 +5700,121 @@ function reconcileTableConfig(layout, serverDefs) {
5603
5700
  };
5604
5701
  return next;
5605
5702
  }
5606
- function inferType(def) {
5607
- const t = (def.type || '').toLowerCase();
5608
- if (t.includes('date'))
5703
+ function resolveColumnTypeFromFieldDefinition(def, fallback) {
5704
+ const semanticType = resolveSemanticColumnTypeFromFieldDefinition(def);
5705
+ if (resolveTextMaskFormatFromFieldDefinition(def) &&
5706
+ shouldUseTextMaskForColumn(def, semanticType)) {
5707
+ return 'string';
5708
+ }
5709
+ if (semanticType)
5710
+ return semanticType;
5711
+ if (fallback)
5712
+ return fallback;
5713
+ return 'string';
5714
+ }
5715
+ function resolveSemanticColumnTypeFromFieldDefinition(def) {
5716
+ const controlType = normalizePresentationToken(def.controlType);
5717
+ const numericFormat = normalizePresentationToken(def.numericFormat ?? def.format);
5718
+ const valuePresentationType = normalizePresentationToken(def.valuePresentation?.type);
5719
+ const dataType = normalizePresentationToken(def.type);
5720
+ if (valuePresentationType === 'currency')
5721
+ return 'currency';
5722
+ if (valuePresentationType === 'percent' || valuePresentationType === 'percentage')
5723
+ return 'percentage';
5724
+ if (valuePresentationType === 'date' || valuePresentationType === 'datetime' || valuePresentationType === 'time')
5609
5725
  return 'date';
5610
- if (t.includes('bool'))
5726
+ if (valuePresentationType === 'boolean')
5611
5727
  return 'boolean';
5612
- if (t.includes('number') || t.includes('int') || t.includes('decimal'))
5728
+ if (valuePresentationType === 'number')
5613
5729
  return 'number';
5614
- return 'string';
5730
+ if (valuePresentationType === 'string')
5731
+ return 'string';
5732
+ if (numericFormat === 'currency' || controlType === 'currency')
5733
+ return 'currency';
5734
+ if (numericFormat === 'percent' || numericFormat === 'percentage')
5735
+ return 'percentage';
5736
+ if (numericFormat === 'date' || numericFormat === 'datetime')
5737
+ return 'date';
5738
+ if (controlType === 'numerictextbox' || controlType === 'inlinenumber')
5739
+ return 'number';
5740
+ if (controlType === 'checkbox' || controlType === 'toggle' || controlType === 'inlinetoggle')
5741
+ return 'boolean';
5742
+ if (controlType.includes('date') || controlType === 'time' || controlType === 'timepicker')
5743
+ return 'date';
5744
+ if (isColumnType(dataType))
5745
+ return dataType;
5746
+ if (dataType === 'text' || dataType === 'email' || dataType === 'url' || dataType === 'password')
5747
+ return 'string';
5748
+ if (dataType.includes('date') || dataType === 'time')
5749
+ return 'date';
5750
+ if (dataType.includes('bool'))
5751
+ return 'boolean';
5752
+ if (dataType.includes('number') ||
5753
+ dataType.includes('int') ||
5754
+ dataType.includes('decimal') ||
5755
+ dataType.includes('double') ||
5756
+ dataType.includes('float')) {
5757
+ return 'number';
5758
+ }
5759
+ if (isTextualControlType(controlType))
5760
+ return 'string';
5761
+ return undefined;
5762
+ }
5763
+ function shouldUseTextMaskForColumn(def, semanticType) {
5764
+ if (!semanticType || semanticType === 'string')
5765
+ return true;
5766
+ const controlType = normalizePresentationToken(def.controlType);
5767
+ if (isTextualControlType(controlType))
5768
+ return true;
5769
+ if (['date', 'boolean', 'currency', 'percentage', 'custom'].includes(semanticType)) {
5770
+ return false;
5771
+ }
5772
+ const valuePresentationType = normalizePresentationToken(def.valuePresentation?.type);
5773
+ const numericFormat = normalizePresentationToken(def.numericFormat ?? def.format);
5774
+ return !valuePresentationType && !numericFormat;
5775
+ }
5776
+ function resolveTextMaskFormatFromFieldDefinition(def) {
5777
+ return resolveTextMaskFormat(def.mask ??
5778
+ def.displayMask ??
5779
+ def.inputMask ??
5780
+ def.extraProperties?.mask);
5781
+ }
5782
+ function resolveTextMaskFormat(value) {
5783
+ if (typeof value !== 'string')
5784
+ return undefined;
5785
+ const format = value.trim();
5786
+ if (!format)
5787
+ return undefined;
5788
+ const hasMaskTokens = /[0#9Xx]/.test(format);
5789
+ const hasInvalidMaskLetters = /[A-WYZa-wyz]/.test(format);
5790
+ return hasMaskTokens && !hasInvalidMaskLetters ? format : undefined;
5791
+ }
5792
+ function normalizePresentationToken(value) {
5793
+ return String(value ?? '').trim().toLowerCase().replace(/[\s_-]+/g, '');
5794
+ }
5795
+ function isColumnType(value) {
5796
+ return [
5797
+ 'string',
5798
+ 'number',
5799
+ 'date',
5800
+ 'boolean',
5801
+ 'currency',
5802
+ 'percentage',
5803
+ 'custom',
5804
+ ].includes(value);
5805
+ }
5806
+ function isTextualControlType(value) {
5807
+ return [
5808
+ 'input',
5809
+ 'inlineinput',
5810
+ 'textarea',
5811
+ 'search',
5812
+ 'email',
5813
+ 'url',
5814
+ 'phone',
5815
+ 'cpfcnpjinput',
5816
+ 'password',
5817
+ ].includes(value);
5615
5818
  }
5616
5819
 
5617
5820
  const PRAXIS_I18N_CONFIG = new InjectionToken('PRAXIS_I18N_CONFIG', {
@@ -6331,7 +6534,7 @@ const GLOBAL_SURFACE_SERVICE = new InjectionToken('GLOBAL_SURFACE_SERVICE');
6331
6534
 
6332
6535
  const dialogBaseFields = [
6333
6536
  { key: 'message', label: 'Mensagem', type: 'textarea', rows: 2, placeholder: 'Texto principal' },
6334
- { key: 'title', label: 'Titulo', type: 'text', placeholder: 'Titulo do dialogo' },
6537
+ { key: 'title', label: 'Título', type: 'text', placeholder: 'Título do diálogo' },
6335
6538
  {
6336
6539
  key: 'themeColor',
6337
6540
  label: 'Tema',
@@ -6342,13 +6545,13 @@ const dialogBaseFields = [
6342
6545
  { value: 'dark', label: 'Dark' },
6343
6546
  ],
6344
6547
  },
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' },
6548
+ { key: 'positionTop', label: 'Posição topo', type: 'text', placeholder: '12px' },
6549
+ { key: 'positionRight', label: 'Posição direita', type: 'text', placeholder: '12px' },
6550
+ { key: 'positionBottom', label: 'Posição base', type: 'text', placeholder: '12px' },
6551
+ { key: 'positionLeft', label: 'Posição esquerda', type: 'text', placeholder: '12px' },
6349
6552
  {
6350
6553
  key: 'actionsLayout',
6351
- label: 'Layout das acoes',
6554
+ label: 'Layout das ações',
6352
6555
  type: 'select',
6353
6556
  options: [
6354
6557
  { value: 'start', label: 'Start' },
@@ -6359,7 +6562,7 @@ const dialogBaseFields = [
6359
6562
  },
6360
6563
  {
6361
6564
  key: 'animationType',
6362
- label: 'Animacao',
6565
+ label: 'Animação',
6363
6566
  type: 'select',
6364
6567
  options: [
6365
6568
  { value: 'translate', label: 'Translate' },
@@ -6371,7 +6574,7 @@ const dialogBaseFields = [
6371
6574
  },
6372
6575
  {
6373
6576
  key: 'animationDirection',
6374
- label: 'Direcao animacao',
6577
+ label: 'Direção animação',
6375
6578
  type: 'select',
6376
6579
  options: [
6377
6580
  { value: 'up', label: 'Up' },
@@ -6380,13 +6583,13 @@ const dialogBaseFields = [
6380
6583
  { value: 'right', label: 'Right' },
6381
6584
  ],
6382
6585
  },
6383
- { key: 'animationDuration', label: 'Duracao (ms)', type: 'number', placeholder: '300' },
6586
+ { key: 'animationDuration', label: 'Duração (ms)', type: 'number', placeholder: '300' },
6384
6587
  { key: 'width', label: 'Largura', type: 'text', placeholder: '480px' },
6385
6588
  { 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' },
6589
+ { key: 'minWidth', label: 'Largura mínima', type: 'text', placeholder: '280px' },
6590
+ { key: 'maxWidth', label: 'Largura máxima', type: 'text', placeholder: '90vw' },
6591
+ { key: 'minHeight', label: 'Altura mínima', type: 'text', placeholder: '120px' },
6592
+ { key: 'maxHeight', label: 'Altura máxima', type: 'text', placeholder: '90vh' },
6390
6593
  { key: 'disableClose', label: 'Bloquear fechar', type: 'toggle' },
6391
6594
  { key: 'hasBackdrop', label: 'Backdrop', type: 'toggle' },
6392
6595
  { key: 'closeOnBackdropClick', label: 'Fechar ao clicar no backdrop', type: 'toggle' },
@@ -6414,7 +6617,7 @@ const dialogFieldsWithModeDependency = dialogFieldsWithoutMessage.map((field) =>
6414
6617
  ...field,
6415
6618
  dependsOnKey: field.dependsOnKey ?? 'mode',
6416
6619
  dependsOnValue: field.dependsOnValue ?? 'true',
6417
- hint: field.hint ?? 'Disponivel quando "Usar dialogo" estiver ativo.',
6620
+ hint: field.hint ?? 'Disponível quando "Usar diálogo" estiver ativo.',
6418
6621
  }));
6419
6622
  const GLOBAL_ACTION_UI_SCHEMAS = [
6420
6623
  {
@@ -6462,7 +6665,7 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6462
6665
  required: true,
6463
6666
  placeholder: 'Texto exibido no alerta simples',
6464
6667
  },
6465
- { key: 'mode', label: 'Usar dialogo (avancado)', type: 'toggle' },
6668
+ { key: 'mode', label: 'Usar diálogo (avançado)', type: 'toggle' },
6466
6669
  ...dialogFieldsWithModeDependency,
6467
6670
  ],
6468
6671
  },
@@ -6481,19 +6684,19 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6481
6684
  fields: [
6482
6685
  ...dialogBaseFields,
6483
6686
  { key: 'placeholder', label: 'Placeholder', type: 'text' },
6484
- { key: 'defaultValue', label: 'Valor padrao', type: 'text' },
6687
+ { key: 'defaultValue', label: 'Valor padrão', type: 'text' },
6485
6688
  { key: 'okLabel', label: 'Texto OK', type: 'text' },
6486
6689
  { key: 'cancelLabel', label: 'Texto cancelar', type: 'text' },
6487
6690
  ],
6488
6691
  },
6489
6692
  {
6490
6693
  id: 'dialog.open',
6491
- label: 'Abrir dialogo',
6694
+ label: 'Abrir diálogo',
6492
6695
  fields: [
6493
6696
  ...dialogBaseFields,
6494
6697
  {
6495
6698
  key: 'contentType',
6496
- label: 'Tipo de conteudo',
6699
+ label: 'Tipo de conteúdo',
6497
6700
  type: 'select',
6498
6701
  options: [
6499
6702
  { value: 'template', label: 'Template' },
@@ -6514,7 +6717,7 @@ const GLOBAL_ACTION_UI_SCHEMAS = [
6514
6717
  { key: 'message', label: 'Mensagem', type: 'text' },
6515
6718
  {
6516
6719
  key: 'level',
6517
- label: 'Nivel',
6720
+ label: 'Nível',
6518
6721
  type: 'select',
6519
6722
  options: [
6520
6723
  { value: 'log', label: 'log' },
@@ -8474,6 +8677,7 @@ const DEFAULT_JSON_LOGIC_OPERATORS = [
8474
8677
  const ALL_RULE_CONTEXT_ROOTS = [
8475
8678
  'form',
8476
8679
  'row',
8680
+ 'rowData',
8477
8681
  'computed',
8478
8682
  'meta',
8479
8683
  'source',
@@ -9332,6 +9536,7 @@ function mapFieldDefinitionToMetadata(field) {
9332
9536
  'displayOrientation',
9333
9537
  'disabled',
9334
9538
  'readOnly',
9539
+ 'fieldAccess',
9335
9540
  'hidden',
9336
9541
  'formHidden',
9337
9542
  'tableHidden',
@@ -9496,9 +9701,25 @@ function mapFieldDefinitionToMetadata(field) {
9496
9701
  metadata.maxLength = field.maxLength;
9497
9702
  if (field.pattern !== undefined)
9498
9703
  metadata.pattern = field.pattern;
9704
+ if (field.helpText !== undefined) {
9705
+ metadata.helpText = field.helpText;
9706
+ }
9499
9707
  if (field.hint || field.helpText) {
9500
9708
  metadata.hint = field.hint ?? field.helpText;
9501
9709
  }
9710
+ if (field.tooltipOnHover !== undefined) {
9711
+ metadata.tooltipOnHover = field.tooltipOnHover;
9712
+ const tooltip = field.tooltip ??
9713
+ (field.tooltipOnHover === true
9714
+ ? field.description ?? field.helpText ?? field.hint
9715
+ : undefined);
9716
+ if (tooltip !== undefined && tooltip !== null) {
9717
+ metadata.tooltip = String(tooltip);
9718
+ }
9719
+ }
9720
+ else if (field.tooltip !== undefined) {
9721
+ metadata.tooltip = String(field.tooltip);
9722
+ }
9502
9723
  if (field.hiddenCondition !== undefined) {
9503
9724
  metadata.hiddenCondition = field.hiddenCondition;
9504
9725
  }
@@ -11562,7 +11783,7 @@ class ResourceDiscoveryService {
11562
11783
  throw new Error('ResourceDiscoveryService cannot resolve an empty href.');
11563
11784
  }
11564
11785
  if (/^https?:\/\//i.test(normalizedHref)) {
11565
- return normalizedHref;
11786
+ return this.resolveTrustedAbsoluteHref(normalizedHref, options);
11566
11787
  }
11567
11788
  const apiBaseUrl = this.resolveApiBaseHref(options);
11568
11789
  if (!apiBaseUrl) {
@@ -11615,6 +11836,69 @@ class ResourceDiscoveryService {
11615
11836
  const entry = this.resolveApiEntry(options);
11616
11837
  return String(buildApiUrl(entry) || '').trim();
11617
11838
  }
11839
+ resolveTrustedAbsoluteHref(href, options) {
11840
+ const runtimeOrigin = this.getRuntimeOrigin();
11841
+ const baseUrl = this.resolveApiBaseUrl(options);
11842
+ if (!runtimeOrigin || !baseUrl || this.isAbsoluteHttpUrl(baseUrl)) {
11843
+ return href;
11844
+ }
11845
+ let parsed;
11846
+ try {
11847
+ parsed = new URL(href);
11848
+ }
11849
+ catch {
11850
+ return href;
11851
+ }
11852
+ if (!this.isTrustedOrigin(parsed.origin, options)) {
11853
+ return href;
11854
+ }
11855
+ if (!this.isProxyableApiPath(parsed.pathname, baseUrl)) {
11856
+ return href;
11857
+ }
11858
+ return new URL(`${parsed.pathname}${parsed.search}${parsed.hash}`, `${runtimeOrigin}/`).toString();
11859
+ }
11860
+ isTrustedOrigin(origin, options) {
11861
+ const normalizedOrigin = this.normalizeOrigin(origin);
11862
+ if (!normalizedOrigin) {
11863
+ return false;
11864
+ }
11865
+ return this.getTrustedOrigins(options).some((trustedOrigin) => trustedOrigin === normalizedOrigin);
11866
+ }
11867
+ getTrustedOrigins(options) {
11868
+ const origins = this.resolveApiEntry(options).trustedOrigins || [];
11869
+ return origins
11870
+ .map((origin) => this.normalizeOrigin(origin))
11871
+ .filter((origin) => !!origin);
11872
+ }
11873
+ normalizeOrigin(origin) {
11874
+ try {
11875
+ return new URL(origin).origin;
11876
+ }
11877
+ catch {
11878
+ return null;
11879
+ }
11880
+ }
11881
+ isProxyableApiPath(pathname, baseUrl) {
11882
+ const basePath = this.normalizePathPrefix(baseUrl);
11883
+ if (basePath && (pathname === basePath || pathname.startsWith(`${basePath}/`))) {
11884
+ return true;
11885
+ }
11886
+ return pathname === '/schemas'
11887
+ || pathname.startsWith('/schemas/')
11888
+ || pathname === '/v3/api-docs'
11889
+ || pathname.startsWith('/v3/api-docs/');
11890
+ }
11891
+ normalizePathPrefix(baseUrl) {
11892
+ const path = String(baseUrl || '').split(/[?#]/u)[0]?.trim() || '';
11893
+ if (!path.startsWith('/')) {
11894
+ return '';
11895
+ }
11896
+ const normalized = `/${path.replace(/^\/+|\/+$/g, '')}`;
11897
+ return normalized === '/' ? '' : normalized;
11898
+ }
11899
+ isAbsoluteHttpUrl(value) {
11900
+ return /^https?:\/\//i.test(String(value || '').trim());
11901
+ }
11618
11902
  resolveApiBaseHref(options) {
11619
11903
  const baseUrl = this.resolveApiBaseUrl(options);
11620
11904
  if (!baseUrl) {
@@ -11922,6 +12206,209 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
11922
12206
  args: [{ providedIn: 'any' }]
11923
12207
  }] });
11924
12208
 
12209
+ const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS');
12210
+ const PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY = new InjectionToken('PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY');
12211
+ function providePraxisEnterpriseRuntimeContext(options = {}) {
12212
+ const normalized = {
12213
+ ...options,
12214
+ includeGlobalFetchHeaders: options.includeGlobalFetchHeaders ?? true,
12215
+ blocking: options.blocking ?? false,
12216
+ errorPolicy: options.errorPolicy ?? 'ignore',
12217
+ };
12218
+ return [
12219
+ { provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, useValue: normalized },
12220
+ {
12221
+ provide: PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY,
12222
+ useFactory: (service) => {
12223
+ let promise = null;
12224
+ return () => {
12225
+ if (promise)
12226
+ return promise;
12227
+ promise = service.ready().then(() => undefined);
12228
+ return promise;
12229
+ };
12230
+ },
12231
+ deps: [EnterpriseRuntimeContextService],
12232
+ },
12233
+ {
12234
+ provide: APP_INITIALIZER,
12235
+ multi: true,
12236
+ useFactory: (ready) => () => normalized.blocking ? ready() : undefined,
12237
+ deps: [PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_READY],
12238
+ },
12239
+ ];
12240
+ }
12241
+
12242
+ class EnterpriseRuntimeContextService {
12243
+ http = inject(HttpClient);
12244
+ apiUrl = inject(API_URL, { optional: true });
12245
+ options = inject(PRAXIS_ENTERPRISE_RUNTIME_CONTEXT_OPTIONS, {
12246
+ optional: true,
12247
+ });
12248
+ contextSubject = new BehaviorSubject(null);
12249
+ loadPromise = null;
12250
+ contextChanges$ = this.contextSubject.asObservable();
12251
+ get snapshot() {
12252
+ return this.contextSubject.value;
12253
+ }
12254
+ ready() {
12255
+ if (this.contextSubject.value) {
12256
+ return Promise.resolve(this.contextSubject.value);
12257
+ }
12258
+ if (this.loadPromise) {
12259
+ return this.loadPromise;
12260
+ }
12261
+ this.loadPromise = this.load()
12262
+ .catch((error) => {
12263
+ if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
12264
+ throw error;
12265
+ }
12266
+ return null;
12267
+ })
12268
+ .finally(() => {
12269
+ this.loadPromise = null;
12270
+ });
12271
+ return this.loadPromise;
12272
+ }
12273
+ refresh() {
12274
+ this.loadPromise = null;
12275
+ return this.load().catch((error) => {
12276
+ if ((this.options?.errorPolicy ?? 'ignore') === 'fail') {
12277
+ throw error;
12278
+ }
12279
+ return null;
12280
+ });
12281
+ }
12282
+ tenants() {
12283
+ return this.getRuntimeSurface('tenants');
12284
+ }
12285
+ navigation() {
12286
+ return this.getRuntimeSurface('navigation');
12287
+ }
12288
+ securityEvents() {
12289
+ return this.getRuntimeSurface('securityEvents');
12290
+ }
12291
+ async switchContext(command) {
12292
+ const response = await firstValueFrom(this.http.put(this.endpoint('context'), command, {
12293
+ headers: this.requestHeaders({ includeSnapshot: true }),
12294
+ }));
12295
+ if (response?.effectiveContext) {
12296
+ this.contextSubject.next(response.effectiveContext);
12297
+ }
12298
+ return response;
12299
+ }
12300
+ headers(fallback) {
12301
+ return {
12302
+ ...this.normalizeHeaders(fallback ?? {}),
12303
+ ...this.normalizeHeaders(this.headersFromSnapshot(this.contextSubject.value)),
12304
+ };
12305
+ }
12306
+ async load() {
12307
+ const context = await firstValueFrom(this.http.get(this.endpoint('context'), {
12308
+ headers: this.requestHeaders(),
12309
+ }));
12310
+ this.contextSubject.next(context ?? null);
12311
+ return context ?? null;
12312
+ }
12313
+ async getRuntimeSurface(surface) {
12314
+ return firstValueFrom(this.http.get(this.endpoint(surface), {
12315
+ headers: this.requestHeaders({ includeSnapshot: true }),
12316
+ }));
12317
+ }
12318
+ endpoint(surface) {
12319
+ const configured = this.configuredEndpoint(surface);
12320
+ if (configured) {
12321
+ return configured;
12322
+ }
12323
+ return `${this.runtimeRoot()}/${this.surfacePath(surface)}`;
12324
+ }
12325
+ configuredEndpoint(surface) {
12326
+ const configured = surface === 'context'
12327
+ ? (this.options?.endpoints?.context ?? this.options?.endpoint)
12328
+ : this.options?.endpoints?.[surface];
12329
+ const normalized = configured?.trim().replace(/\/+$/, '');
12330
+ return normalized || null;
12331
+ }
12332
+ runtimeRoot() {
12333
+ const configuredContext = this.configuredEndpoint('context');
12334
+ if (configuredContext?.endsWith('/context')) {
12335
+ return configuredContext.slice(0, -'/context'.length);
12336
+ }
12337
+ const defaultEntry = this.apiUrl?.['default'];
12338
+ const base = defaultEntry ? buildApiUrl(defaultEntry) : '';
12339
+ return base ? `${base}/praxis/runtime` : '/api/praxis/runtime';
12340
+ }
12341
+ surfacePath(surface) {
12342
+ switch (surface) {
12343
+ case 'context':
12344
+ return 'context';
12345
+ case 'tenants':
12346
+ return 'tenants';
12347
+ case 'navigation':
12348
+ return 'navigation';
12349
+ case 'securityEvents':
12350
+ return 'security-events';
12351
+ }
12352
+ }
12353
+ requestHeaders(options = {}) {
12354
+ const merged = this.normalizeHeaders({
12355
+ ...(this.options?.includeGlobalFetchHeaders ?? true ? this.globalFetchHeaders() : {}),
12356
+ ...(this.options?.headersFactory?.() ?? {}),
12357
+ ...(options.includeSnapshot ? this.headersFromSnapshot(this.contextSubject.value) : {}),
12358
+ });
12359
+ let headers = new HttpHeaders();
12360
+ for (const [key, value] of Object.entries(merged)) {
12361
+ if (value) {
12362
+ headers = headers.set(key, value);
12363
+ }
12364
+ }
12365
+ return headers;
12366
+ }
12367
+ globalFetchHeaders() {
12368
+ try {
12369
+ const factory = globalThis.PAX_FETCH_HEADERS;
12370
+ return factory?.() ?? {};
12371
+ }
12372
+ catch {
12373
+ return {};
12374
+ }
12375
+ }
12376
+ headersFromSnapshot(context) {
12377
+ if (!context) {
12378
+ return {};
12379
+ }
12380
+ return {
12381
+ 'X-Tenant-ID': context.activeTenant?.tenantId,
12382
+ 'X-User-ID': context.user?.userId,
12383
+ 'X-Env': context.environment ?? undefined,
12384
+ 'Accept-Language': context.locale ?? undefined,
12385
+ 'X-Timezone': context.timezone ?? undefined,
12386
+ 'X-Praxis-Profile-ID': context.activeProfileId ?? undefined,
12387
+ 'X-Praxis-Module-Key': context.activeModuleKey ?? undefined,
12388
+ };
12389
+ }
12390
+ normalizeHeaders(headers) {
12391
+ const normalized = {};
12392
+ for (const [key, value] of Object.entries(headers)) {
12393
+ if (typeof value !== 'string') {
12394
+ continue;
12395
+ }
12396
+ const trimmed = value.trim();
12397
+ if (!trimmed) {
12398
+ continue;
12399
+ }
12400
+ normalized[key] = trimmed;
12401
+ }
12402
+ return normalized;
12403
+ }
12404
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12405
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, providedIn: 'root' });
12406
+ }
12407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: EnterpriseRuntimeContextService, decorators: [{
12408
+ type: Injectable,
12409
+ args: [{ providedIn: 'root' }]
12410
+ }] });
12411
+
11925
12412
  function clonePraxisRuntimeComponentObservation(observation) {
11926
12413
  assertPraxisRuntimeComponentObservationSerializable(observation);
11927
12414
  return JSON.parse(JSON.stringify(observation));
@@ -12444,9 +12931,10 @@ class SurfaceOpenMaterializerService {
12444
12931
  : null;
12445
12932
  if (collectionData) {
12446
12933
  if (this.shouldPreserveCollectionPresentation(payload)) {
12934
+ const preservedPayload = this.ensureCollectionTableSelectionContract(payload);
12447
12935
  return {
12448
- ...payload,
12449
- context: this.mergeMaterializationContext(payload, {
12936
+ ...preservedPayload,
12937
+ context: this.mergeMaterializationContext(preservedPayload, {
12450
12938
  readUrl,
12451
12939
  dataShape: 'array',
12452
12940
  recordCount: collectionData.length,
@@ -12470,18 +12958,24 @@ class SurfaceOpenMaterializerService {
12470
12958
  if (data && typeof data === 'object' && !Array.isArray(data)) {
12471
12959
  const objectData = data;
12472
12960
  if (payload.widget.id === 'praxis-dynamic-form') {
12473
- const schemaFields = await this.resolveSchemaFields(payload, discoveryOptions);
12474
12961
  return {
12475
12962
  ...payload,
12476
12963
  widget: {
12477
12964
  ...payload.widget,
12478
12965
  inputs: {
12479
12966
  ...this.projectMaterializedFormInputs(payload.widget.inputs || {}),
12480
- configPersistenceStrategy: 'input-first',
12481
12967
  mode: payload.widget.inputs?.['mode'] || 'view',
12482
12968
  initialValue: objectData,
12483
12969
  resourceId,
12484
- config: this.buildLocalFormConfig(objectData, schemaFields),
12970
+ layoutPolicy: payload.widget.inputs?.['layoutPolicy'] || {
12971
+ source: 'schema',
12972
+ intent: 'detail',
12973
+ preset: 'compactPresentation',
12974
+ lifecycle: 'live',
12975
+ persistence: 'transient',
12976
+ schemaOperation: 'detail',
12977
+ schemaType: 'response',
12978
+ },
12485
12979
  },
12486
12980
  },
12487
12981
  context: this.mergeMaterializationContext(payload, {
@@ -12519,11 +13013,14 @@ class SurfaceOpenMaterializerService {
12519
13013
  'resourceId',
12520
13014
  'apiEndpointKey',
12521
13015
  'apiUrlEntry',
13016
+ 'schemaUrl',
13017
+ 'readUrl',
12522
13018
  'submitUrl',
12523
13019
  'submitMethod',
12524
13020
  'responseSchemaUrl',
12525
13021
  'customEndpoints',
12526
13022
  'configPersistenceStrategy',
13023
+ 'layoutPolicy',
12527
13024
  'mode',
12528
13025
  'actions',
12529
13026
  'enableCustomization',
@@ -12531,6 +13028,7 @@ class SurfaceOpenMaterializerService {
12531
13028
  'readonlyModeGlobal',
12532
13029
  'disabledModeGlobal',
12533
13030
  'presentationModeGlobal',
13031
+ 'fieldIconPolicy',
12534
13032
  'visibleGlobal',
12535
13033
  'layout',
12536
13034
  'backConfig',
@@ -12544,186 +13042,6 @@ class SurfaceOpenMaterializerService {
12544
13042
  ]);
12545
13043
  return Object.fromEntries(Object.entries(inputs).filter(([key]) => supported.has(key)));
12546
13044
  }
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
13045
  shouldMaterializeItemReadProjection(payload) {
12728
13046
  const surface = payload.context?.['surface'];
12729
13047
  const kind = String(surface?.['kind'] || '').toUpperCase();
@@ -12806,6 +13124,8 @@ class SurfaceOpenMaterializerService {
12806
13124
  bindingOrder: [
12807
13125
  'tableId',
12808
13126
  'componentInstanceId',
13127
+ 'configPersistenceStrategy',
13128
+ 'resourcePath',
12809
13129
  'title',
12810
13130
  'subtitle',
12811
13131
  'icon',
@@ -12813,11 +13133,17 @@ class SurfaceOpenMaterializerService {
12813
13133
  'config',
12814
13134
  'enableCustomization',
12815
13135
  ],
13136
+ outputs: {
13137
+ rowClick: 'emit',
13138
+ selectionChange: 'emit',
13139
+ widgetEvent: 'emit',
13140
+ },
12816
13141
  inputs: {
12817
13142
  ...tableInputOverrides,
12818
13143
  resourcePath: '',
12819
13144
  tableId: String(previousInputs['tableId'] || this.stableSurfaceId(payload)),
12820
13145
  componentInstanceId: `${this.stableSurfaceId(payload)}.${resourceId}`,
13146
+ configPersistenceStrategy: previousInputs['configPersistenceStrategy'] ?? 'volatile',
12821
13147
  title: payload.title,
12822
13148
  subtitle: payload.subtitle,
12823
13149
  icon: payload.icon,
@@ -12833,6 +13159,52 @@ class SurfaceOpenMaterializerService {
12833
13159
  }),
12834
13160
  };
12835
13161
  }
13162
+ ensureCollectionTableSelectionContract(payload) {
13163
+ if (payload.widget?.id !== 'praxis-table') {
13164
+ return payload;
13165
+ }
13166
+ const inputs = payload.widget.inputs || {};
13167
+ return {
13168
+ ...payload,
13169
+ widget: {
13170
+ ...payload.widget,
13171
+ outputs: {
13172
+ ...(payload.widget.outputs || {}),
13173
+ rowClick: 'emit',
13174
+ selectionChange: 'emit',
13175
+ widgetEvent: 'emit',
13176
+ },
13177
+ inputs: {
13178
+ ...inputs,
13179
+ config: this.ensureTableSelectionConfig(inputs['config']),
13180
+ },
13181
+ },
13182
+ };
13183
+ }
13184
+ ensureTableSelectionConfig(config) {
13185
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
13186
+ return config;
13187
+ }
13188
+ const tableConfig = config;
13189
+ const rawBehavior = tableConfig['behavior'];
13190
+ const behavior = (rawBehavior && typeof rawBehavior === 'object' && !Array.isArray(rawBehavior)
13191
+ ? rawBehavior
13192
+ : {});
13193
+ if (behavior['selection'] && typeof behavior['selection'] === 'object') {
13194
+ return config;
13195
+ }
13196
+ return {
13197
+ ...tableConfig,
13198
+ behavior: {
13199
+ ...behavior,
13200
+ selection: {
13201
+ enabled: true,
13202
+ type: 'single',
13203
+ mode: 'both',
13204
+ },
13205
+ },
13206
+ };
13207
+ }
12836
13208
  projectTableInputs(inputs) {
12837
13209
  const supported = new Set([
12838
13210
  'tableId',
@@ -12869,6 +13241,11 @@ class SurfaceOpenMaterializerService {
12869
13241
  behavior: {
12870
13242
  localDataMode: { enabled: true },
12871
13243
  pagination: { enabled: true, pageSize: 10 },
13244
+ selection: {
13245
+ enabled: true,
13246
+ type: 'single',
13247
+ mode: 'both',
13248
+ },
12872
13249
  },
12873
13250
  };
12874
13251
  }
@@ -15674,6 +16051,9 @@ const STEPPER_CONFIG_EDITOR = new InjectionToken('STEPPER_CONFIG_EDITOR');
15674
16051
  const DYNAMIC_PAGE_SHELL_EDITOR = new InjectionToken('DYNAMIC_PAGE_SHELL_EDITOR');
15675
16052
  const DYNAMIC_PAGE_CONFIG_EDITOR = new InjectionToken('DYNAMIC_PAGE_CONFIG_EDITOR');
15676
16053
 
16054
+ const PRAXIS_TABLE_DETAIL_INLINE_RENDERERS = new InjectionToken('PRAXIS_TABLE_DETAIL_INLINE_RENDERERS');
16055
+ const PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS = new InjectionToken('PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS');
16056
+
15677
16057
  function providePraxisHttpCollectionExportProvider(options = {}) {
15678
16058
  return [
15679
16059
  { provide: PRAXIS_COLLECTION_EXPORT_HTTP_OPTIONS, useValue: options },
@@ -16016,6 +16396,743 @@ const FieldDataType = {
16016
16396
  * - Angular Material 3 native support
16017
16397
  */
16018
16398
 
16399
+ const VISUALIZATION_KINDS = new Set([
16400
+ 'line',
16401
+ 'area',
16402
+ 'column',
16403
+ 'comparison',
16404
+ 'stackedBar',
16405
+ 'radial',
16406
+ 'harveyBall',
16407
+ 'bullet',
16408
+ 'delta',
16409
+ 'processFlow',
16410
+ ]);
16411
+ const VISUALIZATION_SURFACES = new Set([
16412
+ 'table-cell',
16413
+ 'list-item',
16414
+ 'object-header',
16415
+ 'card-summary',
16416
+ 'form-presentation',
16417
+ ]);
16418
+ const VISUALIZATION_SIZES = new Set([
16419
+ 'xs',
16420
+ 'sm',
16421
+ 'md',
16422
+ 'lg',
16423
+ 'responsive',
16424
+ ]);
16425
+ const VISUALIZATION_TONES = new Set([
16426
+ 'neutral',
16427
+ 'info',
16428
+ 'success',
16429
+ 'warning',
16430
+ 'danger',
16431
+ 'critical',
16432
+ ]);
16433
+ const TABLE_SAFE_KINDS = new Set([
16434
+ 'line',
16435
+ 'area',
16436
+ 'column',
16437
+ 'comparison',
16438
+ 'stackedBar',
16439
+ 'radial',
16440
+ 'harveyBall',
16441
+ 'bullet',
16442
+ 'delta',
16443
+ 'processFlow',
16444
+ ]);
16445
+ function normalizePraxisPresentationVisualization(value) {
16446
+ if (!value || typeof value !== 'object') {
16447
+ return undefined;
16448
+ }
16449
+ const kind = normalizeEnum$1(value.kind, VISUALIZATION_KINDS);
16450
+ const fallbackText = normalizeText$1(value.fallbackText);
16451
+ if (!kind || !fallbackText) {
16452
+ return undefined;
16453
+ }
16454
+ const surface = normalizeEnum$1(value.surface, VISUALIZATION_SURFACES);
16455
+ const size = normalizeEnum$1(value.size, VISUALIZATION_SIZES);
16456
+ const tone = normalizeEnum$1(value.tone, VISUALIZATION_TONES);
16457
+ const ariaLabel = normalizeText$1(value.ariaLabel);
16458
+ const valueSuffix = normalizeText$1(value.valueSuffix);
16459
+ return {
16460
+ kind,
16461
+ fallbackText,
16462
+ ...(surface ? { surface } : {}),
16463
+ ...(size ? { size } : {}),
16464
+ ...(tone ? { tone } : {}),
16465
+ ...(ariaLabel ? { ariaLabel } : {}),
16466
+ ...(valueSuffix ? { valueSuffix } : {}),
16467
+ ...(Object.prototype.hasOwnProperty.call(value, 'value') ? { value: value.value } : {}),
16468
+ ...(normalizeExpression(value.valueExpr, 'valueExpr') ?? {}),
16469
+ ...(normalizeExpression(value.valueSuffixExpr, 'valueSuffixExpr') ?? {}),
16470
+ ...(normalizeNumber(value.total, 'total') ?? {}),
16471
+ ...(normalizeExpression(value.totalExpr, 'totalExpr') ?? {}),
16472
+ ...(normalizeNumber(value.target, 'target') ?? {}),
16473
+ ...(normalizeExpression(value.targetExpr, 'targetExpr') ?? {}),
16474
+ ...(normalizeNumber(value.baseline, 'baseline') ?? {}),
16475
+ ...(normalizeExpression(value.baselineExpr, 'baselineExpr') ?? {}),
16476
+ ...(normalizePoints(value.points) ?? {}),
16477
+ ...(normalizeExpression(value.pointsExpr, 'pointsExpr') ?? {}),
16478
+ ...(normalizeSegments(value.segments) ?? {}),
16479
+ ...(normalizeExpression(value.segmentsExpr, 'segmentsExpr') ?? {}),
16480
+ ...(normalizeThresholds(value.thresholds) ?? {}),
16481
+ ...(normalizeExpression(value.thresholdsExpr, 'thresholdsExpr') ?? {}),
16482
+ ...(normalizeItems(value.items) ?? {}),
16483
+ ...(normalizeExpression(value.itemsExpr, 'itemsExpr') ?? {}),
16484
+ ...(normalizeExpression(value.toneExpr, 'toneExpr') ?? {}),
16485
+ ...(normalizeExpression(value.ariaLabelExpr, 'ariaLabelExpr') ?? {}),
16486
+ ...(normalizeExpression(value.fallbackTextExpr, 'fallbackTextExpr') ?? {}),
16487
+ };
16488
+ }
16489
+ function isPraxisPresentationVisualizationTableSafe(value) {
16490
+ const normalized = normalizePraxisPresentationVisualization(value);
16491
+ return !!normalized && TABLE_SAFE_KINDS.has(normalized.kind);
16492
+ }
16493
+ function renderPraxisPresentationVisualizationHtml(value, options = {}) {
16494
+ const visualization = normalizePraxisPresentationVisualization(value);
16495
+ if (!visualization) {
16496
+ return '';
16497
+ }
16498
+ switch (visualization.kind) {
16499
+ case 'comparison':
16500
+ return renderComparisonVisualizationHtml(visualization, options);
16501
+ case 'stackedBar':
16502
+ return renderStackedBarVisualizationHtml(visualization, options);
16503
+ case 'bullet':
16504
+ return renderBulletVisualizationHtml(visualization, options);
16505
+ case 'delta':
16506
+ return renderDeltaVisualizationHtml(visualization, options);
16507
+ case 'radial':
16508
+ return renderRadialVisualizationHtml(visualization, options);
16509
+ case 'harveyBall':
16510
+ return renderHarveyBallVisualizationHtml(visualization, options);
16511
+ case 'line':
16512
+ return renderLineVisualizationHtml(visualization, options);
16513
+ case 'area':
16514
+ return renderAreaVisualizationHtml(visualization, options);
16515
+ case 'column':
16516
+ return renderColumnVisualizationHtml(visualization, options);
16517
+ case 'processFlow':
16518
+ return renderProcessFlowVisualizationHtml(visualization, options);
16519
+ default:
16520
+ return `<span class="pfx-micro-viz__fallback">${escapeHtml$1(visualization.fallbackText)}</span>`;
16521
+ }
16522
+ }
16523
+ function renderComparisonVisualizationHtml(visualization, options) {
16524
+ const points = visualization.points ?? [];
16525
+ const max = Math.max(1, ...points.map((point) => Math.max(0, point.value)));
16526
+ const rows = points
16527
+ .map((point) => {
16528
+ const width = percent(point.value, max);
16529
+ return `
16530
+ <span class="pfx-micro-viz__row" data-tone="${escapeHtml$1(point.tone ?? visualization.tone ?? 'info')}">
16531
+ <span class="pfx-micro-viz__label">${escapeHtml$1(point.label ?? '')}</span>
16532
+ <span class="pfx-micro-viz__track">
16533
+ <span class="pfx-micro-viz__bar" style="width:${width}%"></span>
16534
+ </span>
16535
+ <span class="pfx-micro-viz__value">${escapeHtml$1(formatMicroNumber(point.value, options.locale))}</span>
16536
+ </span>`;
16537
+ })
16538
+ .join('');
16539
+ return `<span class="pfx-micro-viz" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">${rows}</span>`;
16540
+ }
16541
+ function renderStackedBarVisualizationHtml(visualization, options) {
16542
+ const segments = visualization.segments ?? [];
16543
+ const total = visualization.total && visualization.total > 0
16544
+ ? visualization.total
16545
+ : Math.max(1, segments.reduce((sum, segment) => sum + Math.max(0, segment.value), 0));
16546
+ const bars = segments
16547
+ .map((segment) => `
16548
+ <span
16549
+ class="pfx-micro-viz__segment"
16550
+ data-tone="${escapeHtml$1(segment.tone ?? visualization.tone ?? 'info')}"
16551
+ style="width:${percent(segment.value, total)}%"
16552
+ title="${escapeHtml$1(`${segment.label ?? ''} ${formatMicroNumber(segment.value, options.locale)}`.trim())}"
16553
+ ></span>`)
16554
+ .join('');
16555
+ const meta = segments
16556
+ .slice(0, 3)
16557
+ .map((segment) => `<span>${escapeHtml$1(segment.label ?? '')}: ${escapeHtml$1(formatMicroNumber(segment.value, options.locale))}</span>`)
16558
+ .join('');
16559
+ return `
16560
+ <span class="pfx-micro-viz" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16561
+ <span class="pfx-micro-viz__segments">${bars}</span>
16562
+ <span class="pfx-micro-viz__meta">${meta}</span>
16563
+ </span>`;
16564
+ }
16565
+ function resolveBulletMax(visualization) {
16566
+ const thresholds = visualization.thresholds ?? [];
16567
+ const values = [
16568
+ toFiniteNumber(visualization.value) ?? 0,
16569
+ visualization.target ?? 0,
16570
+ visualization.total ?? 0,
16571
+ ...thresholds.map(t => t.value)
16572
+ ].filter(v => Number.isFinite(v) && v > 0);
16573
+ return Math.max(...values, 100);
16574
+ }
16575
+ function renderBulletVisualizationHtml(visualization, options) {
16576
+ const currentValue = toFiniteNumber(visualization.value) ?? 0;
16577
+ const max = resolveBulletMax(visualization);
16578
+ const target = toFiniteNumber(visualization.target);
16579
+ const targetLeft = target === undefined ? null : percent(target, max);
16580
+ const isTable = visualization.surface === 'table-cell';
16581
+ // thresholds
16582
+ const thresholds = visualization.thresholds ?? [];
16583
+ let previous = 0;
16584
+ const bands = thresholds.map(t => {
16585
+ const current = Math.max(t.value, previous);
16586
+ const left = max > 0 ? percent(previous, max) : '0';
16587
+ const width = max > 0 ? percent(current - previous, max) : '0';
16588
+ previous = current;
16589
+ return { left, width, tone: t.tone ?? 'info' };
16590
+ }).filter(b => parseFloat(b.width) > 0);
16591
+ 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('');
16592
+ const topHtml = isTable ? '' : `
16593
+ <div class="pfx-micro-bullet__top">
16594
+ <span class="pfx-micro-bullet__label">${escapeHtml$1(visualization.fallbackText)}</span>
16595
+ <span class="pfx-micro-bullet__value">
16596
+ ${escapeHtml$1(formatMicroNumber(currentValue, options.locale))}
16597
+ ${target === undefined ? '' : `<span class="pfx-micro-bullet__target-val">/ Target: ${escapeHtml$1(formatMicroNumber(target, options.locale))}</span>`}
16598
+ </span>
16599
+ </div>`;
16600
+ const bottomHtml = isTable ? '' : `
16601
+ <div class="pfx-micro-bullet__bottom">
16602
+ <span>${escapeHtml$1(formatMicroNumber(visualization.baseline ?? 0, options.locale))}</span>
16603
+ <span>${escapeHtml$1(formatMicroNumber(max, options.locale))}</span>
16604
+ </div>`;
16605
+ return `
16606
+ <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)}">
16607
+ ${topHtml}
16608
+ <span class="pfx-micro-bullet__track">
16609
+ ${bandsHtml}
16610
+ <span class="pfx-micro-bullet__actual" data-tone="${escapeHtml$1(visualization.tone ?? 'info')}" style="width: ${percent(currentValue, max)}%;"></span>
16611
+ ${targetLeft === null ? '' : `<span class="pfx-micro-bullet__target" style="left: ${targetLeft}%;"></span>`}
16612
+ </span>
16613
+ ${bottomHtml}
16614
+ </span>`;
16615
+ }
16616
+ function renderDeltaVisualizationHtml(visualization, options) {
16617
+ const value = toFiniteNumber(visualization.value);
16618
+ const direction = value === undefined ? 'neutral' : value < 0 ? 'down' : value > 0 ? 'up' : 'neutral';
16619
+ const symbol = direction === 'up' ? '&#9650;' : direction === 'down' ? '&#9660;' : '&rarr;';
16620
+ const tone = visualization.tone ??
16621
+ (value === undefined
16622
+ ? 'neutral'
16623
+ : value < 0
16624
+ ? 'danger'
16625
+ : value > 0
16626
+ ? 'success'
16627
+ : 'neutral');
16628
+ const valueSuffix = visualization.valueSuffix ?? '';
16629
+ const text = value === undefined
16630
+ ? visualization.fallbackText
16631
+ : `${formatMicroNumber(Math.abs(value), options.locale)}${valueSuffix}`;
16632
+ const directionLabel = direction === 'up'
16633
+ ? 'up'
16634
+ : direction === 'down'
16635
+ ? 'down'
16636
+ : 'stable';
16637
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText}: ${directionLabel} ${text}`;
16638
+ return `
16639
+ <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)}">
16640
+ <span class="pfx-micro-viz__delta-symbol" aria-hidden="true">${symbol}</span>
16641
+ <span>${escapeHtml$1(text)}</span>
16642
+ </span>`;
16643
+ }
16644
+ function percent(value, total) {
16645
+ if (!Number.isFinite(value) || !Number.isFinite(total) || total <= 0) {
16646
+ return '0';
16647
+ }
16648
+ return Math.max(0, Math.min(100, (value / total) * 100)).toFixed(2);
16649
+ }
16650
+ function toFiniteNumber(value) {
16651
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
16652
+ }
16653
+ function formatMicroNumber(value, locale) {
16654
+ return new Intl.NumberFormat(locale || undefined, {
16655
+ maximumFractionDigits: Math.abs(value) < 10 ? 2 : 0,
16656
+ }).format(value);
16657
+ }
16658
+ function escapeHtml$1(value) {
16659
+ return String(value ?? '')
16660
+ .replace(/&/g, '&amp;')
16661
+ .replace(/</g, '&lt;')
16662
+ .replace(/>/g, '&gt;')
16663
+ .replace(/"/g, '&quot;')
16664
+ .replace(/'/g, '&#39;');
16665
+ }
16666
+ function normalizePoints(value) {
16667
+ const points = normalizeNumericEntries(value);
16668
+ return points.length ? { points } : undefined;
16669
+ }
16670
+ function normalizeSegments(value) {
16671
+ const segments = normalizeNumericEntries(value);
16672
+ return segments.length ? { segments } : undefined;
16673
+ }
16674
+ function normalizeThresholds(value) {
16675
+ const thresholds = normalizeNumericEntries(value);
16676
+ return thresholds.length ? { thresholds } : undefined;
16677
+ }
16678
+ function normalizeItems(value) {
16679
+ if (!Array.isArray(value)) {
16680
+ return undefined;
16681
+ }
16682
+ const items = value
16683
+ .map((item) => normalizeVisualizationItem(item))
16684
+ .filter((item) => !!item);
16685
+ return items.length ? { items } : undefined;
16686
+ }
16687
+ function normalizeExpression(value, key) {
16688
+ if (typeof value === 'string') {
16689
+ const normalized = value.trim();
16690
+ return normalized ? { [key]: normalized } : undefined;
16691
+ }
16692
+ if (value && typeof value === 'object') {
16693
+ return { [key]: value };
16694
+ }
16695
+ return undefined;
16696
+ }
16697
+ function normalizeNumericEntries(value) {
16698
+ if (!Array.isArray(value)) {
16699
+ return [];
16700
+ }
16701
+ return value
16702
+ .map((item) => {
16703
+ if (!item || typeof item !== 'object' || !Number.isFinite(item.value)) {
16704
+ return null;
16705
+ }
16706
+ const label = normalizeText$1(item.label);
16707
+ const tone = normalizeEnum$1(item.tone, VISUALIZATION_TONES);
16708
+ return {
16709
+ value: item.value,
16710
+ ...(label ? { label } : {}),
16711
+ ...(tone ? { tone } : {}),
16712
+ };
16713
+ })
16714
+ .filter((item) => !!item);
16715
+ }
16716
+ function normalizeVisualizationItem(item) {
16717
+ if (!item || typeof item !== 'object') {
16718
+ return null;
16719
+ }
16720
+ const id = normalizeText$1(item.id);
16721
+ const label = normalizeText$1(item.label);
16722
+ const icon = normalizeText$1(item.icon);
16723
+ const state = normalizeText$1(item.state);
16724
+ const tone = normalizeEnum$1(item.tone, VISUALIZATION_TONES);
16725
+ const normalizedValue = Number.isFinite(item.value) ? item.value : undefined;
16726
+ if (!id && !label && normalizedValue === undefined && !icon && !state && !tone) {
16727
+ return null;
16728
+ }
16729
+ return {
16730
+ ...(id ? { id } : {}),
16731
+ ...(label ? { label } : {}),
16732
+ ...(normalizedValue !== undefined ? { value: normalizedValue } : {}),
16733
+ ...(icon ? { icon } : {}),
16734
+ ...(state ? { state } : {}),
16735
+ ...(tone ? { tone } : {}),
16736
+ };
16737
+ }
16738
+ function normalizeNumber(value, key) {
16739
+ return Number.isFinite(value) ? { [key]: value } : undefined;
16740
+ }
16741
+ function normalizeEnum$1(value, allowed) {
16742
+ if (typeof value !== 'string') {
16743
+ return undefined;
16744
+ }
16745
+ const normalized = value.trim();
16746
+ return allowed.has(normalized) ? normalized : undefined;
16747
+ }
16748
+ function normalizeText$1(value) {
16749
+ if (typeof value !== 'string') {
16750
+ return undefined;
16751
+ }
16752
+ const trimmed = value.trim();
16753
+ return trimmed.length ? trimmed : undefined;
16754
+ }
16755
+ function renderRadialVisualizationHtml(visualization, options) {
16756
+ const value = toFiniteNumber(visualization.value) ?? 0;
16757
+ const total = visualization.total && visualization.total > 0 ? visualization.total : 100;
16758
+ const pct = Math.max(0, Math.min(100, (value / total) * 100));
16759
+ const tone = visualization.tone ?? 'info';
16760
+ const dashArray = `${pct.toFixed(1)}, 100`;
16761
+ const pctText = `${Math.round(pct)}%`;
16762
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText} (${pctText})`;
16763
+ const isTable = visualization.surface === 'table-cell';
16764
+ const svgText = isTable
16765
+ ? ''
16766
+ : `<text x="18" y="21" class="pfx-micro-radial-svg__text">${escapeHtml$1(pctText)}</text>`;
16767
+ const externalText = isTable
16768
+ ? `<span class="pfx-micro-radial-value">${escapeHtml$1(pctText)}</span>`
16769
+ : '';
16770
+ return `
16771
+ <span class="pfx-micro-viz pfx-micro-viz__radial" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(aria)}">
16772
+ <svg class="pfx-micro-radial-svg" viewBox="0 0 36 36">
16773
+ <circle class="pfx-micro-radial-svg__track" cx="18" cy="18" r="15.9155" />
16774
+ <circle class="pfx-micro-radial-svg__bar" cx="18" cy="18" r="15.9155" stroke-dasharray="${dashArray}" transform="rotate(-90 18 18)" />
16775
+ ${svgText}
16776
+ </svg>
16777
+ ${externalText}
16778
+ </span>`;
16779
+ }
16780
+ function renderHarveyBallVisualizationHtml(visualization, options) {
16781
+ const value = toFiniteNumber(visualization.value) ?? 0;
16782
+ const total = visualization.total && visualization.total > 0 ? visualization.total : 100;
16783
+ const pct = Math.max(0, Math.min(100, (value / total) * 100));
16784
+ const tone = visualization.tone ?? 'info';
16785
+ const strokeLength = pct * 0.50265;
16786
+ const dashArray = `${strokeLength.toFixed(3)} 50.265`;
16787
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText} (${Math.round(pct)}%)`;
16788
+ return `
16789
+ <span class="pfx-micro-viz pfx-micro-viz__harvey" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(aria)}">
16790
+ <svg class="pfx-micro-harvey-svg" viewBox="0 0 36 36">
16791
+ <circle class="pfx-micro-harvey-svg__track" cx="18" cy="18" r="16" />
16792
+ <circle class="pfx-micro-harvey-svg__bar" cx="18" cy="18" r="8" stroke-dasharray="${dashArray}" transform="rotate(-90 18 18)" />
16793
+ </svg>
16794
+ <span class="pfx-micro-harvey-fraction">
16795
+ <strong>${escapeHtml$1(formatMicroNumber(value, options.locale))}</strong>
16796
+ <span class="pfx-separator">/</span>
16797
+ <span class="pfx-total">${escapeHtml$1(formatMicroNumber(total, options.locale))}</span>
16798
+ </span>
16799
+ </span>`;
16800
+ }
16801
+ function getPointsCoordinates(points, width, height, padding) {
16802
+ if (points.length < 2)
16803
+ return [];
16804
+ const values = points.map(p => p.value);
16805
+ const minVal = Math.min(...values);
16806
+ const maxVal = Math.max(...values);
16807
+ const valRange = maxVal - minVal === 0 ? 1 : maxVal - minVal;
16808
+ return points.map((p, index) => {
16809
+ const x = padding + (index / (points.length - 1)) * (width - 2 * padding);
16810
+ const y = height - padding - ((p.value - minVal) / valRange) * (height - 2 * padding);
16811
+ return { x, y };
16812
+ });
16813
+ }
16814
+ function renderLineVisualizationHtml(visualization, options) {
16815
+ const points = visualization.points ?? [];
16816
+ const tone = visualization.tone ?? 'info';
16817
+ if (points.length < 2) {
16818
+ return renderFallbackVisualizationHtml(visualization, tone);
16819
+ }
16820
+ const width = 100;
16821
+ const height = 30;
16822
+ const padding = 4;
16823
+ const coords = getPointsCoordinates(points, width, height, padding);
16824
+ const pathD = coords.map((c, i) => `${i === 0 ? 'M' : 'L'} ${c.x.toFixed(1)} ${c.y.toFixed(1)}`).join(' ');
16825
+ // Highlight extreme/boundary values
16826
+ let minIdx = 0;
16827
+ let maxIdx = 0;
16828
+ for (let i = 1; i < points.length; i++) {
16829
+ if (points[i].value < points[minIdx].value)
16830
+ minIdx = i;
16831
+ if (points[i].value > points[maxIdx].value)
16832
+ maxIdx = i;
16833
+ }
16834
+ const markers = [
16835
+ { x: coords[0].x, y: coords[0].y, tone: points[0].tone ?? tone },
16836
+ { x: coords[coords.length - 1].x, y: coords[coords.length - 1].y, tone: points[points.length - 1].tone ?? tone }
16837
+ ];
16838
+ if (minIdx !== 0 && minIdx !== coords.length - 1) {
16839
+ markers.push({ x: coords[minIdx].x, y: coords[minIdx].y, tone: points[minIdx].tone ?? 'danger' });
16840
+ }
16841
+ if (maxIdx !== 0 && maxIdx !== coords.length - 1) {
16842
+ markers.push({ x: coords[maxIdx].x, y: coords[maxIdx].y, tone: points[maxIdx].tone ?? 'success' });
16843
+ }
16844
+ 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('');
16845
+ const isTable = visualization.surface === 'table-cell';
16846
+ const firstPoint = points[0];
16847
+ const lastPoint = points[points.length - 1];
16848
+ const leftHtml = isTable ? '' : `
16849
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16850
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16851
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16852
+ </div>`;
16853
+ const rightHtml = isTable ? '' : `
16854
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16855
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16856
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16857
+ </div>`;
16858
+ return `
16859
+ <span class="pfx-micro-viz-container">
16860
+ ${leftHtml}
16861
+ <span class="pfx-micro-viz pfx-micro-viz__line" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16862
+ <svg class="pfx-micro-line__svg" viewBox="0 0 100 30">
16863
+ <path class="pfx-micro-line__path" d="${pathD}" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
16864
+ ${circlesHtml}
16865
+ </svg>
16866
+ </span>
16867
+ ${rightHtml}
16868
+ </span>`;
16869
+ }
16870
+ function renderAreaVisualizationHtml(visualization, options) {
16871
+ const points = visualization.points ?? [];
16872
+ const tone = visualization.tone ?? 'info';
16873
+ if (points.length < 2) {
16874
+ return renderFallbackVisualizationHtml(visualization, tone);
16875
+ }
16876
+ const width = 100;
16877
+ const height = 30;
16878
+ const padding = 4;
16879
+ const coords = getPointsCoordinates(points, width, height, padding);
16880
+ const lineD = coords.map((c, i) => `${i === 0 ? 'M' : 'L'} ${c.x.toFixed(1)} ${c.y.toFixed(1)}`).join(' ');
16881
+ const firstX = coords[0].x.toFixed(1);
16882
+ const lastX = coords[coords.length - 1].x.toFixed(1);
16883
+ const areaD = `${lineD} L ${lastX} ${height} L ${firstX} ${height} Z`;
16884
+ // Highlight extreme/boundary values
16885
+ let minIdx = 0;
16886
+ let maxIdx = 0;
16887
+ for (let i = 1; i < points.length; i++) {
16888
+ if (points[i].value < points[minIdx].value)
16889
+ minIdx = i;
16890
+ if (points[i].value > points[maxIdx].value)
16891
+ maxIdx = i;
16892
+ }
16893
+ const markers = [
16894
+ { x: coords[0].x, y: coords[0].y, tone: points[0].tone ?? tone },
16895
+ { x: coords[coords.length - 1].x, y: coords[coords.length - 1].y, tone: points[points.length - 1].tone ?? tone }
16896
+ ];
16897
+ if (minIdx !== 0 && minIdx !== coords.length - 1) {
16898
+ markers.push({ x: coords[minIdx].x, y: coords[minIdx].y, tone: points[minIdx].tone ?? 'danger' });
16899
+ }
16900
+ if (maxIdx !== 0 && maxIdx !== coords.length - 1) {
16901
+ markers.push({ x: coords[maxIdx].x, y: coords[maxIdx].y, tone: points[maxIdx].tone ?? 'success' });
16902
+ }
16903
+ 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('');
16904
+ const isTable = visualization.surface === 'table-cell';
16905
+ const firstPoint = points[0];
16906
+ const lastPoint = points[points.length - 1];
16907
+ const leftHtml = isTable ? '' : `
16908
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16909
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16910
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16911
+ </div>`;
16912
+ const rightHtml = isTable ? '' : `
16913
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16914
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16915
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16916
+ </div>`;
16917
+ return `
16918
+ <span class="pfx-micro-viz-container">
16919
+ ${leftHtml}
16920
+ <span class="pfx-micro-viz pfx-micro-viz__area" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16921
+ <svg class="pfx-micro-area__svg" viewBox="0 0 100 30">
16922
+ <path class="pfx-micro-area__fill" d="${areaD}" fill="currentColor" fill-opacity="0.15" />
16923
+ <path class="pfx-micro-area__path" d="${lineD}" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
16924
+ ${circlesHtml}
16925
+ </svg>
16926
+ </span>
16927
+ ${rightHtml}
16928
+ </span>`;
16929
+ }
16930
+ function renderColumnVisualizationHtml(visualization, options) {
16931
+ const points = visualization.points ?? [];
16932
+ const tone = visualization.tone ?? 'info';
16933
+ if (points.length === 0) {
16934
+ return renderFallbackVisualizationHtml(visualization, tone);
16935
+ }
16936
+ const width = 100;
16937
+ const height = 30;
16938
+ const padding = 4;
16939
+ const values = points.map(p => p.value);
16940
+ const maxVal = Math.max(...values, 0);
16941
+ const minVal = Math.min(...values, 0);
16942
+ const valRange = maxVal - minVal === 0 ? 1 : maxVal - minVal;
16943
+ const colWidth = Math.max(2, (width - 2 * padding) / points.length - 2);
16944
+ const columnsHtml = points.map((p, i) => {
16945
+ const x = padding + i * ((width - 2 * padding) / points.length) + 1;
16946
+ const rectHeight = Math.max(2, ((p.value - minVal) / valRange) * (height - 2 * padding));
16947
+ const rectY = height - padding - rectHeight;
16948
+ const itemTone = p.tone ?? tone;
16949
+ 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)}" />`;
16950
+ }).join('');
16951
+ const isTable = visualization.surface === 'table-cell';
16952
+ const firstPoint = points[0];
16953
+ const lastPoint = points[points.length - 1];
16954
+ const leftHtml = isTable ? '' : `
16955
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--start">
16956
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(firstPoint.value, options.locale))}</span>
16957
+ ${firstPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(firstPoint.label)}</span>` : ''}
16958
+ </div>`;
16959
+ const rightHtml = isTable ? '' : `
16960
+ <div class="pfx-micro-trend__label-col pfx-micro-trend__label-col--end">
16961
+ <span class="pfx-micro-trend__value">${escapeHtml$1(formatMicroNumber(lastPoint.value, options.locale))}</span>
16962
+ ${lastPoint.label ? `<span class="pfx-micro-trend__label">${escapeHtml$1(lastPoint.label)}</span>` : ''}
16963
+ </div>`;
16964
+ return `
16965
+ <span class="pfx-micro-viz-container">
16966
+ ${leftHtml}
16967
+ <span class="pfx-micro-viz pfx-micro-viz__column" data-tone="${escapeHtml$1(tone)}" role="img" aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}">
16968
+ <svg class="pfx-micro-column__svg" viewBox="0 0 100 30">
16969
+ ${columnsHtml}
16970
+ </svg>
16971
+ </span>
16972
+ ${rightHtml}
16973
+ </span>`;
16974
+ }
16975
+ function renderProcessFlowVisualizationHtml(visualization, options) {
16976
+ const items = visualization.items ?? [];
16977
+ if (items.length === 0) {
16978
+ return renderFallbackVisualizationHtml(visualization, visualization.tone ?? 'neutral');
16979
+ }
16980
+ const isTable = visualization.surface === 'table-cell';
16981
+ const stepLabels = items.map((item, index) => item.label ?? item.id ?? `${index + 1}`);
16982
+ const aria = visualization.ariaLabel ?? `${visualization.fallbackText}: ${stepLabels.join(' > ')}`;
16983
+ const stepsHtml = items.map((item, index) => {
16984
+ const itemTone = item.tone ?? 'neutral';
16985
+ const itemState = item.state ?? '';
16986
+ const isLast = index === items.length - 1;
16987
+ const itemLabel = stepLabels[index];
16988
+ const label = !isTable && item.label ? `<span class="pfx-micro-step__label">${escapeHtml$1(item.label)}</span>` : '';
16989
+ const connector = !isLast ? `<span class="pfx-micro-step__connector" data-tone="${escapeHtml$1(itemTone)}"></span>` : '';
16990
+ const stepCircle = `
16991
+ <span class="pfx-micro-step__node" data-tone="${escapeHtml$1(itemTone)}" aria-hidden="true">
16992
+ ${item.icon ? `<span class="material-icons pfx-micro-step__icon" aria-hidden="true">${escapeHtml$1(item.icon)}</span>` : `${index + 1}`}
16993
+ </span>`;
16994
+ return `
16995
+ <div class="pfx-micro-step" data-state="${escapeHtml$1(itemState)}" data-tone="${escapeHtml$1(itemTone)}">
16996
+ <div class="pfx-micro-step__node-wrapper" title="${escapeHtml$1(itemLabel)}">
16997
+ ${stepCircle}
16998
+ ${label}
16999
+ </div>
17000
+ ${connector}
17001
+ </div>`;
17002
+ }).join('');
17003
+ return `
17004
+ <span class="pfx-micro-viz pfx-micro-viz__process" role="img" aria-label="${escapeHtml$1(aria)}">
17005
+ ${stepsHtml}
17006
+ </span>`;
17007
+ }
17008
+ function renderFallbackVisualizationHtml(visualization, tone) {
17009
+ return `
17010
+ <span
17011
+ class="pfx-micro-viz pfx-micro-viz__fallback"
17012
+ data-tone="${escapeHtml$1(tone)}"
17013
+ role="img"
17014
+ aria-label="${escapeHtml$1(visualization.ariaLabel ?? visualization.fallbackText)}"
17015
+ >${escapeHtml$1(visualization.fallbackText)}</span>`;
17016
+ }
17017
+
17018
+ const TONES = new Set([
17019
+ 'neutral',
17020
+ 'info',
17021
+ 'success',
17022
+ 'warning',
17023
+ 'danger',
17024
+ ]);
17025
+ const APPEARANCES = new Set([
17026
+ 'plain',
17027
+ 'soft',
17028
+ 'outlined',
17029
+ 'filled',
17030
+ ]);
17031
+ const PRESENTERS = new Set([
17032
+ 'text',
17033
+ 'badge',
17034
+ 'chip',
17035
+ 'status',
17036
+ 'iconValue',
17037
+ 'progress',
17038
+ 'rating',
17039
+ 'microVisualization',
17040
+ ]);
17041
+ /**
17042
+ * Resolves readonly field presentation from a base semantic config plus ordered
17043
+ * Json Logic rules. Later matching rules override earlier presentation values.
17044
+ */
17045
+ function resolveFieldPresentation(base, rules, context = {}, options = {}) {
17046
+ let resolved = normalizeFieldPresentation(base);
17047
+ let matchedRule = false;
17048
+ if (!Array.isArray(rules) || !options.jsonLogic) {
17049
+ return resolved;
17050
+ }
17051
+ for (const rule of rules) {
17052
+ if (!rule?.when || !matchesPresentationRule(rule, context, options.jsonLogic)) {
17053
+ continue;
17054
+ }
17055
+ const effect = normalizeFieldPresentation(rule.set ?? rule.effect);
17056
+ resolved = {
17057
+ ...resolved,
17058
+ ...effect,
17059
+ };
17060
+ matchedRule = true;
17061
+ }
17062
+ return matchedRule ? { ...resolved, matchedRule } : resolved;
17063
+ }
17064
+ function normalizeFieldPresentation(value) {
17065
+ if (!value || typeof value !== 'object') {
17066
+ return {};
17067
+ }
17068
+ const presenter = normalizePresenter(value.presenter ?? value.variant);
17069
+ const tone = normalizeTone(value.tone);
17070
+ const appearance = normalizeAppearance(value.appearance);
17071
+ const icon = normalizeText(value.icon);
17072
+ const label = normalizeText(value.label);
17073
+ const badge = normalizeText(value.badge);
17074
+ const tooltip = normalizeText(value.tooltip);
17075
+ const visualization = normalizePraxisPresentationVisualization(value.visualization);
17076
+ return {
17077
+ ...(presenter ? { presenter } : {}),
17078
+ ...(tone ? { tone } : {}),
17079
+ ...(appearance ? { appearance } : {}),
17080
+ ...(icon ? { icon } : {}),
17081
+ ...(label ? { label } : {}),
17082
+ ...(badge ? { badge } : {}),
17083
+ ...(tooltip ? { tooltip } : {}),
17084
+ ...(value.valuePresentation && typeof value.valuePresentation === 'object'
17085
+ ? { valuePresentation: value.valuePresentation }
17086
+ : {}),
17087
+ ...(visualization ? { visualization } : {}),
17088
+ ...(value.interactions && typeof value.interactions === 'object'
17089
+ ? { interactions: normalizeInteractions(value.interactions) }
17090
+ : {}),
17091
+ };
17092
+ }
17093
+ function matchesPresentationRule(rule, context, jsonLogic) {
17094
+ try {
17095
+ const result = jsonLogic.evaluate(rule.when, context);
17096
+ return typeof jsonLogic.truthy === 'function'
17097
+ ? jsonLogic.truthy(result)
17098
+ : Boolean(result);
17099
+ }
17100
+ catch {
17101
+ return false;
17102
+ }
17103
+ }
17104
+ function normalizePresenter(value) {
17105
+ return normalizeEnum(value, PRESENTERS);
17106
+ }
17107
+ function normalizeTone(value) {
17108
+ return normalizeEnum(value, TONES);
17109
+ }
17110
+ function normalizeAppearance(value) {
17111
+ return normalizeEnum(value, APPEARANCES);
17112
+ }
17113
+ function normalizeEnum(value, allowed) {
17114
+ if (typeof value !== 'string') {
17115
+ return undefined;
17116
+ }
17117
+ const normalized = value.trim();
17118
+ return allowed.has(normalized) ? normalized : undefined;
17119
+ }
17120
+ function normalizeText(value) {
17121
+ if (typeof value !== 'string') {
17122
+ return undefined;
17123
+ }
17124
+ const trimmed = value.trim();
17125
+ return trimmed.length ? trimmed : undefined;
17126
+ }
17127
+ function normalizeInteractions(value) {
17128
+ return {
17129
+ ...(value.copy === true ? { copy: true } : {}),
17130
+ ...(value.details === true ? { details: true } : {}),
17131
+ ...(value.expand === true ? { expand: true } : {}),
17132
+ ...(value.link === true ? { link: true } : {}),
17133
+ };
17134
+ }
17135
+
16019
17136
  /**
16020
17137
  * @fileoverview Specialized metadata interfaces for Angular Material components
16021
17138
  *
@@ -16392,6 +17509,43 @@ function normalizeSelectLike(meta) {
16392
17509
  return m;
16393
17510
  }
16394
17511
 
17512
+ const SERVER_OWNED_FIELD_SEMANTIC_KEYS = [
17513
+ 'label',
17514
+ 'hint',
17515
+ 'helpText',
17516
+ 'description',
17517
+ 'tooltip',
17518
+ 'tooltipOnHover',
17519
+ 'icon',
17520
+ 'prefixIcon',
17521
+ 'suffixIcon',
17522
+ 'iconPosition',
17523
+ 'iconSize',
17524
+ 'iconColor',
17525
+ 'iconClass',
17526
+ 'iconStyle',
17527
+ 'iconFontSize',
17528
+ ];
17529
+ function applyServerOwnedFieldSemantics(merged, serverField) {
17530
+ const next = { ...merged };
17531
+ const server = serverField;
17532
+ for (const key of SERVER_OWNED_FIELD_SEMANTIC_KEYS) {
17533
+ if (server[key] === undefined) {
17534
+ delete next[key];
17535
+ }
17536
+ else {
17537
+ next[key] = server[key];
17538
+ }
17539
+ }
17540
+ return next;
17541
+ }
17542
+
17543
+ function withFormConfigSections(config) {
17544
+ return {
17545
+ ...config,
17546
+ sections: config.sections || [],
17547
+ };
17548
+ }
16395
17549
  function createDefaultFormConfig() {
16396
17550
  const config = {
16397
17551
  sections: [
@@ -16435,7 +17589,21 @@ function createDefaultFormConfig() {
16435
17589
  return ensureIds(config);
16436
17590
  }
16437
17591
  function isValidFormConfig(config) {
16438
- return config && typeof config === 'object' && Array.isArray(config.sections);
17592
+ if (!config || typeof config !== 'object') {
17593
+ return false;
17594
+ }
17595
+ if (config.sections !== undefined) {
17596
+ return Array.isArray(config.sections);
17597
+ }
17598
+ return hasSchemaDrivenFormConfigGrounding(config);
17599
+ }
17600
+ function hasSchemaDrivenFormConfigGrounding(config) {
17601
+ const metadata = config.metadata;
17602
+ return (metadata?.source === 'schema' ||
17603
+ !!metadata?.schemaLayoutPolicy ||
17604
+ !!metadata?.schemaId ||
17605
+ !!metadata?.schemaContext ||
17606
+ Array.isArray(config.fieldMetadata));
16439
17607
  }
16440
17608
  /**
16441
17609
  * Cria configuração vazia para inicialização
@@ -16488,7 +17656,7 @@ function mergeFieldMetadata(config, fieldMetadata) {
16488
17656
  function getReferencedFieldMetadata(config, allFieldMetadata) {
16489
17657
  // Get all field names referenced in the config
16490
17658
  const referencedFieldNames = new Set();
16491
- config.sections.forEach((section) => {
17659
+ withFormConfigSections(config).sections.forEach((section) => {
16492
17660
  section.rows.forEach((row) => {
16493
17661
  row.columns.forEach((column) => {
16494
17662
  getFormColumnFieldNames(column).forEach((fieldName) => {
@@ -16554,7 +17722,7 @@ function syncWithServerMetadata(localConfig, serverMetadata) {
16554
17722
  toggleOptions: pick('toggleOptions'),
16555
17723
  nodes: pick('nodes'),
16556
17724
  };
16557
- mergedOverlapping.push(merged);
17725
+ mergedOverlapping.push(applyServerOwnedFieldSemantics(merged, serverField));
16558
17726
  // Track simple modifications for diagnostics
16559
17727
  ['label', 'required', 'maxLength', 'minLength', 'dataType', 'controlType'].forEach((prop) => {
16560
17728
  if (loc[prop] !== base[prop]) {
@@ -16894,7 +18062,7 @@ const EVENT_REGISTRATION_EDITORIAL_TEMPLATE = {
16894
18062
  content: [
16895
18063
  {
16896
18064
  type: 'text',
16897
- text: 'Ao enviar a inscricao, o participante reconhece o tratamento dos dados para credenciamento, comunicacoes e operacao do evento.',
18065
+ text: 'Ao enviar a inscrição, o participante reconhece o tratamento dos dados para credenciamento, comunicações e operação do evento.',
16898
18066
  },
16899
18067
  ],
16900
18068
  }),
@@ -17035,7 +18203,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17035
18203
  wrap: true,
17036
18204
  items: [
17037
18205
  { type: 'badge', label: 'onboarding' },
17038
- { type: 'text', text: 'Admissao, conferencia e preferencias iniciais' },
18206
+ { type: 'text', text: 'Admissão, conferência e preferências iniciais' },
17039
18207
  ],
17040
18208
  },
17041
18209
  }, {
@@ -17044,7 +18212,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17044
18212
  subtitle: 'Resumo do fluxo',
17045
18213
  content: [
17046
18214
  { type: 'text', text: 'Dados pessoais e de contato.' },
17047
- { type: 'text', text: 'Preferencias operacionais iniciais.' },
18215
+ { type: 'text', text: 'Preferências operacionais iniciais.' },
17048
18216
  { type: 'text', text: 'Anexos e termos obrigatorios.' },
17049
18217
  ],
17050
18218
  }),
@@ -17076,7 +18244,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17076
18244
  id: 'operations',
17077
18245
  appearance: 'step',
17078
18246
  stepLabel: '2',
17079
- title: 'Operacao inicial',
18247
+ title: 'Operação inicial',
17080
18248
  description: 'Dados para preparacao do ambiente e comunicacao inicial.',
17081
18249
  rows: [
17082
18250
  {
@@ -17102,7 +18270,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17102
18270
  title: 'Uso interno',
17103
18271
  subtitle: 'Antes do envio',
17104
18272
  badge: 'info',
17105
- description: 'As informacoes deste fluxo sao usadas exclusivamente para cadastro interno, provisionamento e comunicacao de onboarding.',
18273
+ description: 'As informações deste fluxo são usadas exclusivamente para cadastro interno, provisionamento e comunicação de onboarding.',
17106
18274
  }),
17107
18275
  formBlocksBeforeActionsPlacement: 'afterSections',
17108
18276
  actions: {
@@ -17151,7 +18319,7 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17151
18319
  required: true,
17152
18320
  options: [
17153
18321
  { text: 'Presencial', value: 'ONSITE' },
17154
- { text: 'Hibrido', value: 'HYBRID' },
18322
+ { text: 'Híbrido', value: 'HYBRID' },
17155
18323
  { text: 'Remoto', value: 'REMOTE' },
17156
18324
  ],
17157
18325
  },
@@ -17162,22 +18330,22 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_TEMPLATE = {
17162
18330
  required: true,
17163
18331
  options: [
17164
18332
  { text: 'Sim', value: 'YES' },
17165
- { text: 'Nao', value: 'NO' },
18333
+ { text: 'Não', value: 'NO' },
17166
18334
  ],
17167
18335
  },
17168
18336
  {
17169
18337
  name: 'shippingAddress',
17170
- label: 'Endereco para envio',
18338
+ label: 'Endereço para envio',
17171
18339
  controlType: 'textarea',
17172
18340
  },
17173
18341
  {
17174
18342
  name: 'accessibilityNotes',
17175
- label: 'Observacoes de acessibilidade ou preferencias',
18343
+ label: 'Observações de acessibilidade ou preferências',
17176
18344
  controlType: 'textarea',
17177
18345
  },
17178
18346
  {
17179
18347
  name: 'privacyConsent',
17180
- label: 'Confirmo ciencia sobre o tratamento dos meus dados no processo de onboarding.',
18348
+ label: 'Confirmo ciência sobre o tratamento dos meus dados no processo de onboarding.',
17181
18349
  controlType: 'checkbox',
17182
18350
  selectionMode: 'boolean',
17183
18351
  variant: 'consent',
@@ -17250,7 +18418,7 @@ const EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE = {
17250
18418
  id: 'operations',
17251
18419
  appearance: 'step',
17252
18420
  stepLabel: '2',
17253
- title: 'Operacao inicial',
18421
+ title: 'Operação inicial',
17254
18422
  description: 'Configure os recursos necessarios para o primeiro dia.',
17255
18423
  rows: [
17256
18424
  {
@@ -17360,17 +18528,17 @@ const EMPLOYEE_ONBOARDING_GUIDED_EDITORIAL_TEMPLATE = {
17360
18528
  options: [
17361
18529
  { text: 'Presencial', value: 'Presencial' },
17362
18530
  { text: 'Remoto', value: 'Remoto' },
17363
- { text: 'Hibrido', value: 'Hibrido' },
18531
+ { text: 'Híbrido', value: 'Híbrido' },
17364
18532
  ],
17365
18533
  },
17366
18534
  {
17367
18535
  name: 'accessibilityNotes',
17368
- label: 'Observacoes adicionais',
18536
+ label: 'Observações adicionais',
17369
18537
  controlType: 'textarea',
17370
18538
  },
17371
18539
  {
17372
18540
  name: 'privacyConsent',
17373
- label: 'Confirmo ciencia sobre o tratamento dos meus dados no processo de onboarding.',
18541
+ label: 'Confirmo ciência sobre o tratamento dos meus dados no processo de onboarding.',
17374
18542
  controlType: 'checkbox',
17375
18543
  selectionMode: 'boolean',
17376
18544
  variant: 'consent',
@@ -17386,7 +18554,7 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17386
18554
  version: '1.0.0',
17387
18555
  metadata: {
17388
18556
  title: 'Privacy Consent',
17389
- description: 'Template focado em aceite explicito, base legal, preferencias de comunicacao e registro de consentimento.',
18557
+ description: 'Template focado em aceite explícito, base legal, preferências de comunicação e registro de consentimento.',
17390
18558
  category: 'consent',
17391
18559
  tags: ['privacy', 'consent', 'compliance', 'legal'],
17392
18560
  source: 'catalog',
@@ -17408,13 +18576,13 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17408
18576
  title: 'Consentimento e tratamento de dados',
17409
18577
  subtitle: 'Template regulatorio',
17410
18578
  badge: 'info',
17411
- description: 'Use este template quando o objetivo principal do fluxo for registrar ciencia, aceite e preferencias relacionadas a privacidade.',
18579
+ description: 'Use este template quando o objetivo principal do fluxo for registrar ciência, aceite e preferências relacionadas a privacidade.',
17412
18580
  }),
17413
18581
  sections: [
17414
18582
  {
17415
18583
  id: 'consent',
17416
18584
  appearance: 'card',
17417
- title: 'Preferencias e consentimentos',
18585
+ title: 'Preferências e consentimentos',
17418
18586
  description: 'Aceites explicitos e canais opcionais de comunicacao.',
17419
18587
  rows: [
17420
18588
  {
@@ -17497,7 +18665,7 @@ const PRIVACY_CONSENT_EDITORIAL_TEMPLATE = {
17497
18665
  },
17498
18666
  {
17499
18667
  name: 'consentNotes',
17500
- label: 'Observacoes adicionais',
18668
+ label: 'Observações adicionais',
17501
18669
  controlType: 'textarea',
17502
18670
  },
17503
18671
  ],
@@ -17533,6 +18701,8 @@ const RULE_PROPERTY_SCHEMA = {
17533
18701
  { name: 'tooltip', type: 'string', label: 'Tooltip' },
17534
18702
  { name: 'prefixIcon', type: 'string', label: 'Ícone prefixo' },
17535
18703
  { name: 'suffixIcon', type: 'string', label: 'Ícone sufixo' },
18704
+ { name: 'presentation', type: 'object', label: 'Apresentação', category: 'appearance' },
18705
+ { name: 'presentationRules', type: 'array', label: 'Regras de apresentação', category: 'appearance' },
17536
18706
  { name: 'prefixText', type: 'string', label: 'Texto prefixo' },
17537
18707
  { name: 'suffixText', type: 'string', label: 'Texto sufixo' },
17538
18708
  { name: 'defaultValue', type: 'object', label: 'Valor padrão' },
@@ -18256,8 +19426,8 @@ const EMPLOYEE_ONBOARDING_EDITORIAL_SOLUTION = {
18256
19426
  fields: [
18257
19427
  { key: 'selectedEquipment', label: 'Equipamentos', valuePath: 'formData.selectedEquipment', hideWhenEmpty: true },
18258
19428
  { 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 },
19429
+ { key: 'shippingAddress', label: 'Endereço para envio', valuePath: 'formData.shippingAddress', hideWhenEmpty: true },
19430
+ { key: 'accessibilityNotes', label: 'Observações adicionais', valuePath: 'formData.accessibilityNotes', hideWhenEmpty: true },
18261
19431
  ],
18262
19432
  },
18263
19433
  ],
@@ -19566,6 +20736,388 @@ const ValidationPattern = {
19566
20736
  CUSTOM: '',
19567
20737
  };
19568
20738
 
20739
+ function materializeFormLayoutFromMetadata(fields, options = {}) {
20740
+ const policy = normalizeLayoutPolicy(options.policy);
20741
+ const visibleFields = normalizeFields(fields, options.includeHidden === true);
20742
+ const layoutFields = fieldsForLayoutPolicy(visibleFields, policy);
20743
+ const groupedFields = groupFields(layoutFields);
20744
+ const sections = groupedFields.map(([groupKey, groupFields], sectionIndex) => createSection(groupKey, groupFields, sectionIndex, policy, options));
20745
+ return ensureIds({
20746
+ sections,
20747
+ fieldMetadata: fieldsForPolicy(visibleFields, policy),
20748
+ metadata: {
20749
+ version: '1.0.0',
20750
+ lastUpdated: new Date(),
20751
+ source: 'schema',
20752
+ generatedLayoutPreset: policy.preset,
20753
+ schemaLayoutPolicy: policy,
20754
+ ...(policy.preset === 'compactPresentation'
20755
+ ? { presentationDensity: 'compact' }
20756
+ : {}),
20757
+ },
20758
+ });
20759
+ }
20760
+ function normalizeLayoutPolicy(policy) {
20761
+ const intent = policy?.intent ?? (policy?.preset === 'groupedCommand' ? 'command' : 'detail');
20762
+ const preset = policy?.preset ?? (intent === 'command' ? 'groupedCommand' : 'compactPresentation');
20763
+ return {
20764
+ source: policy?.source ?? 'authored',
20765
+ preset,
20766
+ intent,
20767
+ lifecycle: policy?.lifecycle ?? 'initial',
20768
+ persistence: policy?.persistence ?? 'authorable',
20769
+ detachBehavior: policy?.detachBehavior ?? 'none',
20770
+ schemaOperation: policy?.schemaOperation,
20771
+ schemaType: policy?.schemaType,
20772
+ detailSummary: policy?.detailSummary,
20773
+ };
20774
+ }
20775
+ function normalizeFields(fields, includeHidden) {
20776
+ return (fields || [])
20777
+ .filter((field) => !!field?.name)
20778
+ .filter((field) => includeHidden || !isFormHidden(field))
20779
+ .sort(compareFields);
20780
+ }
20781
+ function isFormHidden(field) {
20782
+ const anyField = field;
20783
+ return anyField.formHidden === true || anyField.hidden === true || anyField.visible === false;
20784
+ }
20785
+ function groupFields(fields) {
20786
+ const groups = new Map();
20787
+ for (const field of fields) {
20788
+ const groupKey = normalizeGroupLabel(field.group);
20789
+ groups.set(groupKey, [...(groups.get(groupKey) || []), field]);
20790
+ }
20791
+ return Array.from(groups.entries()).sort(([, left], [, right]) => compareGroupFields(left, right));
20792
+ }
20793
+ function createSection(groupKey, groupFields, sectionIndex, policy, options) {
20794
+ const title = groupKey === 'default'
20795
+ ? options.defaultSectionTitle || 'Informacoes'
20796
+ : groupKey;
20797
+ const sectionId = stableSectionId(groupKey);
20798
+ const presentationRole = resolvePresentationRole(groupKey, groupFields, options.presentationRoleMap);
20799
+ return {
20800
+ id: sectionId,
20801
+ title,
20802
+ ...(policy.preset === 'compactPresentation'
20803
+ ? {
20804
+ icon: resolvePresentationSectionIcon(presentationRole),
20805
+ sectionHeader: {
20806
+ mode: 'icon',
20807
+ size: 'sm',
20808
+ fallbackIcon: resolvePresentationSectionIcon(presentationRole),
20809
+ },
20810
+ className: [
20811
+ 'pdx-presentation-section',
20812
+ `pdx-presentation-section--${presentationRole}`,
20813
+ ].join(' '),
20814
+ presentationRole,
20815
+ appearance: 'plain',
20816
+ }
20817
+ : {}),
20818
+ rows: policy.preset === 'groupedCommand'
20819
+ ? createCommandRows(groupFields, sectionId)
20820
+ : createPresentationRows(groupFields, sectionId),
20821
+ };
20822
+ }
20823
+ function createPresentationRows(fields, sectionId) {
20824
+ const presentationFields = resolvePresentationFields(fields);
20825
+ const rows = [];
20826
+ let pending = [];
20827
+ let pendingSpan = 0;
20828
+ let rowIndex = 0;
20829
+ const flush = () => {
20830
+ if (!pending.length)
20831
+ return;
20832
+ rows.push({ id: `${sectionId}-row-${++rowIndex}`, columns: pending });
20833
+ pending = [];
20834
+ pendingSpan = 0;
20835
+ };
20836
+ for (const field of presentationFields) {
20837
+ const span = hasExplicitWidth(field)
20838
+ ? resolveCommandSpan(field)
20839
+ : { xs: 12, sm: 12, md: 12, lg: 12, xl: 12 };
20840
+ const mdSpan = span.md ?? 12;
20841
+ const column = {
20842
+ id: `${sectionId}-col-${field.name}`,
20843
+ fields: [field.name],
20844
+ items: [{ id: `${sectionId}-item-${field.name}`, kind: 'field', fieldName: field.name }],
20845
+ span,
20846
+ };
20847
+ if (mdSpan >= 12) {
20848
+ flush();
20849
+ pending = [column];
20850
+ flush();
20851
+ continue;
20852
+ }
20853
+ if (pendingSpan + mdSpan > 12) {
20854
+ flush();
20855
+ }
20856
+ pending.push(column);
20857
+ pendingSpan += mdSpan;
20858
+ }
20859
+ flush();
20860
+ return rows;
20861
+ }
20862
+ function createCommandRows(fields, sectionId) {
20863
+ const rows = [];
20864
+ let pending = [];
20865
+ let pendingSpan = 0;
20866
+ let rowIndex = 0;
20867
+ const flush = () => {
20868
+ if (!pending.length)
20869
+ return;
20870
+ rows.push({ id: `${sectionId}-row-${++rowIndex}`, columns: pending });
20871
+ pending = [];
20872
+ pendingSpan = 0;
20873
+ };
20874
+ for (const field of fields) {
20875
+ const span = resolveCommandSpan(field);
20876
+ const mdSpan = span.md ?? 12;
20877
+ const column = {
20878
+ id: `${sectionId}-col-${field.name}`,
20879
+ fields: [field.name],
20880
+ items: [{ id: `${sectionId}-item-${field.name}`, kind: 'field', fieldName: field.name }],
20881
+ span,
20882
+ };
20883
+ if (mdSpan >= 12) {
20884
+ flush();
20885
+ pending = [column];
20886
+ flush();
20887
+ continue;
20888
+ }
20889
+ if (pendingSpan + mdSpan > 12) {
20890
+ flush();
20891
+ }
20892
+ pending.push(column);
20893
+ pendingSpan += mdSpan;
20894
+ }
20895
+ flush();
20896
+ return rows;
20897
+ }
20898
+ function resolveCommandSpan(field) {
20899
+ const rawWidth = field.width;
20900
+ const numericWidth = typeof rawWidth === 'number'
20901
+ ? rawWidth
20902
+ : typeof rawWidth === 'string' && /^\d+$/.test(rawWidth.trim())
20903
+ ? Number(rawWidth.trim())
20904
+ : null;
20905
+ if (numericWidth != null && Number.isFinite(numericWidth)) {
20906
+ const span = Math.max(1, Math.min(12, Math.round(numericWidth)));
20907
+ return {
20908
+ xs: 12,
20909
+ sm: span >= 6 ? 12 : 6,
20910
+ md: span,
20911
+ lg: span,
20912
+ xl: span,
20913
+ };
20914
+ }
20915
+ const width = String(rawWidth || '').toLowerCase();
20916
+ const controlType = String(field.controlType || field.type || '').toLowerCase();
20917
+ if (width === 'full' ||
20918
+ width === 'xl' ||
20919
+ controlType.includes('textarea') ||
20920
+ controlType.includes('rich') ||
20921
+ controlType.includes('file') ||
20922
+ controlType.includes('autocomplete') ||
20923
+ controlType.includes('lookup')) {
20924
+ return { xs: 12, sm: 12, md: 12, lg: 12, xl: 12 };
20925
+ }
20926
+ if (width === 'lg')
20927
+ return { xs: 12, sm: 12, md: 8, lg: 8, xl: 8 };
20928
+ if (width === 'md')
20929
+ return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
20930
+ if (width === 'sm')
20931
+ return { xs: 12, sm: 6, md: 4, lg: 4, xl: 4 };
20932
+ if (width === 'xs' || controlType.includes('checkbox') || controlType.includes('toggle')) {
20933
+ return { xs: 12, sm: 6, md: 3, lg: 3, xl: 3 };
20934
+ }
20935
+ return { xs: 12, sm: 12, md: 6, lg: 6, xl: 6 };
20936
+ }
20937
+ function hasExplicitWidth(field) {
20938
+ const rawWidth = field.width;
20939
+ return rawWidth !== undefined && rawWidth !== null && String(rawWidth).trim() !== '';
20940
+ }
20941
+ function fieldsForPolicy(fields, policy) {
20942
+ if (policy.preset !== 'compactPresentation') {
20943
+ return fields;
20944
+ }
20945
+ const presentationFieldNames = new Set(resolveDetailSummaryFields(fields, policy).map((field) => field.name));
20946
+ return fields.map((field) => ({
20947
+ ...field,
20948
+ readOnly: true,
20949
+ presentationMode: field.presentationMode ?? true,
20950
+ ...(presentationFieldNames.has(field.name)
20951
+ ? {}
20952
+ : { formHidden: true, hidden: true }),
20953
+ valuePresentation: {
20954
+ ...(field.valuePresentation || {}),
20955
+ density: (field.valuePresentation || {}).density ?? 'compact',
20956
+ },
20957
+ }));
20958
+ }
20959
+ function fieldsForLayoutPolicy(fields, policy) {
20960
+ if (policy.preset !== 'compactPresentation') {
20961
+ return fields;
20962
+ }
20963
+ return resolveDetailSummaryFields(fields, policy);
20964
+ }
20965
+ function resolvePresentationFields(fields) {
20966
+ return fields.filter((field) => !isFormHidden(field));
20967
+ }
20968
+ function resolveDetailSummaryFields(fields, policy) {
20969
+ if (policy.preset !== 'compactPresentation' || policy.intent === 'command') {
20970
+ return fields;
20971
+ }
20972
+ const summary = policy.detailSummary;
20973
+ if (!summary) {
20974
+ return fields;
20975
+ }
20976
+ const includeFields = normalizedSet(summary.includeFields);
20977
+ const excludeFields = normalizedSet(summary.excludeFields);
20978
+ const includeGroups = normalizedSet(summary.includeGroups);
20979
+ const excludeGroups = normalizedSet(summary.excludeGroups);
20980
+ const includeRoles = normalizedSet(summary.includeRoles);
20981
+ const excludeRoles = normalizedSet(summary.excludeRoles);
20982
+ const filtered = fields
20983
+ .filter((field) => {
20984
+ const fieldName = stableToken(field.name);
20985
+ const groupName = stableToken(normalizeGroupLabel(field.group));
20986
+ const roles = resolveFieldSummaryRoles(field);
20987
+ if (excludeFields.has(fieldName) || excludeGroups.has(groupName))
20988
+ return false;
20989
+ if (roles.some((role) => excludeRoles.has(role)))
20990
+ return false;
20991
+ if (includeFields.size && !includeFields.has(fieldName))
20992
+ return false;
20993
+ if (includeGroups.size && !includeGroups.has(groupName))
20994
+ return false;
20995
+ if (includeRoles.size && !roles.some((role) => includeRoles.has(role)))
20996
+ return false;
20997
+ return true;
20998
+ })
20999
+ .sort((left, right) => compareSummaryFields(left, right, summary));
21000
+ const maxFields = normalizePositiveInteger(summary.maxFields);
21001
+ return maxFields ? filtered.slice(0, maxFields) : filtered;
21002
+ }
21003
+ function compareSummaryFields(left, right, summary) {
21004
+ const leftPriority = resolveSummaryPriority(left, summary);
21005
+ const rightPriority = resolveSummaryPriority(right, summary);
21006
+ if (leftPriority !== rightPriority)
21007
+ return leftPriority - rightPriority;
21008
+ return compareFields(left, right);
21009
+ }
21010
+ function resolveSummaryPriority(field, summary) {
21011
+ const fieldName = stableToken(field.name);
21012
+ const groupName = stableToken(normalizeGroupLabel(field.group));
21013
+ const explicitFieldPriority = numberOrNull(summary.fieldPriority?.[field.name] ?? summary.fieldPriority?.[fieldName]);
21014
+ if (explicitFieldPriority !== null)
21015
+ return explicitFieldPriority;
21016
+ const explicitGroupPriority = numberOrNull(summary.groupPriority?.[String(field.group || '')] ?? summary.groupPriority?.[groupName]);
21017
+ if (explicitGroupPriority !== null)
21018
+ return explicitGroupPriority;
21019
+ const fieldPriority = numberOrNull(field.summaryPriority ??
21020
+ field.detailPriority ??
21021
+ field.presentationPriority);
21022
+ if (fieldPriority !== null)
21023
+ return fieldPriority;
21024
+ return typeof field.order === 'number' ? field.order : Number.MAX_SAFE_INTEGER;
21025
+ }
21026
+ function resolveFieldSummaryRoles(field) {
21027
+ const raw = [
21028
+ field.summaryRole,
21029
+ field.detailRole,
21030
+ field.presentationRole,
21031
+ field.presentation?.role,
21032
+ field.valuePresentation?.role,
21033
+ ];
21034
+ const roles = [];
21035
+ for (const item of raw) {
21036
+ if (Array.isArray(item)) {
21037
+ roles.push(...item.map((value) => stableToken(String(value))).filter(Boolean));
21038
+ }
21039
+ else {
21040
+ const token = stableToken(String(item || ''));
21041
+ if (token)
21042
+ roles.push(token);
21043
+ }
21044
+ }
21045
+ return [...new Set(roles)];
21046
+ }
21047
+ function normalizedSet(values) {
21048
+ return new Set((values || []).map((value) => stableToken(value)).filter(Boolean));
21049
+ }
21050
+ function normalizePositiveInteger(value) {
21051
+ const numberValue = numberOrNull(value);
21052
+ if (numberValue === null || numberValue <= 0) {
21053
+ return null;
21054
+ }
21055
+ return Math.floor(numberValue);
21056
+ }
21057
+ function numberOrNull(value) {
21058
+ if (typeof value === 'number' && Number.isFinite(value)) {
21059
+ return value;
21060
+ }
21061
+ if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) {
21062
+ return Number(value);
21063
+ }
21064
+ return null;
21065
+ }
21066
+ function compareGroupFields(left, right) {
21067
+ return compareFields(left[0], right[0]);
21068
+ }
21069
+ function compareFields(left, right) {
21070
+ const leftOrder = typeof left?.order === 'number' ? left.order : Number.MAX_SAFE_INTEGER;
21071
+ const rightOrder = typeof right?.order === 'number' ? right.order : Number.MAX_SAFE_INTEGER;
21072
+ if (leftOrder !== rightOrder)
21073
+ return leftOrder - rightOrder;
21074
+ return String(left?.name || '').localeCompare(String(right?.name || ''));
21075
+ }
21076
+ function normalizeGroupLabel(group) {
21077
+ const value = String(group || '').trim();
21078
+ return value || 'default';
21079
+ }
21080
+ function resolvePresentationRole(groupName, fields, map) {
21081
+ const direct = map?.[groupName];
21082
+ if (direct)
21083
+ return direct;
21084
+ const normalized = stableToken(groupName);
21085
+ if (normalized.includes('ident'))
21086
+ return 'identity';
21087
+ if (normalized.includes('marc') || normalized.includes('status'))
21088
+ return 'markers';
21089
+ if (normalized.includes('regra') || normalized.includes('rule'))
21090
+ return 'rules';
21091
+ if (fields.some((field) => String(field.controlType || '').toLowerCase().includes('checkbox'))) {
21092
+ return 'markers';
21093
+ }
21094
+ return 'default';
21095
+ }
21096
+ function resolvePresentationSectionIcon(role) {
21097
+ switch (role) {
21098
+ case 'identity':
21099
+ return 'badge';
21100
+ case 'rules':
21101
+ return 'rule';
21102
+ case 'markers':
21103
+ return 'fact_check';
21104
+ default:
21105
+ return 'info';
21106
+ }
21107
+ }
21108
+ function stableSectionId(groupName) {
21109
+ const token = stableToken(groupName) || 'default';
21110
+ return `section-${token}`;
21111
+ }
21112
+ function stableToken(value) {
21113
+ return String(value || '')
21114
+ .normalize('NFD')
21115
+ .replace(/[\u0300-\u036f]/g, '')
21116
+ .toLowerCase()
21117
+ .replace(/[^a-z0-9]+/g, '-')
21118
+ .replace(/^-+|-+$/g, '');
21119
+ }
21120
+
19569
21121
  function resolveSpan(span) {
19570
21122
  const xs = clamp(span?.xs ?? 12, 'xs');
19571
21123
  const sm = clamp(span?.sm ?? xs, 'sm');
@@ -20346,7 +21898,7 @@ class SurfaceOpenActionEditorComponent {
20346
21898
  .filter(Boolean)));
20347
21899
  }
20348
21900
  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: `
21901
+ 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
21902
  <div class="surface-editor">
20351
21903
  <div class="surface-section">
20352
21904
  <div class="surface-section-title">{{ t('editor.presets.title', 'Presets') }}</div>
@@ -20643,17 +22195,17 @@ class SurfaceOpenActionEditorComponent {
20643
22195
  {{ t('editor.bindings.empty', 'No bindings configured yet.') }}
20644
22196
  </div>
20645
22197
  }
20646
- <div class="surface-empty">
22198
+ <div class="surface-guidance">
20647
22199
  @if (bindingSourceSuggestionsPreview) {
20648
- <div>
22200
+ <div class="surface-guidance__item">
20649
22201
  {{ t('editor.bindings.suggestedSources', 'Suggested sources: {{value}}', { value: bindingSourceSuggestionsPreview }) }}
20650
22202
  </div>
20651
22203
  }
20652
- <div>
22204
+ <div class="surface-guidance__item surface-guidance__item--primary">
20653
22205
  {{ t('editor.bindings.sourceSemantics', 'Use payload.* for the canonical event envelope and runtime.* for direct host state when the source component exposes it.') }}
20654
22206
  </div>
20655
22207
  @if (bindingTargetSuggestionsPreview) {
20656
- <div>
22208
+ <div class="surface-guidance__item">
20657
22209
  {{ t('editor.bindings.suggestedTargets', 'Suggested targets: {{value}}', { value: bindingTargetSuggestionsPreview }) }}
20658
22210
  </div>
20659
22211
  }
@@ -20689,11 +22241,11 @@ class SurfaceOpenActionEditorComponent {
20689
22241
  </mat-form-field>
20690
22242
  </div>
20691
22243
  </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"] }] });
22244
+ `, 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
22245
  }
20694
22246
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SurfaceOpenActionEditorComponent, decorators: [{
20695
22247
  type: Component,
20696
- args: [{ selector: 'praxis-surface-open-action-editor', standalone: true, providers: [providePraxisI18nConfig(SURFACE_OPEN_I18N_CONFIG)], imports: [
22248
+ 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
22249
  FormsModule,
20698
22250
  MatButtonModule,
20699
22251
  MatFormFieldModule,
@@ -20999,17 +22551,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20999
22551
  {{ t('editor.bindings.empty', 'No bindings configured yet.') }}
21000
22552
  </div>
21001
22553
  }
21002
- <div class="surface-empty">
22554
+ <div class="surface-guidance">
21003
22555
  @if (bindingSourceSuggestionsPreview) {
21004
- <div>
22556
+ <div class="surface-guidance__item">
21005
22557
  {{ t('editor.bindings.suggestedSources', 'Suggested sources: {{value}}', { value: bindingSourceSuggestionsPreview }) }}
21006
22558
  </div>
21007
22559
  }
21008
- <div>
22560
+ <div class="surface-guidance__item surface-guidance__item--primary">
21009
22561
  {{ t('editor.bindings.sourceSemantics', 'Use payload.* for the canonical event envelope and runtime.* for direct host state when the source component exposes it.') }}
21010
22562
  </div>
21011
22563
  @if (bindingTargetSuggestionsPreview) {
21012
- <div>
22564
+ <div class="surface-guidance__item">
21013
22565
  {{ t('editor.bindings.suggestedTargets', 'Suggested targets: {{value}}', { value: bindingTargetSuggestionsPreview }) }}
21014
22566
  </div>
21015
22567
  }
@@ -21045,7 +22597,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21045
22597
  </mat-form-field>
21046
22598
  </div>
21047
22599
  </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"] }]
22600
+ `, 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
22601
  }], propDecorators: { value: [{
21050
22602
  type: Input
21051
22603
  }], hostKind: [{
@@ -21072,6 +22624,12 @@ const ENUMS$1 = {
21072
22624
  textTransformApply: ['displayOnly', 'saveOnly', 'both'],
21073
22625
  fieldSource: ['schema', 'local'],
21074
22626
  fieldSubmitPolicy: ['include', 'omit', 'includeWhenDirty'],
22627
+ fieldPresentationTone: ['neutral', 'info', 'success', 'warning', 'danger'],
22628
+ fieldPresentationAppearance: ['plain', 'soft', 'outlined', 'filled'],
22629
+ fieldPresenterKind: ['text', 'badge', 'chip', 'status', 'iconValue', 'progress', 'rating', 'microVisualization'],
22630
+ presentationVisualizationKind: ['line', 'area', 'column', 'comparison', 'stackedBar', 'radial', 'harveyBall', 'bullet', 'delta', 'processFlow'],
22631
+ presentationVisualizationSurface: ['table-cell', 'list-item', 'object-header', 'card-summary', 'form-presentation'],
22632
+ presentationVisualizationSize: ['xs', 'sm', 'md', 'lg', 'responsive'],
21075
22633
  visibleIn: ['form', 'filter', 'table', 'dialog'],
21076
22634
  appearance: ['fill', 'outline'],
21077
22635
  color: ['primary', 'accent', 'warn'],
@@ -21082,7 +22640,7 @@ const ENUMS$1 = {
21082
22640
  sectionDescriptionStyle: ['bodyLarge', 'bodyMedium', 'bodySmall'],
21083
22641
  };
21084
22642
  const FIELD_METADATA_CAPABILITIES = {
21085
- version: 'v1.4',
22643
+ version: 'v1.5',
21086
22644
  enums: ENUMS$1,
21087
22645
  notes: [
21088
22646
  '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 +22649,11 @@ const FIELD_METADATA_CAPABILITIES = {
21091
22649
  'Detalhes específicos de cada controle (ex: opções de datepicker, máscaras específicas) devem ser consultados nos catálogos de microcomponentes.',
21092
22650
  'POLICY: Arrays e objetos (ex: options, validators) devem sofrer merge/append, nunca substituição completa sem confirmação.',
21093
22651
  '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.',
22652
+ '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
22653
  'POLICY: formSubmit.formData e o payload filtrado para backend; formSubmit.rawFormData preserva os valores completos da UI, incluindo campos locais/transient.',
22654
+ 'POLICY: fieldAccess e metadata-driven UX; nao trate como seguranca frontend. Use somente authorities explicitas, nunca capabilities como sinonimo implicito.',
22655
+ 'POLICY: presentation/presentationRules descrevem somente estado visual semantico em modo leitura. Nao gere CSS, HTML, comandos ou mutacoes por Json Logic.',
22656
+ 'POLICY: presentation.visualization e renderer-neutral. Nao gere EChartsOption, SVG, HTML ou CSS; use kind/surface/size/fallbackText e dados semanticos.',
21096
22657
  ],
21097
22658
  capabilities: [
21098
22659
  // =============================================================================
@@ -21194,6 +22755,13 @@ const FIELD_METADATA_CAPABILITIES = {
21194
22755
  description: 'Texto de ajuda exibido abaixo do campo.',
21195
22756
  intentExamples: ['colocar dica', 'ajuda no rodapé do campo'],
21196
22757
  },
22758
+ {
22759
+ path: 'helpText',
22760
+ category: 'identity',
22761
+ valueKind: 'string',
22762
+ description: 'Texto semântico de ajuda publicado pelo schema/DTO.',
22763
+ intentExamples: ['explicar regra de negócio do campo', 'ajuda vinda do backend'],
22764
+ },
21197
22765
  {
21198
22766
  path: 'tooltip',
21199
22767
  category: 'identity',
@@ -21201,6 +22769,13 @@ const FIELD_METADATA_CAPABILITIES = {
21201
22769
  description: 'Texto exibido ao passar o mouse.',
21202
22770
  intentExamples: ['adicionar tooltip'],
21203
22771
  },
22772
+ {
22773
+ path: 'tooltipOnHover',
22774
+ category: 'identity',
22775
+ valueKind: 'boolean',
22776
+ description: 'Habilita apresentação do tooltip no hover quando suportado pelo renderer.',
22777
+ intentExamples: ['mostrar tooltip ao passar o mouse', 'ativar dica no hover'],
22778
+ },
21204
22779
  {
21205
22780
  path: 'description',
21206
22781
  category: 'identity',
@@ -21292,24 +22867,24 @@ const FIELD_METADATA_CAPABILITIES = {
21292
22867
  category: 'data',
21293
22868
  valueKind: 'enum',
21294
22869
  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.',
22870
+ description: 'Origem semântica do campo. Use local para campos do host que não vêm do schema backend.',
22871
+ intentExamples: ['campo local', 'campo auxiliar do host', 'campo que não vem do schema'],
22872
+ 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
22873
  },
21299
22874
  {
21300
22875
  path: 'transient',
21301
22876
  category: 'data',
21302
22877
  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.',
22878
+ description: 'Marca o campo como temporário/local para preenchimento. O dynamic-form omite do submit por padrão.',
22879
+ intentExamples: ['campo temporário', 'campo transient', 'não enviar no payload', 'usar apenas na UI'],
22880
+ safetyNotes: 'Campos transient continuam participando de UI, validação, regras, visibilidade e valueChange; eles apenas saem do payload persistido por padrão.',
21306
22881
  },
21307
22882
  {
21308
22883
  path: 'submitPolicy',
21309
22884
  category: 'behavior',
21310
22885
  valueKind: 'enum',
21311
22886
  allowedValues: ENUMS$1.fieldSubmitPolicy,
21312
- description: 'Politica de submit para sobrescrever o padrao de campos locais/transient.',
22887
+ description: 'Política de submit para sobrescrever o padrão de campos locais/transient.',
21313
22888
  intentExamples: ['omitir do submit', 'enviar mesmo sendo local', 'enviar apenas se alterado'],
21314
22889
  safetyNotes: 'Use omit para nunca persistir, include para enviar sempre e includeWhenDirty apenas quando o controle estiver dirty.',
21315
22890
  },
@@ -21412,6 +22987,166 @@ const FIELD_METADATA_CAPABILITIES = {
21412
22987
  description: 'Tamanho do ícone.',
21413
22988
  intentExamples: ['ícone pequeno', 'aumentar tamanho do ícone', 'ícone grande'],
21414
22989
  },
22990
+ {
22991
+ path: 'iconColor',
22992
+ category: 'appearance',
22993
+ valueKind: 'string',
22994
+ description: 'Cor semântica ou token de cor aplicado ao ícone principal.',
22995
+ intentExamples: ['ícone em cor primária', 'usar token do tema no ícone'],
22996
+ },
22997
+ {
22998
+ path: 'iconClass',
22999
+ category: 'appearance',
23000
+ valueKind: 'string',
23001
+ description: 'Classe CSS controlada pelo host para o ícone principal.',
23002
+ intentExamples: ['usar classe de ícone outlined', 'aplicar classe corporativa'],
23003
+ },
23004
+ {
23005
+ path: 'iconStyle',
23006
+ category: 'appearance',
23007
+ valueKind: 'string',
23008
+ description: 'Estilo visual semântico do ícone quando o renderer suportar variações.',
23009
+ intentExamples: ['usar ícone arredondado', 'aplicar estilo filled'],
23010
+ },
23011
+ {
23012
+ path: 'iconFontSize',
23013
+ category: 'appearance',
23014
+ valueKind: 'string',
23015
+ description: 'Tamanho tipográfico do ícone principal.',
23016
+ intentExamples: ['ícone com 18px', 'ajustar tamanho do ícone'],
23017
+ },
23018
+ // =============================================================================
23019
+ // PRESENTATION MODE
23020
+ // =============================================================================
23021
+ {
23022
+ path: 'valuePresentation',
23023
+ category: 'appearance',
23024
+ valueKind: 'object',
23025
+ description: 'Formato canonico de exibicao em superficies readonly/display, como moeda, numero, percentual, data, datetime, time e boolean.',
23026
+ safetyNotes: 'Preferir este contrato a formatadores legados quando a intencao for apresentacao de valor.',
23027
+ intentExamples: ['mostrar como moeda', 'formatar como data longa', 'exibir percentual'],
23028
+ },
23029
+ {
23030
+ path: 'presentation',
23031
+ category: 'appearance',
23032
+ valueKind: 'object',
23033
+ description: 'Estado visual semantico base para presentationMode, incluindo presenter, tone, icon, label, badge, tooltip, appearance e formatter opcional.',
23034
+ safetyNotes: 'Use apenas semantica declarativa; nao incluir CSS arbitrario, HTML, comandos ou efeitos mutaveis.',
23035
+ intentExamples: ['status com icone', 'badge de pendente', 'campo em tom warning'],
23036
+ },
23037
+ {
23038
+ path: 'presentation.presenter',
23039
+ category: 'appearance',
23040
+ valueKind: 'enum',
23041
+ allowedValues: ENUMS$1.fieldPresenterKind,
23042
+ description: 'Tipo semantico de renderizacao em modo apresentacao.',
23043
+ intentExamples: ['renderizar como status', 'usar chip', 'mostrar icone com valor'],
23044
+ },
23045
+ {
23046
+ path: 'presentation.tone',
23047
+ category: 'appearance',
23048
+ valueKind: 'enum',
23049
+ allowedValues: ENUMS$1.fieldPresentationTone,
23050
+ description: 'Tom semantico mapeado pelo consumidor para tokens de tema.',
23051
+ intentExamples: ['tom de sucesso', 'tom de alerta', 'tom de erro'],
23052
+ },
23053
+ {
23054
+ path: 'presentation.appearance',
23055
+ category: 'appearance',
23056
+ valueKind: 'enum',
23057
+ allowedValues: ENUMS$1.fieldPresentationAppearance,
23058
+ description: 'Nivel de enfase visual do apresentador.',
23059
+ intentExamples: ['status preenchido', 'badge contornado', 'chip suave'],
23060
+ },
23061
+ {
23062
+ path: 'presentation.icon',
23063
+ category: 'appearance',
23064
+ valueKind: 'string',
23065
+ description: 'Nome de icone Material Symbols usado pelo apresentador semantico.',
23066
+ intentExamples: ['icone lock', 'icone payments', 'icone schedule'],
23067
+ },
23068
+ {
23069
+ path: 'presentation.label',
23070
+ category: 'identity',
23071
+ valueKind: 'string',
23072
+ description: 'Rotulo semantico exibido por apresentadores como status, badge ou chip.',
23073
+ intentExamples: ['rotulo Bloqueado', 'texto Aprovado', 'status Aguardando aprovacao'],
23074
+ },
23075
+ {
23076
+ path: 'presentation.badge',
23077
+ category: 'appearance',
23078
+ valueKind: 'string',
23079
+ description: 'Marcador secundario opcional exibido junto ao valor em superficies de apresentacao.',
23080
+ intentExamples: ['badge alto valor', 'marcador D+35', 'sinalizar revisao executiva'],
23081
+ },
23082
+ {
23083
+ path: 'presentation.valuePresentation',
23084
+ category: 'appearance',
23085
+ valueKind: 'object',
23086
+ description: 'Override de formatacao aplicado apenas pela superficie de apresentacao.',
23087
+ safetyNotes: 'Nao altera o valor real do FormControl nem o payload de submit.',
23088
+ },
23089
+ {
23090
+ path: 'presentation.visualization',
23091
+ category: 'appearance',
23092
+ valueKind: 'object',
23093
+ description: 'Micro visualizacao renderer-neutral para superficies compactas como tabela, lista, header, card e form read-only.',
23094
+ safetyNotes: 'Exige fallback textual e nao pode conter opcoes de ECharts, HTML, SVG bruto, CSS ou comandos.',
23095
+ intentExamples: ['micro chart de SLA', 'barra empilhada em celula', 'bullet chart de orcamento', 'fluxo compacto de aprovacao'],
23096
+ },
23097
+ {
23098
+ path: 'presentation.visualization.kind',
23099
+ category: 'appearance',
23100
+ valueKind: 'enum',
23101
+ allowedValues: ENUMS$1.presentationVisualizationKind,
23102
+ description: 'Tipo semantico da micro visualizacao de apresentacao.',
23103
+ intentExamples: ['comparison', 'stackedBar', 'bullet', 'processFlow'],
23104
+ },
23105
+ {
23106
+ path: 'presentation.visualization.surface',
23107
+ category: 'layout',
23108
+ valueKind: 'enum',
23109
+ allowedValues: ENUMS$1.presentationVisualizationSurface,
23110
+ description: 'Superficie alvo usada para aplicar regras de densidade e fallback.',
23111
+ intentExamples: ['table-cell', 'list-item', 'form-presentation'],
23112
+ },
23113
+ {
23114
+ path: 'presentation.visualization.size',
23115
+ category: 'layout',
23116
+ valueKind: 'enum',
23117
+ allowedValues: ENUMS$1.presentationVisualizationSize,
23118
+ description: 'Tamanho semantico da micro visualizacao.',
23119
+ intentExamples: ['xs em tabela', 'md em header', 'responsive em card'],
23120
+ },
23121
+ {
23122
+ path: 'presentation.visualization.fallbackText',
23123
+ category: 'accessibility',
23124
+ valueKind: 'string',
23125
+ description: 'Texto equivalente obrigatorio para fallback, exportacao e leitores de tela.',
23126
+ safetyNotes: 'Deve explicar valor, unidade, meta, tendencia ou estado quando aplicavel.',
23127
+ },
23128
+ {
23129
+ path: 'presentationRules',
23130
+ category: 'appearance',
23131
+ valueKind: 'array',
23132
+ description: 'Regras Json Logic ordenadas que sobrescrevem presentation em modo readonly/display; regras posteriores que casam vencem.',
23133
+ safetyNotes: 'As regras devem produzir apenas set/effect semantico. Nao use para alterar valor, executar acao, navegar ou injetar HTML/CSS.',
23134
+ intentExamples: ['se status for BLOQUEADO, usar tone danger', 'se valor maior que limite, mostrar badge de revisao'],
23135
+ },
23136
+ {
23137
+ path: 'presentationRules[].when',
23138
+ category: 'behavior',
23139
+ valueKind: 'object',
23140
+ description: 'Guarda Json Logic avaliada contra o contexto de apresentacao do campo.',
23141
+ safetyNotes: 'Use Json Logic serializavel; funcoes nao sao aceitas.',
23142
+ },
23143
+ {
23144
+ path: 'presentationRules[].set',
23145
+ category: 'appearance',
23146
+ valueKind: 'object',
23147
+ description: 'Patch semantico aplicado sobre presentation quando a guarda for verdadeira.',
23148
+ safetyNotes: 'Somente presenter, tone, icon, label, badge, tooltip, appearance, valuePresentation e interactions seguras.',
23149
+ },
21415
23150
  // =============================================================================
21416
23151
  // MASK / FORMAT
21417
23152
  // =============================================================================
@@ -21451,8 +23186,8 @@ const FIELD_METADATA_CAPABILITIES = {
21451
23186
  path: 'required',
21452
23187
  category: 'validation',
21453
23188
  valueKind: 'boolean',
21454
- description: 'Campo obrigatorio (alias rapido do validators.required).',
21455
- intentExamples: ['campo obrigatorio', 'exigir preenchimento'],
23189
+ description: 'Campo obrigatório (alias rápido do validators.required).',
23190
+ intentExamples: ['campo obrigatório', 'exigir preenchimento'],
21456
23191
  },
21457
23192
  {
21458
23193
  path: 'validators.requiredMessage',
@@ -21471,7 +23206,7 @@ const FIELD_METADATA_CAPABILITIES = {
21471
23206
  path: 'validators.emailMessage',
21472
23207
  category: 'validation',
21473
23208
  valueKind: 'string',
21474
- description: 'Mensagem customizada para validacao de email.',
23209
+ description: 'Mensagem customizada para validação de email.',
21475
23210
  },
21476
23211
  {
21477
23212
  path: 'validators.minLength',
@@ -21611,15 +23346,15 @@ const FIELD_METADATA_CAPABILITIES = {
21611
23346
  path: 'validators.customValidator',
21612
23347
  category: 'validation',
21613
23348
  valueKind: 'expression',
21614
- description: 'Validador customizado (funcao).',
21615
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23349
+ description: 'Validador customizado (função).',
23350
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21616
23351
  },
21617
23352
  {
21618
23353
  path: 'validators.asyncValidator',
21619
23354
  category: 'validation',
21620
23355
  valueKind: 'expression',
21621
- description: 'Validador async customizado (funcao).',
21622
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23356
+ description: 'Validador async customizado (função).',
23357
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21623
23358
  },
21624
23359
  {
21625
23360
  path: 'validators.matchField',
@@ -21637,8 +23372,8 @@ const FIELD_METADATA_CAPABILITIES = {
21637
23372
  path: 'validators.uniqueValidator',
21638
23373
  category: 'validation',
21639
23374
  valueKind: 'expression',
21640
- description: 'Validador de unicidade via API (funcao).',
21641
- safetyNotes: 'Funcoes nao sao serializaveis; exige wiring manual.',
23375
+ description: 'Validador de unicidade via API (função).',
23376
+ safetyNotes: 'Funções não são serializáveis; exige wiring manual.',
21642
23377
  },
21643
23378
  {
21644
23379
  path: 'validators.uniqueMessage',
@@ -21650,8 +23385,8 @@ const FIELD_METADATA_CAPABILITIES = {
21650
23385
  path: 'validators.conditionalValidation',
21651
23386
  category: 'validation',
21652
23387
  valueKind: 'array',
21653
- description: 'Regras de validacao condicional.',
21654
- safetyNotes: 'Use regras declarativas com Json Logic serializavel; nao gere funcoes aqui.',
23388
+ description: 'Regras de validação condicional.',
23389
+ safetyNotes: 'Use regras declarativas com Json Logic serializável; não gere funções aqui.',
21655
23390
  },
21656
23391
  {
21657
23392
  path: 'validators.conditionalValidation[].condition',
@@ -21671,13 +23406,13 @@ const FIELD_METADATA_CAPABILITIES = {
21671
23406
  category: 'validation',
21672
23407
  valueKind: 'enum',
21673
23408
  allowedValues: ENUMS$1.validatorTrigger,
21674
- description: 'Gatilho de validacao no validator.',
23409
+ description: 'Gatilho de validação no validator.',
21675
23410
  },
21676
23411
  {
21677
23412
  path: 'validators.validationDebounce',
21678
23413
  category: 'validation',
21679
23414
  valueKind: 'number',
21680
- description: 'Debounce de validacao no validator (ms).',
23415
+ description: 'Debounce de validação no validator (ms).',
21681
23416
  },
21682
23417
  {
21683
23418
  path: 'validators.showInlineErrors',
@@ -21800,6 +23535,35 @@ const FIELD_METADATA_CAPABILITIES = {
21800
23535
  description: 'Oculta apenas no filtro.',
21801
23536
  intentExamples: ['esconder na busca', 'remover do filtro'],
21802
23537
  },
23538
+ {
23539
+ path: 'fieldAccess',
23540
+ category: 'behavior',
23541
+ valueKind: 'object',
23542
+ description: 'Politica canonica de UX para visibilidade/edicao por authorities publicadas pelo backend.',
23543
+ safetyNotes: 'Nao e barreira de seguranca. O backend continua responsavel por filtrar dados sensiveis e validar payloads.',
23544
+ intentExamples: ['campo visivel somente para RH', 'bloquear edicao por perfil corporativo'],
23545
+ },
23546
+ {
23547
+ path: 'fieldAccess.visibleForAuthorities',
23548
+ category: 'behavior',
23549
+ valueKind: 'array',
23550
+ description: 'Authorities que podem ver o campo no runtime quando a UX tiver claims explicitas.',
23551
+ safetyNotes: 'Nao inferir a partir de capabilities sem mapeamento canonico publicado.',
23552
+ },
23553
+ {
23554
+ path: 'fieldAccess.editableForAuthorities',
23555
+ category: 'behavior',
23556
+ valueKind: 'array',
23557
+ description: 'Authorities que podem editar o campo no runtime quando a UX tiver claims explicitas.',
23558
+ safetyNotes: 'Edicao concedida implica materializacao visivel no runtime; a validacao final permanece no backend.',
23559
+ },
23560
+ {
23561
+ path: 'fieldAccess.reason',
23562
+ category: 'misc',
23563
+ valueKind: 'string',
23564
+ description: 'Justificativa explicativa/auditavel da politica de acesso do campo.',
23565
+ safetyNotes: 'Reason sozinho nao deve decidir acesso nem revelar detalhes sensiveis para usuarios sem permissao.',
23566
+ },
21803
23567
  // =============================================================================
21804
23568
  // DEPENDENCIES
21805
23569
  // =============================================================================
@@ -22004,12 +23768,12 @@ const ENUMS = {
22004
23768
  actionPlacement: ['header', 'window'],
22005
23769
  };
22006
23770
  const CAPS = [
22007
- { path: 'page', category: 'page', valueKind: 'object', description: 'Definicao da pagina dinamica.' },
23771
+ { path: 'page', category: 'page', valueKind: 'object', description: 'Definição da página dinâmica.' },
22008
23772
  { 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.' },
23773
+ { path: 'page.layoutPreset', category: 'layout', valueKind: 'string', description: 'ID canônico opcional do preset estrutural da página.' },
23774
+ { path: 'page.layoutPresetOptions', category: 'layout', valueKind: 'object', description: 'Opções específicas do preset estrutural consumidas por builders e runtimes futuros.' },
23775
+ { path: 'page.themePreset', category: 'appearance', valueKind: 'string', description: 'ID opcional do preset de tema para shell, gráficos, densidade e defaults visuais.' },
23776
+ { path: 'page.layout', category: 'layout', valueKind: 'object', description: 'Layout base da página.' },
22013
23777
  { path: 'page.layout.orientation', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.layoutOrientation, description: 'Orientacao do grid (vertical/columns).' },
22014
23778
  { path: 'page.layout.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas (quando orientation=columns).' },
22015
23779
  { path: 'page.layout.gap', category: 'layout', valueKind: 'string', description: 'Gap entre widgets (ex: 16px).' },
@@ -22018,7 +23782,7 @@ const CAPS = [
22018
23782
  { path: 'page.layout.breakpoints.md', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint md.' },
22019
23783
  { path: 'page.layout.breakpoints.lg', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint lg.' },
22020
23784
  { 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.' },
23785
+ { path: 'page.canvas', category: 'layout', valueKind: 'object', description: 'Canvas espacial canônico da página quando houver geometria explícita.' },
22022
23786
  { path: 'page.canvas.mode', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.canvasMode, description: 'Modo canonico do canvas. Valor atual: grid.' },
22023
23787
  { path: 'page.canvas.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas do canvas espacial.' },
22024
23788
  { path: 'page.canvas.rowUnit', category: 'layout', valueKind: 'string', description: 'Altura base das linhas do canvas, como 80px.' },
@@ -22032,10 +23796,10 @@ const CAPS = [
22032
23796
  { path: 'page.canvas.items.<widgetKey>.rowSpan', category: 'layout', valueKind: 'number', description: 'Quantidade de linhas ocupadas pelo widget.' },
22033
23797
  { path: 'page.canvas.items.<widgetKey>.zIndex', category: 'layout', valueKind: 'number', description: 'Camada opcional do item no canvas.' },
22034
23798
  { 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.' },
23799
+ { path: 'page.canvas.items.<widgetKey>.constraints.minColSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de colunas permitido.' },
23800
+ { path: 'page.canvas.items.<widgetKey>.constraints.minRowSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de linhas permitido.' },
23801
+ { path: 'page.canvas.items.<widgetKey>.constraints.maxColSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de colunas permitido.' },
23802
+ { path: 'page.canvas.items.<widgetKey>.constraints.maxRowSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de linhas permitido.' },
22039
23803
  { path: 'page.canvas.items.<widgetKey>.constraints.lockPosition', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de posicao do item no canvas.' },
22040
23804
  { path: 'page.canvas.items.<widgetKey>.constraints.lockSize', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de tamanho do item no canvas.' },
22041
23805
  { path: 'page.widgets', category: 'widgets', valueKind: 'array', description: 'Lista de widgets renderizados.' },
@@ -22043,32 +23807,32 @@ const CAPS = [
22043
23807
  { path: 'page.widgets[].className', category: 'widgets', valueKind: 'string', description: 'Classe CSS opcional do widget.' },
22044
23808
  { path: 'page.widgets[].definition.id', category: 'widgets', valueKind: 'string', description: 'ID do componente do widget (ex: praxis-table).' },
22045
23809
  { 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.' },
23810
+ { 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.' },
23811
+ { 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.' },
23812
+ { 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.' },
23813
+ { 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
23814
  { 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.' },
23815
+ { path: 'page.widgets[].shell', category: 'shell', valueKind: 'object', description: 'Configuração do shell do widget.' },
22052
23816
  { 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.' },
23817
+ { path: 'page.widgets[].shell.title', category: 'shell', valueKind: 'string', description: 'Título do shell.' },
23818
+ { path: 'page.widgets[].shell.subtitle', category: 'shell', valueKind: 'string', description: 'Subtítulo do shell.' },
23819
+ { path: 'page.widgets[].shell.icon', category: 'shell', valueKind: 'string', description: 'Ícone do shell.' },
22056
23820
  { 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.' },
23821
+ { path: 'page.widgets[].shell.actions', category: 'shell', valueKind: 'array', description: 'Ações do shell.' },
23822
+ { path: 'page.widgets[].shell.actions[].id', category: 'shell', valueKind: 'string', description: 'ID da ação.' },
23823
+ { path: 'page.widgets[].shell.actions[].label', category: 'shell', valueKind: 'string', description: 'Label da ação.' },
23824
+ { path: 'page.widgets[].shell.actions[].icon', category: 'shell', valueKind: 'string', description: 'Ícone da ação.' },
23825
+ { path: 'page.widgets[].shell.actions[].variant', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionVariant, description: 'Estilo visual da ação.' },
23826
+ { path: 'page.widgets[].shell.actions[].placement', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionPlacement, description: 'Posicionamento da ação.' },
23827
+ { path: 'page.widgets[].shell.actions[].emit', category: 'shell', valueKind: 'string', description: 'Evento emitido ao acionar a ação.' },
22064
23828
  { path: 'page.state', category: 'state', valueKind: 'object', description: 'Estado declarativo opcional compartilhado por widgets e composicao.' },
22065
23829
  { path: 'page.state.values', category: 'state', valueKind: 'object', description: 'Valores primarios mutaveis escritos por widgets, defaults ou host.' },
22066
23830
  { path: 'page.state.schema', category: 'state', valueKind: 'object', description: 'Descritores dos paths primarios de estado.' },
22067
23831
  { path: 'page.state.schema.<token>.type', category: 'state', valueKind: 'string', description: 'Tipo semantico opcional do path de estado.' },
22068
23832
  { 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.' },
23833
+ { 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
23834
  { 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.' },
23835
+ { path: 'page.state.schema.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do path para builders e catálogos AI.' },
22072
23836
  { path: 'page.state.schema.<token>.tags', category: 'state', valueKind: 'array', description: 'Tags opcionais para busca e governanca do estado.' },
22073
23837
  { path: 'page.state.derived', category: 'state', valueKind: 'object', description: 'Descritores de estado derivado recomputado pelo runtime.' },
22074
23838
  { path: 'page.state.derived.<token>.dependsOn', category: 'state', valueKind: 'array', description: 'Paths de estado que alimentam o valor derivado.' },
@@ -22077,9 +23841,9 @@ const CAPS = [
22077
23841
  { path: 'page.state.derived.<token>.compute.expression', category: 'state', valueKind: 'expression', description: 'Expressao Json Logic para compute.kind=json-logic.' },
22078
23842
  { path: 'page.state.derived.<token>.compute.value', category: 'state', valueKind: 'object', description: 'Valor template para compute.kind=template.' },
22079
23843
  { 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.' },
23844
+ { path: 'page.state.derived.<token>.compute.options', category: 'state', valueKind: 'object', description: 'Opções do operador ou transformer.' },
22081
23845
  { 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.' },
23846
+ { path: 'page.state.derived.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do estado derivado.' },
22083
23847
  { path: 'page.state.derived.<token>.cache', category: 'state', valueKind: 'boolean', description: 'Permite cache futuro do valor derivado.' },
22084
23848
  { path: 'page.composition', category: 'connections', valueKind: 'object', description: 'Envelope canonico da composicao persistida.' },
22085
23849
  { path: 'page.composition.version', category: 'connections', valueKind: 'string', description: 'Versao do envelope de composicao.' },
@@ -22095,7 +23859,7 @@ const CAPS = [
22095
23859
  { path: 'page.composition.links[].from.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de origem.' },
22096
23860
  { path: 'page.composition.links[].from.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de origem.' },
22097
23861
  { 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.' },
23862
+ { 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
23863
  { path: 'page.composition.links[].from.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de origem.' },
22100
23864
  { path: 'page.composition.links[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino do link.' },
22101
23865
  { 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 +23874,11 @@ const CAPS = [
22110
23874
  { path: 'page.composition.links[].to.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de destino.' },
22111
23875
  { path: 'page.composition.links[].to.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de destino.' },
22112
23876
  { 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.' },
23877
+ { 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
23878
  { 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.' },
23879
+ { path: 'page.composition.links[].intent', category: 'connections', valueKind: 'string', description: 'Intenção semântica do link.' },
22116
23880
  { 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.' },
23881
+ { 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
23882
  { path: 'page.composition.links[].policy', category: 'connections', valueKind: 'object', description: 'Politicas operacionais opcionais do link, como debounce, distinct e missing-value.' },
22119
23883
  { path: 'page.composition.links[].metadata', category: 'connections', valueKind: 'object', description: 'Metadados opcionais do link.' },
22120
23884
  { path: 'page.grouping', category: 'layout', valueKind: 'array', description: 'Modelo semantico opcional de secoes, abas, areas hero e rails.' },
@@ -22155,15 +23919,15 @@ const DYNAMIC_PAGE_AI_CAPABILITIES = {
22155
23919
  enums: ENUMS,
22156
23920
  targets: ['praxis-dynamic-page'],
22157
23921
  notes: [
22158
- 'Este catalogo e especifico para o runtime praxis-dynamic-page; operacoes de authoring/mutacao pertencem ao manifesto do praxis-page-builder.',
23922
+ '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
23923
  'WidgetPageDefinition e o contrato canonico persistido: widgets, composition.links, state, context, layout, canvas, presets, grouping, slotAssignments, deviceLayouts e themePreset.',
22160
23924
  '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".',
23925
+ 'page.canvas.items é um mapa por widget key; não modele canvas.items como array.',
23926
+ 'Taxonomia editorial: condition usa Json Logic canônico; transform usa pipeline declarativo; não trate ambos como a mesma "expression".',
22163
23927
  'Para remocao/replace, use flags {_remove:true} ou {_replace:true} no item.',
22164
23928
  '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.',
23929
+ 'Inputs de widgets dependem do componente (ex: praxis-table, praxis-dynamic-form). Evite inventar campos; prefira pedir confirmação.',
23930
+ '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
23931
  'Use ids estaveis para links e keys estaveis para widgets.',
22168
23932
  'Nested component ports usam endpoint component-port com nestedPath; o owner em ref.widget continua sendo o widget top-level.',
22169
23933
  'Objetivo: compor widgets e relacionamentos canonicos (ex.: master-detail).',
@@ -22192,7 +23956,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22192
23956
  mode: 'enum',
22193
23957
  options: [
22194
23958
  { value: 'fixed', label: 'Linhas fixas' },
22195
- { value: 'content', label: 'Conteudo' },
23959
+ { value: 'content', label: 'Conteúdo' },
22196
23960
  ],
22197
23961
  },
22198
23962
  'page.canvas.collisionPolicy': {
@@ -22261,7 +24025,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22261
24025
  'page.widgets[].shell.actions[].variant': {
22262
24026
  mode: 'enum',
22263
24027
  options: [
22264
- { value: 'icon', label: 'Icone' },
24028
+ { value: 'icon', label: 'Ícone' },
22265
24029
  { value: 'text', label: 'Texto' },
22266
24030
  { value: 'outlined', label: 'Outlined' },
22267
24031
  ],
@@ -22291,7 +24055,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22291
24055
  mode: 'suggested',
22292
24056
  options: [
22293
24057
  { 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)' },
24058
+ { value: 'rowAction', label: 'Ação da linha (praxis-table)' },
22295
24059
  { value: 'formSubmit', label: 'Submit do formulario (praxis-dynamic-form)' },
22296
24060
  ],
22297
24061
  },
@@ -22305,7 +24069,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22305
24069
  'page.composition.links[].transform.steps[].config.path': {
22306
24070
  mode: 'suggested',
22307
24071
  options: [
22308
- { value: 'payload.row.id', label: 'ID padrao do registro', example: 'rowClick -> resourceId' },
24072
+ { value: 'payload.row.id', label: 'ID padrão do registro', example: 'rowClick -> resourceId' },
22309
24073
  ],
22310
24074
  },
22311
24075
  },
@@ -22617,7 +24381,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22617
24381
  { name: 'toInput', type: 'STRING' },
22618
24382
  { name: 'map', type: 'STRING' },
22619
24383
  ],
22620
- safetyNotes: 'Use transform pick-path payload.row.id para master-detail padrao.',
24384
+ safetyNotes: 'Use transform pick-path payload.row.id para master-detail padrão.',
22621
24385
  patchTemplate: {
22622
24386
  page: {
22623
24387
  composition: {
@@ -22668,7 +24432,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22668
24432
  { name: 'fromWidget', type: 'STRING' },
22669
24433
  { name: 'toWidget', type: 'STRING' },
22670
24434
  ],
22671
- safetyNotes: 'Padrao master-detail: rowClick -> resourceId com transform pick-path payload.row.id.',
24435
+ safetyNotes: 'Padrão master-detail: rowClick -> resourceId com transform pick-path payload.row.id.',
22672
24436
  patchTemplate: {
22673
24437
  page: {
22674
24438
  composition: {
@@ -22711,7 +24475,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22711
24475
  },
22712
24476
  {
22713
24477
  id: 'page.template.applyMasterDetail',
22714
- intentExamples: ['criar pagina master detail', 'setup master detail', 'tabela e formulario', 'master-detail'],
24478
+ intentExamples: ['criar página master detail', 'setup master detail', 'tabela e formulário', 'master-detail'],
22715
24479
  operation: 'create',
22716
24480
  scope: 'GLOBAL',
22717
24481
  valueType: 'OBJECT',
@@ -22720,7 +24484,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22720
24484
  { name: 'formId', type: 'STRING' },
22721
24485
  { name: 'resourcePath', type: 'STRING' },
22722
24486
  ],
22723
- safetyNotes: 'Padrao master-detail: tabela (rowClick) -> formulario (resourceId) com transform pick-path payload.row.id.',
24487
+ safetyNotes: 'Padrão master-detail: tabela (rowClick) -> formulario (resourceId) com transform pick-path payload.row.id.',
22724
24488
  patchTemplate: {
22725
24489
  page: {
22726
24490
  widgets: [
@@ -22796,30 +24560,30 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
22796
24560
  },
22797
24561
  hints: [
22798
24562
  '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.',
24563
+ 'Mutações agentic de página pertencem ao manifesto do praxis-page-builder; use este context pack como descoberta/runtime guidance.',
22800
24564
  '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.',
24565
+ 'page.canvas.items é um mapa por widget key, não um array; cada entrada guarda col, row, colSpan, rowSpan, zIndex e constraints opcionais.',
22802
24566
  '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.',
24567
+ 'Preferir mudanças incrementais: alterar/estender em vez de substituir toda a página.',
22804
24568
  'Para remover um item, envie {_remove: true} junto ao widget/link.',
22805
24569
  'Para substituir um item inteiro, envie {_replace: true}.',
22806
24570
  'Para alterar origem/destino de link, use {_beforeKey} com o id antigo.',
22807
24571
  'Use keys estaveis para widgets e ids estaveis para links ao criar composicoes.',
22808
24572
  '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.',
24573
+ 'Praxis Table gera colunas dinamicamente a partir do resourcePath quando columns não forem definidas.',
24574
+ 'Praxis Dynamic Form gera campos dinamicamente a partir do resourcePath quando config não for definida.',
24575
+ '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
24576
  'Praxis List pode filtrar via config.dataSource.query (enviado para /filter).',
22813
24577
  'Quando houver recursos secundarios (ex.: enderecos), use contextHints.addressResourcePath.',
22814
24578
  'Exemplo master-detail: tabela emite rowClick -> form.resourceId via transform pick-path payload.row.id.',
22815
24579
  '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
24580
  'Ao criar widgets, use inputs minimos e complemente depois (evite inventar campos).',
22817
24581
  '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.',
24582
+ 'Intenção comum: criar página master-detail = criar tabela + criar formulário + conectar seleção via composition.links.',
24583
+ 'Intenção comum: ajustar página existente = modificar apenas widgets/inputs necessários.',
22820
24584
  '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" }}}',
24585
+ 'Exemplo de widget tabela (mínimo): { key:"masterTable", definition:{ id:"praxis-table", inputs:{ resourcePath:"/api/x" }}}',
24586
+ 'Exemplo de widget formulário (mínimo): { key:"detailForm", definition:{ id:"praxis-dynamic-form", inputs:{ resourcePath:"/api/x", mode:"view" }}}',
22823
24587
  'Se houver idField conhecido, use transform pick-path payload.row.{idField} em links canonicos.',
22824
24588
  ],
22825
24589
  };
@@ -24945,9 +26709,21 @@ class DynamicWidgetLoaderDirective {
24945
26709
  const defaultOrderMap = {
24946
26710
  'praxis-table': ['tableId', 'componentInstanceId', 'configPersistenceStrategy', 'resourcePath', 'data', 'config'],
24947
26711
  'praxis-crud': ['crudId', 'componentInstanceId', 'metadata'],
24948
- 'praxis-dynamic-form': ['formId', 'componentInstanceId', 'resourcePath'],
26712
+ 'praxis-dynamic-form': [
26713
+ 'formId',
26714
+ 'componentInstanceId',
26715
+ 'resourcePath',
26716
+ 'schemaUrl',
26717
+ 'submitUrl',
26718
+ 'submitMethod',
26719
+ 'apiEndpointKey',
26720
+ 'apiUrlEntry',
26721
+ 'initialValue',
26722
+ 'mode',
26723
+ 'layoutPolicy',
26724
+ ],
24949
26725
  'praxis-tabs': ['tabsId', 'componentInstanceId', 'configPersistenceStrategy', 'config'],
24950
- 'praxis-list': ['listId', 'componentInstanceId', 'config'],
26726
+ 'praxis-list': ['listId', 'componentInstanceId', 'enableCustomization', 'config'],
24951
26727
  'praxis-expansion': ['expansionId', 'componentInstanceId', 'config'],
24952
26728
  'praxis-stepper': ['stepperId', 'componentInstanceId', 'config'],
24953
26729
  'praxis-files-upload': ['filesUploadId', 'componentInstanceId', 'config'],
@@ -25307,28 +27083,160 @@ const BUILTIN_SHELL_PRESETS = {
25307
27083
  },
25308
27084
  'light-neutral': {
25309
27085
  card: {
25310
- background: '#f8fafc',
25311
- borderColor: '#d7dfeb',
27086
+ background: 'var(--md-sys-color-surface)',
27087
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 82%, transparent)',
25312
27088
  borderRadius: '12px',
25313
- shadow: '0 4px 12px rgba(15, 23, 42, 0.06)',
27089
+ shadow: '0 4px 14px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
25314
27090
  },
25315
27091
  header: {
25316
- titleColor: '#1f2937',
25317
- subtitleColor: '#6b7280',
25318
- iconColor: '#0f172a',
27092
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 72%, transparent)',
27093
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 70%, transparent)',
27094
+ titleColor: 'var(--md-sys-color-on-surface)',
27095
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27096
+ iconColor: 'var(--md-sys-color-primary)',
27097
+ },
27098
+ body: {
27099
+ background: 'var(--md-sys-color-surface)',
27100
+ textColor: 'var(--md-sys-color-on-surface)',
25319
27101
  },
25320
27102
  },
25321
27103
  graphite: {
25322
27104
  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)',
27105
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 94%, var(--md-sys-color-surface-container-high) 6%)',
27106
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 74%, transparent)',
27107
+ borderRadius: '12px',
27108
+ shadow: '0 8px 22px color-mix(in srgb, var(--md-sys-color-shadow, #000) 11%, transparent)',
27109
+ },
27110
+ header: {
27111
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 76%, transparent)',
27112
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 62%, transparent)',
27113
+ titleColor: 'var(--md-sys-color-on-surface)',
27114
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27115
+ iconColor: 'var(--md-sys-color-primary)',
27116
+ },
27117
+ body: {
27118
+ background: 'var(--md-sys-color-surface)',
27119
+ textColor: 'var(--md-sys-color-on-surface)',
27120
+ },
27121
+ },
27122
+ frameless: {
27123
+ card: {
27124
+ background: 'transparent',
27125
+ borderColor: 'transparent',
27126
+ borderRadius: '0',
27127
+ shadow: 'none',
25327
27128
  },
25328
27129
  header: {
25329
- titleColor: '#f3f4f6',
25330
- subtitleColor: '#9ca3af',
25331
- iconColor: '#cbd5f5',
27130
+ background: 'transparent',
27131
+ borderColor: 'transparent',
27132
+ titleColor: 'var(--md-sys-color-on-surface)',
27133
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27134
+ iconColor: 'var(--md-sys-color-primary)',
27135
+ },
27136
+ body: {
27137
+ background: 'transparent',
27138
+ textColor: 'var(--md-sys-color-on-surface)',
27139
+ padding: '0',
27140
+ },
27141
+ },
27142
+ 'data-panel': {
27143
+ card: {
27144
+ background: 'var(--md-sys-color-surface)',
27145
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 76%, transparent)',
27146
+ borderRadius: '10px',
27147
+ shadow: '0 5px 16px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
27148
+ },
27149
+ header: {
27150
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 64%, transparent)',
27151
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-outline-variant) 58%, transparent)',
27152
+ titleColor: 'var(--md-sys-color-on-surface)',
27153
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27154
+ iconColor: 'var(--md-sys-color-primary)',
27155
+ },
27156
+ body: {
27157
+ background: 'var(--md-sys-color-surface)',
27158
+ textColor: 'var(--md-sys-color-on-surface)',
27159
+ padding: '12px',
27160
+ },
27161
+ },
27162
+ 'chart-panel': {
27163
+ card: {
27164
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 92%, var(--md-sys-color-primary-container) 8%)',
27165
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 22%, var(--md-sys-color-outline-variant) 62%)',
27166
+ borderRadius: '12px',
27167
+ shadow: '0 10px 24px color-mix(in srgb, var(--md-sys-color-shadow, #000) 9%, transparent)',
27168
+ },
27169
+ header: {
27170
+ background: 'color-mix(in srgb, var(--md-sys-color-primary-container) 22%, transparent)',
27171
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 20%, transparent)',
27172
+ titleColor: 'var(--md-sys-color-on-surface)',
27173
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27174
+ iconColor: 'var(--md-sys-color-primary)',
27175
+ },
27176
+ body: {
27177
+ background: 'transparent',
27178
+ textColor: 'var(--md-sys-color-on-surface)',
27179
+ padding: '12px',
27180
+ },
27181
+ },
27182
+ 'metric-panel': {
27183
+ card: {
27184
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 78%, var(--md-sys-color-primary-container) 22%)',
27185
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 24%, transparent)',
27186
+ borderRadius: '10px',
27187
+ shadow: '0 8px 18px color-mix(in srgb, var(--md-sys-color-shadow, #000) 8%, transparent)',
27188
+ },
27189
+ header: {
27190
+ background: 'transparent',
27191
+ borderColor: 'transparent',
27192
+ titleColor: 'var(--md-sys-color-on-surface)',
27193
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27194
+ iconColor: 'var(--md-sys-color-primary)',
27195
+ },
27196
+ body: {
27197
+ background: 'transparent',
27198
+ textColor: 'var(--md-sys-color-on-surface)',
27199
+ padding: '10px 12px',
27200
+ },
27201
+ },
27202
+ 'executive-card': {
27203
+ card: {
27204
+ background: 'color-mix(in srgb, var(--md-sys-color-surface) 88%, var(--md-sys-color-surface-container-high) 12%)',
27205
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 28%, var(--md-sys-color-outline-variant) 50%)',
27206
+ borderRadius: '10px',
27207
+ shadow: '0 12px 28px color-mix(in srgb, var(--md-sys-color-shadow, #000) 13%, transparent)',
27208
+ },
27209
+ header: {
27210
+ background: 'color-mix(in srgb, var(--md-sys-color-primary-container) 18%, transparent)',
27211
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent)',
27212
+ titleColor: 'var(--md-sys-color-on-surface)',
27213
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27214
+ iconColor: 'var(--md-sys-color-primary)',
27215
+ },
27216
+ body: {
27217
+ background: 'transparent',
27218
+ textColor: 'var(--md-sys-color-on-surface)',
27219
+ padding: '14px',
27220
+ },
27221
+ },
27222
+ 'filter-bar': {
27223
+ card: {
27224
+ background: 'color-mix(in srgb, var(--md-sys-color-surface-container-low) 74%, var(--md-sys-color-secondary-container) 26%)',
27225
+ borderColor: 'color-mix(in srgb, var(--md-sys-color-secondary) 24%, transparent)',
27226
+ borderRadius: '999px',
27227
+ shadow: '0 6px 18px color-mix(in srgb, var(--md-sys-color-shadow, #000) 7%, transparent)',
27228
+ },
27229
+ header: {
27230
+ background: 'transparent',
27231
+ borderColor: 'transparent',
27232
+ titleColor: 'var(--md-sys-color-on-surface)',
27233
+ subtitleColor: 'var(--md-sys-color-on-surface-variant)',
27234
+ iconColor: 'var(--md-sys-color-secondary)',
27235
+ },
27236
+ body: {
27237
+ background: 'transparent',
27238
+ textColor: 'var(--md-sys-color-on-surface)',
27239
+ padding: '10px 14px',
25332
27240
  },
25333
27241
  },
25334
27242
  };
@@ -25404,6 +27312,11 @@ class WidgetShellComponent {
25404
27312
  const builtins = this.buildWindowActions(custom);
25405
27313
  return [...builtins, ...custom];
25406
27314
  }
27315
+ displayActionIcon(action) {
27316
+ return action.pressed === true && action.pressedIcon
27317
+ ? action.pressedIcon
27318
+ : action.icon;
27319
+ }
25407
27320
  onAction(action, ev) {
25408
27321
  ev.stopPropagation();
25409
27322
  const handled = this.handleWindowAction(action);
@@ -25413,6 +27326,7 @@ class WidgetShellComponent {
25413
27326
  command: action.command,
25414
27327
  emit: action.emit,
25415
27328
  payload,
27329
+ pressed: action.pressed,
25416
27330
  action,
25417
27331
  };
25418
27332
  this.loader?.dispatchAction(event);
@@ -25603,14 +27517,16 @@ class WidgetShellComponent {
25603
27517
  <button
25604
27518
  [disabled]="action.disabled"
25605
27519
  [matTooltip]="action.tooltip || ''"
25606
- matTooltipPosition="below"
27520
+ matTooltipPosition="above"
25607
27521
  [ngClass]="action.variant === 'outlined' ? 'pdx-action-outlined' : 'pdx-action-text'"
27522
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25608
27523
  mat-button
25609
27524
  type="button"
27525
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25610
27526
  (click)="onAction(action, $event)"
25611
27527
  >
25612
- @if (action.icon) {
25613
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27528
+ @if (displayActionIcon(action); as actionIcon) {
27529
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25614
27530
  }
25615
27531
  <span class="pdx-action-label">{{ action.label }}</span>
25616
27532
  </button>
@@ -25620,13 +27536,15 @@ class WidgetShellComponent {
25620
27536
  mat-icon-button
25621
27537
  [disabled]="action.disabled"
25622
27538
  [matTooltip]="action.tooltip || action.label || ''"
25623
- matTooltipPosition="below"
27539
+ matTooltipPosition="above"
25624
27540
  [attr.aria-label]="action.label || action.tooltip || action.id"
27541
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27542
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25625
27543
  type="button"
25626
27544
  (click)="onAction(action, $event)"
25627
27545
  >
25628
- @if (action.icon) {
25629
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27546
+ @if (displayActionIcon(action); as actionIcon) {
27547
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25630
27548
  }
25631
27549
  </button>
25632
27550
  }
@@ -25637,7 +27555,7 @@ class WidgetShellComponent {
25637
27555
  mat-icon-button
25638
27556
  type="button"
25639
27557
  [matTooltip]="moreActionsLabel()"
25640
- matTooltipPosition="below"
27558
+ matTooltipPosition="above"
25641
27559
  [attr.aria-label]="moreActionsLabel()"
25642
27560
  [matMenuTriggerFor]="overflowMenu"
25643
27561
  (click)="$event.stopPropagation()"
@@ -25653,13 +27571,15 @@ class WidgetShellComponent {
25653
27571
  mat-icon-button
25654
27572
  [disabled]="action.disabled"
25655
27573
  [matTooltip]="action.tooltip || action.label || ''"
25656
- matTooltipPosition="below"
27574
+ matTooltipPosition="above"
25657
27575
  [attr.aria-label]="action.label || action.tooltip || action.id"
27576
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27577
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25658
27578
  type="button"
25659
27579
  (click)="onAction(action, $event)"
25660
27580
  >
25661
- @if (action.icon) {
25662
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27581
+ @if (displayActionIcon(action); as actionIcon) {
27582
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25663
27583
  }
25664
27584
  </button>
25665
27585
  }
@@ -25670,10 +27590,11 @@ class WidgetShellComponent {
25670
27590
  @for (action of overflowHeaderActions; track action.id) {
25671
27591
  <button
25672
27592
  mat-menu-item
27593
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25673
27594
  (click)="onAction(action, $event)"
25674
27595
  >
25675
- @if (action.icon) {
25676
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27596
+ @if (displayActionIcon(action); as actionIcon) {
27597
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25677
27598
  }
25678
27599
  <span>{{ action.label || action.id }}</span>
25679
27600
  </button>
@@ -25688,7 +27609,7 @@ class WidgetShellComponent {
25688
27609
  @if (expanded || fullscreen) {
25689
27610
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
25690
27611
  }
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 });
27612
+ `, 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
27613
  }
25693
27614
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, decorators: [{
25694
27615
  type: Component,
@@ -25747,14 +27668,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25747
27668
  <button
25748
27669
  [disabled]="action.disabled"
25749
27670
  [matTooltip]="action.tooltip || ''"
25750
- matTooltipPosition="below"
27671
+ matTooltipPosition="above"
25751
27672
  [ngClass]="action.variant === 'outlined' ? 'pdx-action-outlined' : 'pdx-action-text'"
27673
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25752
27674
  mat-button
25753
27675
  type="button"
27676
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25754
27677
  (click)="onAction(action, $event)"
25755
27678
  >
25756
- @if (action.icon) {
25757
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27679
+ @if (displayActionIcon(action); as actionIcon) {
27680
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25758
27681
  }
25759
27682
  <span class="pdx-action-label">{{ action.label }}</span>
25760
27683
  </button>
@@ -25764,13 +27687,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25764
27687
  mat-icon-button
25765
27688
  [disabled]="action.disabled"
25766
27689
  [matTooltip]="action.tooltip || action.label || ''"
25767
- matTooltipPosition="below"
27690
+ matTooltipPosition="above"
25768
27691
  [attr.aria-label]="action.label || action.tooltip || action.id"
27692
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27693
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25769
27694
  type="button"
25770
27695
  (click)="onAction(action, $event)"
25771
27696
  >
25772
- @if (action.icon) {
25773
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27697
+ @if (displayActionIcon(action); as actionIcon) {
27698
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25774
27699
  }
25775
27700
  </button>
25776
27701
  }
@@ -25781,7 +27706,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25781
27706
  mat-icon-button
25782
27707
  type="button"
25783
27708
  [matTooltip]="moreActionsLabel()"
25784
- matTooltipPosition="below"
27709
+ matTooltipPosition="above"
25785
27710
  [attr.aria-label]="moreActionsLabel()"
25786
27711
  [matMenuTriggerFor]="overflowMenu"
25787
27712
  (click)="$event.stopPropagation()"
@@ -25797,13 +27722,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25797
27722
  mat-icon-button
25798
27723
  [disabled]="action.disabled"
25799
27724
  [matTooltip]="action.tooltip || action.label || ''"
25800
- matTooltipPosition="below"
27725
+ matTooltipPosition="above"
25801
27726
  [attr.aria-label]="action.label || action.tooltip || action.id"
27727
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
27728
+ [class.pdx-shell-action--pressed]="action.pressed === true"
25802
27729
  type="button"
25803
27730
  (click)="onAction(action, $event)"
25804
27731
  >
25805
- @if (action.icon) {
25806
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27732
+ @if (displayActionIcon(action); as actionIcon) {
27733
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25807
27734
  }
25808
27735
  </button>
25809
27736
  }
@@ -25814,10 +27741,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25814
27741
  @for (action of overflowHeaderActions; track action.id) {
25815
27742
  <button
25816
27743
  mat-menu-item
27744
+ [attr.aria-pressed]="action.pressed == null ? null : action.pressed"
25817
27745
  (click)="onAction(action, $event)"
25818
27746
  >
25819
- @if (action.icon) {
25820
- <mat-icon [praxisIcon]="action.icon"></mat-icon>
27747
+ @if (displayActionIcon(action); as actionIcon) {
27748
+ <mat-icon [praxisIcon]="actionIcon"></mat-icon>
25821
27749
  }
25822
27750
  <span>{{ action.label || action.id }}</span>
25823
27751
  </button>
@@ -25832,7 +27760,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
25832
27760
  @if (expanded || fullscreen) {
25833
27761
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
25834
27762
  }
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"] }]
27763
+ `, 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
27764
  }], propDecorators: { hostCollapsed: [{
25837
27765
  type: HostBinding,
25838
27766
  args: ['class.pdx-widget-shell-collapsed']
@@ -26010,7 +27938,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26010
27938
  id: 'analytics-calm',
26011
27939
  label: 'Analytics Calm',
26012
27940
  description: 'Superfícies leves, ênfase clara em dados e motion sutil.',
26013
- shellPreset: 'light-neutral',
27941
+ shellPreset: 'chart-panel',
26014
27942
  chartThemePreset: 'executive',
26015
27943
  density: 'comfortable',
26016
27944
  motion: 'subtle',
@@ -26027,7 +27955,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26027
27955
  id: 'workspace-balanced',
26028
27956
  label: 'Workspace Balanced',
26029
27957
  description: 'Equilíbrio entre densidade operacional e clareza visual.',
26030
- shellPreset: 'light-neutral',
27958
+ shellPreset: 'data-panel',
26031
27959
  chartThemePreset: 'default',
26032
27960
  density: 'comfortable',
26033
27961
  motion: 'subtle',
@@ -26044,7 +27972,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26044
27972
  id: 'ops-monitoring',
26045
27973
  label: 'Ops Monitoring',
26046
27974
  description: 'Contraste um pouco maior para leitura rápida de status, filas e alertas.',
26047
- shellPreset: 'graphite',
27975
+ shellPreset: 'data-panel',
26048
27976
  chartThemePreset: 'compact',
26049
27977
  density: 'compact',
26050
27978
  motion: 'subtle',
@@ -26061,7 +27989,7 @@ const BUILTIN_PAGE_THEME_PRESETS = {
26061
27989
  id: 'executive-command-center',
26062
27990
  label: 'Executive Command Center',
26063
27991
  description: 'Superfície premium para dashboards corporativos com hierarquia executiva, dados densos e ações de decisão.',
26064
- shellPreset: 'graphite',
27992
+ shellPreset: 'executive-card',
26065
27993
  chartThemePreset: 'executive',
26066
27994
  density: 'compact',
26067
27995
  motion: 'subtle',
@@ -31033,9 +32961,18 @@ class DynamicWidgetPageComponent {
31033
32961
  if (!widget.shell) {
31034
32962
  return runtimeEnrichedWidget;
31035
32963
  }
32964
+ const widgetTemplateContext = {
32965
+ ...templateContext,
32966
+ widget: {
32967
+ key: widget.key,
32968
+ definition: this.cloneStateValues(widget.definition),
32969
+ inputs: this.cloneStateValues(widget.definition?.inputs || {}),
32970
+ shell: this.cloneStateValues(widget.shell || {}),
32971
+ },
32972
+ };
31036
32973
  return {
31037
32974
  ...runtimeEnrichedWidget,
31038
- shell: this.resolveTemplate(widget.shell, templateContext),
32975
+ shell: this.resolveTemplate(widget.shell, widgetTemplateContext),
31039
32976
  };
31040
32977
  });
31041
32978
  }
@@ -31088,9 +33025,16 @@ class DynamicWidgetPageComponent {
31088
33025
  origin: 'dynamic-page.rich-content',
31089
33026
  componentId: 'praxis-dynamic-page',
31090
33027
  },
33028
+ }).then((result) => {
33029
+ if (!result?.success) {
33030
+ this.emitRichContentCustomAction(widgetKey, actionId, payload);
33031
+ }
31091
33032
  });
31092
33033
  return;
31093
33034
  }
33035
+ this.emitRichContentCustomAction(widgetKey, actionId, payload);
33036
+ }
33037
+ emitRichContentCustomAction(widgetKey, actionId, payload) {
31094
33038
  this.onWidgetEvent(widgetKey, {
31095
33039
  ownerWidgetKey: widgetKey,
31096
33040
  sourceComponentId: 'praxis-rich-content',
@@ -31412,6 +33356,8 @@ class DynamicWidgetPageComponent {
31412
33356
  void this.confirmAndRemoveWidget(fromKey);
31413
33357
  return;
31414
33358
  }
33359
+ if (this.handleToggleInputCommand(fromKey, evt))
33360
+ return;
31415
33361
  if (this.handleSetInputCommand(fromKey, evt))
31416
33362
  return;
31417
33363
  const output = evt?.emit || (evt?.id ? `shell:${evt.id}` : undefined);
@@ -31436,6 +33382,32 @@ class DynamicWidgetPageComponent {
31436
33382
  this.widgets.set(widgets);
31437
33383
  return true;
31438
33384
  }
33385
+ handleToggleInputCommand(fromKey, evt) {
33386
+ if (evt?.command !== 'pdx:toggle-input')
33387
+ return false;
33388
+ const payload = evt?.payload;
33389
+ const input = typeof payload?.input === 'string' ? payload.input.trim() : '';
33390
+ if (!input)
33391
+ return true;
33392
+ const page = this.ensurePageDefinition();
33393
+ const widget = (page.widgets || []).find((candidate) => candidate.key === fromKey);
33394
+ const currentValue = this.lookup(widget?.definition?.inputs || {}, input);
33395
+ const nextValue = !Boolean(currentValue);
33396
+ const result = this.applyWidgetInputPatchToPage(page, fromKey, {
33397
+ ownerWidgetKey: fromKey,
33398
+ sourceComponentId: 'widget-shell',
33399
+ output: evt.emit || `shell:${evt.id}`,
33400
+ payload: {
33401
+ inputPatch: {
33402
+ [input]: nextValue,
33403
+ },
33404
+ },
33405
+ });
33406
+ if (result.changed) {
33407
+ this.applyPageUpdate(result.page, true, undefined, false, true);
33408
+ }
33409
+ return true;
33410
+ }
31439
33411
  mergeOrder(keys) {
31440
33412
  const seen = new Set();
31441
33413
  const out = [];
@@ -33974,24 +35946,24 @@ const PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA = {
33974
35946
  selector: 'praxis-dynamic-page',
33975
35947
  component: DynamicWidgetPageComponent,
33976
35948
  friendlyName: 'Dynamic Page',
33977
- description: 'Pagina dinamica com widgets e composition.links em layout responsivo, incluindo mediacao runtime para rich-content hospedado.',
35949
+ description: 'Página dinâmica com widgets e composition.links em layout responsivo, incluindo mediação runtime para rich-content hospedado.',
33978
35950
  icon: 'dashboard',
33979
35951
  inputs: [
33980
- { name: 'page', type: 'WidgetPageDefinition', description: 'Definicao da pagina (widgets, layout e composition.links).' },
35952
+ { name: 'page', type: 'WidgetPageDefinition', description: 'Definição da página (widgets, layout e composition.links).' },
33981
35953
  { 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.' },
35954
+ { name: 'strictValidation', type: 'boolean', description: 'Habilita validação estrita de inputs.' },
35955
+ { name: 'enableCustomization', type: 'boolean', description: 'Habilita affordances de edição na página.' },
35956
+ { name: 'showPageSettingsButton', type: 'boolean', description: 'Exibe botão de configuração da página.' },
33985
35957
  { 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.' },
35958
+ { name: 'pageEditorComponent', type: 'Type<any>', description: 'Override do editor de configuração da página.' },
35959
+ { name: 'autoPersist', type: 'boolean', description: 'Ativa persistência automática (load/save) da página.' },
35960
+ { name: 'pageIdentity', type: 'PageIdentity', description: 'Identidade de persistência (tenant/usuário/rota/locale).' },
35961
+ { name: 'componentInstanceId', type: 'string', description: 'Identificador opcional para múltiplas instâncias na mesma rota.' },
33990
35962
  ],
33991
35963
  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.' },
35964
+ { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitido ao alterar a definição da página.' },
35965
+ { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos dos widgets filhos com ownerWidgetKey para integrações do host.' },
35966
+ { name: 'widgetDiagnosticsChange', type: 'Record<string, WidgetResolutionDiagnostic>', description: 'Emitido quando o runtime detecta widgets resolvidos ou falhos durante o carregamento dinâmico.' },
33995
35967
  ],
33996
35968
  tags: ['widget', 'page', 'dynamic', 'layout'],
33997
35969
  lib: '@praxisui/core',
@@ -34026,6 +35998,8 @@ class PraxisSurfaceHostComponent {
34026
35998
  */
34027
35999
  renderTitleInsideBody = false;
34028
36000
  widgetEvent = new EventEmitter();
36001
+ rowClick = new EventEmitter();
36002
+ selectionChange = new EventEmitter();
34029
36003
  beforeWidgetLoader;
34030
36004
  mainWidgetLoader;
34031
36005
  afterWidgetLoader;
@@ -34139,13 +36113,19 @@ class PraxisSurfaceHostComponent {
34139
36113
  }
34140
36114
  }
34141
36115
  onSlotWidgetEvent(ownerWidgetKey, event) {
36116
+ if (event.output === 'rowClick') {
36117
+ this.rowClick.emit(event.payload);
36118
+ }
36119
+ if (event.output === 'selectionChange') {
36120
+ this.selectionChange.emit(event.payload);
36121
+ }
34142
36122
  this.widgetEvent.emit({
34143
36123
  ...event,
34144
36124
  ownerWidgetKey: event.ownerWidgetKey || ownerWidgetKey,
34145
36125
  });
34146
36126
  }
34147
36127
  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: `
36128
+ 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
36129
  <div class="pdx-surface-host">
34150
36130
  @if (subtitle || (title && renderTitleInsideBody)) {
34151
36131
  <header class="pdx-surface-host__header">
@@ -34172,6 +36152,7 @@ class PraxisSurfaceHostComponent {
34172
36152
  [ownerWidgetKey]="beforeWidgetKey"
34173
36153
  [context]="context"
34174
36154
  [strictValidation]="strictValidation"
36155
+ [autoWireOutputs]="true"
34175
36156
  (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34176
36157
  ></ng-container>
34177
36158
  </div>
@@ -34184,6 +36165,7 @@ class PraxisSurfaceHostComponent {
34184
36165
  [ownerWidgetKey]="mainWidgetKey"
34185
36166
  [context]="context"
34186
36167
  [strictValidation]="strictValidation"
36168
+ [autoWireOutputs]="true"
34187
36169
  (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
34188
36170
  ></ng-container>
34189
36171
  }
@@ -34196,6 +36178,7 @@ class PraxisSurfaceHostComponent {
34196
36178
  [ownerWidgetKey]="afterWidgetKey"
34197
36179
  [context]="context"
34198
36180
  [strictValidation]="strictValidation"
36181
+ [autoWireOutputs]="true"
34199
36182
  (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34200
36183
  ></ng-container>
34201
36184
  </div>
@@ -34233,6 +36216,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34233
36216
  [ownerWidgetKey]="beforeWidgetKey"
34234
36217
  [context]="context"
34235
36218
  [strictValidation]="strictValidation"
36219
+ [autoWireOutputs]="true"
34236
36220
  (widgetEvent)="onSlotWidgetEvent(beforeWidgetKey, $event)"
34237
36221
  ></ng-container>
34238
36222
  </div>
@@ -34245,6 +36229,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34245
36229
  [ownerWidgetKey]="mainWidgetKey"
34246
36230
  [context]="context"
34247
36231
  [strictValidation]="strictValidation"
36232
+ [autoWireOutputs]="true"
34248
36233
  (widgetEvent)="onSlotWidgetEvent(mainWidgetKey, $event)"
34249
36234
  ></ng-container>
34250
36235
  }
@@ -34257,6 +36242,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34257
36242
  [ownerWidgetKey]="afterWidgetKey"
34258
36243
  [context]="context"
34259
36244
  [strictValidation]="strictValidation"
36245
+ [autoWireOutputs]="true"
34260
36246
  (widgetEvent)="onSlotWidgetEvent(afterWidgetKey, $event)"
34261
36247
  ></ng-container>
34262
36248
  </div>
@@ -34284,6 +36270,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
34284
36270
  type: Input
34285
36271
  }], widgetEvent: [{
34286
36272
  type: Output
36273
+ }], rowClick: [{
36274
+ type: Output
36275
+ }], selectionChange: [{
36276
+ type: Output
34287
36277
  }], beforeWidgetLoader: [{
34288
36278
  type: ViewChild,
34289
36279
  args: ['beforeWidgetLoader', { read: DynamicWidgetLoaderDirective }]
@@ -35244,15 +37234,9 @@ function applyLocalCustomizations$1(base, local) {
35244
37234
  // Server authority on identity/core props
35245
37235
  const authoritative = {
35246
37236
  name: base.name,
35247
- label: base.label,
35248
37237
  type: base.type,
35249
37238
  controlType: base.controlType,
35250
37239
  required: base.required,
35251
- hint: base.hint,
35252
- helpText: base.helpText,
35253
- description: base.description,
35254
- icon: base.icon,
35255
- iconPosition: base.iconPosition,
35256
37240
  endpoint: base.endpoint,
35257
37241
  resourcePath: base.resourcePath,
35258
37242
  optionSource: base.optionSource,
@@ -35288,12 +37272,13 @@ function applyLocalCustomizations$1(base, local) {
35288
37272
  ? serverBackedLocal.queryParams
35289
37273
  : base.queryParams,
35290
37274
  };
35291
- return {
37275
+ const merged = {
35292
37276
  ...base,
35293
37277
  ...serverBackedLocal,
35294
37278
  ...authoritative,
35295
37279
  ...preserved,
35296
37280
  };
37281
+ return applyServerOwnedFieldSemantics(merged, base);
35297
37282
  }
35298
37283
  function mergeServerVisibilityFlag(serverValue) {
35299
37284
  return serverValue === true ? true : undefined;
@@ -35758,4 +37743,4 @@ function provideHookWhitelist(allowed) {
35758
37743
  * Generated bundle index. Do not edit.
35759
37744
  */
35760
37745
 
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 };
37746
+ 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_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, 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, withFormConfigSections, withMessage, withPraxisHttpLoading };