paginate-pdf 0.1.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/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/chunk-HBSLYOBE.js +301 -0
- package/dist/chunk-HBSLYOBE.js.map +1 -0
- package/dist/chunk-IE5QDJFU.js +104 -0
- package/dist/chunk-IE5QDJFU.js.map +1 -0
- package/dist/index.cjs +427 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +461 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +14 -0
- package/dist/react.d.ts +14 -0
- package/dist/react.js +40 -0
- package/dist/react.js.map +1 -0
- package/dist/testing.cjs +132 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +7 -0
- package/dist/testing.d.ts +7 -0
- package/dist/testing.js +11 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-DGaknP5f.d.cts +82 -0
- package/dist/types-DGaknP5f.d.ts +82 -0
- package/package.json +78 -0
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/testing.ts
|
|
21
|
+
var testing_exports = {};
|
|
22
|
+
__export(testing_exports, {
|
|
23
|
+
collectBlockTree: () => collectBlockTree,
|
|
24
|
+
collectTables: () => collectTables,
|
|
25
|
+
computePageSlices: () => computePageSlices
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(testing_exports);
|
|
28
|
+
|
|
29
|
+
// src/block-tree.ts
|
|
30
|
+
function isRenderable(element) {
|
|
31
|
+
if (!(element instanceof HTMLElement)) return false;
|
|
32
|
+
const styles = window.getComputedStyle(element);
|
|
33
|
+
return styles.display !== "none" && styles.visibility !== "hidden";
|
|
34
|
+
}
|
|
35
|
+
function collectBlockTree(root, shouldAvoidBreak) {
|
|
36
|
+
const rootTop = root.getBoundingClientRect().top;
|
|
37
|
+
function build(element) {
|
|
38
|
+
if (!isRenderable(element)) return null;
|
|
39
|
+
const rect = element.getBoundingClientRect();
|
|
40
|
+
if (rect.height <= 0) return null;
|
|
41
|
+
const node = {
|
|
42
|
+
top: rect.top - rootTop,
|
|
43
|
+
bottom: rect.bottom - rootTop
|
|
44
|
+
};
|
|
45
|
+
if (shouldAvoidBreak(element) || element.tagName === "TR") {
|
|
46
|
+
return { ...node, children: [], splittable: false };
|
|
47
|
+
}
|
|
48
|
+
const children = Array.from(element.children).map(build).filter((child) => child !== null);
|
|
49
|
+
return { ...node, children, splittable: children.length > 0 };
|
|
50
|
+
}
|
|
51
|
+
return Array.from(root.children).map(build).filter((child) => child !== null);
|
|
52
|
+
}
|
|
53
|
+
function collectTables(root) {
|
|
54
|
+
const rootTop = root.getBoundingClientRect().top;
|
|
55
|
+
const tables = [];
|
|
56
|
+
root.querySelectorAll("table").forEach((table) => {
|
|
57
|
+
const thead = table.querySelector(":scope > thead");
|
|
58
|
+
if (!thead || !isRenderable(thead)) return;
|
|
59
|
+
const tableRect = table.getBoundingClientRect();
|
|
60
|
+
const theadRect = thead.getBoundingClientRect();
|
|
61
|
+
if (tableRect.height <= 0 || theadRect.height <= 0) return;
|
|
62
|
+
tables.push({
|
|
63
|
+
top: tableRect.top - rootTop,
|
|
64
|
+
bottom: tableRect.bottom - rootTop,
|
|
65
|
+
theadTop: theadRect.top - rootTop,
|
|
66
|
+
theadBottom: theadRect.bottom - rootTop
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return tables;
|
|
70
|
+
}
|
|
71
|
+
function findBreak(nodes, start, limit, minLead, minTail) {
|
|
72
|
+
let best = start;
|
|
73
|
+
for (const node of nodes) {
|
|
74
|
+
if (node.bottom <= start) continue;
|
|
75
|
+
if (node.top >= limit) break;
|
|
76
|
+
if (node.bottom <= limit) {
|
|
77
|
+
best = node.bottom;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (node.splittable) {
|
|
81
|
+
const inner = findBreak(node.children, start, limit, minLead, minTail);
|
|
82
|
+
const keptHere = inner - node.top;
|
|
83
|
+
const carriedOver = node.bottom - inner;
|
|
84
|
+
if (inner > best && keptHere >= minLead && carriedOver >= minTail) {
|
|
85
|
+
return inner;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (node.top > best) best = node.top;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
return best;
|
|
92
|
+
}
|
|
93
|
+
function findHeaderReserve(start, tables) {
|
|
94
|
+
for (const table of tables) {
|
|
95
|
+
const bodyStart = table.theadBottom;
|
|
96
|
+
if (start > bodyStart && start < table.bottom) {
|
|
97
|
+
return {
|
|
98
|
+
heightPx: table.theadBottom - table.theadTop,
|
|
99
|
+
header: { top: table.theadTop, bottom: table.theadBottom }
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
function computePageSlices(tree, contentHeightPx, totalHeightPx, minSplitLeadRatio, minSplitTailRatio, tables = []) {
|
|
106
|
+
if (contentHeightPx <= 0 || totalHeightPx <= 0) return [];
|
|
107
|
+
const minLead = contentHeightPx * minSplitLeadRatio;
|
|
108
|
+
const minTail = contentHeightPx * minSplitTailRatio;
|
|
109
|
+
const slices = [];
|
|
110
|
+
let start = 0;
|
|
111
|
+
while (start < totalHeightPx) {
|
|
112
|
+
const reserve = findHeaderReserve(start, tables);
|
|
113
|
+
const usableHeight = contentHeightPx - (reserve?.heightPx ?? 0);
|
|
114
|
+
const limit = start + usableHeight;
|
|
115
|
+
if (limit >= totalHeightPx) {
|
|
116
|
+
slices.push({ start, end: totalHeightPx, header: reserve?.header });
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
let end = findBreak(tree, start, limit, minLead, minTail);
|
|
120
|
+
if (end <= start) end = limit;
|
|
121
|
+
slices.push({ start, end, header: reserve?.header });
|
|
122
|
+
start = end;
|
|
123
|
+
}
|
|
124
|
+
return slices;
|
|
125
|
+
}
|
|
126
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
127
|
+
0 && (module.exports = {
|
|
128
|
+
collectBlockTree,
|
|
129
|
+
collectTables,
|
|
130
|
+
computePageSlices
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=testing.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts","../src/block-tree.ts"],"sourcesContent":["export { collectBlockTree, collectTables, computePageSlices } from \"./block-tree.js\";\nexport type { BlockNode, PageSlice, TableInfo } from \"./types.js\";\n","import type { BlockNode, PageSlice, TableInfo } from \"./types.js\";\n\nfunction isRenderable(element: Element): element is HTMLElement {\n if (!(element instanceof HTMLElement)) return false;\n\n const styles = window.getComputedStyle(element);\n\n return styles.display !== \"none\" && styles.visibility !== \"hidden\";\n}\n\nexport function collectBlockTree(\n root: HTMLElement,\n shouldAvoidBreak: (element: Element) => boolean,\n): BlockNode[] {\n const rootTop = root.getBoundingClientRect().top;\n\n function build(element: Element): BlockNode | null {\n if (!isRenderable(element)) return null;\n\n const rect = element.getBoundingClientRect();\n if (rect.height <= 0) return null;\n\n const node = {\n top: rect.top - rootTop,\n bottom: rect.bottom - rootTop,\n };\n\n if (\n shouldAvoidBreak(element) ||\n element.tagName === \"TR\"\n ) {\n return { ...node, children: [], splittable: false };\n }\n\n const children = Array.from(element.children)\n .map(build)\n .filter((child): child is BlockNode => child !== null);\n\n return { ...node, children, splittable: children.length > 0 };\n }\n\n return Array.from(root.children)\n .map(build)\n .filter((child): child is BlockNode => child !== null);\n}\n\nexport function collectTables(root: HTMLElement): TableInfo[] {\n const rootTop = root.getBoundingClientRect().top;\n const tables: TableInfo[] = [];\n\n root.querySelectorAll(\"table\").forEach((table) => {\n const thead = table.querySelector(\":scope > thead\");\n if (!thead || !isRenderable(thead)) return;\n\n const tableRect = table.getBoundingClientRect();\n const theadRect = thead.getBoundingClientRect();\n if (tableRect.height <= 0 || theadRect.height <= 0) return;\n\n tables.push({\n top: tableRect.top - rootTop,\n bottom: tableRect.bottom - rootTop,\n theadTop: theadRect.top - rootTop,\n theadBottom: theadRect.bottom - rootTop,\n });\n });\n\n return tables;\n}\n\nfunction findBreak(\n nodes: BlockNode[],\n start: number,\n limit: number,\n minLead: number,\n minTail: number,\n): number {\n let best = start;\n\n for (const node of nodes) {\n if (node.bottom <= start) continue;\n if (node.top >= limit) break;\n\n if (node.bottom <= limit) {\n best = node.bottom;\n continue;\n }\n\n if (node.splittable) {\n const inner = findBreak(node.children, start, limit, minLead, minTail);\n const keptHere = inner - node.top;\n const carriedOver = node.bottom - inner;\n\n if (inner > best && keptHere >= minLead && carriedOver >= minTail) {\n return inner;\n }\n }\n\n if (node.top > best) best = node.top;\n break;\n }\n\n return best;\n}\n\nfunction findHeaderReserve(start: number, tables: TableInfo[]) {\n for (const table of tables) {\n const bodyStart = table.theadBottom;\n if (start > bodyStart && start < table.bottom) {\n return {\n heightPx: table.theadBottom - table.theadTop,\n header: { top: table.theadTop, bottom: table.theadBottom },\n };\n }\n }\n return null;\n}\n\nexport function computePageSlices(\n tree: BlockNode[],\n contentHeightPx: number,\n totalHeightPx: number,\n minSplitLeadRatio: number,\n minSplitTailRatio: number,\n tables: TableInfo[] = [],\n): PageSlice[] {\n if (contentHeightPx <= 0 || totalHeightPx <= 0) return [];\n\n const minLead = contentHeightPx * minSplitLeadRatio;\n const minTail = contentHeightPx * minSplitTailRatio;\n const slices: PageSlice[] = [];\n let start = 0;\n\n while (start < totalHeightPx) {\n const reserve = findHeaderReserve(start, tables);\n const usableHeight = contentHeightPx - (reserve?.heightPx ?? 0);\n const limit = start + usableHeight;\n\n if (limit >= totalHeightPx) {\n slices.push({ start, end: totalHeightPx, header: reserve?.header });\n break;\n }\n\n let end = findBreak(tree, start, limit, minLead, minTail);\n\n if (end <= start) end = limit;\n\n slices.push({ start, end, header: reserve?.header });\n start = end;\n }\n\n return slices;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { f as BlockNode, T as TableInfo, g as PageSlice } from './types-DGaknP5f.cjs';
|
|
2
|
+
|
|
3
|
+
declare function collectBlockTree(root: HTMLElement, shouldAvoidBreak: (element: Element) => boolean): BlockNode[];
|
|
4
|
+
declare function collectTables(root: HTMLElement): TableInfo[];
|
|
5
|
+
declare function computePageSlices(tree: BlockNode[], contentHeightPx: number, totalHeightPx: number, minSplitLeadRatio: number, minSplitTailRatio: number, tables?: TableInfo[]): PageSlice[];
|
|
6
|
+
|
|
7
|
+
export { BlockNode, PageSlice, TableInfo, collectBlockTree, collectTables, computePageSlices };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { f as BlockNode, T as TableInfo, g as PageSlice } from './types-DGaknP5f.js';
|
|
2
|
+
|
|
3
|
+
declare function collectBlockTree(root: HTMLElement, shouldAvoidBreak: (element: Element) => boolean): BlockNode[];
|
|
4
|
+
declare function collectTables(root: HTMLElement): TableInfo[];
|
|
5
|
+
declare function computePageSlices(tree: BlockNode[], contentHeightPx: number, totalHeightPx: number, minSplitLeadRatio: number, minSplitTailRatio: number, tables?: TableInfo[]): PageSlice[];
|
|
6
|
+
|
|
7
|
+
export { BlockNode, PageSlice, TableInfo, collectBlockTree, collectTables, computePageSlices };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type PageFormat = "a4" | "letter" | "legal" | [number, number];
|
|
2
|
+
interface BorderOptions {
|
|
3
|
+
color: string;
|
|
4
|
+
widthMm?: number;
|
|
5
|
+
}
|
|
6
|
+
interface PageNumberOptions {
|
|
7
|
+
format?: (page: number, total: number) => string;
|
|
8
|
+
position?: "bottom-left" | "bottom-center" | "bottom-right";
|
|
9
|
+
fontSize?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}
|
|
12
|
+
interface PdfMetadata {
|
|
13
|
+
title?: string;
|
|
14
|
+
author?: string;
|
|
15
|
+
subject?: string;
|
|
16
|
+
keywords?: string;
|
|
17
|
+
creator?: string;
|
|
18
|
+
}
|
|
19
|
+
type PaginatePdfStage = {
|
|
20
|
+
phase: "preparing";
|
|
21
|
+
} | {
|
|
22
|
+
phase: "capturing";
|
|
23
|
+
} | {
|
|
24
|
+
phase: "paginating";
|
|
25
|
+
} | {
|
|
26
|
+
phase: "rendering-page";
|
|
27
|
+
page: number;
|
|
28
|
+
totalPages: number;
|
|
29
|
+
} | {
|
|
30
|
+
phase: "done";
|
|
31
|
+
totalPages: number;
|
|
32
|
+
};
|
|
33
|
+
interface PaginatePdfOptions {
|
|
34
|
+
filename?: string;
|
|
35
|
+
format?: PageFormat;
|
|
36
|
+
marginMm?: number;
|
|
37
|
+
scale?: number;
|
|
38
|
+
maxCanvasDimension?: number;
|
|
39
|
+
imageQuality?: number;
|
|
40
|
+
background?: string;
|
|
41
|
+
border?: BorderOptions;
|
|
42
|
+
pageNumbers?: boolean | PageNumberOptions;
|
|
43
|
+
metadata?: PdfMetadata;
|
|
44
|
+
repeatTableHeaders?: boolean;
|
|
45
|
+
avoidBreakAttribute?: string;
|
|
46
|
+
minSplitLeadRatio?: number;
|
|
47
|
+
minSplitTailRatio?: number;
|
|
48
|
+
inlineCrossOriginImages?: boolean;
|
|
49
|
+
waitForFonts?: boolean;
|
|
50
|
+
waitForImages?: boolean;
|
|
51
|
+
save?: boolean;
|
|
52
|
+
onProgress?: (stage: PaginatePdfStage) => void;
|
|
53
|
+
beforeCapture?: (clonedDocument: Document, clonedElement: HTMLElement) => void | Promise<void>;
|
|
54
|
+
html2canvasOptions?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
interface PaginatePdfResult {
|
|
57
|
+
pageCount: number;
|
|
58
|
+
blob(): Blob;
|
|
59
|
+
save(filename?: string): void;
|
|
60
|
+
}
|
|
61
|
+
interface BlockNode {
|
|
62
|
+
top: number;
|
|
63
|
+
bottom: number;
|
|
64
|
+
children: BlockNode[];
|
|
65
|
+
splittable: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface TableInfo {
|
|
68
|
+
top: number;
|
|
69
|
+
bottom: number;
|
|
70
|
+
theadTop: number;
|
|
71
|
+
theadBottom: number;
|
|
72
|
+
}
|
|
73
|
+
interface PageSlice {
|
|
74
|
+
start: number;
|
|
75
|
+
end: number;
|
|
76
|
+
header?: {
|
|
77
|
+
top: number;
|
|
78
|
+
bottom: number;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type { BorderOptions as B, PaginatePdfOptions as P, TableInfo as T, PaginatePdfResult as a, PageFormat as b, PageNumberOptions as c, PaginatePdfStage as d, PdfMetadata as e, BlockNode as f, PageSlice as g };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type PageFormat = "a4" | "letter" | "legal" | [number, number];
|
|
2
|
+
interface BorderOptions {
|
|
3
|
+
color: string;
|
|
4
|
+
widthMm?: number;
|
|
5
|
+
}
|
|
6
|
+
interface PageNumberOptions {
|
|
7
|
+
format?: (page: number, total: number) => string;
|
|
8
|
+
position?: "bottom-left" | "bottom-center" | "bottom-right";
|
|
9
|
+
fontSize?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}
|
|
12
|
+
interface PdfMetadata {
|
|
13
|
+
title?: string;
|
|
14
|
+
author?: string;
|
|
15
|
+
subject?: string;
|
|
16
|
+
keywords?: string;
|
|
17
|
+
creator?: string;
|
|
18
|
+
}
|
|
19
|
+
type PaginatePdfStage = {
|
|
20
|
+
phase: "preparing";
|
|
21
|
+
} | {
|
|
22
|
+
phase: "capturing";
|
|
23
|
+
} | {
|
|
24
|
+
phase: "paginating";
|
|
25
|
+
} | {
|
|
26
|
+
phase: "rendering-page";
|
|
27
|
+
page: number;
|
|
28
|
+
totalPages: number;
|
|
29
|
+
} | {
|
|
30
|
+
phase: "done";
|
|
31
|
+
totalPages: number;
|
|
32
|
+
};
|
|
33
|
+
interface PaginatePdfOptions {
|
|
34
|
+
filename?: string;
|
|
35
|
+
format?: PageFormat;
|
|
36
|
+
marginMm?: number;
|
|
37
|
+
scale?: number;
|
|
38
|
+
maxCanvasDimension?: number;
|
|
39
|
+
imageQuality?: number;
|
|
40
|
+
background?: string;
|
|
41
|
+
border?: BorderOptions;
|
|
42
|
+
pageNumbers?: boolean | PageNumberOptions;
|
|
43
|
+
metadata?: PdfMetadata;
|
|
44
|
+
repeatTableHeaders?: boolean;
|
|
45
|
+
avoidBreakAttribute?: string;
|
|
46
|
+
minSplitLeadRatio?: number;
|
|
47
|
+
minSplitTailRatio?: number;
|
|
48
|
+
inlineCrossOriginImages?: boolean;
|
|
49
|
+
waitForFonts?: boolean;
|
|
50
|
+
waitForImages?: boolean;
|
|
51
|
+
save?: boolean;
|
|
52
|
+
onProgress?: (stage: PaginatePdfStage) => void;
|
|
53
|
+
beforeCapture?: (clonedDocument: Document, clonedElement: HTMLElement) => void | Promise<void>;
|
|
54
|
+
html2canvasOptions?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
interface PaginatePdfResult {
|
|
57
|
+
pageCount: number;
|
|
58
|
+
blob(): Blob;
|
|
59
|
+
save(filename?: string): void;
|
|
60
|
+
}
|
|
61
|
+
interface BlockNode {
|
|
62
|
+
top: number;
|
|
63
|
+
bottom: number;
|
|
64
|
+
children: BlockNode[];
|
|
65
|
+
splittable: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface TableInfo {
|
|
68
|
+
top: number;
|
|
69
|
+
bottom: number;
|
|
70
|
+
theadTop: number;
|
|
71
|
+
theadBottom: number;
|
|
72
|
+
}
|
|
73
|
+
interface PageSlice {
|
|
74
|
+
start: number;
|
|
75
|
+
end: number;
|
|
76
|
+
header?: {
|
|
77
|
+
top: number;
|
|
78
|
+
bottom: number;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type { BorderOptions as B, PaginatePdfOptions as P, TableInfo as T, PaginatePdfResult as a, PageFormat as b, PageNumberOptions as c, PaginatePdfStage as d, PdfMetadata as e, BlockNode as f, PageSlice as g };
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "paginate-pdf",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Turn any DOM element into a paginated PDF that never cuts through a line of text or an image — page breaks always land in an empty gap.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pdf",
|
|
7
|
+
"html2canvas",
|
|
8
|
+
"jspdf",
|
|
9
|
+
"html-to-pdf",
|
|
10
|
+
"dom-to-pdf",
|
|
11
|
+
"page-break",
|
|
12
|
+
"pagination",
|
|
13
|
+
"print"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.cjs",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./react": {
|
|
27
|
+
"types": "./dist/react.d.ts",
|
|
28
|
+
"import": "./dist/react.js",
|
|
29
|
+
"require": "./dist/react.cjs"
|
|
30
|
+
},
|
|
31
|
+
"./testing": {
|
|
32
|
+
"types": "./dist/testing.d.ts",
|
|
33
|
+
"import": "./dist/testing.js",
|
|
34
|
+
"require": "./dist/testing.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"dev": "tsup --watch",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"prepublishOnly": "npm run build"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"react": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"react": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"html2canvas-pro": "^2.4.0",
|
|
57
|
+
"jspdf": "^4.2.1"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/react": "^19.0.0",
|
|
61
|
+
"esbuild": "^0.28.2",
|
|
62
|
+
"playwright": "^1.62.1",
|
|
63
|
+
"react": "^19.0.0",
|
|
64
|
+
"tsup": "^8.3.0",
|
|
65
|
+
"typescript": "^5.6.0"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=18"
|
|
69
|
+
},
|
|
70
|
+
"repository": {
|
|
71
|
+
"type": "git",
|
|
72
|
+
"url": "git+https://github.com/arslaan07/paginate-pdf.git"
|
|
73
|
+
},
|
|
74
|
+
"homepage": "https://github.com/arslaan07/paginate-pdf#readme",
|
|
75
|
+
"bugs": {
|
|
76
|
+
"url": "https://github.com/arslaan07/paginate-pdf/issues"
|
|
77
|
+
}
|
|
78
|
+
}
|