Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: flex gap bindings #34974

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Libraries/Components/View/ReactNativeStyleAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
borderRightWidth: true,
borderStartWidth: true,
borderTopWidth: true,
columnGap: true,
borderWidth: true,
bottom: true,
direction: true,
Expand All @@ -43,6 +44,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
flexGrow: true,
flexShrink: true,
flexWrap: true,
gap: true,
height: true,
justifyContent: true,
left: true,
Expand Down Expand Up @@ -71,6 +73,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
paddingVertical: true,
position: true,
right: true,
rowGap: true,
start: true,
top: true,
width: true,
Expand Down
3 changes: 3 additions & 0 deletions Libraries/NativeComponent/BaseViewConfig.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ const validAttributesForNonEventProps = {
maxHeight: true,
flex: true,
flexGrow: true,
rowGap: true,
columnGap: true,
gap: true,
flexShrink: true,
flexBasis: true,
aspectRatio: true,
Expand Down
3 changes: 3 additions & 0 deletions Libraries/NativeComponent/BaseViewConfig.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ const validAttributesForNonEventProps = {

flex: true,
flexGrow: true,
rowGap: true,
columnGap: true,
gap: true,
flexShrink: true,
flexBasis: true,
flexDirection: true,
Expand Down
3 changes: 3 additions & 0 deletions Libraries/StyleSheet/StyleSheetTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export interface FlexStyle {
| 'row-reverse'
| 'column-reverse'
| undefined;
rowGap?: number | undefined;
gap?: number | undefined;
columnGap?: number | undefined;
flexGrow?: number | undefined;
flexShrink?: number | undefined;
flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse' | undefined;
Expand Down
13 changes: 13 additions & 0 deletions Libraries/StyleSheet/StyleSheetTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,19 @@ export type ____ShadowStyle_InternalCore = $ReadOnly<{
* @platform ios
*/
shadowRadius?: number,

/**
intergalacticspacehighway marked this conversation as resolved.
Show resolved Hide resolved
* In React Native, gap works the same way it does in CSS.
* If there are two or more children in a container, they will be separated from each other
* by the value of the gap - but the children will not be separated from the edges of their parent container.
* For horizontal gaps, use columnGap, for vertical gaps, use rowGap, and to apply both at the same time, it's gap.
* When align-content or justify-content are set to space-between or space-around, the separation
* between children may be larger than the gap value.
* See https://developer.mozilla.org/en-US/docs/Web/CSS/gap for more details.
*/
rowGap?: number,
columnGap?: number,
gap?: number,
}>;

export type ____ShadowStyle_Internal = $ReadOnly<{
Expand Down
3 changes: 3 additions & 0 deletions Libraries/StyleSheet/splitLayoutProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ export default function splitLayoutProps(props: ?____ViewStyle_Internal): {
case 'bottom':
case 'top':
case 'transform':
case 'rowGap':
case 'columnGap':
case 'gap':
// $FlowFixMe[cannot-write]
// $FlowFixMe[incompatible-use]
// $FlowFixMe[prop-missing]
Expand Down
3 changes: 3 additions & 0 deletions React/Views/RCTShadowView.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry

@property (nonatomic, assign) float flex;
@property (nonatomic, assign) float flexGrow;
@property (nonatomic, assign) float rowGap;
@property (nonatomic, assign) float columnGap;
@property (nonatomic, assign) float gap;
@property (nonatomic, assign) float flexShrink;
@property (nonatomic, assign) YGValue flexBasis;

Expand Down
14 changes: 14 additions & 0 deletions React/Views/RCTShadowView.m
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,20 @@ - (YGValue)flexBasis
return YGNodeStyleGetFlexBasis(_yogaNode);
}

#define RCT_GAP_PROPERTY(setProp, getProp, cssProp, type, gap) \
-(void)set##setProp : (type)value \
{ \
YGNodeStyleSet##cssProp(_yogaNode, gap, value); \
} \
-(type)getProp \
{ \
return YGNodeStyleGet##cssProp(_yogaNode, gap); \
}

RCT_GAP_PROPERTY(RowGap, rowGap, Gap, float, YGGutterRow);
RCT_GAP_PROPERTY(ColumnGap, columnGap, Gap, float, YGGutterColumn);
RCT_GAP_PROPERTY(Gap, gap, Gap, float, YGGutterAll);

#define RCT_STYLE_PROPERTY(setProp, getProp, cssProp, type) \
-(void)set##setProp : (type)value \
{ \
Expand Down
3 changes: 3 additions & 0 deletions React/Views/RCTViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ - (RCTShadowView *)shadowView
RCT_EXPORT_SHADOW_PROPERTY(alignContent, YGAlign)
RCT_EXPORT_SHADOW_PROPERTY(position, YGPositionType)
RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float)
RCT_EXPORT_SHADOW_PROPERTY(rowGap, float)
RCT_EXPORT_SHADOW_PROPERTY(columnGap, float)
RCT_EXPORT_SHADOW_PROPERTY(gap, float)

RCT_EXPORT_SHADOW_PROPERTY(overflow, YGOverflow)
RCT_EXPORT_SHADOW_PROPERTY(display, YGDisplay)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,30 @@ public void setFlexGrow(float flexGrow) {
super.setFlexGrow(flexGrow);
}

@ReactProp(name = ViewProps.ROW_GAP, defaultFloat = YogaConstants.UNDEFINED)
public void setRowGap(float rowGap) {
if (isVirtual()) {
return;
}
super.setRowGap(PixelUtil.toPixelFromDIP(rowGap));
}

@ReactProp(name = ViewProps.COLUMN_GAP, defaultFloat = YogaConstants.UNDEFINED)
public void setColumnGap(float columnGap) {
if (isVirtual()) {
return;
}
super.setColumnGap(PixelUtil.toPixelFromDIP(columnGap));
}

@ReactProp(name = ViewProps.GAP, defaultFloat = YogaConstants.UNDEFINED)
public void setGap(float gap) {
if (isVirtual()) {
return;
}
super.setGap(PixelUtil.toPixelFromDIP(gap));
}

@ReactProp(name = ViewProps.FLEX_SHRINK, defaultFloat = 0f)
public void setFlexShrink(float flexShrink) {
if (isVirtual()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ public interface ReactShadowNode<T extends ReactShadowNode> {

void setFlexGrow(float flexGrow);

void setRowGap(float rowGap);

void setColumnGap(float columnGap);

void setGap(float gap);

void setFlexShrink(float flexShrink);

void setFlexBasis(float flexBasis);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.facebook.yoga.YogaDisplay;
import com.facebook.yoga.YogaEdge;
import com.facebook.yoga.YogaFlexDirection;
import com.facebook.yoga.YogaGutter;
import com.facebook.yoga.YogaJustify;
import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaNode;
Expand Down Expand Up @@ -794,6 +795,21 @@ public void setFlexGrow(float flexGrow) {
mYogaNode.setFlexGrow(flexGrow);
}

@Override
public void setRowGap(float rowGap) {
mYogaNode.setGap(YogaGutter.ROW, rowGap);
}

@Override
public void setColumnGap(float columnGap) {
mYogaNode.setGap(YogaGutter.COLUMN, columnGap);
}

@Override
public void setGap(float gap) {
mYogaNode.setGap(YogaGutter.ALL, gap);
}

@Override
public void setFlexShrink(float flexShrink) {
mYogaNode.setFlexShrink(flexShrink);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public class ViewProps {
public static final String FLEX_BASIS = "flexBasis";
public static final String FLEX_DIRECTION = "flexDirection";
public static final String FLEX_WRAP = "flexWrap";
public static final String ROW_GAP = "rowGap";
public static final String COLUMN_GAP = "columnGap";
public static final String GAP = "gap";
public static final String HEIGHT = "height";
public static final String JUSTIFY_CONTENT = "justifyContent";
public static final String LEFT = "left";
Expand Down Expand Up @@ -203,6 +206,9 @@ public class ViewProps {
FLEX_BASIS,
FLEX_DIRECTION,
FLEX_GROW,
ROW_GAP,
COLUMN_GAP,
GAP,
FLEX_SHRINK,
FLEX_WRAP,
JUSTIFY_CONTENT,
Expand Down
13 changes: 13 additions & 0 deletions ReactCommon/react/renderer/components/view/YogaStylableProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ static inline T const getFieldValue(
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGDimensionWidth, widthStr); \
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGDimensionHeight, heightStr);

#define REBUILD_FIELD_YG_GUTTER(field, rowGapStr, columnGapStr, gapStr) \
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGGutterRow, rowGapStr); \
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGGutterColumn, columnGapStr); \
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED(field, YGGutterAll, gapStr); \


#define REBUILD_FIELD_YG_EDGES(field, prefix, suffix) \
REBUILD_YG_FIELD_SWITCH_CASE_INDEXED( \
field, YGEdgeLeft, prefix "Left" suffix); \
Expand Down Expand Up @@ -114,6 +120,7 @@ void YogaStylableProps::setProp(
REBUILD_FIELD_SWITCH_CASE_YSP(flexShrink);
REBUILD_FIELD_SWITCH_CASE_YSP(flexBasis);
REBUILD_FIELD_SWITCH_CASE2(positionType, "position");
REBUILD_FIELD_YG_GUTTER(gap, "rowGap", "columnGap", "gap");
REBUILD_FIELD_SWITCH_CASE_YSP(aspectRatio);
REBUILD_FIELD_YG_DIMENSION(dimensions, "width", "height");
REBUILD_FIELD_YG_DIMENSION(minDimensions, "minWidth", "minHeight");
Expand Down Expand Up @@ -163,6 +170,12 @@ SharedDebugStringConvertibleList YogaStylableProps::getDebugProps() const {
"flex", yogaStyle.flex(), defaultYogaStyle.flex()),
debugStringConvertibleItem(
"flexGrow", yogaStyle.flexGrow(), defaultYogaStyle.flexGrow()),
debugStringConvertibleItem(
"rowGap", yogaStyle.gap()[YGGutterRow], defaultYogaStyle.gap()[YGGutterRow]),
debugStringConvertibleItem(
"columnGap", yogaStyle.gap()[YGGutterColumn], defaultYogaStyle.gap()[YGGutterColumn]),
debugStringConvertibleItem(
"gap", yogaStyle.gap()[YGGutterAll], defaultYogaStyle.gap()[YGGutterAll]),
debugStringConvertibleItem(
"flexShrink", yogaStyle.flexShrink(), defaultYogaStyle.flexShrink()),
debugStringConvertibleItem(
Expand Down
7 changes: 7 additions & 0 deletions ReactCommon/react/renderer/components/view/propsConversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ static inline YGStyle convertRawProp(
"",
sourceValue.padding(),
yogaStyle.padding());

yogaStyle.gap()[YGGutterRow] = convertRawProp(context, rawProps, "rowGap", sourceValue.gap()[YGGutterRow], yogaStyle.gap()[YGGutterRow]);

yogaStyle.gap()[YGGutterColumn] = convertRawProp(context, rawProps, "columnGap", sourceValue.gap()[YGGutterColumn], yogaStyle.gap()[YGGutterColumn]);

yogaStyle.gap()[YGGutterAll] = convertRawProp(context, rawProps, "gap", sourceValue.gap()[YGGutterAll], yogaStyle.gap()[YGGutterAll]);

yogaStyle.border() = convertRawProp(
context,
rawProps,
Expand Down
1 change: 1 addition & 0 deletions ReactCommon/react/test_utils/shadowTreeGeneration.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ static inline ShadowNode::Unshared messWithYogaStyles(
"marginRight", "marginBottom", "paddingLeft", "paddingTop",
"paddingRight", "paddingBottom", "width", "height",
"maxWidth", "maxHeight", "minWidth", "minHeight",
"rowGap", "columnGap", "gap",
};

for (auto const &property : properties) {
Expand Down
40 changes: 40 additions & 0 deletions packages/rn-tester/js/examples/View/ViewExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,40 @@ class DisplayNoneStyle extends React.Component<
this.setState({index: this.state.index + 1});
};
}

class FlexGapExample extends React.Component<$ReadOnly<{||}>> {
render(): React.Node {
return (
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
borderWidth: 1,
rowGap: 20,
columnGap: 30,
}}>
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View
style={{
backgroundColor: 'pink',
height: 30,
flexBasis: 30,
}}
/>
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View style={{backgroundColor: 'black', height: 30, width: 30}} />
<View style={{backgroundColor: 'pink', height: 30, width: 30}} />
<View style={{backgroundColor: 'pink', height: 30, width: 30}} />
<View style={{backgroundColor: 'pink', height: 30, width: 30}} />
<View style={{backgroundColor: 'pink', height: 30, width: 30}} />
</View>
);
}
}

exports.title = 'View';
exports.documentationURL = 'https://reactnative.dev/docs/view';
exports.category = 'Basic';
Expand Down Expand Up @@ -612,4 +646,10 @@ exports.examples = [
);
},
},
{
title: 'FlexGap',
render(): React.Node {
return <FlexGapExample />;
},
},
];