Add margin auto support to react native

Summary:
This diff adds margin:auto (https://drafts.csswg.org/css-flexbox-1/#auto-margins) support to React Native. This enables layout not previously supported without inserting empty 'spacer' views. See below Playground for usage.

```
class Playground extends React.Component {
  render() {
    return (
      <View style={{width: '100%', height: '100%', flexDirection: 'row', backgroundColor: 'white'}}>
        <View style={{width: 100, height: 100, backgroundColor: 'red'}}/>
        <View style={{width: 100, height: 100, marginLeft: 'auto', backgroundColor: 'blue'}}/>
      </View>
    );
  }
}
```

Reviewed By: astreet

Differential Revision: D4611753

fbshipit-source-id: e78335565c193f7fb263129a638b444715ba5ab0
This commit is contained in:
Emil Sjolander 2017-03-01 09:12:45 -08:00 committed by Facebook Github Bot
parent fb266fcaad
commit cc275557be
4 changed files with 80 additions and 18 deletions

View File

@ -507,7 +507,9 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
return (YGValue) { [json floatValue], YGUnitPoint }; return (YGValue) { [json floatValue], YGUnitPoint };
} else if ([json isKindOfClass:[NSString class]]) { } else if ([json isKindOfClass:[NSString class]]) {
NSString *s = (NSString *) json; NSString *s = (NSString *) json;
if ([s hasSuffix:@"%"]) { if ([s isEqualToString:@"auto"]) {
return (YGValue) { YGUndefined, YGUnitAuto };
} else if ([s hasSuffix:@"%"]) {
return (YGValue) { [[s substringToIndex:s.length] floatValue], YGUnitPercent }; return (YGValue) { [[s substringToIndex:s.length] floatValue], YGUnitPercent };
} else { } else {
RCTLogConvertError(json, @"a YGValue. Did you forget the % or pt suffix?"); RCTLogConvertError(json, @"a YGValue. Did you forget the % or pt suffix?");

View File

@ -70,19 +70,41 @@ switch (ygvalue.unit) { \
break; \ break; \
} }
#define DEFINE_PROCESS_META_PROPS(type) \ #define RCT_SET_YGVALUE_AUTO(ygvalue, setter, ...) \
static void RCTProcessMetaProps##type(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { \ switch (ygvalue.unit) { \
RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSet##type, node, YGEdgeStart); \ case YGUnitAuto: \
RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSet##type, node, YGEdgeEnd); \ setter##Auto(__VA_ARGS__); \
RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSet##type, node, YGEdgeTop); \ break; \
RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSet##type, node, YGEdgeBottom); \ case YGUnitUndefined: \
RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSet##type, node, YGEdgeHorizontal); \ setter(__VA_ARGS__, YGUndefined); \
RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSet##type, node, YGEdgeVertical); \ break; \
RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSet##type, node, YGEdgeAll); \ case YGUnitPoint: \
setter(__VA_ARGS__, ygvalue.value); \
break; \
case YGUnitPercent: \
setter##Percent(__VA_ARGS__, ygvalue.value); \
break; \
} }
DEFINE_PROCESS_META_PROPS(Padding); static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
DEFINE_PROCESS_META_PROPS(Margin); RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSetPadding, node, YGEdgeStart);
RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSetPadding, node, YGEdgeEnd);
RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSetPadding, node, YGEdgeTop);
RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSetPadding, node, YGEdgeBottom);
RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetPadding, node, YGEdgeHorizontal);
RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSetPadding, node, YGEdgeVertical);
RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSetPadding, node, YGEdgeAll);
}
static void RCTProcessMetaPropsMargin(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_LEFT], YGNodeStyleSetMargin, node, YGEdgeStart);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_RIGHT], YGNodeStyleSetMargin, node, YGEdgeEnd);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_TOP], YGNodeStyleSetMargin, node, YGEdgeTop);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_BOTTOM], YGNodeStyleSetMargin, node, YGEdgeBottom);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetMargin, node, YGEdgeHorizontal);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_VERTICAL], YGNodeStyleSetMargin, node, YGEdgeVertical);
RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_ALL], YGNodeStyleSetMargin, node, YGEdgeAll);
}
static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) {
YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_LEFT].value); YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_LEFT].value);
@ -522,9 +544,19 @@ RCT_BORDER_PROPERTY(Bottom, BOTTOM)
RCT_BORDER_PROPERTY(Right, RIGHT) RCT_BORDER_PROPERTY(Right, RIGHT)
// Dimensions // Dimensions
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \ #define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
- (void)set##setProp:(YGValue)value \ - (void)set##setProp:(YGValue)value \
{ \
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \
[self dirtyText]; \
} \
- (YGValue)getProp \
{ \
return YGNodeStyleGet##cssProp(_yogaNode); \
}
#define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
- (void)set##setProp:(YGValue)value \
{ \ { \
RCT_SET_YGVALUE(value, YGNodeStyleSet##cssProp, _yogaNode); \ RCT_SET_YGVALUE(value, YGNodeStyleSet##cssProp, _yogaNode); \
[self dirtyText]; \ [self dirtyText]; \
@ -536,10 +568,10 @@ RCT_BORDER_PROPERTY(Right, RIGHT)
RCT_DIMENSION_PROPERTY(Width, width, Width) RCT_DIMENSION_PROPERTY(Width, width, Width)
RCT_DIMENSION_PROPERTY(Height, height, Height) RCT_DIMENSION_PROPERTY(Height, height, Height)
RCT_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth) RCT_MIN_MAX_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth)
RCT_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight) RCT_MIN_MAX_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight)
RCT_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth) RCT_MIN_MAX_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth)
RCT_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight) RCT_MIN_MAX_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight)
// Position // Position
@ -644,7 +676,7 @@ static inline YGSize RCTShadowViewMeasure(YGNodeRef node, float width, YGMeasure
- (void)setFlexBasis:(YGValue)value - (void)setFlexBasis:(YGValue)value
{ {
RCT_SET_YGVALUE(value, YGNodeStyleSetFlexBasis, _yogaNode); RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode);
} }
- (YGValue)flexBasis - (YGValue)flexBasis

