fabricjs-document-engine 1.0.1 → 1.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/README.md +277 -36
- package/README.zh-CN.md +697 -0
- package/dist/assets/asset-manifest.d.cts +3 -0
- package/dist/assets/asset-manifest.d.ts +3 -0
- package/dist/assets/asset-pipeline.cjs +22 -10
- package/dist/assets/asset-pipeline.d.cts +5 -1
- package/dist/assets/asset-pipeline.d.ts +5 -1
- package/dist/assets/asset-pipeline.js +22 -10
- package/dist/assets/font-check.cjs +9 -1
- package/dist/assets/font-check.js +9 -1
- package/dist/assets/image-check.cjs +88 -6
- package/dist/assets/image-check.d.cts +17 -0
- package/dist/assets/image-check.d.ts +17 -0
- package/dist/assets/image-check.js +88 -7
- package/dist/commands/clipboard.cjs +136 -0
- package/dist/commands/clipboard.d.cts +47 -0
- package/dist/commands/clipboard.d.ts +47 -0
- package/dist/commands/clipboard.js +135 -0
- package/dist/commands/layers.cjs +97 -0
- package/dist/commands/layers.d.cts +39 -0
- package/dist/commands/layers.d.ts +39 -0
- package/dist/commands/layers.js +92 -0
- package/dist/engine/create-document-engine.cjs +85 -14
- package/dist/engine/create-document-engine.d.cts +20 -1
- package/dist/engine/create-document-engine.d.ts +20 -1
- package/dist/engine/create-document-engine.js +86 -15
- package/dist/engine/errors.d.cts +1 -1
- package/dist/engine/errors.d.ts +1 -1
- package/dist/export/batch-render.cjs +172 -0
- package/dist/export/batch-render.d.cts +43 -0
- package/dist/export/batch-render.d.ts +43 -0
- package/dist/export/batch-render.js +171 -0
- package/dist/export/export-options.cjs +18 -1
- package/dist/export/export-options.d.cts +23 -0
- package/dist/export/export-options.d.ts +23 -0
- package/dist/export/export-options.js +18 -2
- package/dist/export/preflight-export.cjs +11 -2
- package/dist/export/preflight-export.d.cts +1 -1
- package/dist/export/preflight-export.d.ts +1 -1
- package/dist/export/preflight-export.js +11 -2
- package/dist/export/render-export.cjs +18 -3
- package/dist/export/render-export.js +18 -4
- package/dist/export/svg/embed-assets.cjs +249 -0
- package/dist/export/svg/embed-assets.js +249 -0
- package/dist/export/svg/overrides.cjs +32 -0
- package/dist/export/svg/overrides.js +32 -0
- package/dist/export/svg/text-on-path.cjs +252 -0
- package/dist/export/svg/text-on-path.js +249 -0
- package/dist/fabric/fabric-adapter.cjs +46 -5
- package/dist/fabric/fabric-adapter.js +46 -5
- package/dist/fabric/object-registry.cjs +1 -1
- package/dist/fabric/object-registry.js +1 -1
- package/dist/import/svg-import.cjs +256 -0
- package/dist/import/svg-import.d.cts +50 -0
- package/dist/import/svg-import.d.ts +50 -0
- package/dist/import/svg-import.js +256 -0
- package/dist/index.cjs +12 -0
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -1
- package/dist/pdf/export-pdf.cjs +440 -0
- package/dist/pdf/export-pdf.d.cts +73 -0
- package/dist/pdf/export-pdf.d.ts +73 -0
- package/dist/pdf/export-pdf.js +440 -0
- package/dist/pdf/fonts.cjs +115 -0
- package/dist/pdf/fonts.d.cts +12 -0
- package/dist/pdf/fonts.d.ts +12 -0
- package/dist/pdf/fonts.js +112 -0
- package/dist/pdf/page-layout.cjs +79 -0
- package/dist/pdf/page-layout.d.cts +51 -0
- package/dist/pdf/page-layout.d.ts +51 -0
- package/dist/pdf/page-layout.js +76 -0
- package/dist/pdf/text-decorations.cjs +108 -0
- package/dist/pdf/text-decorations.js +107 -0
- package/dist/pdf.cjs +7 -0
- package/dist/pdf.d.cts +4 -0
- package/dist/pdf.d.ts +4 -0
- package/dist/pdf.js +3 -0
- package/dist/react/use-layers.cjs +53 -0
- package/dist/react/use-layers.d.cts +10 -0
- package/dist/react/use-layers.d.ts +10 -0
- package/dist/react/use-layers.js +53 -0
- package/dist/react.cjs +2 -0
- package/dist/react.d.cts +3 -1
- package/dist/react.d.ts +3 -1
- package/dist/react.js +2 -1
- package/dist/util/concurrency.cjs +28 -0
- package/dist/util/concurrency.js +27 -0
- package/package.json +55 -14
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
//#region src/pdf/page-layout.ts
|
|
2
|
+
/** Page sizes in PDF points (1/72 inch), portrait. */
|
|
3
|
+
const PAGE_SIZES = {
|
|
4
|
+
A3: [841.89, 1190.55],
|
|
5
|
+
A4: [595.28, 841.89],
|
|
6
|
+
A5: [419.53, 595.28],
|
|
7
|
+
Letter: [612, 792],
|
|
8
|
+
Legal: [612, 1008],
|
|
9
|
+
Tabloid: [792, 1224]
|
|
10
|
+
};
|
|
11
|
+
/** One CSS pixel is 1/96 inch, and a PDF point 1/72 inch. */
|
|
12
|
+
const POINTS_PER_PIXEL = .75;
|
|
13
|
+
function normalizeMargin(margin) {
|
|
14
|
+
if (margin === void 0) return {
|
|
15
|
+
top: 0,
|
|
16
|
+
right: 0,
|
|
17
|
+
bottom: 0,
|
|
18
|
+
left: 0
|
|
19
|
+
};
|
|
20
|
+
if (typeof margin === "number") return {
|
|
21
|
+
top: margin,
|
|
22
|
+
right: margin,
|
|
23
|
+
bottom: margin,
|
|
24
|
+
left: margin
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
top: margin.top ?? 0,
|
|
28
|
+
right: margin.right ?? 0,
|
|
29
|
+
bottom: margin.bottom ?? 0,
|
|
30
|
+
left: margin.left ?? 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function pageSizeFor(page, content, margin) {
|
|
34
|
+
if (page === "canvas") return [content.width * POINTS_PER_PIXEL + margin.left + margin.right, content.height * POINTS_PER_PIXEL + margin.top + margin.bottom];
|
|
35
|
+
if (Array.isArray(page)) return [page[0], page[1]];
|
|
36
|
+
return [...PAGE_SIZES[page]];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Where a canvas of `content` pixels goes on the page. `contain` shows all of
|
|
40
|
+
* it as large as fits, `cover` fills the box and crops, and `none` prints it
|
|
41
|
+
* at its real size (96 pixels to the inch) from the top-left of the box.
|
|
42
|
+
*/
|
|
43
|
+
function layoutPage(content, options = {}) {
|
|
44
|
+
const margin = normalizeMargin(options.margin);
|
|
45
|
+
const page = options.page ?? "canvas";
|
|
46
|
+
let [pageWidth, pageHeight] = pageSizeFor(page, content, margin);
|
|
47
|
+
const wantsLandscape = options.orientation === "landscape" || options.orientation !== "portrait" && page !== "canvas" && !Array.isArray(page) && content.width > content.height;
|
|
48
|
+
if (page !== "canvas" && !Array.isArray(page) && wantsLandscape !== pageWidth > pageHeight) [pageWidth, pageHeight] = [pageHeight, pageWidth];
|
|
49
|
+
const box = {
|
|
50
|
+
x: margin.left,
|
|
51
|
+
y: margin.top,
|
|
52
|
+
width: Math.max(0, pageWidth - margin.left - margin.right),
|
|
53
|
+
height: Math.max(0, pageHeight - margin.top - margin.bottom)
|
|
54
|
+
};
|
|
55
|
+
const fit = options.fit ?? "contain";
|
|
56
|
+
const scaleX = content.width > 0 ? box.width / content.width : 1;
|
|
57
|
+
const scaleY = content.height > 0 ? box.height / content.height : 1;
|
|
58
|
+
const scale = fit === "none" ? POINTS_PER_PIXEL : fit === "cover" ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
|
|
59
|
+
const width = content.width * scale;
|
|
60
|
+
const height = content.height * scale;
|
|
61
|
+
const centered = fit !== "none";
|
|
62
|
+
const layout = {
|
|
63
|
+
pageWidth,
|
|
64
|
+
pageHeight,
|
|
65
|
+
orientation: pageWidth > pageHeight ? "landscape" : "portrait",
|
|
66
|
+
x: centered ? box.x + (box.width - width) / 2 : box.x,
|
|
67
|
+
y: centered ? box.y + (box.height - height) / 2 : box.y,
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
scale
|
|
71
|
+
};
|
|
72
|
+
if (width > box.width + .01 || height > box.height + .01) layout.clip = box;
|
|
73
|
+
return layout;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
exports.PAGE_SIZES = PAGE_SIZES;
|
|
77
|
+
exports.POINTS_PER_PIXEL = POINTS_PER_PIXEL;
|
|
78
|
+
exports.layoutPage = layoutPage;
|
|
79
|
+
exports.normalizeMargin = normalizeMargin;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/pdf/page-layout.d.ts
|
|
2
|
+
/** Page sizes in PDF points (1/72 inch), portrait. */
|
|
3
|
+
export declare const PAGE_SIZES: Readonly<Record<NamedPageSize, readonly [number, number]>>;
|
|
4
|
+
export type NamedPageSize = "A3" | "A4" | "A5" | "Letter" | "Legal" | "Tabloid";
|
|
5
|
+
/** A named size, `canvas` for a page the size of the canvas, or `[width, height]` in points. */
|
|
6
|
+
export type PdfPageSize = NamedPageSize | "canvas" | readonly [number, number];
|
|
7
|
+
export type PdfOrientation = "portrait" | "landscape" | "auto";
|
|
8
|
+
export type PdfFit = "contain" | "cover" | "none";
|
|
9
|
+
export interface PdfMargin {
|
|
10
|
+
top: number;
|
|
11
|
+
right: number;
|
|
12
|
+
bottom: number;
|
|
13
|
+
left: number;
|
|
14
|
+
}
|
|
15
|
+
/** One CSS pixel is 1/96 inch, and a PDF point 1/72 inch. */
|
|
16
|
+
export declare const POINTS_PER_PIXEL = .75;
|
|
17
|
+
export interface PageLayoutOptions {
|
|
18
|
+
page?: PdfPageSize;
|
|
19
|
+
orientation?: PdfOrientation;
|
|
20
|
+
margin?: number | Partial<PdfMargin>;
|
|
21
|
+
fit?: PdfFit;
|
|
22
|
+
}
|
|
23
|
+
export interface PageLayout {
|
|
24
|
+
pageWidth: number;
|
|
25
|
+
pageHeight: number;
|
|
26
|
+
orientation: "portrait" | "landscape";
|
|
27
|
+
/** Where the canvas is drawn, in points. It can be larger than the page with `cover`. */
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
/** Points per canvas pixel. */
|
|
33
|
+
scale: number;
|
|
34
|
+
/** The box inside the margins, set when the drawing must be clipped to it. */
|
|
35
|
+
clip?: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Where a canvas of `content` pixels goes on the page. `contain` shows all of
|
|
44
|
+
* it as large as fits, `cover` fills the box and crops, and `none` prints it
|
|
45
|
+
* at its real size (96 pixels to the inch) from the top-left of the box.
|
|
46
|
+
*/
|
|
47
|
+
export declare function layoutPage(content: {
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
}, options?: PageLayoutOptions): PageLayout;
|
|
51
|
+
//#endregion
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/pdf/page-layout.d.ts
|
|
2
|
+
/** Page sizes in PDF points (1/72 inch), portrait. */
|
|
3
|
+
export declare const PAGE_SIZES: Readonly<Record<NamedPageSize, readonly [number, number]>>;
|
|
4
|
+
export type NamedPageSize = "A3" | "A4" | "A5" | "Letter" | "Legal" | "Tabloid";
|
|
5
|
+
/** A named size, `canvas` for a page the size of the canvas, or `[width, height]` in points. */
|
|
6
|
+
export type PdfPageSize = NamedPageSize | "canvas" | readonly [number, number];
|
|
7
|
+
export type PdfOrientation = "portrait" | "landscape" | "auto";
|
|
8
|
+
export type PdfFit = "contain" | "cover" | "none";
|
|
9
|
+
export interface PdfMargin {
|
|
10
|
+
top: number;
|
|
11
|
+
right: number;
|
|
12
|
+
bottom: number;
|
|
13
|
+
left: number;
|
|
14
|
+
}
|
|
15
|
+
/** One CSS pixel is 1/96 inch, and a PDF point 1/72 inch. */
|
|
16
|
+
export declare const POINTS_PER_PIXEL = .75;
|
|
17
|
+
export interface PageLayoutOptions {
|
|
18
|
+
page?: PdfPageSize;
|
|
19
|
+
orientation?: PdfOrientation;
|
|
20
|
+
margin?: number | Partial<PdfMargin>;
|
|
21
|
+
fit?: PdfFit;
|
|
22
|
+
}
|
|
23
|
+
export interface PageLayout {
|
|
24
|
+
pageWidth: number;
|
|
25
|
+
pageHeight: number;
|
|
26
|
+
orientation: "portrait" | "landscape";
|
|
27
|
+
/** Where the canvas is drawn, in points. It can be larger than the page with `cover`. */
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
/** Points per canvas pixel. */
|
|
33
|
+
scale: number;
|
|
34
|
+
/** The box inside the margins, set when the drawing must be clipped to it. */
|
|
35
|
+
clip?: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Where a canvas of `content` pixels goes on the page. `contain` shows all of
|
|
44
|
+
* it as large as fits, `cover` fills the box and crops, and `none` prints it
|
|
45
|
+
* at its real size (96 pixels to the inch) from the top-left of the box.
|
|
46
|
+
*/
|
|
47
|
+
export declare function layoutPage(content: {
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
}, options?: PageLayoutOptions): PageLayout;
|
|
51
|
+
//#endregion
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//#region src/pdf/page-layout.ts
|
|
2
|
+
/** Page sizes in PDF points (1/72 inch), portrait. */
|
|
3
|
+
const PAGE_SIZES = {
|
|
4
|
+
A3: [841.89, 1190.55],
|
|
5
|
+
A4: [595.28, 841.89],
|
|
6
|
+
A5: [419.53, 595.28],
|
|
7
|
+
Letter: [612, 792],
|
|
8
|
+
Legal: [612, 1008],
|
|
9
|
+
Tabloid: [792, 1224]
|
|
10
|
+
};
|
|
11
|
+
/** One CSS pixel is 1/96 inch, and a PDF point 1/72 inch. */
|
|
12
|
+
const POINTS_PER_PIXEL = .75;
|
|
13
|
+
function normalizeMargin(margin) {
|
|
14
|
+
if (margin === void 0) return {
|
|
15
|
+
top: 0,
|
|
16
|
+
right: 0,
|
|
17
|
+
bottom: 0,
|
|
18
|
+
left: 0
|
|
19
|
+
};
|
|
20
|
+
if (typeof margin === "number") return {
|
|
21
|
+
top: margin,
|
|
22
|
+
right: margin,
|
|
23
|
+
bottom: margin,
|
|
24
|
+
left: margin
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
top: margin.top ?? 0,
|
|
28
|
+
right: margin.right ?? 0,
|
|
29
|
+
bottom: margin.bottom ?? 0,
|
|
30
|
+
left: margin.left ?? 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function pageSizeFor(page, content, margin) {
|
|
34
|
+
if (page === "canvas") return [content.width * POINTS_PER_PIXEL + margin.left + margin.right, content.height * POINTS_PER_PIXEL + margin.top + margin.bottom];
|
|
35
|
+
if (Array.isArray(page)) return [page[0], page[1]];
|
|
36
|
+
return [...PAGE_SIZES[page]];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Where a canvas of `content` pixels goes on the page. `contain` shows all of
|
|
40
|
+
* it as large as fits, `cover` fills the box and crops, and `none` prints it
|
|
41
|
+
* at its real size (96 pixels to the inch) from the top-left of the box.
|
|
42
|
+
*/
|
|
43
|
+
function layoutPage(content, options = {}) {
|
|
44
|
+
const margin = normalizeMargin(options.margin);
|
|
45
|
+
const page = options.page ?? "canvas";
|
|
46
|
+
let [pageWidth, pageHeight] = pageSizeFor(page, content, margin);
|
|
47
|
+
const wantsLandscape = options.orientation === "landscape" || options.orientation !== "portrait" && page !== "canvas" && !Array.isArray(page) && content.width > content.height;
|
|
48
|
+
if (page !== "canvas" && !Array.isArray(page) && wantsLandscape !== pageWidth > pageHeight) [pageWidth, pageHeight] = [pageHeight, pageWidth];
|
|
49
|
+
const box = {
|
|
50
|
+
x: margin.left,
|
|
51
|
+
y: margin.top,
|
|
52
|
+
width: Math.max(0, pageWidth - margin.left - margin.right),
|
|
53
|
+
height: Math.max(0, pageHeight - margin.top - margin.bottom)
|
|
54
|
+
};
|
|
55
|
+
const fit = options.fit ?? "contain";
|
|
56
|
+
const scaleX = content.width > 0 ? box.width / content.width : 1;
|
|
57
|
+
const scaleY = content.height > 0 ? box.height / content.height : 1;
|
|
58
|
+
const scale = fit === "none" ? POINTS_PER_PIXEL : fit === "cover" ? Math.max(scaleX, scaleY) : Math.min(scaleX, scaleY);
|
|
59
|
+
const width = content.width * scale;
|
|
60
|
+
const height = content.height * scale;
|
|
61
|
+
const centered = fit !== "none";
|
|
62
|
+
const layout = {
|
|
63
|
+
pageWidth,
|
|
64
|
+
pageHeight,
|
|
65
|
+
orientation: pageWidth > pageHeight ? "landscape" : "portrait",
|
|
66
|
+
x: centered ? box.x + (box.width - width) / 2 : box.x,
|
|
67
|
+
y: centered ? box.y + (box.height - height) / 2 : box.y,
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
scale
|
|
71
|
+
};
|
|
72
|
+
if (width > box.width + .01 || height > box.height + .01) layout.clip = box;
|
|
73
|
+
return layout;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { PAGE_SIZES, POINTS_PER_PIXEL, layoutPage, normalizeMargin };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//#region src/pdf/text-decorations.ts
|
|
2
|
+
const DECORATIONS = [
|
|
3
|
+
"underline",
|
|
4
|
+
"overline",
|
|
5
|
+
"linethrough"
|
|
6
|
+
];
|
|
7
|
+
function num(value) {
|
|
8
|
+
return Number.isFinite(value) ? String(Math.round(value * 1e4) / 1e4) : "0";
|
|
9
|
+
}
|
|
10
|
+
function escapeAttribute(value) {
|
|
11
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
12
|
+
}
|
|
13
|
+
function isText(object) {
|
|
14
|
+
const candidate = object;
|
|
15
|
+
return Array.isArray(candidate._textLines) && typeof candidate.getValueOfPropertyAt === "function" && !candidate.path;
|
|
16
|
+
}
|
|
17
|
+
function hasStraightDecorations(object) {
|
|
18
|
+
if (!isText(object)) return false;
|
|
19
|
+
return DECORATIONS.some((type) => object[type] || object.styleHas(type));
|
|
20
|
+
}
|
|
21
|
+
function rect(x, y, width, height, color) {
|
|
22
|
+
if (typeof color !== "string" || width <= 0 || height <= 0) return "";
|
|
23
|
+
return `\t\t<rect x="${num(x)}" y="${num(y)}" width="${num(width)}" height="${num(height)}" fill="${escapeAttribute(color)}" />\n`;
|
|
24
|
+
}
|
|
25
|
+
/** The same boxes as Fabric's `_renderTextDecoration` for text that is not on a path. */
|
|
26
|
+
function decorationRects(text, type) {
|
|
27
|
+
if (!text[type] && !text.styleHas(type)) return "";
|
|
28
|
+
let markup = "";
|
|
29
|
+
let topOffset = text._getTopOffset();
|
|
30
|
+
const leftOffset = text._getLeftOffset();
|
|
31
|
+
const charSpacing = text._getWidthOfCharSpacing();
|
|
32
|
+
const aligner = type === "linethrough" ? .5 : type === "overline" ? 1 : 0;
|
|
33
|
+
const offsetY = text.offsets[type];
|
|
34
|
+
const at = (line, char, property) => text.getValueOfPropertyAt(line, char, property);
|
|
35
|
+
const colorAt = (line, char) => at(line, char, "textDecorationColor") || at(line, char, "fill");
|
|
36
|
+
const thicknessAt = (line, char) => Number(at(line, char, "textDecorationThickness") ?? 66.667);
|
|
37
|
+
for (let lineIndex = 0; lineIndex < text._textLines.length; lineIndex += 1) {
|
|
38
|
+
const heightOfLine = text.getHeightOfLine(lineIndex);
|
|
39
|
+
if (!text[type] && !text.styleHas(type, lineIndex)) {
|
|
40
|
+
topOffset += heightOfLine;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (!text.__charBounds[lineIndex]) text.getLineWidth(lineIndex);
|
|
44
|
+
const line = text._textLines[lineIndex];
|
|
45
|
+
const maxHeight = heightOfLine / text.lineHeight;
|
|
46
|
+
const lineLeftOffset = text._getLineLeftOffset(lineIndex);
|
|
47
|
+
const top = topOffset + maxHeight * (1 - text._fontSizeFraction);
|
|
48
|
+
let boxStart = 0;
|
|
49
|
+
let boxWidth = 0;
|
|
50
|
+
let lastDecoration = at(lineIndex, 0, type);
|
|
51
|
+
let lastFill = at(lineIndex, 0, "fill");
|
|
52
|
+
let lastColor = colorAt(lineIndex, 0);
|
|
53
|
+
let lastThickness = thicknessAt(lineIndex, 0);
|
|
54
|
+
let size = text.getHeightOfChar(lineIndex, 0);
|
|
55
|
+
let dy = Number(at(lineIndex, 0, "deltaY") ?? 0);
|
|
56
|
+
let currentDecoration = lastDecoration;
|
|
57
|
+
let currentColor = lastColor;
|
|
58
|
+
let currentThickness = lastThickness;
|
|
59
|
+
const startOf = (start, width) => {
|
|
60
|
+
const drawStart = leftOffset + lineLeftOffset + start;
|
|
61
|
+
return text.direction === "rtl" ? text.width - drawStart - width : drawStart;
|
|
62
|
+
};
|
|
63
|
+
for (let charIndex = 0; charIndex < line.length; charIndex += 1) {
|
|
64
|
+
const box = text.__charBounds[lineIndex][charIndex];
|
|
65
|
+
currentDecoration = at(lineIndex, charIndex, type);
|
|
66
|
+
const currentFill = at(lineIndex, charIndex, "fill");
|
|
67
|
+
currentColor = colorAt(lineIndex, charIndex);
|
|
68
|
+
currentThickness = thicknessAt(lineIndex, charIndex);
|
|
69
|
+
const currentSize = text.getHeightOfChar(lineIndex, charIndex);
|
|
70
|
+
const currentDy = Number(at(lineIndex, charIndex, "deltaY") ?? 0);
|
|
71
|
+
if ((currentDecoration !== lastDecoration || currentFill !== lastFill || currentColor !== lastColor || currentSize !== size || currentThickness !== lastThickness || currentDy !== dy) && boxWidth > 0) {
|
|
72
|
+
const thickness = text.fontSize * lastThickness / 1e3;
|
|
73
|
+
if (lastDecoration && lastColor && lastThickness) markup += rect(startOf(boxStart, boxWidth), top + offsetY * size + dy - aligner * thickness, boxWidth, thickness, lastColor);
|
|
74
|
+
boxStart = box.left;
|
|
75
|
+
boxWidth = box.width;
|
|
76
|
+
lastDecoration = currentDecoration;
|
|
77
|
+
lastColor = currentColor;
|
|
78
|
+
lastThickness = currentThickness;
|
|
79
|
+
lastFill = currentFill;
|
|
80
|
+
size = currentSize;
|
|
81
|
+
dy = currentDy;
|
|
82
|
+
} else boxWidth += box.kernedWidth;
|
|
83
|
+
}
|
|
84
|
+
const thickness = text.fontSize * currentThickness / 1e3;
|
|
85
|
+
if (currentDecoration && currentColor && currentThickness) markup += rect(startOf(boxStart, boxWidth), top + offsetY * size + dy - aligner * thickness, boxWidth - charSpacing, thickness, currentColor);
|
|
86
|
+
topOffset += heightOfLine;
|
|
87
|
+
}
|
|
88
|
+
return markup;
|
|
89
|
+
}
|
|
90
|
+
/** SVG for straight text with its decorations as boxes instead of CSS. */
|
|
91
|
+
function decoratedTextToSVG(object, reviver) {
|
|
92
|
+
const text = object;
|
|
93
|
+
const inner = text._toSVG().join("").replace(/\stext-decoration="[^"]*"/g, "").replace(/text-decoration:[^;"]*;?\s*/g, "");
|
|
94
|
+
const markup = [
|
|
95
|
+
decorationRects(text, "underline"),
|
|
96
|
+
inner,
|
|
97
|
+
decorationRects(text, "overline"),
|
|
98
|
+
decorationRects(text, "linethrough")
|
|
99
|
+
];
|
|
100
|
+
return text._createBaseSVGMarkup(markup, {
|
|
101
|
+
reviver,
|
|
102
|
+
noStyle: true,
|
|
103
|
+
withShadow: true
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
exports.decoratedTextToSVG = decoratedTextToSVG;
|
|
108
|
+
exports.hasStraightDecorations = hasStraightDecorations;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region src/pdf/text-decorations.ts
|
|
2
|
+
const DECORATIONS = [
|
|
3
|
+
"underline",
|
|
4
|
+
"overline",
|
|
5
|
+
"linethrough"
|
|
6
|
+
];
|
|
7
|
+
function num(value) {
|
|
8
|
+
return Number.isFinite(value) ? String(Math.round(value * 1e4) / 1e4) : "0";
|
|
9
|
+
}
|
|
10
|
+
function escapeAttribute(value) {
|
|
11
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
12
|
+
}
|
|
13
|
+
function isText(object) {
|
|
14
|
+
const candidate = object;
|
|
15
|
+
return Array.isArray(candidate._textLines) && typeof candidate.getValueOfPropertyAt === "function" && !candidate.path;
|
|
16
|
+
}
|
|
17
|
+
function hasStraightDecorations(object) {
|
|
18
|
+
if (!isText(object)) return false;
|
|
19
|
+
return DECORATIONS.some((type) => object[type] || object.styleHas(type));
|
|
20
|
+
}
|
|
21
|
+
function rect(x, y, width, height, color) {
|
|
22
|
+
if (typeof color !== "string" || width <= 0 || height <= 0) return "";
|
|
23
|
+
return `\t\t<rect x="${num(x)}" y="${num(y)}" width="${num(width)}" height="${num(height)}" fill="${escapeAttribute(color)}" />\n`;
|
|
24
|
+
}
|
|
25
|
+
/** The same boxes as Fabric's `_renderTextDecoration` for text that is not on a path. */
|
|
26
|
+
function decorationRects(text, type) {
|
|
27
|
+
if (!text[type] && !text.styleHas(type)) return "";
|
|
28
|
+
let markup = "";
|
|
29
|
+
let topOffset = text._getTopOffset();
|
|
30
|
+
const leftOffset = text._getLeftOffset();
|
|
31
|
+
const charSpacing = text._getWidthOfCharSpacing();
|
|
32
|
+
const aligner = type === "linethrough" ? .5 : type === "overline" ? 1 : 0;
|
|
33
|
+
const offsetY = text.offsets[type];
|
|
34
|
+
const at = (line, char, property) => text.getValueOfPropertyAt(line, char, property);
|
|
35
|
+
const colorAt = (line, char) => at(line, char, "textDecorationColor") || at(line, char, "fill");
|
|
36
|
+
const thicknessAt = (line, char) => Number(at(line, char, "textDecorationThickness") ?? 66.667);
|
|
37
|
+
for (let lineIndex = 0; lineIndex < text._textLines.length; lineIndex += 1) {
|
|
38
|
+
const heightOfLine = text.getHeightOfLine(lineIndex);
|
|
39
|
+
if (!text[type] && !text.styleHas(type, lineIndex)) {
|
|
40
|
+
topOffset += heightOfLine;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (!text.__charBounds[lineIndex]) text.getLineWidth(lineIndex);
|
|
44
|
+
const line = text._textLines[lineIndex];
|
|
45
|
+
const maxHeight = heightOfLine / text.lineHeight;
|
|
46
|
+
const lineLeftOffset = text._getLineLeftOffset(lineIndex);
|
|
47
|
+
const top = topOffset + maxHeight * (1 - text._fontSizeFraction);
|
|
48
|
+
let boxStart = 0;
|
|
49
|
+
let boxWidth = 0;
|
|
50
|
+
let lastDecoration = at(lineIndex, 0, type);
|
|
51
|
+
let lastFill = at(lineIndex, 0, "fill");
|
|
52
|
+
let lastColor = colorAt(lineIndex, 0);
|
|
53
|
+
let lastThickness = thicknessAt(lineIndex, 0);
|
|
54
|
+
let size = text.getHeightOfChar(lineIndex, 0);
|
|
55
|
+
let dy = Number(at(lineIndex, 0, "deltaY") ?? 0);
|
|
56
|
+
let currentDecoration = lastDecoration;
|
|
57
|
+
let currentColor = lastColor;
|
|
58
|
+
let currentThickness = lastThickness;
|
|
59
|
+
const startOf = (start, width) => {
|
|
60
|
+
const drawStart = leftOffset + lineLeftOffset + start;
|
|
61
|
+
return text.direction === "rtl" ? text.width - drawStart - width : drawStart;
|
|
62
|
+
};
|
|
63
|
+
for (let charIndex = 0; charIndex < line.length; charIndex += 1) {
|
|
64
|
+
const box = text.__charBounds[lineIndex][charIndex];
|
|
65
|
+
currentDecoration = at(lineIndex, charIndex, type);
|
|
66
|
+
const currentFill = at(lineIndex, charIndex, "fill");
|
|
67
|
+
currentColor = colorAt(lineIndex, charIndex);
|
|
68
|
+
currentThickness = thicknessAt(lineIndex, charIndex);
|
|
69
|
+
const currentSize = text.getHeightOfChar(lineIndex, charIndex);
|
|
70
|
+
const currentDy = Number(at(lineIndex, charIndex, "deltaY") ?? 0);
|
|
71
|
+
if ((currentDecoration !== lastDecoration || currentFill !== lastFill || currentColor !== lastColor || currentSize !== size || currentThickness !== lastThickness || currentDy !== dy) && boxWidth > 0) {
|
|
72
|
+
const thickness = text.fontSize * lastThickness / 1e3;
|
|
73
|
+
if (lastDecoration && lastColor && lastThickness) markup += rect(startOf(boxStart, boxWidth), top + offsetY * size + dy - aligner * thickness, boxWidth, thickness, lastColor);
|
|
74
|
+
boxStart = box.left;
|
|
75
|
+
boxWidth = box.width;
|
|
76
|
+
lastDecoration = currentDecoration;
|
|
77
|
+
lastColor = currentColor;
|
|
78
|
+
lastThickness = currentThickness;
|
|
79
|
+
lastFill = currentFill;
|
|
80
|
+
size = currentSize;
|
|
81
|
+
dy = currentDy;
|
|
82
|
+
} else boxWidth += box.kernedWidth;
|
|
83
|
+
}
|
|
84
|
+
const thickness = text.fontSize * currentThickness / 1e3;
|
|
85
|
+
if (currentDecoration && currentColor && currentThickness) markup += rect(startOf(boxStart, boxWidth), top + offsetY * size + dy - aligner * thickness, boxWidth - charSpacing, thickness, currentColor);
|
|
86
|
+
topOffset += heightOfLine;
|
|
87
|
+
}
|
|
88
|
+
return markup;
|
|
89
|
+
}
|
|
90
|
+
/** SVG for straight text with its decorations as boxes instead of CSS. */
|
|
91
|
+
function decoratedTextToSVG(object, reviver) {
|
|
92
|
+
const text = object;
|
|
93
|
+
const inner = text._toSVG().join("").replace(/\stext-decoration="[^"]*"/g, "").replace(/text-decoration:[^;"]*;?\s*/g, "");
|
|
94
|
+
const markup = [
|
|
95
|
+
decorationRects(text, "underline"),
|
|
96
|
+
inner,
|
|
97
|
+
decorationRects(text, "overline"),
|
|
98
|
+
decorationRects(text, "linethrough")
|
|
99
|
+
];
|
|
100
|
+
return text._createBaseSVGMarkup(markup, {
|
|
101
|
+
reviver,
|
|
102
|
+
noStyle: true,
|
|
103
|
+
withShadow: true
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
export { decoratedTextToSVG, hasStraightDecorations };
|
package/dist/pdf.cjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_page_layout = require("./pdf/page-layout.cjs");
|
|
3
|
+
const require_export_pdf = require("./pdf/export-pdf.cjs");
|
|
4
|
+
exports.PAGE_SIZES = require_page_layout.PAGE_SIZES;
|
|
5
|
+
exports.POINTS_PER_PIXEL = require_page_layout.POINTS_PER_PIXEL;
|
|
6
|
+
exports.exportPdf = require_export_pdf.exportPdf;
|
|
7
|
+
exports.layoutPage = require_page_layout.layoutPage;
|
package/dist/pdf.d.cts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PdfFont, PdfFontStyle } from "./pdf/fonts.cjs";
|
|
2
|
+
import { NamedPageSize, PAGE_SIZES, POINTS_PER_PIXEL, PageLayout, PageLayoutOptions, PdfFit, PdfMargin, PdfOrientation, PdfPageSize, layoutPage } from "./pdf/page-layout.cjs";
|
|
3
|
+
import { PdfExportOptions, PdfExportResult, PdfMode, PdfSource, PdfWarning, PdfWarningCode, exportPdf } from "./pdf/export-pdf.cjs";
|
|
4
|
+
export { type NamedPageSize, PAGE_SIZES, POINTS_PER_PIXEL, type PageLayout, type PageLayoutOptions, type PdfExportOptions, type PdfExportResult, type PdfFit, type PdfFont, type PdfFontStyle, type PdfMargin, type PdfMode, type PdfOrientation, type PdfPageSize, type PdfSource, type PdfWarning, type PdfWarningCode, exportPdf, layoutPage };
|
package/dist/pdf.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PdfFont, PdfFontStyle } from "./pdf/fonts.js";
|
|
2
|
+
import { NamedPageSize, PAGE_SIZES, POINTS_PER_PIXEL, PageLayout, PageLayoutOptions, PdfFit, PdfMargin, PdfOrientation, PdfPageSize, layoutPage } from "./pdf/page-layout.js";
|
|
3
|
+
import { PdfExportOptions, PdfExportResult, PdfMode, PdfSource, PdfWarning, PdfWarningCode, exportPdf } from "./pdf/export-pdf.js";
|
|
4
|
+
export { type NamedPageSize, PAGE_SIZES, POINTS_PER_PIXEL, type PageLayout, type PageLayoutOptions, type PdfExportOptions, type PdfExportResult, type PdfFit, type PdfFont, type PdfFontStyle, type PdfMargin, type PdfMode, type PdfOrientation, type PdfPageSize, type PdfSource, type PdfWarning, type PdfWarningCode, exportPdf, layoutPage };
|
package/dist/pdf.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const require_layers = require("../commands/layers.cjs");
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region src/react/use-layers.ts
|
|
4
|
+
const noLayers = [];
|
|
5
|
+
const subscribeToNothing = () => () => void 0;
|
|
6
|
+
const nothing = () => noLayers;
|
|
7
|
+
function sameLayers(first, second) {
|
|
8
|
+
return first.length === second.length && first.every((layer, index) => {
|
|
9
|
+
const other = second[index];
|
|
10
|
+
return layer.id === other.id && layer.type === other.type && layer.name === other.name && layer.index === other.index && layer.visible === other.visible && layer.locked === other.locked;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function createLayerStore(engine) {
|
|
14
|
+
let snapshot = require_layers.getLayers(engine);
|
|
15
|
+
const refresh = () => {
|
|
16
|
+
const next = require_layers.getLayers(engine);
|
|
17
|
+
if (sameLayers(next, snapshot)) return false;
|
|
18
|
+
snapshot = next;
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
subscribe(onChange) {
|
|
23
|
+
const update = () => {
|
|
24
|
+
if (refresh()) onChange();
|
|
25
|
+
};
|
|
26
|
+
const stops = [
|
|
27
|
+
engine.on("history:change", update),
|
|
28
|
+
engine.on("document:change", update),
|
|
29
|
+
engine.on("load:success", update)
|
|
30
|
+
];
|
|
31
|
+
engine.canvas.on("object:added", update);
|
|
32
|
+
engine.canvas.on("object:removed", update);
|
|
33
|
+
update();
|
|
34
|
+
return () => {
|
|
35
|
+
stops.forEach((stop) => stop());
|
|
36
|
+
engine.canvas.off("object:added", update);
|
|
37
|
+
engine.canvas.off("object:removed", update);
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
getSnapshot: () => snapshot
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The layers of the canvas from top to bottom. It updates after every undo
|
|
45
|
+
* step, load and add or remove. A change that is not recorded, such as
|
|
46
|
+
* `object.set('visible', false)` alone, shows after `engine.commit()`.
|
|
47
|
+
*/
|
|
48
|
+
function useLayers(engine) {
|
|
49
|
+
const store = (0, react.useMemo)(() => engine ? createLayerStore(engine) : null, [engine]);
|
|
50
|
+
return (0, react.useSyncExternalStore)(store ? store.subscribe : subscribeToNothing, store ? store.getSnapshot : nothing, nothing);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
exports.useLayers = useLayers;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DocumentEngine } from "../engine/create-document-engine.cjs";
|
|
2
|
+
import { LayerInfo } from "../commands/layers.cjs";
|
|
3
|
+
//#region src/react/use-layers.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The layers of the canvas from top to bottom. It updates after every undo
|
|
6
|
+
* step, load and add or remove. A change that is not recorded, such as
|
|
7
|
+
* `object.set('visible', false)` alone, shows after `engine.commit()`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useLayers(engine: DocumentEngine | null | undefined): LayerInfo[];
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DocumentEngine } from "../engine/create-document-engine.js";
|
|
2
|
+
import { LayerInfo } from "../commands/layers.js";
|
|
3
|
+
//#region src/react/use-layers.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The layers of the canvas from top to bottom. It updates after every undo
|
|
6
|
+
* step, load and add or remove. A change that is not recorded, such as
|
|
7
|
+
* `object.set('visible', false)` alone, shows after `engine.commit()`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useLayers(engine: DocumentEngine | null | undefined): LayerInfo[];
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getLayers } from "../commands/layers.js";
|
|
2
|
+
import { useMemo, useSyncExternalStore } from "react";
|
|
3
|
+
//#region src/react/use-layers.ts
|
|
4
|
+
const noLayers = [];
|
|
5
|
+
const subscribeToNothing = () => () => void 0;
|
|
6
|
+
const nothing = () => noLayers;
|
|
7
|
+
function sameLayers(first, second) {
|
|
8
|
+
return first.length === second.length && first.every((layer, index) => {
|
|
9
|
+
const other = second[index];
|
|
10
|
+
return layer.id === other.id && layer.type === other.type && layer.name === other.name && layer.index === other.index && layer.visible === other.visible && layer.locked === other.locked;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function createLayerStore(engine) {
|
|
14
|
+
let snapshot = getLayers(engine);
|
|
15
|
+
const refresh = () => {
|
|
16
|
+
const next = getLayers(engine);
|
|
17
|
+
if (sameLayers(next, snapshot)) return false;
|
|
18
|
+
snapshot = next;
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
subscribe(onChange) {
|
|
23
|
+
const update = () => {
|
|
24
|
+
if (refresh()) onChange();
|
|
25
|
+
};
|
|
26
|
+
const stops = [
|
|
27
|
+
engine.on("history:change", update),
|
|
28
|
+
engine.on("document:change", update),
|
|
29
|
+
engine.on("load:success", update)
|
|
30
|
+
];
|
|
31
|
+
engine.canvas.on("object:added", update);
|
|
32
|
+
engine.canvas.on("object:removed", update);
|
|
33
|
+
update();
|
|
34
|
+
return () => {
|
|
35
|
+
stops.forEach((stop) => stop());
|
|
36
|
+
engine.canvas.off("object:added", update);
|
|
37
|
+
engine.canvas.off("object:removed", update);
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
getSnapshot: () => snapshot
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The layers of the canvas from top to bottom. It updates after every undo
|
|
45
|
+
* step, load and add or remove. A change that is not recorded, such as
|
|
46
|
+
* `object.set('visible', false)` alone, shows after `engine.commit()`.
|
|
47
|
+
*/
|
|
48
|
+
function useLayers(engine) {
|
|
49
|
+
const store = useMemo(() => engine ? createLayerStore(engine) : null, [engine]);
|
|
50
|
+
return useSyncExternalStore(store ? store.subscribe : subscribeToNothing, store ? store.getSnapshot : nothing, nothing);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { useLayers };
|
package/dist/react.cjs
CHANGED
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const require_use_document_engine = require("./react/use-document-engine.cjs");
|
|
4
4
|
const require_use_document_state = require("./react/use-document-state.cjs");
|
|
5
5
|
const require_use_document_event = require("./react/use-document-event.cjs");
|
|
6
|
+
const require_use_layers = require("./react/use-layers.cjs");
|
|
6
7
|
const require_engine_context = require("./react/engine-context.cjs");
|
|
7
8
|
exports.DocumentEngineProvider = require_engine_context.DocumentEngineProvider;
|
|
8
9
|
exports.useDocumentEngine = require_use_document_engine.useDocumentEngine;
|
|
9
10
|
exports.useDocumentEvent = require_use_document_event.useDocumentEvent;
|
|
10
11
|
exports.useDocumentState = require_use_document_state.useDocumentState;
|
|
11
12
|
exports.useEngine = require_engine_context.useEngine;
|
|
13
|
+
exports.useLayers = require_use_layers.useLayers;
|
package/dist/react.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DocumentState } from "./state/document-state-store.cjs";
|
|
2
|
+
import { LayerInfo } from "./commands/layers.cjs";
|
|
2
3
|
import { ReactEngineOptions, useDocumentEngine } from "./react/use-document-engine.cjs";
|
|
3
4
|
import { useDocumentState } from "./react/use-document-state.cjs";
|
|
4
5
|
import { useDocumentEvent } from "./react/use-document-event.cjs";
|
|
6
|
+
import { useLayers } from "./react/use-layers.cjs";
|
|
5
7
|
import { DocumentEngineProvider, DocumentEngineProviderProps, useEngine } from "./react/engine-context.cjs";
|
|
6
|
-
export { DocumentEngineProvider, type DocumentEngineProviderProps, type DocumentState, type ReactEngineOptions, useDocumentEngine, useDocumentEvent, useDocumentState, useEngine };
|
|
8
|
+
export { DocumentEngineProvider, type DocumentEngineProviderProps, type DocumentState, type LayerInfo, type ReactEngineOptions, useDocumentEngine, useDocumentEvent, useDocumentState, useEngine, useLayers };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DocumentState } from "./state/document-state-store.js";
|
|
2
|
+
import { LayerInfo } from "./commands/layers.js";
|
|
2
3
|
import { ReactEngineOptions, useDocumentEngine } from "./react/use-document-engine.js";
|
|
3
4
|
import { useDocumentState } from "./react/use-document-state.js";
|
|
4
5
|
import { useDocumentEvent } from "./react/use-document-event.js";
|
|
6
|
+
import { useLayers } from "./react/use-layers.js";
|
|
5
7
|
import { DocumentEngineProvider, DocumentEngineProviderProps, useEngine } from "./react/engine-context.js";
|
|
6
|
-
export { DocumentEngineProvider, type DocumentEngineProviderProps, type DocumentState, type ReactEngineOptions, useDocumentEngine, useDocumentEvent, useDocumentState, useEngine };
|
|
8
|
+
export { DocumentEngineProvider, type DocumentEngineProviderProps, type DocumentState, type LayerInfo, type ReactEngineOptions, useDocumentEngine, useDocumentEvent, useDocumentState, useEngine, useLayers };
|