Skip to content

Commit 80f4df9

Browse files
committed
feat: enhance processClipPath with additional geometry box and shape parsing tests
1 parent 41a0403 commit 80f4df9

File tree

3 files changed

+312
-3
lines changed

3 files changed

+312
-3
lines changed

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

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,30 @@ describe('processClipPath', () => {
2929
geometryBox: 'content-box',
3030
});
3131
});
32+
33+
it('should parse margin-box', () => {
34+
expect(processClipPath('margin-box')).toEqual({
35+
geometryBox: 'margin-box',
36+
});
37+
});
38+
39+
it('should parse fill-box', () => {
40+
expect(processClipPath('fill-box')).toEqual({
41+
geometryBox: 'fill-box',
42+
});
43+
});
44+
45+
it('should parse stroke-box', () => {
46+
expect(processClipPath('stroke-box')).toEqual({
47+
geometryBox: 'stroke-box',
48+
});
49+
});
50+
51+
it('should parse view-box', () => {
52+
expect(processClipPath('view-box')).toEqual({
53+
geometryBox: 'view-box',
54+
});
55+
});
3256
});
3357

3458
describe('inset() function', () => {
@@ -56,6 +80,18 @@ describe('processClipPath', () => {
5680
});
5781
});
5882

83+
it('should parse inset with three values', () => {
84+
expect(processClipPath('inset(10px 20px 30px)')).toEqual({
85+
shape: {
86+
type: 'inset',
87+
top: 10,
88+
right: 20,
89+
left: 20,
90+
bottom: 30,
91+
},
92+
});
93+
});
94+
5995
it('should parse inset with four values', () => {
6096
expect(processClipPath('inset(10px 20px 30px 40px)')).toEqual({
6197
shape: {
@@ -128,6 +164,17 @@ describe('processClipPath', () => {
128164
});
129165
});
130166

167+
it('should parse circle with percentage position', () => {
168+
expect(processClipPath('circle(50px at 25% 75%)')).toEqual({
169+
shape: {
170+
type: 'circle',
171+
r: 50,
172+
cx: '25%',
173+
cy: '75%',
174+
},
175+
});
176+
});
177+
131178
it('should parse circle with percentage radius', () => {
132179
expect(processClipPath('circle(50%)')).toEqual({
133180
shape: {
@@ -179,6 +226,18 @@ describe('processClipPath', () => {
179226
});
180227
});
181228

229+
it('should parse ellipse with percentage position', () => {
230+
expect(processClipPath('ellipse(50px 25px at 10% 20%)')).toEqual({
231+
shape: {
232+
type: 'ellipse',
233+
rx: 50,
234+
ry: 25,
235+
cx: '10%',
236+
cy: '20%',
237+
},
238+
});
239+
});
240+
182241
it('should parse empty ellipse', () => {
183242
expect(processClipPath('ellipse()')).toEqual({
184243
shape: {
@@ -461,6 +520,61 @@ describe('processClipPath', () => {
461520
});
462521
});
463522

523+
describe('case-insensitive parsing', () => {
524+
it('should parse case-insensitive inset', () => {
525+
expect(processClipPath('InSeT(10Px)')).toEqual({
526+
shape: {
527+
type: 'inset',
528+
top: 10,
529+
right: 10,
530+
bottom: 10,
531+
left: 10,
532+
},
533+
});
534+
});
535+
536+
it('should parse case-insensitive circle', () => {
537+
expect(processClipPath('CiRcLe(50Px)')).toEqual({
538+
shape: {
539+
type: 'circle',
540+
r: 50,
541+
},
542+
});
543+
});
544+
545+
it('should parse case-insensitive geometry box', () => {
546+
expect(processClipPath('BoRdEr-BoX')).toEqual({
547+
geometryBox: 'border-box',
548+
});
549+
});
550+
});
551+
552+
describe('whitespace handling', () => {
553+
it('should handle extra whitespace in inset', () => {
554+
expect(processClipPath(' inset( 10px 20px ) ')).toEqual({
555+
shape: {
556+
type: 'inset',
557+
top: 10,
558+
bottom: 10,
559+
right: 20,
560+
left: 20,
561+
},
562+
});
563+
});
564+
565+
it('should handle newlines in input', () => {
566+
expect(processClipPath('inset(10px\n20px)')).toEqual({
567+
shape: {
568+
type: 'inset',
569+
top: 10,
570+
bottom: 10,
571+
right: 20,
572+
left: 20,
573+
},
574+
});
575+
});
576+
});
577+
464578
describe('invalid values', () => {
465579
it('should return null for null', () => {
466580
expect(processClipPath(null)).toBeNull();
@@ -470,6 +584,10 @@ describe('processClipPath', () => {
470584
expect(processClipPath(undefined)).toBeNull();
471585
});
472586

587+
it('should return null for empty string', () => {
588+
expect(processClipPath('')).toBeNull();
589+
});
590+
473591
it('should return null for invalid string', () => {
474592
expect(processClipPath('invalid')).toBeNull();
475593
});
@@ -482,12 +600,40 @@ describe('processClipPath', () => {
482600
expect(processClipPath('inset(invalid)')).toBeNull();
483601
});
484602

603+
it('should return null for inset with too many values', () => {
604+
expect(processClipPath('inset(10px 20px 30px 40px 50px)')).toBeNull();
605+
});
606+
485607
it('should return null for circle with invalid radius', () => {
486608
expect(processClipPath('circle(invalid)')).toBeNull();
487609
});
488610

611+
it('should return null for ellipse with invalid radii', () => {
612+
expect(processClipPath('ellipse(invalid)')).toBeNull();
613+
});
614+
489615
it('should return null for polygon with invalid points', () => {
490616
expect(processClipPath('polygon(0)')).toBeNull();
491617
});
618+
619+
it('should return null for polygon with too few points', () => {
620+
expect(processClipPath('polygon(0px 0px)')).toBeNull();
621+
});
622+
623+
it('should return null for rect with invalid values', () => {
624+
expect(processClipPath('rect(invalid)')).toBeNull();
625+
});
626+
627+
it('should return null for rect with wrong number of values', () => {
628+
expect(processClipPath('rect(10px 20px)')).toBeNull();
629+
});
630+
631+
it('should return null for xywh with invalid values', () => {
632+
expect(processClipPath('xywh(invalid)')).toBeNull();
633+
});
634+
635+
it('should return null for xywh with wrong number of values', () => {
636+
expect(processClipPath('xywh(10px 20px)')).toBeNull();
637+
});
492638
});
493639
});

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ export default function processClipPath(
119119
}
120120

121121
if (typeof clipPath === 'string') {
122-
return parseClipPathString(clipPath.replace(/\n/g, ' ').trim());
122+
return parseClipPathString(
123+
clipPath.replace(/\n/g, ' ').toLowerCase().trim(),
124+
);
123125
}
124126

125127
// Process object input
@@ -274,6 +276,10 @@ function processEllipseShape(shape: EllipseShapeValue): ?ParsedEllipseShape {
274276
}
275277

276278
function processPolygonShape(shape: PolygonShapeValue): ?ParsedPolygonShape {
279+
if (shape.points.length < 3) {
280+
return null;
281+
}
282+
277283
const result: ParsedPolygonShape = {
278284
type: 'polygon',
279285
points: [],
@@ -624,7 +630,7 @@ function parsePolygonFunction(args: string): ?ParsedPolygonShape {
624630
points.push({x, y});
625631
}
626632

627-
if (points.length === 0) {
633+
if (points.length < 3) {
628634
return null;
629635
}
630636

0 commit comments

Comments
 (0)