@praxisui/dynamic-form 9.0.66 → 9.0.68-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.
package/README.md CHANGED
@@ -258,6 +258,14 @@ Recommended defaults:
258
258
  - dense command drawers: `helpPresentation.display = "auto"` with popover preference for select, checkbox, toggle, date and numeric controls;
259
259
  - operational input-heavy forms: `fieldIconPolicy = "presentation-only"` unless the icon is part of the actual affordance.
260
260
 
261
+ `layoutPolicy.persistence = "transient"` also suppresses automatic UI-storage
262
+ writes of derived schema metadata and its context index. Schema fields, hashes,
263
+ context and verification state remain available in memory. Pending metadata work
264
+ rechecks the policy before sending a write; this does not cancel requests already
265
+ sent. Existing storage reads and explicit editor Apply/Save behavior are unchanged.
266
+ `configPersistenceStrategy = "input-first"` alone controls precedence, not this
267
+ no-automatic-write policy. The default persistent behavior is unchanged.
268
+
261
269
  On narrow viewports, the standard form action footer stacks validation guidance
262
270
  above the command CTA and keeps the action full width. This is presentation
263
271
  behavior only; submit labels, visibility and confirmation still come from the
@@ -303,6 +311,24 @@ Common inputs:
303
311
  - `domainRules`
304
312
  - `editorialContext`
305
313
 
314
+ `providePraxisDynamicFormMetadata()` also registers localized editorial copy through
315
+ the existing `ComponentMetadataRegistry`. Shared editors resolve labels and help
316
+ with `resolveEditorial('praxis-dynamic-form')`, while raw input names, types and
317
+ defaults remain authoritative. The form owns the pt-BR/en-US dictionaries. Hosts
318
+ can override keys such as `praxisDynamicForm.editorial.mode.label` using the normal
319
+ Praxis i18n provider/translator; consuming builders need no form-specific map.
320
+ Advanced inputs without editorial overrides retain their raw metadata copy.
321
+
322
+ Surface action editors in custom actions, command rules and section headers
323
+ propagate invalid JSON drafts into the owner's dirty/valid state. Apply/Save stays
324
+ blocked until all errors are corrected; tab navigation preserves raw text and
325
+ Reset explicitly discards it. See [consumer validation](../praxis-core/docs/surface-draft-consumers-validation-2026-09-08.md).
326
+
327
+ In the actions editor, omitted optional text (icons, shortcuts, tooltips and CSS
328
+ classes) is displayed as an empty input. Opening a tab does not write empty
329
+ strings into the configuration; existing host text and explicit user edits retain
330
+ their values.
331
+
306
332
  `actions` is also a registered Dynamic Page input. A host or surface
307
333
  materializer may use it for presentation affordances such as a contextual
308
334
  submit label and button visibility. It must not use that input to replace the
@@ -322,6 +348,19 @@ by local master-detail/detail surfaces. With a remote read source, the backend
322
348
  entity remains canonical; a later `initialValue` change never resets hydrated
323
349
  fields or pending user edits. Change `resourceId` to load another remote entity.
324
350
 
351
+ During a remote entity read, the form preserves its layout and mounted controls,
352
+ but hides the previous values from sight, keyboard interaction and assistive
353
+ technology. A local status explains the update. Failed or invalid reads keep the
354
+ body and submit blocked and offer a local retry for the same identity. Successful
355
+ reads replace the record snapshot, clearing fields omitted by the new response;
356
+ superseded reads cannot apply to the current selection. This is automatic runtime
357
+ behavior, not an additional widget binding or editor setting. Creation commands
358
+ and authoritative local `initialValue` snapshots retain their existing behavior.
359
+ Hiding is immediate: an opacity transition must not reveal the previous identity
360
+ under the new header. Explicit retry focuses a stable detail region; the response
361
+ does not steal focus after the user navigates elsewhere. See the
362
+ [local feedback contract and evidence](docs/entity-read-feedback.md).
363
+
325
364
  For local master-detail views, `emptyState` is the canonical opt-in placeholder
326
365
  while neither `resourceId` nor a non-empty `initialValue` identifies a record.
327
366
  The Dynamic Form replaces its field surface with the shared
@@ -331,6 +370,14 @@ the component owns the deterministic transition between "select a record" and
331
370
  the presentation-only form. Do not duplicate that state with a consumer-local
332
371
  card or keep an empty form visible behind it.
333
372
 
373
+ The placeholder follows its content height, without reserving a fraction of the
374
+ viewport. Its existing `--pdx-form-context-empty-min-height` and
375
+ `--pdx-form-context-empty-padding` tokens default to `0`; the shared card still
376
+ provides its internal spacing. Hosts can override those tokens to reserve more
377
+ space. `--pdx-form-context-empty-max-width` continues to default to `32rem`.
378
+ Visual choices such as alignment, density and icon container remain in
379
+ `emptyState`, including the native editor and JSON document.
380
+
334
381
  ```html
335
382
  <praxis-dynamic-form
336
383
  mode="view"
@@ -438,6 +485,12 @@ Presentation formatting of field values is resolved by `@praxisui/dynamic-fields
438
485
 
439
486
  ### Compact Presentation Preset
440
487
 
488
+ For a detail form inside a widget card, use `sections[].appearance: "plain"`
489
+ to keep a single outer frame. Plain sections retain transparent backgrounds,
490
+ no shadow and no internal padding in field, presentation, compact and editorial
491
+ contexts. Card and step sections keep their own surfaces. Configure section
492
+ spacing and presentation density separately; explicit authored styles still apply.
493
+
441
494
  For dense enterprise read-only screens, `DynamicFormLayoutService.generateFormConfigFromMetadata`
442
495
  can materialize a compact presentation layout directly from governed field metadata:
443
496
 
@@ -562,3 +615,120 @@ Main exports:
562
615
  - Keep backend schema fields server-backed; use local/transient metadata only for UI-owned state.
563
616
  - Prefer explicit `schemaUrl + submitUrl + submitMethod` for backend-published surfaces and actions.
564
617
  - Use the official documentation for full recipes on cascades, schema reconciliation, domain rules, action layout, and visual editor workflows.
