Skip to content

feat(w-div): smart column stretch covers WAnchor and WButton rows#99

Merged
anilcancakir merged 5 commits into
masterfrom
feat/flex-stretch-wrappers
Jun 9, 2026
Merged

feat(w-div): smart column stretch covers WAnchor and WButton rows#99
anilcancakir merged 5 commits into
masterfrom
feat/flex-stretch-wrappers

Conversation

@anilcancakir

@anilcancakir anilcancakir commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

In a flex flex-col with no explicit items-*, Wind's smart column cross-axis stretch now covers WAnchor (any child) and WButton children, not only bare WDiv. A clickable nav row authored as WAnchor(onTap) > WDiv(...) (WDiv carries no onTap) previously rendered at content width; it now fills the column width by default, matching CSS align-items: stretch where element type is irrelevant. No explicit items-stretch / w-full needed.

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

  • WButton is stretch-eligible, gated by its own className.
  • WAnchor delegates eligibility to its effective child: inner WDiv's className decides; a WText / raw child always stretches.
  • Left untouched: explicit width (w-* / min-w-* / max-w-* / w-full), self-flex (grow / flex-grow / flex-auto / flex-initial / shrink / flex-shrink / flex-N), absolute, bare WText leaves, raw Flutter widgets.
  • Stretch stays SizedBox(width: double.infinity) under the existing bounded-width LayoutBuilder guard. No CrossAxisAlignment.stretch introduced (crash-safe).

Tests (TDD red-green)

New test/widgets/w_div/flex_stretch_test.dart group: 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 analyze 0 issues, dart format no diff
  • flutter test 1381 pass (1 pre-existing skip)
  • ./tool/coverage.sh 90 -> 90.6%
  • flutter pub publish --dry-run clean (post-commit)
  • 5-surface sync: 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

    • Smart column cross-axis stretch now also applies to clickable row containers, so nav/button rows fill column width by default.
  • Documentation

    • Expanded docs to clarify when auto-stretch applies and explicit exceptions (explicit widths, flex-grow wrappers, absolute children, bare text/raw widgets); rows remain unaffected.
    • Added example demonstrating clickable-row stretching.
  • Tests

    • Added tests covering stretch behavior and regression scenarios for interactive wrappers.

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.
Copilot AI review requested due to automatic review settings June 9, 2026 00:11
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1b1bfdd0-7df7-42e0-b23c-e0ab9902f75a

📥 Commits

Reviewing files that changed from the base of the PR and between f91d75e and daaaf08.

📒 Files selected for processing (4)
  • doc/layout/flexbox.md
  • example/lib/pages/layout/flex_grow.dart
  • lib/src/widgets/w_div.dart
  • test/widgets/w_div/flex_stretch_test.dart
✅ Files skipped from review due to trivial changes (1)
  • doc/layout/flexbox.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • example/lib/pages/layout/flex_grow.dart
  • lib/src/widgets/w_div.dart

📝 Walkthrough

Walkthrough

This PR extends Wind's smart column cross-axis stretch behavior to include clickable container widgets (WAnchor and WButton) alongside WDiv. The core logic now checks widget types and applies conditional eligibility, while documentation, examples, and tests articulate the updated stretching rules and exceptions.

Changes

Smart Column Stretch for Clickable Widgets

Layer / File(s) Summary
Stretch eligibility logic for clickable wrappers
lib/src/widgets/w_div.dart
WDiv imports w_button.dart and updates _shouldStretchColumnChild to recognize WButton via className and WAnchor by delegating to inner WDiv when present; otherwise treats non-WDiv content as eligible for smart stretch wrapping.
Documentation of stretch behavior across references
CHANGELOG.md, doc/layout/flexbox.md, skills/wind-ui/references/layouts.md, skills/wind-ui/references/tailwind-divergence.md
CHANGELOG, user-facing flexbox docs, and reference material describe that smart column stretch now covers WAnchor and WButton, clarify exceptions (explicit widths, Expanded/Flexible, absolute children, bare WText, raw widgets), explain WAnchor inner-child-dependent behavior, and confirm items-* opt-out.
Example widget and UI tweaks
example/lib/pages/layout/flex_grow.dart
New _ClickableStretchDemo example renders sidebar nav rows via WAnchor and a WButton section; minor className color adjustments for existing labels.
Example-driven tests
test/widgets/w_div/flex_stretch_test.dart
New smart column stretch (interaction wrappers) test group verifies stretch/no-stretch for WAnchor and WButton, explicit width constraints, unbounded contexts, self-flex exclusions, and that bare WText is not wrapped by an infinite-width SizedBox.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • fluttersdk/wind#97: Related earlier change that originally implemented the smart column cross-axis stretch for WDiv; this PR extends that work to WAnchor/WButton.

