Repository navigation
Dashboard grid geometry: host-declared columns and row height, widget footprints, saved layouts that survive a geometry change #85239
Description
Where we start
Today, the dashboard package determines the column count automatically.
A host passes a count, and the package steps it down to two columns under 960px and to one under 600px. Those breakpoints are not configurable, so a host cannot set up a dashboard for responsive use on its own terms. The row height accepts only three presets.
A widget has no way to say how small it can get. A resize can crush a tile, and the only workaround is a per-widget pixel guess inside the host that rots as the widget changes.
And a saved layout is a list of spans with no unit. width: 2 is half of four columns and a sixth of twelve; height: 3 is 948px on 300px rows and 168px on 40px rows. When the geometry changes, the same numbers render a different board, and the user's composition disappears.
What we do in this round
We move the column policy into data the host declares, and we let the grid surface resolve its own count from it.
We let widgets declare a footprint, a kind rather than a measurement, and we let each host turn it into a floor in its own geometry.
And we make a saved layout carry the geometry it was written under, so a host can change its geometry and still render what users saved.
We work one package at a time, from the bottom up. We build the grid first, then the widget contract, then the dashboard package, then the wp-admin dashboard and its PHP.
Each PR is small enough to review and test on its own, updates the documentation it touches as part of the change, and shows the change in a Storybook story when there is something to see. The PRs are stacked, each one based on the previous one, so GitHub retargets them as they merge.
1. The grid takes the column count as steps (#85216)
columns on DashboardGrid and DashboardLanes accepts, besides a number, a map from container width to count: { 0: 1, 600: 2, 960: 4 }.
A step can be 'auto', which lifts the cap from that width upward and leaves the count at minColumnWidth. A number continues to resolve as before, and the floor composes with every shape.
Both surfaces resolve the count through one shared function, from their own measured width and gap. Nothing in the grid knows about dashboards.
2. Widgets declare a footprint (#85227)
widget.json gains footprint: the smallest form the widget's content can take. Four values, glance, strip, card, and panel, with no units.
A strip is wide and shallow; a panel needs both axes. The field travels through the build manifest, the PHP registry, and the REST record into WidgetType.footprint, sanitized at registration, and nothing consumes it yet.
This is the first half of #81795. The natural form of #81797 stays out of this round.
3. The dashboard forwards the grid settings as declared (#85228)
The dashboard package stops stepping the count and stops snapping the row height.
columns and minColumnWidth pass through untouched, and any positive rowHeight is rendered as given. When a host sets neither columns nor minColumnWidth, the package applies WIDGET_DASHBOARD_COLUMN_STEPS, the same three steps as before, now provided as data a host can replace.
This is the breaking change of the round. A host that passed columns: N and relied on the package steps now gets N columns at every width, and states the steps instead: columns: { 0: 1, 600: 2, 960: N }. A row height outside the presets now renders instead of snapping.
The experimental dashboard keeps its behavior here: it states the steps itself and keeps snapping the stored row height.
4. Footprints become floors (#85229)
The dashboard appraises each form in pixels, strip at least 440 wide, card 200 by 200, panel 440 by 360, glance none, and hands the floors to the surface as itemLimits.
The surface rounds a floor up to whole tracks of the current geometry, so a resize never commits below it and a stored span renders bounded. Nothing is stored: the floor is derived on every render, and the same declaration lands differently as the geometry changes.
The widths sit under what one column and two columns offer at 960px, so a card takes one column and a strip or a panel two across the whole four-column band.
5. A layout can be rescaled across geometries (#85230)
Two pure functions. layoutGeometry( gridSettings ) gives the geometry a layout's spans count against: the count on a wide container and the row height. rescaleLayout( layout, from, to ) re-expresses a layout authored in one geometry in another: heights keep their pixels, widths keep their proportion of the surface, fill and full stay.
The geometry carries no gap. The surfaces read the real gap per density, so the conversion is inherently approximate, and one internal constant keeps it stable across hosts.
6. The experimental dashboard stamps its layout and moves to 40px rows (#85232)
The dashboardLayout preference becomes a record, { geometry, widgets }.
The hook writes the geometry it saves under and rescales on read when the stored geometry differs.
A plain array, saved before the record existed, counts as four columns of the row height the removed Layout settings drawer persisted, or 300px. A record with an unreadable stamp counts as current, so nothing moves.
The page outlines its steps and renders 40px rows, so a tile's height can match its content. The record is consumer code: the package exposes nothing new to it, and each host maintains its own storage and legacy.
7. The default layout declares its geometry (#85238)
The seed is authored in 40px rows and served as the same record, both when injected into the user's preferences and from the default-layout route, so the first render is an identity.
A dashboard that renders with another geometry declares it through gutenberg_dashboard_default_layout_geometry. Reset reads the record and rescales from its stamp.
What we leave out, for now
The natural form of a footprint (#81797), so a new tile is born at the size its content is designed around. A per-host override of the pixel appraisal of footprints. A version in the layout record, for changes that are not geometry. And a floor in the wp-admin dashboard: with steps only, the stamp is exact, and the dashboard behaves as it did before.
Activity