Layout Phase 1 — decomposed components + 8-step pipeline + hybrid Style builder#29
Merged
Conversation
Phase 1 of the layout migration: replace Phase 0's mega-Style with a hybrid Style builder over decomposed components, install the 8-step BuiyLayoutStep pipeline skeleton, keep all existing tests + hello_button green. Add a Visual component (background_token / foreground_token / border_radius) carrying render-side fields formerly mixed into Style; eventual home is buiy-render-pipeline-design. 12 TDD-shaped tasks. Three-reviewer swarm (spec coverage, plan quality, Bevy/Taffy API correctness) ran against the draft; BLOCKERS for the render-module break and missing change-detection filter on sync_styles addressed before commit. Spec: docs/specs/2026-05-08-buiy-layout-design/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… axis enums
Spec: docs/specs/2026-05-08-buiy-layout-design/{box-model,display-and-positioning,flex-and-grid}.md.
Phase 1 of the layout migration. Ships only Length::Px/Percent and
the Sizing/Edges/BoxSizing/FlexAxis/PositionKind shapes; richer
unit resolution (em/rem/viewport/container/calc) lands in Phase 10.
Plan deviation: the plan called for creating a new layout/mod.rs in
this task, but Rust's module system (E0761) disallows both layout.rs
and layout/mod.rs under one 'pub mod layout;'. The submodule lands
via 'mod types;' inside the existing layout.rs; Task 7 transitions
to the directory module by deleting layout.rs.
Two impl blocks (Length, Edges) carry a narrow #[allow(dead_code)]
until Task 3 wires the Style builder; comments mark when the allows
come off.
…ms/AlignContent Code-review follow-up to commit 1377bbc — three public enums in layout::types lacked doc comments while their neighbors (FlexAxis, FlexWrap, PositionKind) had them. Brief 1-2 line doc each citing the CSS property the variant set models.
After executing Task 1: - E0761 forbids layout.rs and layout/mod.rs coexisting; Tasks 1-6 add 'mod xxx;' to the existing layout.rs, and Task 7 transitions to a directory module by deleting layout.rs. - Phase 1 helper methods (Length::px, Edges::all, etc.) lack production callers until Task 3+; narrowly-scoped #[allow(dead_code)] on the impl blocks keeps clippy -D warnings clean. - clippy derivable_impls prefers #[derive(Default)] + #[default] over manual impl Default for enums with a clearly-defaulted variant. - Three pub enums (JustifyContent / AlignItems / AlignContent) now carry brief CSS-citation doc comments (caught by code review). Step 1.1, 1.4, 1.7 and the New-files block updated to match. Tasks 2-6's "Update layout/mod.rs" steps will be corrected in a follow-up patch as those tasks come up for execution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…, FlexParams, FlexItem
Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 2.1.
Phase 1 of the layout migration. Phase-0-equivalent surface only:
the components Phase 0's mega-Style touched. Other components
(Anchor, Grid*, Container, WritingMode, Overflow, Scroll, Stacking,
Transform, Containment, MultiColumn) land in later phase plans.
Display ships every spec variant for forward stability; Phase 1
translates non-{Block, Flex(_), InlineFlex(_), None} variants to
Block in Task 4 (translate.rs). Position::Fixed and Position::Sticky
similarly defer to Phases 7/8.
mod types and mod components are promoted to 'pub mod' so Task 3+
reach them via crate::layout::{components, types} from outside the
layout module.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code-review follow-up to commit 4ef1be5. Phase 0 puts Default right after Reflect (see crates/buiy_core/src/components.rs:26,32,55 and focus.rs:28); Tasks 1-2 deviated by placing Default at the end of the derive list. Reorder mechanically across types.rs (Task 1) and components.rs (Task 2) — no semantic change. This pattern is the convention going forward for all Phase 1 layout modules.
Code-review follow-up to commit 1bf342e. Phase 0 puts Default right after Reflect (or after Component, Reflect); Tasks 1-2 deviated by placing Default later. Plan code blocks for types.rs and components.rs updated to match Phase 0's ordering, so Tasks 3-7 inherit the convention without re-running the same fix loop. Display also flipped from manual 'impl Default { Block }' to '#[derive(Default)]' + '#[default] Block' (clippy derivable_impls). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…osed components Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 2.2-2.4. Style is a Bevy Bundle whose default expands to defaulted decomposed components; fluent setters write the same fields a struct literal would. Phase 1 simplification: every component is always inserted (default-valued or set), to keep the Bundle derive simple. Phase 4 revisits this when LogicalBoxModel needs skip-on-default semantics. FlexItem stays decomposed-only per the child-side convention; it's spawned alongside Style, not inside it.
Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 1.2.
Pure function over a borrowed view of the Phase 1 component set.
Phase 1 unit resolution is Px + Percent only; intrinsic / em / rem
/ viewport / container / Fr / Calc are reserved for Phase 10.
Display variants outside {Block, Flex(_), InlineFlex(_), None}
translate to Block; Grid/InlineGrid included until Phase 3 wires
GridParams/GridItem. Position::Fixed / Sticky translate to
Absolute / Relative until Phases 7/8 land the real semantics.
FlexItem.order is stored but not honored (Taffy 0.10 has no
Style.order field).
… config Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 3. Eight ordered sub-sets of BuiySet::Layout. Steps 0/1/3/7 do real work in Phase 1; steps 2/4/5/6 are wired as empty sub-sets that later phases populate without reordering. Order is enforced by a test added in Task 10. configure_pipeline is dead code until Task 7's LayoutPlugin calls it; narrow #[allow(dead_code)] keeps clippy quiet, removed in 7. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…layout root Code-review follow-up to commit 7820a45. Plan's Step 5.2 calls for flat re-exports so external callers reach crate::layout::BuiyLayoutStep (and the internal LayoutPlugin reaches configure_pipeline) without the pipeline:: namespace. Two-line addition; the wider re-export of Tasks 1-3's submodule items is held back until Task 7's transition deletes layout.rs (Phase 0's 'use crate::components::Style' would collide with 'pub use style::Style' at the crate-public level). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rustfmt drift inherited from Task 3 (commit 1cb0ada) and Task 4 (commit b4c6df6) — those commits were verified against clippy -D warnings + cargo check, but cargo fmt --check was not part of the per-task verification gate. CI runs the full check chain (fmt + clippy + doc + test) per CLAUDE.md, so this needs to be fmt-clean before Phase 1 lands. Pure formatting; no semantic change. cargo fmt --all -- --check clean after this commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same struct as Phase 0, moved into its target location with crate- visible field access (Phase 0's were private). Old layout.rs still owns the live LayoutTree resource until Task 7 swaps the plugin over; the new tree.rs is namespaced as crate::layout::tree::LayoutTree to avoid collision with Phase 0's pub struct LayoutTree.
…ecomposed components Phase 1 of the layout migration. Tasks 7+8 (atomic) + Task 11 test migration (picking.rs, picking_backend.rs migrated inline since they reference the deleted Style from components). - Delete crates/buiy_core/src/layout.rs (flat Phase 0 module). - Delete components::Style and components::FlexDirection. - Add layout/mod.rs with LayoutPlugin registering decomposed components and chaining the 8-step pipeline (steps 0/1/3/7 active, 2/4/5/6 empty stubs for later phase plans). - Add layout/systems.rs with gc_removed_nodes, sync_styles, taffy_compute, write_resolved_layout (all pub(super)). - Add components::Visual (background_token, foreground_token, border_radius) carrying the render-side fields formerly on the mega-Style; eventual home is buiy-render-pipeline-design. - Migrate the render extract to query (&Visual, &ResolvedLayout) so the workspace continues to compile + render after Style's deletion. - Migrate Button::new to Style::default().width_px(120.0) .height_px(32.0).padding(8.0) plus a Visual carrying the three theme tokens; visual appearance preserved. - Style is now a Bundle (decomposes on insert) rather than a reflectable Component; reflection now sees the decomposed components. - Re-export decomposed components, the Style builder, and Visual from buiy + buiy_core. - Migrate tests/layout.rs and tests/components.rs (Task 11) to new Style builder + Visual API; migrate tests/picking.rs and tests/picking_backend.rs (Style removal). All tests pass: 0 failures across workspace. Spec: docs/specs/2026-05-08-buiy-layout-design/. Plan: docs/plans/2026-05-08-buiy-layout-foundation.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…he consumers Code-review follow-up to commit ac33faa. The #[allow(dead_code)] / #[allow(unused_imports)] attributes added during Tasks 4/5/6 were gated on 'until Task 7 wires this in' — Task 7 has now wired LayoutPlugin / sync_styles / configure_pipeline to consume them. Drop the stale suppressions; clippy stays clean because the items are now reachable through the live system schedule. - pipeline.rs: drop #[allow(dead_code)] on configure_pipeline (LayoutPlugin::build calls it). - translate.rs: drop module-level #![allow(dead_code)] (style_to_taffy / StyleView called from sync_styles). - tree.rs: drop module-level #![allow(dead_code)]; also remove the unused taffy_node_for helper (systems access by_entity directly per Correction 2 in the Task 7+8 dispatch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…valence Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 8 tests #1, #3, #4 + box-model.md § 6. - layout_topology: parent-resolves-before-children invariant on a 4-deep tree (architecture.md § 5). - layout_pipeline_order: tracker systems in each BuiyLayoutStep set fire in 0..7 order (architecture.md § 3). - layout_box_sizing: ContentBox produces 120px total for width 100 + padding 10/side; BorderBox produces 100px total (box-model.md § 2.2). - layout_style_equivalence: struct literal and fluent builder forms produce identical ResolvedLayout after one Update (architecture.md § 2.2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ctive CHANGELOG records the Phase 0 mega-Style removal, the new layout/ module with 8-step pipeline, the hybrid Style builder, and the Visual component carrying the render-side surface. Spec README moves from draft to active. Spec § 4.1 now points at the Phase 1 plan and clarifies that the migration is a series of plans (other phases tracked in the plan's phasing table). docs/README.md index entries for both spec and plan flip from draft to active.
Final-review follow-ups to commits e19779d (docs) and f3b3eef (allows cleanup): - docs/plans/2026-05-08-buiy-layout-foundation.md header bumped from draft to active; e19779d's commit message promised this flip but the file was missed in the diff. - Drop three stale #[allow(dead_code)] annotations whose comments promised they'd be removed once consumers landed: impl Length (Edges::ZERO uses Length::ZERO; px/percent are pub API for end users — pub items don't trigger dead_code anyway), impl Edges (Edges::all is called from style.rs's padding/margin/border setters; ZERO is used by Edges::default), impl Style (button.rs uses width_px/height_px/padding; tests use flex_column). cargo clippy --workspace --all-targets -- -D warnings still clean after removal — the allows were not suppressing real warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Stylewith a hybridStylebuilder (struct-literal + fluent setters over the same fields) that decomposes intoBoxModel,Display,Position,FlexParamson insert.BuiyLayoutSteppipeline as ordered sub-sets ofBuiySet::Layout. Phase 1 implements steps 0/1/3/7 (RemovedNodesGc,SyncStyles,TaffyCompute,WriteResolvedLayout); steps 2/4/5/6 are wired empty stubs for later phases (CqActivate,CqFlipCheck,CqFlipReRun,PostTaffyOverrides) so adding container queries / sticky / table / multicol / anchor doesn't reorder anything.sync_stylescarries the spec'sOr<(Changed<Display>, Changed<BoxModel>, Changed<Position>, Changed<FlexParams>, Changed<FlexItem>, Changed<Children>, Changed<ChildOf>)>filter, so steady-state frames iterate zero entities (matches spec § 9 O(0) contract).components::Visual(background_token,foreground_token,border_radius) carrying the render-side surface that used to leak into the layoutStyle.Button::newinserts both the layoutStylebuilder and aVisualwith the same theme tokens — visual appearance preserved.2026-05-08-buiy-layout-designflipsdraft → active; this plan is the first in a series of phase plans (Phase 2-10 sketched in the plan's "Phasing strategy" table — overflow/scroll, grid, writing-modes, container queries, anchors, sticky/table/multicol, stacking + top-layer, transforms, full unit resolution).Spec:
docs/specs/2026-05-08-buiy-layout-design/. Plan:docs/plans/2026-05-08-buiy-layout-foundation.md(12 tasks, all landed across 18 commits).Test plan
cargo fmt --all -- --check— cleancargo clippy --workspace --all-targets -- -D warnings— cleanRUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps— cleancargo test --workspace— 71 passing, 0 failing (up from Phase 0's ~50)cargo build --example hello_button— clean (visual appearance preserved via theVisualcomponent)cargo run --example hello_buttonto confirm the rendered button matches Phase 0 (CI doesn't have a GPU)cargo test --workspacepost-merge to confirm no rebase artifactsWhat's NOT in this PR (Phase 2+)
Anchor,GridParams/GridItem,MultiColumn,Container,WritingMode,Overflow,Scroll,Stacking,Transform,ContainmentcomponentsPx+PercentLogicalBoxModelinsert helper / writing-mode inheritance passEach is tracked in the plan's "Phasing strategy" table with explicit dependencies.
🤖 Generated with Claude Code