From 9669c10afceef65626c82149210afc07d47df98b Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Wed, 21 Dec 2022 20:07:35 -0800 Subject: [PATCH] feat: Add Fabric implementation of inset logical properties (#35692) Summary: This PR implements `inset` logical properties as requested on https://github.com/facebook/react-native/issues/34425. This implementation includes the addition of the following style properties - `inset`, equivalent to `top`, `bottom`, `right` and `left`. - `insetBlock`, equivalent to `top` and `bottom`. - `insetBlockEnd`, equivalent to `bottom`. - `insetBlockStart`, equivalent to `top`. - `insetInline`, equivalent to `right` and `left`. - `insetInlineEnd`, equivalent to `right` or `left`. - `insetInlineStart`, equivalent to `right` or `left`. ## Changelog [GENERAL] [ADDED] - Add Fabric implementation of inset logical properties Pull Request resolved: https://github.com/facebook/react-native/pull/35692 Test Plan: 1. Open the RNTester app and navigate to the `View` page 2. Test the new style properties through the `Insets` section
Android iOS
1 2
Reviewed By: NickGerleman Differential Revision: D42193661 Pulled By: ryancat fbshipit-source-id: 3db8bcd2c4db0ef4886b9ec49a46424d57362620 --- .../View/ReactNativeStyleAttributes.js | 7 ++ .../NativeComponent/BaseViewConfig.android.js | 8 ++ .../NativeComponent/BaseViewConfig.ios.js | 8 ++ Libraries/StyleSheet/StyleSheetTypes.d.ts | 7 ++ Libraries/StyleSheet/StyleSheetTypes.js | 16 ++++ .../view/YogaLayoutableShadowNode.cpp | 21 +++++ .../components/view/YogaStylableProps.cpp | 55 ++++++++++++ .../components/view/YogaStylableProps.h | 9 ++ .../rn-tester/js/examples/View/ViewExample.js | 86 +++++++++++++++++++ 9 files changed, 217 insertions(+) diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 06f1d6df54ef6f..8b93bb79072e60 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -46,6 +46,13 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { flexWrap: true, gap: true, height: true, + inset: true, + insetBlock: true, + insetBlockEnd: true, + insetBlockStart: true, + insetInline: true, + insetInlineEnd: true, + insetInlineStart: true, justifyContent: true, left: true, margin: true, diff --git a/Libraries/NativeComponent/BaseViewConfig.android.js b/Libraries/NativeComponent/BaseViewConfig.android.js index b394cf551bd6be..b25e9ed0dce6b0 100644 --- a/Libraries/NativeComponent/BaseViewConfig.android.js +++ b/Libraries/NativeComponent/BaseViewConfig.android.js @@ -258,6 +258,14 @@ const validAttributesForNonEventProps = { top: true, bottom: true, + inset: true, + insetBlock: true, + insetBlockEnd: true, + insetBlockStart: true, + insetInline: true, + insetInlineEnd: true, + insetInlineStart: true, + position: true, style: ReactNativeStyleAttributes, diff --git a/Libraries/NativeComponent/BaseViewConfig.ios.js b/Libraries/NativeComponent/BaseViewConfig.ios.js index 8d371596dba5d6..52897e611d5fd5 100644 --- a/Libraries/NativeComponent/BaseViewConfig.ios.js +++ b/Libraries/NativeComponent/BaseViewConfig.ios.js @@ -232,6 +232,14 @@ const validAttributesForNonEventProps = { bottom: true, left: true, + inset: true, + insetBlock: true, + insetBlockEnd: true, + insetBlockStart: true, + insetInline: true, + insetInlineEnd: true, + insetInlineStart: true, + width: true, height: true, diff --git a/Libraries/StyleSheet/StyleSheetTypes.d.ts b/Libraries/StyleSheet/StyleSheetTypes.d.ts index 427265e580885a..4a77bada47948f 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -59,6 +59,13 @@ export interface FlexStyle { flexShrink?: number | undefined; flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse' | undefined; height?: number | string | undefined; + inset?: number | string | undefined; + insetBlock?: number | string | undefined; + insetBlockEnd?: number | string | undefined; + insetBlockStart?: number | string | undefined; + insetInline?: number | string | undefined; + insetInlineEnd?: number | string | undefined; + insetInlineStart?: number | string | undefined; justifyContent?: | 'flex-start' | 'flex-end' diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index d2f18a74024cc9..34ba38b3804a9c 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -132,6 +132,22 @@ type ____LayoutStyle_Internal = $ReadOnly<{ */ top?: DimensionValue, + /** `inset` is a shorthand that corresponds to the top, right, bottom, and/or left properties. + * + * It works similarly to `inset` in CSS, but in React Native you + * must use points or percentages. Ems and other units are not supported. + * + * See https://developer.mozilla.org/en-US/docs/Web/CSS/inset + * for more details of how `inset` affects layout. + */ + inset?: DimensionValue, + insetBlock?: DimensionValue, + insetBlockEnd?: DimensionValue, + insetBlockStart?: DimensionValue, + insetInline?: DimensionValue, + insetInlineEnd?: DimensionValue, + insetInlineStart?: DimensionValue, + /** `minWidth` is the minimum width for this component, in logical pixels. * * It works similarly to `min-width` in CSS, but in React Native you diff --git a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp index 4bc5bac4a971b0..93c3b543f10b5a 100644 --- a/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp @@ -333,6 +333,21 @@ void YogaLayoutableShadowNode::updateYogaProps() { YGStyle result{baseStyle}; // Aliases with precedence + if (!props.inset.isUndefined()) { + result.position()[YGEdgeAll] = props.inset; + } + if (!props.insetBlock.isUndefined()) { + result.position()[YGEdgeVertical] = props.insetBlock; + } + if (!props.insetInline.isUndefined()) { + result.position()[YGEdgeHorizontal] = props.insetInline; + } + if (!props.insetInlineEnd.isUndefined()) { + result.position()[YGEdgeEnd] = props.insetInlineEnd; + } + if (!props.insetInlineStart.isUndefined()) { + result.position()[YGEdgeStart] = props.insetInlineStart; + } if (!props.marginInline.isUndefined()) { result.margin()[YGEdgeHorizontal] = props.marginInline; } @@ -359,6 +374,12 @@ void YogaLayoutableShadowNode::updateYogaProps() { } // Aliases without precedence + if (CompactValue(result.position()[YGEdgeBottom]).isUndefined()) { + result.position()[YGEdgeBottom] = props.insetBlockEnd; + } + if (CompactValue(result.position()[YGEdgeTop]).isUndefined()) { + result.position()[YGEdgeTop] = props.insetBlockStart; + } if (CompactValue(result.margin()[YGEdgeTop]).isUndefined()) { result.margin()[YGEdgeTop] = props.marginBlockStart; } diff --git a/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp b/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp index 614da3b2fbef88..17e342dd6ee14c 100644 --- a/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp +++ b/ReactCommon/react/renderer/components/view/YogaStylableProps.cpp @@ -134,6 +134,19 @@ void YogaStylableProps::setProp( REBUILD_FIELD_YG_EDGES(border, "border", "Width"); // Aliases + RAW_SET_PROP_SWITCH_CASE(inset, "inset", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetBlock, "insetBlock", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetBlockEnd, "insetBlockEnd", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetBlockStart, "insetBlockStart", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetInline, "insetInline", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetInlineEnd, "insetInlineEnd", CompactValue::ofUndefined()); + RAW_SET_PROP_SWITCH_CASE( + insetInlineStart, "insetInlineStart", CompactValue::ofUndefined()); RAW_SET_PROP_SWITCH_CASE( marginInline, "marginInline", CompactValue::ofUndefined()); RAW_SET_PROP_SWITCH_CASE( @@ -245,6 +258,48 @@ void YogaStylableProps::convertRawPropAliases( const PropsParserContext &context, YogaStylableProps const &sourceProps, RawProps const &rawProps) { + inset = convertRawProp( + context, + rawProps, + "inset", + sourceProps.inset, + CompactValue::ofUndefined()); + insetBlock = convertRawProp( + context, + rawProps, + "insetBlock", + sourceProps.insetBlock, + CompactValue::ofUndefined()); + insetBlockEnd = convertRawProp( + context, + rawProps, + "insetBlockEnd", + sourceProps.insetBlockEnd, + CompactValue::ofUndefined()); + insetBlockStart = convertRawProp( + context, + rawProps, + "insetBlockStart", + sourceProps.insetBlockStart, + CompactValue::ofUndefined()); + insetInline = convertRawProp( + context, + rawProps, + "insetInline", + sourceProps.insetInline, + CompactValue::ofUndefined()); + insetInlineEnd = convertRawProp( + context, + rawProps, + "insetInlineEnd", + sourceProps.insetInlineEnd, + CompactValue::ofUndefined()); + insetInlineStart = convertRawProp( + context, + rawProps, + "insetInlineStart", + sourceProps.insetInlineStart, + CompactValue::ofUndefined()); marginInline = convertRawProp( context, rawProps, diff --git a/ReactCommon/react/renderer/components/view/YogaStylableProps.h b/ReactCommon/react/renderer/components/view/YogaStylableProps.h index 8891436cdb0364..4a25898f70d80c 100644 --- a/ReactCommon/react/renderer/components/view/YogaStylableProps.h +++ b/ReactCommon/react/renderer/components/view/YogaStylableProps.h @@ -43,6 +43,11 @@ class YogaStylableProps : public Props { // Duplicates of existing properties with different names, taking // precendence. E.g. "marginBlock" instead of "marginVertical" + CompactValue inset; + CompactValue insetInline; + CompactValue insetInlineEnd; + CompactValue insetInlineStart; + CompactValue marginInline; CompactValue marginInlineStart; CompactValue marginInlineEnd; @@ -56,6 +61,10 @@ class YogaStylableProps : public Props { // BlockEnd/BlockStart map to top/bottom (no writing mode), but we preserve // Yoga's precedence and prefer specific edges (e.g. top) to ones which are // flow relative (e.g. blockStart). + CompactValue insetBlock; + CompactValue insetBlockEnd; + CompactValue insetBlockStart; + CompactValue marginBlockStart; CompactValue marginBlockEnd; diff --git a/packages/rn-tester/js/examples/View/ViewExample.js b/packages/rn-tester/js/examples/View/ViewExample.js index 7a073a3a491697..de2e04acc1aec4 100644 --- a/packages/rn-tester/js/examples/View/ViewExample.js +++ b/packages/rn-tester/js/examples/View/ViewExample.js @@ -652,4 +652,90 @@ exports.examples = [ return ; }, }, + { + title: 'Insets', + render(): React.Node { + return ( + + + + inset 10 + + + + + insetBlock 5 + + + + + insetBlockEnd 5 + + + + + insetBlockStart 5 + + + + + insetInline 5 + + + + + insetInlineEnd 5 + + + + + insetInlineStart 5 + + + + ); + }, + }, ];