618
+
619
+ ### Modo de consulta no Page Builder
620
+
621
+ Ao conectar um formulário a um recurso e alterar somente `mode` para `view`, o editor preserva a ausência de configuração autorada. Assim, os campos continuam derivados do schema após salvar e reabrir a página. Uma configuração de formulário efetivamente editada continua sendo persistida.
622
+
623
+ `configPatchChange` publica um `inputPatch` parcial com `config`, `resourcePath`, `mode` e/ou `presentationModeGlobal`. Consumidores devem aplicar somente as propriedades presentes: a conexão rápida publica a rota sem fixar uma configuração de campos ainda vazia.
624
+
625
+ ### Configurar a exibição inicial no Page Builder
626
+
627
+ Abra **Configurar conteúdo → Geral → Dados do formulário**. Para um detalhe de leitura, selecione **Modo de dados: view** e **Modo de exibição: Apresentação**. Salve o conteúdo e a página. **Campos de formulário** preserva controles de leitura; **Automático (seguir schema)** remove o override e respeita `layoutPolicy`. A preferência usa `bindings.presentationModeGlobal` no documento e o input homônimo no widget. Não é necessário criar uma ação rápida para iniciar em apresentação.
628
+
629
+ O botão criado em **Configurar widget → Ações rápidas (inputs)** continua sendo uma troca durante a interação. Para tipografia, densidade e alinhamento da apresentação em execução, use **Configurar formulário → Modo Apresentação**; esse editor persiste `contextSnapshot.presentation` separadamente da ativação.
630
+
631
+
632
+ ### Presentation style projection and editor UX
633
+
634
+ - `contextSnapshot.presentation` is the canonical style snapshot. The optional runtime input `presentation: DynamicFormPresentationSnapshot | null` projects it into page widgets independently of schema-generated `config`. Explicit styles take precedence over stored style preferences; `null` restores defaults and blocks stale stored overrides; omission retains normal style resolution.
635
+ - Runtime editor Apply/Save emits `presentation` with `mode` and `presentationModeGlobal` in `configPatchChange.inputPatch`. Widget save/reopen preserves the same snapshot; omitting the document block clears the widget projection with `null`.
636
+ - Numeric font sizes and label widths are pixels. Capturing a runtime `rem` size converts it using the host root font size; opening and saving must not reinterpret `0.78rem` as `0.78px`.
637
+ - **Geral → Dados do formulário** separates **Criar / Editar / Visualizar** from **Automático / Campos / Apresentação**. Selecting presentation in Create/Edit keeps the operation unchanged and explains the inactive state with an explicit action to switch to View.
638
+ - **Estilo da apresentação** remains discoverable regardless of the current mode. It previews sample data and does not activate presentation by itself. Filter Form does not expose this tab because it has no presentation runtime.
639
+ - Applying or finishing widget editing updates the page draft. **Salvar página** persists the composition. Shortening sample text affects the preview only.
640
+
641
+
642
+ ### Limpeza de seleção em detalhes controlados
643
+
644
+ Em formulários `view`/`edit` ligados a uma identidade remota, mudar `resourceId` de um registro para `null` limpa o snapshot anterior e cancela a leitura pendente, inclusive quando ela usa `readUrl`. Respostas de seleções substituídas não podem hidratar o registro atual. Um rebuild de configuração após essa limpeza não restaura o cache nem a semente `initialValue` do registro anterior; uma nova identidade inicia sua própria hidratação. Isso não altera snapshots locais authorados por `initialValue`, nem os defaults de comandos em modo `create`.
645
+
646
+
647
+ ### Recoverable schema loading
648
+
649
+ Dynamic Form consumes Core's `SCHEMA_METADATA_CLIENT_OPTIONS` transport policy
650
+ for schema deadlines and cancellation. Timeouts use the existing error/retry
651
+ surface; superseded results cannot finish a newer initialization. There is no
652
+ additional widget timeout input. See [schema loading recovery](docs/schema-loading-recovery.md)
653
+ for provider configuration, scope, and validation limits.
654
+
655
+
656
+ ### Orientação antes da seleção de um registro
657
+
658
+ O editor nativo, em **Geral → Sem registro selecionado**, materializa o contrato existente `PraxisDynamicFormEmptyState` em `bindings.emptyState`. O wrapper Page Builder projeta esse binding para `inputs.emptyState`; Apply, Save e JSON usam o mesmo documento. Não pertence a `FormConfig` nem substitui o modo dos dados.
659
+
660
+ `title` é obrigatório e não pode conter apenas espaços. `description` e `icon` são textos opcionais; a cópia de negócio permanece literal, sem ser interpretada automaticamente como chave i18n. O seletor usa o catálogo canônico de ícones. Restaurar o ícone padrão limpa a escolha explícita. Os controles do editor usam o catálogo i18n Form; a aparência runtime usa os tokens do empty state compartilhado.
661
+
662
+ As opções de aparência ficam em disclosure avançado: `tone` (`neutral`, `primary`, `secondary`), `variant` (`card`, `inline`, `panel`, `transparent`), `alignment` (`start`, `center`), `density` (`compact`, `comfortable`) e `iconContainer` (`none`, `circle`, `soft`). Ausência de opção herda o padrão do componente; JSON inválido produz diagnóstico.
663
+
664
+ A orientação aparece somente em `mode=view`, sem registro selecionado nem snapshot local. Criar e Editar preservam a configuração sem exibi-la. Desligar grava `null`, que impede reativação por uma preferência antiga; substituir um documento que omite o binding também limpa a orientação. Em `input-first`, a página governa o valor. Filter Form não expõe essa seção, pois não possui contexto de seleção equivalente.
665
+
666
+ Após Aplicar, o dono da página confirma o commit local pelo canal transitório de sessão `appliedValues$`. O wrapper/nativo usa `acceptAppliedValue` para comparar o draft com a última prévia aceita; retornar aos valores de abertura volta a habilitar Aplicar quando a prévia diverge. Redefinir continua restaurando a abertura do Form. A confirmação local não comprova persistência HTTP.
667
+
668
+ O wrapper isola `SETTINGS_PANEL_DATA` do editor embutido: o envelope do host e seus observables nunca são clonados como configuração. O Core envia o canal de confirmação apenas a editores que declaram o input `appliedValues$`; o editor nativo consome esse canal somente junto ao documento canônico.
669
+
670
+ ### Leitura do editor de layout
671
+
672
+ **Espaço após as seções** define o valor proposto para `gapBottom`, em pixels. Alterar o número não modifica o formulário. **Preencher espaços não definidos** leva o valor ao rascunho somente nas seções sem espaçamento explícito; valores existentes, inclusive zero, são preservados. O comando não cria uma marca paralela de personalização. Aplicar/Salvar continuam confirmando o rascunho; o controle não altera o espaço entre colunas.
673
+
674
+ **Densidade do editor** (Compacta, Confortável e Espaçosa) e **Guias do editor** (Bordas das seções e Separadores) ajustam somente a visualização de trabalho. Não alteram o documento nem habilitam Aplicar/Salvar. Os controles mantêm nomes acessíveis, estados selecionado/pressionado e dicas explicativas no catálogo `praxisDynamicFormLayoutEditor`, com português, inglês e substituição pelo tradutor do host. Os valores internos e os tokens visuais existentes permanecem os mesmos.
675
+
676
+ **Renomear seção**, no cabeçalho, edita somente o título. **Salvar nome** ou Enter confirma; Cancelar ou Escape descarta a edição do nome e devolve o foco ao botão. Nomes vazios são recusados. Aparência, descrição, ícone e comportamento continuam no editor completo da seção. Uma seção sem linhas orienta a sequência linha → colunas → campos e oferece **Adicionar primeira linha**, usando o comando existente. Os textos usam o catálogo i18n da lib e a aparência herda tokens do host. Remover uma seção preserva os metadados dos campos: os campos elegíveis sem outro posicionamento voltam ao catálogo; blocos visuais pertencentes à seção são removidos com sua estrutura. Essas alterações continuam sujeitas a Aplicar/Salvar do editor e Salvar página.
677
+
678
+ O botão de ações de cada linha mostra seu número e possui nome acessível com linha e seção. O menu mantém os presets, Adicionar coluna e Remover linha existentes, utilizando o comportamento de teclado e foco do menu Material.
679
+
680
+ Os controles de espaçamento e faixa de tela ficam em **Ajustar layout da linha**, recolhidos inicialmente; abrir esse grupo não altera o documento. O menu da linha sempre atua na linha, independentemente da seleção anterior. Presets mostram miniaturas proporcionais e nomes traduzidos. A distribuição de larguras afeta somente a faixa exibida (por padrão MD); a estrutura de colunas é compartilhada pelas faixas. Ao reduzir colunas, seus itens são anexados em ordem à última coluna mantida, preservando campos e blocos visuais. As larguras das demais faixas nas colunas mantidas permanecem inalteradas.
681
+
682
+ Selecionar um campo mostra sua localização usando o título da seção e o rótulo dos metadados. As ações **Editar campo** e **Layout da coluna** abrem os editores canônicos existentes; selecionar ou abrir um editor não modifica o documento. Enter e Espaço selecionam o campo focado. As ações são suprimidas quando o alvo não existe mais na estrutura canônica.
683
+
684
+ Para posicionar um campo disponível sem arrastar, abra **Opções da coluna → Adicionar campo da API**, navegue com as setas e confirme com Enter. O campo sai do catálogo de disponíveis e recebe foco na coluna; Tab continua para editar seus metadados. Isso posiciona um campo já definido, sem criar ou duplicar metadados. Campos já posicionados não podem ser reinseridos por esse comando. A coluna vazia e o catálogo explicam esse caminho usando o catálogo i18n da lib.
685
+
686
+ Em colunas mistas, esse comando acrescenta o campo ao final de `items[]`, inclusive depois de blocos visuais. Os itens anteriores conservam identidade e conteúdo. Para escolher outra posição, use **Mover campo**; a posição considera também os blocos visuais. `fields[]` permanece uma projeção apenas dos campos, sem incluir conteúdo editorial.
687
+
688
+ Nas opções de movimentação, blocos visuais mostram a posição original na coluna e um resumo do conteúdo, por exemplo **bloco visual (posição 2): Revise as informações…**. O número conta todos os itens, inclusive o campo sendo movido; não é um identificador persistido. Textos iguais e blocos vazios são diferenciados pela posição. O resumo reutiliza a leitura textual do editor, normaliza espaços e limita a prévia a 80 caracteres; não avalia bindings nem renderiza HTML. Os valores das opções continuam sendo IDs canônicos.
689
+
690
+ Na prévia de um bloco visual, Enter abre a edição do conteúdo e Espaço seleciona o bloco. Botões internos conservam sua própria ativação pelo teclado: abrir o menu ou remover o bloco não deve disparar o editor de conteúdo. Ao inserir ou mover um bloco, o foco acompanha a prévia selecionada; ao removê-lo, retorna à coluna preservada. O editor não recupera esse foco se a seleção mudar antes da renderização.
691
+
692
+ **Mover campo** abre a escolha de seção, linha, coluna e posição sem depender do arraste. Linhas e colunas mostram um resumo dos primeiros três itens, com a quantidade restante quando necessário. Os rótulos vêm de `fieldMetadata`, com nome técnico como fallback; blocos visuais e destinos vazios são identificados. Os resumos descrevem a estrutura authorada, incluindo campos ocultos, e não simulam permissões ou visibilidade runtime. A posição considera todos os itens da coluna, incluindo blocos visuais. O serviço de layout é isolado por instância do editor, para que operações do rascunho não sejam transmitidas aos formulários em uso. Abrir ou cancelar não altera o documento; confirmar utiliza `DynamicFormLayoutService.moveLayoutItemById`, conserva a identidade do item, seus metadados e os contêineres vazios, e seleciona/foca o campo no destino. A aparência passa a ser a da coluna de destino. Se o documento for substituído enquanto o diálogo estiver aberto, a movimentação é recusada com orientação para escolher novamente. Aplicar, Salvar e fechar e Salvar página mantêm suas responsabilidades existentes.
693
+
694
+ Na aba **Estilo** da coluna, o alinhamento é vertical na linha (`align-self`), não alinhamento de texto. O grupo visual Topo/Centro/Base/Preencher mantém os valores canônicos `start`/`center`/`end`/`stretch`. **Espaço interno** apresenta o `padding` numérico existente em pixels; o editor mantém sua faixa de 0 a 32. Classe CSS do host e identificador de teste ficam em **Integração com o aplicativo**, recolhidos inicialmente. Expandir esse grupo não limpa seus valores nem modifica o documento; os controles usam i18n da lib e tokens Material/Praxis existentes.
695
+
696
+ O painel de coluna identifica seu alvo por seção, linha e número da coluna no título. Os campos aparecem com os rótulos de `fieldMetadata`, seguindo a ordem canônica de `items`; nomes técnicos são fallback quando não existe rótulo. Esse contexto é transitório e não entra no JSON salvo. As faixas XS–XL mantêm seus códigos e ganham nomes traduzidos e explicação da herança. Largura e recuo ficam juntos; **Ordem visual da coluna** é recolhida inicialmente e aberta quando há erro de ordem. Abrir grupos ou trocar a faixa de prévia não modifica o formulário.
697
+
698
+ O editor da coluna apresenta uma prévia de 12 partes, derivada da largura e do recuo resolvidos para a faixa selecionada. Ela representa a coluna isolada, não a distribuição completa da linha. **Modelos para várias faixas de tela** separa os presets responsivos dos ajustes de largura/recuo: o grupo informa quais modelos também afetam visibilidade e estilo. **Usar valores atuais em todas as faixas** copia largura, recuo, ordem e visibilidade; não restaura valores iniciais. Valores sem definição própria continuam seguindo a herança responsiva canônica.
699
+
700
+ Largura aceita inteiros de 1 a 12, recuo de 0 a 11 e ordem de -12 a 12. Limpar um valor mantém a herança responsiva; não equivale a zero. Valores inválidos permanecem visíveis para correção, com erro traduzido por propriedade/faixa, e bloqueiam Aplicar/Salvar, a prévia e os resumos numéricos. A edição JSON valida esses mesmos domínios novamente no momento de aplicar. **Ocultar em mobile** e **Somente desktop** alteram apenas visibilidade: preservam largura, recuo, ordem e estilo, inclusive em colunas personalizadas.
701
+
702
+
703
+
704
+
705
+
706
+ Os rótulos Largura, Recuo e Faixa de tela apresentam os contratos existentes `span`, `offset` e breakpoint; não mudam o documento salvo. Colunas também podem ser reorganizadas pelo menu Mover para esquerda/direita. O resumo de espaçamento distingue valor herdado de zero explícito, exibindo px somente para números.
707
+
708
+ O indicador “Oculto nos metadados” aparece quando `FieldMetadata.hidden` ou `FieldMetadata.formHidden` é explicitamente true. Ele é informativo, usa a tradução do editor e os tokens de texto do tema. Não avalia `hiddenCondition`, permissões ou visibilidade da coluna, nem altera esses contratos. A ausência desse indicador não é garantia de visibilidade no runtime.
709
+
710
+
711
+ ### Row spacing guidance in the layout editor
712
+
713
+ The row inspector treats unused grid space as an intentional authoring choice,
714
+ not a requirement to fill all 12 units. Guidance includes offsets and respects
715
+ inherited visibility at the selected preview breakpoint. Columns containing only
716
+ fields with static `hidden: true` or `formHidden: true` do not contribute; rich
717
+ content, mixed visible content, unknown field references and empty draft columns
718
+ remain available for planning.
719
+
720
+ The optional width suggestion uses the same occupancy calculation. Inspecting a
721
+ row or changing its preview breakpoint does not change its document. This is
722
+ static authoring guidance, not a simulation of record-dependent rules, schema
723
+ hydration or permission decisions. Numeric domain validation and Apply/Save
724
+ validation remain separate and unchanged.
725
+
726
+
727
+ ### Navegação em painéis estreitos
728
+
729
+ A adaptação de authoring considera a largura do contêiner, inclusive quando o
730
+ painel é estreito em uma janela desktop. Table e Dynamic Form exibem “Seção do
731
+ editor” até 768px de largura disponível, mantendo a mesma seleção e os conteúdos
732
+ das abas. Acima desse limite, reaparece a navegação por abas. O Settings Panel
733
+ organiza título, expandir e fechar em uma grade até 599px; a prévia, quando
734
+ suportada, ocupa a linha seguinte. Nenhum documento ou protocolo de Save é alterado.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-09-06T19:09:46.917Z",
3
+ "generatedAt": "2026-09-09T10:03:24.330Z",
4
4
  "packageName": "@praxisui/dynamic-form",
