@praxisui/crud 9.0.5-rc.13 → 9.0.5-rc.15

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,7 +102,7 @@ It emits:
102
102
 
103
103
  - `configureRequested`
104
104
  - `afterOpen`, `afterClose`, `afterSave`, `afterDelete`
105
- - `reactiveDeterminationExecuted` (metadata-only evidence with action context) and `reactiveDeterminationPendingChange`
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.
106
106
  - `error`
107
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.
108
108
  - `tableRuntimeConfigChange`
@@ -110,7 +110,7 @@ It emits:
110
110
 
111
111
  The component keeps `crudContext` stable for change detection and refreshes the table after successful save/delete flows.
112
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; cancel waits for bounded stabilization and stays open on timeout. A custom `CrudDrawerAdapter` must bind `onReactiveDetermination` and `onReactiveDeterminationPendingChange`, use the child Dynamic Form stability API, and refuse every adapter-owned close/submit while pending. These callbacks are runtime-only and must never be persisted in CRUD metadata.
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
114
 
115
115
  ## Metadata Boundaries
116
116
 
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-08-13T17:03:40.689Z",
3
+ "generatedAt": "2026-08-14T00:04:43.614Z",
4
4
  "packageName": "@praxisui/crud",
5
- "packageVersion": "9.0.5-rc.13",
5
+ "packageVersion": "9.0.5-rc.15",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -136,6 +136,12 @@
136
136
  "required": false,
137
137
  "description": "Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis."
138
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
+ },
139
145
  {
140
146
  "name": "rowClick",
141
147
  "type": "{ row: unknown; index: number }",
@@ -7236,9 +7242,9 @@
7236
7242
  {
7237
7243
  "chunkIndex": 0,
7238
7244
  "chunkKind": "summary",
7239
- "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 - 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",
7240
7246
  "sourcePointer": "projects/praxis-crud/src/lib/praxis-crud.metadata.ts",
7241
- "contentHash": "78a90bf2630d8c008dd8b162852e6a323bbf624d53295cf926c824cb34afa149",
7247
+ "contentHash": "3d654a50a00fa942aaaf216c39a6fa4e5eb711ff24b6d7b778aa4f48d0ea2d63",
7242
7248
  "sourceKind": "component_definition",
7243
7249
  "sourceId": "praxis-crud",
7244
7250
  "corpusVersion": "1.0.0"
@@ -196,6 +196,7 @@ class CrudLauncherService {
196
196
  reactiveDeterminationCallbacks: {
197
197
  onEvent: drawerCallbacks?.onReactiveDetermination,
198
198
  onPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
199
+ onStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
199
200
  },
200
201
  };
201
202
  const modalCfg = { ...(merged.metadata.defaults?.modal || {}) };
@@ -249,6 +250,7 @@ class CrudLauncherService {
249
250
  onResult: drawerCallbacks?.onResult,
250
251
  onReactiveDetermination: drawerCallbacks?.onReactiveDetermination,
251
252
  onReactiveDeterminationPendingChange: drawerCallbacks?.onReactiveDeterminationPendingChange,
253
+ onReactiveDeterminationStabilityChange: drawerCallbacks?.onReactiveDeterminationStabilityChange,
252
254
  }));
253
255
  return { mode };
254
256
  }
@@ -3817,6 +3819,7 @@ class PraxisCrudComponent {
3817
3819
  /** Metadata-only Reactive Determination evidence from an open form host. */
3818
3820
  reactiveDeterminationExecuted = new EventEmitter();
3819
3821
  reactiveDeterminationPendingChange = new EventEmitter();
3822
+ reactiveDeterminationStabilityChange = new EventEmitter();
3820
3823
  error = new EventEmitter();
3821
3824
  rowClick = new EventEmitter();
3822
3825
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
@@ -4070,6 +4073,10 @@ class PraxisCrudComponent {
4070
4073
  action: effectiveAction.action,
4071
4074
  pending,
4072
4075
  }),
