Skip to content

Commit cf37479

Browse files
mayank-96facebook-github-bot
authored andcommitted
feat: mapped layout props for view component (facebook#34590)
Summary: This PR adds mapping for layout props, it maps marginInlineStart: 'marginStart', marginInlineEnd: 'marginEnd', marginBlockStart: 'marginTop', marginBlockEnd: 'marginBottom', marginBlock: 'marginVertical', marginInline: 'marginHorizontal', paddingInlineStart: 'paddingStart', paddingInlineEnd: 'paddingEnd', paddingBlockStart: 'paddingTop', paddingBlockEnd: 'paddingBottom', paddingBlock: 'paddingVertical', paddingInline: 'paddingHorizontal', as requested on facebook#34425 ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [General][Added] - Added CSS logical properties by mapping layout props. Pull Request resolved: facebook#34590 Test Plan: ```js <View style={[ { marginBlockStart: 5, // maps to "marginTop" borderWidth: 1, borderRadius: 5, padding: 5, } ]}> <Text style={{fontSize: 11}}>Hello World!</Text> </View> ``` Reviewed By: cipolleschi Differential Revision: D41108750 Pulled By: necolas fbshipit-source-id: 870b9b58a740aba12290a0604a9f6b52aa52de4c
1 parent 082a033 commit cf37479

File tree

10 files changed

+254
-25
lines changed

10 files changed

+254
-25
lines changed

Libraries/Components/TextInput/TextInput.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {TextInputType} from './TextInput.flow';
1919

2020
import usePressability from '../../Pressability/usePressability';
2121
import flattenStyle from '../../StyleSheet/flattenStyle';
22+
import processLayoutProps from '../../StyleSheet/processStyles';
2223
import StyleSheet, {
2324
type ColorValue,
2425
type TextStyleProp,
@@ -1406,11 +1407,14 @@ function InternalTextInput(props: Props): React.Node {
14061407
? RCTMultilineTextInputView
14071408
: RCTSinglelineTextInputView;
14081409

1409-
const style =
1410+
let style =
14101411
props.multiline === true
1411-
? StyleSheet.flatten([styles.multilineInput, props.style])
1412+
? [styles.multilineInput, props.style]
14121413
: props.style;
14131414

1415+
style = flattenStyle(style);
1416+
style = processLayoutProps(style);
1417+
14141418
const useOnChangeSync =
14151419
(props.unstable_onChangeSync || props.unstable_onChangeTextSync) &&
14161420
!(props.onChange || props.onChangeText);
@@ -1442,7 +1446,9 @@ function InternalTextInput(props: Props): React.Node {
14421446
/>
14431447
);
14441448
} else if (Platform.OS === 'android') {
1445-
const style = [props.style];
1449+
let style = flattenStyle(props.style);
1450+
style = processLayoutProps(style);
1451+
14461452
const autoCapitalize = props.autoCapitalize || 'sentences';
14471453
const _accessibilityLabelledBy =
14481454
props?.['aria-labelledby'] ?? props?.accessibilityLabelledBy;

Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ exports[`TextInput tests should render as expected: should deep render when mock
3232
onStartShouldSetResponder={[Function]}
3333
rejectResponderTermination={true}
3434
selection={null}
35+
style={Object {}}
3536
submitBehavior="blurAndSubmit"
3637
text=""
3738
underlineColorAndroid="transparent"
@@ -70,6 +71,7 @@ exports[`TextInput tests should render as expected: should deep render when not
7071
onStartShouldSetResponder={[Function]}
7172
rejectResponderTermination={true}
7273
selection={null}
74+
style={Object {}}
7375
submitBehavior="blurAndSubmit"
7476
text=""
7577
underlineColorAndroid="transparent"

Libraries/Components/View/View.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import type {ViewProps} from './ViewPropTypes';
1212

1313
import flattenStyle from '../../StyleSheet/flattenStyle';
14+
import processLayoutProps from '../../StyleSheet/processStyles';
1415
import TextAncestor from '../../Text/TextAncestor';
1516
import {getAccessibilityRoleFromRole} from '../../Utilities/AcessibilityMapping';
1617
import ViewNativeComponent from './ViewNativeComponent';
@@ -57,7 +58,6 @@ const View: React.AbstractComponent<
5758
nativeID,
5859
pointerEvents,
5960
role,
60-
style,
6161
tabIndex,
6262
...otherProps
6363
}: ViewProps,
@@ -81,8 +81,10 @@ const View: React.AbstractComponent<
8181
text: ariaValueText ?? accessibilityValue?.text,
8282
};
8383

84-
const flattenedStyle = flattenStyle(style);
85-
const newPointerEvents = flattenedStyle?.pointerEvents || pointerEvents;
84+
let style = flattenStyle(otherProps.style);
85+
style = processLayoutProps(style);
86+
87+
const newPointerEvents = style?.pointerEvents || pointerEvents;
8688

8789
return (
8890
<TextAncestor.Provider value={false}>

Libraries/Image/Image.android.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {ImageAndroid} from './Image.flow';
1313
import type {ImageProps as ImagePropsType} from './ImageProps';
1414

1515
import flattenStyle from '../StyleSheet/flattenStyle';
16+
import processLayoutProps from '../StyleSheet/processStyles';
1617
import StyleSheet from '../StyleSheet/StyleSheet';
1718
import TextAncestor from '../Text/TextAncestor';
1819
import ImageAnalyticsTagContext from './ImageAnalyticsTagContext';
@@ -165,6 +166,9 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
165166
}
166167

167168
const {height, width, ...restProps} = props;
169+
170+
style = processLayoutProps(style);
171+
168172
const {onLoadStart, onLoad, onLoadEnd, onError} = props;
169173
const nativeProps = {
170174
...restProps,

Libraries/Image/Image.ios.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {ImageIOS} from './Image.flow';
1414
import type {ImageProps as ImagePropsType} from './ImageProps';
1515

1616
import flattenStyle from '../StyleSheet/flattenStyle';
17+
import processLayoutProps from '../StyleSheet/processStyles';
1718
import StyleSheet from '../StyleSheet/StyleSheet';
1819
import ImageAnalyticsTagContext from './ImageAnalyticsTagContext';
1920
import ImageInjection from './ImageInjection';
@@ -137,6 +138,8 @@ const BaseImage = (props: ImagePropsType, forwardedRef) => {
137138
// $FlowFixMe[prop-missing]
138139
const tintColor = props.tintColor || style.tintColor;
139140

141+
style = processLayoutProps(style);
142+
140143
if (props.children != null) {
141144
throw new Error(
142145
'The <Image> component cannot contain children. If you want to render content on top of the image, consider using the <ImageBackground> component or absolute positioning.',

Libraries/StyleSheet/StyleSheetTypes.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,15 @@ export interface FlexStyle {
6969
| undefined;
7070
left?: number | string | undefined;
7171
margin?: number | string | undefined;
72+
marginBlock?: number | string | undefined;
73+
marginBlockEnd?: number | string | undefined;
74+
marginBlockStart?: number | string | undefined;
7275
marginBottom?: number | string | undefined;
7376
marginEnd?: number | string | undefined;
7477
marginHorizontal?: number | string | undefined;
78+
marginInline?: number | string | undefined;
79+
marginInlineEnd?: number | string | undefined;
80+
marginInlineStart?: number | string | undefined;
7581
marginLeft?: number | string | undefined;
7682
marginRight?: number | string | undefined;
7783
marginStart?: number | string | undefined;
@@ -84,8 +90,14 @@ export interface FlexStyle {
8490
overflow?: 'visible' | 'hidden' | 'scroll' | undefined;
8591
padding?: number | string | undefined;
8692
paddingBottom?: number | string | undefined;
93+
paddingBlock?: number | string | undefined;
94+
paddingBlockEnd?: number | string | undefined;
95+
paddingBlockStart?: number | string | undefined;
8796
paddingEnd?: number | string | undefined;
8897
paddingHorizontal?: number | string | undefined;
98+
paddingInline?: number | string | undefined;
99+
paddingInlineEnd?: number | string | undefined;
100+
paddingInlineStart?: number | string | undefined;
89101
paddingLeft?: number | string | undefined;
90102
paddingRight?: number | string | undefined;
91103
paddingStart?: number | string | undefined;

Libraries/StyleSheet/StyleSheetTypes.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,23 @@ type ____LayoutStyle_Internal = $ReadOnly<{
179179
*/
180180
margin?: DimensionValue,
181181

182+
/** Setting `marginBlock` has the same effect as setting both
183+
* `marginTop` and `marginBottom`.
184+
*/
185+
marginBlock?: DimensionValue,
186+
187+
/** `marginBlockEnd` works like `margin-bottom` in CSS.
188+
* See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom
189+
* for more details.
190+
*/
191+
marginBlockEnd?: DimensionValue,
192+
193+
/** `marginBlockStart` works like `margin-top` in CSS.
194+
* See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-top
195+
* for more details.
196+
*/
197+
marginBlockStart?: DimensionValue,
198+
182199
/** `marginBottom` works like `margin-bottom` in CSS.
183200
* See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom
184201
* for more details.
@@ -196,6 +213,23 @@ type ____LayoutStyle_Internal = $ReadOnly<{
196213
*/
197214
marginHorizontal?: DimensionValue,
198215

216+
/** Setting `marginInline` has the same effect as setting
217+
* both `marginLeft` and `marginRight`.
218+
*/
219+
marginInline?: DimensionValue,
220+
221+
/**
222+
* When direction is `ltr`, `marginInlineEnd` is equivalent to `marginRight`.
223+
* When direction is `rtl`, `marginInlineEnd` is equivalent to `marginLeft`.
224+
*/
225+
marginInlineEnd?: DimensionValue,
226+
227+
/**
228+
* When direction is `ltr`, `marginInlineStart` is equivalent to `marginLeft`.
229+
* When direction is `rtl`, `marginInlineStart` is equivalent to `marginRight`.
230+
*/
231+
marginInlineStart?: DimensionValue,
232+
199233
/** `marginLeft` works like `margin-left` in CSS.
200234
* See https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left
201235
* for more details.
@@ -232,6 +266,23 @@ type ____LayoutStyle_Internal = $ReadOnly<{
232266
*/
233267
padding?: DimensionValue,
234268

269+
/** Setting `paddingBlock` is like setting both of
270+
* `paddingTop` and `paddingBottom`.
271+
*/
272+
paddingBlock?: DimensionValue,
273+
274+
/** `paddingBlockEnd` works like `padding-bottom` in CSS.
275+
* See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom
276+
* for more details.
277+
*/
278+
paddingBlockEnd?: DimensionValue,
279+
280+
/** `paddingBlockStart` works like `padding-top` in CSS.
281+
* See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-top
282+
* for more details.
283+
*/
284+
paddingBlockStart?: DimensionValue,
285+
235286
/** `paddingBottom` works like `padding-bottom` in CSS.
236287
* See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom
237288
* for more details.
@@ -249,6 +300,23 @@ type ____LayoutStyle_Internal = $ReadOnly<{
249300
*/
250301
paddingHorizontal?: DimensionValue,
251302

303+
/** Setting `paddingInline` is like setting both of
304+
* `paddingLeft` and `paddingRight`.
305+
*/
306+
paddingInline?: DimensionValue,
307+
308+
/**
309+
* When direction is `ltr`, `paddingInlineEnd` is equivalent to `paddingRight`.
310+
* When direction is `rtl`, `paddingInlineEnd` is equivalent to `paddingLeft`.
311+
*/
312+
paddingInlineEnd?: DimensionValue,
313+
314+
/**
315+
* When direction is `ltr`, `paddingInlineStart` is equivalent to `paddingLeft`.
316+
* When direction is `rtl`, `paddingInlineStart` is equivalent to `paddingRight`.
317+
*/
318+
paddingInlineStart?: DimensionValue,
319+
252320
/** `paddingLeft` works like `padding-left` in CSS.
253321
* See https://developer.mozilla.org/en-US/docs/Web/CSS/padding-left
254322
* for more details.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @emails oncall+react_native
9+
*/
10+
11+
'use strict';
12+
13+
const processLayoutProps = require('../processStyles');
14+
15+
describe('processLayoutProps', () => {
16+
it('it should map layout style properties', () => {
17+
const style = {
18+
marginInlineStart: 10,
19+
marginInlineEnd: 20,
20+
marginBlockStart: 30,
21+
marginBlockEnd: 40,
22+
marginBlock: 50,
23+
marginInline: 60,
24+
paddingInlineStart: 70,
25+
paddingInlineEnd: 80,
26+
paddingBlockStart: 90,
27+
paddingBlockEnd: 100,
28+
paddingBlock: 110,
29+
paddingInline: 120,
30+
};
31+
const processedStyle = processLayoutProps(style);
32+
expect(processedStyle.marginStart).toBe(10);
33+
expect(processedStyle.marginEnd).toBe(20);
34+
expect(processedStyle.marginTop).toBe(30);
35+
expect(processedStyle.marginBottom).toBe(40);
36+
expect(processedStyle.marginVertical).toBe(50);
37+
expect(processedStyle.marginHorizontal).toBe(60);
38+
expect(processedStyle.paddingStart).toBe(70);
39+
expect(processedStyle.paddingEnd).toBe(80);
40+
expect(processedStyle.paddingTop).toBe(90);
41+
expect(processedStyle.paddingBottom).toBe(100);
42+
expect(processedStyle.paddingVertical).toBe(110);
43+
expect(processedStyle.paddingHorizontal).toBe(120);
44+
45+
expect(processedStyle.marginInlineStart).toBe(undefined);
46+
expect(processedStyle.marginInlineEnd).toBe(undefined);
47+
expect(processedStyle.marginBlockStart).toBe(undefined);
48+
expect(processedStyle.marginBlockEnd).toBe(undefined);
49+
expect(processedStyle.marginBlock).toBe(undefined);
50+
expect(processedStyle.marginInline).toBe(undefined);
51+
expect(processedStyle.paddingInlineStart).toBe(undefined);
52+
expect(processedStyle.paddingInlineEnd).toBe(undefined);
53+
expect(processedStyle.paddingBlockStart).toBe(undefined);
54+
expect(processedStyle.paddingBlockEnd).toBe(undefined);
55+
expect(processedStyle.paddingBlock).toBe(undefined);
56+
expect(processedStyle.paddingInline).toBe(undefined);
57+
});
58+
59+
it('should override style properties', () => {
60+
const style = {marginStart: 20, marginInlineStart: 40};
61+
const processedStyle = processLayoutProps(style);
62+
expect(processedStyle.marginStart).toBe(40);
63+
});
64+
65+
it('should overwrite properties with `undefined`', () => {
66+
const style = {marginInlineStart: 40, marginStart: undefined};
67+
const processedStyle = processLayoutProps(style);
68+
expect(processedStyle.marginStart).toBe(40);
69+
});
70+
71+
it('should not fail on falsy values', () => {
72+
expect(() => processLayoutProps({})).not.toThrow();
73+
expect(() => processLayoutProps(null)).not.toThrow();
74+
expect(() => processLayoutProps(false)).not.toThrow();
75+
expect(() => processLayoutProps(undefined)).not.toThrow();
76+
});
77+
78+
it('should not change style if there is no layout style property', () => {
79+
const style = {backgroundColor: '#000', width: 10};
80+
const processedStyle = processLayoutProps(style);
81+
expect(processedStyle).toStrictEqual(style);
82+
});
83+
});

Libraries/StyleSheet/processStyles.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow strict-local
9+
*/
10+
11+
'use strict';
12+
13+
import type {____FlattenStyleProp_Internal} from './StyleSheetTypes';
14+
15+
function processLayoutProps<T>(
16+
flattenedStyle: ____FlattenStyleProp_Internal<T>,
17+
): ____FlattenStyleProp_Internal<T> {
18+
const _flattenedStyle = {...flattenedStyle};
19+
const layoutPropMap = {
20+
marginInlineStart: 'marginStart',
21+
marginInlineEnd: 'marginEnd',
22+
marginBlockStart: 'marginTop',
23+
marginBlockEnd: 'marginBottom',
24+
marginBlock: 'marginVertical',
25+
marginInline: 'marginHorizontal',
26+
paddingInlineStart: 'paddingStart',
27+
paddingInlineEnd: 'paddingEnd',
28+
paddingBlockStart: 'paddingTop',
29+
paddingBlockEnd: 'paddingBottom',
30+
paddingBlock: 'paddingVertical',
31+
paddingInline: 'paddingHorizontal',
32+
};
33+
if (_flattenedStyle) {
34+
Object.keys(layoutPropMap).forEach(key => {
35+
if (_flattenedStyle && _flattenedStyle[key] !== undefined) {
36+
_flattenedStyle[layoutPropMap[key]] = _flattenedStyle[key];
37+
delete _flattenedStyle[key];
38+
}
39+
});
40+
}
41+
42+
return _flattenedStyle;
43+
}
44+
45+
module.exports = processLayoutProps;

0 commit comments

Comments
 (0)