@praxisui/table 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
@@ -2,14 +2,77 @@
2
2
 
3
3
  Enterprise data table for Praxis UI applications.
4
4
 
5
+ Opt-in responsive record cards (`appearance.responsive.mobile.cardMode`) adapt to
6
+ the narrower of the viewport and the table host, including resized desktop widgets.
7
+ The existing mobile breakpoint is reused; virtualization and horizontal-scroll
8
+ policy are unchanged. At up to 480 px of internal width, labels stack above values.
9
+ Selection decoration does not replace field labels. No column is removed by this
10
+ adaptation. The config editor no longer displays an informational version banner
11
+ over actionable diagnostics.
12
+
13
+ In card mode, an intentionally empty action-column heading does not reserve a
14
+ label row or extra vertical padding. Explicit action headings remain visible,
15
+ and the action buttons retain their configured dimensions. Selection keeps its
16
+ own accessible control area; this refinement does not reorder business fields.
17
+
18
+ The checked row-selection radio inherits `--p-table-row-selected-fg` in its normal,
19
+ hover, focus and pressed states, including responsive cards. Disabled and unselected
20
+ radios keep Material's state tokens. Custom themes must maintain sufficient contrast
21
+ between the selected-row foreground and background; the built-in light/dark themes
22
+ are covered by a real-backend regression with a minimum 3:1 indicator contrast.
23
+
24
+ Table action authoring projects session availability out of `toolbar.actions`,
25
+ `actions.row.actions`, `actions.bulk.actions` and nested action `children` before
26
+ editor normalization and portable persistence. Internal `__praxis*` action fields
27
+ are runtime-only; business payloads remain intact. Collection availability preserves
28
+ an explicit host `disabled: true`, and a temporary denial does not become an authored
29
+ restriction when a label or order changes. Older snapshots with an ambiguous denial
30
+ retain `disabled: true`; raw-document validation reports
31
+ `table.action.disabled.origin.unknown`, and portable runtime projection logs that
32
+ diagnostic. Review those older settings explicitly instead of inferring permission.
33
+ See [the implementation evidence](test-dev/action-authoring-projection-result-2026-09-08.md).
34
+ The toolbar editor also compares its initial and edited projections before emitting
35
+ configuration: changing an action label must not materialize export, row-action or
36
+ layout defaults. Untouched host settings remain inherited, while explicit control
37
+ changes retain their derived behavior (for example, hybrid row-action display).
38
+ The [live authoring journey](test-dev/action-authoring-live-roundtrip-2026-09-08.md)
39
+ records the persisted-page comparison and validation.
40
+ Action editor text belongs to the `praxisTableEditor` namespace: quick-add and selected
41
+ action inputs have distinct label keys, and target/selection-limit controls have pt-BR
42
+ and en-US translations. Host translators can override this chrome without changing
43
+ the authored business action label. See [copy validation](test-dev/action-authoring-copy-2026-09-08.md).
44
+ The JSON tab follows visual edits while its text is an untouched projection. Pending
45
+ manual JSON, including incomplete or empty text, is preserved on document updates;
46
+ after applying it and receiving the host acknowledgement, visual synchronization
47
+ resumes. See the [selection-to-surface journey and regression proof](test-dev/view-action-surface-journey-2026-09-08.md).
48
+
5
49
  Use this package to render local or backend-driven data grids with `TableConfig`, filtering, sorting, pagination, selection, row actions, visual rules, configurable toolbar, rich detail rows, and optional AI-assisted authoring.
6
50
 
51
+ On remote pagination, selection is cleared and the existing `selectionChange`
52
+ event is emitted before requesting the new page when both
53
+ `behavior.selection.persistSelection` and `persistOnDataUpdate` are disabled
54
+ (or omitted). Connected detail views therefore leave the previous record context
55
+ during loading, including when that request later fails or is cancelled. Enabling
56
+ either policy preserves the selection during loading: `persistSelection` retains
57
+ cross-page selection, while `persistOnDataUpdate` reconciles it against the rows
58
+ returned by the new page. Local pagination keeps its synchronous reconciliation.
59
+ This timing change is specific to pagination; it does not redefine filter or
60
+ sort transitions, permissions, or action availability.
61
+
7
62
  Item workflow actions discovered through resource capabilities/action catalogs are executable
8
63
  runtime contracts. When an action publishes `execution`, the table materializes its canonical
9
64
  Dynamic Form surface, propagates the row version declared by `resourceVersionField`, and applies
10
65
  the backend-authored refresh policy after success. Hosts should not recreate these actions from
