diff --git a/Libraries/Animated/NativeAnimatedHelper.js b/Libraries/Animated/NativeAnimatedHelper.js index f24478627f049a..a097db20a6b081 100644 --- a/Libraries/Animated/NativeAnimatedHelper.js +++ b/Libraries/Animated/NativeAnimatedHelper.js @@ -391,11 +391,15 @@ const SUPPORTED_STYLES = { borderBottomLeftRadius: true, borderBottomRightRadius: true, borderBottomStartRadius: true, + borderEndEndRadius: true, + borderEndStartRadius: true, borderRadius: true, borderTopEndRadius: true, borderTopLeftRadius: true, borderTopRightRadius: true, borderTopStartRadius: true, + borderStartEndRadius: true, + borderStartStartRadius: true, elevation: true, opacity: true, transform: true, diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 8b93bb79072e60..7408b96a461432 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -125,10 +125,14 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { borderColor: colorAttributes, borderCurve: true, borderEndColor: colorAttributes, + borderEndEndRadius: true, + borderEndStartRadius: true, borderLeftColor: colorAttributes, borderRadius: true, borderRightColor: colorAttributes, borderStartColor: colorAttributes, + borderStartEndRadius: true, + borderStartStartRadius: true, borderStyle: true, borderTopColor: colorAttributes, borderTopEndRadius: true, diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 76125cd9fad6e0..b60bc0a8d1efec 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -45,7 +45,10 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = borderTopEndRadius: true, borderBottomStartRadius: true, borderBottomEndRadius: true, - + borderEndEndRadius: true, + borderEndStartRadius: true, + borderStartEndRadius: true, + borderStartStartRadius: true, borderStyle: true, hitSlop: true, pointerEvents: true, diff --git a/Libraries/NativeComponent/BaseViewConfig.ios.js b/Libraries/NativeComponent/BaseViewConfig.ios.js index 1888cb142e9924..d8af157c4920ec 100644 --- a/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -221,6 +221,10 @@ const validAttributesForNonEventProps = { borderBottomRightRadius: true, borderBottomStartRadius: true, borderBottomEndRadius: true, + borderEndEndRadius: true, + borderEndStartRadius: true, + borderStartEndRadius: true, + borderStartStartRadius: true, display: true, zIndex: true, diff --git a/Libraries/StyleSheet/StyleSheetTypes.d.ts b/Libraries/StyleSheet/StyleSheetTypes.d.ts index 4a77bada47948f..f8ea56ae7989ff 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -240,12 +240,16 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { borderBottomWidth?: number | undefined; borderColor?: ColorValue | undefined; borderEndColor?: ColorValue | undefined; + borderEndEndRadius?: number | undefined; + borderEndStartRadius?: number | undefined; borderLeftColor?: ColorValue | undefined; borderLeftWidth?: number | undefined; borderRadius?: number | undefined; borderRightColor?: ColorValue | undefined; borderRightWidth?: number | undefined; borderStartColor?: ColorValue | undefined; + borderStartEndRadius?: number | undefined; + borderStartStartRadius?: number | undefined; borderStyle?: 'solid' | 'dotted' | 'dashed' | undefined; borderTopColor?: ColorValue | undefined; borderTopEndRadius?: number | undefined; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index b6b056b93637cc..44015f2b02b160 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -703,6 +703,10 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ borderBottomLeftRadius?: number | AnimatedNode, borderBottomRightRadius?: number | AnimatedNode, borderBottomStartRadius?: number | AnimatedNode, + borderEndEndRadius?: number | AnimatedNode, + borderEndStartRadius?: number | AnimatedNode, + borderStartEndRadius?: number | AnimatedNode, + borderStartStartRadius?: number | AnimatedNode, borderTopEndRadius?: number | AnimatedNode, borderTopLeftRadius?: number | AnimatedNode, borderTopRightRadius?: number | AnimatedNode, diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b3df8e80a68b38..adda5c1f016848 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -71,6 +71,10 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) CGFloat borderBottomRightRadius; @property (nonatomic, assign) CGFloat borderBottomStartRadius; @property (nonatomic, assign) CGFloat borderBottomEndRadius; +@property (nonatomic, assign) CGFloat borderEndEndRadius; +@property (nonatomic, assign) CGFloat borderEndStartRadius; +@property (nonatomic, assign) CGFloat borderStartEndRadius; +@property (nonatomic, assign) CGFloat borderStartStartRadius; /** * Border colors (actually retained). diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 923e584786604f..f9a38f31040f1b 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -128,6 +128,10 @@ - (instancetype)initWithFrame:(CGRect)frame _borderBottomRightRadius = -1; _borderBottomStartRadius = -1; _borderBottomEndRadius = -1; + _borderEndEndRadius = -1; + _borderEndStartRadius = -1; + _borderStartEndRadius = -1; + _borderStartStartRadius = -1; _borderCurve = RCTBorderCurveCircular; _borderStyle = RCTBorderStyleSolid; _hitTestEdgeInsets = UIEdgeInsetsZero; @@ -667,11 +671,16 @@ - (RCTCornerRadii)cornerRadii CGFloat bottomLeftRadius; CGFloat bottomRightRadius; + const CGFloat logicalTopStartRadius = RCTDefaultIfNegativeTo(_borderStartStartRadius, _borderTopStartRadius); + const CGFloat logicalTopEndRadius = RCTDefaultIfNegativeTo(_borderStartEndRadius, _borderTopEndRadius); + const CGFloat logicalBottomStartRadius = RCTDefaultIfNegativeTo(_borderEndStartRadius, _borderBottomStartRadius); + const CGFloat logicalBottomEndRadius = RCTDefaultIfNegativeTo(_borderEndEndRadius, _borderBottomEndRadius); + if ([[RCTI18nUtil sharedInstance] doLeftAndRightSwapInRTL]) { - const CGFloat topStartRadius = RCTDefaultIfNegativeTo(_borderTopLeftRadius, _borderTopStartRadius); - const CGFloat topEndRadius = RCTDefaultIfNegativeTo(_borderTopRightRadius, _borderTopEndRadius); - const CGFloat bottomStartRadius = RCTDefaultIfNegativeTo(_borderBottomLeftRadius, _borderBottomStartRadius); - const CGFloat bottomEndRadius = RCTDefaultIfNegativeTo(_borderBottomRightRadius, _borderBottomEndRadius); + const CGFloat topStartRadius = RCTDefaultIfNegativeTo(_borderTopLeftRadius, logicalTopStartRadius); + const CGFloat topEndRadius = RCTDefaultIfNegativeTo(_borderTopRightRadius, logicalTopEndRadius); + const CGFloat bottomStartRadius = RCTDefaultIfNegativeTo(_borderBottomLeftRadius, logicalBottomStartRadius); + const CGFloat bottomEndRadius = RCTDefaultIfNegativeTo(_borderBottomRightRadius, logicalBottomEndRadius); const CGFloat directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius; const CGFloat directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius; @@ -683,10 +692,10 @@ - (RCTCornerRadii)cornerRadii bottomLeftRadius = RCTDefaultIfNegativeTo(radius, directionAwareBottomLeftRadius); bottomRightRadius = RCTDefaultIfNegativeTo(radius, directionAwareBottomRightRadius); } else { - const CGFloat directionAwareTopLeftRadius = isRTL ? _borderTopEndRadius : _borderTopStartRadius; - const CGFloat directionAwareTopRightRadius = isRTL ? _borderTopStartRadius : _borderTopEndRadius; - const CGFloat directionAwareBottomLeftRadius = isRTL ? _borderBottomEndRadius : _borderBottomStartRadius; - const CGFloat directionAwareBottomRightRadius = isRTL ? _borderBottomStartRadius : _borderBottomEndRadius; + const CGFloat directionAwareTopLeftRadius = isRTL ? logicalTopEndRadius : logicalTopStartRadius; + const CGFloat directionAwareTopRightRadius = isRTL ? logicalTopStartRadius : logicalTopEndRadius; + const CGFloat directionAwareBottomLeftRadius = isRTL ? logicalBottomEndRadius : logicalBottomStartRadius; + const CGFloat directionAwareBottomRightRadius = isRTL ? logicalBottomStartRadius : logicalBottomEndRadius; topLeftRadius = RCTDefaultIfNegativeTo(radius, RCTDefaultIfNegativeTo(_borderTopLeftRadius, directionAwareTopLeftRadius)); @@ -946,7 +955,8 @@ -(void)setBorder##side##Radius : (CGFloat)radius \ setBorderRadius() setBorderRadius(TopLeft) setBorderRadius(TopRight) setBorderRadius(TopStart) setBorderRadius(TopEnd) setBorderRadius(BottomLeft) setBorderRadius(BottomRight) - setBorderRadius(BottomStart) setBorderRadius(BottomEnd) + setBorderRadius(BottomStart) setBorderRadius(BottomEnd) setBorderRadius(EndEnd) + setBorderRadius(EndStart) setBorderRadius(StartEnd) setBorderRadius(StartStart) #pragma mark - Border Curve @@ -960,7 +970,7 @@ -(void)setBorder##side##Curve : (RCTBorderCurve)curve \ [self.layer setNeedsDisplay]; \ } - setBorderCurve() + setBorderCurve() #pragma mark - Border Style @@ -974,6 +984,6 @@ -(void)setBorder##side##Style : (RCTBorderStyle)style \ [self.layer setNeedsDisplay]; \ } - setBorderStyle() + setBorderStyle() - @end + @end diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 309f9a2fb8fc5c..a12aeb42dd8608 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -376,6 +376,10 @@ - (RCTShadowView *)shadowView RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomRight) RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomStart) RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomEnd) +RCT_VIEW_BORDER_RADIUS_PROPERTY(EndEnd) +RCT_VIEW_BORDER_RADIUS_PROPERTY(EndStart) +RCT_VIEW_BORDER_RADIUS_PROPERTY(StartEnd) +RCT_VIEW_BORDER_RADIUS_PROPERTY(StartStart) RCT_REMAP_VIEW_PROPERTY(display, reactDisplay, YGDisplay) RCT_REMAP_VIEW_PROPERTY(zIndex, reactZIndex, NSInteger) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 462fd25ee28949..53cc9783421917 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -139,6 +139,10 @@ public class ViewProps { public static final String BORDER_TOP_END_RADIUS = "borderTopEndRadius"; public static final String BORDER_BOTTOM_START_RADIUS = "borderBottomStartRadius"; public static final String BORDER_BOTTOM_END_RADIUS = "borderBottomEndRadius"; + public static final String BORDER_END_END_RADIUS = "borderEndEndRadius"; + public static final String BORDER_END_START_RADIUS = "borderEndStartRadius"; + public static final String BORDER_START_END_RADIUS = "borderStartEndRadius"; + public static final String BORDER_START_START_RADIUS = "borderStartStartRadius"; public static final String BORDER_START_COLOR = "borderStartColor"; public static final String BORDER_END_COLOR = "borderEndColor"; public static final String ON_LAYOUT = "onLayout"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt index 81080626f7f3b1..100cf1c36d3d0e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt @@ -97,6 +97,10 @@ object ReactMapBufferPropSetter { private const val CORNER_BOTTOM_END = 6 private const val CORNER_BOTTOM_START = 7 private const val CORNER_ALL = 8 + private const val CORNER_END_END = 9 + private const val CORNER_END_START = 10 + private const val CORNER_START_END = 11 + private const val CORNER_START_START = 12 private const val NATIVE_DRAWABLE_KIND = 0 private const val NATIVE_DRAWABLE_ATTRIBUTE = 1 @@ -365,6 +369,10 @@ object ReactMapBufferPropSetter { CORNER_TOP_END -> 6 CORNER_BOTTOM_START -> 7 CORNER_BOTTOM_END -> 8 + CORNER_END_END -> 9 + CORNER_END_START -> 10 + CORNER_START_END -> 11 + CORNER_START_START -> 12 else -> throw IllegalArgumentException("Unknown key for border style: $key") } val borderRadius = entry.doubleValue diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java index 532d025c1aa31a..937abcc20bb392 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewBackgroundDrawable.java @@ -128,7 +128,11 @@ public enum BorderRadiusLocation { TOP_START, TOP_END, BOTTOM_START, - BOTTOM_END + BOTTOM_END, + END_END, + END_START, + START_END, + START_START } public ReactViewBackgroundDrawable(Context context) { @@ -271,7 +275,7 @@ public void setRadius(float radius) { public void setRadius(float radius, int position) { if (mBorderCornerRadii == null) { - mBorderCornerRadii = new float[8]; + mBorderCornerRadii = new float[12]; Arrays.fill(mBorderCornerRadii, YogaConstants.UNDEFINED); } @@ -581,6 +585,11 @@ private void updatePath() { float bottomStartRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_START); float bottomEndRadius = getBorderRadius(BorderRadiusLocation.BOTTOM_END); + float endEndRadius = getBorderRadius(BorderRadiusLocation.END_END); + float endStartRadius = getBorderRadius(BorderRadiusLocation.END_START); + float startEndRadius = getBorderRadius(BorderRadiusLocation.START_END); + float startStartRadius = getBorderRadius(BorderRadiusLocation.START_START); + if (I18nUtil.getInstance().doLeftAndRightSwapInRTL(mContext)) { if (YogaConstants.isUndefined(topStartRadius)) { topStartRadius = topLeftRadius; @@ -598,20 +607,44 @@ private void updatePath() { bottomEndRadius = bottomRightRadius; } - final float directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius; - final float directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius; - final float directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius; - final float directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius; + final float logicalTopStartRadius = + YogaConstants.isUndefined(topStartRadius) ? startStartRadius : topStartRadius; + final float logicalTopEndRadius = + YogaConstants.isUndefined(topEndRadius) ? startEndRadius : topEndRadius; + final float logicalBottomStartRadius = + YogaConstants.isUndefined(bottomStartRadius) ? endStartRadius : bottomStartRadius; + final float logicalBottomEndRadius = + YogaConstants.isUndefined(bottomEndRadius) ? endEndRadius : bottomEndRadius; + + final float directionAwareTopLeftRadius = isRTL ? logicalTopEndRadius : logicalTopStartRadius; + final float directionAwareTopRightRadius = + isRTL ? logicalTopStartRadius : logicalTopEndRadius; + final float directionAwareBottomLeftRadius = + isRTL ? logicalBottomEndRadius : logicalBottomStartRadius; + final float directionAwareBottomRightRadius = + isRTL ? logicalBottomStartRadius : logicalBottomEndRadius; topLeftRadius = directionAwareTopLeftRadius; topRightRadius = directionAwareTopRightRadius; bottomLeftRadius = directionAwareBottomLeftRadius; bottomRightRadius = directionAwareBottomRightRadius; } else { - final float directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius; - final float directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius; - final float directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius; - final float directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius; + final float logicalTopStartRadius = + YogaConstants.isUndefined(topStartRadius) ? startStartRadius : topStartRadius; + final float logicalTopEndRadius = + YogaConstants.isUndefined(topEndRadius) ? startEndRadius : topEndRadius; + final float logicalBottomStartRadius = + YogaConstants.isUndefined(bottomStartRadius) ? endStartRadius : bottomStartRadius; + final float logicalBottomEndRadius = + YogaConstants.isUndefined(bottomEndRadius) ? endEndRadius : bottomEndRadius; + + final float directionAwareTopLeftRadius = isRTL ? logicalTopEndRadius : logicalTopStartRadius; + final float directionAwareTopRightRadius = + isRTL ? logicalTopStartRadius : logicalTopEndRadius; + final float directionAwareBottomLeftRadius = + isRTL ? logicalBottomEndRadius : logicalBottomStartRadius; + final float directionAwareBottomRightRadius = + isRTL ? logicalBottomStartRadius : logicalBottomEndRadius; if (!YogaConstants.isUndefined(directionAwareTopLeftRadius)) { topLeftRadius = directionAwareTopLeftRadius; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java index 7765a3a828c15f..91cbdf7c3b741a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.java @@ -119,6 +119,10 @@ public void nextFocusUp(ReactViewGroup view, int viewId) { ViewProps.BORDER_TOP_END_RADIUS, ViewProps.BORDER_BOTTOM_START_RADIUS, ViewProps.BORDER_BOTTOM_END_RADIUS, + ViewProps.BORDER_END_END_RADIUS, + ViewProps.BORDER_END_START_RADIUS, + ViewProps.BORDER_START_END_RADIUS, + ViewProps.BORDER_START_START_RADIUS, }, defaultFloat = YogaConstants.UNDEFINED) public void setBorderRadius(ReactViewGroup view, int index, float borderRadius) { diff --git a/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h b/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h index fe44e662340b63..6e05d0afb35b19 100644 --- a/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h +++ b/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h @@ -113,6 +113,10 @@ constexpr MapBuffer::Key CORNER_TOP_END = 5; constexpr MapBuffer::Key CORNER_BOTTOM_END = 6; constexpr MapBuffer::Key CORNER_BOTTOM_START = 7; constexpr MapBuffer::Key CORNER_ALL = 8; +constexpr MapBuffer::Key CORNER_END_END = 9; +constexpr MapBuffer::Key CORNER_END_START = 10; +constexpr MapBuffer::Key CORNER_START_END = 11; +constexpr MapBuffer::Key CORNER_START_START = 12; inline void putOptionalFloat( MapBufferBuilder &builder, @@ -122,7 +126,7 @@ inline void putOptionalFloat( } MapBuffer convertBorderRadii(CascadedBorderRadii const &radii) { - MapBufferBuilder builder(9); + MapBufferBuilder builder(13); putOptionalFloat(builder, CORNER_TOP_LEFT, radii.topLeft); putOptionalFloat(builder, CORNER_TOP_RIGHT, radii.topRight); putOptionalFloat(builder, CORNER_BOTTOM_RIGHT, radii.bottomRight); @@ -132,6 +136,10 @@ MapBuffer convertBorderRadii(CascadedBorderRadii const &radii) { putOptionalFloat(builder, CORNER_BOTTOM_END, radii.bottomEnd); putOptionalFloat(builder, CORNER_BOTTOM_START, radii.bottomStart); putOptionalFloat(builder, CORNER_ALL, radii.all); + putOptionalFloat(builder, CORNER_END_END, radii.endEnd); + putOptionalFloat(builder, CORNER_END_START, radii.endStart); + putOptionalFloat(builder, CORNER_START_END, radii.startEnd); + putOptionalFloat(builder, CORNER_START_START, radii.startStart); return builder.build(); } diff --git a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 93c3b543f10b5a..306fd68cd108aa 100644 --- a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -772,6 +772,7 @@ void YogaLayoutableShadowNode::swapLeftAndRightInViewProps( auto &props = const_cast(typedCasting); // Swap border node values, borderRadii, borderColors and borderStyles. + if (props.borderRadii.topLeft.has_value()) { props.borderRadii.topStart = props.borderRadii.topLeft; props.borderRadii.topLeft.reset(); diff --git a/ReactCommon/react/renderer/components/view/primitives.h b/ReactCommon/react/renderer/components/view/primitives.h index ac4dc7fb0c5978..34ea20376f1df9 100644 --- a/ReactCommon/react/renderer/components/view/primitives.h +++ b/ReactCommon/react/renderer/components/view/primitives.h @@ -160,12 +160,21 @@ struct CascadedRectangleCorners { OptionalT bottomStart{}; OptionalT bottomEnd{}; OptionalT all{}; + OptionalT endEnd{}; + OptionalT endStart{}; + OptionalT startEnd{}; + OptionalT startStart{}; Counterpart resolve(bool isRTL, T defaults) const { - const auto topLeading = isRTL ? topEnd : topStart; - const auto topTrailing = isRTL ? topStart : topEnd; - const auto bottomLeading = isRTL ? bottomEnd : bottomStart; - const auto bottomTrailing = isRTL ? bottomStart : bottomEnd; + const auto logicalTopStart = topStart ? topStart : startStart; + const auto logicalTopEnd = topEnd ? topEnd : startEnd; + const auto logicalBottomStart = bottomStart ? bottomStart : endStart; + const auto logicalBottomEnd = bottomEnd ? bottomEnd : endEnd; + + const auto topLeading = isRTL ? logicalTopEnd : logicalTopStart; + const auto topTrailing = isRTL ? logicalTopStart : logicalTopEnd; + const auto bottomLeading = isRTL ? logicalBottomEnd : logicalBottomStart; + const auto bottomTrailing = isRTL ? logicalBottomStart : logicalBottomEnd; return { /* .topLeft = */ topLeft.value_or( @@ -189,7 +198,11 @@ struct CascadedRectangleCorners { this->topEnd, this->bottomStart, this->bottomEnd, - this->all) == + this->all, + this->endEnd, + this->endStart, + this->startEnd, + this->startStart) == std::tie( rhs.topLeft, rhs.topRight, @@ -199,7 +212,11 @@ struct CascadedRectangleCorners { rhs.topEnd, rhs.bottomStart, rhs.bottomEnd, - rhs.all); + rhs.all, + rhs.endEnd, + rhs.endStart, + rhs.startEnd, + rhs.startStart); } bool operator!=(const CascadedRectangleCorners &rhs) const { diff --git a/ReactCommon/react/renderer/components/view/propsConversions.h b/ReactCommon/react/renderer/components/view/propsConversions.h index d5087ae4e6050b..97fa6b6d7eeb02 100644 --- a/ReactCommon/react/renderer/components/view/propsConversions.h +++ b/ReactCommon/react/renderer/components/view/propsConversions.h @@ -401,6 +401,38 @@ static inline CascadedRectangleCorners convertRawProp( defaultValue.bottomEnd, prefix, suffix); + result.endEnd = convertRawProp( + context, + rawProps, + "EndEnd", + sourceValue.endEnd, + defaultValue.endEnd, + prefix, + suffix); + result.endStart = convertRawProp( + context, + rawProps, + "EndStart", + sourceValue.endStart, + defaultValue.endStart, + prefix, + suffix); + result.startEnd = convertRawProp( + context, + rawProps, + "StartEnd", + sourceValue.startEnd, + defaultValue.startEnd, + prefix, + suffix); + result.startStart = convertRawProp( + context, + rawProps, + "StartStart", + sourceValue.startStart, + defaultValue.startStart, + prefix, + suffix); result.all = convertRawProp( context, rawProps, "", sourceValue.all, defaultValue.all, prefix, suffix); diff --git a/ReactCommon/react/renderer/components/view/viewPropConversions.h b/ReactCommon/react/renderer/components/view/viewPropConversions.h index 6a672aef01ad4c..fe253277752cb4 100644 --- a/ReactCommon/react/renderer/components/view/viewPropConversions.h +++ b/ReactCommon/react/renderer/components/view/viewPropConversions.h @@ -38,6 +38,10 @@ constexpr MapBuffer::Key CORNER_TOP_END = 5; constexpr MapBuffer::Key CORNER_BOTTOM_END = 6; constexpr MapBuffer::Key CORNER_BOTTOM_START = 7; constexpr MapBuffer::Key CORNER_ALL = 8; +constexpr MapBuffer::Key CORNER_END_END = 9; +constexpr MapBuffer::Key CORNER_END_START = 10; +constexpr MapBuffer::Key CORNER_START_END = 11; +constexpr MapBuffer::Key CORNER_START_START = 12; inline void putOptionalFloat( MapBufferBuilder &builder, @@ -116,7 +120,7 @@ MapBuffer convertCascadedEdges(CascadedRectangleEdges const &edges) { template MapBuffer convertCascadedCorners(CascadedRectangleCorners const &corners) { - MapBufferBuilder builder(9); + MapBufferBuilder builder(13); putOptionalFloat( builder, CORNER_TOP_LEFT, optionalFromValue(corners.topLeft)); putOptionalFloat( @@ -132,6 +136,13 @@ MapBuffer convertCascadedCorners(CascadedRectangleCorners const &corners) { builder, CORNER_BOTTOM_END, optionalFromValue(corners.bottomEnd)); putOptionalFloat( builder, CORNER_BOTTOM_START, optionalFromValue(corners.bottomStart)); + putOptionalFloat(builder, CORNER_END_END, optionalFromValue(corners.endEnd)); + putOptionalFloat( + builder, CORNER_END_START, optionalFromValue(corners.endStart)); + putOptionalFloat( + builder, CORNER_START_END, optionalFromValue(corners.startEnd)); + putOptionalFloat( + builder, CORNER_START_START, optionalFromValue(corners.startStart)); putOptionalFloat(builder, CORNER_ALL, optionalFromValue(corners.all)); return builder.build(); } diff --git a/ReactCommon/react/renderer/core/PropsMacros.h b/ReactCommon/react/renderer/core/PropsMacros.h index 519c1307f01826..2aa75fd4e4216e 100644 --- a/ReactCommon/react/renderer/core/PropsMacros.h +++ b/ReactCommon/react/renderer/core/PropsMacros.h @@ -71,7 +71,15 @@ CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ struct, bottomEnd, prefix "BottomEnd" suffix, rawValue) \ CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ - struct, all, prefix "" suffix, rawValue) + struct, all, prefix "" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, endEnd, prefix "EndEnd" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, endStart, prefix "EndStart" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, startEnd, prefix "StartEnd" suffix, rawValue) \ + CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ + struct, startStart, prefix "StartStart" suffix, rawValue) #define SET_CASCADED_RECTANGLE_EDGES(struct, prefix, suffix, rawValue) \ CASE_STATEMENT_SET_FIELD_VALUE_INDEXED( \ diff --git a/packages/rn-tester/js/examples/RTL/RTLExample.js b/packages/rn-tester/js/examples/RTL/RTLExample.js index 01bf6deea3e425..06eb6c9bbf79bc 100644 --- a/packages/rn-tester/js/examples/RTL/RTLExample.js +++ b/packages/rn-tester/js/examples/RTL/RTLExample.js @@ -509,6 +509,35 @@ const BorderRadiiExample = withRTLState(({isRTL, setRTL}) => { ); }); +const LogicalBorderRadiiExample = withRTLState(({isRTL, setRTL}) => { + return ( + + Styles + borderStartStartRadius: 10, + borderStartEndRadius: 20, + borderEndStartRadius: 30, + borderEndEndRadius: 40 + + Demo: + + + + + + + + + ); +}); + const BorderExample = withRTLState(({isRTL, setRTL}) => { return ( @@ -771,6 +800,12 @@ exports.examples = [ return ; }, }, + { + title: 'Logical Border Radii Start/End', + render: function (): React.Element { + return ; + }, + }, { title: 'Border', render: function (): React.Element {