jspdf-utils 0.1.2 → 0.1.4

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.
@@ -38,20 +38,13 @@ export interface PrepareResult {
38
38
  /** Compute derived layout values from options. */
39
39
  declare function computeLayout(container: HTMLElement, opts: PageOptions): Layout;
40
40
  /**
41
- * Clone an element and position it off-screen at print width for measurement.
42
- */
43
- declare function createPrintClone(source: HTMLElement, pageWidth?: number): HTMLElement;
44
- /**
45
- * Reset framework/global CSS on table elements inside the clone so that
46
- * jsPDF's doc.html() renderer produces consistent output regardless of
47
- * the host page's CSS environment (e.g. Tailwind preflight, CSS resets).
41
+ * Clone an element into a hidden iframe so that the page's CSS frameworks
42
+ * (Tailwind, Bootstrap, etc.) cannot interfere with PDF rendering.
48
43
  *
49
- * Uses `all: revert` to roll back author-stylesheet properties to
50
- * user-agent defaults while preserving inline styles set by the caller.
51
- *
52
- * Returns a cleanup function that removes the injected style element.
44
+ * Only @font-face rules are copied into the iframe so custom fonts still work.
45
+ * The returned element's `.remove()` method cleans up the iframe automatically.
53
46
  */
54
- declare function resetFrameworkCSS(clone: HTMLElement): () => void;
47
+ declare function createPrintClone(source: HTMLElement, pageWidth?: number): HTMLElement;
55
48
  /**
56
49
  * Convert HTML table attributes (cellpadding, cellspacing, border) to
57
50
  * inline CSS so doc.html()'s renderer picks them up.
@@ -92,4 +85,4 @@ export interface ImagePDFOptions {
92
85
  * screenshot — no selectable or extractable text in the output.
93
86
  */
94
87
  declare function renderImagePDF(source: HTMLElement, opts?: Partial<PageOptions> & ImagePDFOptions): Promise<jsPDF>;
95
- export { PAGE_SIZES, PAGE_MARGINS, computeLayout, createPrintClone, resetFrameworkCSS, normalizeTableAttributes, splitOversizedTables, splitOversizedText, insertPageBreakSpacers, prepare, renderHTML, renderImagePDF, };
88
+ export { PAGE_SIZES, PAGE_MARGINS, computeLayout, createPrintClone, normalizeTableAttributes, splitOversizedTables, splitOversizedText, insertPageBreakSpacers, prepare, renderHTML, renderImagePDF, };
@@ -1,4 +1,4 @@
1
- import j from "html2canvas";
1
+ import D from "html2canvas";
2
2
  const N = {
3
3
  a0: [841, 1189],
4
4
  a1: [594, 841],
@@ -10,7 +10,7 @@ const N = {
10
10
  letter: [215.9, 279.4],
11
11
  legal: [215.9, 355.6],
12
12
  tabloid: [279.4, 431.8]
13
- }, T = {
13
+ }, R = {
14
14
  a0: 40,
15
15
  a1: 35,
16
16
  a2: 30,
@@ -22,214 +22,228 @@ const N = {
22
22
  legal: 25.4,
23
23
  tabloid: 25
24
24
  };
25
- function C(i = {}) {
26
- const o = i.format ?? "a4", [n, t] = N[o], r = i.pageWidth ?? n, e = i.pageHeight ?? t, a = T[o], c = {
25
+ function x(r = {}) {
26
+ const n = r.format ?? "a4", [i, e] = N[n], o = r.pageWidth ?? i, t = r.pageHeight ?? e, a = R[n], c = {
27
27
  top: a,
28
28
  right: a,
29
29
  bottom: a,
30
30
  left: a
31
31
  };
32
32
  return {
33
- unit: i.unit ?? "mm",
34
- format: o,
35
- pageWidth: r,
36
- pageHeight: e,
37
- margin: { ...c, ...i.margin }
33
+ unit: r.unit ?? "mm",
34
+ format: n,
35
+ pageWidth: o,
36
+ pageHeight: t,
37
+ margin: { ...c, ...r.margin }
38
38
  };
39
39
  }
40
- function x(i, o) {
41
- const n = i.offsetWidth, t = o.pageWidth - o.margin.left - o.margin.right, r = t / n, a = (o.pageHeight - o.margin.top - o.margin.bottom) / r;
42
- return { renderedWidth: n, scale: r, contentWidthMm: t, pageContentPx: a };
40
+ function C(r, n) {
41
+ const i = r.offsetWidth, e = n.pageWidth - n.margin.left - n.margin.right, o = e / i, a = (n.pageHeight - n.margin.top - n.margin.bottom) / o;
42
+ return { renderedWidth: i, scale: o, contentWidthMm: e, pageContentPx: a };
43
43
  }
44
- function v(i, o = 210) {
45
- const n = i.cloneNode(!0);
46
- return Object.assign(n.style, {
44
+ function v(r, n = 210) {
45
+ const i = document.createElement("iframe");
46
+ Object.assign(i.style, {
47
47
  position: "fixed",
48
48
  top: "0",
49
- left: "0",
50
- boxSizing: "border-box",
51
- width: o + "mm",
49
+ left: "-99999px",
50
+ width: n + "mm",
51
+ height: "99999px",
52
+ border: "none",
52
53
  opacity: "0.000001",
53
54
  pointerEvents: "none"
54
- }), document.body.appendChild(n), n;
55
- }
56
- function k(i) {
57
- const o = "__jspdf_" + Math.random().toString(36).slice(2, 8);
58
- i.dataset.jspdfClone = o;
59
- const n = `[data-jspdf-clone="${o}"]`, r = ["table", "thead", "tbody", "tfoot", "tr", "td", "th"].map((a) => `${n} ${a}`).join(",") + "{all:revert}", e = document.createElement("style");
60
- return e.textContent = r, document.head.appendChild(e), () => e.remove();
55
+ }), document.body.appendChild(i);
56
+ const e = i.contentDocument;
57
+ if (!e) throw new Error("Could not access iframe document");
58
+ const o = e.createElement("base");
59
+ o.href = document.baseURI, e.head.appendChild(o);
60
+ const t = [];
61
+ for (const c of document.styleSheets)
62
+ try {
63
+ for (const l of c.cssRules)
64
+ l instanceof CSSFontFaceRule && t.push(l.cssText);
65
+ } catch {
66
+ }
67
+ if (t.length > 0) {
68
+ const c = e.createElement("style");
69
+ c.textContent = t.join(`
70
+ `), e.head.appendChild(c);
71
+ }
72
+ const a = r.cloneNode(!0);
73
+ return Object.assign(a.style, {
74
+ boxSizing: "border-box",
75
+ width: n + "mm"
76
+ }), e.body.style.margin = "0", e.body.appendChild(a), a.remove = () => i.remove(), a;
61
77
  }
62
- function A(i) {
63
- for (const o of i.querySelectorAll("table")) {
64
- const n = o.getAttribute("cellpadding");
65
- if (n) {
66
- for (const t of o.querySelectorAll("th, td"))
67
- t.style.padding || (t.style.padding = n + "px");
68
- o.removeAttribute("cellpadding");
78
+ function A(r) {
79
+ for (const n of r.querySelectorAll("table")) {
80
+ const i = n.getAttribute("cellpadding");
81
+ if (i) {
82
+ for (const e of n.querySelectorAll("th, td"))
83
+ e.style.padding || (e.style.padding = i + "px");
84
+ n.removeAttribute("cellpadding");
69
85
  }
70
86
  }
71
87
  }
72
- function S(i, o) {
73
- for (const n of Array.from(
74
- i.querySelectorAll(":scope > table")
88
+ function E(r, n) {
89
+ for (const i of Array.from(
90
+ r.querySelectorAll(":scope > table")
75
91
  )) {
76
- if (n.offsetHeight <= o) continue;
77
- const t = Array.from(n.rows);
78
- if (t.length === 0) continue;
79
- const r = t[0].querySelector("th") !== null, e = r ? t[0] : null, a = r ? t.slice(1) : t, c = e ? e.offsetHeight : 0, d = o - c - 2, h = [];
80
- let s = [], f = 0;
81
- for (const l of a) {
82
- const g = l.offsetHeight;
83
- f + g > d && s.length > 0 && (h.push(s), s = [], f = 0), s.push(l), f += g;
92
+ if (i.offsetHeight <= n) continue;
93
+ const e = Array.from(i.rows);
94
+ if (e.length === 0) continue;
95
+ const o = e[0].querySelector("th") !== null, t = o ? e[0] : null, a = o ? e.slice(1) : e, c = t ? t.offsetHeight : 0, l = n - c - 2, d = [];
96
+ let f = [], h = 0;
97
+ for (const s of a) {
98
+ const g = s.offsetHeight;
99
+ h + g > l && f.length > 0 && (d.push(f), f = [], h = 0), f.push(s), h += g;
84
100
  }
85
- s.length > 0 && h.push(s);
86
- for (const l of h) {
87
- const g = n.cloneNode(!1);
88
- e && g.appendChild(e.cloneNode(!0));
89
- for (const m of l) g.appendChild(m.cloneNode(!0));
90
- n.parentNode.insertBefore(g, n);
101
+ f.length > 0 && d.push(f);
102
+ for (const s of d) {
103
+ const g = i.cloneNode(!1);
104
+ t && g.appendChild(t.cloneNode(!0));
105
+ for (const m of s) g.appendChild(m.cloneNode(!0));
106
+ i.parentNode.insertBefore(g, i);
91
107
  }
92
- n.remove();
108
+ i.remove();
93
109
  }
94
110
  }
95
- function W(i, o) {
96
- for (const n of Array.from(i.querySelectorAll(":scope > *"))) {
97
- const t = n;
98
- if (t.offsetHeight <= o || t.tagName === "TABLE")
111
+ function P(r, n) {
112
+ const i = r.ownerDocument;
113
+ for (const e of Array.from(r.querySelectorAll(":scope > *"))) {
114
+ const o = e;
115
+ if (o.offsetHeight <= n || o.tagName === "TABLE")
99
116
  continue;
100
- const r = t.tagName, e = t.getAttribute("style") || "", a = getComputedStyle(t).width, c = (t.textContent || "").split(/\s+/).filter(Boolean), d = document.createElement(r);
101
- d.setAttribute("style", e), Object.assign(d.style, {
117
+ const t = o.tagName, a = o.getAttribute("style") || "", c = i.defaultView.getComputedStyle(o).width, l = (o.textContent || "").split(/\s+/).filter(Boolean), d = i.createElement(t);
118
+ d.setAttribute("style", a), Object.assign(d.style, {
102
119
  position: "absolute",
103
120
  visibility: "hidden",
104
- width: a
105
- }), i.appendChild(d);
106
- const h = [];
107
- let s = 0;
108
- for (; s < c.length; ) {
109
- let f = s + 1, l = c.length;
110
- for (; f < l; ) {
111
- const m = Math.ceil((f + l) / 2);
112
- d.textContent = c.slice(s, m).join(" "), d.offsetHeight <= o ? f = m : l = m - 1;
121
+ width: c
122
+ }), r.appendChild(d);
123
+ const f = [];
124
+ let h = 0;
125
+ for (; h < l.length; ) {
126
+ let s = h + 1, g = l.length;
127
+ for (; s < g; ) {
128
+ const u = Math.ceil((s + g) / 2);
129
+ d.textContent = l.slice(h, u).join(" "), d.offsetHeight <= n ? s = u : g = u - 1;
113
130
  }
114
- const g = document.createElement(r);
115
- g.setAttribute("style", e), g.textContent = c.slice(s, f).join(" "), h.push(g), s = f;
131
+ const m = i.createElement(t);
132
+ m.setAttribute("style", a), m.textContent = l.slice(h, s).join(" "), f.push(m), h = s;
116
133
  }
117
134
  d.remove();
118
- for (const f of h)
119
- t.parentNode.insertBefore(f, t);
120
- t.remove();
135
+ for (const s of f)
136
+ o.parentNode.insertBefore(s, o);
137
+ o.remove();
121
138
  }
122
139
  }
123
- function P(i, o) {
124
- const n = Array.from(i.children);
125
- for (const t of n) {
126
- const r = t.offsetTop, e = r + t.offsetHeight, a = (Math.floor(r / o) + 1) * o;
127
- if (e > a && t.offsetHeight <= o) {
128
- const c = document.createElement("div");
129
- c.style.height = a - r + 1 + "px", t.parentNode.insertBefore(c, t);
140
+ function W(r, n) {
141
+ const i = r.ownerDocument, e = Array.from(r.children);
142
+ for (const o of e) {
143
+ const t = o.offsetTop, a = t + o.offsetHeight, c = (Math.floor(t / n) + 1) * n;
144
+ if (a > c && o.offsetHeight <= n) {
145
+ const l = i.createElement("div");
146
+ l.style.height = c - t + 1 + "px", o.parentNode.insertBefore(l, o);
130
147
  }
131
148
  }
132
149
  }
133
- function B(i, o = {}) {
134
- const n = C(o), t = v(i, n.pageWidth), r = k(t);
135
- A(t);
136
- const e = x(t, n);
137
- return S(t, e.pageContentPx), W(t, e.pageContentPx), P(t, e.pageContentPx), {
138
- clone: t,
139
- layout: e,
140
- options: n,
141
- cleanup: () => {
142
- r(), t.remove();
143
- }
150
+ function T(r, n = {}) {
151
+ const i = x(n), e = v(r, i.pageWidth);
152
+ A(e);
153
+ const o = C(e, i);
154
+ return E(e, o.pageContentPx), P(e, o.pageContentPx), W(e, o.pageContentPx), {
155
+ clone: e,
156
+ layout: o,
157
+ options: i,
158
+ cleanup: () => e.remove()
144
159
  };
145
160
  }
146
- async function D(i, o, n = {}) {
147
- const { clone: t, layout: r, options: e, cleanup: a } = B(o, n);
161
+ async function F(r, n, i = {}) {
162
+ const { clone: e, layout: o, options: t, cleanup: a } = T(n, i);
148
163
  try {
149
164
  await new Promise((c) => {
150
- i.html(t, {
165
+ r.html(e, {
151
166
  callback: () => c(),
152
- width: r.contentWidthMm,
153
- windowWidth: r.renderedWidth,
167
+ width: o.contentWidthMm,
168
+ windowWidth: o.renderedWidth,
154
169
  margin: [
155
- e.margin.top,
156
- e.margin.right,
157
- e.margin.bottom,
158
- e.margin.left
170
+ t.margin.top,
171
+ t.margin.right,
172
+ t.margin.bottom,
173
+ t.margin.left
159
174
  ]
160
175
  });
161
176
  });
162
177
  } finally {
163
178
  a();
164
179
  }
165
- return i;
180
+ return r;
166
181
  }
167
- async function O(i, o = {}) {
168
- const { imageFormat: n = "JPEG", imageQuality: t = 1, scale: r = 2 } = o, e = C(o), a = v(i, e.pageWidth);
169
- a.style.opacity = "1", a.style.left = "-99999px", A(a);
170
- const c = x(a, e);
171
- S(a, c.pageContentPx), W(a, c.pageContentPx), P(a, c.pageContentPx);
182
+ async function B(r, n = {}) {
183
+ const { imageFormat: i = "JPEG", imageQuality: e = 1, scale: o = 2 } = n, t = x(n), a = v(r, t.pageWidth);
184
+ A(a);
185
+ const c = C(a, t);
186
+ E(a, c.pageContentPx), P(a, c.pageContentPx), W(a, c.pageContentPx);
172
187
  try {
173
- const d = await j(a, {
174
- scale: r,
188
+ const l = await D(a, {
189
+ scale: o,
175
190
  backgroundColor: "#ffffff"
176
- }), { jsPDF: h } = await import("jspdf"), s = e.pageWidth - e.margin.left - e.margin.right, f = e.pageHeight - e.margin.top - e.margin.bottom, l = d.width, g = f / s * l, m = Math.ceil(d.height / g), H = e.pageWidth > e.pageHeight ? "l" : "p", w = new h({
177
- orientation: H,
191
+ }), { jsPDF: d } = await import("jspdf"), f = t.pageWidth - t.margin.left - t.margin.right, h = t.pageHeight - t.margin.top - t.margin.bottom, s = l.width, g = h / f * s, m = Math.ceil(l.height / g), u = t.pageWidth > t.pageHeight ? "l" : "p", H = new d({
192
+ orientation: u,
178
193
  unit: "mm",
179
- format: [e.pageWidth, e.pageHeight]
194
+ format: [t.pageWidth, t.pageHeight]
180
195
  });
181
- for (let u = 0; u < m; u++) {
182
- const p = Math.min(
196
+ for (let p = 0; p < m; p++) {
197
+ const y = Math.min(
183
198
  g,
184
- d.height - u * g
185
- ), y = document.createElement("canvas");
186
- y.width = l, y.height = p;
187
- const b = y.getContext("2d");
188
- if (!b) throw new Error("Could not get canvas context");
189
- b.fillStyle = "#ffffff", b.fillRect(0, 0, l, p), b.drawImage(
190
- d,
191
- 0,
192
- u * g,
199
+ l.height - p * g
200
+ ), b = document.createElement("canvas");
201
+ b.width = s, b.height = y;
202
+ const w = b.getContext("2d");
203
+ if (!w) throw new Error("Could not get canvas context");
204
+ w.fillStyle = "#ffffff", w.fillRect(0, 0, s, y), w.drawImage(
193
205
  l,
194
- p,
195
206
  0,
207
+ p * g,
208
+ s,
209
+ y,
196
210
  0,
197
- l,
198
- p
211
+ 0,
212
+ s,
213
+ y
199
214
  );
200
- const M = y.toDataURL(
201
- `image/${n.toLowerCase()}`,
202
- t
215
+ const S = b.toDataURL(
216
+ `image/${i.toLowerCase()}`,
217
+ e
203
218
  );
204
- u > 0 && w.addPage([e.pageWidth, e.pageHeight], H);
205
- const E = p / l * s;
206
- w.addImage(
219
+ p > 0 && H.addPage([t.pageWidth, t.pageHeight], u);
220
+ const M = y / s * f;
221
+ H.addImage(
222
+ S,
223
+ i,
224
+ t.margin.left,
225
+ t.margin.top,
226
+ f,
207
227
  M,
208
- n,
209
- e.margin.left,
210
- e.margin.top,
211
- s,
212
- E,
213
228
  void 0,
214
229
  "FAST"
215
230
  );
216
231
  }
217
- return w;
232
+ return H;
218
233
  } finally {
219
234
  a.remove();
220
235
  }
221
236
  }
222
237
  export {
223
- T as PAGE_MARGINS,
238
+ R as PAGE_MARGINS,
224
239
  N as PAGE_SIZES,
225
- x as computeLayout,
240
+ C as computeLayout,
226
241
  v as createPrintClone,
227
- P as insertPageBreakSpacers,
242
+ W as insertPageBreakSpacers,
228
243
  A as normalizeTableAttributes,
229
- B as prepare,
230
- D as renderHTML,
231
- O as renderImagePDF,
232
- k as resetFrameworkCSS,
233
- S as splitOversizedTables,
234
- W as splitOversizedText
244
+ T as prepare,
245
+ F as renderHTML,
246
+ B as renderImagePDF,
247
+ E as splitOversizedTables,
248
+ P as splitOversizedText
235
249
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jspdf-utils",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Utility helpers for jsPDF's doc.html() renderer with automatic page breaking, table splitting, and RTL support",
5
5
  "type": "module",
6
6
  "main": "dist/html-to-pdf.js",