feat: complete shared platform UI contracts

This commit is contained in:
2026-07-31 04:21:34 +02:00
parent 5b55f59a92
commit 7b8072d049
19 changed files with 764 additions and 285 deletions
+63
View File
@@ -0,0 +1,63 @@
# DataGrid Sizing Contract
`DataGrid` turns every declared track into a deterministic pixel layout after
its container has a measurable width. The same contract is used on initial
layout, container resize, persisted-layout restore, and pointer resize.
## Column Declarations
- `width: number` or `Npx` is the preferred pixel width.
- `width: N%` is a preferred share of the measured container.
- `width: Nfr` shares residual width by fraction weight.
- `width: minmax(Npx, preferred)` combines a hard lower bound with any
supported preferred width.
- An omitted width and the legacy `fill` flag are one-fraction flexible tracks.
- `minWidth` is a hard floor. Header sort, filter, and resize controls may raise
the effective accessible floor.
- `maxWidth` bounds direct user growth and free/constrained compensation. In a
cover layout it is a preferred maximum: passive tracks may exceed it when
that is necessary to keep the table flush with its container.
## Layout Modes
| `initialFit` | `resizeBehavior` | Initial layout | Pointer resize |
| --- | --- | --- | --- |
| `container` | `cover` | Real columns fill the container. Hard-minimum excess scrolls horizontally. | The active change is compensated by ordinary peer columns. Passive maxima are soft; no blank filler column is created. |
| `content` | `cover` | After measurement, the same cover invariant applies. | Same as cover above. |
| `container` | `constrained` | Real columns fill the container. | Peer compensation respects every hard min/max and stops the active resize when capacity is exhausted. |
| `content` | `free` | Declared content widths are retained. | Only the active column changes, so underflow or horizontal overflow is allowed. |
| `container` | `free` | The initial layout fills the container. | Later user resizing is free. A right-sticky column promotes this mode to cover so its edge remains stable. |
Sticky columns do not absorb ordinary cover residuals and are not resize
compensation targets. A last resizable column compensates against columns to
its left, so it follows the same right-edge invariant as earlier columns.
## Persistence
Only the pixel layout resulting from an explicit user resize is persisted.
Persisted widths are keyed by a signature containing column IDs, declared
widths and bounds, resize affordances, sticky placement, initial fit, and resize
behavior. A changed signature discards the old override and recomputes the
declared layout.
Container reconciliation is suspended while a pointer drag is active. On
release, the already-rendered pixel layout becomes the persisted preference;
there is no second fit pass and therefore no drag-end snap.
## Regression Matrix
`webui/tests/data-grid-sizing.test.ts` covers:
- pixel, percentage, fraction, `minmax`, omitted, and legacy-fill tracks;
- preferred max exhaustion without a synthetic filler column;
- hard-minimum horizontal overflow;
- fixed-only cover grids;
- persisted overrides under growth and viewport pressure;
- stale layout signatures;
- first, middle, and last-column peer compensation;
- free, cover, and constrained resizing;
- cover-expanded tracks that already exceed preferred maxima; and
- preservation of the pointer layout across the commit fit.
`webui/tests/data-grid-actions.test.tsx` also verifies the rendered fixed-cover
shape and guards against reintroducing a synthetic buffer cell.