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
package/dist/html2canvas-pro.js
CHANGED
|
@@ -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
|
*/
|
|
@@ -7037,14 +7037,19 @@
|
|
|
7037
7037
|
}
|
|
7038
7038
|
if (clone.loading === "lazy") clone.loading = "eager";
|
|
7039
7039
|
}
|
|
7040
|
-
if (isCustomElement(clone) && !isSVGElementNode(clone)) return this.createCustomElementClone(clone);
|
|
7040
|
+
if (isCustomElement(clone) && !isSVGElementNode(clone)) return this.createCustomElementClone(node, clone);
|
|
7041
7041
|
return clone;
|
|
7042
7042
|
}
|
|
7043
|
-
createCustomElementClone(
|
|
7043
|
+
createCustomElementClone(originalNode, clonedNode) {
|
|
7044
7044
|
const clone = document.createElement("div");
|
|
7045
|
-
clone.className =
|
|
7046
|
-
copyCSSStyles(
|
|
7047
|
-
|
|
7045
|
+
clone.className = clonedNode.className;
|
|
7046
|
+
copyCSSStyles(clonedNode.style, clone);
|
|
7047
|
+
const attributes = clonedNode.attributes;
|
|
7048
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
7049
|
+
const attr = attributes[i];
|
|
7050
|
+
if (attr.name !== "class" && attr.name !== "style") clone.setAttribute(attr.name, attr.value);
|
|
7051
|
+
}
|
|
7052
|
+
if (originalNode.shadowRoot) try {
|
|
7048
7053
|
clone.attachShadow({ mode: "open" });
|
|
7049
7054
|
} catch (e) {
|
|
7050
7055
|
this.context.logger.error("Failed to attach shadow root to custom element clone:", e);
|
|
@@ -7445,6 +7450,10 @@
|
|
|
7445
7450
|
this.originalElement = element;
|
|
7446
7451
|
}
|
|
7447
7452
|
this.bounds = parseBounds(this.context, element);
|
|
7453
|
+
if (element.tagName === "FIELDSET") {
|
|
7454
|
+
const legend = element.querySelector(":scope > legend");
|
|
7455
|
+
if (legend) this.legendBounds = parseBounds(this.context, legend);
|
|
7456
|
+
}
|
|
7448
7457
|
if (isDebugging(element, 4)) this.debugRender = true;
|
|
7449
7458
|
}
|
|
7450
7459
|
/**
|
|
@@ -8186,18 +8195,29 @@
|
|
|
8186
8195
|
const parseNodeTree = (context, node, parent, root) => {
|
|
8187
8196
|
for (let childNode = node.firstChild, nextNode; childNode; childNode = nextNode) {
|
|
8188
8197
|
nextNode = childNode.nextSibling;
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8198
|
+
parseChildNode(context, childNode, parent, root);
|
|
8199
|
+
}
|
|
8200
|
+
};
|
|
8201
|
+
/**
|
|
8202
|
+
* Parse a single node as a child of `parent`.
|
|
8203
|
+
*
|
|
8204
|
+
* Separated from the tree walk so that nodes assigned to a `<slot>` (including
|
|
8205
|
+
* bare text nodes, which have no child nodes) can be parsed directly. Without
|
|
8206
|
+
* this, slotted shadow-DOM content such as web component labels was silently
|
|
8207
|
+
* dropped because `parseNodeTree` only iterates `node.firstChild` (issue #226).
|
|
8208
|
+
*/
|
|
8209
|
+
const parseChildNode = (context, childNode, parent, root) => {
|
|
8210
|
+
if (isTextNode(childNode) && childNode.data.length > 0) parent.textNodes.push(new TextContainer(context, childNode, parent.styles));
|
|
8211
|
+
else if (isElementNode(childNode)) if (isSlotElement(childNode) && childNode.assignedNodes) childNode.assignedNodes().forEach((assignedNode) => parseChildNode(context, assignedNode, parent, root));
|
|
8212
|
+
else {
|
|
8213
|
+
const container = createContainer(context, childNode);
|
|
8214
|
+
if (container.styles.isVisible()) {
|
|
8215
|
+
if (createsRealStackingContext(childNode, container, root)) container.createsRealStackingContext = true;
|
|
8216
|
+
else if (createsStackingContext(container.styles)) container.createsStackingContext = true;
|
|
8217
|
+
if (LIST_OWNERS.indexOf(childNode.tagName) !== -1) container.isListOwner = true;
|
|
8218
|
+
parent.elements.push(container);
|
|
8219
|
+
if (childNode.shadowRoot) parseNodeTree(context, childNode.shadowRoot, container, root);
|
|
8220
|
+
else if (!isTextareaElement(childNode) && !isSVGElement(childNode) && !isSelectElement(childNode)) parseNodeTree(context, childNode, container, root);
|
|
8201
8221
|
}
|
|
8202
8222
|
}
|
|
8203
8223
|
};
|
|
@@ -9070,6 +9090,7 @@
|
|
|
9070
9090
|
//#endregion
|
|
9071
9091
|
//#region src/render/canvas/text-renderer.ts
|
|
9072
9092
|
const iOSBrokenFonts = ["-apple-system", "system-ui"];
|
|
9093
|
+
const TEXT_OVERFLOW_EPSILON = 1;
|
|
9073
9094
|
/**
|
|
9074
9095
|
* Detect CJK (Chinese, Japanese, Korean) characters in a string.
|
|
9075
9096
|
* CJK characters use the ideographic baseline in browsers, which differs
|
|
@@ -9372,7 +9393,7 @@
|
|
|
9372
9393
|
const firstTop = text.textBounds[0].bounds.top;
|
|
9373
9394
|
if (!text.textBounds.every((tb) => Math.abs(tb.bounds.top - firstTop) < lineHeight * .5)) return false;
|
|
9374
9395
|
let fullText = text.textBounds.map((tb) => tb.text).join("").replace(/\s+/g, " ").trim();
|
|
9375
|
-
if (this.ctx.measureText(fullText).width <= containerBounds.width) return false;
|
|
9396
|
+
if (this.ctx.measureText(fullText).width <= containerBounds.width + TEXT_OVERFLOW_EPSILON) return false;
|
|
9376
9397
|
const bounds = new TextBounds(this.truncateTextWithEllipsis(fullText, containerBounds.width, styles.letterSpacing), text.textBounds[0].bounds);
|
|
9377
9398
|
for (const layer of paintOrder) if (layer === 0) this.renderTextFillWithShadows(bounds, styles, baseline);
|
|
9378
9399
|
else if (layer === 1) this.renderTextStrokeWithStyle(bounds, styles, baseline);
|
|
@@ -10610,10 +10631,38 @@
|
|
|
10610
10631
|
}
|
|
10611
10632
|
let side = 0;
|
|
10612
10633
|
for (const border of borders) {
|
|
10613
|
-
if (border.style !== 0 && !isTransparent(border.color) && border.width > 0)
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10634
|
+
if (border.style !== 0 && !isTransparent(border.color) && border.width > 0) {
|
|
10635
|
+
const renderBorderSide = async () => {
|
|
10636
|
+
if (border.style === 2) await this.borderRenderer.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 2);
|
|
10637
|
+
else if (border.style === 3) await this.borderRenderer.renderDashedDottedBorder(border.color, border.width, side, paint.curves, 3);
|
|
10638
|
+
else if (border.style === 4) await this.borderRenderer.renderDoubleBorder(border.color, border.width, side, paint.curves);
|
|
10639
|
+
else await this.borderRenderer.renderSolidBorder(border.color, side, paint.curves);
|
|
10640
|
+
};
|
|
10641
|
+
const legend = paint.container.legendBounds;
|
|
10642
|
+
if (side === 0 && legend) {
|
|
10643
|
+
const bounds = paint.container.bounds;
|
|
10644
|
+
const legendLeft = legend.left - bounds.left;
|
|
10645
|
+
const legendRight = legend.left + legend.width - bounds.left;
|
|
10646
|
+
if (legendLeft > 0) {
|
|
10647
|
+
this.ctx.save();
|
|
10648
|
+
this.ctx.beginPath();
|
|
10649
|
+
this.ctx.rect(bounds.left, bounds.top, legendLeft, bounds.height);
|
|
10650
|
+
this.ctx.clip();
|
|
10651
|
+
await renderBorderSide();
|
|
10652
|
+
this.ctx.restore();
|
|
10653
|
+
}
|
|
10654
|
+
const rightStart = bounds.left + legendRight;
|
|
10655
|
+
const rightWidth = bounds.width - legendRight;
|
|
10656
|
+
if (rightWidth > 0) {
|
|
10657
|
+
this.ctx.save();
|
|
10658
|
+
this.ctx.beginPath();
|
|
10659
|
+
this.ctx.rect(rightStart, bounds.top, rightWidth, bounds.height);
|
|
10660
|
+
this.ctx.clip();
|
|
10661
|
+
await renderBorderSide();
|
|
10662
|
+
this.ctx.restore();
|
|
10663
|
+
}
|
|
10664
|
+
} else await renderBorderSide();
|
|
10665
|
+
}
|
|
10617
10666
|
side++;
|
|
10618
10667
|
}
|
|
10619
10668
|
}
|