5
- "packageVersion": "9.0.66",
5
+ "packageVersion": "9.0.68-rc.0",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -266,11 +266,17 @@
266
266
  "required": false,
267
267
  "description": "Trava global para desabilitar campos"
268
268
  },
269
+ {
270
+ "name": "presentation",
271
+ "type": "DynamicFormPresentationSnapshot | null",
272
+ "required": false,
273
+ "description": "Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal."
274
+ },
269
275
  {
270
276
  "name": "presentationModeGlobal",
271
277
  "type": "boolean | null",
272
278
  "required": false,
273
- "description": "Modo de apresentacao (sem edicao)"
279
+ "description": "Preferência de exibição, também editável em Geral: true apresenta em view, false força campos, null segue layoutPolicy. Persiste em bindings.presentationModeGlobal."
274
280
  },
275
281
  {
276
282
  "name": "fieldIconPolicy",
@@ -323,7 +329,7 @@
323
329
  "name": "configPatchChange",
324
330
  "type": "DynamicFormConfigPatchChangeEvent",
325
331
  "required": false,
326
- "description": "Emite inputPatch.config quando a configuracao autorada do formulario muda, para hosts persistirem inputs.config sem alterar o payload legado de configChange.",
332
+ "description": "Emite inputPatch parcial com config, resourcePath, mode, presentationModeGlobal e/ou presentation para hosts persistirem apenas as entradas autoradas presentes, incluindo conexao rapida, sem alterar o payload legado de configChange.",
327
333
  "label": "Patch persistivel de configuracao"
328
334
  },
