Skip to content

Commit 14c91cd

Browse files
gabrieldonadelfacebook-github-bot
authored andcommitted
feat: Add string support for aspectRatio (#34629)
Summary: This updates `aspectRatio` to support string values and ratio formats, i.e., `'16 / 9'`, thus aligning it with the [CSS Box Sizing Module Level 4](https://drafts.csswg.org/css-sizing-4/#aspect-ratio) specification as requested on #34425. This also adds unit tests to the `processAspectRatio` function ensuring the style processing works as expected. ## Changelog [General] [Added] - Add string support for aspectRatio Pull Request resolved: #34629 Test Plan: This can be tested either through `processAspectRatio-tests` or by using the following code: ```js <View style={{ backgroundColor: '#527FE4', aspectRatio: '16 / 9', }} /> ``` https://user-images.githubusercontent.com/11707729/189029904-da1dc0a6-85de-46aa-8ec2-3567802c8719.mov Reviewed By: jacdebug Differential Revision: D39423304 Pulled By: cipolleschi fbshipit-source-id: d323de93d6524e411e7ab9943335a8ca323b6e61
1 parent 71fda5e commit 14c91cd

File tree

6 files changed

+120
-5
lines changed

6 files changed

+120
-5
lines changed

Libraries/Components/View/ReactNativeStyleAttributes.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
import type {AnyAttributeType} from '../../Renderer/shims/ReactNativeTypes';
12+
import processAspectRatio from '../../StyleSheet/processAspectRatio';
1213
import processColor from '../../StyleSheet/processColor';
1314
import processFontVariant from '../../StyleSheet/processFontVariant';
1415
import processTransform from '../../StyleSheet/processTransform';
@@ -23,7 +24,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
2324
alignContent: true,
2425
alignItems: true,
2526
alignSelf: true,
26-
aspectRatio: true,
27+
aspectRatio: {process: processAspectRatio},
2728
borderBottomWidth: true,
2829
borderEndWidth: true,
2930
borderLeftWidth: true,

Libraries/StyleSheet/StyleSheetTypes.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export interface FlexStyle {
3333
| undefined;
3434
alignItems?: FlexAlignType | undefined;
3535
alignSelf?: 'auto' | FlexAlignType | undefined;
36-
aspectRatio?: number | undefined;
36+
aspectRatio?: number | string | undefined;
3737
borderBottomWidth?: number | undefined;
3838
borderEndWidth?: number | string | undefined;
3939
borderLeftWidth?: number | undefined;

Libraries/StyleSheet/StyleSheetTypes.js

+7-3
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,7 @@ type ____LayoutStyle_Internal = $ReadOnly<{
446446
flexBasis?: number | string,
447447

448448
/**
449-
* Aspect ratio control the size of the undefined dimension of a node. Aspect ratio is a
450-
* non-standard property only available in react native and not CSS.
449+
* Aspect ratio control the size of the undefined dimension of a node.
451450
*
452451
* - On a node with a set width/height aspect ratio control the size of the unset dimension
453452
* - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis
@@ -457,8 +456,13 @@ type ____LayoutStyle_Internal = $ReadOnly<{
457456
* - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis
458457
* if unset
459458
* - Aspect ratio takes min/max dimensions into account
459+
*
460+
* Supports a number or a ratio, e.g.:
461+
* - aspectRatio: '1 / 1'
462+
* - aspectRatio: '1'
463+
* - aspectRatio: '1'
460464
*/
461-
aspectRatio?: number,
465+
aspectRatio?: number | string,
462466

463467
/** `zIndex` controls which components display on top of others.
464468
* Normally, you don't use `zIndex`. Components render according to
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`processAspectRatio should not accept invalid formats 1`] = `"aspectRatio must either be a number, a ratio or \`auto\`. You passed: 0a"`;
4+
5+
exports[`processAspectRatio should not accept invalid formats 2`] = `"aspectRatio must either be a number, a ratio or \`auto\`. You passed: 1 / 1 1"`;
6+
7+
exports[`processAspectRatio should not accept invalid formats 3`] = `"aspectRatio must either be a number, a ratio or \`auto\`. You passed: auto 1/1"`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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 processAspectRatio = require('../processAspectRatio');
14+
15+
describe('processAspectRatio', () => {
16+
it('should accept numbers', () => {
17+
expect(processAspectRatio(1)).toBe(1);
18+
expect(processAspectRatio(0)).toBe(0);
19+
expect(processAspectRatio(1.5)).toBe(1.5);
20+
});
21+
22+
it('should accept string numbers', () => {
23+
expect(processAspectRatio('1')).toBe(1);
24+
expect(processAspectRatio('0')).toBe(0);
25+
expect(processAspectRatio('1.5')).toBe(1.5);
26+
expect(processAspectRatio('+1.5')).toBe(1.5);
27+
expect(processAspectRatio(' 1')).toBe(1);
28+
expect(processAspectRatio(' 0 ')).toBe(0);
29+
});
30+
31+
it('should accept `auto`', () => {
32+
expect(processAspectRatio('auto')).toBe(undefined);
33+
expect(processAspectRatio(' auto')).toBe(undefined);
34+
expect(processAspectRatio(' auto ')).toBe(undefined);
35+
});
36+
37+
it('should accept ratios', () => {
38+
expect(processAspectRatio('+1/1')).toBe(1);
39+
expect(processAspectRatio('0 / 10')).toBe(0);
40+
expect(processAspectRatio('117/ 13')).toBe(9);
41+
expect(processAspectRatio('1.5 /1.2')).toBe(1.25);
42+
expect(processAspectRatio('1/0')).toBe(Infinity);
43+
});
44+
45+
it('should not accept invalid formats', () => {
46+
expect(() => processAspectRatio('0a')).toThrowErrorMatchingSnapshot();
47+
expect(() => processAspectRatio('1 / 1 1')).toThrowErrorMatchingSnapshot();
48+
expect(() => processAspectRatio('auto 1/1')).toThrowErrorMatchingSnapshot();
49+
});
50+
});
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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
9+
*/
10+
11+
'use strict';
12+
13+
const invariant = require('invariant');
14+
15+
function processAspectRatio(aspectRatio: number | string): ?number {
16+
if (typeof aspectRatio === 'number') {
17+
return aspectRatio;
18+
}
19+
20+
const matches = aspectRatio.split('/').map(s => s.trim());
21+
22+
if (matches.includes('auto')) {
23+
if (__DEV__) {
24+
invariant(
25+
matches.length,
26+
'aspectRatio does not support `auto <ratio>`. You passed: %s',
27+
aspectRatio,
28+
);
29+
}
30+
return;
31+
}
32+
33+
const hasNonNumericValues = matches.some(n => Number.isNaN(Number(n)));
34+
if (__DEV__) {
35+
invariant(
36+
!hasNonNumericValues && (matches.length === 1 || matches.length === 2),
37+
'aspectRatio must either be a number, a ratio or `auto`. You passed: %s',
38+
aspectRatio,
39+
);
40+
}
41+
42+
if (hasNonNumericValues) {
43+
return;
44+
}
45+
46+
if (matches.length === 2) {
47+
return Number(matches[0]) / Number(matches[1]);
48+
}
49+
50+
return Number(matches[0]);
51+
}
52+
53+
module.exports = processAspectRatio;

0 commit comments

Comments
 (0)