Repository navigation
Keep cross axis margins and relative insets of items in wrapping containers (#59532) - #59532
Open
cipolleschi wants to merge 1 commit into
Open
cipolleschi wants to merge 1 commit into
cipolleschi wants to merge 1 commit into
Conversation
|
@cipolleschi has exported this pull request. If you are a Meta employee, you can view the originating Diff in D127132637. |
…ainers (react#59532) Summary: Fixes react/yoga#1856 Fixes react/yoga#1067 In wrapping containers, STEP 8 (multi line alignment) of `CalculateLayout.cpp` repositions items on the cross axis and drops part of each box. In react/yoga#1856 the container is a column (Yoga's default), so `left` is on the cross axis. - `flex-start` uses `computeFlexStartPosition` (the inset) where `computeFlexStartMargin` belongs. v2.0.1 used the margin, so this is a 3.0 regression from react/yoga#1561. - `stretch`, `center` and `flex-end` never add the relative inset. - `center` centers the border box instead of the margin box, which is react/yoga#1067. Every case now uses the leading margin, trailing margin and `relativePosition`. `wrap-reverse` mirrors positions afterwards, so it leads with the flex end margin and applies the inset after mirroring, keeping each margin on its edge and `top: 10` moving the item down. Also, a percentage inset on a `flex-start` item now resolves against the container's cross size, as without wrap (`top: 10%` in a 100x200 row: 10 to 20), and baseline rows, which run this pass even without wrap, honor `bottom` and ignore insets on static items. Column container, padding 10, `flex-wrap: wrap`, default `align-content: flex-start`, item with margin 5 and `left: 10` (item left; expected worked out from the spec): | `align-items` | main | this PR | expected | |---|---|---|---| | `flex-start` | 20 | 25 | 25 | | `stretch` | 15 | 25 | 25 | | `center` | 15 | 25 | 25 | | `flex-end` | 15 | 25 | 25 | | `flex-start`, no inset | 10 | 15 | 15 | The react/yoga#1067 repro goes from top 50 to 100. ### Errata These positions have been in place for a long time, and React Native runs Yoga with `YGErrataAll`. So the previous behavior is kept behind a new erratum, `YGErrataWrapCrossAlignmentIgnoresMarginAndInset` (`1 << 5`). When it is set, STEP 8 and the `wrap-reverse` mirroring use their previous offsets. New configs leave it unset and get the fix; `YGErrataAll` and `YGErrataClassic` include it, so React Native keeps its current layout under the classic conformance, and strict gets the spec behavior. With the erratum, the `main` column of the table above is what you get. The enum bindings (C++, Kotlin and TypeScript) are regenerated with `enums.py`. ### Tests The spec cases are gentest fixtures, eleven in `YGFlexWrapTest.html` and one in `YGAlignItemsTest.html`, with expected values from Chrome and generated C++, Java and JS tests. They cover row and column, LTR and RTL, `wrap` and `wrap-reverse` (including one sided margins), baseline, static items, a percentage inset and both issue repros. All 12 generated C++ tests fail without the fix. `tests/YGFlexWrapCrossAlignmentTest.cpp` keeps 4 hand written errata cases that pin the previous positions under the erratum, including a wrapping row with `align-items: flex-start` and items with `margin: 4`, whose lines stay at top 0 and 38 under `YGErrataAll` and move to 4 and 42 under `YGErrataNone`. The positions they expect under the erratum are the ones `main` gives, and all 4 fail without the erratum checks in `CalculateLayout.cpp`. With the change, all 884 C++ tests pass (868 plus 12 generated plus 4). Laying out 20000 random trees with `YGErrataAll`, every position on this branch matches the base commit exactly, and without the erratum every position matches the first commit of this PR. Not covered here: `auto` cross margins in wrapping containers and baseline rows, which STEP 8 also ignores on `main` (react/yoga#2048). Changelog: [General][Fixed] - Keep cross axis margins and relative insets of items in wrapping containers, with a new erratum that keeps the previous positions under YGErrataAll and YGErrataClassic X-link: react/yoga#2045 Test Plan: Universal macOS Cosmo Studio app and dSYM build passed with the configuration from the failing CI job: ```bash buck2 build fbsource//xplat/mode/cosmo/auto.py#production,macosx-universal,e2e,bundle-rn --show-json-output --config apple.fb_bundle_version=1101344647 //xplat/arfx/cosmo/studio/app/mac:Cosmo "//xplat/arfx/cosmo/studio/app/mac:Cosmo[dsym]" ``` `BUILD SUCCEEDED`, exit code 0. https://www.internalfb.com/buck2/fbae0652-2658-4575-a895-b8a3d54d386f Yoga regression tests: ```bash buck2 test //xplat/yoga:tests ``` Pass 893. Fail 0. Skip 0. Infra Failure 0. Build failure 0. https://www.internalfb.com/intern/testinfra/testrun/12666374165098828 C++ stable API snapshot validation: ```bash buck2 run //xplat/js/react-native-github/scripts/cxx-api:api-snapshot -- --validate ``` Passed, exit code 0. The base includes the landed Boost Filesystem fix in D127790095. The Yoga changes are unchanged apart from merging onto the current base. App launch and Cosmo E2E execution were not tested by the local build. Reviewed By: javache Differential Revision: D127132637 Pulled By: cipolleschi
cipolleschi
force-pushed
the
export-D127132637
branch
from
October 27, 2026 16:38
22e2bc7 to
7ae2cf2
Compare
Visual regression1 visual difference(s) at android: no capture ios
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary:
Fixes react/yoga#1856
Fixes react/yoga#1067
In wrapping containers, STEP 8 (multi line alignment) of
CalculateLayout.cpprepositions items on the cross axis and drops part of each box. In react/yoga#1856 the container is a column (Yoga's default), soleftis on the cross axis.flex-startusescomputeFlexStartPosition(the inset) wherecomputeFlexStartMarginbelongs. v2.0.1 used the margin, so this is a 3.0 regression from Fix mismatched cases of inlineStart/End and flexStart/End yoga#1561.stretch,centerandflex-endnever add the relative inset.centercenters the border box instead of the margin box, which is [React-Native]: Combining flexWrap, alignItems & wrap leads to unwanted alignment yoga#1067.Every case now uses the leading margin, trailing margin and
relativePosition.wrap-reversemirrors positions afterwards, so it leads with the flex end margin and applies the inset after mirroring, keeping each margin on its edge andtop: 10moving the item down.Also, a percentage inset on a
flex-startitem now resolves against the container's cross size, as without wrap (top: 10%in a 100x200 row: 10 to 20), and baseline rows, which run this pass even without wrap, honorbottomand ignore insets on static items.Column container, padding 10,
flex-wrap: wrap, defaultalign-content: flex-start, item with margin 5 andleft: 10(item left; expected worked out from the spec):align-itemsflex-startstretchcenterflex-endflex-start, no insetThe react/yoga#1067 repro goes from top 50 to 100.
Errata
These positions have been in place for a long time, and React Native runs Yoga with
YGErrataAll. So the previous behavior is kept behind a new erratum,YGErrataWrapCrossAlignmentIgnoresMarginAndInset(1 << 5). When it is set, STEP 8 and thewrap-reversemirroring use their previous offsets. New configs leave it unset and get the fix;YGErrataAllandYGErrataClassicinclude it, so React Native keeps its current layout under the classic conformance, and strict gets the spec behavior. With the erratum, themaincolumn of the table above is what you get.The enum bindings (C++, Kotlin and TypeScript) are regenerated with
enums.py.Tests
The spec cases are gentest fixtures, eleven in
YGFlexWrapTest.htmland one inYGAlignItemsTest.html, with expected values from Chrome and generated C++, Java and JS tests. They cover row and column, LTR and RTL,wrapandwrap-reverse(including one sided margins), baseline, static items, a percentage inset and both issue repros. All 12 generated C++ tests fail without the fix.tests/YGFlexWrapCrossAlignmentTest.cppkeeps 4 hand written errata cases that pin the previous positions under the erratum, including a wrapping row withalign-items: flex-startand items withmargin: 4, whose lines stay at top 0 and 38 underYGErrataAlland move to 4 and 42 underYGErrataNone. The positions they expect under the erratum are the onesmaingives, and all 4 fail without the erratum checks inCalculateLayout.cpp.With the change, all 884 C++ tests pass (868 plus 12 generated plus 4). Laying out 20000 random trees with
YGErrataAll, every position on this branch matches the base commit exactly, and without the erratum every position matches the first commit of this PR.Not covered here:
autocross margins in wrapping containers and baseline rows, which STEP 8 also ignores onmain(react/yoga#2048).Changelog:
[General][Fixed] - Keep cross axis margins and relative insets of items in wrapping containers, with a new erratum that keeps the previous positions under YGErrataAll and YGErrataClassic
X-link: react/yoga#2045
Test Plan:
Universal macOS Cosmo Studio app and dSYM build passed with the configuration from the failing CI job:
buck2 build fbsource//xplat/mode/cosmo/auto.py#production,macosx-universal,e2e,bundle-rn --show-json-output --config apple.fb_bundle_version=1101344647 //xplat/arfx/cosmo/studio/app/mac:Cosmo "//xplat/arfx/cosmo/studio/app/mac:Cosmo[dsym]"BUILD SUCCEEDED, exit code 0.https://www.internalfb.com/buck2/fbae0652-2658-4575-a895-b8a3d54d386f
Yoga regression tests:
buck2 test //xplat/yoga:testsPass 893. Fail 0. Skip 0. Infra Failure 0. Build failure 0.
https://www.internalfb.com/intern/testinfra/testrun/12666374165098828
C++ stable API snapshot validation:
Passed, exit code 0.
The base includes the landed Boost Filesystem fix in D127790095. The Yoga changes are unchanged apart from merging onto the current base. App launch and Cosmo E2E execution were not tested by the local build.
Reviewed By: javache
Differential Revision: D127132637
Pulled By: cipolleschi