Skip to content

Phase 2: layout overflow and scrolling#30

Merged
intendednull merged 11 commits into
mainfrom
claude/v01-layout-overflow-and-scrolling
May 9, 2026
Merged

Phase 2: layout overflow and scrolling#30
intendednull merged 11 commits into
mainfrom
claude/v01-layout-overflow-and-scrolling

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Summary

Phase 2 of the layout migration — ships overflow / scrolling component set on top of the Phase 1 foundation:

  • 4 components: Overflow (per-axis overflow + scrollbar config), Scroll (snap container), ScrollOffset (runtime state), ScrollSnapItem (decomposed-only child-side).
  • 9 supporting enum types: OverflowMode, ScrollbarGutter, ScrollbarWidth, ScrollbarColor, ScrollBehavior, OverscrollBehavior, SnapType, SnapAlign, SnapStop.
  • Taffy mapping: OverflowMode::{Visible, Hidden, Clip, Scroll, Auto}taffy::Overflow::{Visible, Hidden, Hidden, Scroll, Scroll} (per spec § 1.1); ScrollbarWidth::{Auto, Thin, None}taffy::Style.scrollbar_width: f32 (12.0 / 8.0 / 0.0).
  • Style Bundle extension: Overflow and Scroll join the Bundle (always-insert pattern from Phase 1) plus 12 fluent setters. ScrollOffset and ScrollSnapItem are decomposed-only per architecture.md § 2.4.
  • Central correctness invariant: sync_styles's change-detection trigger filter widens to include Changed<Overflow> + Changed<Scroll> while deliberately excluding Changed<ScrollOffset> + Changed<ScrollSnapItem> — scroll-position mutations bypass the Taffy translate path entirely. The exclusion is pinned by crates/buiy_core/tests/layout_scroll_offset_no_invalidate.rs, which mirrors the filter directly so any future widening against this contract surfaces in CI.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
  • cargo test --workspace — 93 passed / 0 failed / 4 ignored (was 74 baseline; Phase 2 adds 19 tests)
  • cargo deny check
  • Overflow::is_scroll_container() predicate matches spec § 1.2
  • All 5 OverflowMode variants map to expected taffy::Overflow value through full pipeline
  • Mutating ScrollOffset / ScrollSnapItem does NOT trigger sync_styles (yields 0 entities through the filter mirror)
  • ResolvedLayout is byte-equal across a scroll-only frame

Workflow

Authored via the project's superpowers skills:

  • writing-plans produced the 9-task plan
  • 3-agent self-review swarm caught two BLOCKERs pre-execution: merged Tasks 5+6 atomically (build-break risk), and switched the no-invalidate test from whole-struct equality to per-Vec2-field comparison (ResolvedLayout only derives Clone)
  • subagent-driven-development walked the 9 tasks with implementer → spec-reviewer → code-quality-reviewer cycles
  • Branch-level final reviewer surfaced 2 non-blocking observations (documented in OBSERVATIONS of the review)

🤖 Generated with Claude Code

10-task TDD plan realizing
docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md.

Scope: 4 components (Overflow, Scroll, ScrollOffset, ScrollSnapItem)
+ 9 supporting enum types; Overflow → taffy::Style.overflow mapping per
spec § 1.1; ScrollbarWidth → taffy::Style.scrollbar_width as f32 (12/8/0);
Style Bundle extension with overflow + scroll fields and 12 fluent
setters; sync_styles' change-detection trigger set widens to include
Changed<Overflow> and Changed<Scroll> while excluding Changed<ScrollOffset>
and Changed<ScrollSnapItem> — pinned by tests/layout_scroll_offset_no_invalidate.rs.

Marks Phase 1 as [landed] and Phase 2 as [active] in docs/README.md.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md
Two BLOCKERs:
1. Merged Tasks 5 (translate.rs widening) + 6 (systems.rs widening) into a
   single atomic Task 5 — splitting them left the lib uncompilable between
   commits because StyleView is the bridge between sync_styles' query and
   style_to_taffy. Renumbered remaining tasks 7→6, 8→7, 9→8, 10→9.
2. Fixed Task 8's ScrollOffset-no-invalidate test: ResolvedLayout derives
   only Clone (not Copy + PartialEq), so by-deref-value capture and direct
   assert_eq! both fail to compile. Switched to per-field (Vec2) capture
   and comparison; Vec2 has Copy + PartialEq.

