@praxisui/crud 9.0.5-rc.2 → 9.0.5-rc.20

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.
package/README.md CHANGED
@@ -102,6 +102,7 @@ It emits:
102
102
 
103
103
  - `configureRequested`
104
104
  - `afterOpen`, `afterClose`, `afterSave`, `afterDelete`
105
+ - `reactiveDeterminationExecuted` (metadata-only evidence with action context), `reactiveDeterminationPendingChange`, and `reactiveDeterminationStabilityChange`. The aggregate stability output preserves `action` and distinguishes `pending`, `settled-satisfied`, and `settled-unsatisfied`; “settled” alone is never a success signal.
105
106
  - `error`
106
107
  - `rowClick`, `rowAction`, `selectionChange`. `rowAction` preserves the canonical table envelope (`row`, `action`, `resourceIdentity`) so a governed composition can update task context without forcing visual row selection.
107
108
  - `tableRuntimeConfigChange`
@@ -109,6 +110,8 @@ It emits:
109
110
 
110
111
  The component keeps `crudContext` stable for change detection and refreshes the table after successful save/delete flows.
111
112
 
113
+ Built-in modal, drawer and nested surface-frame form hosts do not close or complete save while a child Reactive Determination is pending or when its latest generation settled unsatisfied; cancel waits for bounded successful stabilization and stays open on timeout/failure. A custom `CrudDrawerAdapter` must bind `onReactiveDetermination`, `onReactiveDeterminationPendingChange`, and `onReactiveDeterminationStabilityChange`, use the child Dynamic Form stability API, and refuse every adapter-owned close/submit while pending or unsatisfied. These callbacks are runtime-only and must never be persisted in CRUD metadata.
114
+
112
115
  ## Metadata Boundaries
113
116
 
114
117
  `resourcePath` and `resourceKey` are intentionally different:
@@ -118,6 +121,16 @@ The component keeps `crudContext` stable for change detection and refreshes the
118
121
 
119
122
  `@praxisui/crud` owns CRUD orchestration: list surface, create/edit/view/delete actions, open mode resolution, parameter mapping, `initialValue`, back policy, and stable handoff to the form host.
120
123
 
124
+ For inferred canonical actions, discovery and launcher resolution are sequential
125
+ decision stages, not equivalent retry mechanisms. The launcher is considered
126
+ only when discovery did not select an executable surface. Once a governed
127
+ surface has been selected, a synchronous or asynchronous open failure is
128
+ fail-closed: the runtime emits the error and a correlated structured diagnostic
129
+ without attempting a second drawer/modal/route path. A table nested in
130
+ `PraxisCrudComponent` always delegates the action to that CRUD owner; a
131
+ standalone table owns its `surface.open` attempt and follows the same
132
+ single-path rule.
133
+
121
134
  Child component semantics stay with their owners:
122
135
 
123
136
  - table configuration belongs to `@praxisui/table`
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-11T20:12:18.507Z",
3
+ "generatedAt": "2026-08-14T19:32:41.263Z",
4
4
  "packageName": "@praxisui/crud",
5
- "packageVersion": "9.0.5-rc.2",
5
+ "packageVersion": "9.0.5-rc.20",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -124,6 +124,24 @@
124
124
  "required": false,
125
125
  "description": "Emitido ao deletar."
126
126
  },
127
+ {
128
+ "name": "reactiveDeterminationExecuted",
129
+ "type": "{ action: string; event: ReactiveDeterminationExecutionEvent }",
130
+ "required": false,
131
+ "description": "Evidencia metadata-only encaminhada pelo formulario aberto, com contexto da acao CRUD."
132
+ },
133
+ {
134
+ "name": "reactiveDeterminationPendingChange",
135
+ "type": "{ action: string; pending: boolean }",
136
+ "required": false,
137
+ "description": "Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis."
138
+ },
139
+ {
140
+ "name": "reactiveDeterminationStabilityChange",
141
+ "type": "CrudReactiveDeterminationStabilityChange",
142
+ "required": false,
143
+ "description": "Conclusao agregada do formulario aberto, distinguindo settled-satisfied de settled-unsatisfied e preservando o contexto da acao."
144
+ },
127
145
  {
128
146
  "name": "rowClick",
129
147
  "type": "{ row: unknown; index: number }",
@@ -7224,9 +7242,9 @@
7224
7242
  {
7225
7243
  "chunkIndex": 0,
7226
7244
  "chunkKind": "summary",
7227
- "content": "Component ID: praxis-crud\nSelector: praxis-crud\nFriendly Name: Praxis CRUD\nDescription: Tabela com operações de CRUD via metadados.\nLib/Package: @praxisui/crud\nTags: widget, crud, configurable, hasWizard, stable\nInputs:\n - metadata (CrudMetadata | string)\n - crudId (string)\n - componentInstanceId (string)\n - tableConfigPersistenceStrategy ('local-first' | 'input-first' | 'volatile')\n - context (Record<string, unknown>)\n - metadata.queryContext (PraxisDataQueryContext | null)\n - metadata.resource.schemaPath (string | null)\n - metadata.resource.title (string | null)\n - metadata.resource.formTitle (string | null)\n - metadata.filterCriteria (Record<string, unknown> | null)\n - metadata.form (FormConfig)\n - metadata.actions[].form (CrudActionFormContract)\n - enableCustomization (boolean)\n - authoringCapability (string | null)\nOutputs:\n - afterOpen ({ mode: FormOpenMode; action: string })\n - afterClose (void)\n - afterSave ({ id: string | number; data: unknown })\n - afterDelete ({ id: string | number })\n - rowClick ({ row: unknown; index: number })\n - rowAction (CrudActionRuntimeEvent)\n - selectionChange (unknown)\n - error (unknown)\n - configureRequested (void)\n - crudAuthoringDocumentApplied (CrudAuthoringWidgetPersistenceEvent)\n - crudAuthoringDocumentSaved (CrudAuthoringWidgetPersistenceEvent)\n",
7245
+ "content": "Component ID: praxis-crud\nSelector: praxis-crud\nFriendly Name: Praxis CRUD\nDescription: Tabela com operações de CRUD via metadados.\nLib/Package: @praxisui/crud\nTags: widget, crud, configurable, hasWizard, stable\nInputs:\n - metadata (CrudMetadata | string)\n - crudId (string)\n - componentInstanceId (string)\n - tableConfigPersistenceStrategy ('local-first' | 'input-first' | 'volatile')\n - context (Record<string, unknown>)\n - metadata.queryContext (PraxisDataQueryContext | null)\n - metadata.resource.schemaPath (string | null)\n - metadata.resource.title (string | null)\n - metadata.resource.formTitle (string | null)\n - metadata.filterCriteria (Record<string, unknown> | null)\n - metadata.form (FormConfig)\n - metadata.actions[].form (CrudActionFormContract)\n - enableCustomization (boolean)\n - authoringCapability (string | null)\nOutputs:\n - afterOpen ({ mode: FormOpenMode; action: string })\n - afterClose (void)\n - afterSave ({ id: string | number; data: unknown })\n - afterDelete ({ id: string | number })\n - reactiveDeterminationExecuted ({ action: string; event: ReactiveDeterminationExecutionEvent })\n - reactiveDeterminationPendingChange ({ action: string; pending: boolean })\n - reactiveDeterminationStabilityChange (CrudReactiveDeterminationStabilityChange)\n - rowClick ({ row: unknown; index: number })\n - rowAction (CrudActionRuntimeEvent)\n - selectionChange (unknown)\n - error (unknown)\n - configureRequested (void)\n - crudAuthoringDocumentApplied (CrudAuthoringWidgetPersistenceEvent)\n - crudAuthoringDocumentSaved (CrudAuthoringWidgetPersistenceEvent)\n",
7228
7246
  "sourcePointer": "projects/praxis-crud/src/lib/praxis-crud.metadata.ts",
7229
- "contentHash": "5f18e01c2da358f033eb9b8ee4616dac8a348addc3ce3e56bcb077b094c13300",
7247
+ "contentHash": "3d654a50a00fa942aaaf216c39a6fa4e5eb711ff24b6d7b778aa4f48d0ea2d63",
7230
7248
  "sourceKind": "component_definition",
7231
7249
  "sourceId": "praxis-crud",
7232
7250
  "corpusVersion": "1.0.0"
@@ -11584,7 +11602,7 @@
11584
11602
  "preserve",
11585
11603
  "fill-compatible"
11586
11604
  ],
11587
- "description": "Define se linhas parciais com dois campos ou mais preservam os spans canônicos ou redistribuem apenas campos compatíveis para completar 12 colunas no breakpoint atual.",
11605
+ "description": "Define se cada linha visual parcial, depois de resolver visibilidade responsiva, CSS order e wrap, preserva os spans canônicos ou redistribui apenas campos compatíveis para completar 12 colunas no breakpoint atual.",
11588
11606
  "safetyNotes": "fill-compatible é uma projeção transitória do runtime: não altera x-ui.width nem persiste sections. Controles compactos, uploads e tipos desconhecidos preservam a largura canônica."
11589
11607
  },