4076
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4077
+ action: effectiveAction.action,
4078
+ ...stability,
4079
+ }),
4073
4080
  }, {
4074
4081
  capabilities: effectiveAction.action === 'create'
4075
4082
  ? this.collectionCapabilities
@@ -4345,6 +4352,10 @@ class PraxisCrudComponent {
4345
4352
  onResult: (result) => handleResult(result),
4346
4353
  onReactiveDetermination: (event) => this.reactiveDeterminationExecuted.emit({ action: normalizedAction, event }),
4347
4354
  onReactiveDeterminationPendingChange: (pending) => this.reactiveDeterminationPendingChange.emit({ action: normalizedAction, pending }),
4355
+ onReactiveDeterminationStabilityChange: (stability) => this.reactiveDeterminationStabilityChange.emit({
4356
+ action: normalizedAction,
4357
+ ...stability,
4358
+ }),
4348
4359
  }, {
4349
4360
  capabilities: this.collectionCapabilities,
4350
4361
  links: this.tableCollectionLinks,
@@ -5516,7 +5527,7 @@ class PraxisCrudComponent {
5516
5527
  return Object.entries(params).reduce((current, [name, value]) => current.split(`{${name}}`).join(value), text);
5517
5528
  }
5518
5529
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisCrudComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5519
- 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", 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: [
5520
5531
  providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
5521
5532
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
5522
5533
  ], viewQueries: [{ propertyName: "table", first: true, predicate: PraxisTable, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
@@ -5639,6 +5650,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
5639
5650
  type: Output
5640
5651
  }], reactiveDeterminationPendingChange: [{
5641
5652
  type: Output
5653
+ }], reactiveDeterminationStabilityChange: [{
5654
+ type: Output
5642
5655
  }], error: [{
5643
5656
  type: Output
5644
5657
  }], rowClick: [{
@@ -5688,6 +5701,7 @@ class DynamicFormDialogHostComponent {
5688
5701
  formComp;
5689
5702
  reactiveDeterminationExecuted = new EventEmitter();
5690
5703
  reactiveDeterminationPendingChange = new EventEmitter();
5704
+ reactiveDeterminationStabilityChange = new EventEmitter();
5691
5705
  modal = {};
5692
5706
  presentation = 'modal';
5693
5707
  maximized = false;
@@ -5699,6 +5713,7 @@ class DynamicFormDialogHostComponent {
5699
5713
  terminalClose = false;
5700
5714
  destroyRef = inject(DestroyRef);
5701
5715
  i18n = inject(PraxisI18nService);
5716
+ reactiveDeterminationStabilitySignature = '';
5702
5717
  resourcePath;
5703
5718
  resourceId;
5704
5719
  initialValue;
@@ -6022,7 +6037,8 @@ class DynamicFormDialogHostComponent {
6022
6037
  if (stage === 'before' || stage === 'error') {
6023
6038
  return;
6024
6039
  }
6025
- if (this.formComp?.hasPendingReactiveDeterminations?.())
6040
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6041
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.())
6026
6042
  return;
6027
6043
  if (this.modal.closeOnSave === false) {
6028
6044
  this.saveState();
@@ -6039,7 +6055,8 @@ class DynamicFormDialogHostComponent {
6039
6055
  }
6040
6056
  }
6041
6057
  onCancel() {
6042
- if (this.formComp?.hasPendingReactiveDeterminations?.()) {
6058
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6059
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6043
6060
  void this.formComp.waitForReactiveDeterminations().then((stable) => {
6044
6061
  if (stable)
6045
6062
  this.continueCancel();
@@ -6051,10 +6068,32 @@ class DynamicFormDialogHostComponent {
6051
6068
  onReactiveDeterminationExecuted(event) {
6052
6069
  this.reactiveDeterminationExecuted.emit(event);
6053
6070
  this.data.reactiveDeterminationCallbacks?.onEvent?.(event);
6071
+ this.emitReactiveDeterminationStability();
6054
6072
  }
6055
6073
  onReactiveDeterminationPendingChange(pending) {
6056
6074
  this.reactiveDeterminationPendingChange.emit(pending);
6057
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);
6058
6097
  }
6059
6098
  continueCancel() {
6060
6099
  if (this.surfaceRef) {
@@ -6093,7 +6132,8 @@ class DynamicFormDialogHostComponent {
6093
6132
  }
6094
6133
  }
6095
6134
  async canLeaveSurfaceFrame() {
6096
- if (this.formComp?.hasPendingReactiveDeterminations?.()) {
6135
+ if (this.formComp?.hasPendingReactiveDeterminations?.()
6136
+ || this.formComp?.hasUnsatisfiedReactiveDeterminations?.()) {
6097
6137
  const stable = await this.formComp.waitForReactiveDeterminations();
6098
6138
  if (!stable)
6099
6139
  return false;
@@ -6237,7 +6277,7 @@ class DynamicFormDialogHostComponent {
6237
6277
  return { ...horizontal, ...vertical };
6238
6278
  }
6239
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 });
6240
- 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" }, 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: [
6241
6281
  GenericCrudService,
6242
6282
  providePraxisI18nConfig(PRAXIS_CRUD_RUNTIME_I18N_CONFIG),
6243
6283
  ], viewQueries: [{ propertyName: "formComp", first: true, predicate: PraxisDynamicForm, descendants: true }], ngImport: i0, template: `
@@ -6491,6 +6531,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
6491
6531
  type: Output
6492
6532
  }], reactiveDeterminationPendingChange: [{
6493
6533
  type: Output
6534
+ }], reactiveDeterminationStabilityChange: [{
6535
+ type: Output
6494
6536
  }] } });
6495
6537
  function getFormSubmitStage(result) {
6496
6538
  if (!result || typeof result !== 'object' || !('stage' in result)) {
@@ -6807,6 +6849,11 @@ const PRAXIS_CRUD_COMPONENT_METADATA = {
6807
6849
  type: '{ action: string; pending: boolean }',
6808
6850
  description: 'Estado agregado de estabilizacao do formulario aberto, sem valores sensiveis.',
6809
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
+ },
6810
6857
  {
6811
6858
  name: 'rowClick',
6812
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.13",
3
+ "version": "9.0.5-rc.15",
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.13",
9
- "@praxisui/table": "^9.0.5-rc.13",
10
- "@praxisui/core": "^9.0.5-rc.13",
11
- "@praxisui/dynamic-fields": "^9.0.5-rc.13",
12
- "@praxisui/settings-panel": "^9.0.5-rc.13",
8
+ "@praxisui/dynamic-form": "^9.0.5-rc.15",
9
+ "@praxisui/table": "^9.0.5-rc.15",
10
+ "@praxisui/core": "^9.0.5-rc.15",
11
+ "@praxisui/dynamic-fields": "^9.0.5-rc.15",
12
+ "@praxisui/settings-panel": "^9.0.5-rc.15",
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.13",
17
+ "@praxisui/ai": "^9.0.5-rc.15",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -68,6 +68,12 @@ interface CrudReactiveDeterminationExecutionEvent {
68
68
  version?: string;
69
69
  };
70
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
+ }
71
77
  interface CrudDrawerOpenConfig {
72
78
  action: CrudAction;
73
79
  metadata: CrudMetadata;
@@ -89,6 +95,8 @@ interface CrudDrawerOpenConfig {
89
95
  onReactiveDetermination?: (event: CrudReactiveDeterminationExecutionEvent) => void;
90
96
  /** Bind to pending state and refuse every adapter-owned close/submit while true. */
91
97
  onReactiveDeterminationPendingChange?: (pending: boolean) => void;
98
+ /** Report aggregate success/unsatisfied stability without form values. */
99
+ onReactiveDeterminationStabilityChange?: (stability: CrudReactiveDeterminationStabilityChange) => void;
92
100
  }
93
101
  interface CrudDrawerAdapter {
94
102
  open(config: CrudDrawerOpenConfig): Promise<void> | void;
@@ -105,4 +113,4 @@ interface DialogConfig<D = any> extends MatDialogConfig<D> {
105
113
  declare const CRUD_DRAWER_ADAPTER: InjectionToken<CrudDrawerAdapter>;
106
114
 
107
115
  export { CRUD_DRAWER_ADAPTER };
108
- export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudReactiveDeterminationExecutionEvent, CrudResource, DialogConfig, FormOpenMode };
116
+ export type { CrudAction, CrudDefaults, CrudDrawerAdapter, CrudDrawerOpenConfig, CrudDrawerResult, CrudDrawerResultType, CrudHeaderConfig, CrudMetadata, CrudParamMapping, CrudReactiveDeterminationExecutionEvent, CrudReactiveDeterminationStabilityChange, CrudResource, DialogConfig, FormOpenMode };
@@ -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';
@@ -201,6 +212,7 @@ declare class PraxisCrudComponent implements OnChanges {
201
212
  action: string;
202
213
  pending: boolean;
203
214
  }>;
215
+ reactiveDeterminationStabilityChange: EventEmitter<CrudReactiveDeterminationStabilityChange>;
204
216
  error: EventEmitter<unknown>;
205
217
  rowClick: EventEmitter<unknown>;
206
218
  /** Emits the canonical table row-action envelope before the CRUD handles its surface/action. */
@@ -363,7 +375,7 @@ declare class PraxisCrudComponent implements OnChanges {
363
375
  private txWithParams;
364
376
  private interpolateTranslationParams;
365
377
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<PraxisCrudComponent, never>;
366
- 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"; "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>;
367
379
  }
368
380
 
369
381
  type CrudDrawerResultType = 'save' | 'delete' | 'close';
@@ -400,6 +412,8 @@ interface CrudDrawerOpenConfig {
400
412
  onReactiveDetermination?: (event: ReactiveDeterminationExecutionEvent) => void;
401
413
  /** Bind to the child pending event and guard every adapter-owned close/submit. */
402
414
  onReactiveDeterminationPendingChange?: (pending: boolean) => void;
415
+ /** Report aggregate settled-success/settled-unsatisfied state without form values. */
416
+ onReactiveDeterminationStabilityChange?: (stability: CrudFormReactiveDeterminationStabilityChange) => void;
403
417
  }
404
418
 
405
419
  interface CrudLaunchRuntime {
@@ -427,6 +441,7 @@ declare class CrudLauncherService {
427
441
  onResult?: (result: CrudDrawerResult) => void;
428
442
  onReactiveDetermination?: CrudDrawerOpenConfig['onReactiveDetermination'];
429
443
  onReactiveDeterminationPendingChange?: CrudDrawerOpenConfig['onReactiveDeterminationPendingChange'];
444
+ onReactiveDeterminationStabilityChange?: CrudDrawerOpenConfig['onReactiveDeterminationStabilityChange'];
430
445
  }, runtime?: CrudLaunchRuntime): Promise<{
431
446
  mode: FormOpenMode;
432
447
  ref?: DialogRef<any>;
@@ -474,6 +489,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
474
489
  formComp?: PraxisDynamicForm;
475
490
  reactiveDeterminationExecuted: EventEmitter<ReactiveDeterminationExecutionEvent>;
476
491
  reactiveDeterminationPendingChange: EventEmitter<boolean>;
492
+ reactiveDeterminationStabilityChange: EventEmitter<CrudFormReactiveDeterminationStabilityChange>;
477
493
  modal: any;
478
494
  presentation: 'modal' | 'drawer' | 'surface-frame';
479
495
  maximized: boolean;
@@ -485,6 +501,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
485
501
  private terminalClose;
486
502
  private destroyRef;
487
503
  private readonly i18n;
504
+ private reactiveDeterminationStabilitySignature;
488
505
  resourcePath?: string;
489
506
  resourceId?: string | number;
490
507
  initialValue?: Record<string, unknown> | null;
@@ -527,6 +544,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
527
544
  onCancel(): void;
528
545
  onReactiveDeterminationExecuted(event: ReactiveDeterminationExecutionEvent): void;
529
546
  onReactiveDeterminationPendingChange(pending: boolean): void;
547
+ private emitReactiveDeterminationStability;
530
548
  private continueCancel;
531
549
  private canLeaveSurfaceFrame;
532
550
  toggleMaximize(initial?: boolean): void;
@@ -537,7 +555,7 @@ declare class DynamicFormDialogHostComponent implements OnInit, AfterViewInit {
537
555
  private updateHostPosition;
538
556
  private resolveMaximizedDrawerPosition;
539
557
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicFormDialogHostComponent, [{ optional: true; }, { optional: true; }, null, null, null, { optional: true; }, { optional: true; }]>;
540
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicFormDialogHostComponent, "praxis-dynamic-form-dialog-host", never, {}, { "reactiveDeterminationExecuted": "reactiveDeterminationExecuted"; "reactiveDeterminationPendingChange": "reactiveDeterminationPendingChange"; }, 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>;
541
559
  }
542
560
 
543
561
  /** Metadata for PraxisCrudComponent */
@@ -819,4 +837,4 @@ type OpenCrudMetadataEditorOptions = {
819
837
  declare function openCrudMetadataEditor(settings: SettingsPanelService, opts?: OpenCrudMetadataEditorOptions): _praxisui_settings_panel.SettingsPanelRef;
820
838
 
821
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 };
822
- 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 };