fix(ui): unify heading help, table sizing and navigation contracts

Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
This commit is contained in:
2026-09-09 02:03:16 +02:00
parent 6591aaa3fd
commit 6d37aa527f
54 changed files with 1728 additions and 117 deletions
+49 -6
View File
@@ -4,6 +4,12 @@ This document defines the binding composition grammar for headed GovOPlaN
pages. Core owns the reusable anatomy; each module owns its domain actions,
wording, authorization, consequences, and data state.
The cross-product [UI design principles](UI_DESIGN_PRINCIPLES.md) define the
display-first editing model, heading-adjacent help, and module-review process.
Normal overview/detail surfaces show readable facts; edit coherent settings in
scoped dialogs. Use an explicit editor mode for a justified broad-editing task,
not merely because a page also offers filters or contains an edit dialog (UI-02).
## Required Page Frame
- Use `PageLayout` for every headed standalone, workspace, or embedded page.
@@ -69,11 +75,19 @@ page or pane action bar.
| Page kind | Leading group | Trailing group |
| --- | --- | --- |
| Overview | Context | Help, Reload when refreshable, then ordinary primary actions |
| Collection | Collection context such as export | Help, Reload when refreshable, then Create at the far right |
| Detail | Object context | Help, Reload when refreshable, ordinary primary actions, then a separated destructive group |
| Editor | Context | Dirty state, Help, Reload if distinctly safe, ordinary primary actions, separated destructive actions, Discard, then Save at the far right |
| Workspace | Task context | Help, Reload when refreshable, ordinary primary actions, then a separated destructive group |
| Overview | Context | Reload when refreshable, then ordinary primary actions |
| Collection | Collection context such as export | Reload when refreshable, then Create at the far right |
| Detail | Object context | Reload when refreshable, ordinary primary actions, then a separated destructive group |
| Editor | Context | Dirty state, Reload if distinctly safe, ordinary primary actions, separated destructive actions, Discard, then Save at the far right |
| Workspace | Task context | Reload when refreshable, ordinary primary actions, then a separated destructive group |
Documentation is associated with text, not an action-group slot (UI-01). Put
`DocumentationHelpLink` in the heading component's `titleHelp`, use `TextWithHelp`
for existing contextual words, and retain `FormField`/`FieldLabel` documentation
beside field labels. Full-canvas `WorkspaceActionBar` surfaces can supply `title`
and `titleHelp` together on the leading side. Do not duplicate a heading or use
`helpAction` for a detached documentation icon. See the shared principle for
card/dialog accessibility and examples.
Reload and Create belong to the same right-aligned group, in that order. A
collection-wide toolbar stays above its workspace, not inside the left tree or
@@ -82,12 +96,40 @@ not remove it. Permission-blocked creation remains visible with an explanation.
On narrow screens the trailing group wraps while retaining right alignment and
the same DOM/keyboard order.
An editor's **Cancel/Close** action is not the same as **Reset/Discard changes**.
When it exits an editing mode, set `discardAction.behavior` to `"exit"`: it stays
enabled for a clean draft, while Save remains disabled until there are changes.
The default `"reset"` behavior still requires changes. Both stay blocked during
an in-flight save; the owning page must use the shared discard confirmation before
exiting a dirty draft. Never require a meaningless edit just to leave configuration.
Deutsch: Abbrechen oder Schließen beendet den Bearbeitungsmodus auch ohne
Änderungen (`discardAction.behavior="exit"`). Zurücksetzen setzt dagegen einen
geänderten Entwurf voraus. Beim Abbrechen eines geänderten Entwurfs vor dem
Verwerfen nachfragen; eine laufende Speicherung bleibt geschützt.
Use `Card bodyLayout="table"` for table surfaces, including tables wrapped by
`LoadingFrame`. This removes body padding explicitly, without relying on the
number of children or negative margins. Place any meaningful explanation or
warning in a padded `ContentSection`; do not add a redundant tagline to every
table. Use `ContentGrid` for sibling cards so spacing does not depend on fragments.
The shared stylesheet also recognizes existing table-only card bodies, either
directly or through `LoadingFrame`; loading must not add an inset, expand the
overlay outside the card, or change the table's measured width. Keep the table
at 100% of its container. Do not reintroduce module-local negative margins,
expanded `calc()` widths, or padding overrides to make a table fit. Mixed
content cards retain their normal padding unless they explicitly declare the
table layout. The browser conformance matrix checks all four card edges,
loading/collapse transitions, scrolling, and row actions at desktop and mobile
widths.
Deutsch: Tabellen belegen den Karteninhalt ohne zusätzlichen Innenabstand,
auch während des Ladens. Neue Tabellenkarten verwenden ausdrücklich
`bodyLayout="table"`; ergänzende Hinweise erhalten ihren eigenen Innenabstand.
Negative Ränder oder modulbezogene Breitenkorrekturen sind nicht nötig.
Karten mit gemischtem Text- oder Formularinhalt behalten ihre normalen Abstände.
Use `MultiSelectFilter` for standalone list facets. It and DataGrid share the
same checkbox body and Select all / Deselect all behavior. `null` means no
restriction, `[]` means no matches, and multiple values mean OR within a facet.
@@ -136,7 +178,8 @@ to fill the slot.
Editor bars always keep Discard and Save visible. Their required `state`
projection is one of `clean`, `dirty`, `invalid`, `saving`, `save-failed`, or
`conflict`, and the central component announces it through a live status label.
Clean and saving states disable both persistence actions; invalid disables Save
Clean states disable Save and reset-style Discard, but keep exit-style Cancel
available; saving disables both persistence actions. Invalid disables Save
while retaining Discard. Failed saves and conflicts keep the draft recoverable
and allow an authorized retry after the module has shown the owning error or
conflict evidence. A module may add a more specific validation, policy, or