@praxisui/core 9.0.4-rc.2 → 9.0.4-rc.21

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.
@@ -8600,6 +8600,14 @@ class GlobalActionService {
8600
8600
  runtime.emitResult(this.toSurfaceResult(payload, 'result'));
8601
8601
  return { success: true };
8602
8602
  });
8603
+ this.register('surface.complete', async (payload, context) => {
8604
+ const runtime = this.resolveSurfaceRuntime(context);
8605
+ if (typeof runtime?.complete !== 'function') {
8606
+ return { success: false, error: 'Surface completion runtime not available' };
8607
+ }
8608
+ runtime.complete(this.toSurfaceOutcome(payload));
8609
+ return { success: true };
8610
+ });
8603
8611
  this.register('dynamicPage.composition.dispatch', async (payload, context) => this.handleCompositionDispatch(payload, context));
8604
8612
  this.register('toast.success', async (payload) => {
8605
8613
  const message = payload?.message || payload;
@@ -8885,6 +8893,21 @@ class GlobalActionService {
8885
8893
  });
8886
8894
  });
8887
8895
  }
8896
+ toSurfaceOutcome(payload) {
8897
+ const result = this.toSurfaceResult(payload, 'completed');
8898
+ const record = payload && typeof payload === 'object'
8899
+ ? payload
8900
+ : {};
8901
+ const requestedKind = String(record['kind'] || 'completed');
8902
+ const kind = requestedKind === 'notification' || requestedKind === 'dismissed' || requestedKind === 'failed'
8903
+ ? requestedKind
8904
+ : 'completed';
8905
+ return {
8906
+ ...result,
8907
+ kind,
8908
+ type: String(record['type'] || 'completed'),
8909
+ };
8910
+ }
8888
8911
  toSurfaceResult(payload, fallbackType) {
8889
8912
  if (payload && typeof payload === 'object' && ('type' in payload || 'data' in payload)) {
8890
8913
  return {
@@ -13884,6 +13907,36 @@ const SURFACE_OPEN_PRESETS = [
13884
13907
  description: 'Abre um formulário dinâmico com resourcePath, formId e resourceId.',
13885
13908
  payload: {
13886
13909
  presentation: 'drawer',
13910
+ lifecycle: {
13911
+ outcomes: [
13912
+ {
13913
+ output: 'formSubmit',
13914
+ when: [{ path: 'stage', equals: 'after' }],
13915
+ outcome: { kind: 'completed', type: 'save', dataPath: 'result' },
13916
+ },
13917
+ {
13918
+ output: 'formSubmit',
13919
+ when: [{ path: 'stage', equals: 'error' }],
13920
+ outcome: { kind: 'failed', type: 'submit-error', errorPath: 'error' },
13921
+ },
13922
+ {
13923
+ output: 'formCancel',
13924
+ outcome: { kind: 'dismissed', type: 'cancel' },
13925
+ },
13926
+ {
13927
+ output: 'formReset',
13928
+ outcome: { kind: 'notification', type: 'reset' },
13929
+ },
13930
+ {
13931
+ output: 'customAction',
13932
+ outcome: { kind: 'notification', type: 'custom-action' },
13933
+ },
13934
+ {
13935
+ output: 'initializationError',
13936
+ outcome: { kind: 'failed', type: 'initialization-error', errorPath: 'error' },
13937
+ },
13938
+ ],
13939
+ },
13887
13940
  widget: {
13888
13941
  id: 'praxis-dynamic-form',
13889
13942
  bindingOrder: [
@@ -13968,8 +14021,341 @@ const SURFACE_OPEN_PRESETS = [
13968
14021
  },
13969
14022
  ];
13970
14023
 
14024
+ const RELATED_RESOURCE_OUTLET_I18N_NAMESPACE = 'relatedResourceOutlet';
14025
+ const RELATED_RESOURCE_OUTLET_I18N_CONFIG = {
14026
+ namespaces: {
14027
+ [RELATED_RESOURCE_OUTLET_I18N_NAMESPACE]: {
14028
+ 'pt-BR': {
14029
+ 'state.idle.title': 'Recurso relacionado não selecionado',
14030
+ 'state.idle.description': 'Selecione uma surface relacionada para carregar os dados.',
14031
+ 'state.resolving.title': 'Resolvendo recurso relacionado',
14032
+ 'state.resolving.description': 'Validando metadados e permissões da relação.',
14033
+ 'state.loading.title': 'Carregando recurso relacionado',
14034
+ 'state.loading.description': 'Aguarde enquanto a coleção relacionada é carregada.',
14035
+ 'state.empty.title': 'Nenhuma operação de leitura publicada',
14036
+ 'state.empty.description': 'A relação existe, mas não há operação de lista ou filtro disponível.',
14037
+ 'state.permission-limited.title': 'Acesso limitado',
14038
+ 'state.permission-limited.description': 'O contexto atual não permite abrir este recurso relacionado.',
14039
+ 'state.not-found.title': 'Relação indisponível',
14040
+ 'state.not-found.description': 'Não foi possível resolver a relação ou o identificador do registro pai.',
14041
+ 'state.error.title': 'Falha ao preparar recurso relacionado',
14042
+ 'state.error.description': 'Ocorreu um erro ao preparar a superfície relacionada.',
14043
+ 'emptyState.related.title': 'Sem registros em {label}',
14044
+ 'emptyState.related.description': 'Esta coleção relacionada não possui registros para o contexto selecionado.',
14045
+ 'emptyState.related.descriptionWithAction': 'Use a ação principal para adicionar um registro relacionado quando houver informações para registrar.',
14046
+ 'emptyState.related.action.create': 'Adicionar registro',
14047
+ 'action.open': 'Abrir relacionado',
14048
+ 'status.ready': 'Recurso relacionado pronto',
14049
+ },
14050
+ 'en-US': {
14051
+ 'state.idle.title': 'Related resource not selected',
14052
+ 'state.idle.description': 'Select a related surface to load its data.',
14053
+ 'state.resolving.title': 'Resolving related resource',
14054
+ 'state.resolving.description': 'Validating relation metadata and permissions.',
14055
+ 'state.loading.title': 'Loading related resource',
14056
+ 'state.loading.description': 'Wait while the related collection is loaded.',
14057
+ 'state.empty.title': 'No read operation published',
14058
+ 'state.empty.description': 'The relation exists, but no list or filter operation is available.',
14059
+ 'state.permission-limited.title': 'Limited access',
14060
+ 'state.permission-limited.description': 'The current context cannot open this related resource.',
14061
+ 'state.not-found.title': 'Relation unavailable',
14062
+ 'state.not-found.description': 'The relation or parent record identifier could not be resolved.',
14063
+ 'state.error.title': 'Failed to prepare related resource',
14064
+ 'state.error.description': 'An error occurred while preparing the related surface.',
14065
+ 'emptyState.related.title': 'No records in {label}',
14066
+ 'emptyState.related.description': 'This related collection has no records for the selected context.',
14067
+ 'emptyState.related.descriptionWithAction': 'Use the primary action to add a related record when there is information to capture.',
14068
+ 'emptyState.related.action.create': 'Add record',
14069
+ 'action.open': 'Open related',
14070
+ 'status.ready': 'Related resource ready',
14071
+ },
14072
+ },
14073
+ },
14074
+ };
14075
+
14076
+ class RelatedResourceSurfaceResolverService {
14077
+ i18n = inject(PraxisI18nService, { optional: true });
14078
+ resolve(request) {
14079
+ try {
14080
+ if (!request?.surface) {
14081
+ return { state: 'idle', reason: 'surface-not-provided' };
14082
+ }
14083
+ const surface = request.surface;
14084
+ if (surface.availability?.allowed === false) {
14085
+ return {
14086
+ state: 'permission-limited',
14087
+ reason: surface.availability.reason || 'surface-not-allowed',
14088
+ surface,
14089
+ relatedResource: surface.relatedResource ?? null,
14090
+ };
14091
+ }
14092
+ const relatedResource = surface.relatedResource ?? null;
14093
+ if (!this.isCompleteRelatedResource(relatedResource)) {
14094
+ return {
14095
+ state: 'not-found',
14096
+ reason: 'related-resource-not-published',
14097
+ surface,
14098
+ relatedResource,
14099
+ };
14100
+ }
14101
+ if (!this.hasReadOperation(relatedResource)) {
14102
+ return {
14103
+ state: 'empty',
14104
+ reason: 'related-resource-read-operation-not-published',
14105
+ surface,
14106
+ relatedResource,
14107
+ };
14108
+ }
14109
+ const parentResourceId = this.resolveParentResourceId(request, relatedResource);
14110
+ if (parentResourceId == null || parentResourceId === '') {
14111
+ return {
14112
+ state: 'not-found',
14113
+ reason: 'parent-resource-id-not-resolved',
14114
+ surface,
14115
+ relatedResource,
14116
+ };
14117
+ }
14118
+ const queryContext = this.buildQueryContext(request.queryContext, relatedResource.childParentField, parentResourceId);
14119
+ const payload = this.buildPayload(surface, relatedResource, parentResourceId, queryContext, request);
14120
+ return {
14121
+ state: 'ready',
14122
+ surface,
14123
+ relatedResource,
14124
+ parentResourceId,
14125
+ childResourcePath: relatedResource.childResourcePath,
14126
+ childResourceKey: relatedResource.childResourceKey,
14127
+ queryContext,
14128
+ payload,
14129
+ };
14130
+ }
14131
+ catch (error) {
14132
+ return {
14133
+ state: 'error',
14134
+ reason: error instanceof Error ? error.message : 'related-resource-resolution-failed',
14135
+ surface: request?.surface ?? null,
14136
+ relatedResource: request?.surface?.relatedResource ?? null,
14137
+ };
14138
+ }
14139
+ }
14140
+ state(state, reason) {
14141
+ return { state, reason };
14142
+ }
14143
+ buildPayload(surface, relatedResource, parentResourceId, queryContext, request) {
14144
+ const preset = SURFACE_OPEN_PRESETS.find((candidate) => candidate.id === 'praxis-table');
14145
+ if (!preset) {
14146
+ throw new Error('Missing canonical surface preset "praxis-table".');
14147
+ }
14148
+ const payload = this.clone(preset.payload);
14149
+ payload.presentation = request.presentation ?? payload.presentation;
14150
+ payload.title = request.title || surface.title;
14151
+ payload.subtitle = request.subtitle || surface.description || undefined;
14152
+ payload.icon = request.icon || payload.icon;
14153
+ payload.widget.inputs = {
14154
+ ...(payload.widget.inputs || {}),
14155
+ configPersistenceStrategy: 'volatile',
14156
+ resourcePath: this.normalizeResourcePath(relatedResource.childResourcePath),
14157
+ apiEndpointKey: request.apiEndpointKey ?? null,
14158
+ apiUrlEntry: request.apiUrlEntry ?? null,
14159
+ tableId: request.tableId || this.buildStableTableId(surface, relatedResource, parentResourceId),
14160
+ config: this.buildTableConfig(surface, relatedResource, request),
14161
+ queryContext,
14162
+ enableCustomization: request.enableCustomization === true,
14163
+ ...(this.trim(request.authoringCapability)
14164
+ ? { authoringCapability: this.trim(request.authoringCapability) }
14165
+ : {}),
14166
+ };
14167
+ payload.context = {
14168
+ ...(payload.context || {}),
14169
+ resource: {
14170
+ resourceKey: surface.resourceKey,
14171
+ resourcePath: this.normalizeResourcePath(request.parentResourcePath || ''),
14172
+ resourceId: parentResourceId,
14173
+ },
14174
+ surface,
14175
+ relatedResource,
14176
+ childResource: {
14177
+ resourceKey: relatedResource.childResourceKey,
14178
+ resourcePath: this.normalizeResourcePath(relatedResource.childResourcePath),
14179
+ parentField: relatedResource.childParentField,
14180
+ selectable: relatedResource.selectable,
14181
+ selectionKeyField: relatedResource.selectionKeyField,
14182
+ operations: relatedResource.childOperations,
14183
+ },
14184
+ };
14185
+ return payload;
14186
+ }
14187
+ buildTableConfig(surface, relatedResource, request) {
14188
+ const tableConfig = request.tableConfig;
14189
+ const emptyState = request.emptyState;
14190
+ const hasTableConfig = !!tableConfig && typeof tableConfig === 'object' && !Array.isArray(tableConfig);
14191
+ const hasEmptyState = !!emptyState && typeof emptyState === 'object' && !Array.isArray(emptyState);
14192
+ const base = hasTableConfig ? tableConfig : {};
14193
+ const toolbar = this.objectValue(base['toolbar']);
14194
+ const columnsVisibility = this.objectValue(toolbar['columnsVisibility']);
14195
+ const behavior = this.objectValue(base['behavior']);
14196
+ const currentEmptyState = this.objectValue(behavior['emptyState']);
14197
+ const hasCurrentEmptyState = Object.keys(currentEmptyState).length > 0;
14198
+ const resolvedEmptyState = hasEmptyState
14199
+ ? {
14200
+ ...currentEmptyState,
14201
+ ...emptyState,
14202
+ }
14203
+ : hasCurrentEmptyState
14204
+ ? currentEmptyState
14205
+ : this.buildRelatedEmptyState(surface, relatedResource, request);
14206
+ if (!hasTableConfig && !resolvedEmptyState) {
14207
+ return undefined;
14208
+ }
14209
+ return {
14210
+ ...base,
14211
+ toolbar: {
14212
+ ...toolbar,
14213
+ columnsVisibility: {
14214
+ enabled: false,
14215
+ ...columnsVisibility,
14216
+ },
14217
+ },
14218
+ behavior: {
14219
+ ...behavior,
14220
+ emptyState: resolvedEmptyState,
14221
+ },
14222
+ };
14223
+ }
14224
+ buildRelatedEmptyState(surface, relatedResource, request) {
14225
+ const label = this.trim(request.title)
14226
+ || this.trim(surface.title)
14227
+ || this.humanizeResourceKey(relatedResource.childResourceKey);
14228
+ const canCreate = relatedResource.childOperations.includes('CREATE');
14229
+ const descriptionKey = canCreate
14230
+ ? 'emptyState.related.descriptionWithAction'
14231
+ : 'emptyState.related.description';
14232
+ const actions = canCreate
14233
+ ? [
14234
+ {
14235
+ label: this.t('emptyState.related.action.create', 'Adicionar registro'),
14236
+ action: 'create',
14237
+ icon: 'add',
14238
+ primary: true,
14239
+ },
14240
+ ]
14241
+ : [];
14242
+ return {
14243
+ title: this.t('emptyState.related.title', 'Sem registros em {label}', { label }),
14244
+ message: this.t(descriptionKey, canCreate
14245
+ ? 'Use a ação principal para adicionar um registro relacionado quando houver informações para registrar.'
14246
+ : 'Esta coleção relacionada não possui registros para o contexto selecionado.', { label }),
14247
+ icon: this.trim(request.icon) || 'hub',
14248
+ tone: 'neutral',
14249
+ variant: 'inline',
14250
+ density: 'compact',
14251
+ alignment: 'center',
14252
+ iconContainer: 'soft',
14253
+ actions,
14254
+ };
14255
+ }
14256
+ objectValue(value) {
14257
+ return value && typeof value === 'object' && !Array.isArray(value)
14258
+ ? value
14259
+ : {};
14260
+ }
14261
+ buildQueryContext(queryContext, childParentField, parentResourceId) {
14262
+ return {
14263
+ ...(queryContext || {}),
14264
+ filters: {
14265
+ ...(queryContext?.filters || {}),
14266
+ [childParentField]: parentResourceId,
14267
+ },
14268
+ meta: {
14269
+ ...(queryContext?.meta || {}),
14270
+ relatedResource: true,
14271
+ parentFilterField: childParentField,
14272
+ },
14273
+ };
14274
+ }
14275
+ resolveParentResourceId(request, relatedResource) {
14276
+ if (request.parentResourceId != null) {
14277
+ return request.parentResourceId;
14278
+ }
14279
+ return this.readPath(request.parentRecord, relatedResource.parentIdPathVariable);
14280
+ }
14281
+ readPath(record, path) {
14282
+ if (!record || !path) {
14283
+ return null;
14284
+ }
14285
+ const value = path.split('.').reduce((current, segment) => {
14286
+ if (!current || typeof current !== 'object' || Array.isArray(current)) {
14287
+ return undefined;
14288
+ }
14289
+ return current[segment];
14290
+ }, record);
14291
+ return typeof value === 'string' || typeof value === 'number' ? value : null;
14292
+ }
14293
+ isCompleteRelatedResource(relatedResource) {
14294
+ return !!relatedResource
14295
+ && !!this.trim(relatedResource.childResourceKey)
14296
+ && !!this.trim(relatedResource.childResourcePath)
14297
+ && !!this.trim(relatedResource.childParentField)
14298
+ && !!this.trim(relatedResource.parentIdPathVariable)
14299
+ && Array.isArray(relatedResource.childOperations);
14300
+ }
14301
+ hasReadOperation(relatedResource) {
14302
+ return relatedResource.childOperations.includes('LIST')
14303
+ || relatedResource.childOperations.includes('FILTER');
14304
+ }
14305
+ buildStableTableId(surface, relatedResource, parentResourceId) {
14306
+ return this.sanitizeStableId(`${relatedResource.childResourceKey}.${surface.id}.${String(parentResourceId)}`);
14307
+ }
14308
+ normalizeResourcePath(resourcePath) {
14309
+ let normalized = this.trim(resourcePath);
14310
+ if (/^https?:\/\//i.test(normalized)) {
14311
+ try {
14312
+ normalized = new URL(normalized).pathname;
14313
+ }
14314
+ catch {
14315
+ return '';
14316
+ }
14317
+ }
14318
+ return normalized
14319
+ .replace(/^\/+/, '')
14320
+ .replace(/^(?:api\/)+/i, '')
14321
+ .replace(/\/+$/, '');
14322
+ }
14323
+ sanitizeStableId(value) {
14324
+ return value.replace(/[^a-zA-Z0-9._-]+/g, '-');
14325
+ }
14326
+ humanizeResourceKey(value) {
14327
+ const lastSegment = this.trim(value).split(/[./_-]+/).filter(Boolean).pop() || 'registros';
14328
+ return lastSegment
14329
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
14330
+ .replace(/\s+/g, ' ')
14331
+ .trim();
14332
+ }
14333
+ t(key, fallback, params) {
14334
+ if (this.i18n) {
14335
+ return this.interpolate(this.i18n.t(key, params, fallback, RELATED_RESOURCE_OUTLET_I18N_NAMESPACE), params);
14336
+ }
14337
+ return this.interpolate(fallback, params);
14338
+ }
14339
+ interpolate(template, params) {
14340
+ return Object.entries(params || {}).reduce((current, [name, value]) => current.replace(new RegExp(`\\{${name}\\}`, 'g'), String(value ?? '')), template);
14341
+ }
14342
+ trim(value) {
14343
+ return typeof value === 'string' ? value.trim() : '';
14344
+ }
14345
+ clone(value) {
14346
+ return value == null ? value : JSON.parse(JSON.stringify(value));
14347
+ }
14348
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
14349
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, providedIn: 'any' });
14350
+ }
14351
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, decorators: [{
14352
+ type: Injectable,
14353
+ args: [{ providedIn: 'any' }]
14354
+ }] });
14355
+
13971
14356
  class ResourceSurfaceOpenAdapterService {
13972
14357
  discovery = inject(ResourceDiscoveryService);
14358
+ relatedResourceResolver = inject(RelatedResourceSurfaceResolverService);
13973
14359
  toPayload(surface, options) {
13974
14360
  const resourcePath = this.normalizeResourcePath(options.resourcePath);
13975
14361
  if (!resourcePath) {
@@ -13982,6 +14368,25 @@ class ResourceSurfaceOpenAdapterService {
13982
14368
  }
13983
14369
  : undefined;
13984
14370
  const resolvedApiEntry = this.discovery.resolveApiEntry(discoveryOptions);
14371
+ const icon = options.icon ?? this.resolveDefaultIcon(surface);
14372
+ if (surface.relatedResource) {
14373
+ const resolution = this.relatedResourceResolver.resolve({
14374
+ surface,
14375
+ parentResourceId: options.resourceId ?? null,
14376
+ parentResourcePath: resourcePath,
14377
+ presentation: options.presentation,
14378
+ title: options.title ?? surface.title,
14379
+ subtitle: options.subtitle ?? surface.description ?? null,
14380
+ icon,
14381
+ queryContext: options.queryContext,
14382
+ apiEndpointKey: options.endpointKey ?? null,
14383
+ apiUrlEntry: options.apiUrlEntry ?? resolvedApiEntry,
14384
+ });
14385
+ if (resolution.state !== 'ready' || !resolution.payload) {
14386
+ throw new Error(`ResourceSurfaceOpenAdapterService could not materialize related surface "${surface.id}": ${resolution.reason || resolution.state}.`);
14387
+ }
14388
+ return resolution.payload;
14389
+ }
13985
14390
  const resolvedSchemaUrl = this.discovery.resolveHref(surface.schemaUrl, discoveryOptions);
13986
14391
  const resolvedSubmitUrl = this.isWritableFormSurface(surface.kind)
13987
14392
  ? this.discovery.resolveHref(surface.path, discoveryOptions)
@@ -13993,7 +14398,7 @@ class ResourceSurfaceOpenAdapterService {
13993
14398
  presentation: options.presentation ?? basePayload.presentation,
13994
14399
  title: options.title ?? surface.title ?? basePayload.title,
13995
14400
  subtitle: options.subtitle ?? surface.description ?? basePayload.subtitle,
13996
- icon: options.icon ?? basePayload.icon,
14401
+ icon: icon ?? basePayload.icon,
13997
14402
  context: {
13998
14403
  resource: {
13999
14404
  resourceKey: surface.resourceKey,
@@ -14082,6 +14487,15 @@ class ResourceSurfaceOpenAdapterService {
14082
14487
  }
14083
14488
  return this.clone(preset.payload);
14084
14489
  }
14490
+ resolveDefaultIcon(surface) {
14491
+ if (surface.relatedResource) {
14492
+ return 'dataset_linked';
14493
+ }
14494
+ if (surface.kind === 'VIEW' || surface.kind === 'READ_PROJECTION') {
14495
+ return 'visibility';
14496
+ }
14497
+ return surface.scope === 'COLLECTION' ? 'add' : 'edit_note';
14498
+ }
14085
14499
  buildStableInstanceId(surface) {
14086
14500
  return `${surface.resourceKey}.${surface.id}`.replace(/[^a-zA-Z0-9._-]+/g, '-');
14087
14501
  }
@@ -14975,6 +15389,7 @@ class ResourceActionOpenAdapterService {
14975
15389
  availability: action.availability,
14976
15390
  successMessage: action.successMessage ?? null,
14977
15391
  tags: action.tags,
15392
+ execution: action.execution ?? null,
14978
15393
  },
14979
15394
  };
14980
15395
  payload.widget.inputs = {
@@ -14982,6 +15397,15 @@ class ResourceActionOpenAdapterService {
14982
15397
  resourcePath,
14983
15398
  formId: this.buildStableInstanceId(action),
14984
15399
  mode: 'create',
15400
+ configPersistenceStrategy: 'input-first',
15401
+ layoutPolicy: {
15402
+ source: 'schema',
15403
+ intent: 'command',
15404
+ preset: 'groupedCommand',
15405
+ lifecycle: 'live',
15406
+ persistence: 'transient',
15407
+ schemaType: 'request',
15408
+ },
14985
15409
  schemaUrl: resolvedRequestSchemaUrl,
14986
15410
  apiEndpointKey: options.endpointKey ?? null,
14987
15411
  apiUrlEntry: options.apiUrlEntry ?? (discoveryOptions ? this.discovery.resolveApiEntry(discoveryOptions) : null),
@@ -14989,6 +15413,9 @@ class ResourceActionOpenAdapterService {
14989
15413
  submitUrl: resolvedSubmitUrl,
14990
15414
  responseSchemaUrl: resolvedResponseSchemaUrl,
14991
15415
  };
15416
+ if (options.initialValue) {
15417
+ payload.widget.inputs['initialValue'] = this.clone(options.initialValue);
15418
+ }
14992
15419
  if (action.scope === 'ITEM') {
14993
15420
  if (options.resourceId != null) {
14994
15421
  payload.widget.inputs['resourceId'] = options.resourceId;
@@ -15003,6 +15430,7 @@ class ResourceActionOpenAdapterService {
15003
15430
  throw new Error(`ResourceActionOpenAdapterService requires resourceId or idBindingPath for item action "${action.id}".`);
15004
15431
  }
15005
15432
  }
15433
+ this.applyExecutionInputs(payload, action, options);
15006
15434
  return payload;
15007
15435
  }
15008
15436
  resolveDynamicFormPreset() {
@@ -15015,6 +15443,49 @@ class ResourceActionOpenAdapterService {
15015
15443
  buildStableInstanceId(action) {
15016
15444
  return `${action.resourceKey}.action.${action.id}`.replace(/[^a-zA-Z0-9._-]+/g, '-');
15017
15445
  }
15446
+ applyExecutionInputs(payload, action, options) {
15447
+ const execution = action.execution;
15448
+ if (!execution) {
15449
+ payload.widget.inputs['submitIdempotencyKey'] = this.createCommandIdentity('idempotency');
15450
+ return;
15451
+ }
15452
+ const inputs = payload.widget.inputs;
15453
+ if (execution.preconditions.idempotencyKey !== 'NONE') {
15454
+ inputs['submitIdempotencyKey'] = this.createCommandIdentity('idempotency');
15455
+ }
15456
+ if (execution.preconditions.correlationId !== 'NONE') {
15457
+ inputs['submitCorrelationId'] =
15458
+ String(options.correlationId ?? '').trim() || this.createCommandIdentity('correlation');
15459
+ }
15460
+ if (execution.preconditions.resourceVersionTransport !== 'IF_MATCH') {
15461
+ return;
15462
+ }
15463
+ if (options.resourceVersion != null && String(options.resourceVersion).trim()) {
15464
+ inputs['submitResourceVersion'] = options.resourceVersion;
15465
+ return;
15466
+ }
15467
+ if (options.resourceVersionBindingPath) {
15468
+ payload.bindings = [
15469
+ ...(payload.bindings || []),
15470
+ {
15471
+ from: options.resourceVersionBindingPath,
15472
+ to: 'widget.inputs.submitResourceVersion',
15473
+ mode: 'path',
15474
+ },
15475
+ ];
15476
+ return;
15477
+ }
15478
+ if (execution.preconditions.resourceVersion === 'REQUIRED') {
15479
+ throw new Error(`ResourceActionOpenAdapterService requires resourceVersion or resourceVersionBindingPath for action "${action.id}".`);
15480
+ }
15481
+ }
15482
+ createIdempotencyKey() {
15483
+ const randomUuid = globalThis.crypto?.randomUUID?.bind(globalThis.crypto);
15484
+ return randomUuid ? randomUuid() : `praxis-action-${Date.now()}-${Math.random().toString(16).slice(2)}`;
15485
+ }
15486
+ createCommandIdentity(kind) {
15487
+ return `${kind}-${this.createIdempotencyKey()}`;
15488
+ }
15018
15489
  normalizeResourcePath(resourcePath) {
15019
15490
  return String(resourcePath || '').trim().replace(/^\/+/, '').replace(/\/+$/, '');
15020
15491
  }
@@ -15069,338 +15540,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
15069
15540
  args: [{ providedIn: 'root' }]
15070
15541
  }] });
15071
15542
 
15072
- const RELATED_RESOURCE_OUTLET_I18N_NAMESPACE = 'relatedResourceOutlet';
15073
- const RELATED_RESOURCE_OUTLET_I18N_CONFIG = {
15074
- namespaces: {
15075
- [RELATED_RESOURCE_OUTLET_I18N_NAMESPACE]: {
15076
- 'pt-BR': {
15077
- 'state.idle.title': 'Recurso relacionado não selecionado',
15078
- 'state.idle.description': 'Selecione uma surface relacionada para carregar os dados.',
15079
- 'state.resolving.title': 'Resolvendo recurso relacionado',
15080
- 'state.resolving.description': 'Validando metadados e permissões da relação.',
15081
- 'state.loading.title': 'Carregando recurso relacionado',
15082
- 'state.loading.description': 'Aguarde enquanto a coleção relacionada é carregada.',
15083
- 'state.empty.title': 'Nenhuma operação de leitura publicada',
15084
- 'state.empty.description': 'A relação existe, mas não há operação de lista ou filtro disponível.',
15085
- 'state.permission-limited.title': 'Acesso limitado',
15086
- 'state.permission-limited.description': 'O contexto atual não permite abrir este recurso relacionado.',
15087
- 'state.not-found.title': 'Relação indisponível',
15088
- 'state.not-found.description': 'Não foi possível resolver a relação ou o identificador do registro pai.',
15089
- 'state.error.title': 'Falha ao preparar recurso relacionado',
15090
- 'state.error.description': 'Ocorreu um erro ao preparar a superfície relacionada.',
15091
- 'emptyState.related.title': 'Sem registros em {label}',
15092
- 'emptyState.related.description': 'Esta coleção relacionada não possui registros para o contexto selecionado.',
15093
- 'emptyState.related.descriptionWithAction': 'Use a ação principal para adicionar um registro relacionado quando houver informações para registrar.',
15094
- 'emptyState.related.action.create': 'Adicionar registro',
15095
- 'action.open': 'Abrir relacionado',
15096
- 'status.ready': 'Recurso relacionado pronto',
15097
- },
15098
- 'en-US': {
15099
- 'state.idle.title': 'Related resource not selected',
15100
- 'state.idle.description': 'Select a related surface to load its data.',
15101
- 'state.resolving.title': 'Resolving related resource',
15102
- 'state.resolving.description': 'Validating relation metadata and permissions.',
15103
- 'state.loading.title': 'Loading related resource',
15104
- 'state.loading.description': 'Wait while the related collection is loaded.',
15105
- 'state.empty.title': 'No read operation published',
15106
- 'state.empty.description': 'The relation exists, but no list or filter operation is available.',
15107
- 'state.permission-limited.title': 'Limited access',
15108
- 'state.permission-limited.description': 'The current context cannot open this related resource.',
15109
- 'state.not-found.title': 'Relation unavailable',
15110
- 'state.not-found.description': 'The relation or parent record identifier could not be resolved.',
15111
- 'state.error.title': 'Failed to prepare related resource',
15112
- 'state.error.description': 'An error occurred while preparing the related surface.',
15113
- 'emptyState.related.title': 'No records in {label}',
15114
- 'emptyState.related.description': 'This related collection has no records for the selected context.',
15115
- 'emptyState.related.descriptionWithAction': 'Use the primary action to add a related record when there is information to capture.',
15116
- 'emptyState.related.action.create': 'Add record',
15117
- 'action.open': 'Open related',
15118
- 'status.ready': 'Related resource ready',
15119
- },
15120
- },
15121
- },
15122
- };
15123
-
15124
- class RelatedResourceSurfaceResolverService {
15125
- i18n = inject(PraxisI18nService, { optional: true });
15126
- resolve(request) {
15127
- try {
15128
- if (!request?.surface) {
15129
- return { state: 'idle', reason: 'surface-not-provided' };
15130
- }
15131
- const surface = request.surface;
15132
- if (surface.availability?.allowed === false) {
15133
- return {
15134
- state: 'permission-limited',
15135
- reason: surface.availability.reason || 'surface-not-allowed',
15136
- surface,
15137
- relatedResource: surface.relatedResource ?? null,
15138
- };
15139
- }
15140
- const relatedResource = surface.relatedResource ?? null;
15141
- if (!this.isCompleteRelatedResource(relatedResource)) {
15142
- return {
15143
- state: 'not-found',
15144
- reason: 'related-resource-not-published',
15145
- surface,
15146
- relatedResource,
15147
- };
15148
- }
15149
- if (!this.hasReadOperation(relatedResource)) {
15150
- return {
15151
- state: 'empty',
15152
- reason: 'related-resource-read-operation-not-published',
15153
- surface,
15154
- relatedResource,
15155
- };
15156
- }
15157
- const parentResourceId = this.resolveParentResourceId(request, relatedResource);
15158
- if (parentResourceId == null || parentResourceId === '') {
15159
- return {
15160
- state: 'not-found',
15161
- reason: 'parent-resource-id-not-resolved',
15162
- surface,
15163
- relatedResource,
15164
- };
15165
- }
15166
- const queryContext = this.buildQueryContext(request.queryContext, relatedResource.childParentField, parentResourceId);
15167
- const payload = this.buildPayload(surface, relatedResource, parentResourceId, queryContext, request);
15168
- return {
15169
- state: 'ready',
15170
- surface,
15171
- relatedResource,
15172
- parentResourceId,
15173
- childResourcePath: relatedResource.childResourcePath,
15174
- childResourceKey: relatedResource.childResourceKey,
15175
- queryContext,
15176
- payload,
15177
- };
15178
- }
15179
- catch (error) {
15180
- return {
15181
- state: 'error',
15182
- reason: error instanceof Error ? error.message : 'related-resource-resolution-failed',
15183
- surface: request?.surface ?? null,
15184
- relatedResource: request?.surface?.relatedResource ?? null,
15185
- };
15186
- }
15187
- }
15188
- state(state, reason) {
15189
- return { state, reason };
15190
- }
15191
- buildPayload(surface, relatedResource, parentResourceId, queryContext, request) {
15192
- const preset = SURFACE_OPEN_PRESETS.find((candidate) => candidate.id === 'praxis-table');
15193
- if (!preset) {
15194
- throw new Error('Missing canonical surface preset "praxis-table".');
15195
- }
15196
- const payload = this.clone(preset.payload);
15197
- payload.presentation = request.presentation ?? payload.presentation;
15198
- payload.title = request.title || surface.title;
15199
- payload.subtitle = request.subtitle || surface.description || undefined;
15200
- payload.icon = request.icon || payload.icon;
15201
- payload.widget.inputs = {
15202
- ...(payload.widget.inputs || {}),
15203
- configPersistenceStrategy: 'volatile',
15204
- resourcePath: this.normalizeResourcePath(relatedResource.childResourcePath),
15205
- apiEndpointKey: request.apiEndpointKey ?? null,
15206
- apiUrlEntry: request.apiUrlEntry ?? null,
15207
- tableId: request.tableId || this.buildStableTableId(surface, relatedResource, parentResourceId),
15208
- config: this.buildTableConfig(surface, relatedResource, request),
15209
- queryContext,
15210
- enableCustomization: request.enableCustomization === true,
15211
- ...(this.trim(request.authoringCapability)
15212
- ? { authoringCapability: this.trim(request.authoringCapability) }
15213
- : {}),
15214
- };
15215
- payload.context = {
15216
- ...(payload.context || {}),
15217
- resource: {
15218
- resourceKey: surface.resourceKey,
15219
- resourcePath: this.normalizeResourcePath(request.parentResourcePath || ''),
15220
- resourceId: parentResourceId,
15221
- },
15222
- surface,
15223
- relatedResource,
15224
- childResource: {
15225
- resourceKey: relatedResource.childResourceKey,
15226
- resourcePath: this.normalizeResourcePath(relatedResource.childResourcePath),
15227
- parentField: relatedResource.childParentField,
15228
- selectable: relatedResource.selectable,
15229
- selectionKeyField: relatedResource.selectionKeyField,
15230
- operations: relatedResource.childOperations,
15231
- },
15232
- };
15233
- return payload;
15234
- }
15235
- buildTableConfig(surface, relatedResource, request) {
15236
- const tableConfig = request.tableConfig;
15237
- const emptyState = request.emptyState;
15238
- const hasTableConfig = !!tableConfig && typeof tableConfig === 'object' && !Array.isArray(tableConfig);
15239
- const hasEmptyState = !!emptyState && typeof emptyState === 'object' && !Array.isArray(emptyState);
15240
- const base = hasTableConfig ? tableConfig : {};
15241
- const toolbar = this.objectValue(base['toolbar']);
15242
- const columnsVisibility = this.objectValue(toolbar['columnsVisibility']);
15243
- const behavior = this.objectValue(base['behavior']);
15244
- const currentEmptyState = this.objectValue(behavior['emptyState']);
15245
- const hasCurrentEmptyState = Object.keys(currentEmptyState).length > 0;
15246
- const resolvedEmptyState = hasEmptyState
15247
- ? {
15248
- ...currentEmptyState,
15249
- ...emptyState,
15250
- }
15251
- : hasCurrentEmptyState
15252
- ? currentEmptyState
15253
- : this.buildRelatedEmptyState(surface, relatedResource, request);
15254
- if (!hasTableConfig && !resolvedEmptyState) {
15255
- return undefined;
15256
- }
15257
- return {
15258
- ...base,
15259
- toolbar: {
15260
- ...toolbar,
15261
- columnsVisibility: {
15262
- enabled: false,
15263
- ...columnsVisibility,
15264
- },
15265
- },
15266
- behavior: {
15267
- ...behavior,
15268
- emptyState: resolvedEmptyState,
15269
- },
15270
- };
15271
- }
15272
- buildRelatedEmptyState(surface, relatedResource, request) {
15273
- const label = this.trim(request.title)
15274
- || this.trim(surface.title)
15275
- || this.humanizeResourceKey(relatedResource.childResourceKey);
15276
- const canCreate = relatedResource.childOperations.includes('CREATE');
15277
- const descriptionKey = canCreate
15278
- ? 'emptyState.related.descriptionWithAction'
15279
- : 'emptyState.related.description';
15280
- const actions = canCreate
15281
- ? [
15282
- {
15283
- label: this.t('emptyState.related.action.create', 'Adicionar registro'),
15284
- action: 'create',
15285
- icon: 'add',
15286
- primary: true,
15287
- },
15288
- ]
15289
- : [];
15290
- return {
15291
- title: this.t('emptyState.related.title', 'Sem registros em {label}', { label }),
15292
- message: this.t(descriptionKey, canCreate
15293
- ? 'Use a ação principal para adicionar um registro relacionado quando houver informações para registrar.'
15294
- : 'Esta coleção relacionada não possui registros para o contexto selecionado.', { label }),
15295
- icon: this.trim(request.icon) || 'hub',
15296
- tone: 'neutral',
15297
- variant: 'inline',
15298
- density: 'compact',
15299
- alignment: 'center',
15300
- iconContainer: 'soft',
15301
- actions,
15302
- };
15303
- }
15304
- objectValue(value) {
15305
- return value && typeof value === 'object' && !Array.isArray(value)
15306
- ? value
15307
- : {};
15308
- }
15309
- buildQueryContext(queryContext, childParentField, parentResourceId) {
15310
- return {
15311
- ...(queryContext || {}),
15312
- filters: {
15313
- ...(queryContext?.filters || {}),
15314
- [childParentField]: parentResourceId,
15315
- },
15316
- meta: {
15317
- ...(queryContext?.meta || {}),
15318
- relatedResource: true,
15319
- parentFilterField: childParentField,
15320
- },
15321
- };
15322
- }
15323
- resolveParentResourceId(request, relatedResource) {
15324
- if (request.parentResourceId != null) {
15325
- return request.parentResourceId;
15326
- }
15327
- return this.readPath(request.parentRecord, relatedResource.parentIdPathVariable);
15328
- }
15329
- readPath(record, path) {
15330
- if (!record || !path) {
15331
- return null;
15332
- }
15333
- const value = path.split('.').reduce((current, segment) => {
15334
- if (!current || typeof current !== 'object' || Array.isArray(current)) {
15335
- return undefined;
15336
- }
15337
- return current[segment];
15338
- }, record);
15339
- return typeof value === 'string' || typeof value === 'number' ? value : null;
15340
- }
15341
- isCompleteRelatedResource(relatedResource) {
15342
- return !!relatedResource
15343
- && !!this.trim(relatedResource.childResourceKey)
15344
- && !!this.trim(relatedResource.childResourcePath)
15345
- && !!this.trim(relatedResource.childParentField)
15346
- && !!this.trim(relatedResource.parentIdPathVariable)
15347
- && Array.isArray(relatedResource.childOperations);
15348
- }
15349
- hasReadOperation(relatedResource) {
15350
- return relatedResource.childOperations.includes('LIST')
15351
- || relatedResource.childOperations.includes('FILTER');
15352
- }
15353
- buildStableTableId(surface, relatedResource, parentResourceId) {
15354
- return this.sanitizeStableId(`${relatedResource.childResourceKey}.${surface.id}.${String(parentResourceId)}`);
15355
- }
15356
- normalizeResourcePath(resourcePath) {
15357
- let normalized = this.trim(resourcePath);
15358
- if (/^https?:\/\//i.test(normalized)) {
15359
- try {
15360
- normalized = new URL(normalized).pathname;
15361
- }
15362
- catch {
15363
- return '';
15364
- }
15365
- }
15366
- return normalized
15367
- .replace(/^\/+/, '')
15368
- .replace(/^(?:api\/)+/i, '')
15369
- .replace(/\/+$/, '');
15370
- }
15371
- sanitizeStableId(value) {
15372
- return value.replace(/[^a-zA-Z0-9._-]+/g, '-');
15373
- }
15374
- humanizeResourceKey(value) {
15375
- const lastSegment = this.trim(value).split(/[./_-]+/).filter(Boolean).pop() || 'registros';
15376
- return lastSegment
15377
- .replace(/([a-z])([A-Z])/g, '$1 $2')
15378
- .replace(/\s+/g, ' ')
15379
- .trim();
15380
- }
15381
- t(key, fallback, params) {
15382
- if (this.i18n) {
15383
- return this.interpolate(this.i18n.t(key, params, fallback, RELATED_RESOURCE_OUTLET_I18N_NAMESPACE), params);
15384
- }
15385
- return this.interpolate(fallback, params);
15386
- }
15387
- interpolate(template, params) {
15388
- return Object.entries(params || {}).reduce((current, [name, value]) => current.replace(new RegExp(`\\{${name}\\}`, 'g'), String(value ?? '')), template);
15389
- }
15390
- trim(value) {
15391
- return typeof value === 'string' ? value.trim() : '';
15392
- }
15393
- clone(value) {
15394
- return value == null ? value : JSON.parse(JSON.stringify(value));
15395
- }
15396
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
15397
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, providedIn: 'any' });
15398
- }
15399
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: RelatedResourceSurfaceResolverService, decorators: [{
15400
- type: Injectable,
15401
- args: [{ providedIn: 'any' }]
15402
- }] });
15403
-
15404
15543
  class SurfaceOpenMaterializerService {
15405
15544
  discovery = inject(ResourceDiscoveryService);
15406
15545
  async materialize(payload, context) {
@@ -15674,6 +15813,8 @@ class SurfaceOpenMaterializerService {
15674
15813
  path: '',
15675
15814
  schemaPath: schemaResourcePath || null,
15676
15815
  idField: this.resolveRelatedSelectionKeyField(payload),
15816
+ title: payload.title || null,
15817
+ formTitle: payload.title || null,
15677
15818
  endpointKey: previousInputs['apiEndpointKey'] ?? undefined,
15678
15819
  apiUrlEntry: previousInputs['apiUrlEntry'] ?? undefined,
15679
15820
  },
@@ -15683,12 +15824,6 @@ class SurfaceOpenMaterializerService {
15683
15824
  queryContext: null,
15684
15825
  defaults: {
15685
15826
  openMode: 'drawer',
15686
- modal: {
15687
- width: 'min(720px, 100vw)',
15688
- maxWidth: '100vw',
15689
- height: '100vh',
15690
- position: 'end',
15691
- },
15692
15827
  },
15693
15828
  actions,
15694
15829
  },
@@ -15860,8 +15995,15 @@ class SurfaceOpenMaterializerService {
15860
15995
  const previousAi = this.objectRecord(previousConfig['ai']);
15861
15996
  const previousAssistant = this.objectRecord(previousAi['assistant']);
15862
15997
  const previousBehavior = this.objectRecord(previousConfig['behavior']);
15998
+ const previousColumns = Array.isArray(previousConfig['columns'])
15999
+ ? previousConfig['columns']
16000
+ : [];
15863
16001
  const generatedConfig = {
15864
- columns: schemaColumns.length ? schemaColumns : fallbackColumns,
16002
+ columns: previousColumns.length
16003
+ ? previousColumns
16004
+ : schemaColumns.length
16005
+ ? schemaColumns
16006
+ : fallbackColumns,
15865
16007
  toolbar: toolbarActions.length
15866
16008
  ? {
15867
16009
  ...previousToolbar,
@@ -15912,12 +16054,14 @@ class SurfaceOpenMaterializerService {
15912
16054
  buildRelatedCrudActions(payload, operations, paths) {
15913
16055
  const noun = this.resolveRelatedActionNoun(payload);
15914
16056
  const formIdPrefix = this.stableSurfaceId(payload);
16057
+ const contextFields = this.buildRelatedContextFields(payload);
15915
16058
  const actions = [];
15916
16059
  if (operations.has('CREATE')) {
15917
16060
  actions.push({
15918
16061
  id: 'create',
15919
16062
  action: 'create',
15920
- label: `Novo ${noun}`,
16063
+ label: `Adicionar ${noun}`,
16064
+ tooltip: this.resolveRelatedActionDescription(payload, 'create', noun),
15921
16065
  formId: `${formIdPrefix}.create`,
15922
16066
  icon: 'add',
15923
16067
  color: 'primary',
@@ -15925,7 +16069,7 @@ class SurfaceOpenMaterializerService {
15925
16069
  position: 'end',
15926
16070
  target: { scope: 'collection' },
15927
16071
  openMode: 'drawer',
15928
- form: this.buildExplicitRelatedActionForm('create', paths),
16072
+ form: this.buildExplicitRelatedActionForm('create', paths, this.buildRelatedParentInitialValue(payload), contextFields),
15929
16073
  });
15930
16074
  }
15931
16075
  if (operations.has('UPDATE')) {
@@ -15933,6 +16077,7 @@ class SurfaceOpenMaterializerService {
15933
16077
  id: 'edit',
15934
16078
  action: 'edit',
15935
16079
  label: `Editar ${noun}`,
16080
+ tooltip: this.resolveRelatedActionDescription(payload, 'edit', noun),
15936
16081
  formId: `${formIdPrefix}.edit`,
15937
16082
  icon: 'edit',
15938
16083
  color: 'primary',
@@ -15943,14 +16088,15 @@ class SurfaceOpenMaterializerService {
15943
16088
  cardinality: { min: 1, max: 1 },
15944
16089
  },
15945
16090
  openMode: 'drawer',
15946
- form: this.buildExplicitRelatedActionForm('edit', paths),
16091
+ form: this.buildExplicitRelatedActionForm('edit', paths, undefined, contextFields),
15947
16092
  });
15948
16093
  }
15949
16094
  if (operations.has('DELETE')) {
15950
16095
  actions.push({
15951
16096
  id: 'delete',
15952
16097
  action: 'delete',
15953
- label: `Apagar ${noun}`,
16098
+ label: `Remover ${noun}`,
16099
+ tooltip: this.resolveRelatedActionDescription(payload, 'delete', noun),
15954
16100
  formId: `${formIdPrefix}.delete`,
15955
16101
  icon: 'delete',
15956
16102
  color: 'warn',
@@ -15992,7 +16138,7 @@ class SurfaceOpenMaterializerService {
15992
16138
  },
15993
16139
  };
15994
16140
  }
15995
- buildExplicitRelatedActionForm(action, paths) {
16141
+ buildExplicitRelatedActionForm(action, paths, initialValue, contextFields) {
15996
16142
  const resourcePath = this.normalizeResourcePath(paths?.resourcePath || '');
15997
16143
  const schemaResourcePath = this.normalizeResourcePath(paths?.schemaResourcePath || resourcePath);
15998
16144
  if (!resourcePath) {
@@ -16003,7 +16149,10 @@ class SurfaceOpenMaterializerService {
16003
16149
  schemaUrl: this.buildSchemaUrl(schemaResourcePath, 'post', 'request'),
16004
16150
  submitUrl: resourcePath,
16005
16151
  submitMethod: 'post',
16006
- layoutPolicy: this.buildRelatedCommandLayoutPolicy('create'),
16152
+ ...(initialValue && Object.keys(initialValue).length
16153
+ ? { initialValue }
16154
+ : {}),
16155
+ layoutPolicy: this.buildRelatedCommandLayoutPolicy('create', contextFields),
16007
16156
  };
16008
16157
  }
16009
16158
  const itemSchemaPath = schemaResourcePath ? `${schemaResourcePath}/{id}` : '';
@@ -16013,7 +16162,7 @@ class SurfaceOpenMaterializerService {
16013
16162
  schemaUrl: this.buildSchemaUrl(itemSchemaPath, 'put', 'request'),
16014
16163
  submitUrl: itemSubmitUrl,
16015
16164
  submitMethod: 'put',
16016
- layoutPolicy: this.buildRelatedCommandLayoutPolicy('update'),
16165
+ layoutPolicy: this.buildRelatedCommandLayoutPolicy('update', contextFields),
16017
16166
  };
16018
16167
  }
16019
16168
  return {
@@ -16021,7 +16170,7 @@ class SurfaceOpenMaterializerService {
16021
16170
  submitMethod: 'delete',
16022
16171
  };
16023
16172
  }
16024
- buildRelatedCommandLayoutPolicy(schemaOperation) {
16173
+ buildRelatedCommandLayoutPolicy(schemaOperation, contextFields) {
16025
16174
  return {
16026
16175
  source: 'schema',
16027
16176
  intent: 'command',
@@ -16030,6 +16179,9 @@ class SurfaceOpenMaterializerService {
16030
16179
  persistence: 'transient',
16031
16180
  schemaOperation,
16032
16181
  schemaType: 'request',
16182
+ ...(contextFields?.length
16183
+ ? { groupedCommand: { contextFields } }
16184
+ : {}),
16033
16185
  };
16034
16186
  }
16035
16187
  buildSchemaUrl(path, operation, schemaType) {
@@ -16061,6 +16213,21 @@ class SurfaceOpenMaterializerService {
16061
16213
  const relatedResource = payload.context?.['relatedResource'];
16062
16214
  return relatedResource;
16063
16215
  }
16216
+ buildRelatedParentInitialValue(payload) {
16217
+ const parentField = String(this.resolveRelatedResource(payload)?.childParentField || '').trim();
16218
+ const resource = payload.context?.['resource'];
16219
+ const parentResourceId = resource?.['resourceId'];
16220
+ if (!parentField ||
16221
+ parentResourceId == null ||
16222
+ String(parentResourceId).trim() === '') {
16223
+ return undefined;
16224
+ }
16225
+ return { [parentField]: parentResourceId };
16226
+ }
16227
+ buildRelatedContextFields(payload) {
16228
+ const parentField = String(this.resolveRelatedResource(payload)?.childParentField || '').trim();
16229
+ return parentField ? [parentField] : [];
16230
+ }
16064
16231
  resolveRelatedSelectionKeyField(payload) {
16065
16232
  const relatedResource = this.resolveRelatedResource(payload);
16066
16233
  const field = String(relatedResource?.selectionKeyField || '').trim();
@@ -16097,22 +16264,42 @@ class SurfaceOpenMaterializerService {
16097
16264
  ]
16098
16265
  .map((value) => String(value || '').trim())
16099
16266
  .find(Boolean) || '';
16100
- const normalized = source
16101
- .normalize('NFD')
16102
- .replace(/[\u0300-\u036f]/g, '')
16103
- .toLowerCase();
16104
- if (/\b(documentos?|documents?)\b/.test(normalized)) {
16105
- return 'documento';
16106
- }
16107
- const firstToken = normalized
16108
- .split(/[^a-z0-9]+/)
16267
+ const firstToken = source
16268
+ .split(/[^\p{L}\p{N}]+/u)
16109
16269
  .filter(Boolean)
16110
- .find((token) => !['de', 'da', 'do', 'das', 'dos', 'legal', 'legais'].includes(token));
16111
- if (firstToken && firstToken.length > 3) {
16112
- return firstToken.endsWith('s') ? firstToken.slice(0, -1) : firstToken;
16270
+ .find((token) => !['de', 'da', 'do', 'das', 'dos'].includes(token.toLocaleLowerCase('pt-BR')));
16271
+ if (firstToken && firstToken.length > 2) {
16272
+ return this.singularizePtBrWord(firstToken).toLocaleLowerCase('pt-BR');
16113
16273
  }
16114
16274
  return 'item';
16115
16275
  }
16276
+ singularizePtBrWord(word) {
16277
+ if (/ções$/iu.test(word))
16278
+ return word.replace(/ções$/iu, 'ção');
16279
+ if (/ões$/iu.test(word))
16280
+ return word.replace(/ões$/iu, 'ão');
16281
+ if (/ais$/iu.test(word))
16282
+ return word.replace(/ais$/iu, 'al');
16283
+ if (/eis$/iu.test(word))
16284
+ return word.replace(/eis$/iu, 'el');
16285
+ if (/res$/iu.test(word))
16286
+ return word.replace(/es$/iu, '');
16287
+ if (/s$/iu.test(word) && !/ss$/iu.test(word))
16288
+ return word.replace(/s$/iu, '');
16289
+ return word;
16290
+ }
16291
+ resolveRelatedActionDescription(payload, action, noun) {
16292
+ const surfaceDescription = String(payload.subtitle
16293
+ || payload.context?.['surface']?.['description']
16294
+ || '').trim();
16295
+ if (surfaceDescription)
16296
+ return surfaceDescription;
16297
+ if (action === 'create')
16298
+ return `Adicione ${noun} ao contexto selecionado.`;
16299
+ if (action === 'edit')
16300
+ return `Atualize os dados de ${noun} no contexto selecionado.`;
16301
+ return `Remova ${noun} do contexto selecionado.`;
16302
+ }
16116
16303
  inferColumnsFromData(data) {
16117
16304
  const first = data.find((item) => item && typeof item === 'object' && !Array.isArray(item));
16118
16305
  if (!first || typeof first !== 'object')
@@ -18821,6 +19008,10 @@ const PRAXIS_GLOBAL_ACTION_CATALOG = [
18821
19008
  type: 'object',
18822
19009
  description: 'Ação estruturada executada quando a surface emite um resultado semântico via surface.result.',
18823
19010
  },
19011
+ lifecycle: {
19012
+ type: 'object',
19013
+ description: 'Política declarativa que converte outputs públicos do widget em outcomes de notificação, conclusão, cancelamento ou falha.',
19014
+ },
18824
19015
  },
18825
19016
  required: ['presentation', 'widget'],
18826
19017
  example: {
@@ -18869,6 +19060,22 @@ const PRAXIS_GLOBAL_ACTION_CATALOG = [
18869
19060
  example: { type: 'selection', data: { id: 42 } },
18870
19061
  },
18871
19062
  },
19063
+ {
19064
+ id: 'surface.complete',
19065
+ label: 'Concluir Surface',
19066
+ icon: 'task_alt',
19067
+ description: 'Publica um resultado terminal e fecha a surface atual atomicamente, garantindo uma única conclusão.',
19068
+ payloadSchema: {
19069
+ type: 'object',
19070
+ properties: {
19071
+ kind: { type: 'string', description: 'Tipo de outcome terminal; normalmente completed.' },
19072
+ type: { type: 'string', description: 'Tipo semântico da conclusão.' },
19073
+ data: { type: 'object', description: 'Dados devolvidos ao owner da surface.' },
19074
+ },
19075
+ required: ['type'],
19076
+ example: { kind: 'completed', type: 'save', data: { id: 42 } },
19077
+ },
19078
+ },
18872
19079
  {
18873
19080
  id: 'dynamicPage.composition.dispatch',
18874
19081
  label: 'Despachar Evento de Composição',
@@ -19161,6 +19368,91 @@ function providePraxisHttpCollectionExportProvider(options = {}) {
19161
19368
  ];
19162
19369
  }
19163
19370
 
19371
+ const TEXT_DESCRIPTOR_KEYS = new Set(['key', 'text', 'params']);
19372
+ /**
19373
+ * Resolves explicit `PraxisTextValue` descriptors in a JSON-like authored
19374
+ * document without mutating the canonical source document.
19375
+ *
19376
+ * Plain strings are intentionally preserved: host-owned business copy only
19377
+ * becomes locale-aware when the author supplies an explicit descriptor.
19378
+ */
19379
+ function resolvePraxisI18nDocument(document, options) {
19380
+ const locale = normalizedLocale(options.locale) ||
19381
+ normalizedLocale(options.config?.locale) ||
19382
+ options.i18n.getLocale();
19383
+ const fallbackLocale = normalizedLocale(options.config?.fallbackLocale) ||
19384
+ options.i18n.getFallbackLocale();
19385
+ const ancestors = new Set();
19386
+ const visit = (value) => {
19387
+ if (isPraxisI18nMessageDescriptor(value)) {
19388
+ return resolveDescriptor(value, locale, fallbackLocale, options);
19389
+ }
19390
+ if (Array.isArray(value)) {
19391
+ if (ancestors.has(value))
19392
+ return value;
19393
+ ancestors.add(value);
19394
+ try {
19395
+ return value.map(visit);
19396
+ }
19397
+ finally {
19398
+ ancestors.delete(value);
19399
+ }
19400
+ }
19401
+ if (!isPlainRecord(value)) {
19402
+ return value;
19403
+ }
19404
+ if (ancestors.has(value))
19405
+ return value;
19406
+ ancestors.add(value);
19407
+ try {
19408
+ return Object.fromEntries(Object.entries(value).map(([key, nestedValue]) => [
19409
+ key,
19410
+ visit(nestedValue),
19411
+ ]));
19412
+ }
19413
+ finally {
19414
+ ancestors.delete(value);
19415
+ }
19416
+ };
19417
+ return visit(document);
19418
+ }
19419
+ function isPraxisI18nMessageDescriptor(value) {
19420
+ if (!isPlainRecord(value))
19421
+ return false;
19422
+ const keys = Object.keys(value);
19423
+ if (!keys.length || keys.some((key) => !TEXT_DESCRIPTOR_KEYS.has(key))) {
19424
+ return false;
19425
+ }
19426
+ const key = value['key'];
19427
+ const text = value['text'];
19428
+ const params = value['params'];
19429
+ return (((typeof key === 'string' && !!key.trim()) ||
19430
+ (typeof text === 'string' && !!text)) &&
19431
+ (params == null || isPlainRecord(params)));
19432
+ }
19433
+ function resolveDescriptor(descriptor, locale, fallbackLocale, options) {
19434
+ const key = descriptor.key?.trim();
19435
+ if (!key) {
19436
+ return options.i18n.resolve(descriptor, descriptor.text, options.namespace);
19437
+ }
19438
+ const pageMessage = options.config?.dictionaries?.[locale]?.[key] ??
19439
+ options.config?.dictionaries?.[fallbackLocale]?.[key];
19440
+ if (pageMessage != null) {
19441
+ return interpolatePraxisTranslation(pageMessage, descriptor.params);
19442
+ }
19443
+ return options.i18n.tForLocale(locale, key, descriptor.params, descriptor.text, options.namespace);
19444
+ }
19445
+ function normalizedLocale(value) {
19446
+ const normalized = value?.trim();
19447
+ return normalized || undefined;
19448
+ }
19449
+ function isPlainRecord(value) {
19450
+ if (!value || typeof value !== 'object' || Array.isArray(value))
19451
+ return false;
19452
+ const prototype = Object.getPrototypeOf(value);
19453
+ return prototype === Object.prototype || prototype === null;
19454
+ }
19455
+
19164
19456
  const RESOURCE_DISCOVERY_I18N_NAMESPACE = 'resourceDiscovery';
19165
19457
  const RESOURCE_AVAILABILITY_REASON_KEY_BY_CODE = {
19166
19458
  'resource-state-blocked': 'availability.reason.resource-state-blocked',
@@ -19869,6 +20161,10 @@ function normalizeSelectLike(meta) {
19869
20161
  }
19870
20162
 
19871
20163
  const SERVER_OWNED_FIELD_SEMANTIC_KEYS = [
20164
+ 'disabled',
20165
+ 'readOnly',
20166
+ 'editable',
20167
+ 'fieldAccess',
19872
20168
  'label',
19873
20169
  'hint',
19874
20170
  'helpText',
@@ -23189,6 +23485,7 @@ function normalizeLayoutPolicy(policy) {
23189
23485
  ? {
23190
23486
  orphanFieldExpansion: policy?.groupedCommand?.orphanFieldExpansion ??
23191
23487
  'medium-and-wide',
23488
+ contextFields: normalizeFieldNameList(policy?.groupedCommand?.contextFields),
23192
23489
  }
23193
23490
  : policy?.groupedCommand,
23194
23491
  };
@@ -23466,6 +23763,12 @@ function spanForColumns(columns) {
23466
23763
  return Math.max(1, Math.min(12, Math.floor(12 / columns)));
23467
23764
  }
23468
23765
  function fieldsForPolicy(fields, policy) {
23766
+ if (policy.preset === 'groupedCommand') {
23767
+ const contextFields = groupedCommandContextFields(policy);
23768
+ return fields.map((field) => contextFields.has(field.name)
23769
+ ? { ...field, formHidden: true, hidden: true }
23770
+ : field);
23771
+ }
23469
23772
  if (policy.preset !== 'compactPresentation') {
23470
23773
  return fields;
23471
23774
  }
@@ -23484,11 +23787,23 @@ function fieldsForPolicy(fields, policy) {
23484
23787
  }));
23485
23788
  }
23486
23789
  function fieldsForLayoutPolicy(fields, policy) {
23790
+ if (policy.preset === 'groupedCommand') {
23791
+ const contextFields = groupedCommandContextFields(policy);
23792
+ return fields.filter((field) => !contextFields.has(field.name));
23793
+ }
23487
23794
  if (policy.preset !== 'compactPresentation') {
23488
23795
  return fields;
23489
23796
  }
23490
23797
  return resolveDetailSummaryFields(fields, policy);
23491
23798
  }
23799
+ function groupedCommandContextFields(policy) {
23800
+ return new Set(normalizeFieldNameList(policy.groupedCommand?.contextFields));
23801
+ }
23802
+ function normalizeFieldNameList(value) {
23803
+ return Array.from(new Set((value || [])
23804
+ .map((fieldName) => String(fieldName || '').trim())
23805
+ .filter(Boolean)));
23806
+ }
23492
23807
  function resolvePresentationFields(fields) {
23493
23808
  return fields.filter((field) => !isFormHidden(field));
23494
23809
  }
@@ -26613,157 +26928,920 @@ const ENUMS = {
26613
26928
  railSide: ['left', 'right'],
26614
26929
  deviceKind: ['desktop', 'tablet', 'mobile'],
26615
26930
  stateMergeStrategy: ['replace', 'merge', 'append', 'remove-keys'],
26616
- derivedStateComputeKind: ['json-logic', 'template', 'operator', 'transformer'],
26931
+ derivedStateComputeKind: [
26932
+ 'json-logic',
26933
+ 'template',
26934
+ 'operator',
26935
+ 'transformer',
26936
+ ],
26617
26937
  shellKind: ['dashboard-card', 'none'],
26618
26938
  actionVariant: ['icon', 'text', 'outlined'],
26619
26939
  actionPlacement: ['header', 'window'],
26620
26940
  };
26621
26941
  const CAPS = [
26622
- { path: 'page', category: 'page', valueKind: 'object', description: 'Definição da página dinâmica.' },
26623
- { path: 'page.context', category: 'context', valueKind: 'object', description: 'Contexto compartilhado entre widgets.' },
26624
- { path: 'page.layoutPreset', category: 'layout', valueKind: 'string', description: 'ID canônico opcional do preset estrutural da página.' },
26625
- { path: 'page.layoutPresetOptions', category: 'layout', valueKind: 'object', description: 'Opções específicas do preset estrutural consumidas por builders e runtimes futuros.' },
26626
- { path: 'page.themePreset', category: 'appearance', valueKind: 'string', description: 'ID opcional do preset de tema para shell, gráficos, densidade e defaults visuais.' },
26627
- { path: 'page.layout', category: 'layout', valueKind: 'object', description: 'Layout base da página.' },
26628
- { path: 'page.layout.orientation', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.layoutOrientation, description: 'Orientacao do grid (vertical/columns).' },
26629
- { path: 'page.layout.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas (quando orientation=columns).' },
26630
- { path: 'page.layout.gap', category: 'layout', valueKind: 'string', description: 'Gap entre widgets (ex: 16px).' },
26631
- { path: 'page.layout.breakpoints', category: 'layout', valueKind: 'object', description: 'Colunas por breakpoint.' },
26632
- { path: 'page.layout.breakpoints.sm', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint sm.' },
26633
- { path: 'page.layout.breakpoints.md', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint md.' },
26634
- { path: 'page.layout.breakpoints.lg', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint lg.' },
26635
- { path: 'page.layout.breakpoints.xl', category: 'layout', valueKind: 'number', description: 'Colunas para breakpoint xl.' },
26636
- { path: 'page.canvas', category: 'layout', valueKind: 'object', description: 'Canvas espacial canônico da página quando houver geometria explícita.' },
26637
- { path: 'page.canvas.mode', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.canvasMode, description: 'Modo canonico do canvas. Valor atual: grid.' },
26638
- { path: 'page.canvas.columns', category: 'layout', valueKind: 'number', description: 'Numero de colunas do canvas espacial.' },
26639
- { path: 'page.canvas.rowUnit', category: 'layout', valueKind: 'string', description: 'Altura base das linhas do canvas, como 80px.' },
26640
- { path: 'page.canvas.gap', category: 'layout', valueKind: 'string', description: 'Espacamento entre itens do canvas.' },
26641
- { path: 'page.canvas.autoRows', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.canvasAutoRows, description: 'Politica de linhas automaticas do canvas.' },
26642
- { path: 'page.canvas.collisionPolicy', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.canvasCollisionPolicy, description: 'Politica de colisao do canvas espacial.' },
26643
- { path: 'page.canvas.items', category: 'layout', valueKind: 'object', description: 'Mapa canonico de geometria por widget key.' },
26644
- { path: 'page.canvas.items.<widgetKey>.col', category: 'layout', valueKind: 'number', description: 'Coluna inicial do widget no canvas.' },
26645
- { path: 'page.canvas.items.<widgetKey>.row', category: 'layout', valueKind: 'number', description: 'Linha inicial do widget no canvas.' },
26646
- { path: 'page.canvas.items.<widgetKey>.colSpan', category: 'layout', valueKind: 'number', description: 'Quantidade de colunas ocupadas pelo widget.' },
26647
- { path: 'page.canvas.items.<widgetKey>.rowSpan', category: 'layout', valueKind: 'number', description: 'Quantidade de linhas ocupadas pelo widget.' },
26648
- { path: 'page.canvas.items.<widgetKey>.zIndex', category: 'layout', valueKind: 'number', description: 'Camada opcional do item no canvas.' },
26649
- { path: 'page.canvas.items.<widgetKey>.constraints', category: 'layout', valueKind: 'object', description: 'Restricoes opcionais de posicao e tamanho do item no canvas.' },
26650
- { path: 'page.canvas.items.<widgetKey>.constraints.minColSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de colunas permitido.' },
26651
- { path: 'page.canvas.items.<widgetKey>.constraints.minRowSpan', category: 'layout', valueKind: 'number', description: 'Span mínimo de linhas permitido.' },
26652
- { path: 'page.canvas.items.<widgetKey>.constraints.maxColSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de colunas permitido.' },
26653
- { path: 'page.canvas.items.<widgetKey>.constraints.maxRowSpan', category: 'layout', valueKind: 'number', description: 'Span máximo de linhas permitido.' },
26654
- { path: 'page.canvas.items.<widgetKey>.constraints.lockPosition', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de posicao do item no canvas.' },
26655
- { path: 'page.canvas.items.<widgetKey>.constraints.lockSize', category: 'layout', valueKind: 'boolean', description: 'Bloqueia alteracao de tamanho do item no canvas.' },
26656
- { path: 'page.widgets', category: 'widgets', valueKind: 'array', description: 'Lista de widgets renderizados.' },
26657
- { path: 'page.widgets[].key', category: 'widgets', valueKind: 'string', description: 'Identificador unico do widget.' },
26658
- { path: 'page.widgets[].className', category: 'widgets', valueKind: 'string', description: 'Classe CSS opcional do widget.' },
26659
- { path: 'page.widgets[].definition.id', category: 'widgets', valueKind: 'string', description: 'ID do componente do widget (ex: praxis-table).' },
26660
- { path: 'page.widgets[].definition.inputs', category: 'widgets', valueKind: 'object', description: 'Inputs iniciais do widget.' },
26661
- { 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.' },
26662
- { 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.' },
26663
- { 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.' },
26664
- { 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.' },
26665
- { path: 'page.widgets[].definition.bindingOrder', category: 'widgets', valueKind: 'array', description: 'Ordem de binding de inputs.' },
26666
- { path: 'page.widgets[].shell', category: 'shell', valueKind: 'object', description: 'Configuração do shell do widget.' },
26667
- { path: 'page.widgets[].shell.kind', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.shellKind, description: 'Tipo de shell.' },
26668
- { path: 'page.widgets[].shell.title', category: 'shell', valueKind: 'string', description: 'Título do shell.' },
26669
- { path: 'page.widgets[].shell.subtitle', category: 'shell', valueKind: 'string', description: 'Subtítulo do shell.' },
26670
- { path: 'page.widgets[].shell.icon', category: 'shell', valueKind: 'string', description: 'Ícone do shell.' },
26671
- { path: 'page.widgets[].shell.showHeader', category: 'shell', valueKind: 'boolean', description: 'Exibe o header do shell.' },
26672
- { path: 'page.widgets[].shell.actions', category: 'shell', valueKind: 'array', description: 'Ações do shell.' },
26673
- { path: 'page.widgets[].shell.actions[].id', category: 'shell', valueKind: 'string', description: 'ID da ação.' },
26674
- { path: 'page.widgets[].shell.actions[].label', category: 'shell', valueKind: 'string', description: 'Label da ação.' },
26675
- { path: 'page.widgets[].shell.actions[].icon', category: 'shell', valueKind: 'string', description: 'Ícone da ação.' },
26676
- { path: 'page.widgets[].shell.actions[].variant', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionVariant, description: 'Estilo visual da ação.' },
26677
- { path: 'page.widgets[].shell.actions[].placement', category: 'shell', valueKind: 'enum', allowedValues: ENUMS.actionPlacement, description: 'Posicionamento da ação.' },
26678
- { path: 'page.widgets[].shell.actions[].emit', category: 'shell', valueKind: 'string', description: 'Evento emitido ao acionar a ação.' },
26679
- { path: 'page.state', category: 'state', valueKind: 'object', description: 'Estado declarativo opcional compartilhado por widgets e composicao.' },
26680
- { path: 'page.state.values', category: 'state', valueKind: 'object', description: 'Valores primarios mutaveis escritos por widgets, defaults ou host.' },
26681
- { path: 'page.state.schema', category: 'state', valueKind: 'object', description: 'Descritores dos paths primarios de estado.' },
26682
- { path: 'page.state.schema.<token>.type', category: 'state', valueKind: 'string', description: 'Tipo semantico opcional do path de estado.' },
26683
- { path: 'page.state.schema.<token>.initial', category: 'state', valueKind: 'object', description: 'Valor inicial usado quando page.state.values omite o path.' },
26684
- { path: 'page.state.schema.<token>.persist', category: 'state', valueKind: 'boolean', description: 'Indica se o path primário deve ser persistido com a página.' },
26685
- { path: 'page.state.schema.<token>.mergeStrategy', category: 'state', valueKind: 'enum', allowedValues: ENUMS.stateMergeStrategy, description: 'Como escritas de widget/estado combinam com o valor atual.' },
26686
- { path: 'page.state.schema.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do path para builders e catálogos AI.' },
26687
- { path: 'page.state.schema.<token>.tags', category: 'state', valueKind: 'array', description: 'Tags opcionais para busca e governanca do estado.' },
26688
- { path: 'page.state.derived', category: 'state', valueKind: 'object', description: 'Descritores de estado derivado recomputado pelo runtime.' },
26689
- { path: 'page.state.derived.<token>.dependsOn', category: 'state', valueKind: 'array', description: 'Paths de estado que alimentam o valor derivado.' },
26690
- { path: 'page.state.derived.<token>.compute', category: 'state', valueKind: 'object', description: 'Descritor de computacao do estado derivado.' },
26691
- { path: 'page.state.derived.<token>.compute.kind', category: 'state', valueKind: 'enum', allowedValues: ENUMS.derivedStateComputeKind, description: 'Tipo de computacao do estado derivado.' },
26692
- { path: 'page.state.derived.<token>.compute.expression', category: 'state', valueKind: 'expression', description: 'Expressao Json Logic para compute.kind=json-logic.' },
26693
- { path: 'page.state.derived.<token>.compute.value', category: 'state', valueKind: 'object', description: 'Valor template para compute.kind=template.' },
26694
- { path: 'page.state.derived.<token>.compute.operator', category: 'state', valueKind: 'string', description: 'Operador para compute.kind=operator.' },
26695
- { path: 'page.state.derived.<token>.compute.options', category: 'state', valueKind: 'object', description: 'Opções do operador ou transformer.' },
26696
- { path: 'page.state.derived.<token>.compute.transformerId', category: 'state', valueKind: 'string', description: 'Identificador do transformer para compute.kind=transformer.' },
26697
- { path: 'page.state.derived.<token>.description', category: 'state', valueKind: 'string', description: 'Descrição opcional do estado derivado.' },
26698
- { path: 'page.state.derived.<token>.cache', category: 'state', valueKind: 'boolean', description: 'Permite cache futuro do valor derivado.' },
26699
- { path: 'page.composition', category: 'connections', valueKind: 'object', description: 'Envelope canonico da composicao persistida.' },
26700
- { path: 'page.composition.version', category: 'connections', valueKind: 'string', description: 'Versao do envelope de composicao.' },
26701
- { path: 'page.composition.links', category: 'connections', valueKind: 'array', description: 'Links canonicos entre widgets, estado e actions globais.' },
26702
- { path: 'page.composition.links[].id', category: 'connections', valueKind: 'string', description: 'Identificador estavel do link.' },
26703
- { path: 'page.composition.links[].from', category: 'connections', valueKind: 'object', description: 'Endpoint de origem do link.' },
26704
- { path: 'page.composition.links[].from.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de origem, como component-port ou state.' },
26705
- { path: 'page.composition.links[].from.ref', category: 'connections', valueKind: 'object', description: 'Referencia estruturada do endpoint de origem.' },
26706
- { path: 'page.composition.links[].from.ref.widget', category: 'connections', valueKind: 'string', description: 'Widget top-level dono do endpoint de origem.' },
26707
- { path: 'page.composition.links[].from.ref.port', category: 'connections', valueKind: 'string', description: 'Porta de origem do componente.' },
26708
- { path: 'page.composition.links[].from.ref.direction', category: 'connections', valueKind: 'string', description: 'Direcao da porta de origem.' },
26709
- { path: 'page.composition.links[].from.ref.nestedPath', category: 'connections', valueKind: 'array', description: 'NestedPath canonico para porta de componente filho de origem.' },
26710
- { path: 'page.composition.links[].from.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de origem.' },
26711
- { path: 'page.composition.links[].from.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de origem.' },
26712
- { 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 },
26713
- { 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.' },
26714
- { path: 'page.composition.links[].from.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de origem.' },
26715
- { path: 'page.composition.links[].to', category: 'connections', valueKind: 'object', description: 'Endpoint de destino do link.' },
26716
- { path: 'page.composition.links[].to.kind', category: 'connections', valueKind: 'string', description: 'Tipo do endpoint de destino, como component-port, state ou global-action.' },
26717
- { path: 'page.composition.links[].to.ref', category: 'connections', valueKind: 'object', description: 'Referencia estruturada do endpoint de destino.' },
26718
- { path: 'page.composition.links[].to.ref.[actionId]', category: 'connections', valueKind: 'string', description: 'ID da action global quando to.kind = global-action.' },
26719
- { path: 'page.composition.links[].to.ref.payload', category: 'connections', valueKind: 'object', description: 'Payload fixo opcional da action global; quando omitido, o runtime entrega o valor transformado do link.' },
26720
- { path: 'page.composition.links[].to.ref.payloadExpr', category: 'connections', valueKind: 'expression', description: 'Expressao opcional de payload da action global suportada pelo GlobalActionService.' },
26721
- { path: 'page.composition.links[].to.ref.widget', category: 'connections', valueKind: 'string', description: 'Widget top-level dono do endpoint de destino.' },
26722
- { path: 'page.composition.links[].to.ref.port', category: 'connections', valueKind: 'string', description: 'Porta de destino do componente.' },
26723
- { path: 'page.composition.links[].to.ref.direction', category: 'connections', valueKind: 'string', description: 'Direcao da porta de destino.' },
26724
- { path: 'page.composition.links[].to.ref.nestedPath', category: 'connections', valueKind: 'array', description: 'NestedPath canonico para porta de componente filho de destino.' },
26725
- { path: 'page.composition.links[].to.ref.nestedPath[].kind', category: 'connections', valueKind: 'string', description: 'Tipo do segmento nested de destino.' },
26726
- { path: 'page.composition.links[].to.ref.nestedPath[].id', category: 'connections', valueKind: 'string', description: 'Identificador estrutural do segmento nested de destino.' },
26727
- { 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 },
26728
- { 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.' },
26729
- { path: 'page.composition.links[].to.ref.nestedPath[].componentType', category: 'connections', valueKind: 'string', description: 'Tipo do componente real do widget filho de destino.' },
26730
- { path: 'page.composition.links[].intent', category: 'connections', valueKind: 'string', description: 'Intenção semântica do link.' },
26731
- { path: 'page.composition.links[].transform', category: 'connections', valueKind: 'object', description: 'Pipeline de transformacao do link.' },
26732
- { 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.' },
26733
- { path: 'page.composition.links[].policy', category: 'connections', valueKind: 'object', description: 'Politicas operacionais opcionais do link, como debounce, distinct e missing-value.' },
26734
- { path: 'page.composition.links[].metadata', category: 'connections', valueKind: 'object', description: 'Metadados opcionais do link.' },
26735
- { path: 'page.grouping', category: 'layout', valueKind: 'array', description: 'Modelo semantico opcional de secoes, abas, areas hero e rails.' },
26736
- { path: 'page.grouping[].kind', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.groupingKind, description: 'Tipo do agrupamento semantico.' },
26737
- { path: 'page.grouping[].id', category: 'layout', valueKind: 'string', description: 'Identificador estavel do agrupamento.' },
26738
- { path: 'page.grouping[].label', category: 'layout', valueKind: 'string', description: 'Rotulo opcional do agrupamento.' },
26739
- { path: 'page.grouping[].widgetKeys', category: 'layout', valueKind: 'array', description: 'Widgets pertencentes ao agrupamento section, hero ou rail.' },
26740
- { path: 'page.grouping[].layout', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.groupingLayout, description: 'Layout opcional para agrupamento section.' },
26741
- { path: 'page.grouping[].tabs', category: 'layout', valueKind: 'array', description: 'Abas do agrupamento kind=tabs.' },
26742
- { path: 'page.grouping[].tabs[].id', category: 'layout', valueKind: 'string', description: 'Identificador estavel da aba.' },
26743
- { path: 'page.grouping[].tabs[].label', category: 'layout', valueKind: 'string', description: 'Rotulo da aba.' },
26744
- { path: 'page.grouping[].tabs[].widgetKeys', category: 'layout', valueKind: 'array', description: 'Widgets renderizados dentro da aba.' },
26745
- { path: 'page.grouping[].emphasis', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.heroEmphasis, description: 'Enfase opcional para agrupamento hero.' },
26746
- { path: 'page.grouping[].side', category: 'layout', valueKind: 'enum', allowedValues: ENUMS.railSide, description: 'Lado do rail quando kind=rail.' },
26747
- { path: 'page.slotAssignments', category: 'layout', valueKind: 'object', description: 'Mapa canonico de widget key para slot semantico de preset.' },
26748
- { path: 'page.deviceLayouts', category: 'layout', valueKind: 'object', description: 'Variantes opcionais de layout por dispositivo.' },
26749
- { path: 'page.deviceLayouts.desktop', category: 'layout', valueKind: 'object', description: 'Overrides de layout para desktop.' },
26750
- { path: 'page.deviceLayouts.tablet', category: 'layout', valueKind: 'object', description: 'Overrides de layout para tablet.' },
26751
- { path: 'page.deviceLayouts.mobile', category: 'layout', valueKind: 'object', description: 'Overrides de layout para mobile.' },
26752
- { path: 'page.deviceLayouts.desktop.layout', category: 'layout', valueKind: 'object', description: 'Override de WidgetPageLayout para desktop.' },
26753
- { path: 'page.deviceLayouts.desktop.canvas', category: 'layout', valueKind: 'object', description: 'Override de canvas para desktop.' },
26754
- { path: 'page.deviceLayouts.desktop.groupingOverrides', category: 'layout', valueKind: 'array', description: 'Overrides de agrupamentos para desktop.' },
26755
- { path: 'page.deviceLayouts.desktop.widgetOverrides', category: 'layout', valueKind: 'object', description: 'Overrides por widget key para desktop.' },
26756
- { path: 'page.deviceLayouts.desktop.widgetOverrides.<widgetKey>.hidden', category: 'layout', valueKind: 'boolean', description: 'Oculta o widget em desktop.' },
26757
- { path: 'page.deviceLayouts.tablet.layout', category: 'layout', valueKind: 'object', description: 'Override de WidgetPageLayout para tablet.' },
26758
- { path: 'page.deviceLayouts.tablet.canvas', category: 'layout', valueKind: 'object', description: 'Override de canvas para tablet.' },
26759
- { path: 'page.deviceLayouts.tablet.groupingOverrides', category: 'layout', valueKind: 'array', description: 'Overrides de agrupamentos para tablet.' },
26760
- { path: 'page.deviceLayouts.tablet.widgetOverrides', category: 'layout', valueKind: 'object', description: 'Overrides por widget key para tablet.' },
26761
- { path: 'page.deviceLayouts.tablet.widgetOverrides.<widgetKey>.hidden', category: 'layout', valueKind: 'boolean', description: 'Oculta o widget em tablet.' },
26762
- { path: 'page.deviceLayouts.mobile.layout', category: 'layout', valueKind: 'object', description: 'Override de WidgetPageLayout para mobile.' },
26763
- { path: 'page.deviceLayouts.mobile.canvas', category: 'layout', valueKind: 'object', description: 'Override de canvas para mobile.' },
26764
- { path: 'page.deviceLayouts.mobile.groupingOverrides', category: 'layout', valueKind: 'array', description: 'Overrides de agrupamentos para mobile.' },
26765
- { path: 'page.deviceLayouts.mobile.widgetOverrides', category: 'layout', valueKind: 'object', description: 'Overrides por widget key para mobile.' },
26766
- { path: 'page.deviceLayouts.mobile.widgetOverrides.<widgetKey>.hidden', category: 'layout', valueKind: 'boolean', description: 'Oculta o widget em mobile.' },
26942
+ {
26943
+ path: 'page',
26944
+ category: 'page',
26945
+ valueKind: 'object',
26946
+ description: 'Definição da página dinâmica.',
26947
+ },
26948
+ {
26949
+ path: 'page.context',
26950
+ category: 'context',
26951
+ valueKind: 'object',
26952
+ description: 'Contexto compartilhado entre widgets.',
26953
+ },
26954
+ {
26955
+ path: 'page.i18n',
26956
+ category: 'localization',
26957
+ valueKind: 'object',
26958
+ description: 'Catálogo de copy de negócio da página, resolvido apenas na projeção runtime.',
26959
+ },
26960
+ {
26961
+ path: 'page.i18n.fallbackLocale',
26962
+ category: 'localization',
26963
+ valueKind: 'string',
26964
+ description: 'Locale de fallback do catálogo próprio da página.',
26965
+ },
26966
+ {
26967
+ path: 'page.i18n.dictionaries',
26968
+ category: 'localization',
26969
+ valueKind: 'object',
26970
+ description: 'Dicionários locale -> chave semântica -> texto usados por descritores PraxisTextValue explícitos.',
26971
+ },
26972
+ {
26973
+ path: 'page.layoutPreset',
26974
+ category: 'layout',
26975
+ valueKind: 'string',
26976
+ description: 'ID canônico opcional do preset estrutural da página.',
26977
+ },
26978
+ {
26979
+ path: 'page.layoutPresetOptions',
26980
+ category: 'layout',
26981
+ valueKind: 'object',
26982
+ description: 'Opções específicas do preset estrutural consumidas por builders e runtimes futuros.',
26983
+ },
26984
+ {
26985
+ path: 'page.themePreset',
26986
+ category: 'appearance',
26987
+ valueKind: 'string',
26988
+ description: 'ID opcional do preset de tema para shell, gráficos, densidade e defaults visuais.',
26989
+ },
26990
+ {
26991
+ path: 'page.layout',
26992
+ category: 'layout',
26993
+ valueKind: 'object',
26994
+ description: 'Layout base da página.',
26995
+ },
26996
+ {
26997
+ path: 'page.layout.orientation',
26998
+ category: 'layout',
26999
+ valueKind: 'enum',
27000
+ allowedValues: ENUMS.layoutOrientation,
27001
+ description: 'Orientacao do grid (vertical/columns).',
27002
+ },
27003
+ {
27004
+ path: 'page.layout.columns',
27005
+ category: 'layout',
27006
+ valueKind: 'number',
27007
+ description: 'Numero de colunas (quando orientation=columns).',
27008
+ },
27009
+ {
27010
+ path: 'page.layout.gap',
27011
+ category: 'layout',
27012
+ valueKind: 'string',
27013
+ description: 'Gap entre widgets (ex: 16px).',
27014
+ },
27015
+ {
27016
+ path: 'page.layout.breakpoints',
27017
+ category: 'layout',
27018
+ valueKind: 'object',
27019
+ description: 'Colunas por breakpoint.',
27020
+ },
27021
+ {
27022
+ path: 'page.layout.breakpoints.sm',
27023
+ category: 'layout',
27024
+ valueKind: 'number',
27025
+ description: 'Colunas para breakpoint sm.',
27026
+ },
27027
+ {
27028
+ path: 'page.layout.breakpoints.md',
27029
+ category: 'layout',
27030
+ valueKind: 'number',
27031
+ description: 'Colunas para breakpoint md.',
27032
+ },
27033
+ {
27034
+ path: 'page.layout.breakpoints.lg',
27035
+ category: 'layout',
27036
+ valueKind: 'number',
27037
+ description: 'Colunas para breakpoint lg.',
27038
+ },
27039
+ {
27040
+ path: 'page.layout.breakpoints.xl',
27041
+ category: 'layout',
27042
+ valueKind: 'number',
27043
+ description: 'Colunas para breakpoint xl.',
27044
+ },
27045
+ {
27046
+ path: 'page.canvas',
27047
+ category: 'layout',
27048
+ valueKind: 'object',
27049
+ description: 'Canvas espacial canônico da página quando houver geometria explícita.',
27050
+ },
27051
+ {
27052
+ path: 'page.canvas.mode',
27053
+ category: 'layout',
27054
+ valueKind: 'enum',
27055
+ allowedValues: ENUMS.canvasMode,
27056
+ description: 'Modo canonico do canvas. Valor atual: grid.',
27057
+ },
27058
+ {
27059
+ path: 'page.canvas.columns',
27060
+ category: 'layout',
27061
+ valueKind: 'number',
27062
+ description: 'Numero de colunas do canvas espacial.',
27063
+ },
27064
+ {
27065
+ path: 'page.canvas.rowUnit',
27066
+ category: 'layout',
27067
+ valueKind: 'string',
27068
+ description: 'Altura base das linhas do canvas, como 80px.',
27069
+ },
27070
+ {
27071
+ path: 'page.canvas.gap',
27072
+ category: 'layout',
27073
+ valueKind: 'string',
27074
+ description: 'Espacamento entre itens do canvas.',
27075
+ },
27076
+ {
27077
+ path: 'page.canvas.autoRows',
27078
+ category: 'layout',
27079
+ valueKind: 'enum',
27080
+ allowedValues: ENUMS.canvasAutoRows,
27081
+ description: 'Politica de linhas automaticas do canvas.',
27082
+ },
27083
+ {
27084
+ path: 'page.canvas.collisionPolicy',
27085
+ category: 'layout',
27086
+ valueKind: 'enum',
27087
+ allowedValues: ENUMS.canvasCollisionPolicy,
27088
+ description: 'Politica de colisao do canvas espacial.',
27089
+ },
27090
+ {
27091
+ path: 'page.canvas.items',
27092
+ category: 'layout',
27093
+ valueKind: 'object',
27094
+ description: 'Mapa canonico de geometria por widget key.',
27095
+ },
27096
+ {
27097
+ path: 'page.canvas.items.<widgetKey>.col',
27098
+ category: 'layout',
27099
+ valueKind: 'number',
27100
+ description: 'Coluna inicial do widget no canvas.',
27101
+ },
27102
+ {
27103
+ path: 'page.canvas.items.<widgetKey>.row',
27104
+ category: 'layout',
27105
+ valueKind: 'number',
27106
+ description: 'Linha inicial do widget no canvas.',
27107
+ },
27108
+ {
27109
+ path: 'page.canvas.items.<widgetKey>.colSpan',
27110
+ category: 'layout',
27111
+ valueKind: 'number',
27112
+ description: 'Quantidade de colunas ocupadas pelo widget.',
27113
+ },
27114
+ {
27115
+ path: 'page.canvas.items.<widgetKey>.rowSpan',
27116
+ category: 'layout',
27117
+ valueKind: 'number',
27118
+ description: 'Quantidade de linhas ocupadas pelo widget.',
27119
+ },
27120
+ {
27121
+ path: 'page.canvas.items.<widgetKey>.zIndex',
27122
+ category: 'layout',
27123
+ valueKind: 'number',
27124
+ description: 'Camada opcional do item no canvas.',
27125
+ },
27126
+ {
27127
+ path: 'page.canvas.items.<widgetKey>.constraints',
27128
+ category: 'layout',
27129
+ valueKind: 'object',
27130
+ description: 'Restricoes opcionais de posicao e tamanho do item no canvas.',
27131
+ },
27132
+ {
27133
+ path: 'page.canvas.items.<widgetKey>.constraints.minColSpan',
27134
+ category: 'layout',
27135
+ valueKind: 'number',
27136
+ description: 'Span mínimo de colunas permitido.',
27137
+ },
27138
+ {
27139
+ path: 'page.canvas.items.<widgetKey>.constraints.minRowSpan',
27140
+ category: 'layout',
27141
+ valueKind: 'number',
27142
+ description: 'Span mínimo de linhas permitido.',
27143
+ },
27144
+ {
27145
+ path: 'page.canvas.items.<widgetKey>.constraints.maxColSpan',
27146
+ category: 'layout',
27147
+ valueKind: 'number',
27148
+ description: 'Span máximo de colunas permitido.',
27149
+ },
27150
+ {
27151
+ path: 'page.canvas.items.<widgetKey>.constraints.maxRowSpan',
27152
+ category: 'layout',
27153
+ valueKind: 'number',
27154
+ description: 'Span máximo de linhas permitido.',
27155
+ },
27156
+ {
27157
+ path: 'page.canvas.items.<widgetKey>.constraints.lockPosition',
27158
+ category: 'layout',
27159
+ valueKind: 'boolean',
27160
+ description: 'Bloqueia alteracao de posicao do item no canvas.',
27161
+ },
27162
+ {
27163
+ path: 'page.canvas.items.<widgetKey>.constraints.lockSize',
27164
+ category: 'layout',
27165
+ valueKind: 'boolean',
27166
+ description: 'Bloqueia alteracao de tamanho do item no canvas.',
27167
+ },
27168
+ {
27169
+ path: 'page.widgets',
27170
+ category: 'widgets',
27171
+ valueKind: 'array',
27172
+ description: 'Lista de widgets renderizados.',
27173
+ },
27174
+ {
27175
+ path: 'page.widgets[].key',
27176
+ category: 'widgets',
27177
+ valueKind: 'string',
27178
+ description: 'Identificador unico do widget.',
27179
+ },
27180
+ {
27181
+ path: 'page.widgets[].className',
27182
+ category: 'widgets',
27183
+ valueKind: 'string',
27184
+ description: 'Classe CSS opcional do widget.',
27185
+ },
27186
+ {
27187
+ path: 'page.widgets[].definition.id',
27188
+ category: 'widgets',
27189
+ valueKind: 'string',
27190
+ description: 'ID do componente do widget (ex: praxis-table).',
27191
+ },
27192
+ {
27193
+ path: 'page.widgets[].definition.inputs',
27194
+ category: 'widgets',
27195
+ valueKind: 'object',
27196
+ description: 'Inputs iniciais do widget.',
27197
+ },
27198
+ {
27199
+ path: 'page.widgets[].definition.inputs.hostCapabilities',
27200
+ category: 'widgets',
27201
+ valueKind: 'object',
27202
+ description: 'Capacidades runtime mediadas pelo host quando definition.id = praxis-rich-content. Não pertence ao JSON persistido.',
27203
+ },
27204
+ {
27205
+ path: 'page.widgets[].definition.inputs.hostCapabilities.dispatchAction',
27206
+ category: 'widgets',
27207
+ valueKind: 'object',
27208
+ description: 'Dispatcher runtime para actionButton e actions declarativas de rich content hospedado na página.',
27209
+ },
27210
+ {
27211
+ path: 'page.widgets[].definition.inputs.hostCapabilities.isActionAvailable',
27212
+ category: 'widgets',
27213
+ valueKind: 'object',
27214
+ description: 'Resolver runtime de disponibilidade de actionId para rich content hospedado na página.',
27215
+ },
27216
+ {
27217
+ path: 'page.widgets[].definition.inputs.hostCapabilities.hasCapability',
27218
+ category: 'widgets',
27219
+ valueKind: 'object',
27220
+ description: 'Resolver runtime de capabilities como page.customization.enabled e page.widget.selected para rich content hospedado na página.',
27221
+ },
27222
+ {
27223
+ path: 'page.widgets[].definition.bindingOrder',
27224
+ category: 'widgets',
27225
+ valueKind: 'array',
27226
+ description: 'Ordem de binding de inputs.',
27227
+ },
27228
+ {
27229
+ path: 'page.widgets[].shell',
27230
+ category: 'shell',
27231
+ valueKind: 'object',
27232
+ description: 'Configuração do shell do widget.',
27233
+ },
27234
+ {
27235
+ path: 'page.widgets[].shell.kind',
27236
+ category: 'shell',
27237
+ valueKind: 'enum',
27238
+ allowedValues: ENUMS.shellKind,
27239
+ description: 'Tipo de shell.',
27240
+ },
27241
+ {
27242
+ path: 'page.widgets[].shell.title',
27243
+ category: 'shell',
27244
+ valueKind: 'string',
27245
+ description: 'Título do shell.',
27246
+ },
27247
+ {
27248
+ path: 'page.widgets[].shell.subtitle',
27249
+ category: 'shell',
27250
+ valueKind: 'string',
27251
+ description: 'Subtítulo do shell.',
27252
+ },
27253
+ {
27254
+ path: 'page.widgets[].shell.icon',
27255
+ category: 'shell',
27256
+ valueKind: 'string',
27257
+ description: 'Ícone do shell.',
27258
+ },
27259
+ {
27260
+ path: 'page.widgets[].shell.showHeader',
27261
+ category: 'shell',
27262
+ valueKind: 'boolean',
27263
+ description: 'Exibe o header do shell.',
27264
+ },
27265
+ {
27266
+ path: 'page.widgets[].shell.actions',
27267
+ category: 'shell',
27268
+ valueKind: 'array',
27269
+ description: 'Ações do shell.',
27270
+ },
27271
+ {
27272
+ path: 'page.widgets[].shell.actions[].id',
27273
+ category: 'shell',
27274
+ valueKind: 'string',
27275
+ description: 'ID da ação.',
27276
+ },
27277
+ {
27278
+ path: 'page.widgets[].shell.actions[].label',
27279
+ category: 'shell',
27280
+ valueKind: 'string',
27281
+ description: 'Label da ação.',
27282
+ },
27283
+ {
27284
+ path: 'page.widgets[].shell.actions[].icon',
27285
+ category: 'shell',
27286
+ valueKind: 'string',
27287
+ description: 'Ícone da ação.',
27288
+ },
27289
+ {
27290
+ path: 'page.widgets[].shell.actions[].variant',
27291
+ category: 'shell',
27292
+ valueKind: 'enum',
27293
+ allowedValues: ENUMS.actionVariant,
27294
+ description: 'Estilo visual da ação.',
27295
+ },
27296
+ {
27297
+ path: 'page.widgets[].shell.actions[].placement',
27298
+ category: 'shell',
27299
+ valueKind: 'enum',
27300
+ allowedValues: ENUMS.actionPlacement,
27301
+ description: 'Posicionamento da ação.',
27302
+ },
27303
+ {
27304
+ path: 'page.widgets[].shell.actions[].emit',
27305
+ category: 'shell',
27306
+ valueKind: 'string',
27307
+ description: 'Evento emitido ao acionar a ação.',
27308
+ },
27309
+ {
27310
+ path: 'page.state',
27311
+ category: 'state',
27312
+ valueKind: 'object',
27313
+ description: 'Estado declarativo opcional compartilhado por widgets e composicao.',
27314
+ },
27315
+ {
27316
+ path: 'page.state.values',
27317
+ category: 'state',
27318
+ valueKind: 'object',
27319
+ description: 'Valores primarios mutaveis escritos por widgets, defaults ou host.',
27320
+ },
27321
+ {
27322
+ path: 'page.state.schema',
27323
+ category: 'state',
27324
+ valueKind: 'object',
27325
+ description: 'Descritores dos paths primarios de estado.',
27326
+ },
27327
+ {
27328
+ path: 'page.state.schema.<token>.type',
27329
+ category: 'state',
27330
+ valueKind: 'string',
27331
+ description: 'Tipo semantico opcional do path de estado.',
27332
+ },
27333
+ {
27334
+ path: 'page.state.schema.<token>.initial',
27335
+ category: 'state',
27336
+ valueKind: 'object',
27337
+ description: 'Valor inicial usado quando page.state.values omite o path.',
27338
+ },
27339
+ {
27340
+ path: 'page.state.schema.<token>.persist',
27341
+ category: 'state',
27342
+ valueKind: 'boolean',
27343
+ description: 'Indica se o path primário deve ser persistido com a página.',
27344
+ },
27345
+ {
27346
+ path: 'page.state.schema.<token>.mergeStrategy',
27347
+ category: 'state',
27348
+ valueKind: 'enum',
27349
+ allowedValues: ENUMS.stateMergeStrategy,
27350
+ description: 'Como escritas de widget/estado combinam com o valor atual.',
27351
+ },
27352
+ {
27353
+ path: 'page.state.schema.<token>.description',
27354
+ category: 'state',
27355
+ valueKind: 'string',
27356
+ description: 'Descrição opcional do path para builders e catálogos AI.',
27357
+ },
27358
+ {
27359
+ path: 'page.state.schema.<token>.tags',
27360
+ category: 'state',
27361
+ valueKind: 'array',
27362
+ description: 'Tags opcionais para busca e governanca do estado.',
27363
+ },
27364
+ {
27365
+ path: 'page.state.derived',
27366
+ category: 'state',
27367
+ valueKind: 'object',
27368
+ description: 'Descritores de estado derivado recomputado pelo runtime.',
27369
+ },
27370
+ {
27371
+ path: 'page.state.derived.<token>.dependsOn',
27372
+ category: 'state',
27373
+ valueKind: 'array',
27374
+ description: 'Paths de estado que alimentam o valor derivado.',
27375
+ },
27376
+ {
27377
+ path: 'page.state.derived.<token>.compute',
27378
+ category: 'state',
27379
+ valueKind: 'object',
27380
+ description: 'Descritor de computacao do estado derivado.',
27381
+ },
27382
+ {
27383
+ path: 'page.state.derived.<token>.compute.kind',
27384
+ category: 'state',
27385
+ valueKind: 'enum',
27386
+ allowedValues: ENUMS.derivedStateComputeKind,
27387
+ description: 'Tipo de computacao do estado derivado.',
27388
+ },
27389
+ {
27390
+ path: 'page.state.derived.<token>.compute.expression',
27391
+ category: 'state',
27392
+ valueKind: 'expression',
27393
+ description: 'Expressao Json Logic para compute.kind=json-logic.',
27394
+ },
27395
+ {
27396
+ path: 'page.state.derived.<token>.compute.value',
27397
+ category: 'state',
27398
+ valueKind: 'object',
27399
+ description: 'Valor template para compute.kind=template.',
27400
+ },
27401
+ {
27402
+ path: 'page.state.derived.<token>.compute.operator',
27403
+ category: 'state',
27404
+ valueKind: 'string',
27405
+ description: 'Operador para compute.kind=operator.',
27406
+ },
27407
+ {
27408
+ path: 'page.state.derived.<token>.compute.options',
27409
+ category: 'state',
27410
+ valueKind: 'object',
27411
+ description: 'Opções do operador ou transformer.',
27412
+ },
27413
+ {
27414
+ path: 'page.state.derived.<token>.compute.transformerId',
27415
+ category: 'state',
27416
+ valueKind: 'string',
27417
+ description: 'Identificador do transformer para compute.kind=transformer.',
27418
+ },
27419
+ {
27420
+ path: 'page.state.derived.<token>.description',
27421
+ category: 'state',
27422
+ valueKind: 'string',
27423
+ description: 'Descrição opcional do estado derivado.',
27424
+ },
27425
+ {
27426
+ path: 'page.state.derived.<token>.cache',
27427
+ category: 'state',
27428
+ valueKind: 'boolean',
27429
+ description: 'Permite cache futuro do valor derivado.',
27430
+ },
27431
+ {
27432
+ path: 'page.composition',
27433
+ category: 'connections',
27434
+ valueKind: 'object',
27435
+ description: 'Envelope canonico da composicao persistida.',
27436
+ },
27437
+ {
27438
+ path: 'page.composition.version',
27439
+ category: 'connections',
27440
+ valueKind: 'string',
27441
+ description: 'Versao do envelope de composicao.',
27442
+ },
27443
+ {
27444
+ path: 'page.composition.links',
27445
+ category: 'connections',
27446
+ valueKind: 'array',
27447
+ description: 'Links canonicos entre widgets, estado e actions globais.',
27448
+ },
27449
+ {
27450
+ path: 'page.composition.links[].id',
27451
+ category: 'connections',
27452
+ valueKind: 'string',
27453
+ description: 'Identificador estavel do link.',
27454
+ },
27455
+ {
27456
+ path: 'page.composition.links[].from',
27457
+ category: 'connections',
27458
+ valueKind: 'object',
27459
+ description: 'Endpoint de origem do link.',
27460
+ },
27461
+ {
27462
+ path: 'page.composition.links[].from.kind',
27463
+ category: 'connections',
27464
+ valueKind: 'string',
27465
+ description: 'Tipo do endpoint de origem, como component-port ou state.',
27466
+ },
27467
+ {
27468
+ path: 'page.composition.links[].from.ref',
27469
+ category: 'connections',
27470
+ valueKind: 'object',
27471
+ description: 'Referencia estruturada do endpoint de origem.',
27472
+ },
27473
+ {
27474
+ path: 'page.composition.links[].from.ref.widget',
27475
+ category: 'connections',
27476
+ valueKind: 'string',
27477
+ description: 'Widget top-level dono do endpoint de origem.',
27478
+ },
27479
+ {
27480
+ path: 'page.composition.links[].from.ref.port',
27481
+ category: 'connections',
27482
+ valueKind: 'string',
27483
+ description: 'Porta de origem do componente.',
27484
+ },
27485
+ {
27486
+ path: 'page.composition.links[].from.ref.direction',
27487
+ category: 'connections',
27488
+ valueKind: 'string',
27489
+ description: 'Direcao da porta de origem.',
27490
+ },
27491
+ {
27492
+ path: 'page.composition.links[].from.ref.nestedPath',
27493
+ category: 'connections',
27494
+ valueKind: 'array',
27495
+ description: 'NestedPath canonico para porta de componente filho de origem.',
27496
+ },
27497
+ {
27498
+ path: 'page.composition.links[].from.ref.nestedPath[].kind',
27499
+ category: 'connections',
27500
+ valueKind: 'string',
27501
+ description: 'Tipo do segmento nested de origem.',
27502
+ },
27503
+ {
27504
+ path: 'page.composition.links[].from.ref.nestedPath[].id',
27505
+ category: 'connections',
27506
+ valueKind: 'string',
27507
+ description: 'Identificador estrutural do segmento nested de origem.',
27508
+ },
27509
+ {
27510
+ path: 'page.composition.links[].from.ref.nestedPath[].key',
27511
+ category: 'connections',
27512
+ valueKind: 'string',
27513
+ description: 'Chave estavel do widget filho no segmento terminal de origem.',
27514
+ critical: true,
27515
+ },
27516
+ {
27517
+ path: 'page.composition.links[].from.ref.nestedPath[].index',
27518
+ category: 'connections',
27519
+ valueKind: 'number',
27520
+ description: 'Índice auxiliar para diagnóstico visual; não use como identidade primária.',
27521
+ },
27522
+ {
27523
+ path: 'page.composition.links[].from.ref.nestedPath[].componentType',
27524
+ category: 'connections',
27525
+ valueKind: 'string',
27526
+ description: 'Tipo do componente real do widget filho de origem.',
27527
+ },
27528
+ {
27529
+ path: 'page.composition.links[].to',
27530
+ category: 'connections',
27531
+ valueKind: 'object',
27532
+ description: 'Endpoint de destino do link.',
27533
+ },
27534
+ {
27535
+ path: 'page.composition.links[].to.kind',
27536
+ category: 'connections',
27537
+ valueKind: 'string',
27538
+ description: 'Tipo do endpoint de destino, como component-port, state ou global-action.',
27539
+ },
27540
+ {
27541
+ path: 'page.composition.links[].to.ref',
27542
+ category: 'connections',
27543
+ valueKind: 'object',
27544
+ description: 'Referencia estruturada do endpoint de destino.',
27545
+ },
27546
+ {
27547
+ path: 'page.composition.links[].to.ref.[actionId]',
27548
+ category: 'connections',
27549
+ valueKind: 'string',
27550
+ description: 'ID da action global quando to.kind = global-action.',
27551
+ },
27552
+ {
27553
+ path: 'page.composition.links[].to.ref.payload',
27554
+ category: 'connections',
27555
+ valueKind: 'object',
27556
+ description: 'Payload fixo opcional da action global; quando omitido, o runtime entrega o valor transformado do link.',
27557
+ },
27558
+ {
27559
+ path: 'page.composition.links[].to.ref.payloadExpr',
27560
+ category: 'connections',
27561
+ valueKind: 'expression',
27562
+ description: 'Expressao opcional de payload da action global suportada pelo GlobalActionService.',
27563
+ },
27564
+ {
27565
+ path: 'page.composition.links[].to.ref.widget',
27566
+ category: 'connections',
27567
+ valueKind: 'string',
27568
+ description: 'Widget top-level dono do endpoint de destino.',
27569
+ },
27570
+ {
27571
+ path: 'page.composition.links[].to.ref.port',
27572
+ category: 'connections',
27573
+ valueKind: 'string',
27574
+ description: 'Porta de destino do componente.',
27575
+ },
27576
+ {
27577
+ path: 'page.composition.links[].to.ref.direction',
27578
+ category: 'connections',
27579
+ valueKind: 'string',
27580
+ description: 'Direcao da porta de destino.',
27581
+ },
27582
+ {
27583
+ path: 'page.composition.links[].to.ref.nestedPath',
27584
+ category: 'connections',
27585
+ valueKind: 'array',
27586
+ description: 'NestedPath canonico para porta de componente filho de destino.',
27587
+ },
27588
+ {
27589
+ path: 'page.composition.links[].to.ref.nestedPath[].kind',
27590
+ category: 'connections',
27591
+ valueKind: 'string',
27592
+ description: 'Tipo do segmento nested de destino.',
27593
+ },
27594
+ {
27595
+ path: 'page.composition.links[].to.ref.nestedPath[].id',
27596
+ category: 'connections',
27597
+ valueKind: 'string',
27598
+ description: 'Identificador estrutural do segmento nested de destino.',
27599
+ },
27600
+ {
27601
+ path: 'page.composition.links[].to.ref.nestedPath[].key',
27602
+ category: 'connections',
27603
+ valueKind: 'string',
27604
+ description: 'Chave estavel do widget filho no segmento terminal de destino.',
27605
+ critical: true,
27606
+ },
27607
+ {
27608
+ path: 'page.composition.links[].to.ref.nestedPath[].index',
27609
+ category: 'connections',
27610
+ valueKind: 'number',
27611
+ description: 'Índice auxiliar para diagnóstico visual; não use como identidade primária.',
27612
+ },
27613
+ {
27614
+ path: 'page.composition.links[].to.ref.nestedPath[].componentType',
27615
+ category: 'connections',
27616
+ valueKind: 'string',
27617
+ description: 'Tipo do componente real do widget filho de destino.',
27618
+ },
27619
+ {
27620
+ path: 'page.composition.links[].intent',
27621
+ category: 'connections',
27622
+ valueKind: 'string',
27623
+ description: 'Intenção semântica do link.',
27624
+ },
27625
+ {
27626
+ path: 'page.composition.links[].transform',
27627
+ category: 'connections',
27628
+ valueKind: 'object',
27629
+ description: 'Pipeline de transformacao do link.',
27630
+ },
27631
+ {
27632
+ path: 'page.composition.links[].condition',
27633
+ category: 'connections',
27634
+ valueKind: 'expression',
27635
+ description: 'Guarda semântica opcional do link, expressa como um único AST Json Logic canônico.',
27636
+ },
27637
+ {
27638
+ path: 'page.composition.links[].policy',
27639
+ category: 'connections',
27640
+ valueKind: 'object',
27641
+ description: 'Politicas operacionais opcionais do link, como debounce, distinct e missing-value.',
27642
+ },
27643
+ {
27644
+ path: 'page.composition.links[].metadata',
27645
+ category: 'connections',
27646
+ valueKind: 'object',
27647
+ description: 'Metadados opcionais do link.',
27648
+ },
27649
+ {
27650
+ path: 'page.grouping',
27651
+ category: 'layout',
27652
+ valueKind: 'array',
27653
+ description: 'Modelo semantico opcional de secoes, abas, areas hero e rails.',
27654
+ },
27655
+ {
27656
+ path: 'page.grouping[].kind',
27657
+ category: 'layout',
27658
+ valueKind: 'enum',
27659
+ allowedValues: ENUMS.groupingKind,
27660
+ description: 'Tipo do agrupamento semantico.',
27661
+ },
27662
+ {
27663
+ path: 'page.grouping[].id',
27664
+ category: 'layout',
27665
+ valueKind: 'string',
27666
+ description: 'Identificador estavel do agrupamento.',
27667
+ },
27668
+ {
27669
+ path: 'page.grouping[].label',
27670
+ category: 'layout',
27671
+ valueKind: 'string',
27672
+ description: 'Rotulo opcional do agrupamento.',
27673
+ },
27674
+ {
27675
+ path: 'page.grouping[].widgetKeys',
27676
+ category: 'layout',
27677
+ valueKind: 'array',
27678
+ description: 'Widgets pertencentes ao agrupamento section, hero ou rail.',
27679
+ },
27680
+ {
27681
+ path: 'page.grouping[].layout',
27682
+ category: 'layout',
27683
+ valueKind: 'enum',
27684
+ allowedValues: ENUMS.groupingLayout,
27685
+ description: 'Layout opcional para agrupamento section.',
27686
+ },
27687
+ {
27688
+ path: 'page.grouping[].tabs',
27689
+ category: 'layout',
27690
+ valueKind: 'array',
27691
+ description: 'Abas do agrupamento kind=tabs.',
27692
+ },
27693
+ {
27694
+ path: 'page.grouping[].tabs[].id',
27695
+ category: 'layout',
27696
+ valueKind: 'string',
27697
+ description: 'Identificador estavel da aba.',
27698
+ },
27699
+ {
27700
+ path: 'page.grouping[].tabs[].label',
27701
+ category: 'layout',
27702
+ valueKind: 'string',
27703
+ description: 'Rotulo da aba.',
27704
+ },
27705
+ {
27706
+ path: 'page.grouping[].tabs[].widgetKeys',
27707
+ category: 'layout',
27708
+ valueKind: 'array',
27709
+ description: 'Widgets renderizados dentro da aba.',
27710
+ },
27711
+ {
27712
+ path: 'page.grouping[].emphasis',
27713
+ category: 'layout',
27714
+ valueKind: 'enum',
27715
+ allowedValues: ENUMS.heroEmphasis,
27716
+ description: 'Enfase opcional para agrupamento hero.',
27717
+ },
27718
+ {
27719
+ path: 'page.grouping[].side',
27720
+ category: 'layout',
27721
+ valueKind: 'enum',
27722
+ allowedValues: ENUMS.railSide,
27723
+ description: 'Lado do rail quando kind=rail.',
27724
+ },
27725
+ {
27726
+ path: 'page.slotAssignments',
27727
+ category: 'layout',
27728
+ valueKind: 'object',
27729
+ description: 'Mapa canonico de widget key para slot semantico de preset.',
27730
+ },
27731
+ {
27732
+ path: 'page.deviceLayouts',
27733
+ category: 'layout',
27734
+ valueKind: 'object',
27735
+ description: 'Variantes opcionais de layout por dispositivo.',
27736
+ },
27737
+ {
27738
+ path: 'page.deviceLayouts.desktop',
27739
+ category: 'layout',
27740
+ valueKind: 'object',
27741
+ description: 'Overrides de layout para desktop.',
27742
+ },
27743
+ {
27744
+ path: 'page.deviceLayouts.tablet',
27745
+ category: 'layout',
27746
+ valueKind: 'object',
27747
+ description: 'Overrides de layout para tablet.',
27748
+ },
27749
+ {
27750
+ path: 'page.deviceLayouts.mobile',
27751
+ category: 'layout',
27752
+ valueKind: 'object',
27753
+ description: 'Overrides de layout para mobile.',
27754
+ },
27755
+ {
27756
+ path: 'page.deviceLayouts.desktop.layout',
27757
+ category: 'layout',
27758
+ valueKind: 'object',
27759
+ description: 'Override de WidgetPageLayout para desktop.',
27760
+ },
27761
+ {
27762
+ path: 'page.deviceLayouts.desktop.canvas',
27763
+ category: 'layout',
27764
+ valueKind: 'object',
27765
+ description: 'Override de canvas para desktop.',
27766
+ },
27767
+ {
27768
+ path: 'page.deviceLayouts.desktop.groupingOverrides',
27769
+ category: 'layout',
27770
+ valueKind: 'array',
27771
+ description: 'Overrides de agrupamentos para desktop.',
27772
+ },
27773
+ {
27774
+ path: 'page.deviceLayouts.desktop.widgetOverrides',
27775
+ category: 'layout',
27776
+ valueKind: 'object',
27777
+ description: 'Overrides por widget key para desktop.',
27778
+ },
27779
+ {
27780
+ path: 'page.deviceLayouts.desktop.widgetOverrides.<widgetKey>.hidden',
27781
+ category: 'layout',
27782
+ valueKind: 'boolean',
27783
+ description: 'Oculta o widget em desktop.',
27784
+ },
27785
+ {
27786
+ path: 'page.deviceLayouts.tablet.layout',
27787
+ category: 'layout',
27788
+ valueKind: 'object',
27789
+ description: 'Override de WidgetPageLayout para tablet.',
27790
+ },
27791
+ {
27792
+ path: 'page.deviceLayouts.tablet.canvas',
27793
+ category: 'layout',
27794
+ valueKind: 'object',
27795
+ description: 'Override de canvas para tablet.',
27796
+ },
27797
+ {
27798
+ path: 'page.deviceLayouts.tablet.groupingOverrides',
27799
+ category: 'layout',
27800
+ valueKind: 'array',
27801
+ description: 'Overrides de agrupamentos para tablet.',
27802
+ },
27803
+ {
27804
+ path: 'page.deviceLayouts.tablet.widgetOverrides',
27805
+ category: 'layout',
27806
+ valueKind: 'object',
27807
+ description: 'Overrides por widget key para tablet.',
27808
+ },
27809
+ {
27810
+ path: 'page.deviceLayouts.tablet.widgetOverrides.<widgetKey>.hidden',
27811
+ category: 'layout',
27812
+ valueKind: 'boolean',
27813
+ description: 'Oculta o widget em tablet.',
27814
+ },
27815
+ {
27816
+ path: 'page.deviceLayouts.mobile.layout',
27817
+ category: 'layout',
27818
+ valueKind: 'object',
27819
+ description: 'Override de WidgetPageLayout para mobile.',
27820
+ },
27821
+ {
27822
+ path: 'page.deviceLayouts.mobile.canvas',
27823
+ category: 'layout',
27824
+ valueKind: 'object',
27825
+ description: 'Override de canvas para mobile.',
27826
+ },
27827
+ {
27828
+ path: 'page.deviceLayouts.mobile.groupingOverrides',
27829
+ category: 'layout',
27830
+ valueKind: 'array',
27831
+ description: 'Overrides de agrupamentos para mobile.',
27832
+ },
27833
+ {
27834
+ path: 'page.deviceLayouts.mobile.widgetOverrides',
27835
+ category: 'layout',
27836
+ valueKind: 'object',
27837
+ description: 'Overrides por widget key para mobile.',
27838
+ },
27839
+ {
27840
+ path: 'page.deviceLayouts.mobile.widgetOverrides.<widgetKey>.hidden',
27841
+ category: 'layout',
27842
+ valueKind: 'boolean',
27843
+ description: 'Oculta o widget em mobile.',
27844
+ },
26767
27845
  ];
26768
27846
  const DYNAMIC_PAGE_AI_CAPABILITIES = {
26769
27847
  version: 'v1.2',
@@ -26771,7 +27849,7 @@ const DYNAMIC_PAGE_AI_CAPABILITIES = {
26771
27849
  targets: ['praxis-dynamic-page'],
26772
27850
  notes: [
26773
27851
  'Este catálogo é específico para o runtime praxis-dynamic-page; operações de authoring/mutação pertencem ao manifesto do praxis-page-builder.',
26774
- 'WidgetPageDefinition e o contrato canonico persistido: widgets, composition.links, state, context, layout, canvas, presets, grouping, slotAssignments, deviceLayouts e themePreset.',
27852
+ 'WidgetPageDefinition e o contrato canonico persistido: widgets, composition.links, state, context, i18n, layout, canvas, presets, grouping, slotAssignments, deviceLayouts e themePreset.',
26775
27853
  'Widgets e page.composition.links sao arrays; ferramentas de patch legadas fazem merge por key estavel e id estavel.',
26776
27854
  'page.canvas.items é um mapa por widget key; não modele canvas.items como array.',
26777
27855
  'Taxonomia editorial: condition usa Json Logic canônico; transform usa pipeline declarativo; não trate ambos como a mesma "expression".',
@@ -26799,9 +27877,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26799
27877
  },
26800
27878
  'page.canvas.mode': {
26801
27879
  mode: 'enum',
26802
- options: [
26803
- { value: 'grid', label: 'Grid' },
26804
- ],
27880
+ options: [{ value: 'grid', label: 'Grid' }],
26805
27881
  },
26806
27882
  'page.canvas.autoRows': {
26807
27883
  mode: 'enum',
@@ -26890,9 +27966,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26890
27966
  },
26891
27967
  'page.composition.version': {
26892
27968
  mode: 'enum',
26893
- options: [
26894
- { value: '1.0.0', label: 'Schema canonico 1.0.0' },
26895
- ],
27969
+ options: [{ value: '1.0.0', label: 'Schema canonico 1.0.0' }],
26896
27970
  },
26897
27971
  'page.composition.links[].intent': {
26898
27972
  mode: 'enum',
@@ -26905,22 +27979,37 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26905
27979
  'page.composition.links[].from.ref.port': {
26906
27980
  mode: 'suggested',
26907
27981
  options: [
26908
- { value: 'rowClick', label: 'Clique na linha (praxis-table)', example: 'Usar table.rowClick -> form.resourceId via transform pick-path payload.row.id' },
27982
+ {
27983
+ value: 'rowClick',
27984
+ label: 'Clique na linha (praxis-table)',
27985
+ example: 'Usar table.rowClick -> form.resourceId via transform pick-path payload.row.id',
27986
+ },
26909
27987
  { value: 'rowAction', label: 'Ação da linha (praxis-table)' },
26910
- { value: 'formSubmit', label: 'Submit do formulario (praxis-dynamic-form)' },
27988
+ {
27989
+ value: 'formSubmit',
27990
+ label: 'Submit do formulario (praxis-dynamic-form)',
27991
+ },
26911
27992
  ],
26912
27993
  },
26913
27994
  'page.composition.links[].to.ref.port': {
26914
27995
  mode: 'suggested',
26915
27996
  options: [
26916
- { value: 'resourceId', label: 'ID do registro (praxis-dynamic-form)', example: 'transform pick-path payload.row.id' },
27997
+ {
27998
+ value: 'resourceId',
27999
+ label: 'ID do registro (praxis-dynamic-form)',
28000
+ example: 'transform pick-path payload.row.id',
28001
+ },
26917
28002
  { value: 'mode', label: 'Modo do formulario (create|edit|view)' },
26918
28003
  ],
26919
28004
  },
26920
28005
  'page.composition.links[].transform.steps[].config.path': {
26921
28006
  mode: 'suggested',
26922
28007
  options: [
26923
- { value: 'payload.row.id', label: 'ID padrão do registro', example: 'rowClick -> resourceId' },
28008
+ {
28009
+ value: 'payload.row.id',
28010
+ label: 'ID padrão do registro',
28011
+ example: 'rowClick -> resourceId',
28012
+ },
26924
28013
  ],
26925
28014
  },
26926
28015
  },
@@ -26932,9 +28021,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26932
28021
  scope: 'ROW',
26933
28022
  patchTemplate: {
26934
28023
  page: {
26935
- widgets: [
26936
- { key: '{{target}}', _remove: true },
26937
- ],
28024
+ widgets: [{ key: '{{target}}', _remove: true }],
26938
28025
  },
26939
28026
  },
26940
28027
  },
@@ -26943,9 +28030,7 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26943
28030
  intentExamples: ['remover conexao', 'excluir conexao', 'apagar conexao'],
26944
28031
  requiresExistingTarget: true,
26945
28032
  scope: 'ROW',
26946
- params: [
26947
- { name: 'id', type: 'STRING' },
26948
- ],
28033
+ params: [{ name: 'id', type: 'STRING' }],
26949
28034
  patchTemplate: {
26950
28035
  page: {
26951
28036
  composition: {
@@ -26963,7 +28048,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
26963
28048
  },
26964
28049
  {
26965
28050
  id: 'page.layout.orientation.set',
26966
- intentExamples: ['orientacao', 'orientation', 'layout vertical', 'layout colunas'],
28051
+ intentExamples: [
28052
+ 'orientacao',
28053
+ 'orientation',
28054
+ 'layout vertical',
28055
+ 'layout colunas',
28056
+ ],
26967
28057
  patchTemplate: {
26968
28058
  page: {
26969
28059
  layout: {
@@ -27048,7 +28138,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27048
28138
  },
27049
28139
  {
27050
28140
  id: 'page.connection.set',
27051
- intentExamples: ['set connection', 'definir conexao', 'valor fixo', 'set constante'],
28141
+ intentExamples: [
28142
+ 'set connection',
28143
+ 'definir conexao',
28144
+ 'valor fixo',
28145
+ 'set constante',
28146
+ ],
27052
28147
  params: [
27053
28148
  { name: 'fromWidget', type: 'STRING' },
27054
28149
  { name: 'fromOutput', type: 'STRING' },
@@ -27065,11 +28160,19 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27065
28160
  id: '{{params.fromWidget}}.{{params.fromOutput}}->{{params.toWidget}}.{{params.toInput}}',
27066
28161
  from: {
27067
28162
  kind: 'component-port',
27068
- ref: { widget: '{{params.fromWidget}}', port: '{{params.fromOutput}}', direction: 'output' },
28163
+ ref: {
28164
+ widget: '{{params.fromWidget}}',
28165
+ port: '{{params.fromOutput}}',
28166
+ direction: 'output',
28167
+ },
27069
28168
  },
27070
28169
  to: {
27071
28170
  kind: 'component-port',
27072
- ref: { widget: '{{params.toWidget}}', port: '{{params.toInput}}', direction: 'input' },
28171
+ ref: {
28172
+ widget: '{{params.toWidget}}',
28173
+ port: '{{params.toInput}}',
28174
+ direction: 'input',
28175
+ },
27073
28176
  },
27074
28177
  intent: 'event-propagation',
27075
28178
  transform: {
@@ -27097,7 +28200,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27097
28200
  },
27098
28201
  {
27099
28202
  id: 'page.widget.upsert',
27100
- intentExamples: ['adicionar widget', 'novo widget', 'inserir widget', 'atualizar widget'],
28203
+ intentExamples: [
28204
+ 'adicionar widget',
28205
+ 'novo widget',
28206
+ 'inserir widget',
28207
+ 'atualizar widget',
28208
+ ],
27101
28209
  params: [
27102
28210
  { name: 'widgetKey', type: 'STRING' },
27103
28211
  { name: 'widgetType', type: 'STRING' },
@@ -27120,7 +28228,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27120
28228
  },
27121
28229
  {
27122
28230
  id: 'page.connection.move',
27123
- intentExamples: ['mover conexao', 'alterar conexao', 'editar conexao', 'trocar conexao'],
28231
+ intentExamples: [
28232
+ 'mover conexao',
28233
+ 'alterar conexao',
28234
+ 'editar conexao',
28235
+ 'trocar conexao',
28236
+ ],
27124
28237
  params: [
27125
28238
  { name: 'fromWidget', type: 'STRING' },
27126
28239
  { name: 'fromOutput', type: 'STRING' },
@@ -27141,11 +28254,19 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27141
28254
  id: '{{params.fromWidget}}.{{params.fromOutput}}->{{params.toWidget}}.{{params.toInput}}',
27142
28255
  from: {
27143
28256
  kind: 'component-port',
27144
- ref: { widget: '{{params.fromWidget}}', port: '{{params.fromOutput}}', direction: 'output' },
28257
+ ref: {
28258
+ widget: '{{params.fromWidget}}',
28259
+ port: '{{params.fromOutput}}',
28260
+ direction: 'output',
28261
+ },
27145
28262
  },
27146
28263
  to: {
27147
28264
  kind: 'component-port',
27148
- ref: { widget: '{{params.toWidget}}', port: '{{params.toInput}}', direction: 'input' },
28265
+ ref: {
28266
+ widget: '{{params.toWidget}}',
28267
+ port: '{{params.toInput}}',
28268
+ direction: 'input',
28269
+ },
27149
28270
  },
27150
28271
  intent: 'event-propagation',
27151
28272
  metadata: {
@@ -27189,7 +28310,11 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27189
28310
  },
27190
28311
  {
27191
28312
  id: 'page.widget.createForm',
27192
- intentExamples: ['criar formulario', 'adicionar formulario', 'widget formulario'],
28313
+ intentExamples: [
28314
+ 'criar formulario',
28315
+ 'adicionar formulario',
28316
+ 'widget formulario',
28317
+ ],
27193
28318
  operation: 'create',
27194
28319
  scope: 'ROW',
27195
28320
  valueType: 'OBJECT',
@@ -27221,7 +28346,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27221
28346
  },
27222
28347
  {
27223
28348
  id: 'page.connection.bindRowToForm',
27224
- intentExamples: ['conectar tabela ao formulario', 'master detail', 'master-detail', 'detalhe'],
28349
+ intentExamples: [
28350
+ 'conectar tabela ao formulario',
28351
+ 'master detail',
28352
+ 'master-detail',
28353
+ 'detalhe',
28354
+ ],
27225
28355
  operation: 'create',
27226
28356
  scope: 'ROW',
27227
28357
  valueType: 'OBJECT',
@@ -27242,11 +28372,19 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27242
28372
  id: '{{params.fromWidget}}.{{params.fromOutput}}->{{params.toWidget}}.{{params.toInput}}',
27243
28373
  from: {
27244
28374
  kind: 'component-port',
27245
- ref: { widget: '{{params.fromWidget}}', port: '{{params.fromOutput}}', direction: 'output' },
28375
+ ref: {
28376
+ widget: '{{params.fromWidget}}',
28377
+ port: '{{params.fromOutput}}',
28378
+ direction: 'output',
28379
+ },
27246
28380
  },
27247
28381
  to: {
27248
28382
  kind: 'component-port',
27249
- ref: { widget: '{{params.toWidget}}', port: '{{params.toInput}}', direction: 'input' },
28383
+ ref: {
28384
+ widget: '{{params.toWidget}}',
28385
+ port: '{{params.toInput}}',
28386
+ direction: 'input',
28387
+ },
27250
28388
  },
27251
28389
  intent: 'event-propagation',
27252
28390
  transform: {
@@ -27275,7 +28413,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27275
28413
  },
27276
28414
  {
27277
28415
  id: 'page.connection.bindMasterDetail',
27278
- intentExamples: ['master detail', 'master-detail', 'conectar tabela ao formulario', 'detalhe'],
28416
+ intentExamples: [
28417
+ 'master detail',
28418
+ 'master-detail',
28419
+ 'conectar tabela ao formulario',
28420
+ 'detalhe',
28421
+ ],
27279
28422
  operation: 'create',
27280
28423
  scope: 'ROW',
27281
28424
  valueType: 'OBJECT',
@@ -27293,11 +28436,19 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27293
28436
  id: '{{params.fromWidget}}.rowClick->{{params.toWidget}}.resourceId',
27294
28437
  from: {
27295
28438
  kind: 'component-port',
27296
- ref: { widget: '{{params.fromWidget}}', port: 'rowClick', direction: 'output' },
28439
+ ref: {
28440
+ widget: '{{params.fromWidget}}',
28441
+ port: 'rowClick',
28442
+ direction: 'output',
28443
+ },
27297
28444
  },
27298
28445
  to: {
27299
28446
  kind: 'component-port',
27300
- ref: { widget: '{{params.toWidget}}', port: 'resourceId', direction: 'input' },
28447
+ ref: {
28448
+ widget: '{{params.toWidget}}',
28449
+ port: 'resourceId',
28450
+ direction: 'input',
28451
+ },
27301
28452
  },
27302
28453
  intent: 'event-propagation',
27303
28454
  transform: {
@@ -27326,7 +28477,12 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27326
28477
  },
27327
28478
  {
27328
28479
  id: 'page.template.applyMasterDetail',
27329
- intentExamples: ['criar página master detail', 'setup master detail', 'tabela e formulário', 'master-detail'],
28480
+ intentExamples: [
28481
+ 'criar página master detail',
28482
+ 'setup master detail',
28483
+ 'tabela e formulário',
28484
+ 'master-detail',
28485
+ ],
27330
28486
  operation: 'create',
27331
28487
  scope: 'GLOBAL',
27332
28488
  valueType: 'OBJECT',
@@ -27373,11 +28529,19 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27373
28529
  id: '{{params.tableId}}.rowClick->{{params.formId}}.resourceId',
27374
28530
  from: {
27375
28531
  kind: 'component-port',
27376
- ref: { widget: '{{params.tableId}}', port: 'rowClick', direction: 'output' },
28532
+ ref: {
28533
+ widget: '{{params.tableId}}',
28534
+ port: 'rowClick',
28535
+ direction: 'output',
28536
+ },
27377
28537
  },
27378
28538
  to: {
27379
28539
  kind: 'component-port',
27380
- ref: { widget: '{{params.formId}}', port: 'resourceId', direction: 'input' },
28540
+ ref: {
28541
+ widget: '{{params.formId}}',
28542
+ port: 'resourceId',
28543
+ direction: 'input',
28544
+ },
27381
28545
  },
27382
28546
  intent: 'event-propagation',
27383
28547
  transform: {
@@ -27412,7 +28576,8 @@ const DYNAMIC_PAGE_COMPONENT_CONTEXT_PACK = {
27412
28576
  hints: [
27413
28577
  'praxis-dynamic-page e runtime de composicao: consome WidgetPageDefinition, renderiza widgets e mantem relacoes em page.composition.links.',
27414
28578
  'Mutações agentic de página pertencem ao manifesto do praxis-page-builder; use este context pack como descoberta/runtime guidance.',
27415
- 'WidgetPageDefinition inclui widgets, composition.links, state, context, layout, canvas, layoutPreset, layoutPresetOptions, grouping, slotAssignments, deviceLayouts e themePreset.',
28579
+ 'WidgetPageDefinition inclui widgets, composition.links, state, context, i18n, layout, canvas, layoutPreset, layoutPresetOptions, grouping, slotAssignments, deviceLayouts e themePreset.',
28580
+ 'page.i18n carrega copy de negócio do documento; use descritores PraxisTextValue explícitos em shells e inputs e preserve strings comuns como dados do domínio.',
27416
28581
  'page.canvas.items é um mapa por widget key, não um array; cada entrada guarda col, row, colSpan, rowSpan, zIndex e constraints opcionais.',
27417
28582
  'Widgets e composition.links sao arrays; o patching deve fazer merge por key (widgets) e por id (links).',
27418
28583
  'Preferir mudanças incrementais: alterar/estender em vez de substituir toda a página.',
@@ -30455,7 +31620,7 @@ class WidgetShellComponent {
30455
31620
  @if (expanded || fullscreen) {
30456
31621
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
30457
31622
  }
30458
- `, 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:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
31623
+ `, isInline: true, styles: [":host{display:block;height:100%}:host(.pdx-widget-shell-collapsed){height:auto}.pdx-shell{position:relative;height:100%;display:flex;flex-direction:column}.pdx-shell.no-shell{background:transparent;border:none;border-radius:0;box-shadow:none}.pdx-shell.dashboard{background:var(--pdx-shell-card-bg, var(--pdx-dashboard-card-bg, var(--md-sys-color-surface-container-low)));border:1px solid var(--pdx-shell-card-border, var(--pdx-dashboard-card-border, var(--md-sys-color-outline-variant)));border-radius:var(--pdx-shell-card-radius, 12px);box-shadow:var(--pdx-shell-card-shadow, 0 4px 12px rgba(15, 23, 42, .06));overflow:hidden}.pdx-shell-header{display:flex;align-items:center;gap:10px;padding:8px 10px 7px;border-bottom:1px solid var(--pdx-shell-header-border, var(--md-sys-color-outline-variant));background:var(--pdx-shell-header-bg, var(--md-sys-color-surface-container))}.pdx-shell-header--drag-enabled{cursor:grab;-webkit-user-select:none;user-select:none;touch-action:none}.pdx-shell-header--drag-enabled:active{cursor:grabbing}.pdx-shell-header--drag-enabled:focus-visible{outline:2px solid color-mix(in srgb,var(--md-sys-color-primary) 72%,white 28%);outline-offset:-2px}.pdx-shell-title{display:flex;align-items:center;gap:8px;min-width:0;flex:1;color:var(--pdx-shell-title-color, inherit)}.pdx-shell-title mat-icon{color:var(--pdx-shell-icon-color, currentColor)}.pdx-shell-text{min-width:0}.pdx-shell-title-text{font-weight:var(--pdx-shell-title-weight, 600);font-size:var(--pdx-shell-title-size, 13px);line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-subtitle{font-size:var(--pdx-shell-subtitle-size, 11px);opacity:.75;color:var(--pdx-shell-subtitle-color, currentColor);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pdx-shell-actions,.pdx-shell-window-actions{display:flex;align-items:center;gap:4px}.pdx-shell-window-actions{margin-left:auto}@media(max-width:640px){.pdx-shell-header,.pdx-shell-title{align-items:flex-start}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical}.pdx-shell-title-text,.pdx-shell-subtitle{-webkit-line-clamp:2}.pdx-shell-actions{flex:0 0 auto}}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i4.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i4.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i4.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
30459
31624
  }
30460
31625
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: WidgetShellComponent, decorators: [{
30461
31626
  type: Component,
@@ -30601,7 +31766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
30601
31766
  @if (expanded || fullscreen) {
30602
31767
  <div class="pdx-shell-backdrop" (click)="closeOverlay()"></div>
30603
31768
  }
30604
- `, 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:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
31769
+ `, 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}@media(max-width:640px){.pdx-shell-header,.pdx-shell-title{align-items:flex-start}.pdx-shell-text{display:grid;gap:2px}.pdx-shell-title-text,.pdx-shell-subtitle{display:-webkit-box;white-space:normal;overflow-wrap:anywhere;-webkit-box-orient:vertical}.pdx-shell-title-text,.pdx-shell-subtitle{-webkit-line-clamp:2}.pdx-shell-actions{flex:0 0 auto}}.pdx-action-outlined{border:1px solid var(--md-sys-color-outline-variant);border-radius:999px;padding:0 10px}.pdx-action-text{padding:0 8px}.pdx-shell-action--pressed:not(.praxis-icon-button){color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}.pdx-action-label{font-size:12px;font-weight:500}.pdx-shell-body{flex:1;min-height:0;padding:var(--pdx-shell-body-padding, 8px 10px 10px 10px);background:var(--pdx-shell-body-bg, transparent);color:var(--pdx-shell-body-color, inherit)}.pdx-shell.no-shell .pdx-shell-body{padding:0}.pdx-shell-body.hidden{display:none}.pdx-shell.collapsed{height:auto}.pdx-shell.collapsed .pdx-shell-header{border-bottom-color:transparent}.pdx-shell.body-fill .pdx-shell-body,.pdx-shell.body-scroll .pdx-shell-body,.pdx-shell.expanded .pdx-shell-body,.pdx-shell.fullscreen .pdx-shell-body{overflow:auto;display:flex;flex-direction:column;min-height:0}.pdx-shell.collapsed .pdx-shell-body{display:none}.pdx-shell.body-fill .pdx-shell-body{overflow:hidden}.pdx-shell.body-scroll .pdx-shell-body{overflow:auto}.pdx-shell.body-fill .pdx-shell-body>*,.pdx-shell.body-scroll .pdx-shell-body>*,.pdx-shell.expanded .pdx-shell-body>*,.pdx-shell.fullscreen .pdx-shell-body>*{flex:1 1 auto;min-height:0;width:100%}.pdx-shell.expanded{position:fixed;top:10vh;left:50%;width:min(920px,92vw);height:min(640px,82vh);transform:translate(-50%);z-index:var(--praxis-layer-widget-shell-expanded, 1290);box-shadow:var(--mat-elevation-level8)}.pdx-shell.fullscreen{position:fixed;inset:0;width:auto;height:auto;transform:none;border-radius:0;z-index:var(--praxis-layer-widget-shell-fullscreen, 1291);box-shadow:var(--mat-elevation-level8)}.pdx-shell-backdrop{position:fixed;inset:0;z-index:var(--praxis-layer-widget-shell-backdrop, 1280);background:#0000008c;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
30605
31770
  }], propDecorators: { hostCollapsed: [{
30606
31771
  type: HostBinding,
30607
31772
  args: ['class.pdx-widget-shell-collapsed']
@@ -35059,7 +36224,8 @@ class DynamicWidgetPageComponent {
35059
36224
  ngOnChanges(changes) {
35060
36225
  if (changes['page'] ||
35061
36226
  changes['context'] ||
35062
- changes['enableCustomization']) {
36227
+ changes['enableCustomization'] ||
36228
+ changes['pageIdentity']) {
35063
36229
  this.widgetShellRenderCache.clear();
35064
36230
  const parsed = this.parsePage(this.page);
35065
36231
  const resolvedPage = parsed ? this.resolvePagePresets(parsed) : parsed;
@@ -35144,10 +36310,10 @@ class DynamicWidgetPageComponent {
35144
36310
  const stateProjectionChanged = !this.areStateValuesEqual(widgets, projectedWidgets);
35145
36311
  widgets = projectedWidgets;
35146
36312
  const nextRuntime = this.buildStateRuntime(state, pageWithPatchedInputs.context);
35147
- if (this.isTransientOnlyCompositionCycle(cycle)
35148
- && !updatedPrimaryStatePaths.length
35149
- && !directDelivery.changed
35150
- && !widgetInputPatchResult.changed) {
36313
+ if (this.isTransientOnlyCompositionCycle(cycle) &&
36314
+ !updatedPrimaryStatePaths.length &&
36315
+ !directDelivery.changed &&
36316
+ !widgetInputPatchResult.changed) {
35151
36317
  this.applyResponsivePresentation(pageWithPatchedInputs, widgets, nextRuntime);
35152
36318
  return;
35153
36319
  }
@@ -35166,8 +36332,8 @@ class DynamicWidgetPageComponent {
35166
36332
  const linksById = new Map(this.compositionDefinition.links.map((link) => [link.id, link]));
35167
36333
  return cycle.matchedLinkIds.every((linkId) => {
35168
36334
  const link = linksById.get(linkId);
35169
- return link?.to.kind === 'state'
35170
- && (link.to.ref.layer ?? 'values') === 'transient';
36335
+ return (link?.to.kind === 'state' &&
36336
+ (link.to.ref.layer ?? 'values') === 'transient');
35171
36337
  });
35172
36338
  }
35173
36339
  applyWidgetInputPatchToPage(page, widgetKey, evt) {
@@ -35246,7 +36412,8 @@ class DynamicWidgetPageComponent {
35246
36412
  const nestedPath = normalizeWidgetEventPath(evt, {
35247
36413
  ownerComponentId: owner.definition.id,
35248
36414
  });
35249
- if (nestedPath.length && this.nestedWidgetAccessor.resolveNestedWidget(owner, nestedPath)) {
36415
+ if (nestedPath.length &&
36416
+ this.nestedWidgetAccessor.resolveNestedWidget(owner, nestedPath)) {
35250
36417
  return nestedPath;
35251
36418
  }
35252
36419
  const sourceChildWidgetKey = String(evt?.sourceChildWidgetKey || '').trim();
@@ -35254,16 +36421,18 @@ class DynamicWidgetPageComponent {
35254
36421
  return null;
35255
36422
  }
35256
36423
  const sourceComponentId = String(evt?.sourceComponentId || '').trim();
35257
- const match = this.nestedWidgetAccessor.listNestedWidgets(owner).find((candidate) => candidate.childWidgetKey === sourceChildWidgetKey
35258
- && (!sourceComponentId || candidate.componentId === sourceComponentId));
36424
+ const match = this.nestedWidgetAccessor
36425
+ .listNestedWidgets(owner)
36426
+ .find((candidate) => candidate.childWidgetKey === sourceChildWidgetKey &&
36427
+ (!sourceComponentId || candidate.componentId === sourceComponentId));
35259
36428
  return match?.nestedPath || null;
35260
36429
  }
35261
36430
  extractWidgetInputPatch(payload) {
35262
36431
  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
35263
36432
  return null;
35264
36433
  }
35265
- const candidate = payload.inputPatch
35266
- ?? payload.payload?.inputPatch;
36434
+ const candidate = payload.inputPatch ??
36435
+ payload.payload?.inputPatch;
35267
36436
  if (!candidate ||
35268
36437
  typeof candidate !== 'object' ||
35269
36438
  Array.isArray(candidate)) {
@@ -35284,8 +36453,7 @@ class DynamicWidgetPageComponent {
35284
36453
  const hasWidgetInput = Object.prototype.hasOwnProperty.call(declaredInputs, inputName);
35285
36454
  const hasMetadataInput = !!this.componentMetadata
35286
36455
  ?.get(widget.definition?.id || '')
35287
- ?.inputs
35288
- ?.some((input) => input.name === inputName);
36456
+ ?.inputs?.some((input) => input.name === inputName);
35289
36457
  if (!hasWidgetInput && !hasMetadataInput) {
35290
36458
  return null;
35291
36459
  }
@@ -35367,10 +36535,12 @@ class DynamicWidgetPageComponent {
35367
36535
  activeWidgetKeys: widgetKeys.slice(0, 80),
35368
36536
  selectedWidgetKey,
35369
36537
  composition: {
35370
- version: this.pageDefinition?.composition?.version
35371
- || '1.0.0',
36538
+ version: this.pageDefinition?.composition?.version || '1.0.0',
35372
36539
  linkCount: compositionLinks.length,
35373
- linkIds: compositionLinks.map((link) => link.id).filter(Boolean).slice(0, 80),
36540
+ linkIds: compositionLinks
36541
+ .map((link) => link.id)
36542
+ .filter(Boolean)
36543
+ .slice(0, 80),
35374
36544
  },
35375
36545
  relationSurfaceRefs: compositionSurfaceRefs.slice(0, 80),
35376
36546
  },
@@ -35406,23 +36576,27 @@ class DynamicWidgetPageComponent {
35406
36576
  };
35407
36577
  }
35408
36578
  registerRuntimeComponentObservationProvider() {
35409
- if (!this.runtimeObservationRegistry || this.runtimeObservationRegistration) {
36579
+ if (!this.runtimeObservationRegistry ||
36580
+ this.runtimeObservationRegistration) {
35410
36581
  return;
35411
36582
  }
35412
- this.runtimeObservationRegistration = this.runtimeObservationRegistry.register({
35413
- getObservation: () => this.buildRuntimeComponentObservation(),
35414
- });
36583
+ this.runtimeObservationRegistration =
36584
+ this.runtimeObservationRegistry.register({
36585
+ getObservation: () => this.buildRuntimeComponentObservation(),
36586
+ });
35415
36587
  }
35416
36588
  resolveRuntimePageId() {
35417
- const identityKey = this.pageIdentity ? buildPageKey(this.pageIdentity) : '';
35418
- return this.componentInstanceId
35419
- || identityKey
35420
- || this.stringOrNull(this.pageDefinition?.context?.['pageId'])
35421
- || 'dynamic-page:default';
36589
+ const identityKey = this.pageIdentity
36590
+ ? buildPageKey(this.pageIdentity)
36591
+ : '';
36592
+ return (this.componentInstanceId ||
36593
+ identityKey ||
36594
+ this.stringOrNull(this.pageDefinition?.context?.['pageId']) ||
36595
+ 'dynamic-page:default');
35422
36596
  }
35423
36597
  resolveRuntimeComponentInstanceId(pageId) {
35424
- return this.componentInstanceId
35425
- || (pageId ? `dynamic-page:${pageId}` : 'dynamic-page:default');
36598
+ return (this.componentInstanceId ||
36599
+ (pageId ? `dynamic-page:${pageId}` : 'dynamic-page:default'));
35426
36600
  }
35427
36601
  isRuntimeObservationVisible() {
35428
36602
  const nativeElement = this.pageCanvasHost?.nativeElement;
@@ -35438,13 +36612,19 @@ class DynamicWidgetPageComponent {
35438
36612
  label: surface.label,
35439
36613
  sourceWidget: surface.source.widget,
35440
36614
  targetWidget: surface.target.widget,
35441
- ...(surface.target.resourcePath ? { targetResourcePath: surface.target.resourcePath } : {}),
35442
- ...(surface.runtimeSurfaceInstanceRef ? {
35443
- runtimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
35444
- targetRuntimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
35445
- } : {}),
36615
+ ...(surface.target.resourcePath
36616
+ ? { targetResourcePath: surface.target.resourcePath }
36617
+ : {}),
36618
+ ...(surface.runtimeSurfaceInstanceRef
36619
+ ? {
36620
+ runtimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
36621
+ targetRuntimeSurfaceInstanceRef: surface.runtimeSurfaceInstanceRef,
36622
+ }
36623
+ : {}),
35446
36624
  statePath: surface.statePath,
35447
- ...(surface.queryMapping ? { queryMapping: surface.queryMapping } : {}),
36625
+ ...(surface.queryMapping
36626
+ ? { queryMapping: surface.queryMapping }
36627
+ : {}),
35448
36628
  operationId: surface.operationId,
35449
36629
  });
35450
36630
  }
@@ -35455,10 +36635,18 @@ class DynamicWidgetPageComponent {
35455
36635
  const claims = [
35456
36636
  { kind: 'component', ref: 'praxis-dynamic-page', observed: true },
35457
36637
  { kind: 'stateDigest', ref: `page:${context.pageId}`, observed: true },
35458
- { kind: 'dataDigest', ref: `page:${context.pageId}:composition`, observed: true },
36638
+ {
36639
+ kind: 'dataDigest',
36640
+ ref: `page:${context.pageId}:composition`,
36641
+ observed: true,
36642
+ },
35459
36643
  ];
35460
36644
  for (const widgetKey of context.widgetKeys.slice(0, 80)) {
35461
- claims.push({ kind: 'component', ref: `widget:${widgetKey}`, observed: true });
36645
+ claims.push({
36646
+ kind: 'component',
36647
+ ref: `widget:${widgetKey}`,
36648
+ observed: true,
36649
+ });
35462
36650
  }
35463
36651
  for (const surfaceRef of context.activeSurfaceRefs.slice(0, 80)) {
35464
36652
  claims.push({ kind: 'surface', ref: surfaceRef, observed: true });
@@ -35528,9 +36716,9 @@ class DynamicWidgetPageComponent {
35528
36716
  const sourceWidget = widgetByKey.get(sourceRef.widget);
35529
36717
  if (!sourceWidget)
35530
36718
  continue;
35531
- const targets = stateToQueryLinks.filter((link) => link.from.kind === 'state'
35532
- && link.from.ref.path === statePath
35533
- && link.to.kind === 'component-port');
36719
+ const targets = stateToQueryLinks.filter((link) => link.from.kind === 'state' &&
36720
+ link.from.ref.path === statePath &&
36721
+ link.to.kind === 'component-port');
35534
36722
  if (!targets.length)
35535
36723
  continue;
35536
36724
  const sourceKey = this.recordSurfaceSourceKey(sourceRef.widget, sourceRef.nestedPath);
@@ -35589,9 +36777,9 @@ class DynamicWidgetPageComponent {
35589
36777
  return surfacesBySource;
35590
36778
  }
35591
36779
  resolveRecordSurfaceQueryMapping(sourceWidget, targetLink) {
35592
- const sourceField = this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['meta']?.['idField'])
35593
- || this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['idField'])
35594
- || this.stringOrNull(sourceWidget?.definition.inputs?.['idField']);
36780
+ const sourceField = this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['meta']?.['idField']) ||
36781
+ this.stringOrNull(sourceWidget?.definition.inputs?.['config']?.['idField']) ||
36782
+ this.stringOrNull(sourceWidget?.definition.inputs?.['idField']);
35595
36783
  const targetFilterField = this.resolveQueryContextFilterField(targetLink);
35596
36784
  if (!sourceField || !targetFilterField) {
35597
36785
  return undefined;
@@ -35622,24 +36810,31 @@ class DynamicWidgetPageComponent {
35622
36810
  return null;
35623
36811
  }
35624
36812
  isTableRowClickToStateLink(link) {
35625
- return link.from.kind === 'component-port'
35626
- && link.from.ref.componentType === 'praxis-table'
35627
- && link.from.ref.port === 'rowClick'
35628
- && link.from.ref.direction === 'output'
35629
- && link.to.kind === 'state'
35630
- && !!link.to.ref.path;
36813
+ return (link.from.kind === 'component-port' &&
36814
+ link.from.ref.componentType === 'praxis-table' &&
36815
+ link.from.ref.port === 'rowClick' &&
36816
+ link.from.ref.direction === 'output' &&
36817
+ link.to.kind === 'state' &&
36818
+ !!link.to.ref.path);
35631
36819
  }
35632
36820
  isStateToTableQueryContextLink(link) {
35633
- return link.from.kind === 'state'
35634
- && !!link.from.ref.path
35635
- && link.to.kind === 'component-port'
35636
- && link.to.ref.componentType === 'praxis-table'
35637
- && link.to.ref.port === 'queryContext'
35638
- && link.to.ref.direction === 'input';
36821
+ return (link.from.kind === 'state' &&
36822
+ !!link.from.ref.path &&
36823
+ link.to.kind === 'component-port' &&
36824
+ link.to.ref.componentType === 'praxis-table' &&
36825
+ link.to.ref.port === 'queryContext' &&
36826
+ link.to.ref.direction === 'input');
35639
36827
  }
35640
36828
  resolveRecordSurfaceId(ref) {
35641
- const tab = [...(ref.nestedPath || [])].reverse().find((segment) => segment.kind === 'tab');
35642
- return String(tab?.id || ref.nestedPath?.map((segment) => segment.key || segment.id).filter(Boolean).join('.') || ref.widget).trim();
36829
+ const tab = [...(ref.nestedPath || [])]
36830
+ .reverse()
36831
+ .find((segment) => segment.kind === 'tab');
36832
+ return String(tab?.id ||
36833
+ ref.nestedPath
36834
+ ?.map((segment) => segment.key || segment.id)
36835
+ .filter(Boolean)
36836
+ .join('.') ||
36837
+ ref.widget).trim();
35643
36838
  }
35644
36839
  resolveRecordSurfaceLabel(ref, targetWidget, targetDefinition) {
35645
36840
  const tabLabel = this.resolveRecordSurfaceTabLabel(ref, targetWidget);
@@ -35648,29 +36843,33 @@ class DynamicWidgetPageComponent {
35648
36843
  const toolbarTitle = this.stringOrNull(targetDefinition?.inputs?.['config']?.['toolbar']?.['title']);
35649
36844
  if (toolbarTitle)
35650
36845
  return toolbarTitle;
35651
- const tab = [...(ref.nestedPath || [])].reverse().find((segment) => segment.kind === 'tab');
36846
+ const tab = [...(ref.nestedPath || [])]
36847
+ .reverse()
36848
+ .find((segment) => segment.kind === 'tab');
35652
36849
  return this.humanizeRecordSurfaceLabel(tab?.id || ref.widget);
35653
36850
  }
35654
36851
  resolveRuntimeSurfaceWidgetKey(targetRef, targetDefinition) {
35655
- return this.stringOrNull(targetDefinition?.inputs?.['componentInstanceId'])
35656
- || this.stringOrNull(targetDefinition?.inputs?.['tableId'])
35657
- || targetRef.widget;
36852
+ return (this.stringOrNull(targetDefinition?.inputs?.['componentInstanceId']) ||
36853
+ this.stringOrNull(targetDefinition?.inputs?.['tableId']) ||
36854
+ targetRef.widget);
35658
36855
  }
35659
36856
  resolveRecordSurfaceTabLabel(ref, targetWidget) {
35660
- const tab = [...(ref.nestedPath || [])].reverse().find((segment) => segment.kind === 'tab');
36857
+ const tab = [...(ref.nestedPath || [])]
36858
+ .reverse()
36859
+ .find((segment) => segment.kind === 'tab');
35661
36860
  if (!tab)
35662
36861
  return null;
35663
36862
  const tabs = targetWidget?.definition.inputs?.['config']?.['tabs'];
35664
36863
  if (!Array.isArray(tabs))
35665
36864
  return null;
35666
- const match = tabs.find((candidate) => this.isRecord(candidate)
35667
- && (this.stringOrNull(candidate['id']) === this.stringOrNull(tab.id)
35668
- || candidate['index'] === tab.index));
36865
+ const match = tabs.find((candidate) => this.isRecord(candidate) &&
36866
+ (this.stringOrNull(candidate['id']) === this.stringOrNull(tab.id) ||
36867
+ candidate['index'] === tab.index));
35669
36868
  if (!this.isRecord(match))
35670
36869
  return null;
35671
- return this.stringOrNull(match['textLabel'])
35672
- || this.stringOrNull(match['label'])
35673
- || this.stringOrNull(match['title']);
36870
+ return (this.stringOrNull(match['textLabel']) ||
36871
+ this.stringOrNull(match['label']) ||
36872
+ this.stringOrNull(match['title']));
35674
36873
  }
35675
36874
  humanizeRecordSurfaceLabel(value) {
35676
36875
  const raw = String(value || '').trim();
@@ -35699,11 +36898,15 @@ class DynamicWidgetPageComponent {
35699
36898
  .slice(0, 120);
35700
36899
  }
35701
36900
  resolveRecordSurfaceChildWidgetKey(path) {
35702
- const widget = [...(path || [])].reverse().find((segment) => segment.kind === 'widget');
36901
+ const widget = [...(path || [])]
36902
+ .reverse()
36903
+ .find((segment) => segment.kind === 'widget');
35703
36904
  return widget?.key;
35704
36905
  }
35705
36906
  recordSurfaceSourceKey(widget, nestedPath) {
35706
- const signature = nestedPath?.length ? this.recordSurfaceNestedPathSignature(nestedPath) : '';
36907
+ const signature = nestedPath?.length
36908
+ ? this.recordSurfaceNestedPathSignature(nestedPath)
36909
+ : '';
35707
36910
  return `${widget}::${signature}`;
35708
36911
  }
35709
36912
  recordSurfaceNestedPathSignature(path) {
@@ -35712,7 +36915,9 @@ class DynamicWidgetPageComponent {
35712
36915
  parseRecordSurfaceNestedPathSignature(signature) {
35713
36916
  try {
35714
36917
  const parsed = JSON.parse(decodeURIComponent(signature));
35715
- return Array.isArray(parsed) ? parsed : [];
36918
+ return Array.isArray(parsed)
36919
+ ? parsed
36920
+ : [];
35716
36921
  }
35717
36922
  catch {
35718
36923
  return [];
@@ -35729,8 +36934,12 @@ class DynamicWidgetPageComponent {
35729
36934
  if (evt?.output !== 'recordSurfaceOpen')
35730
36935
  return false;
35731
36936
  const payload = this.isRecord(evt.payload) ? evt.payload : null;
35732
- const surface = this.isRecord(payload?.['surface']) ? payload['surface'] : null;
35733
- const target = this.isRecord(surface?.['target']) ? surface['target'] : null;
36937
+ const surface = this.isRecord(payload?.['surface'])
36938
+ ? payload['surface']
36939
+ : null;
36940
+ const target = this.isRecord(surface?.['target'])
36941
+ ? surface['target']
36942
+ : null;
35734
36943
  const widgetKey = this.stringOrNull(target?.['widget']);
35735
36944
  const nestedPath = Array.isArray(target?.['nestedPath'])
35736
36945
  ? target['nestedPath']
@@ -35785,7 +36994,9 @@ class DynamicWidgetPageComponent {
35785
36994
  return true;
35786
36995
  }
35787
36996
  applyRecordSurfaceSourceState(page, fromKey, evt, surface, payload) {
35788
- const source = this.isRecord(surface?.['source']) ? surface['source'] : null;
36997
+ const source = this.isRecord(surface?.['source'])
36998
+ ? surface['source']
36999
+ : null;
35789
37000
  const selectedRow = payload?.['selectedRow'];
35790
37001
  if (!source || selectedRow == null) {
35791
37002
  return { page };
@@ -35828,14 +37039,18 @@ class DynamicWidgetPageComponent {
35828
37039
  }
35829
37040
  findRecordSurfaceTabIndex(config, segment) {
35830
37041
  const collection = segment.kind === 'nav'
35831
- ? (this.isRecord(config['nav']) && Array.isArray(config['nav']['links']) ? config['nav']['links'] : [])
35832
- : (Array.isArray(config['tabs']) ? config['tabs'] : []);
37042
+ ? this.isRecord(config['nav']) && Array.isArray(config['nav']['links'])
37043
+ ? config['nav']['links']
37044
+ : []
37045
+ : Array.isArray(config['tabs'])
37046
+ ? config['tabs']
37047
+ : [];
35833
37048
  const id = this.stringOrNull(segment.id);
35834
37049
  const key = this.stringOrNull(segment.key);
35835
37050
  if (id || key) {
35836
37051
  const match = collection.findIndex((item) => {
35837
37052
  const record = this.isRecord(item) ? item : {};
35838
- return (!!id && record['id'] === id) || (!!key && record['key'] === key);
37053
+ return ((!!id && record['id'] === id) || (!!key && record['key'] === key));
35839
37054
  });
35840
37055
  if (match >= 0)
35841
37056
  return match;
@@ -35847,7 +37062,7 @@ class DynamicWidgetPageComponent {
35847
37062
  return true;
35848
37063
  }
35849
37064
  const bindingOrder = widget.definition.bindingOrder;
35850
- return Array.isArray(bindingOrder) && bindingOrder.includes('selectedIndex');
37065
+ return (Array.isArray(bindingOrder) && bindingOrder.includes('selectedIndex'));
35851
37066
  }
35852
37067
  reportStateDiagnostics(diagnostics) {
35853
37068
  if (!diagnostics?.length)
@@ -35940,18 +37155,18 @@ class DynamicWidgetPageComponent {
35940
37155
  this.applyPageUpdate({ ...page, widgets, state }, true, runtime, false, true);
35941
37156
  }
35942
37157
  matchesRuntimeSourceRef(endpoint, sourceRef) {
35943
- return endpoint.kind === 'component-port'
35944
- && endpoint.ref.widget === sourceRef.widget
35945
- && endpoint.ref.port === sourceRef.port
35946
- && endpoint.ref.direction === sourceRef.direction
35947
- && this.areNestedPathsEqual(endpoint.ref.nestedPath, sourceRef.nestedPath);
37158
+ return (endpoint.kind === 'component-port' &&
37159
+ endpoint.ref.widget === sourceRef.widget &&
37160
+ endpoint.ref.port === sourceRef.port &&
37161
+ endpoint.ref.direction === sourceRef.direction &&
37162
+ this.areNestedPathsEqual(endpoint.ref.nestedPath, sourceRef.nestedPath));
35948
37163
  }
35949
37164
  matchesLegacyWidgetEventSource(endpoint, ownerWidgetKey) {
35950
- return endpoint.kind === 'component-port'
35951
- && endpoint.ref.widget === ownerWidgetKey
35952
- && endpoint.ref.port === 'widgetEvent'
35953
- && endpoint.ref.direction === 'output'
35954
- && !endpoint.ref.nestedPath?.length;
37165
+ return (endpoint.kind === 'component-port' &&
37166
+ endpoint.ref.widget === ownerWidgetKey &&
37167
+ endpoint.ref.port === 'widgetEvent' &&
37168
+ endpoint.ref.direction === 'output' &&
37169
+ !endpoint.ref.nestedPath?.length);
35955
37170
  }
35956
37171
  areNestedPathsEqual(left, right) {
35957
37172
  return JSON.stringify(left || []) === JSON.stringify(right || []);
@@ -36088,8 +37303,8 @@ class DynamicWidgetPageComponent {
36088
37303
  pageStateEffective: this.cloneStateValues(runtime.effectiveValues),
36089
37304
  };
36090
37305
  return this.cloneWidgets(widgets).map((widget) => {
36091
- const runtimeEnrichedWidget = this.enrichRuntimeWidgetInputs(widget, runtime);
36092
- if (!widget.shell) {
37306
+ const runtimeEnrichedWidget = this.localizeRuntimeProjection(this.enrichRuntimeWidgetInputs(widget, runtime));
37307
+ if (!runtimeEnrichedWidget.shell) {
36093
37308
  return runtimeEnrichedWidget;
36094
37309
  }
36095
37310
  const widgetTemplateContext = {
@@ -36103,10 +37318,17 @@ class DynamicWidgetPageComponent {
36103
37318
  };
36104
37319
  return {
36105
37320
  ...runtimeEnrichedWidget,
36106
- shell: this.resolveTemplate(widget.shell, widgetTemplateContext),
37321
+ shell: this.resolveTemplate(runtimeEnrichedWidget.shell, widgetTemplateContext),
36107
37322
  };
36108
37323
  });
36109
37324
  }
37325
+ localizeRuntimeProjection(value) {
37326
+ return resolvePraxisI18nDocument(value, {
37327
+ i18n: this.i18n,
37328
+ locale: this.pageIdentity?.locale,
37329
+ config: this.pageDefinition?.i18n,
37330
+ });
37331
+ }
36110
37332
  enrichRuntimeWidgetInputs(widget, runtime) {
36111
37333
  if (widget.definition?.id !== 'praxis-rich-content') {
36112
37334
  return widget;
@@ -36134,7 +37356,8 @@ class DynamicWidgetPageComponent {
36134
37356
  return;
36135
37357
  }
36136
37358
  if (this.globalActions.has(actionId)) {
36137
- void this.globalActions.execute(actionId, payload, {
37359
+ void this.globalActions
37360
+ .execute(actionId, payload, {
36138
37361
  sourceId: widgetKey,
36139
37362
  widgetKey,
36140
37363
  payload: {
@@ -36156,7 +37379,8 @@ class DynamicWidgetPageComponent {
36156
37379
  origin: 'dynamic-page.rich-content',
36157
37380
  componentId: 'praxis-dynamic-page',
36158
37381
  },
36159
- }).then((result) => {
37382
+ })
37383
+ .then((result) => {
36160
37384
  if (!result?.success) {
36161
37385
  this.emitRichContentCustomAction(widgetKey, actionId, payload);
36162
37386
  }
@@ -36306,9 +37530,7 @@ class DynamicWidgetPageComponent {
36306
37530
  });
36307
37531
  }
36308
37532
  shouldRenderWidgetContextOverlay(widget) {
36309
- return (this.enableCustomization &&
36310
- this.isWidgetSelected(widget.key) &&
36311
- !this.hasVisibleWidgetShellHeader(widget));
37533
+ return (this.enableCustomization && !this.hasVisibleWidgetShellHeader(widget));
36312
37534
  }
36313
37535
  widgetShellForRender(widget) {
36314
37536
  if (!this.shouldProjectWidgetHeaderActions(widget)) {
@@ -36346,13 +37568,13 @@ class DynamicWidgetPageComponent {
36346
37568
  if (shellTitle)
36347
37569
  return shellTitle;
36348
37570
  const componentId = widget.definition?.id || '';
36349
- const metadata = componentId ? this.componentMetadata?.get(componentId) : undefined;
37571
+ const metadata = componentId
37572
+ ? this.componentMetadata?.get(componentId)
37573
+ : undefined;
36350
37574
  return metadata?.friendlyName || componentId || widget.key;
36351
37575
  }
36352
37576
  shouldProjectWidgetHeaderActions(widget) {
36353
- return (this.enableCustomization &&
36354
- this.isWidgetSelected(widget.key) &&
36355
- this.hasVisibleWidgetShellHeader(widget));
37577
+ return this.enableCustomization && this.hasVisibleWidgetShellHeader(widget);
36356
37578
  }
36357
37579
  hasVisibleWidgetShellHeader(widget) {
36358
37580
  const shell = widget.shell;
@@ -36370,8 +37592,8 @@ class DynamicWidgetPageComponent {
36370
37592
  return (shell.actions || []).some((action) => this.isVisibleShellAction(action));
36371
37593
  }
36372
37594
  hasVisibleWindowActions(shell) {
36373
- return ((shell.windowActions?.collapsible !== false ||
36374
- shell.windowActions?.fullscreen !== false) ||
37595
+ return (shell.windowActions?.collapsible !== false ||
37596
+ shell.windowActions?.fullscreen !== false ||
36375
37597
  (shell.actions || []).some((action) => this.isVisibleShellAction(action) &&
36376
37598
  (action.placement || 'header') === 'window'));
36377
37599
  }
@@ -36718,10 +37940,10 @@ class DynamicWidgetPageComponent {
36718
37940
  }
36719
37941
  }
36720
37942
  isConfigEditorContextResult(value) {
36721
- return !!value &&
37943
+ return (!!value &&
36722
37944
  typeof value === 'object' &&
36723
37945
  !Array.isArray(value) &&
36724
- ('context' in value || 'diagnostics' in value);
37946
+ ('context' in value || 'diagnostics' in value));
36725
37947
  }
36726
37948
  materializeRuntimeInputsForWidget(page, key) {
36727
37949
  const normalizedKey = String(key || '').trim();
@@ -36734,8 +37956,7 @@ class DynamicWidgetPageComponent {
36734
37956
  }
36735
37957
  const inputNames = this.componentMetadata
36736
37958
  ?.get(widget.definition?.id || '')
36737
- ?.inputs
36738
- ?.map((input) => input.name)
37959
+ ?.inputs?.map((input) => input.name)
36739
37960
  ?.filter((name) => typeof name === 'string' && !!name.trim()) || [];
36740
37961
  if (!inputNames.length) {
36741
37962
  return page;
@@ -36766,10 +37987,10 @@ class DynamicWidgetPageComponent {
36766
37987
  if (typeof loader?.dispatchAction !== 'function') {
36767
37988
  return false;
36768
37989
  }
36769
- return loader?.dispatchAction({
37990
+ return (loader?.dispatchAction({
36770
37991
  id: 'component-settings',
36771
37992
  command: 'component-settings',
36772
- }) === true;
37993
+ }) === true);
36773
37994
  }
36774
37995
  applyWidgetComponentInputs(key, result, persist) {
36775
37996
  if (!result || typeof result !== 'object' || Array.isArray(result))
@@ -36882,7 +38103,9 @@ class DynamicWidgetPageComponent {
36882
38103
  const groupingOverrides = variant.groupingOverrides?.map((override) => ({
36883
38104
  ...override,
36884
38105
  ...(override.widgetKeys
36885
- ? { widgetKeys: override.widgetKeys.filter((key) => key !== widgetKey) }
38106
+ ? {
38107
+ widgetKeys: override.widgetKeys.filter((key) => key !== widgetKey),
38108
+ }
36886
38109
  : {}),
36887
38110
  ...(override.tabs
36888
38111
  ? {
@@ -36895,7 +38118,14 @@ class DynamicWidgetPageComponent {
36895
38118
  }));
36896
38119
  deviceLayouts[device] = {
36897
38120
  ...variant,
36898
- ...(variant.canvas ? { canvas: { ...variant.canvas, ...(canvasItems ? { items: canvasItems } : {}) } } : {}),
38121
+ ...(variant.canvas
38122
+ ? {
38123
+ canvas: {
38124
+ ...variant.canvas,
38125
+ ...(canvasItems ? { items: canvasItems } : {}),
38126
+ },
38127
+ }
38128
+ : {}),
36899
38129
  ...(widgetOverrides ? { widgetOverrides } : {}),
36900
38130
  ...(groupingOverrides ? { groupingOverrides } : {}),
36901
38131
  };
@@ -36905,11 +38135,11 @@ class DynamicWidgetPageComponent {
36905
38135
  return next;
36906
38136
  }
36907
38137
  linkReferencesWidget(link, widgetKey) {
36908
- return this.endpointReferencesWidget(link.from, widgetKey)
36909
- || this.endpointReferencesWidget(link.to, widgetKey);
38138
+ return (this.endpointReferencesWidget(link.from, widgetKey) ||
38139
+ this.endpointReferencesWidget(link.to, widgetKey));
36910
38140
  }
36911
38141
  endpointReferencesWidget(endpoint, widgetKey) {
36912
- return endpoint.kind === 'component-port' && endpoint.ref.widget === widgetKey;
38142
+ return (endpoint.kind === 'component-port' && endpoint.ref.widget === widgetKey);
36913
38143
  }
36914
38144
  openPageSettings() {
36915
38145
  if (!this.settingsPanel)
@@ -37272,7 +38502,7 @@ class DynamicWidgetPageComponent {
37272
38502
  }
37273
38503
  applyResponsivePresentation(pageDefinition, widgets, runtime) {
37274
38504
  const runtimeWidgets = this.projectRuntimeCompositionStateInputs(widgets);
37275
- const effective = this.resolveEffectivePresentation(pageDefinition, runtimeWidgets);
38505
+ const effective = this.resolveEffectivePresentation(pageDefinition, runtimeWidgets, runtime);
37276
38506
  if (effective.canvas) {
37277
38507
  this.applyCanvasLayout(effective.canvas, effective.layout, effective.grouping);
37278
38508
  }
@@ -37287,7 +38517,7 @@ class DynamicWidgetPageComponent {
37287
38517
  grouping: effective.grouping,
37288
38518
  });
37289
38519
  this.renderedGroups.set(effective.groups);
37290
- this.widgets.set(this.resolveShellTemplates(effective.widgets, runtime));
38520
+ this.widgets.set(effective.widgets);
37291
38521
  }
37292
38522
  projectPersistentCompositionStateInputs(widgets, state, now) {
37293
38523
  if (!this.compositionDefinition) {
@@ -37319,23 +38549,24 @@ class DynamicWidgetPageComponent {
37319
38549
  now: snapshot.generatedAt,
37320
38550
  }).widgets;
37321
38551
  }
37322
- resolveEffectivePresentation(pageDefinition, widgets) {
38552
+ resolveEffectivePresentation(pageDefinition, widgets, runtime) {
37323
38553
  const variant = this.resolveDeviceVariant(pageDefinition?.deviceLayouts);
37324
38554
  const layout = this.mergeLayout(pageDefinition?.layout, variant?.layout);
37325
- const grouping = this.applyGroupingOverrides(pageDefinition?.grouping, variant?.groupingOverrides);
38555
+ const grouping = this.localizeRuntimeProjection(this.applyGroupingOverrides(pageDefinition?.grouping, variant?.groupingOverrides));
37326
38556
  const baseWidgets = this.applyWidgetLayoutOverrides(this.applyEditShellActions(widgets), variant?.widgetOverrides);
37327
38557
  const canvas = this.resolveCanvas(pageDefinition?.canvas, variant?.canvas);
37328
38558
  const widgetsWithOverrides = canvas
37329
38559
  ? this.applyCanvasLayoutToWidgets(baseWidgets, canvas)
37330
38560
  : baseWidgets;
38561
+ const renderedWidgets = this.resolveShellTemplates(widgetsWithOverrides, runtime);
37331
38562
  const groups = canvas
37332
38563
  ? []
37333
- : this.buildRenderedGroups(grouping, widgetsWithOverrides, pageDefinition?.slotAssignments);
38564
+ : this.buildRenderedGroups(grouping, renderedWidgets, pageDefinition?.slotAssignments);
37334
38565
  return {
37335
38566
  layout,
37336
38567
  canvas,
37337
38568
  grouping,
37338
- widgets: widgetsWithOverrides,
38569
+ widgets: renderedWidgets,
37339
38570
  groups,
37340
38571
  };
37341
38572
  }
@@ -37408,9 +38639,9 @@ class DynamicWidgetPageComponent {
37408
38639
  if (!normalizedWidgetKey) {
37409
38640
  return false;
37410
38641
  }
37411
- return !!this.ensurePageDefinition().composition?.links?.some((link) => link.from.kind === 'component-port'
37412
- && link.from.ref.widget === normalizedWidgetKey
37413
- && link.from.ref.direction === 'output');
38642
+ return !!this.ensurePageDefinition().composition?.links?.some((link) => link.from.kind === 'component-port' &&
38643
+ link.from.ref.widget === normalizedWidgetKey &&
38644
+ link.from.ref.direction === 'output');
37414
38645
  }
37415
38646
  selectWidget(widgetKey) {
37416
38647
  if (!this.enableCustomization)
@@ -37425,15 +38656,10 @@ class DynamicWidgetPageComponent {
37425
38656
  }
37426
38657
  }
37427
38658
  selectWidgetFromHostEvent(widgetKey, event) {
37428
- if (this.shouldPreserveInnerWidgetInteraction(event)) {
37429
- return;
37430
- }
37431
38659
  if (event.type === 'focusin') {
37432
- setTimeout(() => {
37433
- if (!this.destroyed) {
37434
- this.selectWidget(widgetKey);
37435
- }
37436
- }, 0);
38660
+ if (event.target === event.currentTarget) {
38661
+ this.selectWidget(widgetKey);
38662
+ }
37437
38663
  return;
37438
38664
  }
37439
38665
  this.selectWidget(widgetKey);
@@ -37444,47 +38670,6 @@ class DynamicWidgetPageComponent {
37444
38670
  isWidgetSelected(widgetKey) {
37445
38671
  return this.selectedWidgetKeyState() === widgetKey;
37446
38672
  }
37447
- shouldPreserveInnerWidgetInteraction(event) {
37448
- if (!this.enableCustomization)
37449
- return false;
37450
- const target = event.target;
37451
- const currentTarget = event.currentTarget;
37452
- if (!(target instanceof HTMLElement) || !(currentTarget instanceof HTMLElement)) {
37453
- return false;
37454
- }
37455
- if (target === currentTarget) {
37456
- return false;
37457
- }
37458
- if (event.type === 'focusin') {
37459
- return true;
37460
- }
37461
- const shellHeader = target.closest('.pdx-shell-header');
37462
- if (shellHeader && currentTarget.contains(shellHeader)) {
37463
- return false;
37464
- }
37465
- return !!target.closest([
37466
- 'button',
37467
- 'a',
37468
- 'input',
37469
- 'select',
37470
- 'textarea',
37471
- '[contenteditable="true"]',
37472
- '[role="button"]',
37473
- '[role="tab"]',
37474
- '[role="menuitem"]',
37475
- '[role="option"]',
37476
- '[role="checkbox"]',
37477
- '[role="radio"]',
37478
- '[role="row"]',
37479
- '[role="gridcell"]',
37480
- '[mat-menu-trigger-for]',
37481
- '.mat-mdc-row',
37482
- '.mat-mdc-cell',
37483
- '.mat-mdc-header-cell',
37484
- '.pdx-widget-context-toolbar',
37485
- '.pdx-canvas-resize',
37486
- ].join(','));
37487
- }
37488
38673
  selectCanvasWidget(widgetKey) {
37489
38674
  this.selectWidget(widgetKey);
37490
38675
  }
@@ -38209,7 +39394,9 @@ class DynamicWidgetPageComponent {
38209
39394
  const seen = new Set();
38210
39395
  for (const reference of references || []) {
38211
39396
  const directWidget = widgetMap.get(reference);
38212
- const candidates = directWidget ? [directWidget] : slotWidgetMap.get(reference) || [];
39397
+ const candidates = directWidget
39398
+ ? [directWidget]
39399
+ : slotWidgetMap.get(reference) || [];
38213
39400
  for (const widget of candidates) {
38214
39401
  if (seen.has(widget.key))
38215
39402
  continue;
@@ -38394,7 +39581,7 @@ class DynamicWidgetPageComponent {
38394
39581
  [attr.data-density]="pageThemeDensity"
38395
39582
  [attr.data-motion]="pageThemeMotion"
38396
39583
  [ngStyle]="pageThemeTokenStyle"
38397
- >
39584
+ >
38398
39585
  @if (enableCustomization && showPageSettingsButton) {
38399
39586
  <button
38400
39587
  class="pdx-page-settings"
@@ -38434,6 +39621,7 @@ class DynamicWidgetPageComponent {
38434
39621
  [style.gridColumn]="widgetGridColumn(w)"
38435
39622
  [style.gridRow]="widgetGridRow(w)"
38436
39623
  [style.zIndex]="widgetZIndex(w)"
39624
+ (pointerdown)="selectWidget(w.key)"
38437
39625
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38438
39626
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38439
39627
  >
@@ -38485,7 +39673,9 @@ class DynamicWidgetPageComponent {
38485
39673
  [showAssistant]="showWidgetAssistantButton"
38486
39674
  [assistantLabel]="widgetAssistantLabel()"
38487
39675
  [assistantTooltip]="widgetAssistantTooltip()"
38488
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
39676
+ [showComponentSettings]="
39677
+ canOpenWidgetComponentSettings(w.key)
39678
+ "
38489
39679
  [componentSettingsLabel]="componentSettingsLabel()"
38490
39680
  [componentSettingsTooltip]="componentSettingsTooltip()"
38491
39681
  [showShellSettings]="canOpenWidgetShellSettings()"
@@ -38558,12 +39748,15 @@ class DynamicWidgetPageComponent {
38558
39748
  <div
38559
39749
  class="pdx-widget"
38560
39750
  [attr.data-widget-key]="w.key"
38561
- [class.pdx-widget--interactive]="enableCustomization"
39751
+ [class.pdx-widget--interactive]="
39752
+ enableCustomization
39753
+ "
38562
39754
  [class.pdx-widget--selected]="
38563
39755
  enableCustomization && isWidgetSelected(w.key)
38564
39756
  "
38565
39757
  [class]="w.renderClassName || w.className || ''"
38566
39758
  [style.gridColumn]="widgetGridColumn(w)"
39759
+ (pointerdown)="selectWidget(w.key)"
38567
39760
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38568
39761
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38569
39762
  >
@@ -38587,22 +39780,34 @@ class DynamicWidgetPageComponent {
38587
39780
  </praxis-widget-shell>
38588
39781
  @if (shouldRenderWidgetContextOverlay(w)) {
38589
39782
  <praxis-dynamic-widget-context-toolbar
38590
- [toolbarLabel]="widgetContextToolbarLabel(w.key)"
39783
+ [toolbarLabel]="
39784
+ widgetContextToolbarLabel(w.key)
39785
+ "
38591
39786
  [contextLabel]="widgetContextLabel(w)"
38592
39787
  [contextTooltip]="widgetContextTooltip(w)"
38593
39788
  [showAssistant]="showWidgetAssistantButton"
38594
39789
  [assistantLabel]="widgetAssistantLabel()"
38595
39790
  [assistantTooltip]="widgetAssistantTooltip()"
38596
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
38597
- [componentSettingsLabel]="componentSettingsLabel()"
38598
- [componentSettingsTooltip]="componentSettingsTooltip()"
38599
- [showShellSettings]="canOpenWidgetShellSettings()"
39791
+ [showComponentSettings]="
39792
+ canOpenWidgetComponentSettings(w.key)
39793
+ "
39794
+ [componentSettingsLabel]="
39795
+ componentSettingsLabel()
39796
+ "
39797
+ [componentSettingsTooltip]="
39798
+ componentSettingsTooltip()
39799
+ "
39800
+ [showShellSettings]="
39801
+ canOpenWidgetShellSettings()
39802
+ "
38600
39803
  [shellSettingsLabel]="widgetSettingsLabel()"
38601
39804
  [shellSettingsTooltip]="widgetSettingsTooltip()"
38602
39805
  [moreActionsLabel]="moreWidgetActionsLabel()"
38603
39806
  [removeLabel]="widgetRemoveLabel()"
38604
39807
  (assistant)="requestWidgetAssistant(w.key)"
38605
- (componentSettings)="openWidgetComponentSettings(w.key)"
39808
+ (componentSettings)="
39809
+ openWidgetComponentSettings(w.key)
39810
+ "
38606
39811
  (shellSettings)="openWidgetShellSettings(w.key)"
38607
39812
  (remove)="confirmAndRemoveWidget(w.key)"
38608
39813
  />
@@ -38630,6 +39835,7 @@ class DynamicWidgetPageComponent {
38630
39835
  "
38631
39836
  [class]="widgetClassName(w)"
38632
39837
  [style.gridColumn]="widgetGridColumn(w)"
39838
+ (pointerdown)="selectWidget(w.key)"
38633
39839
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38634
39840
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38635
39841
  >
@@ -38657,16 +39863,22 @@ class DynamicWidgetPageComponent {
38657
39863
  [showAssistant]="showWidgetAssistantButton"
38658
39864
  [assistantLabel]="widgetAssistantLabel()"
38659
39865
  [assistantTooltip]="widgetAssistantTooltip()"
38660
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
39866
+ [showComponentSettings]="
39867
+ canOpenWidgetComponentSettings(w.key)
39868
+ "
38661
39869
  [componentSettingsLabel]="componentSettingsLabel()"
38662
- [componentSettingsTooltip]="componentSettingsTooltip()"
39870
+ [componentSettingsTooltip]="
39871
+ componentSettingsTooltip()
39872
+ "
38663
39873
  [showShellSettings]="canOpenWidgetShellSettings()"
38664
39874
  [shellSettingsLabel]="widgetSettingsLabel()"
38665
39875
  [shellSettingsTooltip]="widgetSettingsTooltip()"
38666
39876
  [moreActionsLabel]="moreWidgetActionsLabel()"
38667
39877
  [removeLabel]="widgetRemoveLabel()"
38668
39878
  (assistant)="requestWidgetAssistant(w.key)"
38669
- (componentSettings)="openWidgetComponentSettings(w.key)"
39879
+ (componentSettings)="
39880
+ openWidgetComponentSettings(w.key)
39881
+ "
38670
39882
  (shellSettings)="openWidgetShellSettings(w.key)"
38671
39883
  (remove)="confirmAndRemoveWidget(w.key)"
38672
39884
  />
@@ -38688,6 +39900,7 @@ class DynamicWidgetPageComponent {
38688
39900
  "
38689
39901
  [class]="widgetClassName(w)"
38690
39902
  [style.gridColumn]="widgetGridColumn(w)"
39903
+ (pointerdown)="selectWidget(w.key)"
38691
39904
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38692
39905
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38693
39906
  >
@@ -38715,7 +39928,9 @@ class DynamicWidgetPageComponent {
38715
39928
  [showAssistant]="showWidgetAssistantButton"
38716
39929
  [assistantLabel]="widgetAssistantLabel()"
38717
39930
  [assistantTooltip]="widgetAssistantTooltip()"
38718
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
39931
+ [showComponentSettings]="
39932
+ canOpenWidgetComponentSettings(w.key)
39933
+ "
38719
39934
  [componentSettingsLabel]="componentSettingsLabel()"
38720
39935
  [componentSettingsTooltip]="componentSettingsTooltip()"
38721
39936
  [showShellSettings]="canOpenWidgetShellSettings()"
@@ -38759,7 +39974,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38759
39974
  [attr.data-density]="pageThemeDensity"
38760
39975
  [attr.data-motion]="pageThemeMotion"
38761
39976
  [ngStyle]="pageThemeTokenStyle"
38762
- >
39977
+ >
38763
39978
  @if (enableCustomization && showPageSettingsButton) {
38764
39979
  <button
38765
39980
  class="pdx-page-settings"
@@ -38799,6 +40014,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38799
40014
  [style.gridColumn]="widgetGridColumn(w)"
38800
40015
  [style.gridRow]="widgetGridRow(w)"
38801
40016
  [style.zIndex]="widgetZIndex(w)"
40017
+ (pointerdown)="selectWidget(w.key)"
38802
40018
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38803
40019
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38804
40020
  >
@@ -38850,7 +40066,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38850
40066
  [showAssistant]="showWidgetAssistantButton"
38851
40067
  [assistantLabel]="widgetAssistantLabel()"
38852
40068
  [assistantTooltip]="widgetAssistantTooltip()"
38853
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
40069
+ [showComponentSettings]="
40070
+ canOpenWidgetComponentSettings(w.key)
40071
+ "
38854
40072
  [componentSettingsLabel]="componentSettingsLabel()"
38855
40073
  [componentSettingsTooltip]="componentSettingsTooltip()"
38856
40074
  [showShellSettings]="canOpenWidgetShellSettings()"
@@ -38923,12 +40141,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38923
40141
  <div
38924
40142
  class="pdx-widget"
38925
40143
  [attr.data-widget-key]="w.key"
38926
- [class.pdx-widget--interactive]="enableCustomization"
40144
+ [class.pdx-widget--interactive]="
40145
+ enableCustomization
40146
+ "
38927
40147
  [class.pdx-widget--selected]="
38928
40148
  enableCustomization && isWidgetSelected(w.key)
38929
40149
  "
38930
40150
  [class]="w.renderClassName || w.className || ''"
38931
40151
  [style.gridColumn]="widgetGridColumn(w)"
40152
+ (pointerdown)="selectWidget(w.key)"
38932
40153
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38933
40154
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
38934
40155
  >
@@ -38952,22 +40173,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38952
40173
  </praxis-widget-shell>
38953
40174
  @if (shouldRenderWidgetContextOverlay(w)) {
38954
40175
  <praxis-dynamic-widget-context-toolbar
38955
- [toolbarLabel]="widgetContextToolbarLabel(w.key)"
40176
+ [toolbarLabel]="
40177
+ widgetContextToolbarLabel(w.key)
40178
+ "
38956
40179
  [contextLabel]="widgetContextLabel(w)"
38957
40180
  [contextTooltip]="widgetContextTooltip(w)"
38958
40181
  [showAssistant]="showWidgetAssistantButton"
38959
40182
  [assistantLabel]="widgetAssistantLabel()"
38960
40183
  [assistantTooltip]="widgetAssistantTooltip()"
38961
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
38962
- [componentSettingsLabel]="componentSettingsLabel()"
38963
- [componentSettingsTooltip]="componentSettingsTooltip()"
38964
- [showShellSettings]="canOpenWidgetShellSettings()"
40184
+ [showComponentSettings]="
40185
+ canOpenWidgetComponentSettings(w.key)
40186
+ "
40187
+ [componentSettingsLabel]="
40188
+ componentSettingsLabel()
40189
+ "
40190
+ [componentSettingsTooltip]="
40191
+ componentSettingsTooltip()
40192
+ "
40193
+ [showShellSettings]="
40194
+ canOpenWidgetShellSettings()
40195
+ "
38965
40196
  [shellSettingsLabel]="widgetSettingsLabel()"
38966
40197
  [shellSettingsTooltip]="widgetSettingsTooltip()"
38967
40198
  [moreActionsLabel]="moreWidgetActionsLabel()"
38968
40199
  [removeLabel]="widgetRemoveLabel()"
38969
40200
  (assistant)="requestWidgetAssistant(w.key)"
38970
- (componentSettings)="openWidgetComponentSettings(w.key)"
40201
+ (componentSettings)="
40202
+ openWidgetComponentSettings(w.key)
40203
+ "
38971
40204
  (shellSettings)="openWidgetShellSettings(w.key)"
38972
40205
  (remove)="confirmAndRemoveWidget(w.key)"
38973
40206
  />
@@ -38995,6 +40228,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
38995
40228
  "
38996
40229
  [class]="widgetClassName(w)"
38997
40230
  [style.gridColumn]="widgetGridColumn(w)"
40231
+ (pointerdown)="selectWidget(w.key)"
38998
40232
  (click)="selectWidgetFromHostEvent(w.key, $event)"
38999
40233
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
39000
40234
  >
@@ -39022,16 +40256,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
39022
40256
  [showAssistant]="showWidgetAssistantButton"
39023
40257
  [assistantLabel]="widgetAssistantLabel()"
39024
40258
  [assistantTooltip]="widgetAssistantTooltip()"
39025
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
40259
+ [showComponentSettings]="
40260
+ canOpenWidgetComponentSettings(w.key)
40261
+ "
39026
40262
  [componentSettingsLabel]="componentSettingsLabel()"
39027
- [componentSettingsTooltip]="componentSettingsTooltip()"
40263
+ [componentSettingsTooltip]="
40264
+ componentSettingsTooltip()
40265
+ "
39028
40266
  [showShellSettings]="canOpenWidgetShellSettings()"
39029
40267
  [shellSettingsLabel]="widgetSettingsLabel()"
39030
40268
  [shellSettingsTooltip]="widgetSettingsTooltip()"
39031
40269
  [moreActionsLabel]="moreWidgetActionsLabel()"
39032
40270
  [removeLabel]="widgetRemoveLabel()"
39033
40271
  (assistant)="requestWidgetAssistant(w.key)"
39034
- (componentSettings)="openWidgetComponentSettings(w.key)"
40272
+ (componentSettings)="
40273
+ openWidgetComponentSettings(w.key)
40274
+ "
39035
40275
  (shellSettings)="openWidgetShellSettings(w.key)"
39036
40276
  (remove)="confirmAndRemoveWidget(w.key)"
39037
40277
  />
@@ -39053,6 +40293,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
39053
40293
  "
39054
40294
  [class]="widgetClassName(w)"
39055
40295
  [style.gridColumn]="widgetGridColumn(w)"
40296
+ (pointerdown)="selectWidget(w.key)"
39056
40297
  (click)="selectWidgetFromHostEvent(w.key, $event)"
39057
40298
  (focusin)="selectWidgetFromHostEvent(w.key, $event)"
39058
40299
  >
@@ -39080,7 +40321,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
39080
40321
  [showAssistant]="showWidgetAssistantButton"
39081
40322
  [assistantLabel]="widgetAssistantLabel()"
39082
40323
  [assistantTooltip]="widgetAssistantTooltip()"
39083
- [showComponentSettings]="canOpenWidgetComponentSettings(w.key)"
40324
+ [showComponentSettings]="
40325
+ canOpenWidgetComponentSettings(w.key)
40326
+ "
39084
40327
  [componentSettingsLabel]="componentSettingsLabel()"
39085
40328
  [componentSettingsTooltip]="componentSettingsTooltip()"
39086
40329
  [showShellSettings]="canOpenWidgetShellSettings()"
@@ -39166,21 +40409,73 @@ const PRAXIS_DYNAMIC_PAGE_COMPONENT_METADATA = {
39166
40409
  description: 'Página dinâmica com widgets e composition.links em layout responsivo, incluindo mediação runtime para rich-content hospedado.',
39167
40410
  icon: 'dashboard',
39168
40411
  inputs: [
39169
- { name: 'page', type: 'WidgetPageDefinition', description: 'Definição da página (widgets, layout e composition.links).' },
39170
- { name: 'context', type: 'Record<string, any>', description: 'Contexto adicional compartilhado entre widgets.' },
39171
- { name: 'strictValidation', type: 'boolean', description: 'Habilita validação estrita de inputs.' },
39172
- { name: 'enableCustomization', type: 'boolean', description: 'Habilita affordances de edição na página.' },
39173
- { name: 'showPageSettingsButton', type: 'boolean', description: 'Exibe botão de configuração da página.' },
39174
- { name: 'shellEditorComponent', type: 'Type<any>', description: 'Override do editor de shell dos widgets.' },
39175
- { name: 'pageEditorComponent', type: 'Type<any>', description: 'Override do editor de configuração da página.' },
39176
- { name: 'autoPersist', type: 'boolean', description: 'Ativa persistência automática (load/save) da página.' },
39177
- { name: 'pageIdentity', type: 'PageIdentity', description: 'Identidade de persistência (tenant/usuário/rota/locale).' },
39178
- { name: 'componentInstanceId', type: 'string', description: 'Identificador opcional para múltiplas instâncias na mesma rota.' },
40412
+ {
40413
+ name: 'page',
40414
+ type: 'WidgetPageDefinition',
40415
+ description: 'Definição da página (widgets, layout, i18n de negócio e composition.links).',
40416
+ },
40417
+ {
40418
+ name: 'context',
40419
+ type: 'Record<string, any>',
40420
+ description: 'Contexto adicional compartilhado entre widgets.',
40421
+ },
40422
+ {
40423
+ name: 'strictValidation',
40424
+ type: 'boolean',
40425
+ description: 'Habilita validação estrita de inputs.',
40426
+ },
40427
+ {
40428
+ name: 'enableCustomization',
40429
+ type: 'boolean',
40430
+ description: 'Habilita affordances de edição na página.',
40431
+ },
40432
+ {
40433
+ name: 'showPageSettingsButton',
40434
+ type: 'boolean',
40435
+ description: 'Exibe botão de configuração da página.',
40436
+ },
40437
+ {
40438
+ name: 'shellEditorComponent',
40439
+ type: 'Type<any>',
40440
+ description: 'Override do editor de shell dos widgets.',
40441
+ },
40442
+ {
40443
+ name: 'pageEditorComponent',
40444
+ type: 'Type<any>',
40445
+ description: 'Override do editor de configuração da página.',
40446
+ },
40447
+ {
40448
+ name: 'autoPersist',
40449
+ type: 'boolean',
40450
+ description: 'Ativa persistência automática (load/save) da página.',
40451
+ },
40452
+ {
40453
+ name: 'pageIdentity',
40454
+ type: 'PageIdentity',
40455
+ description: 'Identidade de persistência (tenant/usuário/rota/locale).',
40456
+ },
40457
+ {
40458
+ name: 'componentInstanceId',
40459
+ type: 'string',
40460
+ description: 'Identificador opcional para múltiplas instâncias na mesma rota.',
40461
+ },
39179
40462
  ],
39180
40463
  outputs: [
39181
- { name: 'pageChange', type: 'WidgetPageDefinition', description: 'Emitido ao alterar a definição da página.' },
39182
- { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos dos widgets filhos com ownerWidgetKey para integrações do host.' },
39183
- { name: 'widgetDiagnosticsChange', type: 'Record<string, WidgetResolutionDiagnostic>', description: 'Emitido quando o runtime detecta widgets resolvidos ou falhos durante o carregamento dinâmico.' },
40464
+ {
40465
+ name: 'pageChange',
40466
+ type: 'WidgetPageDefinition',
40467
+ description: 'Emitido ao alterar a definição da página.',
40468
+ },
40469
+ {
40470
+ name: 'widgetEvent',
40471
+ type: 'WidgetEventEnvelope',
40472
+ description: 'Reemite eventos dos widgets filhos com ownerWidgetKey para integrações do host.',
40473
+ },
40474
+ {
40475
+ name: 'widgetDiagnosticsChange',
40476
+ type: 'Record<string, WidgetResolutionDiagnostic>',
40477
+ description: 'Emitido quando o runtime detecta widgets resolvidos ou falhos durante o carregamento dinâmico.',
40478
+ },
39184
40479
  ],
39185
40480
  tags: ['widget', 'page', 'dynamic', 'layout'],
39186
40481
  lib: '@praxisui/core',
@@ -39208,6 +40503,7 @@ class PraxisSurfaceHostComponent {
39208
40503
  widget;
39209
40504
  afterWidget;
39210
40505
  context = null;
40506
+ lifecycle;
39211
40507
  strictValidation = true;
39212
40508
  /**
39213
40509
  * Keep disabled by default to avoid duplicating the title already shown by
@@ -39331,6 +40627,7 @@ class PraxisSurfaceHostComponent {
39331
40627
  }
39332
40628
  }
39333
40629
  onSlotWidgetEvent(ownerWidgetKey, event) {
40630
+ this.materializeSurfaceOutcome(event);
39334
40631
  const resourceEvent = event.resourceEvent ?? this.toResourceEvent(ownerWidgetKey, event);
39335
40632
  if (event.output === 'rowClick') {
39336
40633
  this.rowClick.emit(event.payload);
@@ -39347,6 +40644,51 @@ class PraxisSurfaceHostComponent {
39347
40644
  ownerWidgetKey: event.ownerWidgetKey || ownerWidgetKey,
39348
40645
  });
39349
40646
  }
40647
+ materializeSurfaceOutcome(event) {
40648
+ const binding = this.lifecycle?.outcomes.find((candidate) => candidate.output === event.output && this.matchesLifecycleConditions(candidate, event.payload));
40649
+ if (!binding)
40650
+ return;
40651
+ const runtime = this.context?.['surfaceRuntime'];
40652
+ if (!runtime)
40653
+ return;
40654
+ const outcome = this.buildSurfaceOutcome(binding, event);
40655
+ if (outcome.kind === 'completed') {
40656
+ runtime.complete?.(outcome);
40657
+ return;
40658
+ }
40659
+ if (outcome.kind === 'dismissed') {
40660
+ runtime.close?.(outcome);
40661
+ return;
40662
+ }
40663
+ runtime.emitResult?.(outcome);
40664
+ }
40665
+ matchesLifecycleConditions(binding, payload) {
40666
+ return (binding.when || []).every((condition) => Object.is(this.readPath(payload, condition.path), condition.equals));
40667
+ }
40668
+ buildSurfaceOutcome(binding, event) {
40669
+ const data = binding.outcome.dataPath
40670
+ ? this.readPath(event.payload, binding.outcome.dataPath)
40671
+ : event.payload;
40672
+ const error = binding.outcome.errorPath
40673
+ ? this.readPath(event.payload, binding.outcome.errorPath)
40674
+ : undefined;
40675
+ return {
40676
+ kind: binding.outcome.kind,
40677
+ type: binding.outcome.type,
40678
+ ...(data !== undefined ? { data } : {}),
40679
+ ...(error !== undefined ? { error } : {}),
40680
+ output: event.output,
40681
+ payload: event.payload,
40682
+ };
40683
+ }
40684
+ readPath(value, path) {
40685
+ return String(path || '')
40686
+ .split('.')
40687
+ .filter(Boolean)
40688
+ .reduce((current, key) => current && typeof current === 'object'
40689
+ ? current[key]
40690
+ : undefined, value);
40691
+ }
39350
40692
  toResourceEvent(ownerWidgetKey, event) {
39351
40693
  const sourceOutput = String(event.output || '').trim();
39352
40694
  if (!sourceOutput) {
@@ -39427,7 +40769,7 @@ class PraxisSurfaceHostComponent {
39427
40769
  };
39428
40770
  }
39429
40771
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisSurfaceHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
39430
- 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", resourceEvent: "resourceEvent" }, 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: `
40772
+ 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", lifecycle: "lifecycle", strictValidation: "strictValidation", renderTitleInsideBody: "renderTitleInsideBody" }, outputs: { widgetEvent: "widgetEvent", rowClick: "rowClick", selectionChange: "selectionChange", resourceEvent: "resourceEvent" }, 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: `
39431
40773
  <div class="pdx-surface-host">
39432
40774
  @if (subtitle || (title && renderTitleInsideBody)) {
39433
40775
  <header class="pdx-surface-host__header">
@@ -39566,6 +40908,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
39566
40908
  type: Input
39567
40909
  }], context: [{
39568
40910
  type: Input
40911
+ }], lifecycle: [{
40912
+ type: Input
39569
40913
  }], strictValidation: [{
39570
40914
  type: Input
39571
40915
  }], renderTitleInsideBody: [{
@@ -39992,6 +41336,76 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
39992
41336
  `, styles: [":host{display:block;min-width:0}.pdx-related-outlet{display:block;min-width:0;color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__state{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:var(--pdx-related-outlet-gap, 12px);min-height:var(--pdx-related-outlet-min-height, 64px);padding:var(--pdx-related-outlet-padding, 12px);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .16));border-radius:var(--pdx-related-outlet-radius, 8px);background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface, transparent))}.pdx-related-outlet--compact .pdx-related-outlet__state{min-height:var(--pdx-related-outlet-compact-min-height, 48px);padding:var(--pdx-related-outlet-compact-padding, 8px 10px)}.pdx-related-outlet__state--ready{border-color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__icon{display:inline-grid;place-items:center;width:32px;height:32px;color:var(--md-sys-color-primary, currentColor)}.pdx-related-outlet__state--busy .pdx-related-outlet__icon{color:var(--md-sys-color-secondary, currentColor)}.pdx-related-outlet__copy{display:grid;gap:2px;min-width:0}.pdx-related-outlet__copy h3,.pdx-related-outlet__copy p{margin:0}.pdx-related-outlet__copy h3{font:var(--md-sys-typescale-title-small, 600 .95rem/1.25rem system-ui);color:var(--md-sys-color-on-surface, currentColor)}.pdx-related-outlet__copy p{font:var(--md-sys-typescale-body-small, 400 .82rem/1.15rem system-ui);color:var(--md-sys-color-on-surface-variant, currentColor)}@media(max-width:600px){.pdx-related-outlet__state{grid-template-columns:auto minmax(0,1fr)}.pdx-related-outlet__state button{grid-column:1 / -1;justify-self:start}}\n"] }]
39993
41337
  }], ctorParameters: () => [], propDecorators: { surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }], surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: false }] }], surfaceCatalog: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceCatalog", required: false }] }], discoverySource: [{ type: i0.Input, args: [{ isSignal: true, alias: "discoverySource", required: false }] }], parentLinks: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentLinks", required: false }] }], apiEndpointKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiEndpointKey", required: false }] }], apiUrlEntry: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiUrlEntry", required: false }] }], parentRecord: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentRecord", required: false }] }], parentResourceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentResourceId", required: false }] }], parentResourcePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentResourcePath", required: false }] }], presentation: [{ type: i0.Input, args: [{ isSignal: true, alias: "presentation", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tableId: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableId", required: false }] }], tableConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableConfig", required: false }] }], enableCustomization: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCustomization", required: false }] }], authoringCapability: [{ type: i0.Input, args: [{ isSignal: true, alias: "authoringCapability", required: false }] }], emptyState: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyState", required: false }] }], queryContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryContext", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], stateReason: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateReason", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], strictValidation: [{ type: i0.Input, args: [{ isSignal: true, alias: "strictValidation", required: false }] }], ownerWidgetKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ownerWidgetKey", required: false }] }], surfaceOpen: [{ type: i0.Output, args: ["surfaceOpen"] }], widgetEvent: [{ type: i0.Output, args: ["widgetEvent"] }], resourceEvent: [{ type: i0.Output, args: ["resourceEvent"] }] } });
39994
41338
 
41339
+ const PRAXIS_RELATED_RESOURCE_OUTLET_PORTS = [
41340
+ {
41341
+ id: 'parentResourceId',
41342
+ label: 'Identificador do recurso pai',
41343
+ direction: 'input',
41344
+ semanticKind: 'value',
41345
+ schema: {
41346
+ id: 'string | number | null',
41347
+ kind: 'ts-type',
41348
+ ref: 'string | number | null',
41349
+ },
41350
+ description: 'Seleção canônica que governa a resolução da coleção filha.',
41351
+ exposure: { public: true, group: 'context' },
41352
+ },
41353
+ {
41354
+ id: 'queryContext',
41355
+ label: 'Contexto de consulta',
41356
+ direction: 'input',
41357
+ semanticKind: 'query-context',
41358
+ schema: {
41359
+ id: 'RelatedResourceQueryContext',
41360
+ kind: 'ts-type',
41361
+ ref: 'RelatedResourceQueryContext',
41362
+ },
41363
+ description: 'Contexto adicional mesclado ao filtro pai-filho publicado pela surface.',
41364
+ exposure: { public: true, advanced: true, group: 'context' },
41365
+ },
41366
+ {
41367
+ id: 'surfaceOpen',
41368
+ label: 'Abertura da superfície relacionada',
41369
+ direction: 'output',
41370
+ semanticKind: 'event',
41371
+ schema: {
41372
+ id: 'SurfaceOpenPayload',
41373
+ kind: 'ts-type',
41374
+ ref: 'SurfaceOpenPayload',
41375
+ },
41376
+ cardinality: 'stream',
41377
+ description: 'Solicita ao host a abertura mediada da superfície no modo open-action.',
41378
+ exposure: { public: true, group: 'events' },
41379
+ },
41380
+ {
41381
+ id: 'widgetEvent',
41382
+ label: 'Evento do widget relacionado',
41383
+ direction: 'output',
41384
+ semanticKind: 'event',
41385
+ schema: {
41386
+ id: 'WidgetEventEnvelope',
41387
+ kind: 'ts-type',
41388
+ ref: 'WidgetEventEnvelope',
41389
+ },
41390
+ cardinality: 'stream',
41391
+ description: 'Reemite eventos do widget filho com identidade de ownership.',
41392
+ exposure: { public: true, advanced: true, group: 'events' },
41393
+ },
41394
+ {
41395
+ id: 'resourceEvent',
41396
+ label: 'Evento canônico do recurso relacionado',
41397
+ direction: 'output',
41398
+ semanticKind: 'event',
41399
+ schema: {
41400
+ id: 'PraxisResourceEvent',
41401
+ kind: 'ts-type',
41402
+ ref: 'PraxisResourceEvent',
41403
+ },
41404
+ cardinality: 'stream',
41405
+ description: 'Promove seleção, mutação e lifecycle do recurso filho para a composição.',
41406
+ exposure: { public: true, group: 'events' },
41407
+ },
41408
+ ];
39995
41409
  const PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA = {
39996
41410
  id: 'praxis-related-resource-outlet',
39997
41411
  selector: 'praxis-related-resource-outlet',
@@ -40010,21 +41424,29 @@ const PRAXIS_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA = {
40010
41424
  { name: 'parentRecord', type: 'Record<string, unknown> | null', description: 'Registro pai usado para resolver parentIdPathVariable.' },
40011
41425
  { name: 'parentResourceId', type: 'string | number | null', description: 'Identificador explícito do registro pai quando não vem do record.' },
40012
41426
  { name: 'parentResourcePath', type: 'string | null', description: 'ResourcePath do recurso pai para contexto da surface.' },
41427
+ { name: 'presentation', type: 'SurfacePresentation', description: 'Apresentação usada no payload de abertura host-mediated.', default: 'drawer' },
41428
+ { name: 'title', type: 'string | null', description: 'Título opcional que substitui o título publicado pela surface.' },
41429
+ { name: 'subtitle', type: 'string | null', description: 'Subtítulo opcional que substitui a descrição publicada pela surface.' },
41430
+ { name: 'icon', type: 'string | null', description: 'Ícone opcional da superfície relacionada.' },
40013
41431
  { name: 'queryContext', type: 'RelatedResourceQueryContext | null', description: 'QueryContext base mesclado com o filtro canônico da relação filha.' },
41432
+ { name: 'tableId', type: 'string | null', description: 'Identidade estável da tabela filha para persistência, observabilidade e testes.' },
40014
41433
  { name: 'tableConfig', type: 'Record<string, unknown> | null', description: 'Configuracao parcial da tabela filha materializada, mesclada ao preset canonico.' },
40015
41434
  { name: 'emptyState', type: 'Record<string, unknown> | null', description: 'Override opcional para behavior.emptyState da tabela filha. Quando omitido, o outlet deriva texto, icone, layout e ação create a partir de surface.relatedResource e dos metadados da surface.' },
40016
41435
  { name: 'enableCustomization', type: 'boolean', description: 'Opt-in explicito para authoring governado da tabela filha.', default: false },
40017
41436
  { name: 'authoringCapability', type: 'string | null', description: 'Capability publica do EnterpriseRuntimeContext exigida quando o authoring da tabela filha estiver habilitado.' },
40018
41437
  { name: 'mode', type: "'inline' | 'open-action'", description: 'Renderiza a tabela filha inline ou emite payload para abertura host-mediated.', default: 'inline' },
40019
41438
  { name: 'state', type: 'RelatedResourceResolutionState | null', description: 'Override de estado para hosts/outlets que estejam carregando discovery remoto.' },
41439
+ { name: 'stateReason', type: 'string | null', description: 'Motivo governado associado ao override de estado.' },
40020
41440
  { name: 'compact', type: 'boolean', description: 'Reduz densidade visual dos estados não materializados.', default: false },
40021
41441
  { name: 'strictValidation', type: 'boolean', description: 'Validação estrita do widget materializado pelo DynamicWidgetLoader.', default: false },
41442
+ { name: 'ownerWidgetKey', type: 'string', description: 'Identidade do owner usada para correlacionar eventos do widget filho.', default: 'related-resource.outlet' },
40022
41443
  ],
40023
41444
  outputs: [
40024
41445
  { name: 'surfaceOpen', type: 'SurfaceOpenPayload', description: 'Emitido em modo open-action com o payload pronto de surface.open.' },
40025
41446
  { name: 'widgetEvent', type: 'WidgetEventEnvelope', description: 'Reemite eventos do widget filho materializado.' },
40026
41447
  { name: 'resourceEvent', type: 'PraxisResourceEvent', description: 'Promove eventos canonicos emitidos pelo widget filho materializado.' },
40027
41448
  ],
41449
+ ports: PRAXIS_RELATED_RESOURCE_OUTLET_PORTS,
40028
41450
  tags: ['resource', 'surface', 'related-resource', 'runtime', 'metadata-driven'],
40029
41451
  lib: '@praxisui/core',
40030
41452
  };
@@ -41535,4 +42957,4 @@ function provideHookWhitelist(allowed) {
41535
42957
  * Generated bundle index. Do not edit.
41536
42958
  */
41537
42959
 
41538
- export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, 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_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, 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, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };
42960
+ export { API_CONFIG_STORAGE_OPTIONS, API_URL, ASYNC_CONFIG_STORAGE, AllowedFileTypes, AnalyticsPresentationResolver, AnalyticsSchemaContractService, AnalyticsStatsRequestBuilderService, ApiConfigStorage, ApiEndpoint, BUILTIN_PAGE_LAYOUT_PRESETS, BUILTIN_PAGE_THEME_PRESETS, BUILTIN_SHELL_PRESETS, COMPONENT_METADATA_REGISTRY_I18N_CONFIG, COMPONENT_METADATA_REGISTRY_I18N_NAMESPACE, CONFIG_STORAGE, CONNECTION_STORAGE, ComponentKeyService, ComponentMetadataRegistry, 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_RELATED_RESOURCE_OUTLET_COMPONENT_METADATA, PRAXIS_RELATED_RESOURCE_OUTLET_PORTS, PRAXIS_RICH_TEXT_BLOCK_METADATA, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PRAXIS_TELEMETRY_TRANSPORT, PRAXIS_THEME_SURFACE_DEFAULTS, PRAXIS_THEME_SURFACE_VARS, PRAXIS_USER_CONTEXT_SUMMARY_METADATA, PRIVACY_CONSENT_EDITORIAL_SOLUTION, PRIVACY_CONSENT_EDITORIAL_TEMPLATE, PraxisCollectionExportService, PraxisCore, PraxisFooterLinksComponent, PraxisGlobalErrorHandler, PraxisHeroBannerComponent, PraxisHttpCollectionExportProvider, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, PraxisIconPickerComponent, PraxisJsonLogicError, PraxisJsonLogicService, PraxisLayerScaleStyleService, PraxisLegalNoticeComponent, PraxisLoadingInterceptor, PraxisRelatedResourceOutletComponent, PraxisResourceIdentityComponent, PraxisRichTextBlockComponent, PraxisRuntimeComponentObservationRegistryService, PraxisSurfaceHostComponent, PraxisUserContextSummaryComponent, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, RULE_PROPERTY_SCHEMA, RelatedResourceSurfaceResolverService, RemoteConfigStorage, ResourceActionOpenAdapterService, ResourceDiscoveryService, ResourceQuickConnectComponent, ResourceRecordOpenError, ResourceRecordOpenService, ResourceSurfaceOpenAdapterService, SCHEMA_VIEWER_CONTEXT, SETTINGS_PANEL_BRIDGE, SETTINGS_PANEL_DATA, STEPPER_CONFIG_EDITOR, SURFACE_DRAWER_BRIDGE, SURFACE_OPEN_I18N_CONFIG, SURFACE_OPEN_I18N_NAMESPACE, SURFACE_OPEN_PRESETS, SchemaMetadataClient, SchemaNormalizerService, SchemaViewerComponent, SurfaceBindingRuntimeService, SurfaceOpenActionEditorComponent, SurfaceOpenMaterializerService, SurfaceOutletRegistryService, TABLE_CONFIG_EDITOR, TableConfigService, TelemetryLoggerSink, TelemetryService, ValidationPattern, WidgetPageStateRuntimeService, WidgetShellComponent, applyLocalCustomizations$2 as applyLocalCustomizations, applyLocalCustomizations$1 as applyLocalFormCustomizations, assertPraxisCollectionExportArtifact, assertPraxisRuntimeComponentObservationSerializable, buildAngularValidators, buildApiUrl, buildBaseColumnFromDef, buildBaseFormField, buildFormConfigFromEditorialTemplate, buildHeaders, buildPageKey, buildPraxisEffectDistinctKey, buildPraxisLayerScaleCss, buildPraxisThemeSurfaceCss, buildSchemaId, buildSchemaIdStorageKeySegment, buildValidatorsFromValidatorOptions, cancelIfCpfInvalidHook, clampRange, classifyEntityLookupResult, clonePraxisRuntimeComponentObservation, cloneTableConfig, cnpjAlphaValidator, collapseWhitespace, composeHeadersWithVersion, conditionalAsyncValidator, convertFormLayoutToConfig, createCorporateLoggerConfig, createCorporateObservabilityOptions, createCpfCnpjValidator, createDefaultFormConfig, createDefaultTableConfig, createEmptyFormConfig, createEmptyRichContentDocument, createFieldLayoutItem, createPersistedPage, customAsyncValidatorFn, customValidatorFn, debounceAsyncValidator, deepMerge, domainKnowledgeTimelineToRichContentDocument, domainRuleTimelineToRichContentDocument, ensureIds, ensureNoConflictsHookFactory, ensurePageIds, escapePraxisExportCell, evaluateFieldAccess, extractNormalizedError, fetchWithETag, fileTypeValidator, fillUndefined, generateId, getDefaultFormHints, getEditorialCompliancePresetById, getEditorialFormTemplateById, getEditorialFormTemplateCatalog, getEditorialSolutionById, getEditorialSolutionCatalog, getEditorialSolutionPresetById, getEditorialThemePresetById, getEssentialConfig, getFieldMetadataCapabilities, getFormColumnFieldNames, getFormLayoutFieldNames, getGlobalActionCatalog, getGlobalActionPayloadActualType, getGlobalActionPayloadTypeIssue, getGlobalActionUiSchema, getMissingGlobalActionPayloadKeys, getPraxisTableCellVisualizationConstraint, getPraxisTableCellVisualizationGuidance, getReferencedFieldMetadata, getRequiredGlobalActionPayloadKeys, getTextTransformer, hasMeaningfulGlobalActionPayloadValue, hasPraxisCollectionExportArtifact, interpolatePraxisTranslation, isAllowedEditorialContentFormat, isAllowedEditorialHref, isCssTextTransform, isEditorialComponentMeta, isEntityLookupMultiplePayloadMode, isEntityLookupPayloadMode, isEntityLookupPayloadModeCompatible, isEntityLookupResultSelectable, isEntityLookupSinglePayloadMode, isFormLayoutItem, isGlobalActionRef, isInlineFilterControlType, isLookupDialogSize, isLookupFilterFieldType, isLookupFilterOperator, isPraxisI18nMessageDescriptor, isPraxisPresentationVisualizationTableSafe, isPraxisRuntimeGlobalActionEffect, isProgrammaticDateRangePreset, isRangeValidForFilter, isRequiredGlobalActionParamPayloadMissing, isRequiredGlobalActionPayloadMissing, isStaticDateRangePreset, isTableConfigV2, isValidFormConfig, isValidTableConfig, legacyCnpjValidator, legacyCpfValidator, logOnErrorHook, mapFieldDefinitionToMetadata, mapFieldDefinitionsToMetadata, matchFieldValidator, materializeFormLayoutFromMetadata, materializeResourceIdentity, maxFileSizeValidator, mergeFieldMetadata, mergePraxisI18nConfigs, mergeTableConfigs, migrateFormLayoutRule, migrateLegacyCompositionLink, migrateLegacyCompositionLinks, minWordsValidator, normalizeControlTypeKey, normalizeControlTypeToken, normalizeEditorialLink, normalizeEnd, normalizeFieldAccessMetadata, normalizeFieldConstraints, normalizeFieldPresentation, normalizeFormConfig, normalizeFormLayoutItems, normalizeFormMetadata, normalizeGlobalActionRef$1 as normalizeGlobalActionRef, normalizeLayoutPolicy, normalizeLookupFilterRequest, normalizePath, normalizePraxisDataQueryContext, normalizePraxisEffectPolicy, normalizePraxisPresentationVisualization, normalizePraxisQueryFilterExpression, normalizePraxisQueryFilterNode, normalizeResourceAvailabilityReasonCode, normalizeResourceIdentityContract, 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, providePraxisRelatedResourceOutletMetadata, providePraxisRichTextBlockMetadata, providePraxisToastGlobalActions, providePraxisUserContextSummaryMetadata, provideRemoteGlobalConfig, readPraxisExportValue, reconcileFilterConfig, reconcileFormConfig, reconcileTableConfig, registerPraxisRuntimeComponentObservation, removeDiacritics, renderPraxisPresentationVisualizationHtml, reportTelemetryHookFactory, requiredCheckedValidator, requiredPresenceValidator, resolveBuiltinPresets, resolveColumnTypeFromFieldDefinition, resolveControlTypeAlias, resolveDateRangeShortcutPreset, resolveDateRangeShortcutPresets, resolveDefaultValuePresentationFormat, resolveEntityLookupPayloadMode, resolveFieldPresentation, resolveHidden, resolveInlineFilterControlType, resolveInlineFilterControlTypeToBaseControlType, resolveLoggerConfig, resolveObservabilityOptions, resolveOffset, resolveOrder, resolvePraxisCollectionExportItems, resolvePraxisExportFields, resolvePraxisExportScope, resolvePraxisFilterCriteria, resolvePraxisI18nDocument, resolveResourceAvailabilityReasonKey, resolveResourceIdentityContract, resolveSpan, resolveTextMaskFormat, resolveTextMaskFormatFromFieldDefinition, resolveValuePresentation, resolveValuePresentationLocale, serializeEntityLookupValueForPayload, serializeOptionSourceFilterRequest, serializePraxisCollectionToCsv, serializePraxisCollectionToExcel, serializePraxisCollectionToJson, slugify, staticDateRangePresetToPreset, stripMasksHook, supportsImplicitValuePresentation, syncWithServerMetadata, toCamel, toCapitalize, toKebab, toPascal, toSentenceCase, toSnake, toTitleCase, translateResourceAvailabilityReason, translateResourceDiscoveryText, translateUnavailableWorkflowMessage, trim, uniqueAsyncValidator, urlValidator, validateGlobalActionRef, validateGlobalActionRefs, withFormConfigSections, withMessage, withPraxisHttpLoading };