@praxisui/dynamic-form 9.0.68-rc.2 → 10.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-09-10T01:25:13.157Z",
3
+ "generatedAt": "2026-09-10T12:25:16.581Z",
4
4
  "packageName": "@praxisui/dynamic-form",
5
- "packageVersion": "9.0.68-rc.2",
5
+ "packageVersion": "10.0.0-rc.0",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -4,7 +4,7 @@ doc_type: "adr"
4
4
  component: "praxis-dynamic-form"
5
5
  status: "accepted"
6
6
  owner: "praxis-ui"
7
- last_updated: "2026-08-19"
7
+ last_updated: "2026-09-10"
8
8
  ---
9
9
 
10
10
  # Dynamic Form Authoring Document Semantics
@@ -50,6 +50,12 @@ Patches vindos de `@praxisui/metadata-editor` para `fieldMetadata` seguem semant
50
50
 
51
51
  Para `entityLookup`, o bloco `fieldMetadata[].optionSource` e aninhado e deve ser mesclado em profundidade. O dynamic-form deve preservar campos existentes, como `key`, `resourcePath`, `valuePropertyPath` e `capabilities.byIds`, quando o editor alterar apenas partes do contrato, como `dependsOn`, `selectionPolicy`, `detail` ou `capabilities.auditSnapshot`.
52
52
 
53
+ No Layout Editor, cada evento aceito é um delta cumulativo relativo ao campo na
54
+ abertura. A aplicação usa esse baseline imutável: A → B → Aplicar → A → Concluir
55
+ restaura A mesmo quando o delta final está vazio. Alterações em outros campos do
56
+ rascunho pai são preservadas. Arrays são substituídos e `null` remove somente a
57
+ propriedade endereçada; a identidade `name` permanece estável.
58
+
53
59
  Essa regra evita perda silenciosa do contrato canonico de Entity Lookup durante o fluxo: abrir editor -> aplicar/salvar -> reabrir editor -> runtime consumir.
54
60
 
55
61
  ## Consequences
@@ -24140,6 +24140,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
24140
24140
  `, styles: [".destination-fields{display:grid;gap:var(--px-editor-section-gap, 1rem)}mat-form-field{width:100%;min-width:0}.destination-option{display:grid;white-space:normal;overflow-wrap:anywhere}.destination-summary{color:var(--mat-sys-on-surface-variant, var(--md-sys-color-on-surface-variant));font-size:var(--mat-sys-body-small-size, .75rem);line-height:var(--mat-sys-body-small-line-height, 1rem)}mat-hint{overflow-wrap:anywhere}\n"] }]
24141
24141
  }] });
24142
24142
 
24143
+ const unsafeKeys = new Set(['__proto__', 'prototype', 'constructor']);
24144
+ function isRecord$1(value) {
24145
+ if (!value || typeof value !== 'object' || Array.isArray(value))
24146
+ return false;
24147
+ const prototype = Object.getPrototypeOf(value);
24148
+ return prototype === Object.prototype || prototype === null;
24149
+ }
24150
+ function cloneValue(value) {
24151
+ if (Array.isArray(value))
24152
+ return value.map(cloneValue);
24153
+ if (!isRecord$1(value))
24154
+ return value;
24155
+ return Object.fromEntries(Object.entries(value)
24156
+ .filter(([key]) => !unsafeKeys.has(key))
24157
+ .map(([key, entry]) => [key, cloneValue(entry)]));
24158
+ }
24159
+ /** Materializes the metadata editor's recursive delta without mutating its baseline. */
24160
+ function mergeFieldMetadataPatch(base, patch) {
24161
+ if (!isRecord$1(patch)) {
24162
+ return cloneValue(patch);
24163
+ }
24164
+ const result = {};
24165
+ if (isRecord$1(base)) {
24166
+ for (const [key, value] of Object.entries(base)) {
24167
+ if (!unsafeKeys.has(key))
24168
+ result[key] = cloneValue(value);
24169
+ }
24170
+ }
24171
+ for (const [key, value] of Object.entries(patch)) {
24172
+ if (unsafeKeys.has(key))
24173
+ continue;
24174
+ if (value === null)
24175
+ delete result[key];
24176
+ else
24177
+ result[key] = mergeFieldMetadataPatch(result[key], value);
24178
+ }
24179
+ return result;
24180
+ }
24181
+
24143
24182
  /**
24144
24183
  * Editor component for configuring sections, rows and fields of a dynamic form.
24145
24184
  * Provides a collapsible palette of available fields.
@@ -24592,10 +24631,12 @@ class LayoutEditorComponent {
24592
24631
  }
24593
24632
  openFieldMetadataEditorInternal(editorComponent, field) {
24594
24633
  const fieldName = field.name;
24634
+ // Each emitted delta is cumulative relative to the field opened in the child.
24635
+ const baseline = mergeFieldMetadataPatch(field, {});
24595
24636
  const handlePatch = (patch) => {
24596
24637
  if (!patch)
24597
24638
  return;
24598
- this.applyFieldMetadataPatch(fieldName, patch);
24639
+ this.applyFieldMetadataPatch(fieldName, patch, baseline);
24599
24640
  };
24600
24641
  const title = this.t('field.editMetadataTitle', { field: field.label || field.name });
24601
24642
  const ref = this.settingsPanel.openChild({
@@ -24614,13 +24655,12 @@ class LayoutEditorComponent {
24614
24655
  ref?.applied$?.subscribe(handlePatch);
24615
24656
  ref?.saved$?.subscribe(handlePatch);
24616
24657
  }
24617
- applyFieldMetadataPatch(fieldName, patch) {
24658
+ applyFieldMetadataPatch(fieldName, patch, baseline) {
24618
24659
  const fieldMetadata = (this.config.fieldMetadata || []).map((field) => {
24619
24660
  if (field.name !== fieldName)
24620
24661
  return field;
24621
24662
  return {
24622
- ...field,
24623
- ...patch,
24663
+ ...mergeFieldMetadataPatch(baseline ?? field, patch),
24624
24664
  name: field.name,
24625
24665
  };
24626
24666
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-form",
3
- "version": "9.0.68-rc.2",
3
+ "version": "10.0.0-rc.0",
4
4
  "description": "Angular dynamic form engine for Praxis UI: metadata-driven forms, hooks, and services integrating @praxisui/* packages.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
@@ -9,13 +9,13 @@
9
9
  "@angular/forms": "^21.0.0",
10
10
  "@angular/material": "^21.0.0",
11
11
  "@angular/router": "^21.0.0",
12
- "@praxisui/ai": "^9.0.68-rc.2",
13
- "@praxisui/dynamic-fields": "^9.0.68-rc.2",
14
- "@praxisui/metadata-editor": "^9.0.68-rc.2",
15
- "@praxisui/rich-content": "^9.0.68-rc.2",
16
- "@praxisui/settings-panel": "^9.0.68-rc.2",
17
- "@praxisui/visual-builder": "^9.0.68-rc.2",
18
- "@praxisui/core": "^9.0.68-rc.2",
12
+ "@praxisui/ai": "^10.0.0-rc.0",
13
+ "@praxisui/dynamic-fields": "^10.0.0-rc.0",
14
+ "@praxisui/metadata-editor": "^10.0.0-rc.0",
15
+ "@praxisui/rich-content": "^10.0.0-rc.0",
16
+ "@praxisui/settings-panel": "^10.0.0-rc.0",
17
+ "@praxisui/visual-builder": "^10.0.0-rc.0",
18
+ "@praxisui/core": "^10.0.0-rc.0",
19
19
  "rxjs": "^7.8.0"
20
20
  },
21
21
  "dependencies": {