Poem

🐰 A column that stretches with grace,
Now embraces each button and anchor's place,
Smart sizing for clickable rows,
Documentation that grows and grows!
Hop forward with tests in place. 🌱

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: extending smart column stretch behavior to WAnchor and WButton rows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/flex-stretch-wrappers

Comment @coderabbitai help to get the list of available commands and usage tips.

@sentry

sentry Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between b71be3c and f91d75e.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • doc/layout/flexbox.md
  • example/lib/pages/layout/flex_grow.dart
  • lib/src/widgets/w_div.dart
  • skills/wind-ui/references/layouts.md
  • skills/wind-ui/references/tailwind-divergence.md
  • test/widgets/w_div/flex_stretch_test.dart

Comment thread example/lib/pages/layout/flex_grow.dart

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 treat WButton and WAnchor children as stretch candidates (with existing opt-outs like explicit width tokens, self-flex tokens, and absolute).
  • 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.

Comment on lines 9 to 11
import 'w_anchor.dart';
import 'w_button.dart';
import 'w_text.dart';
Comment thread lib/src/widgets/w_div.dart Outdated
Comment on lines +849 to +853
/// 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.
Comment thread lib/src/widgets/w_div.dart Outdated
Comment on lines +855 to +858
/// 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.
Comment thread lib/src/widgets/w_div.dart Outdated
Comment on lines +871 to +872
// WText / raw widget: no cross-axis width to honor, always eligible.
return true;
Comment on lines +417 to +419
// 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.
Comment thread doc/layout/flexbox.md Outdated
```

> **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.
@anilcancakir

Copy link
Copy Markdown
Collaborator Author

Addressed the review:

  • CodeRabbit (dark: pairs, flex_grow.dart): fixed. Every text-white in the new stretch demo now carries dark:text-white (5 occurrences).

  • Copilot (doc comments imply WAnchor > WDiv(grow) is safe/supported, w_div.dart:853/858, flexbox.md:211): fixed. Reworded so the comments no longer suggest grow inside WAnchor is meaningful. WAnchor > WDiv(grow) is now called out as unsupported in its own right (the inner WDiv's Expanded asserts under the WAnchor's non-Flex wrappers regardless of stretch); the self-flex exclusion is described as mirroring the direct-WDiv rule (where it genuinely prevents the stretch-compounding assertion), not as a rescue for the wrapped-grow case.

  • Copilot (raw-widget "no width to honor", w_div.dart:872): fixed. Reworded to a policy statement: a WAnchor-wrapped non-WDiv child is stretched so the tap surface fills the column; any explicit width on the wrapped widget still constrains its own content.

  • Copilot (test comment "WButton self-wraps in Expanded", flex_stretch_test.dart:419): fixed. WButton does not wrap in Expanded; the comment now says the grow token is excluded by _selfWrapsInFlex for consistency with the direct-WDiv rule.

  • Copilot (circular import w_div.dart ↔ w_button.dart, line 11): keeping as-is. Intra-package file imports that form a cycle are idiomatic in Dart and Flutter (the SDK's own material / widgets libraries do this pervasively); Dart resolves them and dart analyze raises no warning. The "circular dependency" concern applies to circular dependencies between published packages, not file-level imports within one library. Removing it would mean dropping the child is WButton eligibility (a locked requirement) for no real benefit.

Verification after the fixes: dart analyze 0 issues, dart format no diff, flutter test green, 0 em-dash in the diff.

@anilcancakir anilcancakir merged commit d07604a into master Jun 9, 2026
9 checks passed
@anilcancakir anilcancakir deleted the feat/flex-stretch-wrappers branch June 9, 2026 01:03
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.

2 participants