@praxisui/dynamic-form 0.0.1
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/LICENSE +7 -0
- package/README.md +166 -0
- package/fesm2022/praxisui-dynamic-form.mjs +11135 -0
- package/fesm2022/praxisui-dynamic-form.mjs.map +1 -0
- package/index.d.ts +1104 -0
- package/package.json +43 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# @praxisui/dynamic-form
|
|
2
|
+
|
|
3
|
+
> Standalone dynamic form component with schema-driven UI, native field cascades, settings integration, and a built-in configuration editor.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @praxisui/dynamic-form
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Peer dependencies (Angular v20):
|
|
12
|
+
- `@angular/core` `^20.0.0`
|
|
13
|
+
- `@angular/common` `^20.0.0`
|
|
14
|
+
- `@angular/cdk` `^20.0.0`
|
|
15
|
+
- `@praxisui/core` `^0.0.1`
|
|
16
|
+
- `@praxisui/specification-core` `^0.0.1`
|
|
17
|
+
- `@praxisui/specification` `^0.0.1`
|
|
18
|
+
- `@praxisui/visual-builder` `^0.0.1`
|
|
19
|
+
- `@praxisui/settings-panel` `^0.0.1`
|
|
20
|
+
- `@praxisui/cron-builder` `^0.0.1`
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1) PraxisDynamicForm (standalone)
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { Component } from '@angular/core';
|
|
28
|
+
import { PraxisDynamicForm } from '@praxisui/dynamic-form';
|
|
29
|
+
import type { FormConfig } from '@praxisui/core';
|
|
30
|
+
|
|
31
|
+
@Component({
|
|
32
|
+
selector: 'app-form-demo',
|
|
33
|
+
standalone: true,
|
|
34
|
+
imports: [PraxisDynamicForm],
|
|
35
|
+
template: `
|
|
36
|
+
<praxis-dynamic-form
|
|
37
|
+
[config]="config"
|
|
38
|
+
[mode]="'create'"
|
|
39
|
+
[editModeEnabled]="true"
|
|
40
|
+
(formSubmit)="onSubmit($event)"
|
|
41
|
+
></praxis-dynamic-form>
|
|
42
|
+
`,
|
|
43
|
+
})
|
|
44
|
+
export class FormDemoComponent {
|
|
45
|
+
config: FormConfig = {
|
|
46
|
+
sections: [
|
|
47
|
+
{
|
|
48
|
+
id: 'main',
|
|
49
|
+
label: 'Employee',
|
|
50
|
+
rows: [
|
|
51
|
+
{
|
|
52
|
+
columns: [
|
|
53
|
+
{ fields: [{ name: 'fullName', label: 'Full Name', controlType: 'text' }] },
|
|
54
|
+
{ fields: [{ name: 'email', label: 'E-mail', controlType: 'email' }] },
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
} as any;
|
|
61
|
+
|
|
62
|
+
onSubmit(evt: any) {
|
|
63
|
+
console.log('Submitted:', evt);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Tip: connect to a backend resource by setting `resourcePath`/`resourceId`. The component can fetch schemas and reconcile local layout with server metadata when `editModeEnabled` is true.
|
|
69
|
+
|
|
70
|
+
### 2) Config Editor component
|
|
71
|
+
|
|
72
|
+
Use the standalone editor directly to edit and reconcile the form configuration.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { Component } from '@angular/core';
|
|
76
|
+
import { MatDialog } from '@angular/material/dialog';
|
|
77
|
+
import { PraxisDynamicFormConfigEditor } from '@praxisui/dynamic-form';
|
|
78
|
+
import type { FormConfig } from '@praxisui/core';
|
|
79
|
+
|
|
80
|
+
@Component({
|
|
81
|
+
selector: 'app-form-editor-launcher',
|
|
82
|
+
standalone: true,
|
|
83
|
+
template: `<button (click)="openEditor()">Open Config Editor</button>`,
|
|
84
|
+
})
|
|
85
|
+
export class FormEditorLauncherComponent {
|
|
86
|
+
constructor(private dialog: MatDialog) {}
|
|
87
|
+
|
|
88
|
+
openEditor() {
|
|
89
|
+
const initial: FormConfig = { sections: [] } as any;
|
|
90
|
+
this.dialog.open(PraxisDynamicFormConfigEditor, {
|
|
91
|
+
width: '1024px',
|
|
92
|
+
data: { formConfig: initial, formId: 'employees-form', mode: 'edit' },
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Alternatively, when `editModeEnabled` is true, `praxis-dynamic-form` renders a gear button that opens the editor internally.
|
|
99
|
+
|
|
100
|
+
## API Surface
|
|
101
|
+
|
|
102
|
+
- Components: `PraxisDynamicForm`, `PraxisDynamicFormConfigEditor`, `JsonConfigEditorComponent`, `LayoutEditorComponent`
|
|
103
|
+
- Services: `FormConfigService`, `FormLayoutService`, `DynamicFormLayoutService`, `FormContextService`
|
|
104
|
+
- Utilities: form rule converters, normalize date arrays
|
|
105
|
+
- Metadata helpers: `providePraxisDynamicFormMetadata`
|
|
106
|
+
|
|
107
|
+
See public exports: `projects/praxis-dynamic-form/src/public-api.ts`.
|
|
108
|
+
|
|
109
|
+
## Compatibility
|
|
110
|
+
|
|
111
|
+
- `@praxisui/dynamic-form` `0.0.x` → Angular `20.x`
|
|
112
|
+
- Module format: `ESM2022`
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
Apache-2.0 – see the `LICENSE` packaged with this library or the repository root.
|
|
117
|
+
|
|
118
|
+
# Praxis Dynamic Form — Cascata vs Connections
|
|
119
|
+
|
|
120
|
+
### Concept Usage
|
|
121
|
+
|
|
122
|
+
- [Data Driven Forms](../../../../docs/concepts/data-driven-forms.md)
|
|
123
|
+
- [Declarative UI](../../../../docs/concepts/declarative-ui.md)
|
|
124
|
+
- [Schema‑driven UI](../../../../docs/concepts/schema-driven-ui.md)
|
|
125
|
+
|
|
126
|
+
## Quando usar cada mecanismo
|
|
127
|
+
|
|
128
|
+
- Connections (dot‑path)
|
|
129
|
+
- Para orquestração “externa” (entre widgets, tabs, tabelas ou fora do formulário).
|
|
130
|
+
- Escrevem em `inputs.config.*` do widget do formulário, inclusive metadados de campos (ex.: `inputs.config.fieldMetadata[i].filterCriteria`).
|
|
131
|
+
- Escala bem para cenários de página e integração cross‑widget.
|
|
132
|
+
|
|
133
|
+
- Cascata nativa (campo→campo, intra‑form)
|
|
134
|
+
- Declarativa via metadata (`dependencyFields`, `resetOnDependentChange`, etc.).
|
|
135
|
+
- Observa `FormControl.valueChanges` dos campos dependentes, aplica `filterCriteria` e recarrega conforme estratégia (`loadOn`, `dependencyLoadOnChange`).
|
|
136
|
+
- Elimina código ad hoc na página.
|
|
137
|
+
|
|
138
|
+
## Convivência e fonte de verdade
|
|
139
|
+
|
|
140
|
+
- Se Connections atualizam `filterCriteria` de um campo, considere desativar a cascata nativa nesse campo (`enableDependencyCascade: false`) ou usar `dependencyLoadOnChange: 'manual'` (cascata só atualiza filtros e Connections disparam o load).
|
|
141
|
+
- Estratégia de merge recomendada: `dependencyMergeStrategy: 'merge'` para preservar chaves vindas de Connections.
|
|
142
|
+
|
|
143
|
+
## Links úteis
|
|
144
|
+
|
|
145
|
+
- Fluxo de Schema (ETag/304, schemaId, reconciliação): `docs/schemas/fluxo-schema.md`
|
|
146
|
+
- Guia de implementação e metadados da cascata: `docs/CASCADE-NATIVA.md`
|
|
147
|
+
- Padrões de endpoints (Options vs Filter) para selects: `docs/DEVS-GENERIC-CRUD-SERVICE.md`
|
|
148
|
+
|
|
149
|
+
## Verificação de Schema (ETag/If-None-Match)
|
|
150
|
+
|
|
151
|
+
- Inputs (opcionais; ativos apenas com `editModeEnabled=true`):
|
|
152
|
+
- `notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'`
|
|
153
|
+
- `snoozeMs: number = 86400000`
|
|
154
|
+
- `autoOpenSettingsOnOutdated: boolean = false`
|
|
155
|
+
- Output:
|
|
156
|
+
- `schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string }`
|
|
157
|
+
- Persistência (ConfigStorage):
|
|
158
|
+
- `form-schema-meta:{formId}` → `{ serverHash?: string; lastVerifiedAt?: string }`
|
|
159
|
+
- `form-schema-prefs:{formId}` → `{ notifyIfOutdated?, snoozeMs?, autoOpenSettingsOnOutdated? }`
|
|
160
|
+
- Por hash (suppress): `schemaIgnore:{formId}:{hash}`, `schemaSnooze:{formId}:{hash}`, `schemaNotified:{formId}:{hash}`
|
|
161
|
+
- Comportamento:
|
|
162
|
+
- Quando já existe base local (ex.: `config.sections.length > 0`), o componente faz uma verificação leve via `/schemas/filtered` com `If-None-Match`.
|
|
163
|
+
- 304 → apenas atualiza `lastVerifiedAt` e emite `schemaStatusChange(outdated=false)`.
|
|
164
|
+
- 200 → atualiza `serverHash/lastVerifiedAt`, define `schemaOutdated = editModeEnabled && hadBase`, emite `schemaStatusChange`. Não aplica schema automaticamente.
|
|
165
|
+
- Primeira vez (sem base): baixa o corpo do schema para gerar o layout; persiste `form-schema-meta:{formId}`.
|
|
166
|
+
- Notificações respeitam preferências e são one‑shot por hash; o banner/snackbar oferecem ações para Reconciliar, Lembrar depois (snooze) e Ignorar.
|