jspdf-md-renderer 1.2.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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/enums/mdTokenType.d.ts +18 -0
  4. package/dist/enums/mdTokenType.js +19 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.js +3 -0
  7. package/dist/parser/MdTextParser.d.ts +8 -0
  8. package/dist/parser/MdTextParser.js +91 -0
  9. package/dist/renderer/MdTextRender.d.ts +10 -0
  10. package/dist/renderer/MdTextRender.js +57 -0
  11. package/dist/renderer/components/heading.d.ts +8 -0
  12. package/dist/renderer/components/heading.js +18 -0
  13. package/dist/renderer/components/index.d.ts +5 -0
  14. package/dist/renderer/components/index.js +5 -0
  15. package/dist/renderer/components/list.d.ts +5 -0
  16. package/dist/renderer/components/list.js +12 -0
  17. package/dist/renderer/components/listItem.d.ts +5 -0
  18. package/dist/renderer/components/listItem.js +32 -0
  19. package/dist/renderer/components/paragraph.d.ts +8 -0
  20. package/dist/renderer/components/paragraph.js +44 -0
  21. package/dist/renderer/components/rawItem.d.ts +5 -0
  22. package/dist/renderer/components/rawItem.js +16 -0
  23. package/dist/types/index.d.ts +2 -0
  24. package/dist/types/index.js +2 -0
  25. package/dist/types/parsedElement.d.ts +20 -0
  26. package/dist/types/parsedElement.js +1 -0
  27. package/dist/types/renderOption.d.ts +37 -0
  28. package/dist/types/renderOption.js +1 -0
  29. package/dist/types/wordInfo.d.ts +4 -0
  30. package/dist/types/wordInfo.js +1 -0
  31. package/dist/utils/doc-helpers.d.ts +3 -0
  32. package/dist/utils/doc-helpers.js +3 -0
  33. package/dist/utils/handlePageBreak.d.ts +6 -0
  34. package/dist/utils/handlePageBreak.js +11 -0
  35. package/dist/utils/justifyText.d.ts +15 -0
  36. package/dist/utils/justifyText.js +53 -0
  37. package/package.json +63 -0
  38. package/src/enums/mdTokenType.ts +18 -0
  39. package/src/index.ts +4 -0
  40. package/src/parser/MdTextParser.ts +98 -0
  41. package/src/renderer/MdTextRender.ts +110 -0
  42. package/src/renderer/components/heading.ts +30 -0
  43. package/src/renderer/components/index.ts +5 -0
  44. package/src/renderer/components/list.ts +28 -0
  45. package/src/renderer/components/listItem.ts +62 -0
  46. package/src/renderer/components/paragraph.ts +79 -0
  47. package/src/renderer/components/rawItem.ts +35 -0
  48. package/src/types/index.ts +2 -0
  49. package/src/types/parsedElement.ts +15 -0
  50. package/src/types/renderOption.ts +38 -0
  51. package/src/types/wordInfo.ts +4 -0
  52. package/src/utils/doc-helpers.ts +6 -0
  53. package/src/utils/handlePageBreak.ts +13 -0
  54. package/src/utils/justifyText.ts +103 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jeel Gajera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # jsPDF Markdown Renderer
