-
Notifications
You must be signed in to change notification settings - Fork 0
flex-1 + justify-between: Flexible wrapping breaks space distribution in Row #45
Description
Bug Description
When a WDiv flex-row uses justify-between alongside children that have flex-1, the space distribution doesn't work correctly — non-flex children are not pushed to the right edge. Instead, they sit immediately adjacent to the flex-1 child.
Observed behavior: First render may show correct positioning, then children shift left on rebuild.
Expected behavior: flex-1 child fills remaining space (via Expanded), non-flex children stay at the right edge — matching CSS justify-content: space-between with flex: 1 behavior.
Reproduction
WDiv(
className: 'w-full flex flex-row items-center justify-between gap-4',
children: [
// Title section — should fill remaining space
WDiv(
className: 'flex-1 min-w-0',
child: WText('Long title that should truncate...', className: 'truncate'),
),
// Actions — should be pushed to the right edge
WDiv(
className: 'shrink-0',
child: WText('Action'),
),
],
)Workaround: Replace WDiv Row with native Flutter Row + Expanded:
Row(children: [Expanded(child: titleWidget), actionWidget])Root Cause
In w_div.dart lines 404-421, when needsSpaceDistribution is true (i.e. justify-between, space-around, or space-evenly), all children are wrapped with Flexible:
final needsFlexible = needsSpaceDistribution || hasOverflowClip;
final rowChildren = needsFlexible
? gappedChildren.map((child) {
if (child is SizedBox || child is Flexible || child is Expanded) {
return child;
}
if (child is WDiv && _hasFlexClass(child.className)) {
return child;
}
// ...
return Flexible(child: child); // ← wraps ALL non-flex children
}).toList()
: gappedChildren;Why this breaks
- The
flex-1child correctly becomesExpanded(flex: 1)— tight fit, takes all remaining space. - Non-flex children (e.g.
shrink-0actions) get wrapped withFlexible(child: ...)— loose fit,flex: 1by default. - Now the Row has two flex children — one
Expanded(flex: 1)and oneFlexible(flex: 1). Flutter distributes space equally between them by flex ratio, making both compete for the same space. justify-betweenbecomes irrelevant because there's no non-flex space left to distribute — all children are flex participants.
Additional issue: shrink-0 semantics
In flexbox_grid_parser.dart line 112:
'shrink-0': FlexFit.tight, // flex-shrink: 0 (don't shrink)shrink-0 maps to FlexFit.tight, but CSS flex-shrink: 0 means "don't shrink below intrinsic size" — it should prevent the child from being wrapped in Flexible at all, not set it to tight fit. A tight Flexible forces the child to fill its flex allocation, which is the opposite of "keep intrinsic size."
Suggested Fix
When needsSpaceDistribution is true, don't blindly wrap all children with Flexible. Instead:
- Skip wrapping children that have
shrink-0(they should keep their intrinsic size) - Only wrap children that explicitly opt into shrinking
- Respect that
flex-1children already handle their ownExpandedwrapping
final rowChildren = needsFlexible
? gappedChildren.map((child) {
if (child is SizedBox || child is Flexible || child is Expanded) {
return child;
}
// Skip flex-N children (they self-wrap with Expanded)
if (child is WDiv && _hasFlexClass(child.className)) {
return child;
}
// Skip shrink-0 children (should not shrink)
if (child is WDiv && _hasShrinkZero(child.className)) {
return child;
}
return Flexible(child: child);
}).toList()
: gappedChildren;Environment
- Wind UI:
^1.0.0-alpha.4 - Flutter: 3.41.6
- Dart SDK: ^3.11.3