Skip to content

Commit adffc11

Browse files
Titozzzclaude
andcommitted
Fix radial-gradient position being dropped after an explicit size
In processBackgroundImage, the explicit-size branch shifts the next token to look for a second size value and discards it when it is not a length or percentage. When that token is 'at', the whole position clause is lost: the position defaults back to center and the position values are then re-parsed as a new size, silently overriding the declared one. radial-gradient(circle 100px at 25% 75%, red, blue) previously parsed as size {x: '25%', y: '75%'} with position {top: '50%', left: '50%'}; it now parses as size {x: 100, y: 100} with position {left: '25%', top: '75%'}. The existing test for this syntax only used 'at center', which is indistinguishable from the default position, so the bug was invisible. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 0f1bddd commit adffc11

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,22 @@ describe('processBackgroundImage', () => {
999999
expect(result[0].type).toEqual('radial-gradient');
10001000
});
10011001

1002+
it('should handle radial gradient with explicit size and position', () => {
1003+
const input = 'radial-gradient(circle 100px at 25% 75%, red, blue)';
1004+
const result = processBackgroundImage(input);
1005+
expect(result[0].shape).toEqual('circle');
1006+
expect(result[0].size).toEqual({x: 100, y: 100});
1007+
expect(result[0].position).toEqual({left: '25%', top: '75%'});
1008+
});
1009+
1010+
it('should handle radial gradient with two explicit sizes and position', () => {
1011+
const input = 'radial-gradient(50px 100px at left bottom, red, blue)';
1012+
const result = processBackgroundImage(input);
1013+
expect(result[0].shape).toEqual('ellipse');
1014+
expect(result[0].size).toEqual({x: 50, y: 100});
1015+
expect(result[0].position).toEqual({left: '0%', top: '100%'});
1016+
});
1017+
10021018
// 1. position syntax: [ left | center | right | top | bottom | <length-percentage> ]
10031019
it('should handle radial gradient position length syntax', () => {
10041020
const input = 'radial-gradient(circle at 20px, red, blue)';

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ function parseRadialGradientCSSString(
348348
size = {x: sizeX, y: sizeY};
349349
} else {
350350
hasExplicitSingleSize = true;
351+
// The token after the size is not a second size value (e.g. 'at' or a
352+
// shape keyword). Put it back so the loop can process it, otherwise
353+
// the position would be silently dropped and its values re-parsed as
354+
// a new size.
355+
firstPartTokens.unshift(token);
351356
}
352357
} else if (tokenTrimmed === 'at') {
353358
let top: string | number;

0 commit comments

Comments
 (0)