Phase 3: layout grid#31
Merged
Merged
Conversation
Phase 3 ships GridParams + GridItem, TrackSize / GridLine / GridAreas value types, flips Display::Grid to taffy::Display::Grid, and adds warn-once stubs for reserved Subgrid + Masonry variants. Plan tagged [active] in docs/README.md; flips to [landed] post-merge.
Three reviewer agents surfaced real issues; this revision addresses:
1. Task 1 instant build break — adding Length::Fr to types.rs needs
atomic translate.rs Fr arms in length_to_dim/lp/lpa or cargo build
fails E0004 on the three exhaustive matches. Task 1 now multi-file.
2. Wrong S type parameter — replaced &'static str with String everywhere
(S = DefaultCheapStr = String; &'static str doesn't impl CheapCloneStr).
3. Wrong helper-method idiom — Task 5 helpers now use taffy::prelude
free fns (auto, length, percent, fr, fit_content, min_content,
max_content, minmax) with type inference from return type, instead
of TrackSizingFunction::method() which requires trait imports.
4. name: a.name.as_str().into() — replaced with a.name.clone() (no
'static lifetime guarantee on runtime String).
5. Mixed flex-in-grid claim was false (named-areas test has no flex
children) — Task 8 now adds a real fixture pinning composition.
6. Length::Fr non-grid fallback — added Decision item naming the
Taffy-imposed deviation (LengthPercentage has no Auto variant).
7. Spec § 5 'Multi-column stub warns' missing — added Coverage row
marking deferred to Phase 7.
8. Test count drift — components.rs has 10 tests, not 9.
9. Length::Fr is breaking — added ### Breaking section to CHANGELOG.
10. ChildOf already in Phase 2 filter — re-worded so Phase 3 widens
only with the two grid Changed clauses.
11. Enumerated 6 existing translate::tests needing drive-by edits.
Atomic: types.rs adds Length::Fr, RepeatCount, TrackSize, GridLine, GridAreas + NamedArea, GridAutoFlow, JustifyItems; translate.rs grows a Length::Fr arm in length_to_dim / length_to_lp / length_to_lpa with a single shared warn-once gate. Splitting these into two commits leaves the lib uncompilable (E0004 on the three exhaustive matches). Subgrid + Masonry land as reserved TrackSize / GridAutoFlow variants (warn-once + fallback wired in Phase 3 Task 6). Width discipline: RepeatCount::Count and GridLine::Start/Span/StartEnd use u16/i16 to match Taffy 0.10 directly; GridLine::Area uses String to avoid a smol_str dep. GridAreas::from_lines is the CSS-syntax convenience parser that converts ["a a", "b ."] into NamedArea rectangles. Note: Length gains a variant — this is a breaking change for exhaustive Length matchers downstream. CHANGELOG flags this under ### Breaking in Task 9. DIVERGENCE FROM PLAN (Task 1 Step 5): Plan specifies `MinMax(Box<TrackSize>, Box<TrackSize>)` for the recursive variant. Implemented as `MinMax(Vec<TrackSize>)` because bevy_reflect 0.18 has no `Reflect` impl for `Box<T>` (only Vec / IndexMap / SmallVec / BTreeMap are supported as reflectable containers). `#[reflect(no_field_bounds)]` is added to TrackSize to handle the recursive Reflect bound; the underlying Box-not- reflectable issue is independent of bounds. Vec preserves the recursion semantics; arity (must be 2) becomes a translation-time invariant — Task 5 should validate `len() == 2` and warn-once with Auto fallback otherwise. The doc comment on the variant flags the expected arity. Resolution alternative: drop `Reflect` from TrackSize entirely; that would force `#[reflect(ignore)]` on the GridParams template fields in Task 2 and lose registry visibility for inspectors/BSN — strictly worse for the same compile fix. Also added `#[allow(dead_code)]` on `GridAreas::new` / `area` / `from_lines` (mirroring the precedent at components.rs:168 for `Overflow::is_scroll_container`) because Task 1 introduces them pub but Task 7 (re-exports) lands later; without the allow, `cargo clippy --workspace --all-targets -- -D warnings` (the command Step 12 runs) fails with `dead_code` warnings.
GridParams (container, will join Style Bundle in Task 3) carries the full CSS Grid surface: explicit/auto track templates, named areas, auto-flow, alignment, gap. GridItem (decomposed-only, like FlexItem and ScrollSnapItem) carries per-child placement and self-alignment. Named-area resolution lives in translate.rs (Task 5) because Taffy 0.10 has no native named-area placement.
…tters Adds 12 fluent setters (.grid, .inline_grid, .grid_template_columns, .grid_template_rows, .grid_template_areas, .grid_auto_columns, .grid_auto_rows, .grid_auto_flow, .grid_justify_items, .grid_align_items, .grid_justify_content, .grid_align_content, .grid_gap_px). GridItem stays decomposed-only per architecture.md section 2.4, like FlexItem and ScrollSnapItem.
Phase 1 routed both to Block because GridParams hadn't shipped yet; Phase 3 Task 2 shipped GridParams. Flip the arm so containers actually get grid layout. Taffy 0.10 has no inline-grid variant — both Buiy variants map to the single Taffy variant; Phase 4 (writing modes) may revisit if line-box context differs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Atomic: extends StyleView with grid_params, grid_item, parent_areas; populates taffy::Style.grid_* fields; resolves GridLine::Area via a Buiy-side parent lookup (Taffy 0.10 has no native named-area placement). Length::Fr outside grid templates warns once and falls back to 0 px / Auto. sync_styles now precomputes a parent-areas map for the changed set and widens its Or filter to Changed<GridParams>+Changed<GridItem>. ChildOf is also kept in the filter so re-parenting a grid item under a different grid container picks up the new container's areas. MinMax: stored as Vec<TrackSize> (Bevy 0.18 Reflect lacks a Box<T> impl), arity-2 invariant checked at translate time — non-2 arity warns once and degrades to Auto. Subgrid + Masonry warn-once gates sit alongside the invalid-track-nesting + unresolved-area gates. Note: this is one commit because StyleView is the bridge between translate.rs and systems.rs — splitting would break the lib build between commits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…w::Masonry Both reserved variants degrade to a sensible non-stub equivalent (Auto / Row) and emit one warn! per session naming the limitation. Tests assert the layout pipeline completes without panic when these variants appear; the warn output is observable but not asserted (Bevy log interception is out of scope). Subgrid's warn-gate landed in Task 5; this commit adds the symmetric warn_once_masonry + WARNED_MASONRY AtomicBool and routes GridAutoFlow::Masonry through it inside map_grid_auto_flow. Drive-by: re-export GridParams, GridAutoFlow, and TrackSize from buiy_core::layout so the new integration test can import them. Task 7 will widen the re-export set further (GridItem, GridLine, GridAreas, NamedArea, RepeatCount, JustifyItems) and register reflection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GridParams + GridItem registered for reflection; new value types (TrackSize, GridLine, GridAreas + NamedArea, GridAutoFlow, RepeatCount, JustifyItems) re-exported from buiy_core and the buiy facade alongside the Phase 2 surface.
…eat, mixed) Integration tests pin observable layout for: 1fr 2fr 1fr in a 400 px row produces 100/200/100; named areas resolve child to correct cell (GridLine::Area going through Buiy-side resolution); repeat(auto-fill, 100 px) in 350 px produces 3 columns with 50 px slack; and a grid cell hosting a flex-row with two children pins spec § 5 "Mixed flex-in-grid" composition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GridParams+GridItemship the CSS Grid surface; reservedTrackSize::Subgrid+GridAutoFlow::Masonrywarn-once and degrade.Display::Grid/Display::InlineGridnow route totaffy::Display::Grid(Phase 1 routed both to Block).Style;Length::Frlands grid-only with a non-grid warn-once gate. Breaking:LengthgainsFrvariant — exhaustive matches downstream must add an arm.GridParamsjoinsStyle's Bundle;GridItemdoes not (mirrorsFlexItem/ScrollSnapItem).Test plan
cargo test --workspaceall green (Phase 1 + Phase 2 + new Phase 3 tests)cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningsRUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-depsReferences
docs/plans/2026-05-09-buiy-layout-grid.mddocs/specs/2026-05-08-buiy-layout-design/flex-and-grid.md§ 2Notes from final branch review
Changed<ScrollOffset>andChanged<ScrollSnapItem>still excluded fromsync_stylestrigger filter.MinMax(Vec<TrackSize>)(vsBox<TrackSize>, Box<TrackSize>) — Bevy 0.18 Reflect doesn't supportBox<T: Reflect>. Arity-2 invariant enforced at translate time.RepeatCount::Count(u16)andGridLine::Start/Span/StartEndwidths usei16/u16to match Taffy 0.10 directly (spec usedi32/u32).GridLine::Area(String)(spec usedSmolStr) — avoids a new direct supply-chain dep.Length::Froutside grid templates falls back to0 pxinLengthPercentagecontexts (Taffy type has no Auto),AutoinDimension/LengthPercentageAuto. The warn-once gate is the visible signal.🤖 Generated with Claude Code