Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -352,24 +352,55 @@ describe('<View>', () => {
],
}}
/>
<View
style={{
backgroundImage:
'conic-gradient(from 45deg, #e66465, #9198e5)',
}}
/>
<View
style={{
backgroundImage: [
{
type: 'conic-gradient',
from: '45deg',
colorStops: [{color: '#e66465'}, {color: '#9198e5'}],
},
],
}}
/>
</>,
);
});

const expectedProps = {
const expectedRadialProps = {
backgroundImage:
'[radial-gradient(ellipse farthest-corner at 50% 50% , rgba(230, 100, 101, 1), rgba(145, 152, 229, 1))]',
};
const expectedConicProps = {
backgroundImage:
'[conic-gradient(from 45deg at 50% 50% , rgba(230, 100, 101, 1), rgba(145, 152, 229, 1))]',
};

expect(root.getRenderedOutput().toJSON()).toEqual([
{
children: [],
props: expectedProps,
props: expectedRadialProps,
type: 'View',
},
{
children: [],
props: expectedRadialProps,
type: 'View',
},
{
children: [],
props: expectedConicProps,
type: 'View',
},
{
children: [],
props: expectedProps,
props: expectedConicProps,
type: 'View',
},
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,28 @@ describe('<View> native CSS parsing', () => {
expect(backgroundImage).toContain('linear-gradient');
expect(backgroundImage).toContain('rgba(230, 100, 101, 1)');
});

it('parses a conic-gradient()', () => {
const backgroundImage = mountedProp(
{
backgroundImage: 'conic-gradient(from 45deg, #e66465, #9198e5)',
},
'backgroundImage',
);
expect(backgroundImage).toBe(
'[conic-gradient(from 45deg at 50% 50% , rgba(230, 100, 101, 1), rgba(145, 152, 229, 1))]',
);
});

it('parses a four-value conic-gradient position', () => {
expect(
mountedProp(
{
backgroundImage: 'conic-gradient(at top 20px left 10px, red, blue)',
},
'backgroundImage',
),
).toContain('at 10px 20px');
});
});
});
13 changes: 12 additions & 1 deletion packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,18 @@ type RadialGradientValue = {
}>,
};

export type BackgroundImageValue = LinearGradientValue | RadialGradientValue;
type ConicGradientValue = {
type: 'conic-gradient',
from?: string,
position?: RadialGradientPosition,
colorStops: ReadonlyArray<{
color: ____ColorValue_Internal,
positions?: ReadonlyArray<string>,
}>,
};

export type BackgroundImageValue =
LinearGradientValue | RadialGradientValue | ConicGradientValue;

export type BackgroundSizeValue = {
x: string | number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,97 @@ describe('processBackgroundImage', () => {
]);
});

it('should process a conic gradient string', () => {
const result = processBackgroundImage(
'conic-gradient(from 45deg at 25% 75%, red 0deg, blue .5turn, red 100%)',
);

expect(result).toEqual([
{
type: 'conic-gradient',
from: 45,
position: {left: '25%', top: '75%'},
colorStops: [
{color: processColor('red'), position: '0%'},
{color: processColor('blue'), position: '50%'},
{color: processColor('red'), position: '100%'},
],
},
]);
});

it('should process a conic gradient with four-value position', () => {
expect(
processBackgroundImage(
'conic-gradient(at top 20px left 10px, red, blue)',
),
).toEqual([
{
type: 'conic-gradient',
from: 0,
position: {top: 20, left: 10},
colorStops: [
{color: processColor('red'), position: null},
{color: processColor('blue'), position: null},
],
},
]);
});

it('should process conic gradient object syntax', () => {
const input: ReadonlyArray<BackgroundImageValue> = [
{
type: 'conic-gradient',
from: '0.25turn',
position: {top: '50%', left: '50%'},
colorStops: [
{color: 'red', positions: ['0deg', '90deg']},
{color: 'blue', positions: ['90deg', '360deg']},
],
},
];

expect(processBackgroundImage(input)).toEqual([
{
type: 'conic-gradient',
from: 90,
position: {top: '50%', left: '50%'},
colorStops: [
{color: processColor('red'), position: '0%'},
{color: processColor('red'), position: '25%'},
{color: processColor('blue'), position: '25%'},
{color: processColor('blue'), position: '100%'},
],
},
]);
});

it('should reject invalid conic gradient object stops', () => {
expect(
processBackgroundImage([
{
type: 'conic-gradient',
colorStops: [{color: 'red'}],
},
]),
).toEqual([]);

const numericStop = [
{
type: 'conic-gradient',
colorStops: [{color: 'red', positions: [50]}, {color: 'blue'}],
},
];
// $FlowFixMe[incompatible-type] - verifies runtime validation.
expect(processBackgroundImage(numericStop)).toEqual([]);
});

it('should reject conic gradient length color stops', () => {
expect(processBackgroundImage('conic-gradient(red 10px, blue)')).toEqual(
[],
);
});

it('should process a diagonal linear gradient', () => {
const input = 'linear-gradient(to bottom right, red, blue)';
const result = processBackgroundImage(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ describe('processBackgroundPosition', () => {
]);
});

it('should parse vertical position before horizontal position', () => {
expect(processBackgroundPosition('top 75% left 25%')).toEqual([
{top: '75%', left: '25%'},
]);
});

// Test multiple background positions (comma-separated)
it('should parse multiple background positions', () => {
expect(processBackgroundPosition('left top, right bottom')).toEqual([
Expand Down
Loading