From 9dbff057f414da527d3ad3bf91d11d213246e477 Mon Sep 17 00:00:00 2001 From: dagur Date: Tue, 8 Sep 2026 02:29:43 -0700 Subject: [PATCH] Layout breaks when the first element has a different minWidth than the rest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: fixes https://github.com/react/yoga/issues/2006 `distributeFreeSpaceFirstPass` decrements `totalFlexGrowFactors` / `totalFlexShrinkScaledFactors` as it freezes items, but only reduces `remainingFreeSpace` after the loop. Items after the first frozen one get an inflated fair share and freeze spuriously. When the first item clamps, the whole line freezes and `remainingFreeSpace` drains to 0, so the second pass has nothing to distribute and everything falls back to its flex basis — a 540px row of three `flexGrow: 1` items with `maxWidth: 180` and minWidths 60/30/30 lays out as 60/30/30 instead of 180/180/180. Snapshot both totals before the loop and divide by the snapshot. The first pass is then iteration 1 of CSS Flexbox §9.7, and independent of child order. Changelog: [General][Fixed] - Fix a flex line collapsing to its minimum sizes when the first item clamps to its min or max main size X-link: https://github.com/react/yoga/pull/2021 Reviewed By: javache Differential Revision: D119142409 Pulled By: pasqualeanatriello --- .../yoga/yoga/algorithm/CalculateLayout.cpp | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 4e7930a92bc2..43983227bec9 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -1280,6 +1280,19 @@ static void distributeFreeSpaceFirstPass( float boundMainSize = 0; float deltaFreeSpace = 0; + // The first pass performs a single distribution of the free space over all + // of the line's flexible items, so every item's tentative size must be + // computed against the *original* totals. The totals are still reduced as + // items get frozen below (so the second pass can redistribute), but those + // reduced values must not feed back into the fair-share calculation for the + // remaining items: doing so inflates their tentative size and can freeze + // items that should still be able to grow/shrink (see + // https://github.com/react/yoga/issues/2006). + const float originalTotalFlexGrowFactors = + flexLine.layout.totalFlexGrowFactors; + const float originalTotalFlexShrinkScaledFactors = + flexLine.layout.totalFlexShrinkScaledFactors; + for (auto currentLineChild : flexLine.itemsInFlow) { float childFlexBasis = boundAxisWithinMinAndMax( currentLineChild, @@ -1299,8 +1312,7 @@ static void distributeFreeSpaceFirstPass( flexShrinkScaledFactor != 0) { baseMainSize = childFlexBasis + flexLine.layout.remainingFreeSpace / - flexLine.layout.totalFlexShrinkScaledFactors * - flexShrinkScaledFactor; + originalTotalFlexShrinkScaledFactors * flexShrinkScaledFactor; boundMainSize = boundAxisWithAutoMin( currentLineChild, mainAxis, @@ -1328,8 +1340,8 @@ static void distributeFreeSpaceFirstPass( // Is this child able to grow? if (yoga::isDefined(flexGrowFactor) && flexGrowFactor != 0) { baseMainSize = childFlexBasis + - flexLine.layout.remainingFreeSpace / - flexLine.layout.totalFlexGrowFactors * flexGrowFactor; + flexLine.layout.remainingFreeSpace / originalTotalFlexGrowFactors * + flexGrowFactor; boundMainSize = boundAxis( currentLineChild, mainAxis,

AltStyle によって変換されたページ (->オリジナル) /