329
335
  {
@@ -6630,8 +6636,8 @@
6630
6636
  },
6631
6637
  {
6632
6638
  "name": "emptyState",
6633
- "type": "PraxisDynamicFormEmptyState",
6634
- "description": "Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host."
6639
+ "type": "PraxisDynamicFormEmptyState | null",
6640
+ "description": "Authorado em bindings.emptyState no editor; null desliga explicitamente. Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host."
6635
6641
  },
6636
6642
  {
6637
6643
  "name": "readUrl",
@@ -6648,6 +6654,16 @@
6648
6654
  ],
6649
6655
  "description": "Modo de operação"
6650
6656
  },
6657
+ {
6658
+ "name": "presentation",
6659
+ "type": "DynamicFormPresentationSnapshot | null",
6660
+ "description": "Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal."
6661
+ },
6662
+ {
6663
+ "name": "presentationModeGlobal",
6664
+ "type": "boolean | null",
6665
+ "description": "Preferência de exibição, também authorada em bindings.presentationModeGlobal: true apresenta rótulos e valores somente em mode=view; false força campos; null/ausência segue layoutPolicy. Não altera o modo dos dados."
6666
+ },
6651
6667
  {
6652
6668
  "name": "configPersistenceStrategy",
6653
6669
  "type": "string",
@@ -7529,7 +7545,7 @@
7529
7545
  "type": "string"
7530
7546
  },
