Add the grid layout component

Plan step 35: <x-grid :columns gap min-item>. The column count per
breakpoint is written as five inline custom properties, each filled from
the nearest smaller breakpoint, so a nested grid never inherits its
parent's; min-item fills a row by the room the grid has, and with columns
the counts become a ceiling.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 14:50:47 +02:00
co-authored by Claude Opus 5
parent 8de053f15c
commit da7a05a619
6 changed files with 241 additions and 0 deletions
@@ -795,6 +795,19 @@ Children side by side inside a pane: `<x-row gap="space100" justify="between" st
- `stack-below`: `medium`, `expanded`, `large` or `extra-large` — below that breakpoint the row is a column, its children stretched unless `align` was given.
- It runs in the inline direction, so it mirrors in a right-to-left document by itself.
#### `<x-grid>`
Children in columns inside a pane.
```blade
<x-grid :columns="['compact' => 1, 'medium' => 2, 'expanded' => 3]" gap="space300">…</x-grid>
<x-grid min-item="280px" gap="space200">…</x-grid>
```
- `columns`: a map from breakpoint to count, or one number for all. A breakpoint left out takes the nearest smaller one's count; compact is 1 unless given. Each grid writes all five (`--md-columns-compact``--md-columns-extra-large`), so a grid inside another never inherits its parent's.
- `min-item` fills each row with as many columns as fit at that width — following the grid's own width, the choice inside a pane narrower than the window. With `columns` too, the counts are a ceiling.
- Children keep their source order. M3 publishes no column table for the web; choose counts by the content.
### `<x-app-shell>`
The adaptive app shell, a whole layout's body: one navigation per M3 window size class, the page as `<main id="content" wire:transition.navigate>` behind a skip link, and the snackbar host (do not add another `<x-toast />`). It needs `<x-theme-script />` in `<head>`.