Repository navigation
Grid: Canvas exploration - #84340
Grid: Canvas exploration#84340draganescu wants to merge 12 commits into
Conversation
Pure functions for the manual grid drag, guide and rotate interactions, with unit tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add a rotate child layout value, output with the CSS rotate property in the editor and on the front end, with viewport overrides. - Allow the rotate property through safecss_filter_attr. - Stack the children of manual placement grids on mobile unless the grid sets stackOnMobile to false. - Clear rotation when a block leaves the grid or the grid switches to auto placement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In manual placement grids: - One drop zone covers the grid and works out the landing cells from the pointer, keeping the grabbed cell under it and clamping to the grid. - The landing cells, overlaps with other blocks, and alignment guides to the container and nearby blocks are drawn while dragging. - Dragged blocks stay in place, dimmed, instead of following the pointer. - A grip and a rotate handle sit on the selected block. Rotation snaps to 15 degrees, Shift rotates freely, and Escape cancels. - A Rotation control in the block settings, and a Stack on mobile toggle in the grid settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Children of manual placement grids publish their row span as the --wp--grid-item--row-span custom property, and the grid's mobile stacking rule spans that many rows instead of one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- On mobile, the grip, rotate and resize handles work on a stacked grid. The first edit gives the grid its own mobile layout matching the stack (full width, block order, row spans kept, unrotated), then applies the edit, as one undo step. Sidebar edits do the same. - In manual grids, dragging the bottom resize handle past the last row adds rows, and resizes are measured from the grid's content box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rows were sized by their own content, so cells in the same grid had different heights. Rows now use `1fr`, which makes each one as tall as the tallest, and rows outside the row count match them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes the grip on selected grid items, so drags start from the block toolbar's drag handle. Since a drag no longer starts on the block, the pointer now marks the centre of the dragged block, measured without its rotation, instead of the cell it was grabbed by. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Manual grids take their height from their width with `aspect-ratio: columns / rows`, so their cells are all the same size, close to square, and content no longer makes them bigger. Images cover their cells, below any caption; in the editor, images in a manual grid leave out their default inline `height: auto` so the layout can size them. On mobile, a stacked grid goes back to sizing blocks by their content. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pressing on an empty cell of a manual grid and dragging selects a rectangle of cells. On release, the inserter opens, and the block inserted covers the selected cells. A selected manual grid has handles on its top and bottom edges that add or remove rows in the selected style state. Rows added or removed at the top move every block with them, and rows with blocks in them can't be removed. Blocks dragged out of the grid drop wherever they land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once a drag has been over the block flow, the block tools hide every popover in their slots, including the grid's drop layer. A drag that started outside a manual grid, such as from a block toolbar shown above it, then fell back to the block flow's drop zones inside the grid too. While blocks are dragged, a manual grid's visualizer now renders in the default popover slot, so blocks move between the grid and the block flow in both directions: over the grid, its landing cells show, and elsewhere the block flow's insertion indicator does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for getting this started! A few thoughts from a quick round of testing:
In terms of how to proceed: this is a massive, unreviewable changeset to a feature that is very bug-prone and needs careful testing to get right. We need to split this up into discrete pieces; pretty much each of the bullet points in the "what" section of the PR description could be its own PR. That way we can review and test each bit properly and be confident it's working well. I'm happy to help with reviews and putting together some of the PRs where needed (I had intended to devote some time to this project post-7.2 in any case) |
|
Cool review @tellthemachines and lovely plan. I'll setup as you described as it all makes perfect sense. |
|
This PR is now split into one draft PR per feature. Grid stackEach PR builds on the one before it, and they are linked as a GitHub stack. From #84512 up, the branches have the full feature set of this PR.
Separate PRs
What changed compared with this PR
Status
|
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
|
I will keep the stack up to date and close this exploration. |
Explores the ideas in #81796
What?
Makes moving and arranging blocks in a manual-placement grid (Group block, Grid layout, "Grid item position: Manual") feel direct. All of it sits behind the existing
gutenberg-grid-interactivityexperiment:style.layout.rotate, with per-viewport overrides.aspect-ratio: columns / rows), so all its cells are the same size, close to square, and content never makes them bigger. Images cover their cells. On mobile, the stack goes back to sizing blocks by their content.Why?
Manual grid placement exists, but the only way to place a block precisely today is the arrow movers or typing column and row numbers. The built-in drag-and-drop gives no sense of where a block will land or what it lines up with. The interaction model is inspired by freeform canvas editors, kept to the grid's existing cell-based data so existing content and front-end CSS keep working.
How?
components/grid/grid-visualizer.jsx) replaces the per-cell drop zones. Ondragoverit maps the pointer to a cell using the grid's live track sizes (get-grid-drop-target.js), then works out overlaps and guides (get-alignment-guides.js). On drop it writescolumnStart/rowStartand reorders the block so block order follows visual order, as before. Drags still use native HTML5 drag-and-drop.use-selected-block-event-handlers.js). Drags use the block toolbar's existing drag handle; there is no extra grip on the block.rotateproperty, nottransform, because the editor's block-move animation writestransformon block elements.rotateis added to the safe CSS list inlib/compat/wordpress-7.2/kses.php. The editor (hooks/layout-child.jsx) and PHP (lib/block-supports/layout.php) both output it, and PHP wraps untrusted values into (-180, 180]. Overlays for rotated blocks are rotated to match (use-rotated-overlay-style.js).@mobilemedia query, with a doubled selector so it beats each child's own placement rule (layouts/grid.jsx,hooks/layout.jsx, and the grid branch inlayout.php). Each child publishes its row span as--wp--grid-item--row-spanso the stack keeps it.useUpdateGridChildLayout, which, for a stacked grid in the Mobile style state, first writes mobile overrides that match the stack (mobile-stacking.js), then the edit, in one block update.use-grid-layout-sync.js).block-editor, so it applies to both the post-based site editor and the extensible site editor.Still to do before this can leave draft:
backport-changelogentry for thelayout.phpandkses.phpchanges.Testing Instructions
Testing Instructions for Keyboard
The drag handle, rotate handle, row handles and drawing cells are pointer-only, like the existing resize handles. The movers, the grid's Rows control, the cell appenders and the sidebar controls cover the same actions, except that a block inserted from the keyboard covers one cell.
Screenshots or screencast
To add.
Use of AI Tools
Written with Claude Code (Claude Opus 5.5). The design decisions were made by the PR author in conversation with it; the code, unit and PHP tests, and this description were generated by it.
🤖 Generated with Claude Code