diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.kt index 9e8c8bcf8438..d52cca42ff1e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagersPropertyCache.kt @@ -11,6 +11,7 @@ import android.content.Context import android.view.View import com.facebook.common.logging.FLog import com.facebook.react.bridge.ColorPropConverter +import com.facebook.react.bridge.DimensionPropConverter import com.facebook.react.bridge.Dynamic import com.facebook.react.bridge.DynamicFromObject import com.facebook.react.bridge.JSApplicationIllegalArgumentException @@ -18,6 +19,7 @@ import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.annotations.ReactPropGroup +import com.facebook.yoga.YogaValue import java.lang.reflect.Method /** @@ -192,6 +194,15 @@ internal object ViewManagersPropertyCache { } } + private class DimensionPropSetter(prop: ReactProp, setter: Method) : + PropSetter(prop, "mixed", setter) { + + // A DimensionValue arrives from JS as either a number (points) or a string + // (e.g. "100%"), and is nullable, so the conversion is delegated wholesale. + override fun getValueOrDefault(value: Any?, context: Context): Any? = + DimensionPropConverter.getDimension(value) + } + private class BooleanPropSetter( prop: ReactProp, setter: Method, @@ -399,6 +410,7 @@ internal object ViewManagersPropertyCache { } ReadableArray::class.java -> ArrayPropSetter(annotation, method) ReadableMap::class.java -> MapPropSetter(annotation, method) + YogaValue::class.java -> DimensionPropSetter(annotation, method) else -> throw RuntimeException( "Unrecognized type: $propTypeClass for method: ${method.declaringClass.name}#${method.name}", diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.kt index 0813c85acaa6..0860a3133985 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropAnnotationSetterTest.kt @@ -16,6 +16,8 @@ import com.facebook.react.bridge.ReadableMap import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.annotations.ReactPropGroup +import com.facebook.yoga.YogaUnit +import com.facebook.yoga.YogaValue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -41,6 +43,8 @@ class ReactPropAnnotationSetterTest { fun onBoxedIntSetterCalled(value: Int?) + fun onDimensionSetterCalled(value: YogaValue?) + fun onArraySetterCalled(value: ReadableArray?) fun onMapSetterCalled(value: ReadableMap?) @@ -128,6 +132,11 @@ class ReactPropAnnotationSetterTest { viewManagerUpdatesReceiver.onBoxedIntSetterCalled(value) } + @ReactProp(name = "dimensionProp") + fun setDimensionProp(v: View?, value: YogaValue?) { + viewManagerUpdatesReceiver.onDimensionSetterCalled(value) + } + @ReactProp(name = "arrayProp") fun setArrayProp(v: View?, value: ReadableArray?) { viewManagerUpdatesReceiver.onArraySetterCalled(value) @@ -314,6 +323,27 @@ class ReactPropAnnotationSetterTest { Mockito.reset(updatesReceiverMock) } + @Test + fun testDimensionSetter() { + viewManager.updateProperties(targetView, buildStyles("dimensionProp", 10.5)) + Mockito.verify(updatesReceiverMock).onDimensionSetterCalled(YogaValue(10.5f, YogaUnit.POINT)) + Mockito.verifyNoMoreInteractions(updatesReceiverMock) + Mockito.reset(updatesReceiverMock) + viewManager.updateProperties(targetView, buildStyles("dimensionProp", "100%")) + Mockito.verify(updatesReceiverMock).onDimensionSetterCalled(YogaValue(100f, YogaUnit.PERCENT)) + Mockito.verifyNoMoreInteractions(updatesReceiverMock) + Mockito.reset(updatesReceiverMock) + viewManager.updateProperties(targetView, buildStyles("dimensionProp", null)) + Mockito.verify(updatesReceiverMock).onDimensionSetterCalled(null) + Mockito.verifyNoMoreInteractions(updatesReceiverMock) + Mockito.reset(updatesReceiverMock) + } + + @Test(expected = JSApplicationIllegalArgumentException::class) + fun testFailToUpdateDimensionPropWithArray() { + viewManager.updateProperties(targetView, buildStyles("dimensionProp", JavaOnlyArray())) + } + @Test fun testArraySetter() { val array: ReadableArray = JavaOnlyArray()