@praxisui/manual-form 1.0.0-beta.7 → 2.0.0-beta.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.
- package/README.md +201 -24
- package/fesm2022/praxisui-manual-form.mjs +3672 -218
- package/fesm2022/praxisui-manual-form.mjs.map +1 -1
- package/index.d.ts +242 -17
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Manual Form"
|
|
3
|
+
slug: "manual-form-overview"
|
|
4
|
+
description: "Visao geral do @praxisui/manual-form com formularios declarativos, autodeteccao de campos, autosave, persistencia e hot update de metadata."
|
|
5
|
+
doc_type: "reference"
|
|
6
|
+
document_kind: "component-overview"
|
|
7
|
+
component: "manual-form"
|
|
8
|
+
category: "components"
|
|
9
|
+
audience:
|
|
10
|
+
- "frontend"
|
|
11
|
+
- "host"
|
|
12
|
+
- "architect"
|
|
13
|
+
level: "intermediate"
|
|
14
|
+
status: "active"
|
|
15
|
+
owner: "praxis-ui"
|
|
16
|
+
tags:
|
|
17
|
+
- "manual-form"
|
|
18
|
+
- "forms"
|
|
19
|
+
- "autosave"
|
|
20
|
+
- "metadata-editor"
|
|
21
|
+
- "dynamic-fields"
|
|
22
|
+
order: 38
|
|
23
|
+
icon: "file-pen"
|
|
24
|
+
toc: true
|
|
25
|
+
sidebar: true
|
|
26
|
+
search_boost: 0.95
|
|
27
|
+
reading_time: 14
|
|
28
|
+
estimated_setup_time: 20
|
|
29
|
+
version: "1.0"
|
|
30
|
+
related_docs:
|
|
31
|
+
- "manual-form-api-reference"
|
|
32
|
+
- "host-manual-form-integration"
|
|
33
|
+
- "manual-form-toolbar-execution"
|
|
34
|
+
- "consumer-integration-quickstart"
|
|
35
|
+
- "host-integration-guide"
|
|
36
|
+
keywords:
|
|
37
|
+
- "praxis manual form"
|
|
38
|
+
- "manual form toolkit"
|
|
39
|
+
- "form autosave"
|
|
40
|
+
- "field metadata bridge"
|
|
41
|
+
last_updated: "2026-03-07"
|
|
42
|
+
---
|
|
43
|
+
|
|
1
44
|
# Manual Form Toolkit
|
|
2
45
|
|
|
46
|
+
Biblioteca voltada a formularios declarativos baseados em componentes `pdx-*`, com suporte a persistencia, autodeteccao de campos e ponte com editores de metadata.
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
- Documentação oficial: https://praxisui.dev
|
|
51
|
+
- Aplicação de referência: https://github.com/codexrodrigues/praxis-ui-quickstart
|
|
52
|
+
- Indicado para: equipes que precisam montar formularios Praxis manualmente sem perder consistencia, autosave e governanca
|
|
53
|
+
|
|
54
|
+
## When to use
|
|
55
|
+
|
|
56
|
+
- Declarar formularios manualmente com componentes `pdx-*` sem abrir mao de infraestrutura
|
|
57
|
+
- Adicionar autosave, persistencia e hot update de metadata ao fluxo do host
|
|
58
|
+
- Reduzir o atrito entre formularios manuais e o restante do ecossistema Praxis UI
|
|
59
|
+
|
|
3
60
|
## Instalação
|
|
4
61
|
|
|
5
62
|
```bash
|
|
@@ -35,6 +92,74 @@ O exemplo `/cargos/manual-form` demonstra uso declarativo:
|
|
|
35
92
|
</praxis-manual-form>
|
|
36
93
|
```
|
|
37
94
|
|
|
95
|
+
### Padrão didático para exemplos renderizados
|
|
96
|
+
|
|
97
|
+
Para páginas de documentação que precisam mostrar o componente antes de blocos longos de texto,
|
|
98
|
+
use o wrapper `praxis-manual-form-doc-example`. Ele já entrega:
|
|
99
|
+
|
|
100
|
+
- Banner curto com foco no exemplo live.
|
|
101
|
+
- Tabs para alternar entre `Live`, `Template`, `TS` e `Config`.
|
|
102
|
+
- Toggle de modo de customização (liga/desliga) com evento.
|
|
103
|
+
- Botão de cópia do snippet ativo.
|
|
104
|
+
- Callouts opcionais de `IMPORTANTE`, `NOTA` e `DICA`.
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<praxis-manual-form-doc-example
|
|
108
|
+
title="Cadastro de cargo"
|
|
109
|
+
subtitle="Preview primeiro, explicações depois."
|
|
110
|
+
level="Intermediario"
|
|
111
|
+
bannerTitle="Veja o componente em ação"
|
|
112
|
+
bannerDescription="Explore o live e abra código apenas quando necessário."
|
|
113
|
+
[templateCode]="templateSnippet"
|
|
114
|
+
[tsCode]="tsSnippet"
|
|
115
|
+
[configCode]="configSnippet"
|
|
116
|
+
[customizationEnabled]="editMode()"
|
|
117
|
+
(customizationEnabledChange)="editMode.set($event)"
|
|
118
|
+
important="Persista o draft no submit."
|
|
119
|
+
note="A aba Live abre por padrão."
|
|
120
|
+
tip="Use a aba Config para explicar contratos JSON."
|
|
121
|
+
>
|
|
122
|
+
<div exampleLive>
|
|
123
|
+
<praxis-manual-form
|
|
124
|
+
[formGroup]="form"
|
|
125
|
+
formId="cargo-manual-form"
|
|
126
|
+
[enableCustomization]="editMode()"
|
|
127
|
+
>
|
|
128
|
+
<pdx-text-input formControlName="nome" label="Nome"></pdx-text-input>
|
|
129
|
+
</praxis-manual-form>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div exampleDiagram>
|
|
133
|
+
<!-- Mermaid, SVG ou fluxo simplificado -->
|
|
134
|
+
</div>
|
|
135
|
+
</praxis-manual-form-doc-example>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Também existe um showcase pronto para consumo direto:
|
|
139
|
+
|
|
140
|
+
```html
|
|
141
|
+
<praxis-manual-form-doc-example-showcase></praxis-manual-form-doc-example-showcase>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Esse showcase já inclui providers locais de `API_URL` e `ASYNC_CONFIG_STORAGE`, evitando erro de injeção em páginas de documentação.
|
|
145
|
+
|
|
146
|
+
### Diagrama de funcionamento (alto nível)
|
|
147
|
+
|
|
148
|
+
```mermaid
|
|
149
|
+
flowchart LR
|
|
150
|
+
Host[Template com <pdx-*>] --> ManualForm[praxis-manual-form]
|
|
151
|
+
ManualForm --> Detect[Detecta campos]
|
|
152
|
+
Detect --> Meta[Infere FieldMetadata]
|
|
153
|
+
Meta --> Group[Cria/Adota FormGroup]
|
|
154
|
+
Group --> Render[Renderiza campos + validações]
|
|
155
|
+
ManualForm --> Instance[ManualFormInstance]
|
|
156
|
+
Instance --> Storage[ConfigStorage]
|
|
157
|
+
ManualForm -->|editMode| Editor[Metadata Editor]
|
|
158
|
+
Editor --> Patch[Aplica patch]
|
|
159
|
+
Patch --> Instance
|
|
160
|
+
Instance --> Persist[saveDraft / resetToSeed]
|
|
161
|
+
```
|
|
162
|
+
|
|
38
163
|
### Editor de metadados integrado
|
|
39
164
|
|
|
40
165
|
Use o `ManualFieldMetadataBridgeService` para abrir o editor visual a partir de qualquer campo detectado pelo container. O serviço carrega o módulo sob demanda, aplica o patch retornado e chama `saveDraft()` para persistir as alterações no runtime.
|
|
@@ -58,6 +183,24 @@ export class CargoManualFormComponent {
|
|
|
58
183
|
}
|
|
59
184
|
```
|
|
60
185
|
|
|
186
|
+
### Toolbar de campo (modo de edicao)
|
|
187
|
+
|
|
188
|
+
Quando `enableCustomization` estiver ativo, o manual-form exibe uma toolbar flutuante ao clicar
|
|
189
|
+
no campo. Ela permite alternar `required`, `readOnly`, `hidden` e `disabled`, e abrir o editor
|
|
190
|
+
completo de metadados.
|
|
191
|
+
|
|
192
|
+
Atalhos de teclado (quando o campo esta focado):
|
|
193
|
+
- `F2` ou `Alt+F10` abre a toolbar e move o foco para o primeiro botao.
|
|
194
|
+
- `ESC` fecha a toolbar.
|
|
195
|
+
|
|
196
|
+
Observacao: se um componente de campo interromper o clique (stopPropagation), a toolbar nao
|
|
197
|
+
abrira via mouse. Use os atalhos de teclado ou evite bloquear o click no host do campo.
|
|
198
|
+
|
|
199
|
+
Token de z-index:
|
|
200
|
+
- `--pdx-manual-toolbar-z` (default: `2001`).
|
|
201
|
+
Classe de overlay (para temas corporativos):
|
|
202
|
+
- `.pdx-manual-toolbar-panel` (aplicada no CDK Overlay para customizacoes).
|
|
203
|
+
|
|
61
204
|
## Motivações
|
|
62
205
|
|
|
63
206
|
- DX coerente para formulários manuais (sem JSON).
|
|
@@ -93,7 +236,7 @@ Essa base permite que hosts manualmente criem formulários com componentes Praxi
|
|
|
93
236
|
## Padrão corporativo recomendado
|
|
94
237
|
|
|
95
238
|
- Host tipado: o host deve criar um `FormGroup` tipado e passá‑lo via `[formGroup]`. O container adota esse grupo, aplica metadados/validators e evita interceptações internas. Isso habilita o Angular Language Service a validar `formControlName` e melhora a DX.
|
|
96
|
-
- Modo dinâmico:
|
|
239
|
+
- Modo dinâmico: opção para PoCs e exemplos rápidos; veja os detalhes na seção “Guia rápido”.
|
|
97
240
|
|
|
98
241
|
## Configurações avançadas
|
|
99
242
|
|
|
@@ -104,37 +247,44 @@ Essa base permite que hosts manualmente criem formulários com componentes Praxi
|
|
|
104
247
|
- Autosave
|
|
105
248
|
- `@Input() enableAutoSave: boolean` (padrão: `true`) e `@Input() autoSaveDebounceMs: number` (padrão: `800`).
|
|
106
249
|
|
|
107
|
-
|
|
250
|
+
### API pública adicional
|
|
108
251
|
|
|
109
|
-
|
|
252
|
+
- `ManualFormInstance.metadataChanges()`
|
|
253
|
+
- Emite sempre que o mapa de `FieldMetadata` é atualizado no runtime.
|
|
254
|
+
- Timing: após `patchFieldMetadata()`, `replaceConfig()`, `resetToSeed()` e cargas de config persistida.
|
|
255
|
+
|
|
256
|
+
## SSR (AsyncConfigStorage sem localStorage)
|
|
257
|
+
|
|
258
|
+
Em SSR, `localStorage` não existe. Como `praxis-manual-form` depende do token `ASYNC_CONFIG_STORAGE`, você pode prover uma implementação segura no servidor (ex.: in‑memory) e manter `LocalStorageAsyncAdapter` no browser.
|
|
110
259
|
|
|
111
260
|
Exemplo (Angular com `app.config.server.ts`):
|
|
112
261
|
|
|
113
262
|
```ts
|
|
114
263
|
// app.config.server.ts
|
|
115
264
|
import { ApplicationConfig, PLATFORM_ID, inject, isPlatformServer } from '@angular/core';
|
|
116
|
-
import {
|
|
265
|
+
import { ASYNC_CONFIG_STORAGE, LocalStorageAsyncAdapter, type AsyncConfigStorage } from '@praxisui/core';
|
|
266
|
+
import { EMPTY, of } from 'rxjs';
|
|
117
267
|
|
|
118
|
-
class
|
|
268
|
+
class MemoryAsyncStorage implements AsyncConfigStorage {
|
|
119
269
|
private readonly map = new Map<string, any>();
|
|
120
|
-
loadConfig<T>(key: string)
|
|
121
|
-
saveConfig<T>(key: string, config: T)
|
|
122
|
-
clearConfig(key: string)
|
|
270
|
+
loadConfig<T>(key: string) { return of((this.map.get(key) as T) ?? null); }
|
|
271
|
+
saveConfig<T>(key: string, config: T) { this.map.set(key, config); return EMPTY; }
|
|
272
|
+
clearConfig(key: string) { this.map.delete(key); return EMPTY; }
|
|
123
273
|
}
|
|
124
274
|
|
|
125
275
|
export const appConfig: ApplicationConfig = {
|
|
126
276
|
providers: [
|
|
127
277
|
{
|
|
128
|
-
provide:
|
|
278
|
+
provide: ASYNC_CONFIG_STORAGE,
|
|
129
279
|
useFactory: () => isPlatformServer(inject(PLATFORM_ID))
|
|
130
|
-
? new
|
|
131
|
-
: inject(
|
|
280
|
+
? new MemoryAsyncStorage()
|
|
281
|
+
: inject(LocalStorageAsyncAdapter),
|
|
132
282
|
},
|
|
133
283
|
],
|
|
134
284
|
};
|
|
135
285
|
```
|
|
136
286
|
|
|
137
|
-
Alternativas no servidor: usar cookies, cache distribuído (ex.: Redis) ou persistir por sessão do usuário. Basta implementar a interface `
|
|
287
|
+
Alternativas no servidor: usar cookies, cache distribuído (ex.: Redis) ou persistir por sessão do usuário. Basta implementar a interface `AsyncConfigStorage`.
|
|
138
288
|
|
|
139
289
|
### Exemplo (nested form)
|
|
140
290
|
|
|
@@ -192,6 +342,14 @@ export class MinhaPagina {
|
|
|
192
342
|
</praxis-manual-form>
|
|
193
343
|
```
|
|
194
344
|
|
|
345
|
+
Observações importantes:
|
|
346
|
+
- Aplique `[formGroup]` diretamente no seletor `<praxis-manual-form>` (no host).
|
|
347
|
+
- Evite envolver o componente com um `<form [formGroup]>` externo; não há necessidade e pode causar forms aninhados.
|
|
348
|
+
|
|
349
|
+
Modo dinâmico (sem host tipado):
|
|
350
|
+
- Quando nenhum `[formGroup]` é informado no host, o container renderiza internamente um `<form [formGroup]="formGroup">` para atender o Angular Forms e evitar o erro NG01050.
|
|
351
|
+
- Isso dispensa qualquer “shim” externo para os exemplos dinâmicos.
|
|
352
|
+
|
|
195
353
|
## API do ManualFormComponent (resumo)
|
|
196
354
|
|
|
197
355
|
- Inputs (sinais):
|
|
@@ -200,7 +358,7 @@ export class MinhaPagina {
|
|
|
200
358
|
- `actions?: FormActionsLayout | null`
|
|
201
359
|
- `showHeader = true`, `showActions = true`
|
|
202
360
|
- `enableAutoSave = true`, `autoSaveDebounceMs = 800`
|
|
203
|
-
- `
|
|
361
|
+
- `enableCustomization = false` (habilita ações de customização — ex.: abrir editor por duplo clique)
|
|
204
362
|
- `persistenceOptions?: { namespace?, tenantId?, profileId?, locale? }`
|
|
205
363
|
- `usePathNames = false` (usa `FormControlName.path` como nome do campo)
|
|
206
364
|
- Outputs (sinais):
|
|
@@ -208,12 +366,12 @@ export class MinhaPagina {
|
|
|
208
366
|
- `metadataChange(FormConfig)`
|
|
209
367
|
|
|
210
368
|
- Métodos públicos:
|
|
211
|
-
- `tryOpenFieldEditor(fieldName: string)`: tenta abrir o editor do campo, respeitando `
|
|
369
|
+
- `tryOpenFieldEditor(fieldName: string)`: tenta abrir o editor do campo, respeitando `enableCustomization` (no‑op quando `false`).
|
|
212
370
|
|
|
213
371
|
## Header e Actions
|
|
214
372
|
|
|
215
373
|
- `<praxis-manual-form-header>`: recebe `instance`, `title`, `description`, `saveLabel`, `resetLabel` e emite `save/reset`.
|
|
216
|
-
- Quando `
|
|
374
|
+
- Quando `enableCustomization` está ativo no container, o header exibe um botão “Editar formulário” que emite `editForm`; o container trata esse evento chamando `openFormEditor()`.
|
|
217
375
|
- `<praxis-manual-form-actions>`: recebe `actions: FormActionsLayout`, emite `actionClick` e aceita `trackByFn` opcional para listas grandes.
|
|
218
376
|
|
|
219
377
|
## Editor de Metadados (visual)
|
|
@@ -227,34 +385,48 @@ openEditor(fieldName: string) {
|
|
|
227
385
|
}
|
|
228
386
|
```
|
|
229
387
|
|
|
230
|
-
Integração com Settings Panel: o `ManualFormComponent` utiliza `SettingsPanelService` para abrir o editor do formulário (lista de campos e flags) quando `
|
|
388
|
+
Integração com Settings Panel: o `ManualFormComponent` utiliza `SettingsPanelService` para abrir o editor do formulário (lista de campos e flags) quando `enableCustomization` está ativo. É possível abrir programaticamente via `manualForm.openFormEditor()`.
|
|
231
389
|
|
|
232
390
|
### Duplo clique com modo de edição
|
|
233
391
|
|
|
234
|
-
Para espelhar o comportamento das demais libs (permitir edição apenas quando o modo de edição está ativo), use o input `
|
|
392
|
+
Para espelhar o comportamento das demais libs (permitir edição apenas quando o modo de edição está ativo), use o input `enableCustomization` no container e a diretiva `pdxManualEdit` nos campos:
|
|
235
393
|
|
|
236
394
|
```html
|
|
237
|
-
<praxis-manual-form formId="cargo" [
|
|
395
|
+
<praxis-manual-form formId="cargo" [enableCustomization]="custom.enabled()">
|
|
238
396
|
<pdx-text-input formControlName="nome" label="Nome" pdxManualEdit="nome"></pdx-text-input>
|
|
239
397
|
<pdx-material-currency formControlName="salario" label="Salário" pdxManualEdit="salario"></pdx-material-currency>
|
|
240
398
|
</praxis-manual-form>
|
|
241
399
|
```
|
|
242
400
|
|
|
243
|
-
A diretiva chama `manualForm.tryOpenFieldEditor(fieldName)` e respeita `
|
|
401
|
+
A diretiva chama `manualForm.tryOpenFieldEditor(fieldName)` e respeita `enableCustomization`, de modo que o duplo clique só abre o editor quando a edição está ligada.
|
|
244
402
|
|
|
245
403
|
### Editor do Formulário (lista de campos)
|
|
246
404
|
|
|
247
|
-
O `ManualFormComponent` expõe `openFormEditor()` para abrir um editor simples do formulário que lista todos os campos e permite alternar: visibilidade (mostrar/ocultar), obrigatório, somente leitura e desabilitado — facilitando encontrar campos ocultos e reexibi‑los, além de ajustes rápidos. O editor respeita `
|
|
405
|
+
O `ManualFormComponent` expõe `openFormEditor()` para abrir um editor simples do formulário que lista todos os campos e permite alternar: visibilidade (mostrar/ocultar), obrigatório, somente leitura e desabilitado — facilitando encontrar campos ocultos e reexibi‑los, além de ajustes rápidos. O editor respeita `enableCustomization` e usa o `SettingsPanelService`.
|
|
248
406
|
|
|
249
407
|
Exemplo de uso no host:
|
|
250
408
|
|
|
251
409
|
```html
|
|
252
410
|
<button *ngIf="custom.enabled()" type="button" (click)="manualForm?.openFormEditor()">Editar formulário</button>
|
|
253
|
-
<praxis-manual-form #manualForm [formGroup]="form" formId="'cargo'" [
|
|
411
|
+
<praxis-manual-form #manualForm [formGroup]="form" formId="'cargo'" [enableCustomization]="custom.enabled()">
|
|
254
412
|
<!-- campos -->
|
|
255
413
|
</praxis-manual-form>
|
|
256
414
|
```
|
|
257
415
|
|
|
416
|
+
#### O que o editor cobre (tabs)
|
|
417
|
+
|
|
418
|
+
O editor do formulario (Settings Panel) expõe:
|
|
419
|
+
- **Campos**: visibilidade, obrigatorio, somente leitura, desabilitado.
|
|
420
|
+
- **Acoes**: layout da barra, botoes padrao e acoes customizadas.
|
|
421
|
+
- **Mensagens**: feedbacks de sucesso/erro, loading e confirmacoes.
|
|
422
|
+
- **Comportamento**: flags de UX (ex.: focusFirstError, scrollToErrors).
|
|
423
|
+
- **Dicas**: textos auxiliares para modos de tela (i18n/UX).
|
|
424
|
+
- **Hooks**: JSON com hooks de lifecycle (antes/depois de init/submit).
|
|
425
|
+
- **Regras**: regras de layout/visibilidade (JSON).
|
|
426
|
+
- **Cascatas**: dependencias entre campos via metadados.
|
|
427
|
+
|
|
428
|
+
Obs.: a execucao de hooks/regras depende do host registrar os providers correspondentes.
|
|
429
|
+
|
|
258
430
|
## Extensibilidade por DI
|
|
259
431
|
|
|
260
432
|
- Customize a inferência de `FieldControlType` via tokens:
|
|
@@ -271,11 +443,11 @@ Exemplo de uso no host:
|
|
|
271
443
|
|
|
272
444
|
## ManualFieldEditorOnDblclickDirective (`pdxManualEdit`)
|
|
273
445
|
|
|
274
|
-
- Usa o duplo clique para abrir o editor do campo, respeitando `
|
|
446
|
+
- Usa o duplo clique para abrir o editor do campo, respeitando `enableCustomization` do `ManualFormComponent`.
|
|
275
447
|
- Apenas funciona quando aplicada a elementos dentro de `<praxis-manual-form>`.
|
|
276
448
|
|
|
277
449
|
```html
|
|
278
|
-
<praxis-manual-form formId="cargo" [
|
|
450
|
+
<praxis-manual-form formId="cargo" [enableCustomization]="custom.enabled()">
|
|
279
451
|
<pdx-text-input formControlName="nome" label="Nome" pdxManualEdit="nome"></pdx-text-input>
|
|
280
452
|
</praxis-manual-form>
|
|
281
453
|
```
|
|
@@ -285,7 +457,7 @@ Exemplo de uso no host:
|
|
|
285
457
|
- Preferir host tipado e `usePathNames=true` para nested forms.
|
|
286
458
|
- Habilitar autosave com debounce adequado.
|
|
287
459
|
- Evitar lógica pesada em templates; delegar inferências ao container.
|
|
288
|
-
- No SSR, sempre prover `
|
|
460
|
+
- No SSR, sempre prover `ASYNC_CONFIG_STORAGE` compatível (sem localStorage).
|
|
289
461
|
|
|
290
462
|
## Licença
|
|
291
463
|
|
|
@@ -297,6 +469,11 @@ Apache-2.0 — consulte `LICENSE` neste pacote ou no repositório raiz.
|
|
|
297
469
|
- Layout é responsabilidade do host; não há reordenação automática por metadados.
|
|
298
470
|
- Modo dinâmico sem `[formGroup]` não habilita validação estática de `formControlName` no IDE.
|
|
299
471
|
|
|
472
|
+
## Notas adicionais
|
|
473
|
+
|
|
474
|
+
- Quando `enableCustomization` estiver ativo, o container renderiza o assistente AI (Praxis AI) no header do formulario.
|
|
475
|
+
- `componentInstanceId` ajuda a compor a chave de persistencia (com `formId` e `persistenceOptions`), evitando conflito entre instancias da mesma tela.
|
|
476
|
+
|
|
300
477
|
## Comparativo — Manual vs Dinâmico (JSON)
|
|
301
478
|
|
|
302
479
|
- Manual: controle máximo do HTML; evolui por metadados incrementais; ótimo para telas estáveis com design específico.
|