From b37d8446894f37f61eb143a8bf19e37b4ed84471 Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Sat, 7 May 2022 15:29:34 +0200 Subject: [PATCH 1/5] added ios border curve style prop --- .../View/ReactNativeStyleAttributes.js | 1 + .../NativeComponent/BaseViewConfig.ios.js | 1 + Libraries/StyleSheet/StyleSheetTypes.js | 1 + React/Base/RCTConvert.h | 2 ++ React/Base/RCTConvert.m | 9 ++++++ React/Views/RCTBorderCurve.h | 13 ++++++++ React/Views/RCTViewManager.m | 14 +++++++++ .../rn-tester/js/examples/View/ViewExample.js | 30 +++++++++++++++---- 8 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 React/Views/RCTBorderCurve.h diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 9525991e831b..7dee8e54b513 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -105,6 +105,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { borderBottomRightRadius: true, borderBottomStartRadius: true, borderColor: colorAttributes, + borderCurve: true, borderEndColor: colorAttributes, borderLeftColor: colorAttributes, borderRadius: true, diff --git a/Libraries/NativeComponent/BaseViewConfig.ios.js b/Libraries/NativeComponent/BaseViewConfig.ios.js index 620c915d21f8..b644c3c45785 100644 --- a/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -181,6 +181,7 @@ const validAttributesForNonEventProps = { removeClippedSubviews: true, borderRadius: true, borderColor: {process: require('../StyleSheet/processColor')}, + borderCurve: true, borderWidth: true, borderStyle: true, hitSlop: {diff: require('../Utilities/differ/insetsDiffer')}, diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index a12ed0cafc1a..4b7aa36cda6c 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -532,6 +532,7 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{ backfaceVisibility?: 'visible' | 'hidden', backgroundColor?: ____ColorValue_Internal, borderColor?: ____ColorValue_Internal, + borderCurve?: 'circular' | 'continuous', borderBottomColor?: ____ColorValue_Internal, borderEndColor?: ____ColorValue_Internal, borderLeftColor?: ____ColorValue_Internal, diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index c4913f60c7ab..2f2af8ba6aef 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -10,6 +10,7 @@ #import #import +#import #import #import #import @@ -130,6 +131,7 @@ typedef BOOL css_backface_visibility_t; + (RCTPointerEvents)RCTPointerEvents:(id)json; + (RCTAnimationType)RCTAnimationType:(id)json; + (RCTBorderStyle)RCTBorderStyle:(id)json; ++ (RCTBorderCurve)RCTBorderCurve:(id)json; + (RCTTextDecorationLineType)RCTTextDecorationLineType:(id)json; @end diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index c21ef072acd4..98c14225daa6 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -345,6 +345,15 @@ + (NSLocale *)NSLocale:(id)json RCTBorderStyleSolid, integerValue) +RCT_ENUM_CONVERTER( + RCTBorderCurve, + (@{ + @"circular" : @(RCTBorderCurveCircular), + @"continuous" : @(RCTBorderCurveContinuous), + }), + RCTBorderCurveCircular, + integerValue) + RCT_ENUM_CONVERTER( RCTTextDecorationLineType, (@{ diff --git a/React/Views/RCTBorderCurve.h b/React/Views/RCTBorderCurve.h new file mode 100644 index 000000000000..5cc87a3da7e6 --- /dev/null +++ b/React/Views/RCTBorderCurve.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +typedef NS_ENUM(NSInteger, RCTBorderCurve) { + RCTBorderCurveContinuous = 0, + RCTBorderCurveCircular, +}; \ No newline at end of file diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 5dd39c06871c..cd93a3cdc38f 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -9,6 +9,7 @@ #import "RCTAssert.h" #import "RCTBorderStyle.h" +#import "RCTBorderCurve.h" #import "RCTBridge.h" #import "RCTConvert+Transform.h" #import "RCTConvert.h" @@ -264,6 +265,19 @@ - (RCTShadowView *)shadowView view.removeClippedSubviews = json ? [RCTConvert BOOL:json] : defaultView.removeClippedSubviews; } } +RCT_CUSTOM_VIEW_PROPERTY(borderCurve, RCTBorderCurve, RCTView) +{ + if (@available(iOS 13.0, *)) { + switch ([RCTConvert RCTBorderCurve:json]) { + case RCTBorderCurveContinuous: + view.layer.cornerCurve = kCACornerCurveContinuous; + break; + case RCTBorderCurveCircular: + view.layer.cornerCurve = kCACornerCurveCircular; + break; + } + } +} RCT_CUSTOM_VIEW_PROPERTY(borderRadius, CGFloat, RCTView) { if ([view respondsToSelector:@selector(setBorderRadius:)]) { diff --git a/packages/rn-tester/js/examples/View/ViewExample.js b/packages/rn-tester/js/examples/View/ViewExample.js index 2ea127b9df19..fd15cf4c1ceb 100644 --- a/packages/rn-tester/js/examples/View/ViewExample.js +++ b/packages/rn-tester/js/examples/View/ViewExample.js @@ -17,6 +17,7 @@ const { Text, TouchableWithoutFeedback, View, + Platform, } = require('react-native'); class ViewBorderStyleExample extends React.Component< @@ -360,12 +361,29 @@ exports.examples = [ title: 'Border Radius', render(): React.Node { return ( - - - Too much use of `borderRadius` (especially large radii) on anything - which is scrolling may result in dropped frames. Use sparingly. - - + <> + + + Too much use of `borderRadius` (especially large radii) on + anything which is scrolling may result in dropped frames. Use + sparingly. + + + {Platform.OS === 'ios' && ( + + + View with continuous border curve + + + )} + ); }, }, From b5df52f20000aeb02d8b19b9a7ea8ee96226c60b Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Sat, 14 May 2022 15:59:33 +0200 Subject: [PATCH 2/5] add borderCurve prop to Fabric --- .../View/RCTViewComponentView.mm | 10 ++++++++++ React/Views/RCTView.h | 6 ++++++ React/Views/RCTView.m | 16 ++++++++++++++++ React/Views/RCTViewManager.m | 2 +- .../renderer/components/view/ViewProps.cpp | 8 ++++++++ .../react/renderer/components/view/ViewProps.h | 1 + .../renderer/components/view/conversions.h | 18 ++++++++++++++++++ .../renderer/components/view/primitives.h | 7 +++++++ 8 files changed, 67 insertions(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 172020a7e5b6..89be6477215f 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -580,6 +580,16 @@ - (void)invalidateLayer layer.borderColor = borderColor; CGColorRelease(borderColor); layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft; + if (@available(iOS 13.0, *)) { + switch (borderMetrics.borderCurves.topLeft) { + case BorderCurve::Continuous: + layer.cornerCurve = kCACornerCurveContinuous; + break; + case BorderCurve::Circular: + layer.cornerCurve = kCACornerCurveCircular; + break; + } + } layer.backgroundColor = _backgroundColor.CGColor; } else { if (!_borderLayer) { diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b00905d51fdd..f490372cc1c0 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -7,6 +7,7 @@ #import +#import #import #import #import @@ -93,6 +94,11 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, assign) CGFloat borderEndWidth; @property (nonatomic, assign) CGFloat borderWidth; +/** + * Border curve. + */ +@property (nonatomic, assign) RCTBorderCurve borderCurve; + /** * Border styles. */ diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 03dcc94d9310..76f11b629854 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -10,6 +10,7 @@ #import #import "RCTAutoInsetsProtocol.h" +#import "RCTBorderCurve.h" #import "RCTBorderDrawing.h" #import "RCTI18nUtil.h" #import "RCTLog.h" @@ -126,6 +127,7 @@ - (instancetype)initWithFrame:(CGRect)frame _borderBottomRightRadius = -1; _borderBottomStartRadius = -1; _borderBottomEndRadius = -1; + _borderCurve = RCTBorderCurveCircular; _borderStyle = RCTBorderStyleSolid; _hitTestEdgeInsets = UIEdgeInsetsZero; @@ -945,6 +947,20 @@ -(void)setBorder##side##Radius : (CGFloat)radius \ setBorderRadius(TopEnd) setBorderRadius(BottomLeft) setBorderRadius(BottomRight) setBorderRadius(BottomStart) setBorderRadius(BottomEnd) +#pragma mark - Border Curve + +#define setBorderCurve(side) \ + -(void)setBorder##side##Curve : (RCTBorderCurve)curve \ + { \ + if (_border##side##Curve == curve) { \ + return; \ + } \ + _border##side##Curve = curve; \ + [self.layer setNeedsDisplay]; \ + } + + setBorderCurve() + #pragma mark - Border Style #define setBorderStyle(side) \ diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index cd93a3cdc38f..858cd831b501 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -8,8 +8,8 @@ #import "RCTViewManager.h" #import "RCTAssert.h" -#import "RCTBorderStyle.h" #import "RCTBorderCurve.h" +#import "RCTBorderStyle.h" #import "RCTBridge.h" #import "RCTConvert+Transform.h" #import "RCTConvert.h" diff --git a/ReactCommon/react/renderer/components/view/ViewProps.cpp b/ReactCommon/react/renderer/components/view/ViewProps.cpp index aadc27692bbb..69a4b5cefd81 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.cpp +++ b/ReactCommon/react/renderer/components/view/ViewProps.cpp @@ -57,6 +57,13 @@ ViewProps::ViewProps( "Color", sourceProps.borderColors, {})), + borderCurves(convertRawProp( + context, + rawProps, + "border", + "Curve", + sourceProps.borderCurves, + {})), borderStyles(convertRawProp( context, rawProps, @@ -251,6 +258,7 @@ BorderMetrics ViewProps::resolveBorderMetrics( /* .borderWidths = */ borderWidths.resolve(isRTL, 0), /* .borderRadii = */ ensureNoOverlap(borderRadii.resolve(isRTL, 0), layoutMetrics.frame.size), + /* .borderCurves = */ borderCurves.resolve(isRTL, BorderCurve::Circular), /* .borderStyles = */ borderStyles.resolve(isRTL, BorderStyle::Solid), }; } diff --git a/ReactCommon/react/renderer/components/view/ViewProps.h b/ReactCommon/react/renderer/components/view/ViewProps.h index be31a70f787c..52f869d660ff 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.h +++ b/ReactCommon/react/renderer/components/view/ViewProps.h @@ -45,6 +45,7 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps { // Borders CascadedBorderRadii borderRadii{}; CascadedBorderColors borderColors{}; + CascadedBorderCurves borderCurves{}; CascadedBorderStyles borderStyles{}; // Shadow diff --git a/ReactCommon/react/renderer/components/view/conversions.h b/ReactCommon/react/renderer/components/view/conversions.h index 2da720e2e590..43fcb33de435 100644 --- a/ReactCommon/react/renderer/components/view/conversions.h +++ b/ReactCommon/react/renderer/components/view/conversions.h @@ -560,6 +560,24 @@ inline void fromRawValue( react_native_assert(false); } +inline void fromRawValue( + const PropsParserContext &context, + const RawValue &value, + BorderCurve &result) { + react_native_assert(value.hasType()); + auto stringValue = (std::string)value; + if (stringValue == "circular") { + result = BorderCurve::Circular; + return; + } + if (stringValue == "continuous") { + result = BorderCurve::Continuous; + return; + } + LOG(FATAL) << "Could not parse BorderCurve:" << stringValue; + react_native_assert(false); +} + inline void fromRawValue( const PropsParserContext &context, const RawValue &value, diff --git a/ReactCommon/react/renderer/components/view/primitives.h b/ReactCommon/react/renderer/components/view/primitives.h index 86be3728f403..9c4d35c35d2e 100644 --- a/ReactCommon/react/renderer/components/view/primitives.h +++ b/ReactCommon/react/renderer/components/view/primitives.h @@ -70,6 +70,8 @@ inline static bool operator!=(ViewEvents const &lhs, ViewEvents const &rhs) { enum class BackfaceVisibility { Auto, Visible, Hidden }; +enum class BorderCurve { Circular, Continuous }; + enum class BorderStyle { Solid, Dotted, Dashed }; template @@ -195,11 +197,13 @@ struct CascadedRectangleCorners { }; using BorderWidths = RectangleEdges; +using BorderCurves = RectangleCorners; using BorderStyles = RectangleEdges; using BorderColors = RectangleEdges; using BorderRadii = RectangleCorners; using CascadedBorderWidths = CascadedRectangleEdges; +using CascadedBorderCurves = CascadedRectangleCorners; using CascadedBorderStyles = CascadedRectangleEdges; using CascadedBorderColors = CascadedRectangleEdges; using CascadedBorderRadii = CascadedRectangleCorners; @@ -208,6 +212,7 @@ struct BorderMetrics { BorderColors borderColors{}; BorderWidths borderWidths{}; BorderRadii borderRadii{}; + BorderCurves borderCurves{}; BorderStyles borderStyles{}; bool operator==(const BorderMetrics &rhs) const { @@ -215,11 +220,13 @@ struct BorderMetrics { this->borderColors, this->borderWidths, this->borderRadii, + this->borderCurves, this->borderStyles) == std::tie( rhs.borderColors, rhs.borderWidths, rhs.borderRadii, + rhs.borderCurves, rhs.borderStyles); } From a8190667de8176cfc0eb2545b379398ab2044430 Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Sat, 21 May 2022 12:27:38 +0200 Subject: [PATCH 3/5] CornerCurveFromBorderCurve --- .../View/RCTViewComponentView.mm | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm index 89be6477215f..d9acbf3f2d33 100644 --- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm @@ -516,6 +516,16 @@ static void RCTReleaseRCTBorderColors(RCTBorderColors borderColors) CGColorRelease(borderColors.right); } +static CALayerCornerCurve CornerCurveFromBorderCurve(BorderCurve borderCurve) +{ + switch (borderCurve) { + case BorderCurve::Continuous: + return kCACornerCurveContinuous; + case BorderCurve::Circular: + return kCACornerCurveCircular; + } +} + static RCTBorderStyle RCTBorderStyleFromBorderStyle(BorderStyle borderStyle) { switch (borderStyle) { @@ -581,14 +591,7 @@ - (void)invalidateLayer CGColorRelease(borderColor); layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft; if (@available(iOS 13.0, *)) { - switch (borderMetrics.borderCurves.topLeft) { - case BorderCurve::Continuous: - layer.cornerCurve = kCACornerCurveContinuous; - break; - case BorderCurve::Circular: - layer.cornerCurve = kCACornerCurveCircular; - break; - } + layer.cornerCurve = CornerCurveFromBorderCurve(borderMetrics.borderCurves.topLeft); } layer.backgroundColor = _backgroundColor.CGColor; } else { From 8989fcae83b2f3ea5059c7189972842dd17c4334 Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Thu, 16 Jun 2022 22:09:56 +0200 Subject: [PATCH 4/5] fix border Curve typo --- ReactCommon/react/renderer/components/view/ViewProps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/react/renderer/components/view/ViewProps.cpp b/ReactCommon/react/renderer/components/view/ViewProps.cpp index 17aad2ea7622..38a36dbb86df 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.cpp +++ b/ReactCommon/react/renderer/components/view/ViewProps.cpp @@ -73,7 +73,7 @@ ViewProps::ViewProps( context, rawProps, "border", - "Curves", + "Curve", sourceProps.borderCurves, {})), borderStyles( From 1981d1a7e3d66d7e3dbbaede1ca0061d7e1e549f Mon Sep 17 00:00:00 2001 From: Eric Edouard Date: Sun, 17 Jul 2022 11:19:20 +0200 Subject: [PATCH 5/5] new line in React/Views/RCTBorderCurve.h --- React/Views/RCTBorderCurve.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/Views/RCTBorderCurve.h b/React/Views/RCTBorderCurve.h index 5cc87a3da7e6..b67637e31f50 100644 --- a/React/Views/RCTBorderCurve.h +++ b/React/Views/RCTBorderCurve.h @@ -10,4 +10,4 @@ typedef NS_ENUM(NSInteger, RCTBorderCurve) { RCTBorderCurveContinuous = 0, RCTBorderCurveCircular, -}; \ No newline at end of file +};