Skip to content

Commit c18a0e9

Browse files
committed
fix(renderer): adjust long text rendering and indentation for list items and raw items
chore(deps): update dependencies - [globals, eslint-config-prettier]
1 parent 9f90ca1 commit c18a0e9

File tree

4 files changed

+159
-94
lines changed

4 files changed

+159
-94
lines changed

package.json

Lines changed: 66 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
11
{
2-
"name": "jspdf-md-renderer",
3-
"version": "1.6.0",
4-
"description": "A jsPDF utility to render Markdown directly into formatted PDFs with custom designs.",
5-
"main": "dist/index.js",
6-
"module": "dist/index.mjs",
7-
"types": "dist/index.d.ts",
8-
"exports": {
9-
".": {
10-
"import": "./dist/index.mjs",
11-
"require": "./dist/index.js",
12-
"types": "./dist/index.d.ts"
2+
"name": "jspdf-md-renderer",
3+
"version": "1.6.0",
4+
"description": "A jsPDF utility to render Markdown directly into formatted PDFs with custom designs.",
5+
"main": "dist/index.js",
6+
"module": "dist/index.mjs",
7+
"types": "dist/index.d.ts",
8+
"exports": {
9+
".": {
10+
"import": "./dist/index.mjs",
11+
"require": "./dist/index.js",
12+
"types": "./dist/index.d.ts"
13+
},
14+
"./types": "./dist/types/index.d.ts"
1315
},
14-
"./types": "./dist/types/index.d.ts"
15-
},
16-
"files": [
17-
"dist",
18-
"types",
19-
"LICENSE",
20-
"README.md"
21-
],
22-
"scripts": {
23-
"dev": "npm run format && npm run lint:fix && npm run build",
24-
"build": "rimraf dist && vite build",
25-
"lint": "eslint src/**",
26-
"lint:fix": "eslint src/** --fix",
27-
"format": "prettier --write .",
28-
"test": "echo \"Error: no test specified\" && exit 1",
29-
"prepare": "npm run build",
30-
"watch": "vite build --watch"
31-
},
32-
"repository": {
33-
"type": "git",
34-
"url": "git+https://github.com/JeelGajera/jspdf-md-renderer.git"
35-
},
36-
"keywords": [
37-
"jspdf",
38-
"markdown",
39-
"pdf",
40-
"renderer"
41-
],
42-
"author": "Jeel Gajera <jeelgajera200@gmail.com>",
43-
"license": "MIT",
44-
"bugs": {
45-
"url": "https://github.com/JeelGajera/jspdf-md-renderer/issues"
46-
},
47-
"homepage": "https://github.com/JeelGajera/jspdf-md-renderer#readme",
48-
"dependencies": {
49-
"jspdf": "^3.0.1",
50-
"jspdf-md-renderer": "file:",
51-
"marked": "^15.0.3"
52-
},
53-
"devDependencies": {
54-
"@eslint/js": "^9.16.0",
55-
"@types/node": "^22.10.2",
56-
"@typescript-eslint/eslint-plugin": "^8.18.0",
57-
"@typescript-eslint/parser": "^8.18.0",
58-
"eslint": "^9.16.0",
59-
"eslint-config-prettier": "^9.1.0",
60-
"eslint-plugin-prettier": "^5.2.1",
61-
"globals": "^15.13.0",
62-
"prettier": "^3.4.2",
63-
"rimraf": "^6.0.1",
64-
"typescript": "^5.7.2",
65-
"typescript-eslint": "^8.18.0",
66-
"vite": "^6.2.4",
67-
"vite-plugin-dts": "^4.5.3"
68-
}
16+
"files": [
17+
"dist",
18+
"types",
19+
"LICENSE",
20+
"README.md"
21+
],
22+
"scripts": {
23+
"dev": "npm run format && npm run lint:fix && npm run build",
24+
"build": "rimraf dist && vite build",
25+
"lint": "eslint src/**",
26+
"lint:fix": "eslint src/** --fix",
27+
"format": "prettier --write .",
28+
"test": "echo \"Error: no test specified\" && exit 1",
29+
"prepare": "npm run build",
30+
"watch": "vite build --watch"
31+
},
32+
"repository": {
33+
"type": "git",
34+
"url": "git+https://github.com/JeelGajera/jspdf-md-renderer.git"
35+
},
36+
"keywords": [
37+
"jspdf",
38+
"markdown",
39+
"pdf",
40+
"renderer"
41+
],
42+
"author": "Jeel Gajera <jeelgajera200@gmail.com>",
43+
"license": "MIT",
44+
"bugs": {
45+
"url": "https://github.com/JeelGajera/jspdf-md-renderer/issues"
46+
},
47+
"homepage": "https://github.com/JeelGajera/jspdf-md-renderer#readme",
48+
"dependencies": {
49+
"jspdf": "^3.0.1",
50+
"jspdf-md-renderer": "file:",
51+
"marked": "^15.0.3"
52+
},
53+
"devDependencies": {
54+
"@eslint/js": "^9.16.0",
55+
"@types/node": "^22.10.2",
56+
"@typescript-eslint/eslint-plugin": "^8.18.0",
57+
"@typescript-eslint/parser": "^8.18.0",
58+
"eslint": "^9.16.0",
59+
"eslint-config-prettier": "^10.1.2",
60+
"eslint-plugin-prettier": "^5.2.1",
61+
"globals": "^16.0.0",
62+
"prettier": "^3.4.2",
63+
"rimraf": "^6.0.1",
64+
"typescript": "^5.7.2",
65+
"typescript-eslint": "^8.18.0",
66+
"vite": "^6.2.4",
67+
"vite-plugin-dts": "^4.5.3"
68+
}
6969
}

src/renderer/components/inlineText.ts

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const renderInlineText = (
2929
case 'italic':
3030
return 1.5;
3131
case 'bolditalic':
32-
return 2.5;
32+
return 1.5;
3333
default:
3434
return 0;
3535
}
@@ -61,19 +61,60 @@ const renderInlineText = (
6161
doc.setFont(options.font.regular.name, currentFontStyle);
6262
}
6363

64-
const textWidth = doc.getTextWidth(text);
65-
// Check for line break
66-
if (
67-
cursor.x + textWidth >
68-
options.page.xpading + options.page.maxContentWidth
69-
) {
70-
cursor.x = options.page.xpading;
64+
// Calculate available width for text
65+
const availableWidth = options.page.maxContentWidth - indent - cursor.x;
66+
67+
// Split text into lines
68+
const textLines = doc.splitTextToSize(text, availableWidth);
69+
70+
// Render lines
71+
if (textLines.length > 1) {
72+
// If the text is too long, adjust the cursor position for each line
73+
// render firstline i availabe width
74+
// and rest of the content in the next line with up to indent
75+
const firstLine = textLines[0];
76+
const restContent = textLines?.slice(1)?.join(' ');
77+
// render first line
78+
doc.text(
79+
firstLine,
80+
cursor.x + (indent >= 2 ? indent + 2 * spaceMultiplier(style) : 0),
81+
cursor.y,
82+
{
83+
baseline: 'top',
84+
maxWidth: availableWidth,
85+
},
86+
);
87+
88+
// update cursor position
89+
cursor.x = indent;
7190
cursor.y += getCharHight(doc, options);
91+
92+
// render rest of the content in the next line with up to indent
93+
const maxWidthForRest =
94+
options.page.maxContentWidth -
95+
indent -
96+
options.page.xpading -
97+
options.page.xmargin;
98+
const restLines = doc.splitTextToSize(restContent, maxWidthForRest);
99+
restLines.forEach((line: string) => {
100+
doc.text(line, cursor.x + indent, cursor.y, {
101+
baseline: 'top',
102+
maxWidth: maxWidthForRest,
103+
});
104+
// update cursor position
105+
cursor.x = indent;
106+
cursor.y += getCharHight(doc, options);
107+
});
108+
} else {
109+
doc.text(text, cursor.x + indent, cursor.y, {
110+
baseline: 'top',
111+
maxWidth: availableWidth,
112+
});
113+
cursor.x +=
114+
doc.getTextDimensions(text).w +
115+
(indent >= 2 ? text.split(' ').length + 2 : 2) *
116+
spaceMultiplier(style);
72117
}
73-
const spaceWidth = doc.getTextWidth(' ');
74-
doc.text(text, cursor.x + indent, cursor.y, { baseline: 'top' });
75-
cursor.x +=
76-
textWidth + (spaceWidth * spaceMultiplier(style)) + (style === 'normal'? indent*.7 : 0);
77118
};
78119

79120
// Handle the element based on its type

src/renderer/components/listItem.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ const renderListItem = (
2020
indentLevel: number,
2121
hasRawBullet?: boolean,
2222
start?: number,
23-
ordered?: boolean
23+
ordered?: boolean,
2424
) => Cursor,
2525
start: number,
26-
ordered: boolean
26+
ordered: boolean,
2727
): Cursor => {
2828
// We'll calculate a base indent so list items at the same level are aligned
2929
const baseIndent = indentLevel * options.page.indent;
3030
// The bullet or number for this item
3131
const bullet = ordered ? `${start}. ` : '\u2022 ';
3232

3333
// If we are close to bottom, do a page break
34-
if (cursor.y + getCharHight(doc, options) >= options.page.maxContentHeight) {
34+
if (
35+
cursor.y + getCharHight(doc, options) >=
36+
options.page.maxContentHeight
37+
) {
3538
HandlePageBreaks(doc, options);
3639
cursor.y = options.page.topmargin;
3740
}
@@ -60,15 +63,28 @@ const renderListItem = (
6063

6164
if (subItem.type === MdTokenType.List) {
6265
// A sub-list is always an extra level of indent
63-
parentElementRenderer(subItem, indentLevel + 1, true, start, subItem.ordered ?? false);
66+
parentElementRenderer(
67+
subItem,
68+
indentLevel + 1,
69+
true,
70+
start,
71+
subItem.ordered ?? false,
72+
);
6473
} else if (subItem.type === MdTokenType.ListItem) {
65-
// Same level if parent is a list,
74+
// Same level if parent is a list,
6675
// otherwise if the parent is a list_item, it's nested => indent + 1
6776
const newIndentLevel =
6877
element.type === MdTokenType.List
6978
? indentLevel
7079
: indentLevel + 1;
71-
parentElementRenderer(subItem, newIndentLevel, true, start, ordered);
80+
81+
parentElementRenderer(
82+
subItem,
83+
newIndentLevel,
84+
true,
85+
start,
86+
ordered,
87+
);
7288
} else {
7389
// Inline content (e.g., emphasis, text, strong)
7490
// Render on the same line (indented after bullet)
@@ -86,13 +102,24 @@ const renderListItem = (
86102
cursor.y += getCharHight(doc, options);
87103
}
88104
} else if (element.content) {
89-
// No nested items, just text content
90-
doc.text(
105+
// handle text with line breaks page break & multiple lines texts
106+
const textLines = doc.splitTextToSize(
91107
element.content,
108+
options.page.maxContentWidth - baseIndent - cursor.x,
109+
);
110+
// Render text
111+
doc.text(
112+
textLines,
92113
cursor.x + baseIndent,
93114
cursor.y,
94-
{ baseline: 'top' }
115+
{
116+
baseline: 'top',
117+
maxWidth: options.page.maxContentWidth - baseIndent - cursor.x,
118+
},
95119
);
120+
// Update cursor position\
121+
cursor.y += getCharHight(doc, options) * textLines.length;
122+
cursor.x = options.page.xmargin + baseIndent;
96123
// Move the cursor forward by the text width
97124
const contentWidth = doc.getTextWidth(element.content);
98125
cursor.x += contentWidth;

src/renderer/components/rawItem.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,9 @@ const renderRawItem = (
6464
cursor.x = options.page.xpading;
6565
} else {
6666
// Print text
67-
doc.text(
68-
bullet + element.content,
69-
cursor.x + indent,
70-
cursor.y,
71-
{ baseline: 'top' },
72-
);
67+
doc.text(bullet + element.content, cursor.x + indent, cursor.y, {
68+
baseline: 'top',
69+
});
7370
// Move x forward
7471
cursor.x += doc.getTextWidth(bullet + element.content);
7572
// Handle page break
@@ -79,7 +76,7 @@ const renderRawItem = (
7976
) {
8077
HandlePageBreaks(doc, options);
8178
cursor.x = options.page.xpading;
82-
cursor.y += getCharHight(doc, options);
79+
cursor.y = options.page.topmargin;
8380
}
8481
}
8582
}

0 commit comments

Comments
 (0)