11590
11608
  {
@@ -12248,9 +12266,9 @@
12248
12266
  {
12249
12267
  "chunkIndex": 10,
12250
12268
  "chunkKind": "capabilities",
12251
- "content": "Schema Capability:\n - Path: fieldMetadata[].transformDisplayValue\n Category: transform\n Kind: expression\n Description: Transforma valor para exibição.\n\nSchema Capability:\n - Path: fieldMetadata[].transformSaveValue\n Category: transform\n Kind: expression\n Description: Transforma valor para salvar.\n\nSchema Capability:\n - Path: fieldMetadata[].textTransformApply\n Category: transform\n Kind: enum\n Description: Quando aplicar transformação de texto.\n\nSchema Capability:\n - Path: fieldMetadata[].inlineEditing\n Category: behavior\n Kind: boolean\n Description: Permite edição inline (tabelas).\n\nSchema Capability:\n - Path: fieldMetadata[].unique\n Category: validation\n Kind: boolean\n Description: Valida unicidade no backend.\n\nSchema Capability:\n - Path: fieldMetadata[].readOnly\n Category: behavior\n Kind: boolean\n Description: Campo somente leitura.\n\nSchema Capability:\n - Path: fieldMetadata[].disabled\n Category: behavior\n Kind: boolean\n Description: Campo desabilitado.\n\nSchema Capability:\n - Path: fieldMetadata[].defaultValue\n Category: data\n Kind: object\n Description: Valor inicial do campo.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaLabel\n Category: accessibility\n Kind: string\n Description: Label para leitores de tela.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaDescribedBy\n Category: accessibility\n Kind: string\n Description: IDs de descrição acessível.\n\nSchema Capability:\n - Path: fieldMetadata[].tabIndex\n Category: accessibility\n Kind: number\n Description: Ordem de tabulacao para teclado.\n\nSchema Capability:\n - Path: fieldMetadata[].accessKey\n Category: accessibility\n Kind: string\n Description: Atalho de teclado (accessKey).\n\nComponent Capability:\n - Path: inputs.resourcePath\n Category: inputs\n Kind: string\n Description: Caminho do recurso para carregar/salvar dados via CRUD.\n\nComponent Capability:\n - Path: inputs.resourceId\n Category: inputs\n Kind: string\n Description: ID do registro atual (string ou number).\n\nComponent Capability:\n - Path: inputs.initialValue\n Category: inputs\n Kind: object\n Description: Valores iniciais locais para campos host-authored ou complementares.\n\nComponent Capability:\n - Path: inputs.mode\n Category: inputs\n Kind: enum\n Description: Modo do formulario (create/edit/view).\n\nComponent Capability:\n - Path: inputs.config\n Category: inputs\n Kind: object\n Description: Configuracao completa do formulario (FormConfig).\n\nComponent Capability:\n - Path: inputs.schemaSource\n Category: inputs\n Kind: enum\n Description: Fonte de schema para construcao automatica (resource/filter).\n\nComponent Capability:\n - Path: inputs.schemaUrl\n Category: inputs\n Kind: string\n Description: Schema canonico explicito publicado pelo backend para hosts que seguem surfaces/actions/capabilities.\n\nComponent Capability:\n - Path: inputs.readUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de leitura publicado por surface VIEW/READ_PROJECTION para hidratar a entidade exibida.\n\nComponent Capability:\n - Path: inputs.apiEndpointKey\n Category: inputs\n Kind: string\n Description: Endpoint canonico usado para resolver schemaUrl, readUrl e submitUrl relativos em hosts destacados.\n\nComponent Capability:\n - Path: inputs.submitUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de submit publicado por surface/action.\n\nComponent Capability:\n - Path: inputs.submitMethod\n Category: inputs\n Kind: enum\n Description: Metodo HTTP canonico para o submit quando o backend publica operacao explicita.\n\nComponent Capability:\n - Path: inputs.submitIdempotencyKey\n Category: inputs\n Kind: string\n Description: Identidade estavel da tentativa de comando, materializada a partir da politica execution da action.\n\nComponent Capability:\n - Path: inputs.submitCorrelationId\n Category: inputs\n Kind: string\n Description: Identificador de correlacao governado para rastreabilidade ponta a ponta do comando.\n\nComponent Capability:\n - Path: inputs.submitResourceVersion\n Category: inputs\n Kind: string\n Description: Versao persistida esperada, transportada como If-Match quando exigida pela action.\n\nComponent Capability:\n - Path: inputs.responseSchemaUrl\n Category: inputs\n Kind: string\n Description: Schema de resposta publicado pelo backend para inspeção diagnostica/read-only do host.\n\nComponent Capability:\n - Path: inputs.enableCustomization\n Category: inputs\n Kind: boolean\n Description: Habilita a edicao de layout/configuracao no editor.\n\nComponent Capability:\n - Path: inputs.showAiAssistant\n Category: inputs\n Kind: boolean\n Description: Mostra os gatilhos do copiloto semantico Praxis para a instancia do formulario.\n\nComponent Capability:\n - Path: inputs.formId\n Category: inputs\n Kind: string\n Description: ID persistente para salvar configuracoes e preferencias.\n\nComponent Capability:\n - Path: inputs.editorialContext\n Category: inputs\n Kind: object\n Description: Override de contexto editorial fornecido pelo host para os blocos hospedados antes/depois do formulario.\n\nComponent Capability:\n - Path: inputs.layout\n Category: inputs\n Kind: object\n Description: Layout legado (FormLayout). Preferir inputs.config + sections.\n\nComponent Capability:\n - Path: inputs.generatedLayoutPreset\n Category: inputs\n Kind: enum\n Description: Preset usado somente na criacao inicial de FormConfig a partir de schema/metadata.\n\nComponent Capability:\n - Path: inputs.configPersistenceStrategy\n Category: inputs\n Kind: enum\n Description: Define se preferências locais persistidas ou o contrato explícito do host governam a materialização corrente.\n\nComponent Capability:\n - Path: inputs.layoutPolicy\n Category: inputs\n Kind: object\n Description: Politica opt-in para materializar layout diretamente do schema atual sem depender de FormConfig.sections authoradas.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.source\n Category: inputs\n Kind: enum\n Description: Define se o layout vem de configuracao authorada ou do schema.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.preset\n Category: inputs\n Kind: enum\n Description: Preset de layout schema-driven. compactPresentation cobre detalhe read-only; groupedCommand cobre create/edit.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.intent\n Category: inputs\n Kind: enum\n Description: Intencao da surface: detalhe/apresentacao ou comando/editavel.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.lifecycle\n Category: inputs\n Kind: enum\n Description: Ciclo de materializacao do layout schema-driven.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.persistence\n Category: inputs\n Kind: enum\n Description: Define se sections geradas sao transient ou podem virar layout authorado apos detach explicito.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.orphanFieldExpansion\n Category: inputs\n Kind: enum\n Description: Define como uma linha groupedCommand com um unico campo usa o espaco restante. O default medium-and-wide expande spans 6 ou 8 e preserva campos compactos.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.contextFields\n Category: inputs\n Kind: array\n Description: Campos canônicos do request cujo valor vem do contexto da surface. Eles permanecem no FormGroup e no payload, sem renderizar controles redundantes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.partialRowStrategy\n Category: inputs\n Kind: enum\n Description: Define se linhas parciais com dois campos ou mais preservam os spans canônicos ou redistribuem apenas campos compatíveis para completar 12 colunas no breakpoint atual.",
12269
+ "content": "Schema Capability:\n - Path: fieldMetadata[].transformDisplayValue\n Category: transform\n Kind: expression\n Description: Transforma valor para exibição.\n\nSchema Capability:\n - Path: fieldMetadata[].transformSaveValue\n Category: transform\n Kind: expression\n Description: Transforma valor para salvar.\n\nSchema Capability:\n - Path: fieldMetadata[].textTransformApply\n Category: transform\n Kind: enum\n Description: Quando aplicar transformação de texto.\n\nSchema Capability:\n - Path: fieldMetadata[].inlineEditing\n Category: behavior\n Kind: boolean\n Description: Permite edição inline (tabelas).\n\nSchema Capability:\n - Path: fieldMetadata[].unique\n Category: validation\n Kind: boolean\n Description: Valida unicidade no backend.\n\nSchema Capability:\n - Path: fieldMetadata[].readOnly\n Category: behavior\n Kind: boolean\n Description: Campo somente leitura.\n\nSchema Capability:\n - Path: fieldMetadata[].disabled\n Category: behavior\n Kind: boolean\n Description: Campo desabilitado.\n\nSchema Capability:\n - Path: fieldMetadata[].defaultValue\n Category: data\n Kind: object\n Description: Valor inicial do campo.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaLabel\n Category: accessibility\n Kind: string\n Description: Label para leitores de tela.\n\nSchema Capability:\n - Path: fieldMetadata[].ariaDescribedBy\n Category: accessibility\n Kind: string\n Description: IDs de descrição acessível.\n\nSchema Capability:\n - Path: fieldMetadata[].tabIndex\n Category: accessibility\n Kind: number\n Description: Ordem de tabulacao para teclado.\n\nSchema Capability:\n - Path: fieldMetadata[].accessKey\n Category: accessibility\n Kind: string\n Description: Atalho de teclado (accessKey).\n\nComponent Capability:\n - Path: inputs.resourcePath\n Category: inputs\n Kind: string\n Description: Caminho do recurso para carregar/salvar dados via CRUD.\n\nComponent Capability:\n - Path: inputs.resourceId\n Category: inputs\n Kind: string\n Description: ID do registro atual (string ou number).\n\nComponent Capability:\n - Path: inputs.initialValue\n Category: inputs\n Kind: object\n Description: Valores iniciais locais para campos host-authored ou complementares.\n\nComponent Capability:\n - Path: inputs.mode\n Category: inputs\n Kind: enum\n Description: Modo do formulario (create/edit/view).\n\nComponent Capability:\n - Path: inputs.config\n Category: inputs\n Kind: object\n Description: Configuracao completa do formulario (FormConfig).\n\nComponent Capability:\n - Path: inputs.schemaSource\n Category: inputs\n Kind: enum\n Description: Fonte de schema para construcao automatica (resource/filter).\n\nComponent Capability:\n - Path: inputs.schemaUrl\n Category: inputs\n Kind: string\n Description: Schema canonico explicito publicado pelo backend para hosts que seguem surfaces/actions/capabilities.\n\nComponent Capability:\n - Path: inputs.readUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de leitura publicado por surface VIEW/READ_PROJECTION para hidratar a entidade exibida.\n\nComponent Capability:\n - Path: inputs.apiEndpointKey\n Category: inputs\n Kind: string\n Description: Endpoint canonico usado para resolver schemaUrl, readUrl e submitUrl relativos em hosts destacados.\n\nComponent Capability:\n - Path: inputs.submitUrl\n Category: inputs\n Kind: string\n Description: Endpoint canonico de submit publicado por surface/action.\n\nComponent Capability:\n - Path: inputs.submitMethod\n Category: inputs\n Kind: enum\n Description: Metodo HTTP canonico para o submit quando o backend publica operacao explicita.\n\nComponent Capability:\n - Path: inputs.submitIdempotencyKey\n Category: inputs\n Kind: string\n Description: Identidade estavel da tentativa de comando, materializada a partir da politica execution da action.\n\nComponent Capability:\n - Path: inputs.submitCorrelationId\n Category: inputs\n Kind: string\n Description: Identificador de correlacao governado para rastreabilidade ponta a ponta do comando.\n\nComponent Capability:\n - Path: inputs.submitResourceVersion\n Category: inputs\n Kind: string\n Description: Versao persistida esperada, transportada como If-Match quando exigida pela action.\n\nComponent Capability:\n - Path: inputs.responseSchemaUrl\n Category: inputs\n Kind: string\n Description: Schema de resposta publicado pelo backend para inspeção diagnostica/read-only do host.\n\nComponent Capability:\n - Path: inputs.enableCustomization\n Category: inputs\n Kind: boolean\n Description: Habilita a edicao de layout/configuracao no editor.\n\nComponent Capability:\n - Path: inputs.showAiAssistant\n Category: inputs\n Kind: boolean\n Description: Mostra os gatilhos do copiloto semantico Praxis para a instancia do formulario.\n\nComponent Capability:\n - Path: inputs.formId\n Category: inputs\n Kind: string\n Description: ID persistente para salvar configuracoes e preferencias.\n\nComponent Capability:\n - Path: inputs.editorialContext\n Category: inputs\n Kind: object\n Description: Override de contexto editorial fornecido pelo host para os blocos hospedados antes/depois do formulario.\n\nComponent Capability:\n - Path: inputs.layout\n Category: inputs\n Kind: object\n Description: Layout legado (FormLayout). Preferir inputs.config + sections.\n\nComponent Capability:\n - Path: inputs.generatedLayoutPreset\n Category: inputs\n Kind: enum\n Description: Preset usado somente na criacao inicial de FormConfig a partir de schema/metadata.\n\nComponent Capability:\n - Path: inputs.configPersistenceStrategy\n Category: inputs\n Kind: enum\n Description: Define se preferências locais persistidas ou o contrato explícito do host governam a materialização corrente.\n\nComponent Capability:\n - Path: inputs.layoutPolicy\n Category: inputs\n Kind: object\n Description: Politica opt-in para materializar layout diretamente do schema atual sem depender de FormConfig.sections authoradas.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.source\n Category: inputs\n Kind: enum\n Description: Define se o layout vem de configuracao authorada ou do schema.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.preset\n Category: inputs\n Kind: enum\n Description: Preset de layout schema-driven. compactPresentation cobre detalhe read-only; groupedCommand cobre create/edit.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.intent\n Category: inputs\n Kind: enum\n Description: Intencao da surface: detalhe/apresentacao ou comando/editavel.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.lifecycle\n Category: inputs\n Kind: enum\n Description: Ciclo de materializacao do layout schema-driven.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.persistence\n Category: inputs\n Kind: enum\n Description: Define se sections geradas sao transient ou podem virar layout authorado apos detach explicito.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.orphanFieldExpansion\n Category: inputs\n Kind: enum\n Description: Define como uma linha groupedCommand com um unico campo usa o espaco restante. O default medium-and-wide expande spans 6 ou 8 e preserva campos compactos.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.contextFields\n Category: inputs\n Kind: array\n Description: Campos canônicos do request cujo valor vem do contexto da surface. Eles permanecem no FormGroup e no payload, sem renderizar controles redundantes.\n\nComponent Capability:\n - Path: inputs.layoutPolicy.groupedCommand.partialRowStrategy\n Category: inputs\n Kind: enum\n Description: Define se cada linha visual parcial, depois de resolver visibilidade responsiva, CSS order e wrap, preserva os spans canônicos ou redistribui apenas campos compatíveis para completar 12 colunas no breakpoint atual.",
12252
12270
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/form-ai-capabilities.ts",
12253
- "contentHash": "d8ba06c1f0006e7d3189b75d8329245c840d75d84d753c6dfccc480a4880d347",
12271
+ "contentHash": "a05a482e5873ff1de353543220891daaa3867cea957150def37ea50539a20c21",
12254
12272
  "sourceKind": "component_definition",
12255
12273
  "sourceId": "praxis-dynamic-form-dialog-host",
12256
12274
  "corpusVersion": "1.0.0"
@@ -6,7 +6,7 @@ import { Router, ActivatedRoute, RouterLink } from '@angular/router';
6
6
  import { MatSnackBar } from '@angular/material/snack-bar';
7
7
  import { firstValueFrom, BehaviorSubject, Subscription } from 'rxjs';
8
8
  import * as i2$1 from '@praxisui/core';
9
- import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, PraxisIconDirective, providePraxisI18nConfig, createDefaultTableConfig, EnterpriseRuntimeContextService, GLOBAL_SURFACE_SERVICE, SurfaceOutletRegistryService, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, normalizeSurfaceOperationContext, translateUnavailableWorkflowMessage, isSurfaceNavigationError, translateSurfaceNavigationRejected, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, SURFACE_DRAWER_REF, SURFACE_DRAWER_CONTENT_DATA, PraxisIconButtonComponent, PraxisResourceIdentityComponent, GenericCrudService, ComponentMetadataRegistry } from '@praxisui/core';
9
+ import { ASYNC_CONFIG_STORAGE, GlobalConfigService, CrudOperationResolutionService, LoggerService, SurfaceNavigationError, fillUndefined, SETTINGS_PANEL_DATA, PraxisI18nService, PraxisIconDirective, providePraxisI18nConfig, createDefaultTableConfig, EnterpriseRuntimeContextService, GLOBAL_SURFACE_SERVICE, SurfaceOutletRegistryService, ComponentKeyService, ResourceDiscoveryService, ResourceActionOpenAdapterService, ResourceSurfaceOpenAdapterService, normalizeSurfaceOperationContext, translateUnavailableWorkflowMessage, isSurfaceNavigationError, translateSurfaceNavigationRejected, normalizeUnknownError, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, SURFACE_DRAWER_REF, SURFACE_DRAWER_CONTENT_DATA, PraxisIconButtonComponent, PraxisResourceIdentityComponent, GenericCrudService, ComponentMetadataRegistry } from '@praxisui/core';
10
10
  import { SettingsPanelService } from '@praxisui/settings-panel';
11
11
  import { PraxisTableInlineAuthoringEditorComponent, PraxisTable } from '@praxisui/table';
12
12
  import { ConfirmDialogComponent } from '@praxisui/dynamic-fields';
@@ -193,6 +193,11 @@ class CrudLauncherService {
193
193
  presentation: mode === 'drawer' ? 'drawer' : 'modal',
194
194
  resourceIdentity,
195
195
  contextIdentity,
196
+ reactiveDeterminationCallbacks: {
197
+ onEvent: drawerCallbacks?.onReactiveDetermination,
198
+ onPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
199
+ onStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
200
+ },
196
201
  };
197
202
  const modalCfg = { ...(merged.metadata.defaults?.modal || {}) };
198
203
  const restoreFocus = resolveCrudRestoreFocus(modalCfg.restoreFocus, actionFocusOrigin);
@@ -243,6 +248,9 @@ class CrudLauncherService {
243
248
  restoreFocus,
244
249
  onClose: drawerCallbacks?.onClose,
245
250
  onResult: drawerCallbacks?.onResult,
251
+ onReactiveDetermination: drawerCallbacks?.onReactiveDetermination,
252
+ onReactiveDeterminationPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
253
+ onReactiveDeterminationStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
246
254
  }));
