feat(w-div): smart column stretch covers WAnchor and WButton rows#99
Conversation
A clickable nav row is authored as WAnchor(onTap) > WDiv (WDiv carries no onTap), and a WButton is the canonical button surface. Previously _shouldStretchColumnChild only stretched direct WDiv children, so those wrapped rows rendered at content width instead of filling the column, diverging from CSS align-items: stretch where element type is irrelevant. Extend the eligibility gate: WButton is gated by its own className, WAnchor delegates to its effective child (inner WDiv className decides; WText or raw child always stretches). The existing _selfWrapsInFlex / _hasExplicitCrossWidth / absolute checks are reused on the inner WDiv, so an explicit-width or self-flexing child is still left untouched. Stretch stays a SizedBox(width: infinity) under the bounded-width LayoutBuilder guard; no CrossAxisAlignment.stretch is introduced. hasStretchTarget delegates to the same predicate, so the LayoutBuilder gate and the wrap broaden together.
Update the column-stretch wording in doc/layout/flexbox.md, the layouts and tailwind-divergence skill references, and the CHANGELOG so the eligibility list reads WDiv, WAnchor (any child), and WButton instead of WDiv-only. Folds the broadening into the existing unreleased [1.0.0] Added entry rather than adding a redundant Changed entry for the same version.
Add a sidebar-nav demo with WAnchor-wrapped rows and a WButton column that fill the column width without an explicit items-stretch or w-full, showing the broadened smart-stretch behavior. Dark-mode pairs on every color token.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR extends Wind's smart column cross-axis stretch behavior to include clickable container widgets ( ChangesSmart Column Stretch for Clickable Widgets
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@example/lib/pages/layout/flex_grow.dart`:
- Around line 367-370: The WText instances use the new color token "text-white"
without an explicit dark-mode counterpart; update the className strings for the
WText widgets (e.g., the WText with className 'font-semibold text-sm
text-white') to include a matching dark: token (add a dark: prefixed color token
appropriate for dark mode, e.g., dark:text-<color>) so every color token has a
dark peer; apply the same change to the other WText occurrences referenced (the
ones around the later occurrences noted in the comment).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ede7d147-5ec2-4032-a644-fcf5c7cd1302
📒 Files selected for processing (7)
CHANGELOG.mddoc/layout/flexbox.mdexample/lib/pages/layout/flex_grow.dartlib/src/widgets/w_div.dartskills/wind-ui/references/layouts.mdskills/wind-ui/references/tailwind-divergence.mdtest/widgets/w_div/flex_stretch_test.dart
There was a problem hiding this comment.
Pull request overview
Extends Wind’s “smart column cross-axis stretch” behavior so flex flex-col columns default-stretch not only WDiv children, but also common interactive row surfaces (WAnchor, WButton) to better match CSS align-items: stretch semantics.
Changes:
- Updated
WDiv’s stretch-eligibility logic to treatWButtonandWAnchorchildren as stretch candidates (with existing opt-outs like explicit width tokens, self-flex tokens, andabsolute). - Added widget tests covering stretch behavior for
WAnchor/WButton, including bounded/unbounded constraint safety. - Updated docs, skill references, changelog, and example page to document/demo the refined stretch behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/src/widgets/w_div.dart | Expands smart-stretch eligibility to include WAnchor and WButton. |
| test/widgets/w_div/flex_stretch_test.dart | Adds regression coverage for interaction-wrapper stretch cases and guards. |
| doc/layout/flexbox.md | Documents updated smart-stretch semantics for WAnchor/WButton. |
| skills/wind-ui/references/layouts.md | Updates layout reference to reflect new stretch-eligible children. |
| skills/wind-ui/references/tailwind-divergence.md | Notes reduced divergence from CSS stretch behavior for clickable rows. |
| example/lib/pages/layout/flex_grow.dart | Adds a demo section showing clickable row stretching in practice. |
| CHANGELOG.md | Records the stretch eligibility expansion in release notes. |
| import 'w_anchor.dart'; | ||
| import 'w_button.dart'; | ||
| import 'w_text.dart'; |
| /// child is a `WDiv`, the inner WDiv's `className` decides (a `WAnchor` | ||
| /// carries no `className`), so a `WAnchor > WDiv(w-32)` keeps 128px and a | ||
| /// `WAnchor > WDiv(grow)` stays a self-flexing child that must never be | ||
| /// wrapped in a stretch `SizedBox`; when the child is anything else (a | ||
| /// `WText`, a raw widget) there is no width to honor, so it is eligible. |
| /// The inner-WDiv delegation is load-bearing for crash safety: a | ||
| /// `WAnchor > WDiv(grow)` self-wraps in `Expanded` during its own build, so | ||
| /// adding a `SizedBox(width: infinity)` stretch around it would compound the | ||
| /// flex wrap. `_selfWrapsInFlex` on the inner className excludes it. |
| // WText / raw widget: no cross-axis width to honor, always eligible. | ||
| return true; |
| // A WButton whose own className self-wraps in Expanded must not be | ||
| // wrapped again in SizedBox(width: infinity); _selfWrapsInFlex on the | ||
| // button's className excludes it from the stretch pass. |
| ``` | ||
|
|
||
| > **Column default — smart cross-axis stretch.** A `flex flex-col` with no explicit `items-*` token stretches each `WDiv` child that does not control its own width to the column width, matching CSS `align-items: stretch`. Left untouched: children with an explicit width (`w-*` / `min-w-*` / `max-w-*` / `w-full`, in any state/breakpoint variant), children that self-wrap in `Expanded`/`Flexible` (`grow`, `flex-grow`, `flex-auto`, `flex-initial`, `shrink`, `flex-shrink`, `flex-N`), absolute children, and non-`WDiv` children. `shrink-0` / `flex-none` children still stretch on the cross axis (`flex-shrink` is main-axis only, matching CSS). Add any `items-*` token (e.g. `items-start`) to turn this off and let children size to content. Rows are never auto-stretched on the cross axis. When the column itself sits in an unbounded-width context (a bare `Row` slot, `UnconstrainedBox`, horizontal scroll), the stretch safely falls back to content-sized children instead of forcing an infinite width. | ||
| > **Column default: smart cross-axis stretch.** A `flex flex-col` with no explicit `items-*` token stretches each `WDiv`, `WAnchor` (any child), and `WButton` child that does not control its own width to the column width, matching CSS `align-items: stretch`. For `WAnchor`: when the anchor wraps a `WDiv`, the inner `WDiv`'s className decides (so `WAnchor > WDiv(w-32)` keeps 128 px and `WAnchor > WDiv(grow)` stays self-flexing); when the anchor wraps a `WText` or raw widget, it always stretches. Left untouched: children with an explicit width (`w-*` / `min-w-*` / `max-w-*` / `w-full`, in any state/breakpoint variant), children that self-wrap in `Expanded`/`Flexible` (`grow`, `flex-grow`, `flex-auto`, `flex-initial`, `shrink`, `flex-shrink`, `flex-N`), absolute children, bare `WText` leaves, and raw Flutter widgets. `shrink-0` / `flex-none` children still stretch on the cross axis (`flex-shrink` is main-axis only, matching CSS). Add any `items-*` token (e.g. `items-start`) to turn this off and let children size to content. Rows are never auto-stretched on the cross axis. When the column itself sits in an unbounded-width context (a bare `Row` slot, `UnconstrainedBox`, horizontal scroll), the stretch safely falls back to content-sized children instead of forcing an infinite width. |
Address PR #99 review: the doc comments implied WAnchor > WDiv(grow) is a supported/safe config and that the self-flex exclusion provides crash safety for it. In Flutter, grow on the inner WDiv self-wraps in Expanded whose parent is the WAnchor's non-Flex wrappers, so that config asserts regardless of stretch. Reword to state the inner-WDiv self-flex check mirrors the direct-WDiv rule (and genuinely prevents the stretch-compounding crash for a direct WDiv), that WAnchor > WDiv(grow) is unsupported in its own right, and that a WAnchor-wrapped non-WDiv child is stretched by policy (the tap surface fills the column; any explicit width still constrains the wrapped widget's content). Also fix the test comment: WButton does not self-wrap in Expanded.
Address PR #99 review: every color token in an example page must carry its dark: peer. The clickable-row stretch demo's white labels lacked dark:text-white.
|
Addressed the review:
Verification after the fixes: |
Summary
In a
flex flex-colwith no explicititems-*, Wind's smart column cross-axis stretch now coversWAnchor(any child) andWButtonchildren, not only bareWDiv. A clickable nav row authored asWAnchor(onTap) > WDiv(...)(WDiv carries noonTap) previously rendered at content width; it now fills the column width by default, matching CSSalign-items: stretchwhere element type is irrelevant. No explicititems-stretch/w-fullneeded.This continues #97's smart-stretch work, closing the gap the dashboard demo surfaced (nav highlight hugged the text instead of spanning the sidebar).
Behavior
WButtonis stretch-eligible, gated by its ownclassName.WAnchordelegates eligibility to its effective child: innerWDiv's className decides; aWText/ raw child always stretches.w-*/min-w-*/max-w-*/w-full), self-flex (grow/flex-grow/flex-auto/flex-initial/shrink/flex-shrink/flex-N),absolute, bareWTextleaves, raw Flutter widgets.SizedBox(width: double.infinity)under the existing bounded-widthLayoutBuilderguard. NoCrossAxisAlignment.stretchintroduced (crash-safe).Tests (TDD red-green)
New
test/widgets/w_div/flex_stretch_test.dartgroup: WAnchor>WDiv / WAnchor>WText / WButton stretch; explicit-width inner WDiv not stretched; unbounded-width column does not crash; bare WText leaf still excluded.Verification
dart analyze0 issues,dart formatno diffflutter test1381 pass (1 pre-existing skip)./tool/coverage.sh 90-> 90.6%flutter pub publish --dry-runclean (post-commit)doc/layout/flexbox.md,skills/wind-ui/references/{layouts,tailwind-divergence}.md,CHANGELOG.md,example/lib/pages/layout/flex_grow.dart; README justified-skip (internal eligibility refinement).Planned + executed via
/ac:plan->/ac:execute; reviewer APPROVED.Summary by CodeRabbit
New Features
Documentation
Tests