Skip to content

Commit 93e7e30

Browse files
object style radial gradient js
1 parent 1a34b97 commit 93e7e30

File tree

3 files changed

+152
-20
lines changed

3 files changed

+152
-20
lines changed

packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -734,12 +734,23 @@ type LinearGradientValue = {
734734
};
735735

736736
type RadialExtent =
737-
'closest-corner | closest-side | farthest-corner | farthest-side';
737+
| 'closest-corner'
738+
| 'closest-side'
739+
| 'farthest-corner'
740+
| 'farthest-side';
738741
type RadialGradientValue = {
739742
type: 'radialGradient',
740743
shape: 'circle' | 'ellipse',
741-
size: RadialExtent | [number, number] | [string, string],
742-
position: [number, number] | [string, string],
744+
size:
745+
| RadialExtent
746+
| {
747+
x: number | string,
748+
y: number | string,
749+
},
750+
position: {
751+
x: number | string,
752+
y: number | string,
753+
},
743754
direction?: string,
744755
colorStops: $ReadOnlyArray<{
745756
color: ____ColorValue_Internal,

packages/react-native/Libraries/StyleSheet/__tests__/processBackgroundImage-test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,4 +891,49 @@ describe('processBackgroundImage', () => {
891891
{color: processColor('blue'), position: 40},
892892
]);
893893
});
894+
895+
it('should process radial gradient object syntax', () => {
896+
const input = [
897+
{
898+
type: 'radialGradient',
899+
shape: 'circle',
900+
colorStops: [
901+
{color: 'red', positions: ['10%', 20]},
902+
{color: 'blue', positions: ['30%', 40]},
903+
],
904+
position: {x: '50%', y: 50},
905+
size: 'closest-side',
906+
},
907+
{
908+
type: 'radialGradient',
909+
shape: 'circle',
910+
colorStops: [
911+
{color: 'red', positions: ['10%', 20]},
912+
{color: 'blue', positions: ['30%', 40]},
913+
],
914+
position: {x: '50%', y: 50},
915+
size: {
916+
x: 100,
917+
y: 100,
918+
},
919+
},
920+
];
921+
const result = processBackgroundImage(input);
922+
expect(result[0].colorStops).toEqual([
923+
{color: processColor('red'), position: '10%'},
924+
{color: processColor('red'), position: 20},
925+
{color: processColor('blue'), position: '30%'},
926+
{color: processColor('blue'), position: 40},
927+
]);
928+
expect(result[0].position).toEqual({x: '50%', y: 50});
929+
expect(result[0].size).toEqual({type: 'keyword', value: 'closest-side'});
930+
expect(result[0].shape).toEqual('circle');
931+
expect(result[0].type).toEqual('radialGradient');
932+
933+
expect(result[1].size).toEqual({
934+
type: 'dimensions',
935+
x: 100,
936+
y: 100,
937+
});
938+
});
894939
});

