docs(layout): document the intrinsic-sizing limitation (#129)#136
Conversation
Wrapping Wind content in IntrinsicHeight/IntrinsicWidth (or a Row/Column that needs child intrinsic heights for equal-height columns) throws "LayoutBuilder does not support returning intrinsic dimensions" when that content resolves h-full or a flex basis-*: Wind wraps such content in an internal LayoutBuilder, which runs in the layout phase and cannot answer intrinsic queries. This is a fundamental Flutter constraint, not a Wind bug, and was previously only discoverable at runtime. Adds a dedicated "Intrinsic Sizing Limitation" section to doc/layout/sizing.md (symptom, cause, what triggers it, escape hatches: explicit h-*/size-* sizing, Stack + Positioned for equal-height rows, and the intrinsic-free items-stretch column), and mirrors it in the skill (SKILL.md section 6 + references/layouts.md items-stretch caveat, version 2.8.0). Doc-only: no lib/ change, so CHANGELOG and coverage are untouched. Closes #129
|
Warning Review limit reached
Next review available in: 14 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Documents a Flutter intrinsic-sizing limitation that can surface when Wind introduces internal LayoutBuilder wrappers (notably via basis-* and, in some contexts, h-full), so users can avoid the runtime assertion and choose workable alternatives.
Changes:
- Adds an “Intrinsic Sizing Limitation” section to the public sizing docs with symptom/cause/triggers/escape hatches.
- Updates the
wind-uiskill and layout reference to include the same limitation and guidance. - Bumps the
wind-uiskill version to2.8.0.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| skills/wind-ui/SKILL.md | Adds a limitation note and bumps skill version metadata. |
| skills/wind-ui/references/layouts.md | Adds an intrinsic-sizing caveat to the items-stretch/scroll guidance. |
| doc/layout/sizing.md | Documents the intrinsic-sizing assertion, root cause, triggers, and workarounds. |
|
|
||
| `items-stretch` inside a `SingleChildScrollView` needs an `IntrinsicHeight` wrapper from native Flutter; Wind has no token for it. Rare; reach for it when row children inside a scroll must match heights. | ||
|
|
||
| **Intrinsic sizing limitation.** Wrapping Wind content in `IntrinsicHeight` / `IntrinsicWidth` (or a `Row`/`Column` that needs child intrinsic heights for equal-height columns) throws `LayoutBuilder does not support returning intrinsic dimensions` WHEN that content resolves `h-full` or a flex `basis-*` — both insert an internal `LayoutBuilder`, which cannot answer intrinsic queries (a Flutter constraint, not a Wind bug). Escape hatches: use explicit `h-*` / `size-*` instead of `h-full`; do not wrap such content in `IntrinsicHeight`; for equal-height rows use a `Stack` + `Positioned(top:0,bottom:0)`. Wind's own `items-stretch` column is intrinsic-free and safe. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
h-full only inserts a LayoutBuilder in an unbounded-height context, and basis-* wraps the surrounding flex in a single LayoutBuilder (not the individual child). Reword the sizing.md section, SKILL.md note, and layouts.md caveat to match the implementation precisely.
|
Fixed all three: reworded @coderabbitai review |
|
✅ Action performedReview finished.
|
|
|
||
| `items-stretch` inside a `SingleChildScrollView` needs an `IntrinsicHeight` wrapper from native Flutter; Wind has no token for it. Rare; reach for it when row children inside a scroll must match heights. | ||
|
|
||
| **Intrinsic sizing limitation.** Wrapping Wind content in `IntrinsicHeight` / `IntrinsicWidth` (or a `Row`/`Column` that needs child intrinsic heights for equal-height columns) throws `LayoutBuilder does not support returning intrinsic dimensions` WHEN that content triggers Wind's internal `LayoutBuilder` paths: `h-full` (only in an unbounded-height context) or a flex `basis-*` (a single `LayoutBuilder` around the surrounding flex). `LayoutBuilder` cannot answer intrinsic queries (a Flutter constraint, not a Wind bug). Escape hatches: use explicit `h-*` / `size-*` instead of `h-full`; do not wrap such content in `IntrinsicHeight`; for equal-height rows use a `Stack` + `Positioned(top:0,bottom:0)`. Wind's own `items-stretch` column is intrinsic-free and safe. |
| LayoutBuilder does not support returning intrinsic dimensions. | ||
| ``` | ||
|
|
||
| **Why.** To resolve some sizes against the parent's real constraints, Wind introduces a `LayoutBuilder` (see `lib/src/widgets/w_div.dart`): `h-full` adds one around the cell only when the incoming height is unbounded, and a flex `basis-*` adds a single one around the surrounding flex when any direct child uses `basis-*`. `LayoutBuilder` runs during the layout phase, not the intrinsic-sizing phase, so an intrinsic-dimension query that passes through one of those `LayoutBuilder` paths asserts. This is a fundamental Flutter constraint (`LayoutBuilder` genuinely cannot answer intrinsics), not a Wind bug. Wind content that does **not** hit those `h-full` / `basis-*` paths carries no `LayoutBuilder` and is safe to wrap. |
| - Prefer explicit sizing: give the cells a fixed `h-*` (or `size-*`) instead of `h-full` + `IntrinsicHeight`. | ||
| - Do not wrap Wind content that uses `h-full` / `basis-*` in `IntrinsicHeight` / `IntrinsicWidth`. | ||
| - For an equal-height row, use a `Stack` with a `Positioned(top: 0, bottom: 0)` element for the part that must fill, or reserve equal content so natural heights already match. | ||
| - Wind's own column cross-axis stretch (`items-stretch`, the `flex flex-col` default) is intrinsic-free (`LayoutBuilder` + `SizedBox(width: double.infinity)`), so it is animation-safe and does not hit this assertion. |
|
Addressed the precision concerns + merged master:
@coderabbitai review |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr diff 136 --repo fluttersdk/wind -- doc/layout/sizing.md SKILL.md references/layouts.md || trueLength of output: 306 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr diff 136 --repo fluttersdk/wind > /tmp/pr136.diff
wc -l /tmp/pr136.diff
grep -n "^diff --git" /tmp/pr136.diffLength of output: 520 🏁 Script executed: #!/bin/bash
cat /tmp/pr136.diffLength of output: 5682 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 136 --repo fluttersdk/wind --json commits --jq '.commits[-5:] | .[] | {oid, messageHeadline, committedDate}'Length of output: 816 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 136 --repo fluttersdk/wind --json commits --jq '.commits | length'
gh pr view 136 --repo fluttersdk/wind --json commits --jq '.commits[] | {oid, messageHeadline, committedDate}'Length of output: 887 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 136 --repo fluttersdk/wind --json headRefOid,updatedAt,commits --jq '{headRefOid, updatedAt}'
gh api repos/fluttersdk/wind/commits/9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.commit.committer.date'Length of output: 495 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh api repos/fluttersdk/wind/contents/doc/layout/sizing.md?ref=9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.content' | base64 -d | sed -n '160,215p'
echo "-----SKILL.md-----"
gh api repos/fluttersdk/wind/contents/skills/wind-ui/SKILL.md?ref=9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.content' | base64 -d | sed -n '220,235p'
echo "-----layouts.md-----"
gh api repos/fluttersdk/wind/contents/skills/wind-ui/references/layouts.md?ref=9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.content' | base64 -d | sed -n '375,395p'Length of output: 7786 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "--- diff of precise commit ---"
git -C . rev-parse --is-inside-work-tree 2>/dev/null || echo "no repo, using gh"
gh api repos/fluttersdk/wind/commits/7b0bba5f25a83d11ef217a3474c1379694fbdd1d --jq '.files[].filename'
echo "--- compare precise commit vs merge commit for sizing.md ---"
gh api repos/fluttersdk/wind/compare/7b0bba5f25a83d11ef217a3474c1379694fbdd1d...9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.files[] | .filename'Length of output: 1909 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh api repos/fluttersdk/wind/compare/7b0bba5f25a83d11ef217a3474c1379694fbdd1d...9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.files[] | select(.filename=="doc/layout/sizing.md") | .patch'Length of output: 1619 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh api repos/fluttersdk/wind/compare/7b0bba5f25a83d11ef217a3474c1379694fbdd1d...9974f869d9fa2e1d9afd6057e2e7b2b0e412f7f1 --jq '.files[] | select(.filename=="skills/wind-ui/SKILL.md") | .patch'Length of output: 21242
and:
I diffed your "make root cause precise" commit ( So it looks like the rewording addressing the "intrinsic-free and safe" overclaim wasn't actually pushed. Could you double-check that your local changes were committed and pushed to this branch? Once that lands, ping me again and I'll do a fresh pass. ✅ Action performedReview finished.
|
…(PR #136 follow-up) (#138) Wind's items-stretch column uses a LayoutBuilder internally, so it is a REPLACEMENT for IntrinsicHeight (you don't wrap it in one), not something that is itself safe to nest inside an IntrinsicHeight. Reword SKILL.md and sizing.md accordingly, and list the column-stretch LayoutBuilder as another path in the 'safe to wrap' note. (Follow-up: these rewords missed the #136 squash because an intermediate commit was skipped.)
Summary
Fixes #129. Wrapping Wind content in
IntrinsicHeight/IntrinsicWidth(or aRow/Columnthat needs child intrinsic heights for equal-height columns) throwsLayoutBuilder does not support returning intrinsic dimensions, and this was only discoverable at runtime.Root cause (now documented)
To resolve
h-fulland flexbasis-*against the parent's real constraints, Wind wraps that content in an internalLayoutBuilder.LayoutBuilderruns in the layout phase, not the intrinsic-sizing phase, so any intrinsic query passing through such content asserts. This is a fundamental Flutter constraint, not a Wind bug. Content that does not resolveh-full/basis-*carries noLayoutBuilderand is safe.Changes
doc/layout/sizing.md: new Intrinsic Sizing Limitation section (symptom, cause, what triggers it, escape hatches — explicith-*/size-*,Stack+Positioned(top:0,bottom:0)for equal-height rows, and the intrinsic-freeitems-stretchcolumn) + ToC entry.SKILL.md§6 limitation note +references/layouts.mditems-stretch caveat, version 2.8.0.Definition of done
lib/change, soCHANGELOG.md, tests, and coverage are intentionally untouched.dart format --set-exit-if-changed: clean (0 changed).dart analyze: clean. No new<x-preview>added (section uses inline code), so no example page needed.