Nits:
- Added rationale for ScrollbarWidth → f32 (Auto=12 / Thin=8 / None=0)
  matching common platform scrollbar widths.
- Corrected the inline comment on map_overflow_mode regarding Taffy 0.10's
  Hidden/Clip distinction (Hidden reserves gutter, Clip doesn't).
- Added a note to Task 2 explicitly directing executors to use
  #[reflect(Component, Default)] (matching BoxModel/Position/FlexParams),
  not #[reflect(Component)] (Phase 1's Display oversight).
- Verified empirically that integration tests can use taffy::* without a
  dev-dep addition; documented in Task 7.
- Cross-references in coverage map and body text updated for renumbering.
- Final-note commit count corrected (10 = 9 task-commits + 1 plan-write).

Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md
Adds OverflowMode, ScrollbarGutter, ScrollbarWidth, ScrollbarColor,
ScrollBehavior, OverscrollBehavior, SnapType, SnapAlign, SnapStop —
the supporting type surface for Phase 2 components in the next tasks.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 1
Both ship with default = no-op (Visible/Visible, no snap). Overflow
exposes is_scroll_container() — the spec § 1.2 predicate for
sticky-positioning containing-block resolution (Phase 7).

#[allow(dead_code)] on is_scroll_container: method is part of the
documented public API and consumed in Phase 7; suppress the lint rather
than silently remove or hide it.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 2
ScrollOffset is runtime state — mutating it must not invalidate
ResolvedLayout. ScrollSnapItem is child-side, like FlexItem; both stay
decomposed-only (not in Style Bundle). Their exclusion from sync_styles'
change-detection filter is enforced in Task 5.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 3
Adds container-side overflow and scroll-snap fields plus 12 fluent
setters. ScrollOffset (runtime) and ScrollSnapItem (child-side) stay
out of the Bundle per architecture.md § 2.4.

Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 2.2-2.4
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 4
Atomic. Extends StyleView with `overflow` + `scroll`; maps OverflowMode
{Visible, Hidden, Clip, Scroll, Auto} → taffy::Overflow {Visible,
Hidden, Hidden, Scroll, Scroll} per spec § 1.1; ScrollbarWidth
{Auto, Thin, None} → 12.0 / 8.0 / 0.0 (f32).

Widens sync_styles' Or<(Changed<...>)> filter to include
Changed<Overflow> + Changed<Scroll>, matching architecture.md § 1.2.
Changed<ScrollOffset> and Changed<ScrollSnapItem> are intentionally
excluded — runtime state and child-side respectively (Task 8 asserts).

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md § 1.1
Spec: docs/specs/2026-05-08-buiy-layout-design/architecture.md § 1.2
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 5
LayoutPlugin now reflects Overflow / Scroll / ScrollOffset /
ScrollSnapItem; the four components and 9 supporting enums are
re-exported from buiy_core and the buiy facade.

Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 6
…ection

End-to-end fixture: spawn Buiy entities with each OverflowMode variant,
verify the resulting taffy::Style.overflow.x/y matches spec § 1.1 mapping.
Adds doc-hidden by_entity / tree_ref accessors on LayoutTree to enable
integration-test inspection of the Taffy bridge state.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md § 1, § 5
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 7
…layout

Pins Phase 2's central correctness invariant: mutating runtime/child-side
scroll components must not enter sync_styles' trigger filter. Test
mirrors the filter directly so future filter widenings against this
contract surface in CI.

Spec: docs/specs/2026-05-08-buiy-layout-design/overflow-and-scrolling.md § 2.1
Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 8
Adds Unreleased entries for the four new components, 9 enum types,
Style Bundle extension, and the sync_styles trigger-set widening.

Plan: docs/plans/2026-05-08-buiy-layout-overflow-and-scrolling.md task 9
@intendednull intendednull merged commit f992bc7 into main May 9, 2026
6 checks passed
@intendednull intendednull deleted the claude/v01-layout-overflow-and-scrolling branch May 9, 2026 07:20
intendednull added a commit that referenced this pull request May 9, 2026
Phase 2 (overflow + scrolling) merged in PR #30 (commit f992bc7).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant