From 8f5efb73740307dccca49d88551a58f82eb864d3 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Wed, 11 Feb 2026 08:47:51 -0800 Subject: [PATCH] Migrate LayoutShadowNode from Java to Kotlin (#55523) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/55523 Migrate LayoutShadowNode.java to Kotlin as part of the ongoing effort to move React Native Android to 100% Kotlin. LayoutShadowNode is a small deprecated Legacy Architecture class that extends ReactShadowNodeImpl. Updated the ReactNoNewJavaDetector lint allowlist and regenerated ReactAndroid.api. Differential Revision: D92852545 --- .../ReactAndroid/api/ReactAndroid.api | 77 +- .../react/uimanager/LayoutShadowNode.java | 985 ------------------ .../react/uimanager/LayoutShadowNode.kt | 737 +++++++++++++ 3 files changed, 778 insertions(+), 1021 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 80c168cd95d19c..a308eeb4ec9549 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3388,47 +3388,52 @@ public final class com/facebook/react/uimanager/JSTouchDispatcher { } public class com/facebook/react/uimanager/LayoutShadowNode : com/facebook/react/uimanager/ReactShadowNodeImpl { + public static final field Companion Lcom/facebook/react/uimanager/LayoutShadowNode$Companion; + public field collapsable Z public fun ()V - public fun setAlignContent (Ljava/lang/String;)V - public fun setAlignItems (Ljava/lang/String;)V - public fun setAlignSelf (Ljava/lang/String;)V - public fun setAspectRatio (F)V - public fun setBorderWidths (IF)V - public fun setCollapsable (Z)V - public fun setCollapsableChildren (Z)V - public fun setColumnGap (Lcom/facebook/react/bridge/Dynamic;)V - public fun setDisplay (Ljava/lang/String;)V + public final fun setAlignContent (Ljava/lang/String;)V + public final fun setAlignItems (Ljava/lang/String;)V + public final fun setAlignSelf (Ljava/lang/String;)V + public final fun setAspectRatio (F)V + public final fun setBorderWidths (IF)V + public final fun setCollapsable (Z)V + public final fun setCollapsableChildren (Z)V + public final fun setColumnGap (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setDisplay (Ljava/lang/String;)V public fun setFlex (F)V - public fun setFlexBasis (Lcom/facebook/react/bridge/Dynamic;)V - public fun setFlexDirection (Ljava/lang/String;)V + public final fun setFlexBasis (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setFlexDirection (Ljava/lang/String;)V public fun setFlexGrow (F)V public fun setFlexShrink (F)V - public fun setFlexWrap (Ljava/lang/String;)V - public fun setGap (Lcom/facebook/react/bridge/Dynamic;)V - public fun setHeight (Lcom/facebook/react/bridge/Dynamic;)V - public fun setInset (Lcom/facebook/react/bridge/Dynamic;)V - public fun setInsetBlock (ILcom/facebook/react/bridge/Dynamic;)V - public fun setInsetInline (ILcom/facebook/react/bridge/Dynamic;)V - public fun setJustifyContent (Ljava/lang/String;)V - public fun setMarginBlock (ILcom/facebook/react/bridge/Dynamic;)V - public fun setMarginInline (ILcom/facebook/react/bridge/Dynamic;)V - public fun setMargins (ILcom/facebook/react/bridge/Dynamic;)V - public fun setMaxHeight (Lcom/facebook/react/bridge/Dynamic;)V - public fun setMaxWidth (Lcom/facebook/react/bridge/Dynamic;)V - public fun setMinHeight (Lcom/facebook/react/bridge/Dynamic;)V - public fun setMinWidth (Lcom/facebook/react/bridge/Dynamic;)V - public fun setOverflow (Ljava/lang/String;)V - public fun setPaddingBlock (ILcom/facebook/react/bridge/Dynamic;)V - public fun setPaddingInline (ILcom/facebook/react/bridge/Dynamic;)V - public fun setPaddings (ILcom/facebook/react/bridge/Dynamic;)V - public fun setPosition (Ljava/lang/String;)V - public fun setPositionValues (ILcom/facebook/react/bridge/Dynamic;)V - public fun setRowGap (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setFlexWrap (Ljava/lang/String;)V + public final fun setGap (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setHeight (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setInset (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setInsetBlock (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setInsetInline (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setJustifyContent (Ljava/lang/String;)V + public final fun setMarginBlock (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setMarginInline (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setMargins (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setMaxHeight (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setMaxWidth (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setMinHeight (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setMinWidth (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setOverflow (Ljava/lang/String;)V + public final fun setPaddingBlock (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setPaddingInline (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setPaddings (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setPosition (Ljava/lang/String;)V + public final fun setPositionValues (ILcom/facebook/react/bridge/Dynamic;)V + public final fun setRowGap (Lcom/facebook/react/bridge/Dynamic;)V public fun setShouldNotifyOnLayout (Z)V - public fun setShouldNotifyPointerEnter (Z)V - public fun setShouldNotifyPointerLeave (Z)V - public fun setShouldNotifyPointerMove (Z)V - public fun setWidth (Lcom/facebook/react/bridge/Dynamic;)V + public final fun setShouldNotifyPointerEnter (Z)V + public final fun setShouldNotifyPointerLeave (Z)V + public final fun setShouldNotifyPointerMove (Z)V + public final fun setWidth (Lcom/facebook/react/bridge/Dynamic;)V +} + +public final class com/facebook/react/uimanager/LayoutShadowNode$Companion { } public final class com/facebook/react/uimanager/LengthPercentage { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java deleted file mode 100644 index 757727322c0629..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ /dev/null @@ -1,985 +0,0 @@ -/* - * 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 androidx.annotation.Nullable; -import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.Dynamic; -import com.facebook.react.bridge.ReadableType; -import com.facebook.react.common.ReactConstants; -import com.facebook.react.common.annotations.internal.LegacyArchitecture; -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel; -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger; -import com.facebook.react.modules.i18nmanager.I18nUtil; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.annotations.ReactPropGroup; -import com.facebook.yoga.YogaAlign; -import com.facebook.yoga.YogaConstants; -import com.facebook.yoga.YogaDisplay; -import com.facebook.yoga.YogaFlexDirection; -import com.facebook.yoga.YogaJustify; -import com.facebook.yoga.YogaOverflow; -import com.facebook.yoga.YogaPositionType; -import com.facebook.yoga.YogaUnit; -import com.facebook.yoga.YogaWrap; - -/** - * Supply setters for base view layout properties such as width, height, flex properties, borders, - * etc. - * - *

Checking for isVirtual everywhere is a hack to get around the fact that some virtual nodes - * still have layout properties set on them in JS: for example, a component that returns a - * may or may not be embedded in a parent text. There are better solutions that should probably be - * explored, namely using the VirtualText class in JS and setting the correct set of validAttributes - */ -@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR) -@Deprecated( - since = "This class is part of Legacy Architecture and will be removed in a future release") -public class LayoutShadowNode extends ReactShadowNodeImpl { - static { - LegacyArchitectureLogger.assertLegacyArchitecture( - "LayoutShadowNode", LegacyArchitectureLogLevel.ERROR); - } - - /** A Mutable version of com.facebook.yoga.YogaValue */ - private static class MutableYogaValue { - float value; - YogaUnit unit; - - private MutableYogaValue() {} - - private MutableYogaValue(MutableYogaValue mutableYogaValue) { - value = mutableYogaValue.value; - unit = mutableYogaValue.unit; - } - - void setFromDynamic(Dynamic dynamic) { - if (dynamic.isNull()) { - unit = YogaUnit.UNDEFINED; - value = YogaConstants.UNDEFINED; - } else if (dynamic.getType() == ReadableType.String) { - final String s = dynamic.asString(); - if (s.equals("auto")) { - unit = YogaUnit.AUTO; - value = YogaConstants.UNDEFINED; - } else if (s.endsWith("%")) { - unit = YogaUnit.PERCENT; - value = Float.parseFloat(s.substring(0, s.length() - 1)); - } else { - FLog.w(ReactConstants.TAG, "Unknown value: " + s); - unit = YogaUnit.UNDEFINED; - value = YogaConstants.UNDEFINED; - } - } else if (dynamic.getType() == ReadableType.Number) { - unit = YogaUnit.POINT; - value = PixelUtil.toPixelFromDIP(dynamic.asDouble()); - } else { - unit = YogaUnit.UNDEFINED; - value = YogaConstants.UNDEFINED; - } - } - } - - private final MutableYogaValue mTempYogaValue; - - public LayoutShadowNode() { - mTempYogaValue = new MutableYogaValue(); - } - - @ReactProp(name = ViewProps.WIDTH) - public void setWidth(Dynamic width) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(width); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleWidth(mTempYogaValue.value); - break; - case AUTO: - setStyleWidthAuto(); - break; - case PERCENT: - setStyleWidthPercent(mTempYogaValue.value); - break; - } - - width.recycle(); - } - - @ReactProp(name = ViewProps.MIN_WIDTH) - public void setMinWidth(Dynamic minWidth) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(minWidth); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleMinWidth(mTempYogaValue.value); - break; - case PERCENT: - setStyleMinWidthPercent(mTempYogaValue.value); - break; - } - - minWidth.recycle(); - } - - boolean mCollapsable; - - @ReactProp(name = "collapsableChildren") - public void setCollapsableChildren(boolean collapsableChildren) { - // Do Nothing: Align with static ViewConfigs - - } - - @ReactProp(name = "collapsable") - public void setCollapsable(boolean collapsable) { - mCollapsable = collapsable; - } - - @ReactProp(name = ViewProps.MAX_WIDTH) - public void setMaxWidth(Dynamic maxWidth) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(maxWidth); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleMaxWidth(mTempYogaValue.value); - break; - case PERCENT: - setStyleMaxWidthPercent(mTempYogaValue.value); - break; - } - - maxWidth.recycle(); - } - - @ReactProp(name = ViewProps.HEIGHT) - public void setHeight(Dynamic height) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(height); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleHeight(mTempYogaValue.value); - break; - case AUTO: - setStyleHeightAuto(); - break; - case PERCENT: - setStyleHeightPercent(mTempYogaValue.value); - break; - } - - height.recycle(); - } - - @ReactProp(name = ViewProps.MIN_HEIGHT) - public void setMinHeight(Dynamic minHeight) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(minHeight); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleMinHeight(mTempYogaValue.value); - break; - case PERCENT: - setStyleMinHeightPercent(mTempYogaValue.value); - break; - } - - minHeight.recycle(); - } - - @ReactProp(name = ViewProps.MAX_HEIGHT) - public void setMaxHeight(Dynamic maxHeight) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(maxHeight); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setStyleMaxHeight(mTempYogaValue.value); - break; - case PERCENT: - setStyleMaxHeightPercent(mTempYogaValue.value); - break; - } - - maxHeight.recycle(); - } - - @ReactProp(name = ViewProps.FLEX, defaultFloat = 0f) - public void setFlex(float flex) { - if (isVirtual()) { - return; - } - super.setFlex(flex); - } - - @ReactProp(name = ViewProps.FLEX_GROW, defaultFloat = 0f) - public void setFlexGrow(float flexGrow) { - if (isVirtual()) { - return; - } - super.setFlexGrow(flexGrow); - } - - @ReactProp(name = ViewProps.ROW_GAP) - public void setRowGap(Dynamic rowGap) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(rowGap); - switch (mTempYogaValue.unit) { - case AUTO: - case POINT: - case UNDEFINED: - setRowGap(mTempYogaValue.value); - break; - case PERCENT: - setRowGapPercent(mTempYogaValue.value); - break; - } - - rowGap.recycle(); - } - - @ReactProp(name = ViewProps.COLUMN_GAP) - public void setColumnGap(Dynamic columnGap) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(columnGap); - switch (mTempYogaValue.unit) { - case AUTO: - case POINT: - case UNDEFINED: - setColumnGap(mTempYogaValue.value); - break; - case PERCENT: - setColumnGapPercent(mTempYogaValue.value); - break; - } - - columnGap.recycle(); - } - - @ReactProp(name = ViewProps.GAP) - public void setGap(Dynamic gap) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(gap); - switch (mTempYogaValue.unit) { - case AUTO: - case POINT: - case UNDEFINED: - setGap(mTempYogaValue.value); - break; - case PERCENT: - setGapPercent(mTempYogaValue.value); - break; - } - - gap.recycle(); - } - - @ReactProp(name = ViewProps.FLEX_SHRINK, defaultFloat = 0f) - public void setFlexShrink(float flexShrink) { - if (isVirtual()) { - return; - } - super.setFlexShrink(flexShrink); - } - - @ReactProp(name = ViewProps.FLEX_BASIS) - public void setFlexBasis(Dynamic flexBasis) { - if (isVirtual()) { - return; - } - - mTempYogaValue.setFromDynamic(flexBasis); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setFlexBasis(mTempYogaValue.value); - break; - case AUTO: - setFlexBasisAuto(); - break; - case PERCENT: - setFlexBasisPercent(mTempYogaValue.value); - break; - } - - flexBasis.recycle(); - } - - @ReactProp(name = ViewProps.ASPECT_RATIO, defaultFloat = Float.NaN) - public void setAspectRatio(float aspectRatio) { - setStyleAspectRatio(aspectRatio); - } - - @ReactProp(name = ViewProps.FLEX_DIRECTION) - public void setFlexDirection(@Nullable String flexDirection) { - if (isVirtual()) { - return; - } - - if (flexDirection == null) { - setFlexDirection(YogaFlexDirection.COLUMN); - return; - } - - switch (flexDirection) { - case "column": - { - setFlexDirection(YogaFlexDirection.COLUMN); - break; - } - case "column-reverse": - { - setFlexDirection(YogaFlexDirection.COLUMN_REVERSE); - break; - } - case "row": - { - setFlexDirection(YogaFlexDirection.ROW); - break; - } - case "row-reverse": - { - setFlexDirection(YogaFlexDirection.ROW_REVERSE); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for flexDirection: " + flexDirection); - setFlexDirection(YogaFlexDirection.COLUMN); - break; - } - } - } - - @ReactProp(name = ViewProps.FLEX_WRAP) - public void setFlexWrap(@Nullable String flexWrap) { - if (isVirtual()) { - return; - } - - if (flexWrap == null) { - setFlexWrap(YogaWrap.NO_WRAP); - return; - } - - switch (flexWrap) { - case "nowrap": - { - setFlexWrap(YogaWrap.NO_WRAP); - break; - } - case "wrap": - { - setFlexWrap(YogaWrap.WRAP); - break; - } - case "wrap-reverse": - { - setFlexWrap(YogaWrap.WRAP_REVERSE); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for flexWrap: " + flexWrap); - setFlexWrap(YogaWrap.NO_WRAP); - break; - } - } - } - - @ReactProp(name = ViewProps.ALIGN_SELF) - public void setAlignSelf(@Nullable String alignSelf) { - if (isVirtual()) { - return; - } - - if (alignSelf == null) { - setAlignSelf(YogaAlign.AUTO); - return; - } - - switch (alignSelf) { - case "auto": - { - setAlignSelf(YogaAlign.AUTO); - return; - } - case "flex-start": - { - setAlignSelf(YogaAlign.FLEX_START); - return; - } - case "center": - { - setAlignSelf(YogaAlign.CENTER); - return; - } - case "flex-end": - { - setAlignSelf(YogaAlign.FLEX_END); - return; - } - case "stretch": - { - setAlignSelf(YogaAlign.STRETCH); - return; - } - case "baseline": - { - setAlignSelf(YogaAlign.BASELINE); - return; - } - case "space-between": - { - setAlignSelf(YogaAlign.SPACE_BETWEEN); - return; - } - case "space-around": - { - setAlignSelf(YogaAlign.SPACE_AROUND); - return; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for alignSelf: " + alignSelf); - setAlignSelf(YogaAlign.AUTO); - return; - } - } - } - - @ReactProp(name = ViewProps.ALIGN_ITEMS) - public void setAlignItems(@Nullable String alignItems) { - if (isVirtual()) { - return; - } - - if (alignItems == null) { - setAlignItems(YogaAlign.STRETCH); - return; - } - - switch (alignItems) { - case "auto": - { - setAlignItems(YogaAlign.AUTO); - return; - } - case "flex-start": - { - setAlignItems(YogaAlign.FLEX_START); - return; - } - case "center": - { - setAlignItems(YogaAlign.CENTER); - return; - } - case "flex-end": - { - setAlignItems(YogaAlign.FLEX_END); - return; - } - case "stretch": - { - setAlignItems(YogaAlign.STRETCH); - return; - } - case "baseline": - { - setAlignItems(YogaAlign.BASELINE); - return; - } - case "space-between": - { - setAlignItems(YogaAlign.SPACE_BETWEEN); - return; - } - case "space-around": - { - setAlignItems(YogaAlign.SPACE_AROUND); - return; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for alignItems: " + alignItems); - setAlignItems(YogaAlign.STRETCH); - return; - } - } - } - - @ReactProp(name = ViewProps.ALIGN_CONTENT) - public void setAlignContent(@Nullable String alignContent) { - if (isVirtual()) { - return; - } - - if (alignContent == null) { - setAlignContent(YogaAlign.FLEX_START); - return; - } - - switch (alignContent) { - case "auto": - { - setAlignContent(YogaAlign.AUTO); - return; - } - case "flex-start": - { - setAlignContent(YogaAlign.FLEX_START); - return; - } - case "center": - { - setAlignContent(YogaAlign.CENTER); - return; - } - case "flex-end": - { - setAlignContent(YogaAlign.FLEX_END); - return; - } - case "stretch": - { - setAlignContent(YogaAlign.STRETCH); - return; - } - case "baseline": - { - setAlignContent(YogaAlign.BASELINE); - return; - } - case "space-between": - { - setAlignContent(YogaAlign.SPACE_BETWEEN); - return; - } - case "space-around": - { - setAlignContent(YogaAlign.SPACE_AROUND); - return; - } - case "space-evenly": - { - setAlignContent(YogaAlign.SPACE_EVENLY); - return; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for alignContent: " + alignContent); - setAlignContent(YogaAlign.FLEX_START); - return; - } - } - } - - @ReactProp(name = ViewProps.JUSTIFY_CONTENT) - public void setJustifyContent(@Nullable String justifyContent) { - if (isVirtual()) { - return; - } - - if (justifyContent == null) { - setJustifyContent(YogaJustify.FLEX_START); - return; - } - - switch (justifyContent) { - case "flex-start": - { - setJustifyContent(YogaJustify.FLEX_START); - break; - } - case "center": - { - setJustifyContent(YogaJustify.CENTER); - break; - } - case "flex-end": - { - setJustifyContent(YogaJustify.FLEX_END); - break; - } - case "space-between": - { - setJustifyContent(YogaJustify.SPACE_BETWEEN); - break; - } - case "space-around": - { - setJustifyContent(YogaJustify.SPACE_AROUND); - break; - } - case "space-evenly": - { - setJustifyContent(YogaJustify.SPACE_EVENLY); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for justifyContent: " + justifyContent); - setJustifyContent(YogaJustify.FLEX_START); - break; - } - } - } - - @ReactProp(name = ViewProps.OVERFLOW) - public void setOverflow(@Nullable String overflow) { - if (isVirtual()) { - return; - } - if (overflow == null) { - setOverflow(YogaOverflow.VISIBLE); - return; - } - - switch (overflow) { - case "visible": - { - setOverflow(YogaOverflow.VISIBLE); - break; - } - case "hidden": - { - setOverflow(YogaOverflow.HIDDEN); - break; - } - case "scroll": - { - setOverflow(YogaOverflow.SCROLL); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for overflow: " + overflow); - setOverflow(YogaOverflow.VISIBLE); - break; - } - } - } - - @ReactProp(name = ViewProps.DISPLAY) - public void setDisplay(@Nullable String display) { - if (isVirtual()) { - return; - } - - if (display == null) { - setDisplay(YogaDisplay.FLEX); - return; - } - - switch (display) { - case "flex": - { - setDisplay(YogaDisplay.FLEX); - break; - } - case "none": - { - setDisplay(YogaDisplay.NONE); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for display: " + display); - setDisplay(YogaDisplay.FLEX); - break; - } - } - } - - @ReactPropGroup( - names = { - "marginBlock", - "marginBlockEnd", - "marginBlockStart", - }) - public void setMarginBlock(int index, Dynamic margin) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - "marginInline", - "marginInlineEnd", - "marginInlineStart", - }) - public void setMarginInline(int index, Dynamic margin) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - "paddingBlock", - "paddingBlockEnd", - "paddingBlockStart", - }) - public void setPaddingBlock(int index, Dynamic padding) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - "paddingInline", - "paddingInlineEnd", - "paddingInlineStart", - }) - public void setPaddingInline(int index, Dynamic padding) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - "insetBlock", - "insetBlockEnd", - "insetBlockStart", - }) - public void setInsetBlock(int index, Dynamic inset) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - "insetInline", - "insetInlineEnd", - "insetInlineStart", - }) - public void setInsetInline(int index, Dynamic inset) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactProp(name = "inset") - public void setInset(Dynamic inset) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactPropGroup( - names = { - ViewProps.MARGIN, - ViewProps.MARGIN_VERTICAL, - ViewProps.MARGIN_HORIZONTAL, - ViewProps.MARGIN_START, - ViewProps.MARGIN_END, - ViewProps.MARGIN_TOP, - ViewProps.MARGIN_BOTTOM, - ViewProps.MARGIN_LEFT, - ViewProps.MARGIN_RIGHT, - }) - public void setMargins(int index, Dynamic margin) { - if (isVirtual()) { - return; - } - - int spacingType = - maybeTransformLeftRightToStartEnd(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]); - - mTempYogaValue.setFromDynamic(margin); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setMargin(spacingType, mTempYogaValue.value); - break; - case AUTO: - setMarginAuto(spacingType); - break; - case PERCENT: - setMarginPercent(spacingType, mTempYogaValue.value); - break; - } - - margin.recycle(); - } - - @ReactPropGroup( - names = { - ViewProps.PADDING, - ViewProps.PADDING_VERTICAL, - ViewProps.PADDING_HORIZONTAL, - ViewProps.PADDING_START, - ViewProps.PADDING_END, - ViewProps.PADDING_TOP, - ViewProps.PADDING_BOTTOM, - ViewProps.PADDING_LEFT, - ViewProps.PADDING_RIGHT, - }) - public void setPaddings(int index, Dynamic padding) { - if (isVirtual()) { - return; - } - - int spacingType = - maybeTransformLeftRightToStartEnd(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]); - - mTempYogaValue.setFromDynamic(padding); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setPadding(spacingType, mTempYogaValue.value); - break; - case PERCENT: - setPaddingPercent(spacingType, mTempYogaValue.value); - break; - } - - padding.recycle(); - } - - @ReactPropGroup( - names = { - ViewProps.BORDER_WIDTH, - ViewProps.BORDER_START_WIDTH, - ViewProps.BORDER_END_WIDTH, - ViewProps.BORDER_TOP_WIDTH, - ViewProps.BORDER_BOTTOM_WIDTH, - ViewProps.BORDER_LEFT_WIDTH, - ViewProps.BORDER_RIGHT_WIDTH, - }, - defaultFloat = Float.NaN) - public void setBorderWidths(int index, float borderWidth) { - if (isVirtual()) { - return; - } - int spacingType = maybeTransformLeftRightToStartEnd(ViewProps.BORDER_SPACING_TYPES[index]); - setBorder(spacingType, PixelUtil.toPixelFromDIP(borderWidth)); - } - - @ReactPropGroup( - names = { - ViewProps.START, - ViewProps.END, - ViewProps.LEFT, - ViewProps.RIGHT, - ViewProps.TOP, - ViewProps.BOTTOM, - }) - public void setPositionValues(int index, Dynamic position) { - if (isVirtual()) { - return; - } - - final int[] POSITION_SPACING_TYPES = { - Spacing.START, Spacing.END, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM - }; - - int spacingType = maybeTransformLeftRightToStartEnd(POSITION_SPACING_TYPES[index]); - - mTempYogaValue.setFromDynamic(position); - switch (mTempYogaValue.unit) { - case POINT: - case UNDEFINED: - setPosition(spacingType, mTempYogaValue.value); - break; - case PERCENT: - setPositionPercent(spacingType, mTempYogaValue.value); - break; - } - - position.recycle(); - } - - private int maybeTransformLeftRightToStartEnd(int spacingType) { - if (!I18nUtil.getInstance().doLeftAndRightSwapInRTL(getThemedContext())) { - return spacingType; - } - - switch (spacingType) { - case Spacing.LEFT: - return Spacing.START; - case Spacing.RIGHT: - return Spacing.END; - default: - return spacingType; - } - } - - @ReactProp(name = ViewProps.POSITION) - public void setPosition(@Nullable String position) { - if (isVirtual()) { - return; - } - - if (position == null) { - setPositionType(YogaPositionType.RELATIVE); - return; - } - - switch (position) { - case "relative": - { - setPositionType(YogaPositionType.RELATIVE); - break; - } - case "absolute": - { - setPositionType(YogaPositionType.ABSOLUTE); - break; - } - default: - { - FLog.w(ReactConstants.TAG, "invalid value for position: " + position); - setPositionType(YogaPositionType.RELATIVE); - break; - } - } - } - - @Override - @ReactProp(name = "onLayout") - public void setShouldNotifyOnLayout(boolean shouldNotifyOnLayout) { - super.setShouldNotifyOnLayout(shouldNotifyOnLayout); - } - - @ReactProp(name = "onPointerEnter") - public void setShouldNotifyPointerEnter(boolean value) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactProp(name = "onPointerLeave") - public void setShouldNotifyPointerLeave(boolean value) { - // Do Nothing: Align with static ViewConfigs - } - - @ReactProp(name = "onPointerMove") - public void setShouldNotifyPointerMove(boolean value) { - // Do Nothing: Align with static ViewConfigs - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.kt new file mode 100644 index 00000000000000..5fab1b88366036 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.kt @@ -0,0 +1,737 @@ +/* + * 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.Dynamic +import com.facebook.react.bridge.ReadableType +import com.facebook.react.common.ReactConstants +import com.facebook.react.common.annotations.internal.LegacyArchitecture +import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel +import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger +import com.facebook.react.modules.i18nmanager.I18nUtil +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.uimanager.annotations.ReactPropGroup +import com.facebook.yoga.YogaAlign +import com.facebook.yoga.YogaConstants +import com.facebook.yoga.YogaDisplay +import com.facebook.yoga.YogaFlexDirection +import com.facebook.yoga.YogaJustify +import com.facebook.yoga.YogaOverflow +import com.facebook.yoga.YogaPositionType +import com.facebook.yoga.YogaUnit +import com.facebook.yoga.YogaWrap + +/** + * Supply setters for base view layout properties such as width, height, flex properties, borders, + * etc. + * + * Checking for isVirtual everywhere is a hack to get around the fact that some virtual nodes still + * have layout properties set on them in JS: for example, a component that returns a may or + * may not be embedded in a parent text. There are better solutions that should probably be + * explored, namely using the VirtualText class in JS and setting the correct set of validAttributes + */ +@Suppress("DEPRECATION") +@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR) +@Deprecated("This class is part of Legacy Architecture and will be removed in a future release") +public open class LayoutShadowNode : ReactShadowNodeImpl() { + + /** A Mutable version of com.facebook.yoga.YogaValue */ + private class MutableYogaValue { + var value: Float = 0f + var unit: YogaUnit = YogaUnit.UNDEFINED + + constructor() + + constructor(other: MutableYogaValue) { + value = other.value + unit = other.unit + } + + fun setFromDynamic(dynamic: Dynamic) { + if (dynamic.isNull) { + unit = YogaUnit.UNDEFINED + value = YogaConstants.UNDEFINED + } else if (dynamic.type == ReadableType.String) { + val s = dynamic.asString() + if (s == "auto") { + unit = YogaUnit.AUTO + value = YogaConstants.UNDEFINED + } else if (s != null && s.endsWith("%")) { + unit = YogaUnit.PERCENT + value = s.substring(0, s.length - 1).toFloat() + } else { + FLog.w(ReactConstants.TAG, "Unknown value: $s") + unit = YogaUnit.UNDEFINED + value = YogaConstants.UNDEFINED + } + } else if (dynamic.type == ReadableType.Number) { + unit = YogaUnit.POINT + value = PixelUtil.toPixelFromDIP(dynamic.asDouble()) + } else { + unit = YogaUnit.UNDEFINED + value = YogaConstants.UNDEFINED + } + } + } + + private val tempYogaValue: MutableYogaValue = MutableYogaValue() + + @JvmField public var collapsable: Boolean = false + + @ReactProp(name = ViewProps.WIDTH) + public fun setWidth(width: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(width) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleWidth(tempYogaValue.value) + YogaUnit.AUTO -> setStyleWidthAuto() + YogaUnit.PERCENT -> setStyleWidthPercent(tempYogaValue.value) + else -> {} + } + + width.recycle() + } + + @ReactProp(name = ViewProps.MIN_WIDTH) + public fun setMinWidth(minWidth: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(minWidth) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleMinWidth(tempYogaValue.value) + YogaUnit.PERCENT -> setStyleMinWidthPercent(tempYogaValue.value) + else -> {} + } + + minWidth.recycle() + } + + @ReactProp(name = "collapsableChildren") + public fun setCollapsableChildren(@Suppress("UNUSED_PARAMETER") collapsableChildren: Boolean) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactProp(name = "collapsable") + public fun setCollapsable(collapsable: Boolean) { + this.collapsable = collapsable + } + + @ReactProp(name = ViewProps.MAX_WIDTH) + public fun setMaxWidth(maxWidth: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(maxWidth) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleMaxWidth(tempYogaValue.value) + YogaUnit.PERCENT -> setStyleMaxWidthPercent(tempYogaValue.value) + else -> {} + } + + maxWidth.recycle() + } + + @ReactProp(name = ViewProps.HEIGHT) + public fun setHeight(height: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(height) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleHeight(tempYogaValue.value) + YogaUnit.AUTO -> setStyleHeightAuto() + YogaUnit.PERCENT -> setStyleHeightPercent(tempYogaValue.value) + else -> {} + } + + height.recycle() + } + + @ReactProp(name = ViewProps.MIN_HEIGHT) + public fun setMinHeight(minHeight: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(minHeight) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleMinHeight(tempYogaValue.value) + YogaUnit.PERCENT -> setStyleMinHeightPercent(tempYogaValue.value) + else -> {} + } + + minHeight.recycle() + } + + @ReactProp(name = ViewProps.MAX_HEIGHT) + public fun setMaxHeight(maxHeight: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(maxHeight) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setStyleMaxHeight(tempYogaValue.value) + YogaUnit.PERCENT -> setStyleMaxHeightPercent(tempYogaValue.value) + else -> {} + } + + maxHeight.recycle() + } + + @ReactProp(name = ViewProps.FLEX, defaultFloat = 0f) + public override fun setFlex(flex: Float) { + if (isVirtual) { + return + } + super.setFlex(flex) + } + + @ReactProp(name = ViewProps.FLEX_GROW, defaultFloat = 0f) + public override fun setFlexGrow(flexGrow: Float) { + if (isVirtual) { + return + } + super.setFlexGrow(flexGrow) + } + + @ReactProp(name = ViewProps.ROW_GAP) + public fun setRowGap(rowGap: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(rowGap) + when (tempYogaValue.unit) { + YogaUnit.AUTO, + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setRowGap(tempYogaValue.value) + YogaUnit.PERCENT -> setRowGapPercent(tempYogaValue.value) + else -> {} + } + + rowGap.recycle() + } + + @ReactProp(name = ViewProps.COLUMN_GAP) + public fun setColumnGap(columnGap: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(columnGap) + when (tempYogaValue.unit) { + YogaUnit.AUTO, + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setColumnGap(tempYogaValue.value) + YogaUnit.PERCENT -> setColumnGapPercent(tempYogaValue.value) + else -> {} + } + + columnGap.recycle() + } + + @ReactProp(name = ViewProps.GAP) + public fun setGap(gap: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(gap) + when (tempYogaValue.unit) { + YogaUnit.AUTO, + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setGap(tempYogaValue.value) + YogaUnit.PERCENT -> setGapPercent(tempYogaValue.value) + else -> {} + } + + gap.recycle() + } + + @ReactProp(name = ViewProps.FLEX_SHRINK, defaultFloat = 0f) + public override fun setFlexShrink(flexShrink: Float) { + if (isVirtual) { + return + } + super.setFlexShrink(flexShrink) + } + + @ReactProp(name = ViewProps.FLEX_BASIS) + public fun setFlexBasis(flexBasis: Dynamic) { + if (isVirtual) { + return + } + + tempYogaValue.setFromDynamic(flexBasis) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setFlexBasis(tempYogaValue.value) + YogaUnit.AUTO -> setFlexBasisAuto() + YogaUnit.PERCENT -> setFlexBasisPercent(tempYogaValue.value) + else -> {} + } + + flexBasis.recycle() + } + + @ReactProp(name = ViewProps.ASPECT_RATIO, defaultFloat = Float.NaN) + public fun setAspectRatio(aspectRatio: Float) { + setStyleAspectRatio(aspectRatio) + } + + @ReactProp(name = ViewProps.FLEX_DIRECTION) + public fun setFlexDirection(flexDirection: String?) { + if (isVirtual) { + return + } + + if (flexDirection == null) { + setFlexDirection(YogaFlexDirection.COLUMN) + return + } + + when (flexDirection) { + "column" -> setFlexDirection(YogaFlexDirection.COLUMN) + "column-reverse" -> setFlexDirection(YogaFlexDirection.COLUMN_REVERSE) + "row" -> setFlexDirection(YogaFlexDirection.ROW) + "row-reverse" -> setFlexDirection(YogaFlexDirection.ROW_REVERSE) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for flexDirection: $flexDirection") + setFlexDirection(YogaFlexDirection.COLUMN) + } + } + } + + @ReactProp(name = ViewProps.FLEX_WRAP) + public fun setFlexWrap(flexWrap: String?) { + if (isVirtual) { + return + } + + if (flexWrap == null) { + setFlexWrap(YogaWrap.NO_WRAP) + return + } + + when (flexWrap) { + "nowrap" -> setFlexWrap(YogaWrap.NO_WRAP) + "wrap" -> setFlexWrap(YogaWrap.WRAP) + "wrap-reverse" -> setFlexWrap(YogaWrap.WRAP_REVERSE) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for flexWrap: $flexWrap") + setFlexWrap(YogaWrap.NO_WRAP) + } + } + } + + @ReactProp(name = ViewProps.ALIGN_SELF) + public fun setAlignSelf(alignSelf: String?) { + if (isVirtual) { + return + } + + if (alignSelf == null) { + setAlignSelf(YogaAlign.AUTO) + return + } + + when (alignSelf) { + "auto" -> setAlignSelf(YogaAlign.AUTO) + "flex-start" -> setAlignSelf(YogaAlign.FLEX_START) + "center" -> setAlignSelf(YogaAlign.CENTER) + "flex-end" -> setAlignSelf(YogaAlign.FLEX_END) + "stretch" -> setAlignSelf(YogaAlign.STRETCH) + "baseline" -> setAlignSelf(YogaAlign.BASELINE) + "space-between" -> setAlignSelf(YogaAlign.SPACE_BETWEEN) + "space-around" -> setAlignSelf(YogaAlign.SPACE_AROUND) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for alignSelf: $alignSelf") + setAlignSelf(YogaAlign.AUTO) + } + } + } + + @ReactProp(name = ViewProps.ALIGN_ITEMS) + public fun setAlignItems(alignItems: String?) { + if (isVirtual) { + return + } + + if (alignItems == null) { + setAlignItems(YogaAlign.STRETCH) + return + } + + when (alignItems) { + "auto" -> setAlignItems(YogaAlign.AUTO) + "flex-start" -> setAlignItems(YogaAlign.FLEX_START) + "center" -> setAlignItems(YogaAlign.CENTER) + "flex-end" -> setAlignItems(YogaAlign.FLEX_END) + "stretch" -> setAlignItems(YogaAlign.STRETCH) + "baseline" -> setAlignItems(YogaAlign.BASELINE) + "space-between" -> setAlignItems(YogaAlign.SPACE_BETWEEN) + "space-around" -> setAlignItems(YogaAlign.SPACE_AROUND) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for alignItems: $alignItems") + setAlignItems(YogaAlign.STRETCH) + } + } + } + + @ReactProp(name = ViewProps.ALIGN_CONTENT) + public fun setAlignContent(alignContent: String?) { + if (isVirtual) { + return + } + + if (alignContent == null) { + setAlignContent(YogaAlign.FLEX_START) + return + } + + when (alignContent) { + "auto" -> setAlignContent(YogaAlign.AUTO) + "flex-start" -> setAlignContent(YogaAlign.FLEX_START) + "center" -> setAlignContent(YogaAlign.CENTER) + "flex-end" -> setAlignContent(YogaAlign.FLEX_END) + "stretch" -> setAlignContent(YogaAlign.STRETCH) + "baseline" -> setAlignContent(YogaAlign.BASELINE) + "space-between" -> setAlignContent(YogaAlign.SPACE_BETWEEN) + "space-around" -> setAlignContent(YogaAlign.SPACE_AROUND) + "space-evenly" -> setAlignContent(YogaAlign.SPACE_EVENLY) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for alignContent: $alignContent") + setAlignContent(YogaAlign.FLEX_START) + } + } + } + + @ReactProp(name = ViewProps.JUSTIFY_CONTENT) + public fun setJustifyContent(justifyContent: String?) { + if (isVirtual) { + return + } + + if (justifyContent == null) { + setJustifyContent(YogaJustify.FLEX_START) + return + } + + when (justifyContent) { + "flex-start" -> setJustifyContent(YogaJustify.FLEX_START) + "center" -> setJustifyContent(YogaJustify.CENTER) + "flex-end" -> setJustifyContent(YogaJustify.FLEX_END) + "space-between" -> setJustifyContent(YogaJustify.SPACE_BETWEEN) + "space-around" -> setJustifyContent(YogaJustify.SPACE_AROUND) + "space-evenly" -> setJustifyContent(YogaJustify.SPACE_EVENLY) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for justifyContent: $justifyContent") + setJustifyContent(YogaJustify.FLEX_START) + } + } + } + + @ReactProp(name = ViewProps.OVERFLOW) + public fun setOverflow(overflow: String?) { + if (isVirtual) { + return + } + if (overflow == null) { + setOverflow(YogaOverflow.VISIBLE) + return + } + + when (overflow) { + "visible" -> setOverflow(YogaOverflow.VISIBLE) + "hidden" -> setOverflow(YogaOverflow.HIDDEN) + "scroll" -> setOverflow(YogaOverflow.SCROLL) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for overflow: $overflow") + setOverflow(YogaOverflow.VISIBLE) + } + } + } + + @ReactProp(name = ViewProps.DISPLAY) + public fun setDisplay(display: String?) { + if (isVirtual) { + return + } + + if (display == null) { + setDisplay(YogaDisplay.FLEX) + return + } + + when (display) { + "flex" -> setDisplay(YogaDisplay.FLEX) + "none" -> setDisplay(YogaDisplay.NONE) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for display: $display") + setDisplay(YogaDisplay.FLEX) + } + } + } + + @ReactPropGroup(names = ["marginBlock", "marginBlockEnd", "marginBlockStart"]) + public fun setMarginBlock( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") margin: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup(names = ["marginInline", "marginInlineEnd", "marginInlineStart"]) + public fun setMarginInline( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") margin: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup(names = ["paddingBlock", "paddingBlockEnd", "paddingBlockStart"]) + public fun setPaddingBlock( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") padding: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup(names = ["paddingInline", "paddingInlineEnd", "paddingInlineStart"]) + public fun setPaddingInline( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") padding: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup(names = ["insetBlock", "insetBlockEnd", "insetBlockStart"]) + public fun setInsetBlock( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") inset: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup(names = ["insetInline", "insetInlineEnd", "insetInlineStart"]) + public fun setInsetInline( + @Suppress("UNUSED_PARAMETER") index: Int, + @Suppress("UNUSED_PARAMETER") inset: Dynamic, + ) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactProp(name = "inset") + public fun setInset(@Suppress("UNUSED_PARAMETER") inset: Dynamic) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactPropGroup( + names = + [ + ViewProps.MARGIN, + ViewProps.MARGIN_VERTICAL, + ViewProps.MARGIN_HORIZONTAL, + ViewProps.MARGIN_START, + ViewProps.MARGIN_END, + ViewProps.MARGIN_TOP, + ViewProps.MARGIN_BOTTOM, + ViewProps.MARGIN_LEFT, + ViewProps.MARGIN_RIGHT, + ] + ) + public fun setMargins(index: Int, margin: Dynamic) { + if (isVirtual) { + return + } + + val spacingType = + maybeTransformLeftRightToStartEnd(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]) + + tempYogaValue.setFromDynamic(margin) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setMargin(spacingType, tempYogaValue.value) + YogaUnit.AUTO -> setMarginAuto(spacingType) + YogaUnit.PERCENT -> setMarginPercent(spacingType, tempYogaValue.value) + else -> {} + } + + margin.recycle() + } + + @ReactPropGroup( + names = + [ + ViewProps.PADDING, + ViewProps.PADDING_VERTICAL, + ViewProps.PADDING_HORIZONTAL, + ViewProps.PADDING_START, + ViewProps.PADDING_END, + ViewProps.PADDING_TOP, + ViewProps.PADDING_BOTTOM, + ViewProps.PADDING_LEFT, + ViewProps.PADDING_RIGHT, + ] + ) + public fun setPaddings(index: Int, padding: Dynamic) { + if (isVirtual) { + return + } + + val spacingType = + maybeTransformLeftRightToStartEnd(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]) + + tempYogaValue.setFromDynamic(padding) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setPadding(spacingType, tempYogaValue.value) + YogaUnit.PERCENT -> setPaddingPercent(spacingType, tempYogaValue.value) + else -> {} + } + + padding.recycle() + } + + @ReactPropGroup( + names = + [ + ViewProps.BORDER_WIDTH, + ViewProps.BORDER_START_WIDTH, + ViewProps.BORDER_END_WIDTH, + ViewProps.BORDER_TOP_WIDTH, + ViewProps.BORDER_BOTTOM_WIDTH, + ViewProps.BORDER_LEFT_WIDTH, + ViewProps.BORDER_RIGHT_WIDTH, + ], + defaultFloat = Float.NaN, + ) + public fun setBorderWidths(index: Int, borderWidth: Float) { + if (isVirtual) { + return + } + val spacingType = maybeTransformLeftRightToStartEnd(ViewProps.BORDER_SPACING_TYPES[index]) + setBorder(spacingType, PixelUtil.toPixelFromDIP(borderWidth)) + } + + @ReactPropGroup( + names = + [ + ViewProps.START, + ViewProps.END, + ViewProps.LEFT, + ViewProps.RIGHT, + ViewProps.TOP, + ViewProps.BOTTOM, + ] + ) + public fun setPositionValues(index: Int, position: Dynamic) { + if (isVirtual) { + return + } + + val positionSpacingTypes = + intArrayOf( + Spacing.START, + Spacing.END, + Spacing.LEFT, + Spacing.RIGHT, + Spacing.TOP, + Spacing.BOTTOM, + ) + + val spacingType = maybeTransformLeftRightToStartEnd(positionSpacingTypes[index]) + + tempYogaValue.setFromDynamic(position) + when (tempYogaValue.unit) { + YogaUnit.POINT, + YogaUnit.UNDEFINED -> setPosition(spacingType, tempYogaValue.value) + YogaUnit.PERCENT -> setPositionPercent(spacingType, tempYogaValue.value) + else -> {} + } + + position.recycle() + } + + private fun maybeTransformLeftRightToStartEnd(spacingType: Int): Int { + if (!I18nUtil.getInstance().doLeftAndRightSwapInRTL(themedContext)) { + return spacingType + } + + return when (spacingType) { + Spacing.LEFT -> Spacing.START + Spacing.RIGHT -> Spacing.END + else -> spacingType + } + } + + @ReactProp(name = ViewProps.POSITION) + public fun setPosition(position: String?) { + if (isVirtual) { + return + } + + if (position == null) { + setPositionType(YogaPositionType.RELATIVE) + return + } + + when (position) { + "relative" -> setPositionType(YogaPositionType.RELATIVE) + "absolute" -> setPositionType(YogaPositionType.ABSOLUTE) + else -> { + FLog.w(ReactConstants.TAG, "invalid value for position: $position") + setPositionType(YogaPositionType.RELATIVE) + } + } + } + + @ReactProp(name = "onLayout") + public override fun setShouldNotifyOnLayout(shouldNotifyOnLayout: Boolean) { + super.setShouldNotifyOnLayout(shouldNotifyOnLayout) + } + + @ReactProp(name = "onPointerEnter") + public fun setShouldNotifyPointerEnter(@Suppress("UNUSED_PARAMETER") value: Boolean) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactProp(name = "onPointerLeave") + public fun setShouldNotifyPointerLeave(@Suppress("UNUSED_PARAMETER") value: Boolean) { + // Do Nothing: Align with static ViewConfigs + } + + @ReactProp(name = "onPointerMove") + public fun setShouldNotifyPointerMove(@Suppress("UNUSED_PARAMETER") value: Boolean) { + // Do Nothing: Align with static ViewConfigs + } + + public companion object { + init { + LegacyArchitectureLogger.assertLegacyArchitecture( + "LayoutShadowNode", + LegacyArchitectureLogLevel.ERROR, + ) + } + } +}