247
255
  return { mode };
248
256
  }
@@ -3808,6 +3816,10 @@ class PraxisCrudComponent {
3808
3816
  afterClose = new EventEmitter();
3809
3817
  afterSave = new EventEmitter();
3810
3818
  afterDelete = new EventEmitter();
3819
+ /** Metadata-only Reactive Determination evidence from an open form host. */
3820
+ reactiveDeterminationExecuted = new EventEmitter();
3821
+ reactiveDeterminationPendingChange = new EventEmitter();
3822
+ reactiveDeterminationStabilityChange = new EventEmitter();
3811
3823
  error = new EventEmitter();
3812
3824
  rowClick = new EventEmitter();
3813
3825
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
@@ -3834,11 +3846,13 @@ class PraxisCrudComponent {
3834
3846
  snack = inject(MatSnackBar);
3835
3847
  dialog = inject(DialogService);
3836
3848
  i18n = inject(PraxisI18nService);
3849
+ logger = inject(LoggerService, { optional: true });
3837
3850
  injector = inject(Injector);
3838
3851
  resourceDiscoveryInstance;
3839
3852
  actionOpenAdapterInstance;
3840
3853
  surfaceOpenAdapterInstance;
3841
3854
  materializedRefreshSequence = 0;
3855
+ surfaceOpenAttemptSequence = 0;
3842
3856
  global = (() => {
3843
3857
  try {
3844
3858
  return inject(GlobalConfigService);
@@ -4051,6 +4065,18 @@ class PraxisCrudComponent {
4051
4065
  this.refreshTable();
4052
4066
  }
4053
4067
  },
4068
+ onReactiveDetermination: (event) => this.reactiveDeterminationExecuted.emit({
4069
+ action: effectiveAction.action,
4070
+ event,
4071
+ }),
4072
+ onReactiveDeterminationPendingChange: (pending) => this.reactiveDeterminationPendingChange.emit({
4073
+ action: effectiveAction.action,
4074
+ pending,
4075
+ }),
4076
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4077
+ action: effectiveAction.action,
4078
+ ...stability,
4079
+ }),
4054
4080
  }, {
4055
4081
  capabilities: effectiveAction.action === 'create'
4056
4082
  ? this.collectionCapabilities
@@ -4324,6 +4350,12 @@ class PraxisCrudComponent {
4324
4350
  const { mode, ref } = await this.launcher.launch(createAction, undefined, this.resolvedMetadata, this.componentKeyId(), {
4325
4351
  onClose: () => emitDrawerClose(),
4326
4352
  onResult: (result) => handleResult(result),
4353
+ onReactiveDetermination: (event) => this.reactiveDeterminationExecuted.emit({ action: normalizedAction, event }),
4354
+ onReactiveDeterminationPendingChange: (pending) => this.reactiveDeterminationPendingChange.emit({ action: normalizedAction, pending }),
4355
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4356
+ action: normalizedAction,
4357
+ ...stability,
4358
+ }),
4327
4359
  }, {
4328
4360
  capabilities: this.collectionCapabilities,
4329
4361
  links: this.tableCollectionLinks,
@@ -4582,6 +4614,12 @@ class PraxisCrudComponent {
4582
4614
  return true;
4583
4615
  }
4584
4616
  const focusOrigin = this.resolveRuntimeFocusOrigin(runtimeEvent);
4617
+ const correlationId = [
4618
+ this.componentKeyId() || this.crudId || 'praxis-crud',
4619
+ 'surface.open',
4620
+ surface.id,
4621
+ ++this.surfaceOpenAttemptSequence,
4622
+ ].join(':');
4585
4623
  let openPromise;
4586
4624
  try {
4587
4625
  const surfaceContext = {
@@ -4592,6 +4630,7 @@ class PraxisCrudComponent {
4592
4630
  resourcePath,
4593
4631
  surfaceId: surface.id,
4594
4632
  operationId: surface.operationId,
4633
+ correlationId,
4595
4634
  },
4596
4635
  runtime: {
4597
4636
  row: row ?? null,
@@ -4607,11 +4646,8 @@ class PraxisCrudComponent {
4607
4646
  openPromise = handledInline ? Promise.resolve(undefined) : Promise.resolve(this.surfaceService.open(payload, surfaceContext));
4608
4647
  }
4609
4648
  catch (error) {
4610
- if (this.notifySurfaceNavigationFailure(error)) {
4611
- this.error.emit(error);
4612
- return true;
4613
- }
4614
- return false;
4649
+ this.reportDiscoveredSurfaceOpenFailure(error, normalizedAction, surface, resourcePath, correlationId);
4650
+ return true;
4615
4651
  }
4616
4652
  try {
4617
4653
  this.bindDiscoveredSurfaceLifecycle(await openPromise);
@@ -4621,8 +4657,7 @@ class PraxisCrudComponent {
4621
4657
  });
4622
4658
  }
4623
4659
  catch (err) {
4624
- this.error.emit(err);
4625
- this.notifySurfaceNavigationFailure(err);
4660
+ this.reportDiscoveredSurfaceOpenFailure(err, normalizedAction, surface, resourcePath, correlationId);
4626
4661
  }
4627
4662
  return true;
4628
4663
  }
@@ -4742,6 +4777,31 @@ class PraxisCrudComponent {
4742
4777
  this.snack.open(translateSurfaceNavigationRejected(this.i18n), undefined, { duration: 4500 });
4743
4778
  return true;
4744
4779
  }
4780
+ reportDiscoveredSurfaceOpenFailure(error, action, surface, resourcePath, correlationId) {
4781
+ const normalizedCause = normalizeUnknownError(error);
4782
+ this.error.emit(error);
4783
+ this.notifySurfaceNavigationFailure(error);
4784
+ this.logger?.warn('Discovered CRUD surface failed to open.', {
4785
+ context: {
4786
+ lib: '@praxisui/crud',
4787
+ component: 'PraxisCrudComponent',
4788
+ actionId: action,
4789
+ correlationId,
4790
+ },
4791
+ data: {
4792
+ surfaceId: surface.id,
4793
+ mode: 'drawer',
4794
+ resourcePath,
4795
+ selectedPath: 'surface.open',
4796
+ fallback: 'none',
4797
+ cause: {
4798
+ name: normalizedCause.name,
4799
+ message: normalizedCause.message,
4800
+ },
4801
+ },
4802
+ throttleKey: `crud:surface.open:${action}:${surface.id}`,
4803
+ });
4804
+ }
4745
4805
  async resolveDiscoveredActionCatalog(row) {
4746
4806
  try {
4747
4807
  if (row) {
@@ -5467,7 +5527,7 @@ class PraxisCrudComponent {
5467
5527
  return Object.entries(params).reduce((current, [name, value]) => current.split(`{${name}}`).join(value), text);
5468
5528
  }
5469
5529
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5470
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisCrudComponent, isStandalone: true, selector: "praxis-crud", inputs: { metadata: "metadata", crudId: "crudId", componentInstanceId: "componentInstanceId", tableConfigPersistenceStrategy: "tableConfigPersistenceStrategy", context: "context", enableCustomization: "enableCustomization", authoringCapability: "authoringCapability" }, outputs: { configureRequested: "configureRequested", afterOpen: "afterOpen", afterClose: "afterClose", afterSave: "afterSave", afterDelete: "afterDelete", error: "error", rowClick: "rowClick", rowAction: "rowAction", selectionChange: "selectionChange", tableRuntimeConfigChange: "tableRuntimeConfigChange", crudAuthoringDocumentApplied: "crudAuthoringDocumentApplied", crudAuthoringDocumentSaved: "crudAuthoringDocumentSaved" }, providers: [
5530
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisCrudComponent, isStandalone: true, selector: "praxis-crud", inputs: { metadata: "metadata", crudId: "crudId", componentInstanceId: "componentInstanceId", tableConfigPersistenceStrategy: "tableConfigPersistenceStrategy", context: "context", enableCustomization: "enableCustomization", authoringCapability: "authoringCapability" }, outputs: { configureRequested: "configureRequested", afterOpen: "afterOpen", afterClose: "afterClose", afterSave: "afterSave", afterDelete: "afterDelete", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", reactiveDeterminationStabilityChange: "reactiveDeterminationStabilityChange", error: "error", rowClick: "rowClick", rowAction: "rowAction", selectionChange: "selectionChange", tableRuntimeConfigChange: "tableRuntimeConfigChange", crudAuthoringDocumentApplied: "crudAuthoringDocumentApplied", crudAuthoringDocumentSaved: "crudAuthoringDocumentSaved" }, providers: [
5471
5531
  providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
5472
5532
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
5473
5533
  ], viewQueries: [{ propertyName: "table", first: true, predicate: PraxisTable, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -5586,6 +5646,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5586
5646
  type: Output
5587
5647
  }], afterDelete: [{
5588
5648
  type: Output
5649
+ }], reactiveDeterminationExecuted: [{
5650
+ type: Output
5651
+ }], reactiveDeterminationPendingChange: [{
5652
+ type: Output
5653
+ }], reactiveDeterminationStabilityChange: [{
5654
+ type: Output
5589
5655
  }], error: [{
5590
5656
  type: Output
5591
5657
  }], rowClick: [{
@@ -5633,6 +5699,9 @@ class DynamicFormDialogHostComponent {
5633
5699
  configStorage;
5634
5700
  surfaceRef;
5635
5701
  formComp;
5702
+ reactiveDeterminationExecuted = new EventEmitter();
5703
+ reactiveDeterminationPendingChange = new EventEmitter();
5704
+ reactiveDeterminationStabilityChange = new EventEmitter();
5636
5705
  modal = {};
5637
5706
  presentation = 'modal';
5638
5707
  maximized = false;
@@ -5644,6 +5713,7 @@ class DynamicFormDialogHostComponent {
5644
5713
  terminalClose = false;
5645
5714
  destroyRef = inject(DestroyRef);
5646
5715
  i18n = inject(PraxisI18nService);
5716
+ reactiveDeterminationStabilitySignature = '';
5647
5717
  resourcePath;
5648
5718
  resourceId;
5649
5719
  initialValue;
@@ -5967,6 +6037,9 @@ class DynamicFormDialogHostComponent {
5967
6037
  if (stage === 'before' || stage === 'error') {
5968
6038
  return;
5969
6039
  }
6040
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6041
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.())
6042
+ return;
5970
6043
  if (this.modal.closeOnSave === false) {
5971
6044
  this.saveState();
5972
6045
  return;
@@ -5982,6 +6055,47 @@ class DynamicFormDialogHostComponent {
5982
6055
  }
5983
6056
  }
5984
6057
  onCancel() {
6058
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6059
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6060
+ void this.formComp.waitForReactiveDeterminations().then((stable) => {
6061
+ if (stable)
6062
+ this.continueCancel();
6063
+ });
6064
+ return;
6065
+ }
6066
+ this.continueCancel();
6067
+ }
6068
+ onReactiveDeterminationExecuted(event) {
6069
+ this.reactiveDeterminationExecuted.emit(event);
6070
+ this.data.reactiveDeterminationCallbacks?.onEvent?.(event);
6071
+ this.emitReactiveDeterminationStability();
6072
+ }
6073
+ onReactiveDeterminationPendingChange(pending) {
6074
+ this.reactiveDeterminationPendingChange.emit(pending);
6075
+ this.data.reactiveDeterminationCallbacks?.onPendingChange?.(pending);
6076
+ this.emitReactiveDeterminationStability();
6077
+ }
6078
+ emitReactiveDeterminationStability() {
6079
+ const pending = this.formComp?.hasPendingReactiveDeterminations?.() === true;
6080
+ const unsatisfied = this.formComp?.hasUnsatisfiedReactiveDeterminations?.() === true;
6081
+ const status = pending
6082
+ ? 'pending'
6083
+ : unsatisfied
6084
+ ? 'settled-unsatisfied'
6085
+ : 'settled-satisfied';
6086
+ const signature = `${status}:${pending}:${unsatisfied}`;
6087
+ if (signature === this.reactiveDeterminationStabilitySignature)
6088
+ return;
6089
+ this.reactiveDeterminationStabilitySignature = signature;
6090
+ const stability = {
6091
+ status,
6092
+ pending,
6093
+ unsatisfied,
6094
+ };
6095
+ this.reactiveDeterminationStabilityChange.emit(stability);
6096
+ this.data.reactiveDeterminationCallbacks?.onStabilityChange?.(stability);
6097
+ }
6098
+ continueCancel() {
5985
6099
  if (this.surfaceRef) {
5986
6100
  void this.canLeaveSurfaceFrame().then((allowed) => {
5987
6101
  if (!allowed)
@@ -6018,6 +6132,12 @@ class DynamicFormDialogHostComponent {
6018
6132
  }
6019
6133
  }
6020
6134
  async canLeaveSurfaceFrame() {
6135
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6136
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6137
+ const stable = await this.formComp.waitForReactiveDeterminations();
6138
+ if (!stable)
6139
+ return false;
6140
+ }
6021
6141
  if (this.terminalClose || !this.formComp?.form.dirty) {
6022
6142
  return true;
6023
6143
  }
@@ -6157,7 +6277,7 @@ class DynamicFormDialogHostComponent {
6157
6277
  return { ...horizontal, ...vertical };
6158
6278
  }
6159
6279
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, deps: [{ token: MatDialogRef, optional: true }, { token: MAT_DIALOG_DATA, optional: true }, { token: DialogService }, { token: i2$1.GenericCrudService }, { token: ASYNC_CONFIG_STORAGE }, { token: SURFACE_DRAWER_REF, optional: true }, { token: SURFACE_DRAWER_CONTENT_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
6160
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", host: { properties: { "attr.data-density": "modal.density || \"default\"", "attr.data-presentation": "presentation", "class.praxis-drawer": "presentation === \"drawer\"", "class.praxis-surface-frame": "isSurfaceFrame" }, classAttribute: "praxis-dialog" }, providers: [
6280
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: DynamicFormDialogHostComponent, isStandalone: true, selector: "praxis-dynamic-form-dialog-host", outputs: { reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange", reactiveDeterminationStabilityChange: "reactiveDeterminationStabilityChange" }, host: { properties: { "attr.data-density": "modal.density || \"default\"", "attr.data-presentation": "presentation", "class.praxis-drawer": "presentation === \"drawer\"", "class.praxis-surface-frame": "isSurfaceFrame" }, classAttribute: "praxis-dialog" }, providers: [
6161
6281
  GenericCrudService,
6162
6282
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
6163
6283
  ], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
@@ -6256,9 +6376,11 @@ class DynamicFormDialogHostComponent {
6256
6376
  [actions]="formActions"
6257
6377
  (formSubmit)="onSave($event)"
6258
6378
  (formCancel)="onCancel()"
6379
+ (reactiveDeterminationExecuted)="onReactiveDeterminationExecuted($event)"
6380
+ (reactiveDeterminationPendingChange)="onReactiveDeterminationPendingChange($event)"
6259
6381
  ></praxis-dynamic-form>
6260
6382
  </mat-dialog-content>
6261
- `, isInline: true, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisResourceIdentityComponent, selector: "praxis-resource-identity", inputs: ["identity", "emptyTitle", "density", "showMetadataLabels", "showKeyLabel", "ariaLabel"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange"] }], encapsulation: i0.ViewEncapsulation.None });
6383
+ `, isInline: true, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisResourceIdentityComponent, selector: "praxis-resource-identity", inputs: ["identity", "emptyTitle", "density", "showMetadataLabels", "showKeyLabel", "ariaLabel"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange"] }], encapsulation: i0.ViewEncapsulation.None });
6262
6384
  }
6263
6385
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormDialogHostComponent, decorators: [{
6264
6386
  type: Component,
@@ -6374,6 +6496,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6374
6496
  [actions]="formActions"
6375
6497
  (formSubmit)="onSave($event)"
6376
6498
  (formCancel)="onCancel()"
6499
+ (reactiveDeterminationExecuted)="onReactiveDeterminationExecuted($event)"
6500
+ (reactiveDeterminationPendingChange)="onReactiveDeterminationPendingChange($event)"
6377
6501
  ></praxis-dynamic-form>
6378
6502
  </mat-dialog-content>
6379
6503
  `, styles: ["praxis-dynamic-form-dialog-host{--dlg-header-h: 56px;--dlg-footer-h: 56px;--dlg-pad: 16px;display:flex;flex-direction:column;height:100%;overflow:hidden}praxis-dynamic-form-dialog-host[data-density=compact]{--dlg-header-h: 44px;--dlg-footer-h: 44px;--dlg-pad: 12px}praxis-dynamic-form-dialog-host .dialog-header{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:var(--dlg-pad);min-height:var(--dlg-header-h);padding:10px var(--dlg-pad);margin:0;background:var(--md-sys-color-surface-container-high);border-bottom:1px solid var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-title{margin:0;font:inherit;font-weight:600;color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host .dialog-heading{display:grid;min-width:0;gap:2px}praxis-dynamic-form-dialog-host .dialog-title-icon{display:inline-grid;flex:0 0 auto;width:36px;height:36px;place-items:center;border-radius:10px;color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 12%,transparent)}praxis-dynamic-form-dialog-host .dialog-title-icon mat-icon{width:22px;height:22px;font-size:22px}praxis-dynamic-form-dialog-host .dialog-subtitle{display:-webkit-box;overflow:hidden;color:var(--md-sys-color-on-surface-variant);font-size:.82rem;font-weight:400;line-height:1.35;-webkit-box-orient:vertical;-webkit-line-clamp:2}praxis-dynamic-form-dialog-host .spacer{flex:1}praxis-dynamic-form-dialog-host .dialog-content{flex:1 1 auto;overflow:auto;padding:var(--dlg-pad);max-height:calc(100svh - var(--dlg-header-h) - 32px)}praxis-dynamic-form-dialog-host .crud-operation-context{position:sticky;top:0;z-index:1;display:grid;gap:.75rem;margin-block-end:var(--dlg-pad);padding-block:.5rem .75rem;background:var(--pfx-form-surface, var(--md-sys-color-surface));border-bottom:1px solid var(--md-sys-color-outline-variant)}praxis-dynamic-form-dialog-host .crud-resource-identity{display:grid;gap:.25rem;min-width:0}praxis-dynamic-form-dialog-host .crud-resource-identity__label{color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-label-medium, 500 .75rem/1rem inherit)}praxis-dynamic-form-dialog-host.praxis-drawer{--dlg-header-h: 72px;width:100%;min-width:0;max-width:100vw;height:100dvh;background:var(--pfx-form-surface, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-header{background:color-mix(in srgb,var(--md-sys-color-surface-container-high, var(--md-sys-color-surface)),transparent 4%)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content{display:flex;flex-direction:column;max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form{display:block;flex:1 1 auto;min-height:0}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form{min-height:100%}praxis-dynamic-form-dialog-host.praxis-drawer .dialog-content>praxis-dynamic-form>.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:auto;padding-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}praxis-dynamic-form-dialog-host.praxis-surface-frame .dialog-content{max-height:none;min-height:0;padding:clamp(12px,2.4vw,24px)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}praxis-dynamic-form-dialog-host .dialog-header button.praxis-icon-button:hover{color:var(--md-sys-color-primary)}praxis-dynamic-form-dialog-host .dialog-footer{position:sticky;bottom:0;z-index:1;padding:var(--dlg-pad)}.pfx-blur-backdrop{background-color:var(--pfx-backdrop, rgba(15, 23, 42, .42))!important;backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 10px)) saturate(110%)}.pfx-transparent-backdrop{background-color:transparent!important}.cdk-overlay-pane.pfx-dialog-pane{overflow:hidden;transition:width .2s ease,height .2s ease,margin .2s ease}.cdk-overlay-pane.pfx-dialog-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane .mdc-dialog__surface{display:flex;flex-direction:column;width:100%;min-width:0;height:100%;max-height:inherit;overflow:hidden;background:var(--pfx-form-surface, var(--md-sys-color-surface))!important;border:1px solid var(--pfx-form-stroke, var(--md-sys-color-outline-variant))!important}.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-dialog-pane.pfx-dialog-frosted .mdc-dialog__surface{backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}.cdk-overlay-pane.pfx-drawer-pane{margin:0!important;border-radius:0!important;box-shadow:var(--md-sys-elevation-level3, 0 24px 80px rgba(15, 23, 42, .28)),0 0 0 1px color-mix(in srgb,var(--md-sys-color-outline, #64748b) 24%,transparent)}.cdk-overlay-pane.pfx-drawer-pane.pfx-drawer-maximized{margin:var(--pfx-drawer-edge-gap, 8px)!important}.cdk-overlay-pane.pfx-drawer-pane .mat-mdc-dialog-surface,.cdk-overlay-pane.pfx-drawer-pane .mdc-dialog__surface{min-width:0!important;border-radius:0!important}\n"] }]
@@ -6403,6 +6527,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6403
6527
  }] }], propDecorators: { formComp: [{
6404
6528
  type: ViewChild,
6405
6529
  args: [PraxisDynamicForm]
6530
+ }], reactiveDeterminationExecuted: [{
6531
+ type: Output
6532
+ }], reactiveDeterminationPendingChange: [{
6533
+ type: Output
6534
+ }], reactiveDeterminationStabilityChange: [{
6535
+ type: Output
6406
6536
  }] } });
6407
6537
  function getFormSubmitStage(result) {
6408
6538
  if (!result || typeof result !== 'object' || !('stage' in result)) {
@@ -6709,6 +6839,21 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
6709
6839
  type: '{ id: string | number }',
6710
6840
  description: 'Emitido ao deletar.',
6711
6841
  },
6842
+ {
6843
+ name: 'reactiveDeterminationExecuted',
6844
+ type: '{ action: string; event: ReactiveDeterminationExecutionEvent }',
6845
+ description: 'Evidencia metadata-only encaminhada pelo formulario aberto, com contexto da acao CRUD.',
6846
+ },
6847
+ {
6848
+ name: 'reactiveDeterminationPendingChange',
6849
+ type: '{ action: string; pending: boolean }',
6850
+ description: 'Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis.',
6851
+ },
6852
+ {
6853
+ name: 'reactiveDeterminationStabilityChange',
6854
+ type: 'CrudReactiveDeterminationStabilityChange',
6855
+ description: 'Conclusao agregada do formulario aberto, distinguindo settled-satisfied de settled-unsatisfied e preservando o contexto da acao.',
6856
+ },
6712
6857
  {
6713
6858
  name: 'rowClick',
6714
6859
  type: '{ row: unknown; index: number }',
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@praxisui/crud",
3
- "version": "9.0.5-rc.2",
3
+ "version": "9.0.5-rc.20",
4
4
  "description": "CRUD building blocks for Praxis UI: integrates dynamic forms and tables with unified configuration and services.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/dynamic-form": "^9.0.5-rc.2",
9
- "@praxisui/table": "^9.0.5-rc.2",
10
- "@praxisui/core": "^9.0.5-rc.2",
11
- "@praxisui/dynamic-fields": "^9.0.5-rc.2",
12
- "@praxisui/settings-panel": "^9.0.5-rc.2",
8
+ "@praxisui/dynamic-form": "^9.0.5-rc.20",
9
+ "@praxisui/table": "^9.0.5-rc.20",
10
+ "@praxisui/core": "^9.0.5-rc.20",
11
+ "@praxisui/dynamic-fields": "^9.0.5-rc.20",
12
+ "@praxisui/settings-panel": "^9.0.5-rc.20",
13
13
  "@angular/cdk": "^21.0.0",
14
14
  "@angular/forms": "^21.0.0",
15
15
  "@angular/material": "^21.0.0",
16
16
  "@angular/router": "^21.0.0",
17
- "@praxisui/ai": "^9.0.5-rc.2",
17
+ "@praxisui/ai": "^9.0.5-rc.20",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -51,6 +51,29 @@ interface CrudDrawerResult {
51
51
  type: CrudDrawerResultType;
52
52
  data?: Record<string, unknown>;
53
53
  }
54
+ /** Minimal structural evidence contract kept local to the light entrypoint. */
55
+ interface CrudReactiveDeterminationExecutionEvent {
56
+ determinationId: string;
57
+ operationId: string;
58
+ status: 'pending' | 'success' | 'skipped' | 'error';
59
+ sourcePaths: string[];
60
+ targetPaths: string[];
61
+ appliedTargetPaths?: string[];
62
+ correlationId: string;
63
+ durationMs: number;
64
+ reason?: string;
65
+ provenance: {
66
+ kind: 'platform' | 'host';
67
+ source: string;
68
+ version?: string;
69
+ };
70
+ }
71
+ /** Minimal structural stability contract kept local to the light entrypoint. */
72
+ interface CrudReactiveDeterminationStabilityChange {
73
+ status: 'pending' | 'settled-satisfied' | 'settled-unsatisfied';
74
+ pending: boolean;
75
+ unsatisfied: boolean;
76
+ }
54
77
  interface CrudDrawerOpenConfig {
55
78
  action: CrudAction;
56
79
  metadata: CrudMetadata;
@@ -68,6 +91,12 @@ interface CrudDrawerOpenConfig {
68
91
  * Hosts podem propagar `save/delete/close` para sincronizar telemetria/eventos.
69
92
  */
70
93
  onResult?: (result: CrudDrawerResult) => void;
94
+ /** Bind to the child form's metadata-only determination evidence. */
95
+ onReactiveDetermination?: (event: CrudReactiveDeterminationExecutionEvent) => void;
96
+ /** Bind to pending state and refuse every adapter-owned close/submit while true. */
97
+ onReactiveDeterminationPendingChange?: (pending: boolean) => void;
98
+ /** Report aggregate success/unsatisfied stability without form values. */
99
+ onReactiveDeterminationStabilityChange?: (stability: CrudReactiveDeterminationStabilityChange) => void;
71
100
  }
72
101
  interface CrudDrawerAdapter {
73
102
  open(config: CrudDrawerOpenConfig): Promise<void> | void;
@@ -84,4 +113,4 @@ interface DialogConfig<D = any> extends MatDialogConfig<D> {
84
113
  declare const CRUD_DRAWER_ADAPTER: InjectionToken<CrudDrawerAdapter>;
85
114
 
86
115
  export { CRUD_DRAWER_ADAPTER };
87
- export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudResource, DialogConfig, FormOpenMode };
116
+ export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudReactiveDeterminationExecutionEvent, CrudReactiveDeterminationStabilityChange, CrudResource, DialogConfig, FormOpenMode };
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { NgZone, OnChanges, EventEmitter, SimpleChanges, OnInit, AfterViewInit, Provider, OnDestroy } from '@angular/core';
3
3
  import * as _praxisui_core from '@praxisui/core';
4
- import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, MaterializedResourceIdentity, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, SurfaceDrawerRef, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
4
+ import { RowAction, ToolbarAction, ApiEndpoint, ApiUrlEntry, DynamicFormLayoutPolicy, BackConfig, TableConfig, PraxisDataQueryContext, FormConfig, ReactiveDeterminationExecutionEvent, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, MaterializedResourceIdentity, LoadingState, RestApiLinks, ResourceCapabilitySnapshot, SurfaceDrawerRef, GenericCrudService, AsyncConfigStorage, ComponentDocMeta, AiCapabilityCatalog, AiCapability, AiCapabilityCategory, AiValueKind, ComponentAuthoringManifest, SettingsValueProvider } from '@praxisui/core';
5
5
  export { BackConfig } from '@praxisui/core';
6
6
  import { TableConfigPersistenceStrategy } from '@praxisui/table';
7
7
  import { MatDialogConfig, MatDialogRef, MatDialog } from '@angular/material/dialog';
@@ -48,6 +48,17 @@ declare class DialogService {
48
48
  }
49
49
 
50
50
  type FormOpenMode = 'route' | 'modal' | 'drawer';
51
+ type CrudReactiveDeterminationStabilityStatus = 'pending' | 'settled-satisfied' | 'settled-unsatisfied';
52
+ /** Value-free stability evidence for the Dynamic Form opened by one CRUD action. */
53
+ interface CrudFormReactiveDeterminationStabilityChange {
54
+ status: CrudReactiveDeterminationStabilityStatus;
55
+ pending: boolean;
56
+ unsatisfied: boolean;
57
+ }
58
+ /** Public CRUD output enriched with the action that owns the open form. */
59
+ interface CrudReactiveDeterminationStabilityChange extends CrudFormReactiveDeterminationStabilityChange {
60
+ action: string;
61
+ }
51
62
  interface CrudParamMapping {
52
63
  from: string;
53
64
  to: 'routeParam' | 'query' | 'input';
@@ -192,6 +203,16 @@ declare class PraxisCrudComponent implements OnChanges {
192
203
  afterDelete: EventEmitter<{
193
204
  id: string | number;
194
205
  }>;
206
+ /** Metadata-only Reactive Determination evidence from an open form host. */
207
+ reactiveDeterminationExecuted: EventEmitter<{
208
+ action: string;
209
+ event: ReactiveDeterminationExecutionEvent;
210
+ }>;
211
+ reactiveDeterminationPendingChange: EventEmitter<{
212
+ action: string;
213
+ pending: boolean;
214
+ }>;
215
+ reactiveDeterminationStabilityChange: EventEmitter<CrudReactiveDeterminationStabilityChange>;
195
216
  error: EventEmitter<unknown>;
196
217
  rowClick: EventEmitter<unknown>;
197
218
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
@@ -218,11 +239,13 @@ declare class PraxisCrudComponent implements OnChanges {
218
239
  private readonly snack;
219
240
  private readonly dialog;
220
241
  private readonly i18n;
242
+ private readonly logger;
221
243
  private readonly injector;
222
244
  private resourceDiscoveryInstance?;
223
245
  private actionOpenAdapterInstance?;
224
246
  private surfaceOpenAdapterInstance?;
225
247
  private materializedRefreshSequence;
248
+ private surfaceOpenAttemptSequence;
226
249
  private readonly global;
227
250
  private readonly surfaceService;
228
251
  private readonly surfaceOutlets;
@@ -302,6 +325,7 @@ declare class PraxisCrudComponent implements OnChanges {
302
325
  private resolveDiscoveredSurfaceCatalog;
303
326
  private tryOpenDiscoveredWorkflowAction;
304
327
  private notifySurfaceNavigationFailure;
328
+ private reportDiscoveredSurfaceOpenFailure;
305
329
  private resolveDiscoveredActionCatalog;
306
330
  private selectDiscoveredWorkflowAction;
307
331
  private resolveProvidedWorkflowAction;
@@ -351,7 +375,7 @@ declare class PraxisCrudComponent implements OnChanges {
351
375
  private txWithParams;
352
376
  private interpolateTranslationParams;
353
377
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisCrudComponent, never>;
354
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisCrudComponent, "praxis-crud", never, { "metadata": { "alias": "metadata"; "required": true; }; "crudId": { "alias": "crudId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "tableConfigPersistenceStrategy": { "alias": "tableConfigPersistenceStrategy"; "required": false; }; "context": { "alias": "context"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; }, { "configureRequested": "configureRequested"; "afterOpen": "afterOpen"; "afterClose": "afterClose"; "afterSave": "afterSave"; "afterDelete": "afterDelete"; "error": "error"; "rowClick": "rowClick"; "rowAction": "rowAction"; "selectionChange": "selectionChange"; "tableRuntimeConfigChange": "tableRuntimeConfigChange"; "crudAuthoringDocumentApplied": "crudAuthoringDocumentApplied"; "crudAuthoringDocumentSaved": "crudAuthoringDocumentSaved"; }, never, never, true, never>;
378
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PraxisCrudComponent, "praxis-crud", never, { "metadata": { "alias": "metadata"; "required": true; }; "crudId": { "alias": "crudId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "tableConfigPersistenceStrategy": { "alias": "tableConfigPersistenceStrategy"; "required": false; }; "context": { "alias": "context"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; }, { "configureRequested": "configureRequested"; "afterOpen": "afterOpen"; "afterClose": "afterClose"; "afterSave": "afterSave"; "afterDelete": "afterDelete"; "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "reactiveDeterminationStabilityChange": "reactiveDeterminationStabilityChange"; "error": "error"; "rowClick": "rowClick"; "rowAction": "rowAction"; "selectionChange": "selectionChange"; "tableRuntimeConfigChange": "tableRuntimeConfigChange"; "crudAuthoringDocumentApplied": "crudAuthoringDocumentApplied"; "crudAuthoringDocumentSaved": "crudAuthoringDocumentSaved"; }, never, never, true, never>;
355
379
  }
356
380
 
357
381
  type CrudDrawerResultType = 'save' | 'delete' | 'close';
@@ -359,6 +383,38 @@ interface CrudDrawerResult {
359
383
  type: CrudDrawerResultType;
360
384
  data?: Record<string, unknown>;
361
385
  }
386
+ interface CrudDrawerOpenConfig {
387
+ action: CrudAction;
388
+ metadata: CrudMetadata;
389
+ inputs: Record<string, unknown>;
390
+ /** Read-only record context for existing-record drawers. It is never part of form inputs or submit payloads. */
391
+ resourceIdentity?: MaterializedResourceIdentity | null;
392
+ /** Read-only task scope for related operations. It is never part of form inputs or submit payloads. */
393
+ contextIdentity?: MaterializedResourceIdentity | null;
394
+ /**
395
+ * Ephemeral focus policy resolved for this opening. A host adapter must
396
+ * forward it to its native overlay and must never persist, clone, or put it
397
+ * into form inputs or submit payloads. When a responsive render replaces a
398
+ * detached HTMLElement, an adapter should recover the matching
399
+ * `data-praxis-focus-key` element before focusing it.
400
+ */
401
+ restoreFocus?: boolean | string | HTMLElement;
402
+ /**
403
+ * Notifica fechamento do drawer (cancelamento/fechamento externo/resultado finalizado).
404
+ */
405
+ onClose?: () => void;
406
+ /**
407
+ * Notifica resultado semântico do fluxo em drawer.
408
+ * Hosts podem propagar `save/delete/close` para sincronizar telemetria/eventos.
409
+ */
410
+ onResult?: (result: CrudDrawerResult) => void;
411
+ /** Bind to the child Dynamic Form metadata-only execution event. */
412
+ onReactiveDetermination?: (event: ReactiveDeterminationExecutionEvent) => void;
413
+ /** Bind to the child pending event and guard every adapter-owned close/submit. */
414
+ onReactiveDeterminationPendingChange?: (pending: boolean) => void;
415
+ /** Report aggregate settled-success/settled-unsatisfied state without form values. */
416
+ onReactiveDeterminationStabilityChange?: (stability: CrudFormReactiveDeterminationStabilityChange) => void;
417
+ }
362
418
 
363
419
  interface CrudLaunchRuntime {
364
420
  capabilities?: ResourceCapabilitySnapshot | null;
@@ -383,6 +439,9 @@ declare class CrudLauncherService {
383
439
  launch(action: CrudAction, row: Record<string, unknown> | undefined, metadata: CrudMetadata, componentKeyId?: string | null, drawerCallbacks?: {
384
440
  onClose?: () => void;
385
441
  onResult?: (result: CrudDrawerResult) => void;
442
+ onReactiveDetermination?: CrudDrawerOpenConfig['onReactiveDetermination'];
443
+ onReactiveDeterminationPendingChange?: CrudDrawerOpenConfig['onReactiveDeterminationPendingChange'];
444
+ onReactiveDeterminationStabilityChange?: CrudDrawerOpenConfig['onReactiveDeterminationStabilityChange'];
386
445
  }, runtime?: CrudLaunchRuntime): Promise<{
387
446
  mode: FormOpenMode;
388
447
  ref?: DialogRef<any>;
@@ -428,6 +487,9 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
428
487
  private configStorage;
429
488
  private readonly surfaceRef;
430
489
  formComp?: PraxisDynamicForm;
490
+ reactiveDeterminationExecuted: EventEmitter<ReactiveDeterminationExecutionEvent>;
491
+ reactiveDeterminationPendingChange: EventEmitter<boolean>;
492
+ reactiveDeterminationStabilityChange: EventEmitter<CrudFormReactiveDeterminationStabilityChange>;
431
493
  modal: any;
432
494
  presentation: 'modal' | 'drawer' | 'surface-frame';
433
495
  maximized: boolean;
@@ -439,6 +501,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
439
501
  private terminalClose;
440
502
  private destroyRef;
441
503
  private readonly i18n;
504
+ private reactiveDeterminationStabilitySignature;
442
505
  resourcePath?: string;
443
506
  resourceId?: string | number;
444
507
  initialValue?: Record<string, unknown> | null;
@@ -479,6 +542,10 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
479
542
  ngAfterViewInit(): void;
480
543
  onSave(result: unknown): void;
481
544
  onCancel(): void;
545
+ onReactiveDeterminationExecuted(event: ReactiveDeterminationExecutionEvent): void;
546
+ onReactiveDeterminationPendingChange(pending: boolean): void;
547
+ private emitReactiveDeterminationStability;
548
+ private continueCancel;
482
549
  private canLeaveSurfaceFrame;
483
550
  toggleMaximize(initial?: boolean): void;
484
551
  private resolveOverlayPane;
@@ -488,7 +555,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
488
555
  private updateHostPosition;
489
556
  private resolveMaximizedDrawerPosition;
490
557
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicFormDialogHostComponent, [{ optional: true; }, { optional: true; }, null, null, null, { optional: true; }, { optional: true; }]>;
491
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicFormDialogHostComponent, "praxis-dynamic-form-dialog-host", never, {}, {}, never, never, true, never>;
558
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicFormDialogHostComponent, "praxis-dynamic-form-dialog-host", never, {}, { "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; "reactiveDeterminationStabilityChange": "reactiveDeterminationStabilityChange"; }, never, never, true, never>;
492
559
  }
493
560
 
494
561
  /** Metadata for PraxisCrudComponent */
@@ -770,4 +837,4 @@ type OpenCrudMetadataEditorOptions = {
770
837
  declare function openCrudMetadataEditor(settings: SettingsPanelService, opts?: OpenCrudMetadataEditorOptions): _praxisui_settings_panel.SettingsPanelRef;
771
838
 
772
839
  export { CRUD_AI_CAPABILITIES, CrudLauncherService, CrudMetadataEditorComponent, CrudPageHeaderComponent, DialogService, DynamicFormDialogHostComponent, PRAXIS_CRUD_AUTHORING_MANIFEST, PRAXIS_CRUD_COMPONENT_METADATA, PraxisCrudComponent, PraxisCrudWidgetConfigEditor, assertCrudMetadata, createCrudAuthoringDocument, findCrudAction, normalizeCrudAuthoringDocument, openCrudMetadataEditor, parseLegacyOrCrudDocument, providePraxisCrudMetadata, serializeCrudAuthoringDocument, validateCrudAuthoringDocument };
773
- export type { Capability, CapabilityCatalog, CapabilityCategory, CrudAction, CrudActionFormContract, CrudActionResolutionMode, CrudAuthoringDocument, CrudAuthoringWidgetPersistenceEvent, CrudDefaults, CrudEditorDiagnostic, CrudHeaderConfig, CrudHeaderVariant, CrudMetadata, CrudMetadataAssertionOptions, CrudParamMapping, CrudResource, CrudValidationContext, DialogConfig, DialogRef, FormOpenMode, OpenCrudMetadataEditorOptions, PraxisCrudWidgetEditorInputs, PraxisCrudWidgetEditorValue, ValueKind };
840
+ export type { Capability, CapabilityCatalog, CapabilityCategory, CrudAction, CrudActionFormContract, CrudActionResolutionMode, CrudAuthoringDocument, CrudAuthoringWidgetPersistenceEvent, CrudDefaults, CrudEditorDiagnostic, CrudFormReactiveDeterminationStabilityChange, CrudHeaderConfig, CrudHeaderVariant, CrudMetadata, CrudMetadataAssertionOptions, CrudParamMapping, CrudReactiveDeterminationStabilityChange, CrudReactiveDeterminationStabilityStatus, CrudResource, CrudValidationContext, DialogConfig, DialogRef, FormOpenMode, OpenCrudMetadataEditorOptions, PraxisCrudWidgetEditorInputs, PraxisCrudWidgetEditorValue, ValueKind };