Skip to content

Commit a594050

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
Re-land: fixYogaFlexBasisFitContentInMainAxis (facebook#56064)
Summary: X-link: facebook/yoga#1917 Re-land of D94658492 with fixes, which was reverted in D95669495. ## Context D94658492 added the `fixYogaFlexBasisFitContentInMainAxis` flag to avoid unnecessary re-measurement cascades in Yoga. When Yoga computes flex basis for container children, the legacy behavior applies a `FitContent` constraint in the main axis, bounding the child's measurement by the parent's available space. This creates a dependency between the child's flex basis and the parent's content-determined size — when one sibling changes size, all siblings get re-measured and their shadow nodes get cloned unnecessarily. The fix switches from `FitContent` to `MaxContent` for non-measure container children under auto-height parents, making each child's flex basis independent of the parent's size. ## What went wrong D94658492 modeled the fix as a `YogaErrata` bit (`FLEX_BASIS_FIT_CONTENT_IN_MAIN_AXIS`). Errata flags are bitmasks, and apps that opt into `ALL` or `CLASSIC` errata (like IGVR and Airwave) inadvertently picked up the new behavior without explicitly enabling the feature flag, causing breakages. ## What changed in this re-land This diff models the fix as a `YogaExperimentalFeature` (`FIX_FLEX_BASIS_FIT_CONTENT`) instead of a `YogaErrata` bit. Experimental features are individually opt-in, so existing apps won't accidentally pick up the change. This diff only wires up the RN feature flag infrastructure (flag defaults to `false`). The iOS MobileConfig override and the Yoga layout logic will be landed in follow-up diffs. changelog: [internal] Reviewed By: javache, NickGerleman Differential Revision: D95852922
1 parent c625015 commit a594050

27 files changed

+266
-65
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<039798c50526ff1abf33bc7987aa78a9>>
7+
* @generated SignedSource<<5144fb0350b71394206d614c68ef87f0>>
88
*/
99

1010
/**
@@ -390,6 +390,12 @@ public object ReactNativeFeatureFlags {
390390
@JvmStatic
391391
public fun fixTextClippingAndroid15useBoundsForWidth(): Boolean = accessor.fixTextClippingAndroid15useBoundsForWidth()
392392

393+
/**
394+
* Fix flex basis computation to not apply FitContent constraint in the main axis for non-measure container nodes, preventing unnecessary re-measurement in scroll containers.
395+
*/
396+
@JvmStatic
397+
public fun fixYogaFlexBasisFitContentInMainAxis(): Boolean = accessor.fixYogaFlexBasisFitContentInMainAxis()
398+
393399
/**
394400
* Enable system assertion validating that Fusebox is configured with a single host. When set, the CDP backend will dynamically disable features (Perf and Network) in the event that multiple hosts are registered (undefined behaviour), and broadcast this over `ReactNativeApplication.systemStateChanged`.
395401
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<cbc85fcd815ba2585166a53e7b410f30>>
7+
* @generated SignedSource<<d284f066f036908977797a381a044dfa>>
88
*/
99

1010
/**
@@ -80,6 +80,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
8080
private var fixFindShadowNodeByTagRaceConditionCache: Boolean? = null
8181
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
8282
private var fixTextClippingAndroid15useBoundsForWidthCache: Boolean? = null
83+
private var fixYogaFlexBasisFitContentInMainAxisCache: Boolean? = null
8384
private var fuseboxAssertSingleHostStateCache: Boolean? = null
8485
private var fuseboxEnabledReleaseCache: Boolean? = null
8586
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
@@ -650,6 +651,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
650651
return cached
651652
}
652653

654+
override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean {
655+
var cached = fixYogaFlexBasisFitContentInMainAxisCache
656+
if (cached == null) {
657+
cached = ReactNativeFeatureFlagsCxxInterop.fixYogaFlexBasisFitContentInMainAxis()
658+
fixYogaFlexBasisFitContentInMainAxisCache = cached
659+
}
660+
return cached
661+
}
662+
653663
override fun fuseboxAssertSingleHostState(): Boolean {
654664
var cached = fuseboxAssertSingleHostStateCache
655665
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<3d472893c05bdee6e09f834f52d3d92f>>
7+
* @generated SignedSource<<de1c66a540520cd88c4d358ba30f2c6d>>
88
*/
99

1010
/**
@@ -148,6 +148,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
148148

149149
@DoNotStrip @JvmStatic public external fun fixTextClippingAndroid15useBoundsForWidth(): Boolean
150150

151+
@DoNotStrip @JvmStatic public external fun fixYogaFlexBasisFitContentInMainAxis(): Boolean
152+
151153
@DoNotStrip @JvmStatic public external fun fuseboxAssertSingleHostState(): Boolean
152154

153155
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<29f7031f91527f41f2f184596c542a5b>>
7+
* @generated SignedSource<<ab3b1d2277b8cc9db1708ef94515fb35>>
88
*/
99

1010
/**
@@ -143,6 +143,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
143143

144144
override fun fixTextClippingAndroid15useBoundsForWidth(): Boolean = false
145145

146+
override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean = false
147+
146148
override fun fuseboxAssertSingleHostState(): Boolean = true
147149

148150
override fun fuseboxEnabledRelease(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<014ee4afdf58a61c9974df198068d81a>>
7+
* @generated SignedSource<<7b87f5541ecf881d8ce51c5edd5b99b0>>
88
*/
99

1010
/**
@@ -84,6 +84,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
8484
private var fixFindShadowNodeByTagRaceConditionCache: Boolean? = null
8585
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
8686
private var fixTextClippingAndroid15useBoundsForWidthCache: Boolean? = null
87+
private var fixYogaFlexBasisFitContentInMainAxisCache: Boolean? = null
8788
private var fuseboxAssertSingleHostStateCache: Boolean? = null
8889
private var fuseboxEnabledReleaseCache: Boolean? = null
8990
private var fuseboxFrameRecordingEnabledCache: Boolean? = null
@@ -714,6 +715,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
714715
return cached
715716
}
716717

718+
override fun fixYogaFlexBasisFitContentInMainAxis(): Boolean {
719+
var cached = fixYogaFlexBasisFitContentInMainAxisCache
720+
if (cached == null) {
721+
cached = currentProvider.fixYogaFlexBasisFitContentInMainAxis()
722+
accessedFeatureFlags.add("fixYogaFlexBasisFitContentInMainAxis")
723+
fixYogaFlexBasisFitContentInMainAxisCache = cached
724+
}
725+
return cached
726+
}
727+
717728
override fun fuseboxAssertSingleHostState(): Boolean {
718729
var cached = fuseboxAssertSingleHostStateCache
719730
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<acd57b19a67924a91c6b25904cb24d3b>>
7+
* @generated SignedSource<<f34b257861830bae7012fc5201904831>>
88
*/
99

1010
/**
@@ -143,6 +143,8 @@ public interface ReactNativeFeatureFlagsProvider {
143143

144144
@DoNotStrip public fun fixTextClippingAndroid15useBoundsForWidth(): Boolean
145145

146+
@DoNotStrip public fun fixYogaFlexBasisFitContentInMainAxis(): Boolean
147+
146148
@DoNotStrip public fun fuseboxAssertSingleHostState(): Boolean
147149

148150
@DoNotStrip public fun fuseboxEnabledRelease(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/yoga/YogaExperimentalFeature.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
package com.facebook.yoga;
1111

1212
public enum YogaExperimentalFeature {
13-
WEB_FLEX_BASIS(0);
13+
WEB_FLEX_BASIS(0),
14+
FIX_FLEX_BASIS_FIT_CONTENT(1);
1415

1516
private final int mIntValue;
1617

@@ -25,6 +26,7 @@ public int intValue() {
2526
public static YogaExperimentalFeature fromInt(int value) {
2627
switch (value) {
2728
case 0: return WEB_FLEX_BASIS;
29+
case 1: return FIX_FLEX_BASIS_FIT_CONTENT;
2830
default: throw new IllegalArgumentException("Unknown enum value: " + value);
2931
}
3032
}

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<a753500d987b8719f0ba1bba8d3e4dc4>>
7+
* @generated SignedSource<<b4670c40175b42e04eb8f03b752a0c00>>
88
*/
99

1010
/**
@@ -399,6 +399,12 @@ class ReactNativeFeatureFlagsJavaProvider
399399
return method(javaProvider_);
400400
}
401401

402+
bool fixYogaFlexBasisFitContentInMainAxis() override {
403+
static const auto method =
404+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixYogaFlexBasisFitContentInMainAxis");
405+
return method(javaProvider_);
406+
}
407+
402408
bool fuseboxAssertSingleHostState() override {
403409
static const auto method =
404410
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fuseboxAssertSingleHostState");
@@ -877,6 +883,11 @@ bool JReactNativeFeatureFlagsCxxInterop::fixTextClippingAndroid15useBoundsForWid
877883
return ReactNativeFeatureFlags::fixTextClippingAndroid15useBoundsForWidth();
878884
}
879885

886+
bool JReactNativeFeatureFlagsCxxInterop::fixYogaFlexBasisFitContentInMainAxis(
887+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
888+
return ReactNativeFeatureFlags::fixYogaFlexBasisFitContentInMainAxis();
889+
}
890+
880891
bool JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState(
881892
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
882893
return ReactNativeFeatureFlags::fuseboxAssertSingleHostState();
@@ -1233,6 +1244,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
12331244
makeNativeMethod(
12341245
"fixTextClippingAndroid15useBoundsForWidth",
12351246
JReactNativeFeatureFlagsCxxInterop::fixTextClippingAndroid15useBoundsForWidth),
1247+
makeNativeMethod(
1248+
"fixYogaFlexBasisFitContentInMainAxis",
1249+
JReactNativeFeatureFlagsCxxInterop::fixYogaFlexBasisFitContentInMainAxis),
12361250
makeNativeMethod(
12371251
"fuseboxAssertSingleHostState",
12381252
JReactNativeFeatureFlagsCxxInterop::fuseboxAssertSingleHostState),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<6ff305bf95e95cd8a65c138fc24b43f8>>
7+
* @generated SignedSource<<5433b4a2f4a0574591a38017422edac8>>
88
*/
99

1010
/**
@@ -210,6 +210,9 @@ class JReactNativeFeatureFlagsCxxInterop
210210
static bool fixTextClippingAndroid15useBoundsForWidth(
211211
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
212212

213+
static bool fixYogaFlexBasisFitContentInMainAxis(
214+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
215+
213216
static bool fuseboxAssertSingleHostState(
214217
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
215218

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<903b6404deb3339d2cfeced5be354134>>
7+
* @generated SignedSource<<bfb72cee88230c56d2c101be808ef300>>
88
*/
99

1010
/**
@@ -266,6 +266,10 @@ bool ReactNativeFeatureFlags::fixTextClippingAndroid15useBoundsForWidth() {
266266
return getAccessor().fixTextClippingAndroid15useBoundsForWidth();
267267
}
268268

269+
bool ReactNativeFeatureFlags::fixYogaFlexBasisFitContentInMainAxis() {
270+
return getAccessor().fixYogaFlexBasisFitContentInMainAxis();
271+
}
272+
269273
bool ReactNativeFeatureFlags::fuseboxAssertSingleHostState() {
270274
return getAccessor().fuseboxAssertSingleHostState();
271275
}

0 commit comments

Comments
 (0)