Skip to content

Commit 27d1b48

Browse files
authored
feat(svg): extract svg parser (#3365)
1 parent 0138fdd commit 27d1b48

27 files changed

Lines changed: 1915 additions & 868 deletions

File tree

.changeset/tall-phones-cheer.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@react-pdf/examples": minor
3+
"@react-pdf/image": minor
4+
"@react-pdf/layout": minor
5+
"@react-pdf/math": minor
6+
"@react-pdf/svg": minor
7+
"@react-pdf/vite-example": minor
8+
---
9+
10+
feat(svg): extract svg parser
Lines changed: 88 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import React from 'react';
2-
import { Document, Page, View, Image, Text, StyleSheet, Font } from '@react-pdf/renderer';
2+
import {
3+
Document,
4+
Page,
5+
View,
6+
Image,
7+
Text,
8+
StyleSheet,
9+
} from '@react-pdf/renderer';
310

411
import SimpleIcon from '../../../public/simple-icon.svg';
512
import TestLogoUnitless from '../../../public/test-logo-unitless.svg';
@@ -10,107 +17,141 @@ import TestLogoCm from '../../../public/test-logo-cm.svg';
1017
import TestLogoMm from '../../../public/test-logo-mm.svg';
1118
import VideoCall from '../../../public/video-call.svg';
1219

13-
Font.register({
14-
family: 'Roboto',
15-
src: '/Roboto-Regular.ttf',
16-
});
17-
1820
const styles = StyleSheet.create({
1921
page: {
2022
padding: 40,
21-
backgroundColor: '#f5f5f5',
23+
backgroundColor: '#fafafa',
2224
},
2325
title: {
24-
fontSize: 24,
26+
fontSize: 18,
27+
fontWeight: 'bold',
28+
color: '#1a1a1a',
29+
},
30+
subtitle: {
31+
fontSize: 9,
32+
color: '#888',
2533
marginBottom: 20,
26-
textAlign: 'center',
2734
},
28-
section: {
29-
marginBottom: 30,
35+
card: {
36+
backgroundColor: '#ffffff',
37+
borderRadius: 5,
38+
padding: 12,
39+
borderWidth: 1,
40+
borderColor: '#e8e8e8',
41+
marginBottom: 8,
3042
},
31-
sectionTitle: {
32-
fontSize: 14,
33-
marginBottom: 10,
34-
color: '#333',
43+
label: {
44+
fontSize: 8,
45+
color: '#999',
46+
textTransform: 'uppercase',
47+
letterSpacing: 0.5,
48+
marginBottom: 6,
3549
},
3650
row: {
51+
flexDirection: 'row',
52+
gap: 8,
53+
marginBottom: 8,
54+
},
55+
halfCard: {
56+
flex: 1,
57+
backgroundColor: '#ffffff',
58+
borderRadius: 5,
59+
padding: 12,
60+
borderWidth: 1,
61+
borderColor: '#e8e8e8',
62+
},
63+
imageRow: {
3764
flexDirection: 'row',
3865
alignItems: 'center',
39-
gap: 20,
40-
marginBottom: 10,
66+
gap: 16,
4167
},
4268
imageContainer: {
4369
alignItems: 'center',
4470
},
45-
label: {
46-
fontSize: 10,
47-
color: '#666',
48-
marginTop: 5,
71+
imageLabel: {
72+
fontSize: 7,
73+
color: '#aaa',
74+
marginTop: 4,
75+
},
76+
footer: {
77+
marginTop: 'auto',
78+
paddingTop: 12,
79+
borderTopWidth: 1,
80+
borderTopColor: '#e8e8e8',
81+
flexDirection: 'row',
82+
justifyContent: 'space-between',
83+
},
84+
footerText: {
85+
fontSize: 7,
86+
color: '#aaa',
4987
},
5088
});
5189

5290
const SvgImageExample = () => (
5391
<Document>
5492
<Page size="A4" style={styles.page}>
55-
<Text style={styles.title}>SVG via Image</Text>
93+
<Text style={styles.title}>SVG Image</Text>
94+
<Text style={styles.subtitle}>
95+
SVG files rendered via the Image component with different sizes and
96+
units
97+
</Text>
5698

57-
<View style={styles.section}>
58-
<Text style={styles.sectionTitle}>Basic SVG Images</Text>
59-
<View style={styles.row}>
99+
<View style={styles.card}>
100+
<Text style={styles.label}>Basic SVG Images</Text>
101+
<View style={styles.imageRow}>
60102
<View style={styles.imageContainer}>
61103
<Image src={SimpleIcon} style={{ width: 40, height: 40 }} />
62-
<Text style={styles.label}>40x40</Text>
104+
<Text style={styles.imageLabel}>40x40</Text>
63105
</View>
64106
<View style={styles.imageContainer}>
65107
<Image src={SimpleIcon} style={{ width: 60, height: 60 }} />
66-
<Text style={styles.label}>60x60</Text>
108+
<Text style={styles.imageLabel}>60x60</Text>
67109
</View>
68110
<View style={styles.imageContainer}>
69111
<Image src={SimpleIcon} style={{ width: 100, height: 100 }} />
70-
<Text style={styles.label}>100x100</Text>
112+
<Text style={styles.imageLabel}>100x100</Text>
71113
</View>
72114
<View style={styles.imageContainer}>
73115
<Image src={TestLogoUnitless} style={{ width: 120, height: 120 }} />
74-
<Text style={styles.label}>With Text and Gradient (120x120)</Text>
116+
<Text style={styles.imageLabel}>With Text and Gradient</Text>
75117
</View>
76118
</View>
77119
</View>
78120

79-
<View style={styles.section}>
80-
<Text style={styles.sectionTitle}>
81-
SVG with Different Units (native size)
82-
</Text>
83-
<View style={styles.row}>
121+
<View style={styles.card}>
122+
<Text style={styles.label}>Different Units (Native Size)</Text>
123+
<View style={styles.imageRow}>
84124
<View style={styles.imageContainer}>
85125
<Image src={TestLogoIn} />
86-
<Text style={styles.label}>1in = 72</Text>
126+
<Text style={styles.imageLabel}>1in = 72</Text>
87127
</View>
88128
<View style={styles.imageContainer}>
89129
<Image src={TestLogoCm} />
90-
<Text style={styles.label}>3cm ≈ 85</Text>
130+
<Text style={styles.imageLabel}>3cm ≈ 85</Text>
91131
</View>
92132
<View style={styles.imageContainer}>
93133
<Image src={TestLogoPx} />
94-
<Text style={styles.label}>120px = 90</Text>
134+
<Text style={styles.imageLabel}>120px = 90</Text>
95135
</View>
96136
<View style={styles.imageContainer}>
97137
<Image src={TestLogoPt} />
98-
<Text style={styles.label}>100pt = 100</Text>
138+
<Text style={styles.imageLabel}>100pt = 100</Text>
99139
</View>
100140
<View style={styles.imageContainer}>
101141
<Image src={TestLogoMm} />
102-
<Text style={styles.label}>50mm ≈ 142</Text>
142+
<Text style={styles.imageLabel}>50mm ≈ 142</Text>
103143
</View>
104144
</View>
105145
</View>
106146

107-
<View style={styles.section}>
108-
<Text style={styles.sectionTitle}>Complex image</Text>
109-
<View style={styles.row}>
110-
<View style={styles.imageContainer}>
111-
<Image src={VideoCall} style={{ width: 300, height: 172 }} />
112-
</View>
113-
</View>
147+
<View style={styles.card}>
148+
<Text style={styles.label}>Complex SVG</Text>
149+
<Image src={VideoCall} style={{ width: 300, height: 172 }} />
150+
</View>
151+
152+
<View style={styles.footer}>
153+
<Text style={styles.footerText}>SVG files rendered as images</Text>
154+
<Text style={styles.footerText}>Supports multiple unit types</Text>
114155
</View>
115156
</Page>
116157
</Document>
@@ -119,6 +160,6 @@ const SvgImageExample = () => (
119160
export default {
120161
id: 'svg-image',
121162
name: 'SVG Image',
122-
description: 'Test SVG files in Image component',
163+
description: 'SVG files rendered via the Image component',
123164
Document: SvgImageExample,
124165
};

packages/image/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
},
2525
"dependencies": {
2626
"@react-pdf/png-js": "^3.0.0",
27+
"@react-pdf/svg": "^1.0.0",
2728
"jay-peg": "^1.1.1"
2829
},
2930
"files": [

packages/image/src/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import resolveImage from './resolve';
22

3-
export type {
4-
Image,
5-
ImageSrc,
6-
SvgImage,
7-
RasterImage,
8-
SvgNode,
9-
Viewbox,
10-
} from './types';
3+
export type { Image, ImageSrc, SvgImage, RasterImage } from './types';
114

125
export default resolveImage;

0 commit comments

Comments
 (0)