From 111a505c5749d7c3db8ab4f8c1453bd6f70e0901 Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Wed, 30 Sep 2026 13:00:57 -0700 Subject: [PATCH 1/2] Clear null length percentages without a warning (#58753) Summary: Treat a null dynamic length-percentage value as the expected property-reset case instead of reporting it as an unsupported type. Preserve the existing null result while avoiding a warning whenever a percentage border radius is cleared. Add focused coverage for point, percentage, negative, opt-in negative, and null parsing behavior. Changelog: [Android][Fixed] - Avoid warning when clearing percentage border radii Differential Revision: D122278946 --- .../react/uimanager/LengthPercentage.kt | 1 + .../react/uimanager/LengthPercentageTest.kt | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LengthPercentageTest.kt diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt index 1da94fa2672e..ed3c787e27ac 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LengthPercentage.kt @@ -51,6 +51,7 @@ public data class LengthPercentage( null } } + ReadableType.Null -> null else -> { FLog.w(ReactConstants.TAG, "Unsupported type for radius property: ${dynamic.type}") null diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LengthPercentageTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LengthPercentageTest.kt new file mode 100644 index 000000000000..ce0df86e46db --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/LengthPercentageTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.uimanager + +import com.facebook.common.logging.FLog +import com.facebook.react.bridge.DynamicFromObject +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test +import org.mockito.Mockito.mockStatic + +class LengthPercentageTest { + + @Test + fun parsesPointAndPercentageValues() { + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject(12.0))) + .isEqualTo(LengthPercentage(12f, LengthPercentageType.POINT)) + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject("25%"))) + .isEqualTo(LengthPercentage(25f, LengthPercentageType.PERCENT)) + } + + @Test + fun rejectsNegativeValuesByDefault() { + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject(-1.0))).isNull() + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject("-1%"))).isNull() + } + + @Test + fun acceptsNegativeValuesWhenAllowed() { + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject(-1.0), allowNegative = true)) + .isEqualTo(LengthPercentage(-1f, LengthPercentageType.POINT)) + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject("-1%"), allowNegative = true)) + .isEqualTo(LengthPercentage(-1f, LengthPercentageType.PERCENT)) + } + + @Test + fun clearsNullWithoutWarning() { + mockStatic(FLog::class.java).use { flog -> + assertThat(LengthPercentage.setFromDynamic(DynamicFromObject(null))).isNull() + flog.verifyNoInteractions() + } + } +} From d0ccc026d4eb54f1232d1313099745ec090cef63 Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Wed, 30 Sep 2026 13:00:57 -0700 Subject: [PATCH 2/2] Restore nested ScrollView manager generation parity Summary: Regenerate `ReactNestedScrollViewManager` from `ReactScrollViewManager` so the checked-in output exactly matches its generator. This incorporates an existing Kotlin formatting delta and refreshes the SignedSource token. Changelog: [Internal] Differential Revision: D122278947 --- .../scroll/ReactNestedScrollViewManager.kt | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt index 50ec11cbe1e1..632c1d5c73f3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollViewManager.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<3b339a7d81f8e32cf6b6ca93ae9a388b>> + * @generated SignedSource<> */ /** @@ -461,15 +461,17 @@ constructor(private val fpsListener: FpsListener? = null) : companion object { const val REACT_CLASS: String = "RCTScrollView" - fun createExportedCustomDirectEventTypeConstants(): Map = mapOf( - getJSEventName(ScrollEventType.SCROLL) to mapOf("registrationName" to "onScroll"), - getJSEventName(ScrollEventType.BEGIN_DRAG) to - mapOf("registrationName" to "onScrollBeginDrag"), - getJSEventName(ScrollEventType.END_DRAG) to mapOf("registrationName" to "onScrollEndDrag"), - getJSEventName(ScrollEventType.MOMENTUM_BEGIN) to - mapOf("registrationName" to "onMomentumScrollBegin"), - getJSEventName(ScrollEventType.MOMENTUM_END) to - mapOf("registrationName" to "onMomentumScrollEnd"), - ) + fun createExportedCustomDirectEventTypeConstants(): Map = + mapOf( + getJSEventName(ScrollEventType.SCROLL) to mapOf("registrationName" to "onScroll"), + getJSEventName(ScrollEventType.BEGIN_DRAG) to + mapOf("registrationName" to "onScrollBeginDrag"), + getJSEventName(ScrollEventType.END_DRAG) to + mapOf("registrationName" to "onScrollEndDrag"), + getJSEventName(ScrollEventType.MOMENTUM_BEGIN) to + mapOf("registrationName" to "onMomentumScrollBegin"), + getJSEventName(ScrollEventType.MOMENTUM_END) to + mapOf("registrationName" to "onMomentumScrollEnd"), + ) } }