7531
7547
  "span": {
7532
- "type": "number",
7548
+ "type": "integer",
7533
7549
  "minimum": 1,
7534
7550
  "maximum": 12,
7535
7551
  "default": 6
@@ -9184,9 +9200,9 @@
9184
9200
  {
9185
9201
  "chunkIndex": 0,
9186
9202
  "chunkKind": "summary",
9187
- "content": "Component ID: praxis-dynamic-form\nSelector: praxis-dynamic-form\nFriendly Name: Praxis Dynamic Form\nDescription: Formulario dinamico com layout por secoes/linhas/colunas e campos renderizados por metadados.\nCategory: form\nLib/Package: @praxisui/dynamic-form\nTags: widget, form, configurable, hasWizard, stable\nInputs:\n - resourcePath (string)\n - resourceId (string | number | null)\n - initialValue (Record<string, unknown> | null)\n - emptyState (PraxisDynamicFormEmptyState | null)\n - editorialContext (Record<string, unknown> | null)\n - mode ('create' | 'edit' | 'view')\n - config (FormConfig)\n - actions (FormConfig['actions'] | null)\n - schemaSource ('resource' | 'filter')\n - schemaUrl (string | null)\n - readUrl (string | null)\n - apiEndpointKey (ApiEndpoint | string | null)\n - apiUrlEntry (ApiUrlEntry | null)\n - submitUrl (string | null)\n - submitMethod ('post' | 'put' | 'patch' | null)\n - submitIdempotencyKey (string | null)\n - submitCorrelationId (string | null)\n - submitResourceVersion (string | number | null)\n - submitResourceVersionTargetResourceKey (string | null)\n - submitResourceVersionTargetIdField (string | null)\n - responseSchemaUrl (string | null)\n - enableCustomization (boolean)\n - showAiAssistant (boolean)\n - formId (string)\n - componentInstanceId (string)\n - configPersistenceStrategy ('local-first' | 'input-first')\n - layout (FormLayout)\n - generatedLayoutPreset ('default' | 'compactPresentation')\n - layoutPolicy (DynamicFormLayoutPolicy | null)\n - backConfig (BackConfig)\n - hooks (FormHooksLayout)\n - removeEmptyContainersOnSave (boolean)\n - reactiveValidation (boolean | null)\n - reactiveValidationDebounceMs (number | null)\n - notifyIfOutdated ('inline' | 'snackbar' | 'both' | 'none')\n - snoozeMs (number)\n - autoOpenSettingsOnOutdated (boolean)\n - readonlyModeGlobal (boolean | null)\n - disabledModeGlobal (boolean | null)\n - presentationModeGlobal (boolean | null)\n - fieldIconPolicy ('all' | 'presentation-only' | 'none')\n - visibleGlobal (boolean | null)\n - customEndpoints (EndpointConfig)\nOutputs:\n - formSubmit (FormSubmitEvent)\n - formCancel (void)\n - formReset (void)\n - configChange (FormConfig)\n - configPatchChange (DynamicFormConfigPatchChangeEvent)\n - formReady (FormReadyEvent)\n - valueChange (FormValueChangeEvent)\n - payloadPreviewChange (FormPayloadPreviewEvent)\n - syncCompleted (SyncResult)\n - initializationError (FormInitializationError)\n - enableCustomizationChange (boolean)\n - customAction (FormCustomActionEvent)\n - actionConfirmation (FormActionConfirmationEvent)\n - schemaStatusChange ({ outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string })\n - reactiveDeterminationExecuted (ReactiveDeterminationExecutionEvent)\n - reactiveDeterminationPendingChange (boolean)\n",
9203
+ "content": "Component ID: praxis-dynamic-form\nSelector: praxis-dynamic-form\nFriendly Name: Praxis Dynamic Form\nDescription: Formulario dinamico com layout por secoes/linhas/colunas e campos renderizados por metadados.\nCategory: form\nLib/Package: @praxisui/dynamic-form\nTags: widget, form, configurable, hasWizard, stable\nInputs:\n - resourcePath (string)\n - resourceId (string | number | null)\n - initialValue (Record<string, unknown> | null)\n - emptyState (PraxisDynamicFormEmptyState | null)\n - editorialContext (Record<string, unknown> | null)\n - mode ('create' | 'edit' | 'view')\n - config (FormConfig)\n - actions (FormConfig['actions'] | null)\n - schemaSource ('resource' | 'filter')\n - schemaUrl (string | null)\n - readUrl (string | null)\n - apiEndpointKey (ApiEndpoint | string | null)\n - apiUrlEntry (ApiUrlEntry | null)\n - submitUrl (string | null)\n - submitMethod ('post' | 'put' | 'patch' | null)\n - submitIdempotencyKey (string | null)\n - submitCorrelationId (string | null)\n - submitResourceVersion (string | number | null)\n - submitResourceVersionTargetResourceKey (string | null)\n - submitResourceVersionTargetIdField (string | null)\n - responseSchemaUrl (string | null)\n - enableCustomization (boolean)\n - showAiAssistant (boolean)\n - formId (string)\n - componentInstanceId (string)\n - configPersistenceStrategy ('local-first' | 'input-first')\n - layout (FormLayout)\n - generatedLayoutPreset ('default' | 'compactPresentation')\n - layoutPolicy (DynamicFormLayoutPolicy | null)\n - backConfig (BackConfig)\n - hooks (FormHooksLayout)\n - removeEmptyContainersOnSave (boolean)\n - reactiveValidation (boolean | null)\n - reactiveValidationDebounceMs (number | null)\n - notifyIfOutdated ('inline' | 'snackbar' | 'both' | 'none')\n - snoozeMs (number)\n - autoOpenSettingsOnOutdated (boolean)\n - readonlyModeGlobal (boolean | null)\n - disabledModeGlobal (boolean | null)\n - presentation (DynamicFormPresentationSnapshot | null)\n - presentationModeGlobal (boolean | null)\n - fieldIconPolicy ('all' | 'presentation-only' | 'none')\n - visibleGlobal (boolean | null)\n - customEndpoints (EndpointConfig)\nOutputs:\n - formSubmit (FormSubmitEvent)\n - formCancel (void)\n - formReset (void)\n - configChange (FormConfig)\n - configPatchChange (DynamicFormConfigPatchChangeEvent)\n - formReady (FormReadyEvent)\n - valueChange (FormValueChangeEvent)\n - payloadPreviewChange (FormPayloadPreviewEvent)\n - syncCompleted (SyncResult)\n - initializationError (FormInitializationError)\n - enableCustomizationChange (boolean)\n - customAction (FormCustomActionEvent)\n - actionConfirmation (FormActionConfirmationEvent)\n - schemaStatusChange ({ outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string })\n - reactiveDeterminationExecuted (ReactiveDeterminationExecutionEvent)\n - reactiveDeterminationPendingChange (boolean)\n",
9188
9204
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/praxis-dynamic-form.metadata.ts",
9189
- "contentHash": "d0faab3d6a0491de78b65c27a2dbcae6086712c98511010fec7384c544a04191",
9205
+ "contentHash": "57063c838a09c8c0eedf363c56552f772223f3ed3159b0cf265f4f88f5a5214d",
9190
9206
  "sourceKind": "component_definition",
9191
9207
  "sourceId": "praxis-dynamic-form",
9192
9208
  "corpusVersion": "1.0.0"
@@ -9604,9 +9620,9 @@
9604
9620
  {
9605
9621
  "chunkIndex": 42,
9606
9622
  "chunkKind": "authoring_manifest",
9607
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"showAiAssistant\",\"type\":\"boolean\",\"description\":\"Mostra os gatilhos do copiloto semantico Praxis\"},{\"name\":\"config\",\"type\":\"FormConfig\",\"description\":\"Configuração do formulário; sections é opcional em forms schema-driven e não deve ser criado como array vazio apenas para satisfazer TypeScript.\"},{\"name\":\"actions\",\"type\":\"FormConfig['actions'] | null\",\"description\":\"Overrides de apresentação da barra de ações fornecidos pelo host sem substituir o contrato HTTP da surface.\"},{\"name\":\"formId\",\"type\":\"string\",\"description\":\"Identidade estável usada pelo runtime para persistência local da configuração.\"},{\"name\":\"resourcePath\",\"type\":\"string\",\"description\":\"Caminho do recurso (API)\"},{\"name\":\"resourceId\",\"type\":\"string | number | null\",\"description\":\"Identidade canônica do registro carregado em modos edit e view.\"},{\"name\":\"emptyState\",\"type\":\"PraxisDynamicFormEmptyState\",\"description\":\"Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host.\"},{\"name\":\"readUrl\",\"type\":\"string\",\"description\":\"Endpoint canonico de leitura para surfaces VIEW/READ_PROJECTION\"},{\"name\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\"],\"description\":\"Modo de operação\"},{\"name\":\"configPersistenceStrategy\",\"type\":\"string\",\"allowedValues\":[\"local-first\",\"input-first\"],\"description\":\"Precedência entre configuração persistida e contrato explícito do host. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor.\"},{\"name\":\"generatedLayoutPreset\",\"type\":\"string\",\"allowedValues\":[\"default\",\"compactPresentation\"],\"description\":\"Preset usado apenas ao gerar a configuracao inicial a partir de metadata/schema; nao reprocessa layouts persistidos ou autorados.\"},{\"name\":\"layoutPolicy\",\"type\":\"DynamicFormLayoutPolicy\",\"description\":\"Politica opt-in para layout schema-driven transient. Use source=schema apenas quando o backend schema for a fonte canonica do agrupamento; use detailSummary para seleção de campos e densidade responsiva do resumo read-only compacto sem FormConfig.sections locais. Quando o resumo precisar vencer x-ui.width publicado para outras surfaces, use detailSummary.widthPrecedence=summary. Em groupedCommand, orphanFieldExpansion governa linhas lógicas com um unico campo; partialRowStrategy=fill-compatible projeta spans compatíveis depois de resolver visibilidade responsiva, CSS order e wrap, sem alterar x-ui.width ou persistir sections; contextFields identifica campos do request hidratados pela surface que permanecem no payload sem criar controles redundantes.\"},{\"name\":\"fieldIconPolicy\",\"type\":\"string\",\"allowedValues\":[\"all\",\"presentation-only\",\"none\"],\"description\":\"Politica visual do host para icones prefix/suffix de campos vindos da metadata. Use presentation-only para manter icones decorativos em apresentacao e ocultar em controles tradicionais.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Habilita edição visual\"}]}",
9623
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"runtimeInputs\",\"runtimeInputs\":[{\"name\":\"showAiAssistant\",\"type\":\"boolean\",\"description\":\"Mostra os gatilhos do copiloto semantico Praxis\"},{\"name\":\"config\",\"type\":\"FormConfig\",\"description\":\"Configuração do formulário; sections é opcional em forms schema-driven e não deve ser criado como array vazio apenas para satisfazer TypeScript.\"},{\"name\":\"actions\",\"type\":\"FormConfig['actions'] | null\",\"description\":\"Overrides de apresentação da barra de ações fornecidos pelo host sem substituir o contrato HTTP da surface.\"},{\"name\":\"formId\",\"type\":\"string\",\"description\":\"Identidade estável usada pelo runtime para persistência local da configuração.\"},{\"name\":\"resourcePath\",\"type\":\"string\",\"description\":\"Caminho do recurso (API)\"},{\"name\":\"resourceId\",\"type\":\"string | number | null\",\"description\":\"Identidade canônica do registro carregado em modos edit e view.\"},{\"name\":\"emptyState\",\"type\":\"PraxisDynamicFormEmptyState | null\",\"description\":\"Authorado em bindings.emptyState no editor; null desliga explicitamente. Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host.\"},{\"name\":\"readUrl\",\"type\":\"string\",\"description\":\"Endpoint canonico de leitura para surfaces VIEW/READ_PROJECTION\"},{\"name\":\"mode\",\"type\":\"string\",\"allowedValues\":[\"create\",\"edit\",\"view\"],\"description\":\"Modo de operação\"},{\"name\":\"presentation\",\"type\":\"DynamicFormPresentationSnapshot | null\",\"description\":\"Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal.\"},{\"name\":\"presentationModeGlobal\",\"type\":\"boolean | null\",\"description\":\"Preferência de exibição, também authorada em bindings.presentationModeGlobal: true apresenta rótulos e valores somente em mode=view; false força campos; null/ausência segue layoutPolicy. Não altera o modo dos dados.\"},{\"name\":\"configPersistenceStrategy\",\"type\":\"string\",\"allowedValues\":[\"local-first\",\"input-first\"],\"description\":\"Precedência entre configuração persistida e contrato explícito do host. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor.\"},{\"name\":\"generatedLayoutPreset\",\"type\":\"string\",\"allowedValues\":[\"default\",\"compactPresentation\"],\"description\":\"Preset usado apenas ao gerar a configuracao inicial a partir de metadata/schema; nao reprocessa layouts persistidos ou autorados.\"},{\"name\":\"layoutPolicy\",\"type\":\"DynamicFormLayoutPolicy\",\"description\":\"Politica opt-in para layout schema-driven transient. Use source=schema apenas quando o backend schema for a fonte canonica do agrupamento; use detailSummary para seleção de campos e densidade responsiva do resumo read-only compacto sem FormConfig.sections locais. Quando o resumo precisar vencer x-ui.width publicado para outras surfaces, use detailSummary.widthPrecedence=summary. Em groupedCommand, orphanFieldExpansion governa linhas lógicas com um unico campo; partialRowStrategy=fill-compatible projeta spans compatíveis depois de resolver visibilidade responsiva, CSS order e wrap, sem alterar x-ui.width ou persistir sections; contextFields identifica campos do request hidratados pela surface que permanecem no payload sem criar controles redundantes.\"},{\"name\":\"fieldIconPolicy\",\"type\":\"string\",\"allowedValues\":[\"all\",\"presentation-only\",\"none\"],\"description\":\"Politica visual do host para icones prefix/suffix de campos vindos da metadata. Use presentation-only para manter icones decorativos em apresentacao e ocultar em controles tradicionais.\"},{\"name\":\"enableCustomization\",\"type\":\"boolean\",\"description\":\"Habilita edição visual\"}]}",
9608
9624
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-dynamic-form-authoring-manifest.ts",
9609
- "contentHash": "026e5d905a34a27a768849d496c260fac5492a51680558bb6bac26e54f1b99cb",
9625
+ "contentHash": "71de795e514367583af30f004099e53c0376010d58718a6b73935e544a090303",
9610
9626
  "sourceKind": "component_definition",
9611
9627
  "sourceId": "praxis-dynamic-form",
9612
9628
  "corpusVersion": "1.0.0"
@@ -9634,9 +9650,9 @@
9634
9650
  {
9635
9651
  "chunkIndex": 45,
9636
9652
  "chunkKind": "authoring_manifest",
9637
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"field.submitPolicy.set\",\"title\":\"Definir política de submissão do campo\",\"scope\":\"field\",\"targetKind\":\"localField\",\"target\":{\"kind\":\"localField\",\"resolver\":\"field-by-name\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"submitPolicy\"],\"properties\":{\"submitPolicy\":{\"enum\":[\"omit\",\"include\",\"includeWhenDirty\"]}}},\"effects\":[{\"kind\":\"merge-by-key\",\"path\":\"fieldMetadata[]\",\"key\":\"name\"}],\"validators\":[\"field-exists\",\"field-is-local\",\"editor-round-trip-preserve\"],\"affectedPaths\":[\"fieldMetadata[].submitPolicy\"],\"submissionImpact\":\"affects-submission\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.visualBlock.add\",\"title\":\"Adicionar bloco visual\",\"scope\":\"column\",\"targetKind\":\"column\",\"target\":{\"kind\":\"column\",\"resolver\":\"column-by-id-in-row\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"document\"],\"properties\":{\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\",\"required\":[\"kind\",\"version\",\"nodes\"],\"properties\":{\"kind\":{\"const\":\"praxis.rich-content\"},\"version\":{\"type\":\"string\"},\"nodes\":{\"type\":\"array\"}}},\"layout\":{\"enum\":[\"block\",\"inline\"],\"default\":\"block\"},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-visual-block-add\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\"],\"writes\":[\"sections[].rows[].columns[].items\"],\"identityKeys\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.sectionId\",\"target.rowId\",\"target.columnId\",\"id\",\"document\"],\"properties\":{\"target.sectionId\":{\"type\":\"string\"},\"target.rowId\":{\"type\":\"string\"},\"target.columnId\":{\"type\":\"string\"},\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\"},\"layout\":{\"enum\":[\"block\",\"inline\"]},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-layout-location-not-found\",\"duplicate-visual-block-id\",\"invalid-rich-content-document\"],\"description\":\"Adds a richContent layout item into sections[].rows[].columns[].items[] by stable section, row, and column ids.\"}}],\"validators\":[\"layout-target-exists\",\"visual-block-id-unique\",\"rich-content-document-valid\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
9653
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.4\",\"componentId\":\"praxis-dynamic-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"field.submitPolicy.set\",\"title\":\"Definir política de submissão do campo\",\"scope\":\"field\",\"targetKind\":\"localField\",\"target\":{\"kind\":\"localField\",\"resolver\":\"field-by-name\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"submitPolicy\"],\"properties\":{\"submitPolicy\":{\"enum\":[\"omit\",\"include\",\"includeWhenDirty\"]}}},\"effects\":[{\"kind\":\"merge-by-key\",\"path\":\"fieldMetadata[]\",\"key\":\"name\"}],\"validators\":[\"field-exists\",\"field-is-local\",\"editor-round-trip-preserve\"],\"affectedPaths\":[\"fieldMetadata[].submitPolicy\"],\"submissionImpact\":\"affects-submission\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.visualBlock.add\",\"title\":\"Adicionar bloco visual\",\"scope\":\"column\",\"targetKind\":\"column\",\"target\":{\"kind\":\"column\",\"resolver\":\"column-by-id-in-row\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"document\"],\"properties\":{\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\",\"required\":[\"kind\",\"version\",\"nodes\"],\"properties\":{\"kind\":{\"const\":\"praxis.rich-content\"},\"version\":{\"type\":\"string\"},\"nodes\":{\"type\":\"array\"}}},\"layout\":{\"enum\":[\"block\",\"inline\"],\"default\":\"block\"},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-visual-block-add\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\"],\"writes\":[\"sections[].rows[].columns[].items\"],\"identityKeys\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.sectionId\",\"target.rowId\",\"target.columnId\",\"id\",\"document\"],\"properties\":{\"target.sectionId\":{\"type\":\"string\"},\"target.rowId\":{\"type\":\"string\"},\"target.columnId\":{\"type\":\"string\"},\"id\":{\"type\":\"string\"},\"document\":{\"type\":\"object\"},\"layout\":{\"enum\":[\"block\",\"inline\"]},\"rootClassName\":{\"type\":[\"string\",\"null\"]},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-layout-location-not-found\",\"duplicate-visual-block-id\",\"invalid-rich-content-document\"],\"description\":\"Adds a richContent layout item into sections[].rows[].columns[].items[] by stable section, row, and column ids.\"}}],\"validators\":[\"layout-target-exists\",\"visual-block-id-unique\",\"rich-content-document-valid\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
9638
9654
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-dynamic-form-authoring-manifest.ts",
9639
- "contentHash": "167125364e267e04c128dc4d5d1fb1d7d137d0ed5b0c05cb8d13b5aac48b8d4c",
9655
+ "contentHash": "fece171cf8179191d5448ab3636e71b44d885256e63764ef75f11f002bef984c",
9640
9656
  "sourceKind": "component_definition",
9641
9657
  "sourceId": "praxis-dynamic-form",
9642
9658
  "corpusVersion": "1.0.0"
@@ -16839,7 +16855,7 @@
16839
16855
  "type": "string"
16840
16856
  },
16841
16857
  "span": {
16842
- "type": "number",
16858
+ "type": "integer",
16843
16859
  "minimum": 1,
16844
16860
  "maximum": 12,
16845
16861
  "default": 6
@@ -17464,9 +17480,9 @@
17464
17480
  {
17465
17481
  "chunkIndex": 32,
17466
17482
  "chunkKind": "authoring_manifest",
17467
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
17483
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.0.0\",\"componentId\":\"praxis-filter-form\",\"ownerPackage\":\"@praxisui/dynamic-form\",\"configSchemaId\":\"FormConfig\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"layout.section.add\",\"title\":\"Adicionar nova seção\",\"scope\":\"global\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\",\"title\"],\"properties\":{\"id\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"icon\":{\"type\":\"string\"},\"collapsible\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[]\",\"key\":\"id\"}],\"validators\":[\"section-id-unique\"],\"affectedPaths\":[\"sections[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\"]},{\"operationId\":\"layout.section.remove\",\"title\":\"Remover seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{}},\"effects\":[{\"kind\":\"remove-by-key\",\"path\":\"sections[]\",\"key\":\"id\"},{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-section-cleanup\",\"handlerContract\":{\"reads\":[\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[]\"],\"identityKeys\":[\"sections[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.id\"],\"properties\":{\"target.id\":{\"type\":\"string\"}}},\"failureModes\":[\"target-section-not-found\",\"ambiguous-section-target\"],\"description\":\"Removes the target section and its nested rows, columns, and field placements without deleting fieldMetadata records.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"section-exists\"],\"affectedPaths\":[\"sections[]\",\"sections[].rows[]\",\"sections[].rows[].columns[]\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.row.add\",\"title\":\"Adicionar linha numa seção\",\"scope\":\"section\",\"targetKind\":\"section\",\"target\":{\"kind\":\"section\",\"resolver\":\"section-by-id-or-title\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"columns\":{\"type\":\"number\",\"minimum\":1,\"maximum\":12,\"default\":1}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[]\",\"key\":\"id\"}],\"validators\":[\"section-exists\",\"row-id-unique-in-section\"],\"affectedPaths\":[\"sections[].rows[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.column.add\",\"title\":\"Adicionar coluna numa linha\",\"scope\":\"row\",\"targetKind\":\"row\",\"target\":{\"kind\":\"row\",\"resolver\":\"row-by-id-in-section\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"id\"],\"properties\":{\"id\":{\"type\":\"string\"},\"span\":{\"type\":\"integer\",\"minimum\":1,\"maximum\":12,\"default\":6}}},\"effects\":[{\"kind\":\"append-unique\",\"path\":\"sections[].rows[].columns[]\",\"key\":\"id\"}],\"validators\":[\"row-exists\",\"column-id-unique-in-row\"],\"affectedPaths\":[\"sections[].rows[].columns[]\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]},{\"operationId\":\"layout.field.move\",\"title\":\"Mover campo no layout\",\"scope\":\"field\",\"targetKind\":\"field\",\"target\":{\"kind\":\"field\",\"resolver\":\"field-by-name-or-label\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"form-layout-reconciler\",\"handlerContract\":{\"reads\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\",\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"writes\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"identityKeys\":[\"fieldMetadata[].name\",\"sections[].id\",\"sections[].rows[].id\",\"sections[].rows[].columns[].id\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"target.name\",\"targetSectionId\",\"targetRowId\",\"targetColumnId\"],\"properties\":{\"target.name\":{\"type\":\"string\"},\"targetSectionId\":{\"type\":\"string\"},\"targetRowId\":{\"type\":\"string\"},\"targetColumnId\":{\"type\":\"string\"},\"index\":{\"type\":\"number\"}}},\"failureModes\":[\"target-field-not-found\",\"target-layout-location-not-found\",\"ambiguous-field-target\",\"duplicate-field-placement\"],\"description\":\"Moves a field placement by stable section, row, column, and field ids; index is insertion position only.\"}}],\"validators\":[\"field-exists\",\"layout-target-exists\",\"no-index-as-identity\",\"field-exists-in-layout\"],\"affectedPaths\":[\"sections[].rows[].columns[].items\",\"sections[].rows[].columns[].fields\"],\"submissionImpact\":\"visual-only\",\"preconditions\":[\"config-initialized\",\"target-exists\"]}]}",
17468
17484
  "sourcePointer": "projects/praxis-dynamic-form/src/lib/ai/praxis-filter-form-authoring-manifest.ts",
17469
- "contentHash": "93f7c41675e8f3868d1880542f7fd505b3f50ed9140411b08a0896223e2ae35c",
17485
+ "contentHash": "ec4cfc7906dbafd61eeadc04bc4d6212c2dd89e144e06c6291e9318a98f389d8",
17470
17486
  "sourceKind": "component_definition",
17471
17487
  "sourceId": "praxis-filter-form",
17472
17488
  "corpusVersion": "1.0.0"
@@ -0,0 +1,49 @@
1
+ # Optional action text: editor validation
2
+
3
+ Classification: `local-pequena`; fit: `ja-suportado-mal-nomeado-ou-mal-materializado`.
4
+ Owner: Dynamic Form actions editor. The existing FormActionButton and action
5
+ layout properties already represent optional text. Native text inputs bound
6
+ directly to absent values displayed the literal `undefined`.
7
+
8
+ The editor now projects nullish text as an empty input for default/custom action
9
+ labels, icons, shortcuts, tooltips, identifiers and CSS classes. This is a display
10
+ fallback, not configuration normalization: opening tabs emits no config change,
11
+ untouched optional properties remain absent, and host strings (including a literal
12
+ `undefined`) remain strings. Explicit editing and clearing keep the existing
13
+ configChange semantics. No CSS, token, translation, permission or execution rule
14
+ changed.
15
+
16
+ Validation:
17
+
18
+ - 11 focused ActionsEditorComponent tests passed, including DOM rendering across
19
+ all three tabs, no mutation on open, and editing/clearing without materializing
20
+ untouched optional properties. An initial test fixture omitted required
21
+ `visible`; the fixture was corrected before the successful run.
22
+ - Dynamic Form production build and git diff whitespace check passed.
23
+ - Internal browser at `http://localhost:4003/page-builder-ia`, dark desktop,
24
+ 1375 × 912: opened Actions → Custom buttons → added a temporary button → expanded
25
+ it. Icon, tooltip, shortcut and CSS class rendered empty. Editing tooltip was
26
+ reflected in the visual JSON document, with the other three properties absent.
27
+ Cancel/discard closed the temporary draft without Apply or Save.
28
+ - Selecting Ayla Hayes in the table loaded the matching presentation form.
29
+ - The existing browser tab subsequently stopped responding while switching
30
+ selection/mode, including to reload. That sequence is not counted as validated;
31
+ no causal connection to the text fallback was established.
32
+ - Recovery used a fresh internal tab on the same official route. At 1280 × 720
33
+ with editing off, Ayla loaded successfully, then selecting Jonah updated the
34
+ identity, contact and professional values to Jonah after the loading state.
35
+ The presentation remained read-only. The recovered tab was left open showing
36
+ the details. This confirms the fresh-session selection flow, not resolution of
37
+ the previous long-session responsiveness failure.
38
+ - Subsequent investigation identified and corrected a shared translation lookup
39
+ bottleneck, while reproducing an unresolved edit-exit transition; see the
40
+ [performance investigation](../../praxis-core/docs/i18n-editor-performance-2026-09-08.md).
41
+ - Read-only API comparison confirmed the saved page was identical to the baseline
42
+ before this turn. No employee data was written.
43
+
44
+ This cycle does not certify mobile, the full workspace, live AI flows or a new
45
+ persistence round-trip. The correction changes neither accepted paths nor public
46
+ types/manifests; public API, authoring manifest and existing custom-action E2E
47
+ coverage were reviewed. README guidance was updated. No registry, HTTP corpus or
48
+ landing artifact regeneration is needed. Existing skill guidance already requires
49
+ canonical value preservation and visual checks; no new skill contract was needed.