2
+
3
+ A jsPDF utility to render Markdown directly into formatted PDFs with custom designs.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Usage](#usage)
9
+ - [API](#api)
10
+ - [Examples](#examples)
11
+ - [Contributing](#contributing)
12
+ - [License](#license)
13
+
14
+ ## Installation
15
+
16
+ To install the library, you can use npm:
17
+
18
+ ```sh
19
+ npm install jspdf-md-renderer
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Basic Example
25
+
26
+ Here is a basic example of how to use the library to generate a PDF from Markdown content:
27
+
28
+ ```ts
29
+ import { jsPDF } from 'jspdf';
30
+ import { MdTextRender } from 'jspdf-md-renderer';
31
+
32
+ const mdString = `
33
+ # Main Title
34
+
35
+ This is a brief introduction paragraph. It sets the tone for the document and introduces the main topic in a concise manner.
36
+
37
+ ## Section 1: Overview
38
+
39
+ Here is a medium-length paragraph that goes into more detail about the first section. It explains the context, provides background information, and sets up the discussion for the subsections.
40
+
41
+ ## Section 2: Lists and Examples
42
+
43
+ This section showcases how to create simple and nested lists.
44
+
45
+ ### Simple List
46
+
47
+ - Item 1
48
+ - Item 2
49
+ - Item 3
50
+
51
+ ### Nested List
52
+
53
+ 1. First Level 1
54
+ - First Level 2
55
+ - First Level 3
56
+ 2. Second Level 1
57
+ - Second Level 2
58
+ - Another Second Level 2
59
+ - Nested deeper
60
+
61
+ ### Mixed List Example
62
+
63
+ - Topic 1
64
+ 1. Subtopic 1.1
65
+ 2. Subtopic 1.2
66
+ - Topic 2
67
+ - Subtopic 2.1
68
+ - Subtopic 2.2
69
+ 1. Nested Subtopic 2.2.1
70
+ 2. Nested Subtopic 2.2.2
71
+
72
+ `;
73
+
74
+ const generatePDF = async () => {
75
+ const doc = new jsPDF({
76
+ unit: 'mm',
77
+ format: 'a4',
78
+ orientation: 'portrait',
79
+ });
80
+
81
+ const options = {
82
+ cursor: { x: 10, y: 10 },
83
+ page: {
84
+ format: 'a4',
85
+ unit: 'mm',
86
+ orientation: 'portrait',
87
+ maxContentWidth: 190,
88
+ maxContentHeight: 277,
89
+ lineSpace: 1.5,
90
+ defaultLineHeightFactor: 1.2,
91
+ defaultFontSize: 12,
92
+ defaultTitleFontSize: 14,
93
+ topmargin: 10,
94
+ xpading: 10,
95
+ xmargin: 10,
96
+ indent: 10,
97
+ },
98
+ font: {
99
+ bold: { name: 'helvetica', style: 'bold' },
100
+ regular: { name: 'helvetica', style: 'normal' },
101
+ light: { name: 'helvetica', style: 'light' },
102
+ },
103
+ endCursorYHandler: (y) => {
104
+ console.log('End cursor Y position:', y);
105
+ },
106
+ };
107
+
108
+ await MdTextRender(doc, mdString, options);
109
+ doc.save('example.pdf');
110
+ };
111
+
112
+ generatePDF();
113
+ ```
114
+
115
+ ## API
116
+
117
+ ### `MdTextRender`
118
+
119
+ Renders parsed markdown text into a jsPDF document.
120
+
121
+ #### Parameters
122
+
123
+ - `doc`: The jsPDF document instance.
124
+ - `text`: The markdown content to render.
125
+ - `options`: The render options (fonts, page margins, etc.).
126
+
127
+ ### `MdTextParser`
128
+
129
+ Parses markdown into tokens and converts to a custom parsed structure.
130
+
131
+ #### Parameters
132
+
133
+ - `text`: The markdown content to parse.
134
+
135
+ #### Returns
136
+
137
+ - `Promise<ParsedElement[]>`: Parsed markdown elements.
138
+
139
+
140
+ ## Supported Markdown Elements
141
+
142
+ The following Markdown elements are currently supported by `jspdf-md-renderer`:
143
+
144
+ - **Headings**: `#`, `##`, `###`, etc.
145
+ - **Paragraphs**
146
+ - **Lists**:
147
+ - Unordered lists: `-`, `*`, `+`
148
+ - Ordered lists: `1.`, `2.`, `3.`, etc.
149
+
150
+
151
+ ## Examples
152
+
153
+ You can find more examples in the [examples](examples/test-pdf-gen) directory.
154
+
155
+ ## Contributing
156
+
157
+ Contributions are welcome! Please read the [contributing guidelines](CONTRIBUTING.md) first.
158
+
159
+ ## License
160
+
161
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,18 @@
1
+ export declare enum MdTokenType {
2
+ Heading = "heading",
3
+ Paragraph = "paragraph",
4
+ List = "list",
5
+ ListItem = "list_item",
6
+ Blockquote = "blockquote",
7
+ Code = "code",
8
+ Table = "table",
9
+ Html = "html",
10
+ Hr = "hr",
11
+ Image = "image",
12
+ Link = "link",
13
+ Strong = "strong",
14
+ Em = "em",
15
+ TableHeader = "table_header",
16
+ TableCell = "table_cell",
17
+ Raw = "raw"
18
+ }
@@ -0,0 +1,19 @@
1
+ export var MdTokenType;
2
+ (function (MdTokenType) {
3
+ MdTokenType["Heading"] = "heading";
4
+ MdTokenType["Paragraph"] = "paragraph";
5
+ MdTokenType["List"] = "list";
6
+ MdTokenType["ListItem"] = "list_item";
7
+ MdTokenType["Blockquote"] = "blockquote";
8
+ MdTokenType["Code"] = "code";
9
+ MdTokenType["Table"] = "table";
10
+ MdTokenType["Html"] = "html";
11
+ MdTokenType["Hr"] = "hr";
12
+ MdTokenType["Image"] = "image";
13
+ MdTokenType["Link"] = "link";
14
+ MdTokenType["Strong"] = "strong";
15
+ MdTokenType["Em"] = "em";
16
+ MdTokenType["TableHeader"] = "table_header";
17
+ MdTokenType["TableCell"] = "table_cell";
18
+ MdTokenType["Raw"] = "raw";
19
+ })(MdTokenType || (MdTokenType = {}));
@@ -0,0 +1,3 @@
1
+ import { MdTextRender } from './renderer/MdTextRender';
2
+ import { MdTextParser } from './parser/MdTextParser';
3
+ export { MdTextRender, MdTextParser };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { MdTextRender } from './renderer/MdTextRender';
2
+ import { MdTextParser } from './parser/MdTextParser';
3
+ export { MdTextRender, MdTextParser };
@@ -0,0 +1,8 @@
1
+ import { ParsedElement } from '../types/parsedElement';
2
+ /**
3
+ * Parses markdown into tokens and converts to a custom parsed structure.
4
+ *
5
+ * @param text - The markdown content to parse.
6
+ * @returns Parsed markdown elements.
7
+ */
8
+ export declare const MdTextParser: (text: string) => Promise<ParsedElement[]>;
@@ -0,0 +1,91 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { marked } from 'marked';
3
+ import { MdTokenType } from '../enums/mdTokenType';
4
+ /**
5
+ * Parses markdown into tokens and converts to a custom parsed structure.
6
+ *
7
+ * @param text - The markdown content to parse.
8
+ * @returns Parsed markdown elements.
9
+ */
10
+ export const MdTextParser = async (text) => {
11
+ const tokens = await marked.lexer(text, { async: true });
12
+ return convertTokens(tokens);
13
+ };
14
+ /**
15
+ * Convert the markdown tokens to ParsedElements.
16
+ *
17
+ * @param tokens - The list of markdown tokens.
18
+ * @returns Parsed elements in a custom structure.
19
+ */
20
+ const convertTokens = (tokens) => {
21
+ const parsedElements = [];
22
+ tokens.forEach((token) => {
23
+ const handler = tokenHandlers[token.type];
24
+ if (handler) {
25
+ parsedElements.push(handler(token));
26
+ }
27
+ else {
28
+ parsedElements.push({ type: MdTokenType.Raw, content: token.raw });
29
+ }
30
+ });
31
+ return parsedElements.map((element) => element.type === MdTokenType.Raw && element.content === '\n\n'
32
+ ? { ...element, content: element.content.replace('\n\n', '\n') }
33
+ : element);
34
+ };
35
+ /**
36
+ * Map each token type to its handler function.
37
+ */
38
+ const tokenHandlers = {
39
+ [MdTokenType.Heading]: (token) => ({
40
+ type: MdTokenType.Heading,
41
+ depth: token.depth,
42
+ content: token.text,
43
+ }),
44
+ [MdTokenType.Paragraph]: (token) => ({
45
+ type: MdTokenType.Paragraph,
46
+ content: token.text,
47
+ }),
48
+ [MdTokenType.List]: (token) => ({
49
+ type: MdTokenType.List,
50
+ items: token.items ? convertTokens(token.items) : [],
51
+ }),
52
+ [MdTokenType.ListItem]: (token) => ({
53
+ type: MdTokenType.ListItem,
54
+ content: token.text,
55
+ items: token.tokens ? convertTokens(token.tokens) : [],
56
+ }),
57
+ [MdTokenType.Code]: (token) => ({
58
+ type: MdTokenType.Code,
59
+ lang: token.lang,
60
+ code: token.text,
61
+ }),
62
+ [MdTokenType.Table]: (token) => ({
63
+ type: MdTokenType.Table,
64
+ header: token.header.map((header) => ({
65
+ type: MdTokenType.TableHeader,
66
+ content: header,
67
+ })),
68
+ rows: token.rows.map((row) => row.map((cell) => ({
69
+ type: MdTokenType.TableCell,
70
+ content: cell,
71
+ }))),
72
+ }),
73
+ [MdTokenType.Image]: (token) => ({
74
+ type: MdTokenType.Image,
75
+ src: token.href,
76
+ alt: token.text,
77
+ }),
78
+ [MdTokenType.Link]: (token) => ({
79
+ type: MdTokenType.Link,
80
+ href: token.href,
81
+ text: token.text,
82
+ }),
83
+ [MdTokenType.Strong]: (token) => ({
84
+ type: MdTokenType.Strong,
85
+ content: token.text,
86
+ }),
87
+ [MdTokenType.Em]: (token) => ({
88
+ type: MdTokenType.Em,
89
+ content: token.text,
90
+ }),
91
+ };
@@ -0,0 +1,10 @@
1
+ import jsPDF from 'jspdf';
2
+ import { RenderOption } from '../types/renderOption';
3
+ /**
4
+ * Renders parsed markdown text into jsPDF document.
5
+ *
6
+ * @param doc - The jsPDF document.
7
+ * @param text - The markdown content to render.
8
+ * @param options - The render options (fonts, page margins, etc.).
9
+ */
10
+ export declare const MdTextRender: (doc: jsPDF, text: string, options: RenderOption) => Promise<void>;
@@ -0,0 +1,57 @@
1
+ import { MdTokenType } from '../enums/mdTokenType';
2
+ import { MdTextParser } from '../parser/MdTextParser';
3
+ import { HandlePageBreaks } from '../utils/handlePageBreak';
4
+ import { renderHeading, renderList, renderListItem, renderParagraph, renderRawItem, } from './components';
5
+ import { getCharHight } from '../utils/doc-helpers';
6
+ /**
7
+ * Renders parsed markdown text into jsPDF document.
8
+ *
9
+ * @param doc - The jsPDF document.
10
+ * @param text - The markdown content to render.
11
+ * @param options - The render options (fonts, page margins, etc.).
12
+ */
13
+ export const MdTextRender = async (doc, text, options) => {
14
+ const parsedElements = await MdTextParser(text);
15
+ console.log(parsedElements);
16
+ console.log(doc);
17
+ let y = options.cursor.y;
18
+ const x = options.cursor.x;
19
+ const renderElement = (element, indentLevel = 0, hasRawBullet = false) => {
20
+ const indent = indentLevel * options.page.indent;
21
+ if (y +
22
+ doc.splitTextToSize(element.content ?? '', options.page.maxContentWidth - indent).length *
23
+ getCharHight(doc, options) >=
24
+ options.page.maxContentHeight) {
25
+ HandlePageBreaks(doc, options);
26
+ y = options.page.topmargin;
27
+ }
28
+ switch (element.type) {
29
+ case MdTokenType.Heading:
30
+ y = renderHeading(doc, element, x, y, indent, options);
31
+ break;
32
+ case MdTokenType.Paragraph:
33
+ y = renderParagraph(doc, element, x, y, indent, options);
34
+ break;
35
+ case MdTokenType.List:
36
+ y = renderList(doc, element, y, indentLevel, options, renderElement);
37
+ break;
38
+ case MdTokenType.ListItem:
39
+ y = renderListItem(doc, element, x, y, indentLevel, options, renderElement);
40
+ break;
41
+ case MdTokenType.Raw:
42
+ y = renderRawItem(doc, element, x, y, indentLevel, hasRawBullet, options);
43
+ break;
44
+ default:
45
+ console.warn(`Warning: Unsupported element type encountered: ${element.type}.
46
+ If you believe this element type should be supported, please create an issue at:
47
+ https://github.com/JeelGajera/jspdf-md-renderer/issues
48
+ with details of the element and expected behavior. Thank you for helping improve this library!`);
49
+ break;
50
+ }
51
+ return y;
52
+ };
53
+ for (const item of parsedElements) {
54
+ renderElement(item);
55
+ }
56
+ options.endCursorYHandler(y);
57
+ };
@@ -0,0 +1,8 @@
1
+ import jsPDF from 'jspdf';
2
+ import { ParsedElement } from '../../types/parsedElement';
3
+ import { RenderOption } from '../../types/renderOption';
4
+ /**
5
+ * Renders heading elements.
6
+ */
7
+ declare const renderHeading: (doc: jsPDF, element: ParsedElement, x: number, y: number, indent: number, options: RenderOption) => number;
8
+ export default renderHeading;
@@ -0,0 +1,18 @@
1
+ import { getCharHight } from '../../utils/doc-helpers';
2
+ /**
3
+ * Renders heading elements.
4
+ */
5
+ const renderHeading = (doc, element, x, y, indent, options) => {
6
+ const size = 6 - (element?.depth ?? 0) > 0 ? 6 - (element?.depth ?? 0) : 0;
7
+ // doc.setFont(options.font.regular.name, options.font.regular.style);
8
+ doc.setFontSize(options.page.defaultFontSize + size);
9
+ doc.text(element?.content ?? '', x + indent, y, {
10
+ align: 'left',
11
+ maxWidth: options.page.maxContentWidth - indent,
12
+ });
13
+ y += 1.5 * getCharHight(doc, options);
14
+ // doc.setFont(options.font.light.name, options.font.light.style);
15
+ doc.setFontSize(options.page.defaultFontSize);
16
+ return y;
17
+ };
18
+ export default renderHeading;
@@ -0,0 +1,5 @@
1
+ export { default as renderHeading } from './heading';
2
+ export { default as renderParagraph } from './paragraph';
3
+ export { default as renderList } from './list';
4
+ export { default as renderListItem } from './listItem';
5
+ export { default as renderRawItem } from './rawItem';
@@ -0,0 +1,5 @@
1
+ export { default as renderHeading } from './heading';
2
+ export { default as renderParagraph } from './paragraph';
3
+ export { default as renderList } from './list';
4
+ export { default as renderListItem } from './listItem';
5
+ export { default as renderRawItem } from './rawItem';
@@ -0,0 +1,5 @@
1
+ import jsPDF from 'jspdf';
2
+ import { ParsedElement } from '../../types/parsedElement';
3
+ import { RenderOption } from '../../types/renderOption';
4
+ declare const renderList: (doc: jsPDF, element: ParsedElement, y: number, indentLevel: number, options: RenderOption, parentElementRenderer: (element: ParsedElement, indentLevel: number, hasRawBullet?: boolean) => number) => number;
5
+ export default renderList;
@@ -0,0 +1,12 @@
1
+ import { getCharHight } from '../../utils/doc-helpers';
2
+ const renderList = (doc, element, y, indentLevel, options, parentElementRenderer) => {
3
+ doc.setFontSize(options.page.defaultFontSize);
4
+ // doc.setFont(options.font.light.name, options.font.light.style);
5
+ for (const point of element?.items ?? []) {
6
+ y =
7
+ parentElementRenderer(point, indentLevel + 1, true) +
8
+ getCharHight(doc, options) * 0.2; // Recursively render nested list items
9
+ }
10
+ return y;
11
+ };
12
+ export default renderList;
@@ -0,0 +1,5 @@
1
+ import jsPDF from 'jspdf';
2
+ import { ParsedElement } from '../../types/parsedElement';
3
+ import { RenderOption } from '../../types/renderOption';
4
+ declare const renderListItem: (doc: jsPDF, element: ParsedElement, x: number, y: number, indentLevel: number, options: RenderOption, parentElementRenderer: (element: ParsedElement, indentLevel: number, hasRawBullet?: boolean) => number) => number;
5
+ export default renderListItem;
@@ -0,0 +1,32 @@
1
+ import { justifyText } from '../../utils/justifyText';
2
+ import { HandlePageBreaks } from '../../utils/handlePageBreak';
3
+ import { getCharHight } from '../../utils/doc-helpers';
4
+ const renderListItem = (doc, element, x, y, indentLevel, options, parentElementRenderer) => {
5
+ const indent = indentLevel * options.page.indent;
6
+ if (y +
7
+ doc.splitTextToSize(element.content ?? '', options.page.maxContentWidth - indent).length *
8
+ getCharHight(doc, options) -
9
+ 2 * getCharHight(doc, options) >=
10
+ options.page.maxContentHeight) {
11
+ HandlePageBreaks(doc, options);
12
+ y = options.page.topmargin;
13
+ }
14
+ if (!element.items && element.content) {
15
+ const lineHeight = doc.getTextWidth(element.content) >
16
+ options.page.maxContentWidth - indent
17
+ ? options.page.defaultLineHeightFactor
18
+ : options.page.defaultLineHeightFactor + 0.4;
19
+ y =
20
+ justifyText(doc, '\u2022 ' + element.content, x + indent, y, options.page.maxContentWidth - indent, lineHeight) + getCharHight(doc, options);
21
+ }
22
+ // Recursively render nested items if they exist
23
+ if (element.items && element.items.length > 0) {
24
+ for (const subItem of element.items) {
25
+ y =
26
+ parentElementRenderer(subItem, indentLevel + 1, true) +
27
+ getCharHight(doc, options) * 0.2;
28
+ }
29
+ }
30
+ return y;
31
+ };
32
+ export default renderListItem;
@@ -0,0 +1,8 @@
1
+ import jsPDF from 'jspdf';
2
+ import { ParsedElement } from '../../types/parsedElement';
3
+ import { RenderOption } from '../../types/renderOption';
4
+ /**
5
+ * Renders paragraph elements.
6
+ */
7
+ declare const renderParagraph: (doc: jsPDF, element: ParsedElement, x: number, y: number, indent: number, options: RenderOption) => number;
8
+ export default renderParagraph;
@@ -0,0 +1,44 @@
1
+ import { justifyText } from '../../utils/justifyText';
2
+ import { HandlePageBreaks } from '../../utils/handlePageBreak';
3
+ import { getCharHight } from '../../utils/doc-helpers';
4
+ /**
5
+ * Renders paragraph elements.
6
+ */
7
+ const renderParagraph = (doc, element, x, y, indent, options) => {
8
+ doc.setFontSize(options.page.defaultFontSize);
9
+ // doc.setFont(options.font.light.name, options.font.light.style);
10
+ let content = element.content;
11
+ const lineHeight = doc.getTextDimensions('A').h * options.page.defaultLineHeightFactor;
12
+ if (y +
13
+ doc.splitTextToSize(content ?? '', options.page.maxContentWidth - indent).length *
14
+ lineHeight -
15
+ 3 * lineHeight >=
16
+ options.page.maxContentHeight) {
17
+ // ADD Possible text to Page bottom
18
+ const contentLeft = doc.splitTextToSize(content ?? '', options.page.maxContentWidth - indent);
19
+ const possibleContentLines = [];
20
+ const possibleContentY = y;
21
+ for (let j = 0; j < contentLeft.length; j++) {
22
+ if (y - 2 * lineHeight < options.page.maxContentHeight) {
23
+ possibleContentLines.push(contentLeft[j]);
24
+ y += options.page.lineSpace;
25
+ }
26
+ else {
27
+ // set left content to move next page
28
+ if (j <= contentLeft.length - 1) {
29
+ content = contentLeft.slice(j).join('');
30
+ }
31
+ break;
32
+ }
33
+ }
34
+ if (possibleContentLines.length > 0) {
35
+ y = justifyText(doc, possibleContentLines.join(' '), x + indent, possibleContentY, options.page.maxContentWidth - indent, options.page.defaultLineHeightFactor);
36
+ }
37
+ HandlePageBreaks(doc, options);
38
+ y = options.page.topmargin;
39
+ }
40
+ y =
41
+ justifyText(doc, content ?? '', x + indent, y, options.page.maxContentWidth - indent, options.page.defaultLineHeightFactor) + getCharHight(doc, options);
42
+ return y;
43
+ };
44
+ export default renderParagraph;
@@ -0,0 +1,5 @@
1
+ import jsPDF from 'jspdf';
2
+ import { ParsedElement } from '../../types/parsedElement';
3
+ import { RenderOption } from '../../types/renderOption';
4
+ declare const renderRawItem: (doc: jsPDF, element: ParsedElement, x: number, y: number, indentLevel: number, hasRawBullet: boolean, options: RenderOption) => number;
5
+ export default renderRawItem;
@@ -0,0 +1,16 @@
1
+ import { HandlePageBreaks } from '../../utils/handlePageBreak';
2
+ import { getCharHight } from '../../utils/doc-helpers';
3
+ const renderRawItem = (doc, element, x, y, indentLevel, hasRawBullet, options) => {
4
+ const indent = indentLevel * options.page.indent;
5
+ const bullet = hasRawBullet ? '\u2022 ' : ''; // unicode for bullet point
6
+ const lines = doc.splitTextToSize(bullet + element.content, options.page.maxContentWidth - indent);
7
+ if (y + lines.length * getCharHight(doc, options) >=
8
+ options.page.maxContentHeight) {
9
+ HandlePageBreaks(doc, options);
10
+ y = options.page.topmargin;
11
+ }
12
+ doc.text(lines, x + indent, y);
13
+ y += lines.length * getCharHight(doc, options);
14
+ return y;
15
+ };
16
+ export default renderRawItem;
@@ -0,0 +1,2 @@
1
+ export * from './parsedElement';
2
+ export * from './renderOption';
@@ -0,0 +1,2 @@
1
+ export * from './parsedElement';
2
+ export * from './renderOption';
@@ -0,0 +1,20 @@
1
+ export type ParsedElement = {
2
+ type: string;
3
+ content?: string;
4
+ depth?: number;
5
+ items?: ParsedElement[];
6
+ lang?: string;
7
+ code?: string;
8
+ src?: string;
9
+ alt?: string;
10
+ href?: string;
11
+ text?: string;
12
+ header?: {
13
+ type?: string;
14
+ content?: any;
15
+ };
16
+ rows?: {
17
+ type?: string;
18
+ content?: any;
19
+ };
20
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { jsPDFOptions } from 'jspdf';
2
+ export type RenderOption = {
3
+ cursor: {
4
+ x: number;
5
+ y: number;
6
+ };
7
+ page: {
8
+ format?: string | number[];
9
+ unit?: jsPDFOptions['unit'];
10
+ orientation?: jsPDFOptions['orientation'];
11
+ maxContentWidth: number;
12
+ maxContentHeight: number;
13
+ lineSpace: number;
14
+ defaultLineHeightFactor: number;
15
+ defaultFontSize: number;
16
+ defaultTitleFontSize: number;
17
+ topmargin: number;
18
+ xpading: number;
19
+ xmargin: number;
20
+ indent: number;
21
+ };
22
+ font: {
23
+ bold: FontItem;
24
+ regular: FontItem;
25
+ light: FontItem;
26
+ };
27
+ content?: {
28
+ textAlignment: 'left' | 'right' | 'center' | 'justify';
29
+ };
30
+ pageBreakHandler?: () => void;
31
+ endCursorYHandler: (y: number) => void;
32
+ };
33
+ type FontItem = {
34
+ name: string;
35
+ style: string;
36
+ };
37
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export type WordInfo = {
2
+ text: string;
3
+ wordLength: number;
4
+ };
@@ -0,0 +1 @@
1
+ export {};