11
66
  button labels, HTTP methods, or local version-field aliases.
12
67
 
68
+ In a standalone table, the discovered native `view`/`byId` capability opens a readonly
69
+ Dynamic Form through `surface.open`, using the canonical item read and response schema.
70
+ Named record surfaces retain their declared identity, path and schema. Inside a CRUD host,
71
+ native view continues to delegate through `rowAction`; explicit global actions keep precedence.
72
+ The host must provide the surface runtime/drawer bridge and authorize the declared item and
73
+ schema reads. The table forwards its originating injector and trigger focus only in ephemeral
74
+ runtime context, never in authored configuration or API payloads.
75
+
13
76
  Collection workflow actions follow the same contract and are materialized in the toolbar. The
14
77
  table requires a row selection only when the action publishes `selection.idsField` or uses
15
78
  `SELECTION_MAP`; an unrelated current selection is never injected into a selection-independent
@@ -87,6 +150,14 @@ export class LocalTableComponent {
87
150
 
88
151
  ## Minimum Remote Runtime
89
152
 
153
+ For discovered standalone collection create, Table suppresses disabled/denied
154
+ actions and coalesces concurrent opening attempts for the same resource and
155
+ surface while opening is pending. The guard is released after success or failure;
156
+ it does not implement HTTP idempotency or prevent a later deliberate opening.
157
+ A selected surface failure shows localized feedback and never emits a second
158
+ toolbar action as a fallback. CRUD-hosted tables retain CRUD ownership. Diagnostics
159
+ keep correlation and the error type, not arbitrary provider exception messages.
160
+
90
161
  Use `resourcePath` when the host wants the table to enter backend schema/data mode.
91
162
 
92
163
  ```html
@@ -144,6 +215,14 @@ When the collection response exposes `_links.create` or a collection `capabiliti
144
215
 
145
216
  Selector and lookup surfaces can keep the same remote `resourcePath`, schema, pagination and read capabilities while opting out of collection action materialization with `actions.collection.discovery.enabled = false`. The policy suppresses only collection actions discovered from HATEOAS/capabilities, including canonical create and collection workflows. Explicit toolbar actions and configured row actions remain unchanged. Omission preserves the default enabled behavior.
146
217
 
218
+ ## Configuration ownership in Page Builder
219
+
220
+ Use the **Tabela da página** catalog preset when the page owns the table configuration. It sets the existing `configPersistenceStrategy: 'input-first'`, so an older saved `table-config` does not replace the authored input on reload. In **Configurar conteúdo**, the configuration source selector makes this choice explicit; filter edits in its **Filtros** tab belong to `config.behavior.filtering.advancedFilters.settings` and are saved with the widget/page.
221
+
222
+ The runtime default remains `local-first`, which loads saved table preferences. `volatile` is intended for temporary surfaces that neither load nor save persistent table configuration. `input-first` prioritizes the input for table configuration hydration; it does not mean every independent runtime preference is disabled.
223
+
224
+ The native filter **Preferências do Filtro** panel uses its own `filter-config` preference lane. Its saved always-visible order does not override a nonempty `alwaysVisibleFields` supplied by the page. Use the Page Builder content editor to author the page's filters. Editing a field opens a child settings panel and preserves the parent draft; save the child, then its parent and the page to persist authored changes.
225
+
147
226
  ## Runtime Inputs And Outputs
148
227
 
149
228
  Common inputs:
@@ -195,6 +274,11 @@ When row selection is enabled with `mode: "row"` or `mode: "both"`, selectable
195
274
  rows use a single roving keyboard stop. `ArrowUp`, `ArrowDown`, `Home`, and `End`
196
275
  move focus without changing the selection; `Enter` and `Space` activate the
197
276
  focused row through the same `selectionChange` contract used by pointer input.
277
+ For the single-selection radio, native input, label and enlarged touch-target
278
+ activation all select through Material's `change` event and emit one canonical
279
+ selection update. Re-clicking the checked radio retains the selection. The
280
+ existing Space shortcut on the radio can still select or clear it; checkbox and
281
+ explicit row-toggle paths retain their own toggle behavior.
198
282
  Navigation is resolved against the table data model rather than the rows currently
199
283
  mounted in the DOM. In virtualized tables, `Home` and `End` therefore reach the
200
284
  first and last logical records and scroll the viewport before restoring focus.
@@ -266,6 +350,13 @@ Use `config.ai.assistant.enabled = false` when a host needs to disable the embed
266
350
 
267
351
  Use `behavior.emptyState` for table-owned no-data copy and presentation. `message` remains the required backward-compatible text. When `title` is omitted, `message` is used as the empty-state title. When `title` is provided, `message` is rendered as the description unless `description` is explicitly set.
268
352
 
353
+ The no-data region follows its content height. It delegates alignment, variant,
354
+ density and internal spacing to the shared `praxis-empty-state-card`, without
355
+ forcing a centered transparent card or reserving viewport-based height. Existing
356
+ `--pdx-empty-state-*` theme tokens remain available for the card; the surrounding
357
+ table surface uses the table background and border tokens. The default
358
+ presentation remains centered, compact and transparent.
359
+
269
360
  When the host does not provide `behavior.emptyState` or legacy `messages.states` copy, the table uses localized runtime defaults for the initial empty collection and for the filtered/search no-results state. Context-specific entries in `behavior.emptyState.contexts.initial`, `behavior.emptyState.contexts.filtered`, and `behavior.emptyState.contexts.searched` still override the base empty state for those modes.
270
361
 
271
362
  For related resources, the generated empty state is informational and does not repeat the capability-governed CREATE action already kept stable in the toolbar. Declare `behavior.emptyState.actions` only when the journey intentionally needs a distinct contextual action; explicit host actions are preserved. Empty-state and toolbar actions share the public `--praxis-action-control-*` geometry, while `toolbar.appearance.tokens.actionSize` and `actionRadius` remain the stronger per-table overrides.
@@ -286,6 +377,16 @@ const config: TableConfig = {
286
377
 
287
378
  ## Toolbar Appearance
288
379
 
380
+ When a containing Widget Shell already owns the title and resource identity, omit
381
+ the table's `toolbar.title`, `toolbar.subtitle`, and `toolbar.icon` and keep
382
+ `toolbar: { visible: true }`. The toolbar can render commands without its identity
383
+ block. Do not use `visible: false` to deduplicate headings: resource discovery may
384
+ materialize a capability-governed CREATE action and make the toolbar visible.
385
+ Preserve those actions, their availability, and their accessible disabled reasons.
386
+ For nested compositions, bind the shell identity to the propagated canonical
387
+ resource identity and verify it after selection changes and in fullscreen; matching
388
+ configuration alone does not prove that the correct record is presented.
389
+
289
390
  Use `toolbar.appearance` for governed toolbar chrome instead of host CSS targeting internal classes. The built-in preset `table-integrated` composes toolbar and table as one operational block using public tokens for background, border, radius, shadow, spacing, and density.
290
391
 
291
392
  ```ts
@@ -315,6 +416,11 @@ commands are consolidated under one localized `Mais ações` entrypoint without
315
416
  density controls. At narrow widths the first band preserves identity and commands before the scope and
316
417
  query bands, so keyboard focus follows the same reading order presented visually.
317
418
 
419
+ At up to 540 px of toolbar width, identity and the compact command menu share a
420
+ row when no scope region is present; query controls keep their full-width row.
421
+ With scope present, the existing separate bands remain. Long identities retain
422
+ the existing truncation/tooltip behavior rather than overlapping the menu.
423
+
318
424
  Authoring guidance:
319
425
 
320
426
  - use `toolbar.filters.quickFilters` for a small governed scope switch, not as a substitute for every filter;
@@ -353,6 +459,11 @@ The package exports both the table runtime and `PraxisFilter` integration surfac
353
459
  `aria-disabled="true"`, keep execution fail-closed, and announce the contextual disabled reason before
354
460
  the configured operation tooltip. In the compact overflow menu, the same reason is rendered inline so
355
461
  understanding the unavailable command never depends on hovering or focusing a native disabled menu item.
462
+ - When runtime discovery publishes a denied capability, workflow action or surface, toolbar explanations
463
+ use its canonical availability reason from Core’s `resourceDiscovery` translations. Authentication and
464
+ permission denials take precedence over selection guidance. Table locale and host translation overrides
465
+ remain supported; unknown codes use the generic canonical message rather than exposing internal codes.
466
+ An available form surface does not override a denied create operation. This copy does not grant permission.
356
467
  - Inline and overflow actions preserve their actionable origin. Overflow menus finish closing and restore the trigger before emitting the action, allowing dialogs and drawers with `restoreFocus` to return keyboard focus to the correct table control.
357
468
 
358
469
  The filter field manager follows the compact inline visual language and can be themed by hosts through
@@ -375,14 +486,18 @@ control when the operating system displays the thumb. Because the manager render
375
486
  such as `html`, `body`, or the application theme class rather than only on the `praxis-filter` element.
376
487
  When using the `PraxisFilter` i18n input, `selectedFieldsSectionTitle` and
377
488
  `availableFieldsSectionTitle` customize the grouped field-manager headings; both are optional and
378
- default to the Portuguese runtime labels. Each manageable field preserves its authored
489
+ default to the Portuguese runtime labels. The trigger count includes fixed and selected filters.
490
+ Inside the manager, **Campos fixos**, **Campos selecionados** and **Campos disponíveis** state the
491
+ three distinct roles; the selected-section summary counts only the customizable selection. Its
492
+ `selectedFieldsCount` and `selectedFieldsCountSingular` text remains overridable through the same
493
+ i18n input. Each manageable field preserves its authored
379
494
  `FieldMetadata.description` (falling back to its explicit tooltip/help metadata) as an information
380
495
  tooltip on hover and keyboard focus. This lets operators distinguish semantically different filters
381
496
  with similar labels—such as a single date, a date range, and a relative period—without the table
382
497
  runtime fabricating domain guidance.
383
498
 
384
499
  While the field manager is open, its selected and available sections preserve the composition they
385
- had when the draft began. Checkbox state, the displayed-field count, pending-change badges, and the
500
+ had when the draft began. Checkbox state, the selected-field summary, pending-change badges, and the
386
501
  Apply count update immediately, but rows are regrouped only after Apply closes the overlay or when it
387
502
  is opened again. This keeps pointer position, keyboard focus, and scroll anchoring stable. Optional
388
503
  `PraxisFilter.i18n` entries `fieldPendingAddition`, `fieldPendingRemoval`,
@@ -415,6 +530,25 @@ const config: TableConfig = {
415
530
 
416
531
  Use `PraxisTableConfigEditor` or the table settings surfaces when `enableCustomization` is true.
417
532
 
533
+ For `surface.open` actions, invalid input/context JSON remains an unsaved draft:
534
+ the owning editor combines the subeditor's `validationChange` with its other
535
+ validation sources and blocks Apply/Save. Switching tabs preserves the draft;
536
+ correct it or use Cancel/discard before switching or replacing actions. Raw invalid
537
+ text is never included in the settings document. See the
538
+ [Core validation evidence and rollout boundary](../praxis-core/docs/surface-invalid-drafts-validation-2026-09-08.md).
539
+
540
+ In **Overview and behavior → Narrow screens** (Portuguese: **Visão geral e
541
+ comportamento → Telas estreitas**), choose **Cards** and set the maximum width in
542
+ pixels. The native editor and the Page Builder content editor use the existing
543
+ `appearance.responsive.mobile.cardMode` and `appearance.responsive.breakpoints.mobile`
544
+ properties. Missing width defaults to 768 px. The control accepts positive whole
545
+ numbers; invalid drafts block apply/save without replacing the last valid document.
546
+ Switching back to Table keeps other responsive preferences and column priorities.
547
+ Cards retain visible fields, row selection and actions; virtualization keeps the
548
+ standard table renderer. Selection still follows the authored connections and does
549
+ not implicitly navigate to an offscreen detail widget.
550
+
551
+
418
552
  Main authoring areas include:
419
553
 
420
554
  - columns
@@ -426,6 +560,8 @@ Main authoring areas include:
426
560
  - value mapping
427
561
  - JSON config editing
428
562
 
563
+ The runtime loads `PraxisTableConfigEditor` only when `openTableSettings()` reaches the native table authoring flow. Rendering a table does not eagerly materialize the editor chunk; delegated CRUD authoring also returns before that chunk is requested.
564
+
429
565
  The package exports separate governed contracts for the two authoring documents: `PRAXIS_TABLE_AUTHORING_MANIFEST` owns `TableConfig`, including embedded filtering under `behavior.filtering`, while `PRAXIS_FILTER_AUTHORING_MANIFEST` owns the standalone `FilterConfig`. The standalone manifest never persists the controlled `value` DTO and does not expose Table query-builder operations or the nominal `submit` alias. `TABLE_AI_CAPABILITIES` / `TABLE_COMPONENT_AI_CAPABILITIES` remain the component capability discovery surface for the Table aggregate.
430
566
 
431
567
  Canonical table refinements preserve business meaning across preview, persistence, reopen and runtime rendering:
@@ -482,3 +618,55 @@ Main exports:
482
618
  - When `excel` is enabled in `export.formats`, the toolbar also exposes a current-page Excel export that downloads only the rows currently loaded in the table runtime with visible columns and formatted cell values. Full filtered exports continue to use the configured collection export provider.
483
619
  - Theme the table through Material/Praxis tokens instead of targeting internal descendants.
484
620
  - Use the official documentation for full recipes on filters, rich detail rows, rules, formatting, AI authoring, and backend capabilities.
621
+
622
+ ### Authoring de tabela e filtro no Page Builder
623
+
624
+ O editor de conteúdo da tabela recebe a configuração efetiva em contexto transitório. Ao salvar, aplica apenas as mudanças autoradas, preservando paginação e renderizadores derivados do schema. Essa projeção não é copiada integralmente para o documento.
625
+
626
+ O editor do filtro permite selecionar o recurso e carregar seus campos pelo schema de filtro canônico. `resourcePath` e preferências visuais são persistidos; os metadados carregados permanecem derivados da API.
627
+
628
+ Ao receber novos `filterCriteria` ou `queryContext` de outro widget, a consulta remota reinicia na página zero. Para um recurso paginado, selecione estratégia de paginação `server` no editor; a estratégia cliente continua sendo uma opção explícita para dados locais.
629
+
630
+ ## Filter heading and advanced-action presentation
631
+
632
+ Tables and standalone filters share Core `FilterPresentationConfig`. Configure an optional heading above or inline with the filters and present the advanced action as icon, text, or both. Heading visibility is opt-in; omitting presentation preserves the existing appearance. Action placement stays within the auxiliary controls group. It does not move table actions or change filter values.
633
+
634
+ For tables use `config.behavior.filtering.advancedFilters.settings.presentation`; for standalone filters use `FilterConfig.presentation` (runtime input `presentation`). The guided editor exposes semantic choices, while the optional nine `--pfx-filter-*` tokens support theme customization. See [the canonical JSON API](src/lib/praxis-table.json-api.md#filter-presentation) for the exact fields, defaults and token list.
635
+
636
+ When filter persistence is enabled, a presentation acknowledged by **Save and close** is restored over the authored page baseline for the same component identity. **Apply** changes only the current preview. Set `disablePersistence` when the host must always materialize the authored input and must not read or write user filter preferences.
637
+
638
+ The preferences editor carries the complete effective filter document through Apply and Save. Editing presentation, layout or behavior therefore preserves `selectedFieldIds` and metadata overrides owned by the same preference record.
639
+
640
+
641
+ ## Ciclo de vida dos editores do filtro
642
+
643
+ Os painéis de preferências e de metadados são vinculados ao `DestroyRef` da origem
644
+ pelo contrato `owner` do Settings Panel. Remover a origem encerra seus painéis e
645
+ as assinaturas de Apply/Save. Um carregamento lazy concluído após a destruição
646
+ do pai não abre um editor filho. O host deve destruir efetivamente o componente
647
+ quando sua origem deixa de existir, em vez de apenas ocultá-lo por CSS.
648
+
649
+ Salvar metadados no editor filho altera o rascunho do pai; a gravação da configuração
650
+ continua pertencendo ao fluxo de Save do filtro. Destruir a origem não inicia Save
651
+ e não implica cancelar requisições de gravação já iniciadas legitimamente.
652
+
653
+
654
+ ### Confirmação de Save nas preferências do filtro
655
+
656
+ O painel aguarda a conclusão do storage antes de fechar. Apply permanece uma
657
+ prévia sem gravação; erros de Save mantêm o rascunho aberto para nova tentativa.
658
+ Conflitos 409/412 não são sobrescritos automaticamente. Alterações feitas durante
659
+ uma requisição também permanecem abertas após a confirmação da versão enviada.
660
+ O cache local de FilterConfigService é atualizado ou removido somente após sucesso
661
+ de Save/Clear. A garantia corresponde ao storage configurado: o adapter local não
662
+ constitui confirmação de gravação no backend.
663
+
664
+
665
+ ### Navegação em painéis estreitos
666
+
667
+ A adaptação de authoring considera a largura do contêiner, inclusive quando o
668
+ painel é estreito em uma janela desktop. Table e Dynamic Form exibem “Seção do
669
+ editor” até 768px de largura disponível, mantendo a mesma seleção e os conteúdos
670
+ das abas. Acima desse limite, reaparece a navegação por abas. O Settings Panel
671
+ organiza título, expandir e fechar em uma grade até 599px; a prévia, quando
672
+ suportada, ocupa a linha seguinte. Nenhum documento ou protocolo de Save é alterado.