View File

@ -74,6 +74,9 @@ public class LayoutShadowNode extends ReactShadowNode {
case UNDEFINED: case UNDEFINED:
setStyleWidth(mTempYogaValue.value); setStyleWidth(mTempYogaValue.value);
break; break;
case AUTO:
setStyleWidthAuto();
break;
case PERCENT: case PERCENT:
setStyleWidthPercent(mTempYogaValue.value); setStyleWidthPercent(mTempYogaValue.value);
break; break;
@ -134,6 +137,9 @@ public class LayoutShadowNode extends ReactShadowNode {
case UNDEFINED: case UNDEFINED:
setStyleHeight(mTempYogaValue.value); setStyleHeight(mTempYogaValue.value);
break; break;
case AUTO:
setStyleHeightAuto();
break;
case PERCENT: case PERCENT:
setStyleHeightPercent(mTempYogaValue.value); setStyleHeightPercent(mTempYogaValue.value);
break; break;
@ -218,6 +224,9 @@ public class LayoutShadowNode extends ReactShadowNode {
case UNDEFINED: case UNDEFINED:
setFlexBasis(mTempYogaValue.value); setFlexBasis(mTempYogaValue.value);
break; break;
case AUTO:
setFlexBasisAuto();
break;
case PERCENT: case PERCENT:
setFlexBasisPercent(mTempYogaValue.value); setFlexBasisPercent(mTempYogaValue.value);
break; break;
@ -312,6 +321,9 @@ public class LayoutShadowNode extends ReactShadowNode {
case UNDEFINED: case UNDEFINED:
setMargin(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); setMargin(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
break; break;
case AUTO:
setMarginAuto(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]);
break;
case PERCENT: case PERCENT:
setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value);
break; break;

View File

@ -554,6 +554,10 @@ public class ReactShadowNode {
mYogaNode.setWidthPercent(percent); mYogaNode.setWidthPercent(percent);
} }
public void setStyleWidthAuto() {
mYogaNode.setWidthAuto();
}
public void setStyleMinWidth(float widthPx) { public void setStyleMinWidth(float widthPx) {
mYogaNode.setMinWidth(widthPx); mYogaNode.setMinWidth(widthPx);
} }
@ -582,6 +586,10 @@ public class ReactShadowNode {
mYogaNode.setHeightPercent(percent); mYogaNode.setHeightPercent(percent);
} }
public void setStyleHeightAuto() {
mYogaNode.setHeightAuto();
}
public void setStyleMinHeight(float widthPx) { public void setStyleMinHeight(float widthPx) {
mYogaNode.setMinHeight(widthPx); mYogaNode.setMinHeight(widthPx);
} }
@ -614,6 +622,10 @@ public class ReactShadowNode {
mYogaNode.setFlexBasis(flexBasis); mYogaNode.setFlexBasis(flexBasis);
} }
public void setFlexBasisAuto() {
mYogaNode.setFlexBasisAuto();
}
public void setFlexBasisPercent(float percent) { public void setFlexBasisPercent(float percent) {
mYogaNode.setFlexBasisPercent(percent); mYogaNode.setFlexBasisPercent(percent);
} }
@ -654,6 +666,10 @@ public class ReactShadowNode {
mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent); mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent);
} }
public void setMarginAuto(int spacingType) {
mYogaNode.setMarginAuto(YogaEdge.fromInt(spacingType));
}
public final float getPadding(int spacingType) { public final float getPadding(int spacingType) {
return mYogaNode.getLayoutPadding(YogaEdge.fromInt(spacingType)); return mYogaNode.getLayoutPadding(YogaEdge.fromInt(spacingType));
} }