packages/react-native/Libraries/StyleSheet/processBackgroundImage.js

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,40 @@ type LinearGradientBackgroundImage = {
3939

4040
// Radial Gradient
4141
const RADIAL_SHAPE_REGEX = /^(circle|ellipse)(?:\s|$)/i;
42-
const RADIAL_SIZE_REGEX =
43-
/^(closest-side|closest-corner|farthest-side|farthest-corner|([+-]?\d*\.?\d+)(px|%)?)/i;
44-
const RADIAL_POSITION_REGEX =
45-
/^(?:at\s+)?(center|top|right|bottom|left|([+-]?\d*\.?\d+)(px|%)?)(?:\s+(center|top|right|bottom|left|([+-]?\d*\.?\d+)(px|%)?))?/i;
42+
const DEFAULT_RADIAL_SHAPE = 'ellipse';
43+
const DEFAULT_RADIAL_SIZE = {
44+
type: 'keyword',
45+
value: 'farthest-corner',
46+
};
47+
const DEFAULT_RADIAL_POSITION = {
48+
x: '50%',
49+
y: '50%',
50+
};
4651
type RadialExtent =
47-
'closest-corner | closest-side | farthest-corner | farthest-side';
52+
| 'closest-corner'
53+
| 'closest-side'
54+
| 'farthest-corner'
55+
| 'farthest-side';
56+
type RadialGradientSize =
57+
| {
58+
type: 'keyword',
59+
value: RadialExtent,
60+
}
61+
| {
62+
type: 'dimensions',
63+
x: string | number,
64+
y: string | number,
65+
};
66+
type RadialGradientShape = 'circle' | 'ellipse';
67+
type RadialGradientPosition = {
68+
x: number | string,
69+
y: number | string,
70+
};
4871
type RadialGradientBackgroundImage = {
4972
type: 'radialGradient',
50-
shape: 'circle' | 'ellipse',
51-
size: RadialExtent | number | string,
52-
position: string,
73+
shape: RadialGradientShape,
74+
size: RadialGradientSize,
75+
position: RadialGradientPosition,
5376
colorStops: $ReadOnlyArray<{
5477
color: ColorStopColor,
5578
position: ColorStopPosition,
@@ -121,11 +144,57 @@ export default function processBackgroundImage(
121144
colorStops: processedColorStops,
122145
});
123146
} else if (bgImage.type === 'radialGradient') {
147+
let shape: RadialGradientShape = DEFAULT_RADIAL_SHAPE;
148+
let size: RadialGradientSize = DEFAULT_RADIAL_SIZE;
149+
let position: RadialGradientPosition = DEFAULT_RADIAL_POSITION;
150+
151+
if (
152+
bgImage.shape != null &&
153+
(bgImage.shape === 'circle' || bgImage.shape === 'ellipse')
154+
) {
155+
shape = bgImage.shape;
156+
} else {
157+
// If the shape is invalid, return an empty array and do not apply any gradient. Same as web.
158+
return [];
159+
}
160+
161+
if (bgImage.size != null) {
162+
if (
163+
typeof bgImage.size === 'string' &&
164+
(bgImage.size === 'closest-side' ||
165+
bgImage.size === 'closest-corner' ||
166+
bgImage.size === 'farthest-side' ||
167+
bgImage.size === 'farthest-corner')
168+
) {
169+
size = {
170+
type: 'keyword',
171+
value: bgImage.size,
172+
};
173+
} else if (
174+
typeof bgImage.size === 'object' &&
175+
bgImage.size.x != null &&
176+
bgImage.size.y != null
177+
) {
178+
size = {
179+
type: 'dimensions',
180+
x: bgImage.size.x,
181+
y: bgImage.size.y,
182+
};
183+
} else {
184+
// If the size is invalid, return an empty array and do not apply any gradient. Same as web.
185+
return [];
186+
}
187+
}
188+
189+
if (bgImage.position != null) {
190+
position = bgImage.position;
191+
}
192+
124193
result = result.concat({
125194
type: 'radialGradient',
126-
shape: 'circle',
127-
size: 'closest-corner',
128-
position: 'center',
195+
shape,
196+
size,
197+
position,
129198
colorStops: processedColorStops,
130199
});
131200
}
@@ -225,14 +294,21 @@ function parseBackgroundImageCSSString(
225294
}
226295

227296
function parseRadialGradientCSSString(
228-
cssString: string,
229-
): RadialGradientBackgroundImage {
297+
gradientContent: string,
298+
): RadialGradientBackgroundImage | null {
299+
let shape = DEFAULT_RADIAL_SHAPE;
300+
let size: RadialGradientSize = DEFAULT_RADIAL_SIZE;
301+
let position: RadialGradientPosition = DEFAULT_RADIAL_POSITION;
302+
const colorStops: Array<{
303+
color: ColorStopColor,
304+
position: ColorStopPosition,
305+
}> = [];
230306
return {
231307
type: 'radialGradient',
232-
shape: 'circle',
233-
size: 'closest-corner',
234-
position: 'center',
235-
colorStops: [],
308+
shape,
309+
size,
310+
position,
311+
colorStops,
236312
};
237313
}
238314

0 commit comments

Comments
 (0)