html2canvas-pro 2.3.4 → 2.3.6
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/dist/html2canvas-pro.cjs +72 -23
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +72 -23
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +72 -23
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +3 -3
- package/dist/lib/dom/document-cloner.js +25 -6
- package/dist/lib/dom/element-container.js +6 -0
- package/dist/lib/dom/node-parser.js +42 -30
- package/dist/lib/render/canvas/canvas-renderer.js +42 -9
- package/dist/lib/render/canvas/text-renderer.js +8 -1
- package/dist/types/dom/document-cloner.d.ts +1 -1
- package/dist/types/dom/element-container.d.ts +6 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.3.
|
|
2
|
+
* html2canvas-pro 2.3.6 <https://yorickshan.github.io/html2canvas-pro/>
|
|
3
3
|
* Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
|
|
4
4
|
* Released under MIT License
|
|
5
5
|
*/
|
|
@@ -7030,14 +7030,19 @@ var DocumentCloner = class {
|
|
|
7030
7030
|
}
|
|
7031
7031
|
if (clone.loading === "lazy") clone.loading = "eager";
|
|
7032
7032
|
}
|
|
7033
|
-
if (isCustomElement(clone) && !isSVGElementNode(clone)) return this.createCustomElementClone(clone);
|
|
7033
|
+
if (isCustomElement(clone) && !isSVGElementNode(clone)) return this.createCustomElementClone(node, clone);
|
|
7034
7034
|
return clone;
|
|
7035
7035
|
}
|
|
7036
|
-
createCustomElementClone(
|
|
7036
|
+
createCustomElementClone(originalNode, clonedNode) {
|
|
7037
7037
|
const clone = document.createElement("div");
|
|
7038
|
-
clone.className =
|
|
7039
|
-
copyCSSStyles(
|
|
7040
|
-
|
|
7038
|
+
clone.className = clonedNode.className;
|
|
7039
|
+
copyCSSStyles(clonedNode.style, clone);
|
|
7040
|
+
const attributes = clonedNode.attributes;
|
|
7041
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
7042
|
+
const attr = attributes[i];
|
|
7043
|
+
if (attr.name !== "class" && attr.name !== "style") clone.setAttribute(attr.name, attr.value);
|
|
7044
|
+
}
|
|
7045
|
+
if (originalNode.shadowRoot) try {
|
|
7041
7046
|
clone.attachShadow({ mode: "open" });
|
|
7042
7047
|
} catch (e) {
|
|
7043
7048
|
this.context.logger.error("Failed to attach shadow root to custom element clone:", e);
|
|
@@ -7438,6 +7443,10 @@ var ElementContainer = class {
|
|
|
7438
7443
|
this.originalElement = element;
|
|
7439
7444
|
}
|
|
7440
7445
|
this.bounds = parseBounds(this.context, element);
|
|
7446
|
+
if (element.tagName === "FIELDSET") {
|
|
7447
|
+
const legend = element.querySelector(":scope > legend");
|
|
7448
|
+
if (legend) this.legendBounds = parseBounds(this.context, legend);
|
|
7449
|
+
}
|
|
7441
7450
|
if (isDebugging(element, 4)) this.debugRender = true;
|
|
7442
7451
|
}
|
|
7443
7452
|
/**
|
|
@@ -8179,18 +8188,29 @@ const LIST_OWNERS = [
|
|
|
8179
8188
|
const parseNodeTree = (context, node, parent, root) => {
|
|
8180
8189
|
for (let childNode = node.firstChild, nextNode; childNode; childNode = nextNode) {
|
|
8181
8190
|
nextNode = childNode.nextSibling;
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8191
|
+
parseChildNode(context, childNode, parent, root);
|
|
8192
|
+
}
|
|
8193
|
+
};
|
|
8194
|
+
/**
|
|
8195
|
+
* Parse a single node as a child of `parent`.
|
|
8196
|
+
*
|
|
8197
|
+
* Separated from the tree walk so that nodes assigned to a `<slot>` (including
|
|
8198
|
+
* bare text nodes, which have no child nodes) can be parsed directly. Without
|
|
8199
|
+
* this, slotted shadow-DOM content such as web component labels was silently
|
|
8200
|
+
* dropped because `parseNodeTree` only iterates `node.firstChild` (issue #226).
|
|
8201
|
+
*/
|
|
8202
|
+
const parseChildNode = (context, childNode, parent, root) => {
|
|
8203
|
+
if (isTextNode(childNode) && childNode.data.length > 0) parent.textNodes.push(new TextContainer(context, childNode, parent.styles));
|
|
8204
|
+
else if (isElementNode(childNode)) if (isSlotElement(childNode) && childNode.assignedNodes) childNode.assignedNodes().forEach((assignedNode) => parseChildNode(context, assignedNode, parent, root));
|
|
8205
|
+
else {
|
|
8206
|
+
const container = createContainer(context, childNode);
|
|
8207
|
+
if (container.styles.isVisible()) {
|
|
8208
|
+
if (createsRealStackingContext(childNode, container, root)) container.createsRealStackingContext = true;
|
|
8209
|
+
else if (createsStackingContext(container.styles)) container.createsStackingContext = true;
|
|
8210
|
+
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) container.isListOwner = true;
|
|
8211
|
+
parent.elements.push(container);
|
|
8212
|
+
if (childNode.shadowRoot) parseNodeTree(context, childNode.shadowRoot, container, root);
|
|
8213
|
+
else if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) parseNodeTree(context, childNode, container, root);
|
|
8194
8214
|
}
|
|
8195
8215
|
}
|
|
8196
8216
|
};
|
|
@@ -9063,6 +9083,7 @@ const measureBaseline = (ctx, fallback) => {
|
|
|
9063
9083
|
//#endregion
|
|
9064
9084
|
//#region src/render/canvas/text-renderer.ts
|
|
9065
9085
|
const iOSBrokenFonts = ["-apple-system", "system-ui"];
|
|
9086
|
+
const TEXT_OVERFLOW_EPSILON = 1;
|
|
9066
9087
|
/**
|
|
9067
9088
|
* Detect CJK (Chinese, Japanese, Korean) characters in a string.
|
|
9068
9089
|
* CJK characters use the ideographic baseline in browsers, which differs
|
|
@@ -9365,7 +9386,7 @@ var TextRenderer = class {
|
|
|
9365
9386
|
const firstTop = text.textBounds[0].bounds.top;
|
|
9366
9387
|
if (!text.textBounds.every((tb) => Math.abs(tb.bounds.top - firstTop) < lineHeight * .5)) return false;
|
|
9367
9388
|
let fullText = text.textBounds.map((tb) => tb.text).join("").replace(/\s+/g, " ").trim();
|
|
9368
|
-
if (this.ctx.measureText(fullText).width <= containerBounds.width) return false;
|
|
9389
|
+
if (this.ctx.measureText(fullText).width <= containerBounds.width + TEXT_OVERFLOW_EPSILON) return false;
|
|
9369
9390
|
const bounds = new TextBounds(this.truncateTextWithEllipsis(fullText, containerBounds.width, styles.letterSpacing), text.textBounds[0].bounds);
|
|
9370
9391
|
for (const layer of paintOrder) if (layer === 0) this.renderTextFillWithShadows(bounds, styles, baseline);
|
|
9371
9392
|
else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles, baseline);
|
|
@@ -10603,10 +10624,38 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
10603
10624
|
}
|
|
10604
10625
|
let side = 0;
|
|
10605
10626
|
for (const border of borders) {
|
|
10606
|
-
if (border.style !== 0 && !isTransparent(border.color) && border.width > 0)
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10627
|
+
if (border.style !== 0 && !isTransparent(border.color) && border.width > 0) {
|
|
10628
|
+
const renderBorderSide = async () => {
|
|
10629
|
+
if (border.style === 2) await this.borderRenderer.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 2);
|
|
10630
|
+
else if (border.style === 3) await this.borderRenderer.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 3);
|
|
10631
|
+
else if (border.style === 4) await this.borderRenderer.renderDoubleBorder(border.color, border.width, side, paint.curves);
|
|
10632
|
+
else await this.borderRenderer.renderSolidBorder(border.color, side, paint.curves);
|
|
10633
|
+
};
|
|
10634
|
+
const legend = paint.container.legendBounds;
|
|
10635
|
+
if (side === 0 && legend) {
|
|
10636
|
+
const bounds = paint.container.bounds;
|
|
10637
|
+
const legendLeft = legend.left - bounds.left;
|
|
10638
|
+
const legendRight = legend.left + legend.width - bounds.left;
|
|
10639
|
+
if (legendLeft > 0) {
|
|
10640
|
+
this.ctx.save();
|
|
10641
|
+
this.ctx.beginPath();
|
|
10642
|
+
this.ctx.rect(bounds.left, bounds.top, legendLeft, bounds.height);
|
|
10643
|
+
this.ctx.clip();
|
|
10644
|
+
await renderBorderSide();
|
|
10645
|
+
this.ctx.restore();
|
|
10646
|
+
}
|
|
10647
|
+
const rightStart = bounds.left + legendRight;
|
|
10648
|
+
const rightWidth = bounds.width - legendRight;
|
|
10649
|
+
if (rightWidth > 0) {
|
|
10650
|
+
this.ctx.save();
|
|
10651
|
+
this.ctx.beginPath();
|
|
10652
|
+
this.ctx.rect(rightStart, bounds.top, rightWidth, bounds.height);
|
|
10653
|
+
this.ctx.clip();
|
|
10654
|
+
await renderBorderSide();
|
|
10655
|
+
this.ctx.restore();
|
|
10656
|
+
}
|
|
10657
|
+
} else await renderBorderSide();
|
|
10658
|
+
}
|
|
10610
10659
|
side++;
|
|
10611
10660
|
}
|
|
10612
10661
|
}
|