iOS: Implement border(Top|Bottom)(Start|End)Radius and border(Start|End)(Color|Width) RN styles

Reviewed By: shergin

Differential Revision: D5874536

fbshipit-source-id: 5ad237bddb70745aef0341cddb172da5ee388c38
This commit is contained in:
Ramanpreet Nara 2017-10-18 19:29:42 -07:00 committed by Facebook Github Bot
parent 38b5506599
commit 1b5f8d3ee5
8 changed files with 156 additions and 14 deletions

View File

@ -40,6 +40,8 @@ ReactNativeStyleAttributes.borderColor = colorAttributes;
ReactNativeStyleAttributes.borderLeftColor = colorAttributes;
ReactNativeStyleAttributes.borderRightColor = colorAttributes;
ReactNativeStyleAttributes.borderTopColor = colorAttributes;
ReactNativeStyleAttributes.borderStartColor = colorAttributes;
ReactNativeStyleAttributes.borderEndColor = colorAttributes;
ReactNativeStyleAttributes.color = colorAttributes;
ReactNativeStyleAttributes.shadowColor = colorAttributes;
ReactNativeStyleAttributes.textDecorationColor = colorAttributes;

View File

@ -31,11 +31,17 @@ var ViewStylePropTypes = {
borderRightColor: ColorPropType,
borderBottomColor: ColorPropType,
borderLeftColor: ColorPropType,
borderStartColor: ColorPropType,
borderEndColor: ColorPropType,
borderRadius: ReactPropTypes.number,
borderTopLeftRadius: ReactPropTypes.number,
borderTopRightRadius: ReactPropTypes.number,
borderTopStartRadius: ReactPropTypes.number,
borderTopEndRadius: ReactPropTypes.number,
borderBottomLeftRadius: ReactPropTypes.number,
borderBottomRightRadius: ReactPropTypes.number,
borderBottomStartRadius: ReactPropTypes.number,
borderBottomEndRadius: ReactPropTypes.number,
borderStyle: ReactPropTypes.oneOf(['solid', 'dotted', 'dashed']),
borderWidth: ReactPropTypes.number,
borderTopWidth: ReactPropTypes.number,

View File

@ -325,6 +325,18 @@ var LayoutPropTypes = {
*/
borderTopWidth: ReactPropTypes.number,
/**
* When direction is `ltr`, `borderStartWidth` is equivalent to `borderLeftWidth`.
* When direction is `rtl`, `borderStartWidth` is equivalent to `borderRightWidth`.
*/
borderStartWidth: ReactPropTypes.number,
/**
* When direction is `ltr`, `borderEndWidth` is equivalent to `borderRightWidth`.
* When direction is `rtl`, `borderEndWidth` is equivalent to `borderLeftWidth`.
*/
borderEndWidth: ReactPropTypes.number,
/** `borderRightWidth` works like `border-right-width` in CSS.
* See https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-width
* for more details.

View File

@ -122,6 +122,8 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
@property (nonatomic, assign) float borderLeftWidth;
@property (nonatomic, assign) float borderBottomWidth;
@property (nonatomic, assign) float borderRightWidth;
@property (nonatomic, assign) float borderStartWidth;
@property (nonatomic, assign) float borderEndWidth;
/**
* Margin. Defaults to { 0, 0, 0, 0 }.

View File

@ -26,6 +26,8 @@ typedef NS_ENUM(unsigned int, meta_prop_t) {
META_PROP_TOP,
META_PROP_RIGHT,
META_PROP_BOTTOM,
META_PROP_START,
META_PROP_END,
META_PROP_HORIZONTAL,
META_PROP_VERTICAL,
META_PROP_ALL,
@ -121,8 +123,17 @@ static void RCTProcessMetaPropsMargin(const YGValue metaProps[META_PROP_COUNT],
}
static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_LEFT].value);
YGNodeStyleSetBorder(node, YGEdgeEnd, metaProps[META_PROP_RIGHT].value);
if (![[RCTI18nUtil sharedInstance] doesRTLFlipLeftAndRightStyles]) {
YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_START].value);
YGNodeStyleSetBorder(node, YGEdgeEnd, metaProps[META_PROP_END].value);
YGNodeStyleSetBorder(node, YGEdgeLeft, metaProps[META_PROP_LEFT].value);
YGNodeStyleSetBorder(node, YGEdgeRight, metaProps[META_PROP_RIGHT].value);
} else {
const float start = YGFloatIsUndefined(metaProps[META_PROP_START].value) ? metaProps[META_PROP_LEFT].value : metaProps[META_PROP_START].value;
const float end = YGFloatIsUndefined(metaProps[META_PROP_END].value) ? metaProps[META_PROP_RIGHT].value : metaProps[META_PROP_END].value;
YGNodeStyleSetBorder(node, YGEdgeStart, start);
YGNodeStyleSetBorder(node, YGEdgeEnd, end);
}
YGNodeStyleSetBorder(node, YGEdgeTop, metaProps[META_PROP_TOP].value);
YGNodeStyleSetBorder(node, YGEdgeBottom, metaProps[META_PROP_BOTTOM].value);
YGNodeStyleSetBorder(node, YGEdgeHorizontal, metaProps[META_PROP_HORIZONTAL].value);
@ -557,6 +568,8 @@ RCT_BORDER_PROPERTY(Top, TOP)
RCT_BORDER_PROPERTY(Left, LEFT)
RCT_BORDER_PROPERTY(Bottom, BOTTOM)
RCT_BORDER_PROPERTY(Right, RIGHT)
RCT_BORDER_PROPERTY(Start, START)
RCT_BORDER_PROPERTY(End, END)
// Dimensions
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \

View File

@ -70,8 +70,12 @@
@property (nonatomic, assign) CGFloat borderRadius;
@property (nonatomic, assign) CGFloat borderTopLeftRadius;
@property (nonatomic, assign) CGFloat borderTopRightRadius;
@property (nonatomic, assign) CGFloat borderTopStartRadius;
@property (nonatomic, assign) CGFloat borderTopEndRadius;
@property (nonatomic, assign) CGFloat borderBottomLeftRadius;
@property (nonatomic, assign) CGFloat borderBottomRightRadius;
@property (nonatomic, assign) CGFloat borderBottomStartRadius;
@property (nonatomic, assign) CGFloat borderBottomEndRadius;
/**
* Border colors (actually retained).
@ -80,6 +84,8 @@
@property (nonatomic, assign) CGColorRef borderRightColor;
@property (nonatomic, assign) CGColorRef borderBottomColor;
@property (nonatomic, assign) CGColorRef borderLeftColor;
@property (nonatomic, assign) CGColorRef borderStartColor;
@property (nonatomic, assign) CGColorRef borderEndColor;
@property (nonatomic, assign) CGColorRef borderColor;
/**
@ -89,6 +95,8 @@
@property (nonatomic, assign) CGFloat borderRightWidth;
@property (nonatomic, assign) CGFloat borderBottomWidth;
@property (nonatomic, assign) CGFloat borderLeftWidth;
@property (nonatomic, assign) CGFloat borderStartWidth;
@property (nonatomic, assign) CGFloat borderEndWidth;
@property (nonatomic, assign) CGFloat borderWidth;
/**

View File

@ -15,6 +15,7 @@
#import "RCTLog.h"
#import "RCTUtils.h"
#import "UIView+React.h"
#import "RCTI18nUtil.h"
@implementation UIView (RCTViewUnmounting)
@ -110,10 +111,16 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
_borderRightWidth = -1;
_borderBottomWidth = -1;
_borderLeftWidth = -1;
_borderStartWidth = -1;
_borderEndWidth = -1;
_borderTopLeftRadius = -1;
_borderTopRightRadius = -1;
_borderTopStartRadius = -1;
_borderTopEndRadius = -1;
_borderBottomLeftRadius = -1;
_borderBottomRightRadius = -1;
_borderBottomStartRadius = -1;
_borderBottomEndRadius = -1;
_borderStyle = RCTBorderStyleSolid;
_hitTestEdgeInsets = UIEdgeInsetsZero;
@ -127,7 +134,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused)
- (void)setReactLayoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection
{
_reactLayoutDirection = layoutDirection;
if (_reactLayoutDirection != layoutDirection) {
_reactLayoutDirection = layoutDirection;
[self.layer setNeedsDisplay];
}
if ([self respondsToSelector:@selector(setSemanticContentAttribute:)]) {
self.semanticContentAttribute =
@ -424,26 +434,77 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused)
[self.layer setNeedsDisplay];
}
static CGFloat RCTDefaultIfNegativeTo(CGFloat defaultValue, CGFloat x) {
return x >= 0 ? x : defaultValue;
};
- (UIEdgeInsets)bordersAsInsets
{
const CGFloat borderWidth = MAX(0, _borderWidth);
const BOOL isRTL = _reactLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
if ([[RCTI18nUtil sharedInstance] doesRTLFlipLeftAndRightStyles]) {
const CGFloat borderStartWidth = RCTDefaultIfNegativeTo(_borderLeftWidth, _borderStartWidth);
const CGFloat borderEndWidth = RCTDefaultIfNegativeTo(_borderRightWidth, _borderEndWidth);
const CGFloat directionAwareBorderLeftWidth = isRTL ? borderEndWidth : borderStartWidth;
const CGFloat directionAwareBorderRightWidth = isRTL ? borderStartWidth : borderEndWidth;
return (UIEdgeInsets) {
RCTDefaultIfNegativeTo(borderWidth, _borderTopWidth),
RCTDefaultIfNegativeTo(borderWidth, directionAwareBorderLeftWidth),
RCTDefaultIfNegativeTo(borderWidth, _borderBottomWidth),
RCTDefaultIfNegativeTo(borderWidth, directionAwareBorderRightWidth),
};
}
const CGFloat directionAwareBorderLeftWidth = isRTL ? _borderEndWidth : _borderStartWidth;
const CGFloat directionAwareBorderRightWidth = isRTL ? _borderStartWidth : _borderEndWidth;
return (UIEdgeInsets) {
_borderTopWidth >= 0 ? _borderTopWidth : borderWidth,
_borderLeftWidth >= 0 ? _borderLeftWidth : borderWidth,
_borderBottomWidth >= 0 ? _borderBottomWidth : borderWidth,
_borderRightWidth >= 0 ? _borderRightWidth : borderWidth,
RCTDefaultIfNegativeTo(borderWidth, _borderTopWidth),
RCTDefaultIfNegativeTo(borderWidth, RCTDefaultIfNegativeTo(_borderLeftWidth, directionAwareBorderLeftWidth)),
RCTDefaultIfNegativeTo(borderWidth, _borderBottomWidth),
RCTDefaultIfNegativeTo(borderWidth, RCTDefaultIfNegativeTo(_borderRightWidth, directionAwareBorderRightWidth)),
};
}
- (RCTCornerRadii)cornerRadii
{
// Get corner radii
const BOOL isRTL = _reactLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
const CGFloat radius = MAX(0, _borderRadius);
const CGFloat topLeftRadius = _borderTopLeftRadius >= 0 ? _borderTopLeftRadius : radius;
const CGFloat topRightRadius = _borderTopRightRadius >= 0 ? _borderTopRightRadius : radius;
const CGFloat bottomLeftRadius = _borderBottomLeftRadius >= 0 ? _borderBottomLeftRadius : radius;
const CGFloat bottomRightRadius = _borderBottomRightRadius >= 0 ? _borderBottomRightRadius : radius;
CGFloat topLeftRadius;
CGFloat topRightRadius;
CGFloat bottomLeftRadius;
CGFloat bottomRightRadius;
if ([[RCTI18nUtil sharedInstance] doesRTLFlipLeftAndRightStyles]) {
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 directionAwareTopLeftRadius = isRTL ? topEndRadius : topStartRadius;
const CGFloat directionAwareTopRightRadius = isRTL ? topStartRadius : topEndRadius;
const CGFloat directionAwareBottomLeftRadius = isRTL ? bottomEndRadius : bottomStartRadius;
const CGFloat directionAwareBottomRightRadius = isRTL ? bottomStartRadius : bottomEndRadius;
topLeftRadius = RCTDefaultIfNegativeTo(radius, directionAwareTopLeftRadius);
topRightRadius = RCTDefaultIfNegativeTo(radius, directionAwareTopRightRadius);
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;
topLeftRadius = RCTDefaultIfNegativeTo(radius, RCTDefaultIfNegativeTo(_borderTopLeftRadius, directionAwareTopLeftRadius));
topRightRadius = RCTDefaultIfNegativeTo(radius, RCTDefaultIfNegativeTo(_borderTopRightRadius, directionAwareTopRightRadius));
bottomLeftRadius = RCTDefaultIfNegativeTo(radius, RCTDefaultIfNegativeTo(_borderBottomLeftRadius, directionAwareBottomLeftRadius));
bottomRightRadius = RCTDefaultIfNegativeTo(radius, RCTDefaultIfNegativeTo(_borderBottomRightRadius, directionAwareBottomRightRadius));
}
// Get scale factors required to prevent radii from overlapping
const CGSize size = self.bounds.size;
@ -463,11 +524,31 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused)
- (RCTBorderColors)borderColors
{
const BOOL isRTL = _reactLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
if ([[RCTI18nUtil sharedInstance] doesRTLFlipLeftAndRightStyles]) {
const CGColorRef borderStartColor = _borderStartColor ?: _borderLeftColor;
const CGColorRef borderEndColor = _borderEndColor ?: _borderRightColor;
const CGColorRef directionAwareBorderLeftColor = isRTL ? borderEndColor : borderStartColor;
const CGColorRef directionAwareBorderRightColor = isRTL ? borderStartColor : borderEndColor;
return (RCTBorderColors){
_borderTopColor ?: _borderColor,
directionAwareBorderLeftColor ?: _borderColor,
_borderBottomColor ?: _borderColor,
directionAwareBorderRightColor ?: _borderColor,
};
}
const CGColorRef directionAwareBorderLeftColor = isRTL ? _borderEndColor : _borderStartColor;
const CGColorRef directionAwareBorderRightColor = isRTL ? _borderStartColor : _borderEndColor;
return (RCTBorderColors){
_borderTopColor ?: _borderColor,
_borderLeftColor ?: _borderColor,
directionAwareBorderLeftColor ?: _borderLeftColor ?: _borderColor,
_borderBottomColor ?: _borderColor,
_borderRightColor ?: _borderColor,
directionAwareBorderRightColor ?: _borderRightColor ?: _borderColor,
};
}
@ -656,6 +737,8 @@ setBorderColor(Top)
setBorderColor(Right)
setBorderColor(Bottom)
setBorderColor(Left)
setBorderColor(Start)
setBorderColor(End)
#pragma mark - Border Width
@ -674,6 +757,8 @@ setBorderWidth(Top)
setBorderWidth(Right)
setBorderWidth(Bottom)
setBorderWidth(Left)
setBorderWidth(Start)
setBorderWidth(End)
#pragma mark - Border Radius
@ -690,8 +775,12 @@ setBorderWidth(Left)
setBorderRadius()
setBorderRadius(TopLeft)
setBorderRadius(TopRight)
setBorderRadius(TopStart)
setBorderRadius(TopEnd)
setBorderRadius(BottomLeft)
setBorderRadius(BottomRight)
setBorderRadius(BottomStart)
setBorderRadius(BottomEnd)
#pragma mark - Border Style
@ -714,6 +803,8 @@ setBorderStyle()
CGColorRelease(_borderRightColor);
CGColorRelease(_borderBottomColor);
CGColorRelease(_borderLeftColor);
CGColorRelease(_borderStartColor);
CGColorRelease(_borderEndColor);
}
@end

View File

@ -246,6 +246,8 @@ RCT_VIEW_BORDER_PROPERTY(Top)
RCT_VIEW_BORDER_PROPERTY(Right)
RCT_VIEW_BORDER_PROPERTY(Bottom)
RCT_VIEW_BORDER_PROPERTY(Left)
RCT_VIEW_BORDER_PROPERTY(Start)
RCT_VIEW_BORDER_PROPERTY(End)
#define RCT_VIEW_BORDER_RADIUS_PROPERTY(SIDE) \
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Radius, CGFloat, RCTView) \
@ -257,8 +259,12 @@ RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Radius, CGFloat, RCTView) \
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopLeft)
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopRight)
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopStart)
RCT_VIEW_BORDER_RADIUS_PROPERTY(TopEnd)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomLeft)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomRight)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomStart)
RCT_VIEW_BORDER_RADIUS_PROPERTY(BottomEnd)
RCT_REMAP_VIEW_PROPERTY(display, reactDisplay, YGDisplay)
RCT_REMAP_VIEW_PROPERTY(zIndex, reactZIndex, NSInteger)
@ -286,6 +292,8 @@ RCT_EXPORT_SHADOW_PROPERTY(borderTopWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderRightWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderBottomWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderLeftWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderStartWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderEndWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(borderWidth, float)
RCT_EXPORT_SHADOW_PROPERTY(marginTop, YGValue)