react-pdf-html-flabs-2 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # react-pdf-html
2
+
3
+ `<Html>` component for [react-pdf](https://github.com/diegomura/react-pdf/)
4
+
5
+ - Support for CSS via `<style>` tags and `style` attributes (limited to `Style` properties supported by `react-pdf`)
6
+ - [Browser CSS defaults](https://www.w3schools.com/cssref/css_default_values.asp) with option for [style reset](https://meyerweb.com/eric/tools/css/reset/)
7
+ - Basic `<table>`(attempted using flex layouts) `<ul>` and `<ol>` support
8
+ - Ability to provide custom renderers for any tag
9
+
10
+ ## How it Works
11
+
12
+ 1. Parses the HTML string into a JSON tree of nodes using [node-html-parser](https://github.com/taoqf/node-html-parser)
13
+ 2. Parses any `<style>` tags in the document and `style` attributes using [css-tree](https://github.com/csstree/csstree)
14
+ 3. Renders all nodes using the appropriate `react-pdf` components, applying cascading styles for each node as an array passed to the `style` prop:
15
+ - block/container nodes using `<View>`
16
+ - inline/text nodes using `<Text>`, with appropriate nesting and collapsing of whitepace
17
+ - `<img>` nodes using `<Image>`
18
+ - `<a>` nodes using `<Link>`
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm i react-pdf-html
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```tsx
29
+ import Html from 'react-pdf-html';
30
+
31
+ const html = `<html>
32
+ <body>
33
+ <style>
34
+ .my-heading4 {
35
+ background: darkgreen;
36
+ color: white;
37
+ }
38
+ pre {
39
+ background-color: #eee;
40
+ padding: 10px;
41
+ }
42
+ </style>
43
+ <h1>Heading 1</h1>
44
+ <h2 style="background-color: pink">Heading 2</h2>
45
+ <h3>Heading 3</h3>
46
+ <h4 class="my-heading4">Heading 4</h4>
47
+ <p>
48
+ Paragraph with <strong>bold</strong>, <i>italic</i>, <u>underline</u>,
49
+ <s>strikethrough</s>,
50
+ <strong><u><s><i>and all of the above</i></s></u></strong>
51
+ </p>
52
+ <p>
53
+ Paragraph with image <img src="${myFile}" /> and
54
+ <a href="http://google.com">link</a>
55
+ </p>
56
+ <hr />
57
+ <ul>
58
+ <li>Unordered item</li>
59
+ <li>Unordered item</li>
60
+ </ul>
61
+ <ol>
62
+ <li>Ordered item</li>
63
+ <li>Ordered item</li>
64
+ </ol>
65
+ <br /><br /><br /><br /><br />
66
+ Text outside of any tags
67
+ <table>
68
+ <thead>
69
+ <tr>
70
+ <th>Column 1</th>
71
+ <th>Column 2</th>
72
+ <th>Column 3</th>
73
+ </tr>
74
+ </thead>
75
+ <tbody>
76
+ <tr>
77
+ <td>Foo</td>
78
+ <td>Bar</td>
79
+ <td>Foobar</td>
80
+ </tr>
81
+ <tr>
82
+ <td colspan="2">Foo</td>
83
+ <td>Bar</td>
84
+ </tr>
85
+ <tr>
86
+ <td>Some longer thing</td>
87
+ <td>Even more content than before!</td>
88
+ <td>Even more content than before!</td>
89
+ </tr>
90
+ </tbody>
91
+ </table>
92
+ <div style="width: 200px; height: 200px; background: pink"></div>
93
+ <pre>
94
+ function myCode() {
95
+ const foo = 'bar';
96
+ }
97
+ </pre>
98
+ </body>
99
+ </html>
100
+ `;
101
+
102
+ return (
103
+ <Document>
104
+ <Page>
105
+ <Html>{html}</Html>
106
+ </Page>
107
+ </Document>
108
+ );
109
+ ```
110
+
111
+ ## Rendering React Components
112
+
113
+ ```tsx
114
+ import ReactDOMServer from 'react-dom/server';
115
+
116
+ const element = (
117
+ <html>
118
+ <body>
119
+ <style>
120
+ {`
121
+ .heading4 {
122
+ background: darkgreen;
123
+ color: white;
124
+ }
125
+ pre {
126
+ background-color: #eee;
127
+ padding: 10px;
128
+ }`}
129
+ </style>
130
+ <h1>Heading 1</h1>
131
+ <h2 style={{ backgroundColor: 'pink' }}>Heading 2</h2>
132
+ ...
133
+ </body>
134
+ </html>
135
+ );
136
+
137
+ const html = ReactDOMServer.renderToStaticMarkup(element);
138
+
139
+ return (
140
+ <Document>
141
+ <Page>
142
+ <Html>{html}</Html>
143
+ </Page>
144
+ </Document>
145
+ );
146
+ ```
147
+
148
+ ## Props
149
+
150
+ ```ts
151
+ type HtmlProps = {
152
+ children: string; // the HTML
153
+ collapse?: boolean; // Default: true. Collapse whitespace. If false, render newlines as breaks
154
+ renderers?: HtmlRenderers; // Mapping of { tagName: HtmlRenderer }
155
+ style?: Style | Style[]; // Html root View style
156
+ stylesheet?: HtmlStyles | HtmlStyles[]; // Mapping of { selector: Style }
157
+ resetStyles?: false; // If true, style/CSS reset
158
+ };
159
+ ```
160
+
161
+ ## Overriding Element Styles
162
+
163
+ ### Provide a Stylesheet
164
+
165
+ ```tsx
166
+ const stylesheet = {
167
+ // clear margins for all <p> tags
168
+ p: {
169
+ margin: 0,
170
+ },
171
+ // add pink background color to elements with class="special"
172
+ ['.special']: {
173
+ backgroundColor: 'pink',
174
+ },
175
+ };
176
+
177
+ return (
178
+ <Document>
179
+ <Page>
180
+ <Html stylesheet={stylesheet}>{html}</Html>
181
+ </Page>
182
+ </Document>
183
+ );
184
+ ```
185
+
186
+ ### Inline Styles
187
+
188
+ ```tsx
189
+ const html = `<div style="width: 200px; height: 200px; background-color: pink">Foobar</div>`;
190
+
191
+ return (
192
+ <Document>
193
+ <Page>
194
+ <Html>{html}</Html>
195
+ </Page>
196
+ </Document>
197
+ );
198
+ ```
199
+
200
+ ## Resetting Styles
201
+
202
+ Reset browser default styles (see [CSS reset](https://meyerweb.com/eric/tools/css/reset/))
203
+
204
+ ```tsx
205
+ return (
206
+ <Document>
207
+ <Page>
208
+ <Html resetStyles>{html}</Html>
209
+ </Page>
210
+ </Document>
211
+ );
212
+ ```
213
+
214
+ ## Font Sizes
215
+
216
+ The default styesheet roughly matches browser defaults, using a rough emulation of ems:
217
+
218
+ ```tsx
219
+ const em = (em: number, relativeSize: number = fontSize) => em * relativeSize;
220
+
221
+ StyleSheet.create({
222
+ h1: {
223
+ fontSize: em(2),
224
+ marginVertical: em(0.67, em(2)),
225
+ fontWeight: 'bold',
226
+ },
227
+ ...
228
+ });
229
+ ```
230
+
231
+ By default, the basis for the font size ems is based on the `fontSize` from `props.style`:
232
+
233
+ ```tsx
234
+ return (
235
+ <Document>
236
+ <Page>
237
+ <Html style={{ fontSize: 10 }}>{html}</Html>
238
+ </Page>
239
+ </Document>
240
+ );
241
+ ```
242
+
243
+ If this is not defined, it falls back to a default of `18`
package/dist/Html.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { HtmlRenderers } from './render';
3
+ import { HtmlStyle, HtmlStyles } from './styles';
4
+ export type HtmlProps = {
5
+ collapse?: boolean;
6
+ renderers?: HtmlRenderers;
7
+ style?: HtmlStyle | (HtmlStyle | undefined)[];
8
+ stylesheet?: HtmlStyles | HtmlStyles[];
9
+ resetStyles?: boolean;
10
+ children: string;
11
+ };
12
+ declare const Html: React.FC<HtmlProps>;
13
+ export default Html;
package/dist/Html.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const react_1 = __importDefault(require("react"));
7
+ const render_1 = __importDefault(require("./render"));
8
+ const Html = (props) => {
9
+ return react_1.default.createElement(react_1.default.Fragment, null, (0, render_1.default)(props.children, props));
10
+ };
11
+ exports.default = Html;
12
+ //# sourceMappingURL=Html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Html.js","sourceRoot":"","sources":["../src/Html.tsx"],"names":[],"mappings":";;;;;AAAA,kDAA0B;AAC1B,sDAAqD;AAYrD,MAAM,IAAI,GAAwB,CAAC,KAAK,EAAE,EAAE;IAC1C,OAAO,8DAAG,IAAA,gBAAU,EAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAI,CAAC;AAClD,CAAC,CAAC;AAEF,kBAAe,IAAI,CAAC","sourcesContent":["import React from 'react';\nimport renderHtml, { HtmlRenderers } from './render';\nimport { HtmlStyle, HtmlStyles } from './styles';\n\nexport type HtmlProps = {\n collapse?: boolean;\n renderers?: HtmlRenderers;\n style?: HtmlStyle | (HtmlStyle | undefined)[];\n stylesheet?: HtmlStyles | HtmlStyles[];\n resetStyles?: boolean;\n children: string;\n};\n\nconst Html: React.FC<HtmlProps> = (props) => {\n return <>{renderHtml(props.children, props)}</>;\n};\n\nexport default Html;\n"]}
@@ -0,0 +1,3 @@
1
+ export { default, default as Html } from './Html';
2
+ export { default as renderHtml } from './render';
3
+ export { HtmlStyle, HtmlStyles } from './styles';
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderHtml = exports.Html = exports.default = void 0;
7
+ var Html_1 = require("./Html");
8
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(Html_1).default; } });
9
+ Object.defineProperty(exports, "Html", { enumerable: true, get: function () { return __importDefault(Html_1).default; } });
10
+ var render_1 = require("./render");
11
+ Object.defineProperty(exports, "renderHtml", { enumerable: true, get: function () { return __importDefault(render_1).default; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,+BAAkD;AAAzC,gHAAA,OAAO,OAAA;AAAE,6GAAA,OAAO,OAAQ;AACjC,mCAAiD;AAAxC,qHAAA,OAAO,OAAc","sourcesContent":["export { default, default as Html } from './Html';\nexport { default as renderHtml } from './render';\nexport { HtmlStyle, HtmlStyles } from './styles';\n"]}
@@ -0,0 +1,3 @@
1
+ export declare const orderedAlpha: string[];
2
+ export declare const lowerAlpha: string[];
3
+ export declare const upperAlpha: string[];
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.upperAlpha = exports.lowerAlpha = exports.orderedAlpha = void 0;
4
+ exports.orderedAlpha = [
5
+ 'a',
6
+ 'b',
7
+ 'c',
8
+ 'd',
9
+ 'e',
10
+ 'f',
11
+ 'g',
12
+ 'h',
13
+ 'i',
14
+ 'j',
15
+ 'k',
16
+ 'l',
17
+ 'n',
18
+ 'm',
19
+ 'o',
20
+ 'p',
21
+ 'q',
22
+ 'r',
23
+ 's',
24
+ 't',
25
+ 'u',
26
+ 'v',
27
+ 'w',
28
+ 'x',
29
+ 'y',
30
+ 'z',
31
+ ];
32
+ exports.lowerAlpha = ['lower-alpha', 'lower-latin'];
33
+ exports.upperAlpha = ['upper-alpha', 'upper-latin'];
34
+ //# sourceMappingURL=ordered.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordered.type.js","sourceRoot":"","sources":["../src/ordered.type.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG;IAC1B,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;CACJ,CAAC;AAEW,QAAA,UAAU,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAC5C,QAAA,UAAU,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC","sourcesContent":["export const orderedAlpha = [\n 'a',\n 'b',\n 'c',\n 'd',\n 'e',\n 'f',\n 'g',\n 'h',\n 'i',\n 'j',\n 'k',\n 'l',\n 'n',\n 'm',\n 'o',\n 'p',\n 'q',\n 'r',\n 's',\n 't',\n 'u',\n 'v',\n 'w',\n 'x',\n 'y',\n 'z',\n];\n\nexport const lowerAlpha = ['lower-alpha', 'lower-latin'];\nexport const upperAlpha = ['upper-alpha', 'upper-latin'];\n"]}
@@ -0,0 +1,23 @@
1
+ import { HTMLElement, Node as HTMLNode } from 'node-html-parser';
2
+ import { Tag } from './tags';
3
+ import { Block } from 'css-tree';
4
+ import { HtmlStyle, HtmlStyles } from './styles';
5
+ export type HtmlContent = (HtmlElement | string)[];
6
+ export type HtmlElement = HTMLElement & {
7
+ tag: Tag | 'string';
8
+ parentNode: HtmlElement;
9
+ style: HtmlStyle[];
10
+ content: HtmlContent;
11
+ indexOfType: number;
12
+ querySelectorAll: (selector: string) => HtmlElement[];
13
+ querySelector: (selector: string) => HtmlElement;
14
+ };
15
+ export declare const convertRule: (rule: Block, source?: string) => HtmlStyle;
16
+ export declare const convertStylesheet: (stylesheet: string) => HtmlStyles;
17
+ export declare const convertElementStyle: (styleAttr: string, tag: string) => HtmlStyle | undefined;
18
+ export declare const convertNode: (node: HTMLNode) => HtmlElement | string;
19
+ declare const parseHtml: (text: string) => {
20
+ stylesheets: HtmlStyles[];
21
+ rootElement: HtmlElement;
22
+ };
23
+ export default parseHtml;
package/dist/parse.js ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.convertNode = exports.convertElementStyle = exports.convertStylesheet = exports.convertRule = void 0;
7
+ const node_html_parser_1 = require("node-html-parser");
8
+ const css_tree_1 = __importDefault(require("css-tree"));
9
+ const supportedStyles_1 = __importDefault(require("./supportedStyles"));
10
+ const camelize = require('camelize');
11
+ const convertRule = (rule, source = 'style') => {
12
+ const declarations = rule.children
13
+ .filter((declaration) => declaration.type === 'Declaration')
14
+ .toArray();
15
+ return declarations
16
+ .map((entry) => (Object.assign(Object.assign({}, entry), { property: camelize(entry.property) })))
17
+ .reduce((style, { property, value }) => {
18
+ let valueString = css_tree_1.default.generate(value);
19
+ if (property && value) {
20
+ if (property === 'fontFamily') {
21
+ valueString = valueString.replace(/["']+/g, '');
22
+ if (valueString.includes(',')) {
23
+ const reduced = valueString.split(',', 2)[0];
24
+ console.warn(`react-pdf doesn't support fontFamily lists like "${valueString}". Reducing to "${reduced}".`);
25
+ return style;
26
+ }
27
+ }
28
+ else if (!supportedStyles_1.default.includes(property)) {
29
+ if ((property === 'background' &&
30
+ /^#?[a-zA-Z0-9]+$/.test(valueString)) ||
31
+ /^rgba?\([0-9, ]+\)$/i.test(valueString) ||
32
+ /^hsla?\([0-9.%, ]+\)$/i.test(valueString)) {
33
+ property = 'backgroundColor';
34
+ }
35
+ else {
36
+ console.warn(`${source}: Found unsupported style "${property}"`, {
37
+ property,
38
+ value,
39
+ });
40
+ return style;
41
+ }
42
+ }
43
+ if (property == 'border' && valueString == 'none')
44
+ valueString = '0';
45
+ style[property] = valueString;
46
+ }
47
+ return style;
48
+ }, {});
49
+ };
50
+ exports.convertRule = convertRule;
51
+ const convertStylesheet = (stylesheet) => {
52
+ const response = {};
53
+ try {
54
+ const parsed = css_tree_1.default.parse(stylesheet);
55
+ const rules = parsed.children.filter((rule) => { var _a; return rule.type === 'Rule' && ((_a = rule.prelude) === null || _a === void 0 ? void 0 : _a.type) === 'SelectorList'; });
56
+ rules.forEach((rule) => {
57
+ const style = (0, exports.convertRule)(rule.block);
58
+ if (rule.prelude.type !== 'SelectorList') {
59
+ return;
60
+ }
61
+ rule.prelude.children.forEach((selector) => {
62
+ const selectorString = css_tree_1.default.generate(selector);
63
+ response[selectorString] = style;
64
+ });
65
+ });
66
+ }
67
+ catch (e) {
68
+ console.error(`Error parsing stylesheet: "${stylesheet}"`, e);
69
+ }
70
+ return response;
71
+ };
72
+ exports.convertStylesheet = convertStylesheet;
73
+ const convertElementStyle = (styleAttr, tag) => {
74
+ try {
75
+ const parsed = css_tree_1.default.parse(`${tag} { ${styleAttr} }`);
76
+ const rules = parsed.children.filter((rule) => { var _a; return rule.type === 'Rule' && ((_a = rule.prelude) === null || _a === void 0 ? void 0 : _a.type) === 'SelectorList'; });
77
+ const firstRule = rules.first();
78
+ return firstRule ? (0, exports.convertRule)(firstRule.block, tag) : undefined;
79
+ }
80
+ catch (e) {
81
+ console.error(`Error parsing style attribute "${styleAttr}" for tag: ${tag}`, e);
82
+ }
83
+ };
84
+ exports.convertElementStyle = convertElementStyle;
85
+ const convertNode = (node) => {
86
+ if (node.nodeType === node_html_parser_1.NodeType.TEXT_NODE) {
87
+ return node.rawText;
88
+ }
89
+ if (node.nodeType === node_html_parser_1.NodeType.COMMENT_NODE) {
90
+ return '';
91
+ }
92
+ if (node.nodeType !== node_html_parser_1.NodeType.ELEMENT_NODE) {
93
+ throw new Error('Not sure what this is');
94
+ }
95
+ const html = node;
96
+ const content = html.childNodes.map(exports.convertNode);
97
+ const kindCounters = {};
98
+ content.forEach((child) => {
99
+ if (typeof child !== 'string') {
100
+ child.indexOfType =
101
+ child.tag in kindCounters
102
+ ? (kindCounters[child.tag] = kindCounters[child.tag] + 1)
103
+ : (kindCounters[child.tag] = 0);
104
+ }
105
+ });
106
+ let style;
107
+ if (html.attributes.style && html.attributes.style.trim()) {
108
+ style = (0, exports.convertElementStyle)(html.attributes.style, html.tagName);
109
+ }
110
+ return Object.assign(html, {
111
+ tag: (html.tagName || '').toLowerCase(),
112
+ style: style ? [style] : [],
113
+ content,
114
+ indexOfType: 0,
115
+ });
116
+ };
117
+ exports.convertNode = convertNode;
118
+ const parseHtml = (text) => {
119
+ const html = (0, node_html_parser_1.parse)(text, { comment: false });
120
+ const stylesheets = html
121
+ .querySelectorAll('style')
122
+ .map((styleNode) => styleNode.childNodes.map((textNode) => textNode.rawText.trim()).join('\n'))
123
+ .filter((styleText) => !!styleText)
124
+ .map(exports.convertStylesheet);
125
+ return {
126
+ stylesheets,
127
+ rootElement: (0, exports.convertNode)(html),
128
+ };
129
+ };
130
+ exports.default = parseHtml;
131
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n HTMLElement,\n Node as HTMLNode,\n NodeType,\n parse,\n TextNode,\n} from 'node-html-parser';\nimport { Tag } from './tags';\nimport cssTree, { Block, Declaration, List, Rule, StyleSheet } from 'css-tree';\nimport supportedStyles from './supportedStyles';\nimport { HtmlStyle, HtmlStyles } from './styles';\nconst camelize = require('camelize');\n\nexport type HtmlContent = (HtmlElement | string)[];\n\nexport type HtmlElement = HTMLElement & {\n tag: Tag | 'string';\n parentNode: HtmlElement;\n style: HtmlStyle[];\n content: HtmlContent;\n indexOfType: number;\n querySelectorAll: (selector: string) => HtmlElement[];\n querySelector: (selector: string) => HtmlElement;\n};\n\nexport const convertRule = (\n rule: Block,\n source: string = 'style'\n): HtmlStyle => {\n const declarations = rule.children\n .filter((declaration) => declaration.type === 'Declaration')\n .toArray() as Declaration[];\n\n return declarations\n .map((entry) => ({\n ...entry,\n property: camelize(entry.property as string),\n }))\n .reduce((style, { property, value }: Declaration) => {\n let valueString = cssTree.generate(value);\n if (property && value) {\n if (property === 'fontFamily') {\n valueString = valueString.replace(/[\"']+/g, '');\n if (valueString.includes(',')) {\n const reduced = valueString.split(',', 2)[0];\n console.warn(\n `react-pdf doesn't support fontFamily lists like \"${valueString}\". Reducing to \"${reduced}\".`\n );\n return style;\n }\n } else if (!supportedStyles.includes(property)) {\n if (\n (property === 'background' &&\n /^#?[a-zA-Z0-9]+$/.test(valueString)) ||\n /^rgba?\\([0-9, ]+\\)$/i.test(valueString) ||\n /^hsla?\\([0-9.%, ]+\\)$/i.test(valueString)\n ) {\n property = 'backgroundColor';\n } else {\n console.warn(`${source}: Found unsupported style \"${property}\"`, {\n property,\n value,\n });\n return style;\n }\n }\n\n if (property == 'border' && valueString == 'none') valueString = '0';\n style[property as keyof HtmlStyle] = valueString;\n }\n return style;\n }, {} as HtmlStyle);\n};\n\nexport const convertStylesheet = (stylesheet: string): HtmlStyles => {\n const response = {} as HtmlStyles;\n try {\n const parsed = cssTree.parse(stylesheet) as StyleSheet;\n const rules = parsed.children.filter(\n (rule) => rule.type === 'Rule' && rule.prelude?.type === 'SelectorList'\n ) as List<Rule>;\n rules.forEach((rule) => {\n const style = convertRule(rule.block);\n if (rule.prelude.type !== 'SelectorList') {\n return;\n }\n rule.prelude.children.forEach((selector) => {\n const selectorString = cssTree.generate(selector);\n response[selectorString] = style;\n });\n });\n } catch (e) {\n console.error(`Error parsing stylesheet: \"${stylesheet}\"`, e);\n }\n return response;\n};\n\nexport const convertElementStyle = (\n styleAttr: string,\n tag: string\n): HtmlStyle | undefined => {\n try {\n const parsed = cssTree.parse(`${tag} { ${styleAttr} }`) as StyleSheet;\n const rules = parsed.children.filter(\n (rule) => rule.type === 'Rule' && rule.prelude?.type === 'SelectorList'\n ) as List<Rule>;\n const firstRule = rules.first();\n return firstRule ? convertRule(firstRule.block, tag) : undefined;\n } catch (e) {\n console.error(\n `Error parsing style attribute \"${styleAttr}\" for tag: ${tag}`,\n e\n );\n }\n};\n\nexport const convertNode = (node: HTMLNode): HtmlElement | string => {\n if (node.nodeType === NodeType.TEXT_NODE) {\n return (node as TextNode).rawText;\n }\n if (node.nodeType === NodeType.COMMENT_NODE) {\n return '';\n }\n if (node.nodeType !== NodeType.ELEMENT_NODE) {\n throw new Error('Not sure what this is');\n }\n const html = node as HTMLElement;\n const content = html.childNodes.map(convertNode);\n const kindCounters: Record<string, number> = {};\n content.forEach((child) => {\n if (typeof child !== 'string') {\n child.indexOfType =\n child.tag in kindCounters\n ? (kindCounters[child.tag] = kindCounters[child.tag] + 1)\n : (kindCounters[child.tag] = 0);\n }\n });\n\n let style: HtmlStyle | undefined;\n if (html.attributes.style && html.attributes.style.trim()) {\n style = convertElementStyle(html.attributes.style, html.tagName);\n }\n\n return Object.assign(html, {\n tag: (html.tagName || '').toLowerCase() as Tag | string,\n style: style ? [style] : [],\n content,\n indexOfType: 0,\n }) as HtmlElement;\n};\n\nconst parseHtml = (\n text: string\n): { stylesheets: HtmlStyles[]; rootElement: HtmlElement } => {\n const html = parse(text, { comment: false });\n const stylesheets = html\n .querySelectorAll('style')\n .map((styleNode) =>\n styleNode.childNodes.map((textNode) => textNode.rawText.trim()).join('\\n')\n )\n .filter((styleText) => !!styleText)\n .map(convertStylesheet);\n return {\n stylesheets,\n rootElement: convertNode(html) as HtmlElement,\n };\n};\n\nexport default parseHtml;\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.js","sourceRoot":"","sources":["../src/parse.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import parseHtml, {\n convertElementStyle,\n convertStylesheet,\n HtmlElement,\n} from './parse';\n\ndescribe('parse', () => {\n describe('convertStylesheet', () => {\n it('Should convert CSS into HtmlStyles', () => {\n const content = `.my-heading4, #foobar, div > li {\n background: darkgreen;\n color: white;\n }\n div {\n span {\n fontWeight: bold;\n }\n }\n pre {\n background-color: #eee;\n padding: 10px;\n }`;\n\n const result = convertStylesheet(content);\n const expected = {\n '.my-heading4': {\n backgroundColor: 'darkgreen',\n color: 'white',\n },\n '#foobar': {\n backgroundColor: 'darkgreen',\n color: 'white',\n },\n div: {\n // TODO: support nested styles\n },\n 'div>li': {\n backgroundColor: 'darkgreen',\n color: 'white',\n },\n pre: {\n backgroundColor: '#eee',\n padding: '10px',\n },\n };\n\n expect(result).toEqual(expected);\n });\n\n it('Should handle empty', () => {\n const content = ``;\n\n const result = convertStylesheet(content);\n const expected = {};\n\n expect(result).toEqual(expected);\n });\n });\n\n describe('convertElementStyle', () => {\n it('Should convert element CSS into HtmlStyle', () => {\n const content = `background: darkgreen;color: white;bogus: nope`;\n\n const result = convertElementStyle(content, 'div');\n const expected = {\n backgroundColor: 'darkgreen',\n bogus: 'nope',\n color: 'white',\n };\n\n expect(result).toEqual(expected);\n });\n\n it('Should handle empty', () => {\n const content = ``;\n\n const result = convertElementStyle(content, 'div');\n const expected = {};\n\n expect(result).toEqual(expected);\n });\n });\n\n describe('parseHtml', () => {\n it('Should convert HTML into a JSON tree', () => {\n const content = `\nWelcome to your <b>doom!</b>:\n<p>\n <ul>\n <li>First item</li>\n <li>Second item: <a href=\"http://google.com\">google.com</a></li>\n </ul>\n</p>\n `;\n\n const result = parseHtml(content);\n const root = result.rootElement;\n expect(root.content[0]).toEqual('\\nWelcome to your ');\n expect((root.content[1] as HtmlElement).tag).toEqual('b');\n expect((root.content[1] as HtmlElement).content).toEqual(['doom!']);\n expect(root.content[2]).toEqual(':\\n');\n\n const paragraph = root.content[3] as HtmlElement;\n expect(paragraph.tag).toEqual('p');\n expect(paragraph.content[0]).toEqual('\\n ');\n\n const list = paragraph.content[1] as HtmlElement;\n expect(list.tag).toEqual('ul');\n\n const listItem1 = list.content[1] as HtmlElement;\n expect(listItem1.tag).toBe('li');\n expect(listItem1.content).toEqual(['First item']);\n expect(listItem1.indexOfType).toEqual(0);\n\n const listItem2 = list.content[3] as HtmlElement;\n expect(listItem2.tag).toBe('li');\n expect(listItem2.content[0]).toEqual('Second item: ');\n expect(listItem2.indexOfType).toEqual(1);\n\n const link = listItem2.content[1] as HtmlElement;\n expect(link.tag).toBe('a');\n expect(link.attributes.href).toBe('http://google.com');\n expect(link.content).toEqual(['google.com']);\n });\n });\n});\n"]}
@@ -0,0 +1,45 @@
1
+ import React, { ReactElement } from 'react';
2
+ import renderers from './renderers';
3
+ import { HtmlContent, HtmlElement } from './parse';
4
+ import { HtmlStyle, HtmlStyles } from './styles';
5
+ import { Style } from '@react-pdf/types';
6
+ import { Tag } from './tags';
7
+ export type HtmlRenderer = React.FC<React.PropsWithChildren<{
8
+ element: HtmlElement;
9
+ style: Style[];
10
+ stylesheets: HtmlStyles[];
11
+ }>>;
12
+ export type HtmlRenderers = Record<Tag | string, HtmlRenderer>;
13
+ export type HtmlRenderOptions = {
14
+ collapse: boolean;
15
+ renderers: HtmlRenderers;
16
+ stylesheets: HtmlStyles[];
17
+ resetStyles: boolean;
18
+ };
19
+ type ContentBucket = {
20
+ hasBlock: boolean;
21
+ content: HtmlContent;
22
+ };
23
+ export declare const isBlockStyle: (style: HtmlStyle) => boolean;
24
+ export declare const hasBlockContent: (element: HtmlElement | string) => boolean;
25
+ /**
26
+ * Groups all block and non-block elements into buckets so that all non-block elements can be rendered in a parent Text element
27
+ * @param elements Elements to place in buckets of block and non-block content
28
+ * @param collapse
29
+ * @param parentTag
30
+ */
31
+ export declare const bucketElements: (elements: HtmlContent, collapse: boolean, parentTag?: Tag | string) => ContentBucket[];
32
+ type RenderedContent = ReactElement | ReactElement[] | string | string[];
33
+ export declare const renderElement: (element: HtmlElement | string, stylesheets: HtmlStyles[], renderers: HtmlRenderers, children?: any, index?: number) => RenderedContent;
34
+ export declare const collapseWhitespace: (string: any) => string;
35
+ export declare const renderBucketElement: (element: HtmlElement | string, options: HtmlRenderOptions, index: number) => RenderedContent;
36
+ export declare const renderElements: (elements: HtmlContent, options: HtmlRenderOptions, parent?: HtmlElement) => RenderedContent | RenderedContent[];
37
+ export declare const applyStylesheets: (stylesheets: HtmlStyles[], rootElement: HtmlElement) => void;
38
+ declare const renderHtml: (text: string, options?: {
39
+ collapse?: boolean;
40
+ renderers?: HtmlRenderers;
41
+ style?: Style | (Style | undefined)[];
42
+ stylesheet?: HtmlStyles | HtmlStyles[];
43
+ resetStyles?: boolean;
44
+ }) => ReactElement;
45
+ export default renderHtml;