Skip to content

Commit 1d21d49

Browse files
committed
feat: support xywh
1 parent e092843 commit 1d21d49

3 files changed

Lines changed: 84 additions & 30 deletions

File tree

src/parser/shape.ts

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const regexMap = {
99
polygon: /polygon\((.+)\)/,
1010
inset: /inset\((.+)\)/,
1111
rect: /rect\((.+)\)/,
12+
xywh: /xywh\((.+)\)/,
1213
}
1314

1415
export function createShapeParser(
@@ -169,22 +170,7 @@ export function createShapeParser(
169170
const w = width - (offsets[1] + offsets[3])
170171
const h = height - (offsets[0] + offsets[2])
171172

172-
if (r.some((v) => v > 0)) {
173-
const d = buildBorderRadius(
174-
{ left: x, top: y, width: w, height: h },
175-
{ ...style, ...radiusMap }
176-
)
177-
178-
return { type: 'path', d }
179-
}
180-
181-
return {
182-
type: 'rect',
183-
x,
184-
y,
185-
width: w,
186-
height: h,
187-
}
173+
return resolveRectLikeShape(r, x, y, w, h, radiusMap, style)
188174
}
189175
function parseRect(str: string) {
190176
const res = str.match(regexMap['rect'])
@@ -223,22 +209,37 @@ export function createShapeParser(
223209
const w = b - d
224210
const h = c - a
225211

226-
if (r.some((v) => v > 0)) {
227-
const m = buildBorderRadius(
228-
{ left: x, top: y, width: w, height: h },
229-
{ ...style, ...radiusMap }
230-
)
212+
return resolveRectLikeShape(r, x, y, w, h, radiusMap, style)
213+
}
214+
function parseXywh(str: string) {
215+
const res = str.match(regexMap['xywh'])
231216

232-
return { type: 'path', d: m }
233-
}
217+
if (!res) return null
234218

235-
return {
236-
type: 'rect',
237-
x,
238-
y,
239-
width: w,
240-
height: h,
241-
}
219+
const [rect, radius] = splitRound(res[1])
220+
const { r, radiusMap } = resolveRadius(
221+
radius,
222+
width,
223+
height,
224+
inheritedStyle
225+
)
226+
227+
const [x, y, w, h] = rect
228+
.split(' ')
229+
.map((s) => String(s))
230+
.map((s, i) => {
231+
return (
232+
lengthToNumber(
233+
s,
234+
inheritedStyle.fontSize as number,
235+
i === 0 || i === 2 ? width : height,
236+
inheritedStyle,
237+
true
238+
) || 0
239+
)
240+
})
241+
242+
return resolveRectLikeShape(r, x, y, w, h, radiusMap, style)
242243
}
243244

244245
return {
@@ -248,6 +249,7 @@ export function createShapeParser(
248249
parsePolygon,
249250
parseInset,
250251
parseRect,
252+
parseXywh,
251253
}
252254
}
253255

@@ -287,6 +289,33 @@ function resolveFillRule(str: string) {
287289
return [fillRule, d]
288290
}
289291

292+
function resolveRectLikeShape(
293+
r: number[],
294+
x: number,
295+
y: number,
296+
w: number,
297+
h: number,
298+
radiusMap: Record<string, any>,
299+
style: Record<string, string | number>
300+
) {
301+
if (r.some((v) => v > 0)) {
302+
const m = buildBorderRadius(
303+
{ left: x, top: y, width: w, height: h },
304+
{ ...style, ...radiusMap }
305+
)
306+
307+
return { type: 'path', d: m }
308+
}
309+
310+
return {
311+
type: 'rect',
312+
x,
313+
y,
314+
width: w,
315+
height: h,
316+
}
317+
}
318+
290319
function resolvePosition(position: string, xDelta: number, yDelta: number) {
291320
const pos = position.split(' ')
292321
const res: { x: number | string; y: number | string } = {
491 Bytes
Loading

test/clip-path.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,29 @@ describe('clipPath', () => {
187187
)
188188
expect(toImage(svg)).toMatchImageSnapshot()
189189
})
190+
191+
it('should render shape for xywh', async () => {
192+
const svg = await satori(
193+
<div
194+
style={{
195+
height: '100%',
196+
width: '100%',
197+
display: 'flex',
198+
flexDirection: 'column',
199+
alignItems: 'center',
200+
justifyContent: 'center',
201+
backgroundColor: '#fff',
202+
clipPath: 'xywh(5px 5px 30% 20% round 5px)',
203+
fontSize: 32,
204+
fontWeight: 600,
205+
}}
206+
></div>,
207+
{
208+
width: 100,
209+
height: 100,
210+
fonts,
211+
}
212+
)
213+
expect(toImage(svg)).toMatchImageSnapshot()
214+
})
190215
})

0 commit comments

Comments
 (0)