@zumer/snapdom 1.9.6-dev.0 → 1.9.6-dev.2
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 +5 -2
- package/dist/snapdom.js +386 -219
- package/dist/snapdom.min.js +8 -8
- package/dist/snapdom.min.mjs +13 -13
- package/dist/snapdom.mjs +137 -100
- package/package.json +4 -1
- package/types/snapdom.d.ts +1 -1
package/dist/snapdom.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.9.6-dev.
|
|
4
|
+
* v.1.9.6-dev.2
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -440,120 +440,154 @@ function isSlotElement(node) {
|
|
|
440
440
|
return node.nodeType === Node.ELEMENT_NODE && node.tagName === "SLOT";
|
|
441
441
|
}
|
|
442
442
|
function deepClone(node, compress, options = {}, originalRoot) {
|
|
443
|
-
if (node
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
443
|
+
if (!node) {
|
|
444
|
+
throw new Error("Invalid node: node is null or undefined");
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
448
|
+
return node.cloneNode(true);
|
|
449
|
+
}
|
|
450
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
451
|
+
return node.cloneNode(true);
|
|
452
|
+
}
|
|
453
|
+
if (node.getAttribute("data-capture") === "exclude") {
|
|
454
|
+
const spacer = document.createElement("div");
|
|
455
|
+
const rect = node.getBoundingClientRect();
|
|
456
|
+
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
457
|
+
return spacer;
|
|
458
|
+
}
|
|
459
|
+
if (options.exclude && Array.isArray(options.exclude)) {
|
|
460
|
+
for (const selector of options.exclude) {
|
|
461
|
+
try {
|
|
462
|
+
if (node.matches?.(selector)) {
|
|
463
|
+
const spacer = document.createElement("div");
|
|
464
|
+
const rect = node.getBoundingClientRect();
|
|
465
|
+
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
466
|
+
return spacer;
|
|
467
|
+
}
|
|
468
|
+
} catch (err) {
|
|
469
|
+
console.warn(`Invalid selector in exclude option: ${selector}`, err);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (typeof options.filter === "function") {
|
|
455
474
|
try {
|
|
456
|
-
if (
|
|
475
|
+
if (!options.filter(node, originalRoot || node)) {
|
|
457
476
|
const spacer = document.createElement("div");
|
|
458
477
|
const rect = node.getBoundingClientRect();
|
|
459
478
|
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
460
479
|
return spacer;
|
|
461
480
|
}
|
|
462
481
|
} catch (err) {
|
|
463
|
-
console.warn(
|
|
482
|
+
console.warn("Error in filter function:", err);
|
|
464
483
|
}
|
|
465
484
|
}
|
|
466
|
-
|
|
467
|
-
|
|
485
|
+
if (node.tagName === "IFRAME") {
|
|
486
|
+
const fallback = document.createElement("div");
|
|
487
|
+
fallback.textContent = "";
|
|
488
|
+
fallback.style.cssText = `width: ${node.offsetWidth}px; height: ${node.offsetHeight}px; background-image: repeating-linear-gradient(45deg, #ddd, #ddd 5px, #f9f9f9 5px, #f9f9f9 10px);display: flex;align-items: center;justify-content: center;font-size: 12px;color: #555; border: 1px solid #aaa;`;
|
|
489
|
+
return fallback;
|
|
490
|
+
}
|
|
491
|
+
if (node.getAttribute("data-capture") === "placeholder") {
|
|
492
|
+
const clone2 = node.cloneNode(false);
|
|
493
|
+
cache.preNodeMap.set(clone2, node);
|
|
494
|
+
inlineAllStyles(node, clone2, compress);
|
|
495
|
+
const placeholder = document.createElement("div");
|
|
496
|
+
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
|
|
497
|
+
placeholder.style.cssText = `color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;`;
|
|
498
|
+
clone2.appendChild(placeholder);
|
|
499
|
+
return clone2;
|
|
500
|
+
}
|
|
501
|
+
if (node.tagName === "CANVAS") {
|
|
502
|
+
const dataURL = node.toDataURL();
|
|
503
|
+
const img = document.createElement("img");
|
|
504
|
+
img.src = dataURL;
|
|
505
|
+
img.width = node.width;
|
|
506
|
+
img.height = node.height;
|
|
507
|
+
cache.preNodeMap.set(img, node);
|
|
508
|
+
inlineAllStyles(node, img, compress);
|
|
509
|
+
return img;
|
|
510
|
+
}
|
|
511
|
+
let clone;
|
|
468
512
|
try {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
spacer.style.cssText = `display: inline-block; width: ${rect.width}px; height: ${rect.height}px; visibility: hidden;`;
|
|
473
|
-
return spacer;
|
|
513
|
+
clone = node.cloneNode(false);
|
|
514
|
+
if (!clone) {
|
|
515
|
+
throw new Error("Failed to clone node: cloneNode returned null");
|
|
474
516
|
}
|
|
517
|
+
cache.preNodeMap.set(clone, node);
|
|
475
518
|
} catch (err) {
|
|
476
|
-
console.
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
if (node.tagName === "IFRAME") {
|
|
480
|
-
const fallback = document.createElement("div");
|
|
481
|
-
fallback.textContent = "";
|
|
482
|
-
fallback.style.cssText = `width: ${node.offsetWidth}px; height: ${node.offsetHeight}px; background-image: repeating-linear-gradient(45deg, #ddd, #ddd 5px, #f9f9f9 5px, #f9f9f9 10px);display: flex;align-items: center;justify-content: center;font-size: 12px;color: #555; border: 1px solid #aaa;`;
|
|
483
|
-
return fallback;
|
|
484
|
-
}
|
|
485
|
-
if (node.getAttribute("data-capture") === "placeholder") {
|
|
486
|
-
const clone2 = node.cloneNode(false);
|
|
487
|
-
cache.preNodeMap.set(clone2, node);
|
|
488
|
-
inlineAllStyles(node, clone2, compress);
|
|
489
|
-
const placeholder = document.createElement("div");
|
|
490
|
-
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
|
|
491
|
-
placeholder.style.cssText = `color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;`;
|
|
492
|
-
clone2.appendChild(placeholder);
|
|
493
|
-
return clone2;
|
|
494
|
-
}
|
|
495
|
-
if (node.tagName === "CANVAS") {
|
|
496
|
-
const dataURL = node.toDataURL();
|
|
497
|
-
const img = document.createElement("img");
|
|
498
|
-
img.src = dataURL;
|
|
499
|
-
img.width = node.width;
|
|
500
|
-
img.height = node.height;
|
|
501
|
-
img.style.display = "inline-block";
|
|
502
|
-
img.style.width = node.style.width || `${node.width}px`;
|
|
503
|
-
img.style.height = node.style.height || `${node.height}px`;
|
|
504
|
-
return img;
|
|
505
|
-
}
|
|
506
|
-
const clone = node.cloneNode(false);
|
|
507
|
-
cache.preNodeMap.set(clone, node);
|
|
508
|
-
if (node instanceof HTMLInputElement) {
|
|
509
|
-
clone.value = node.value;
|
|
510
|
-
clone.setAttribute("value", node.value);
|
|
511
|
-
if (node.checked !== void 0) {
|
|
512
|
-
clone.checked = node.checked;
|
|
513
|
-
if (node.checked) clone.setAttribute("checked", "");
|
|
519
|
+
console.error("[Snapdom] Failed to clone node:", node, err);
|
|
520
|
+
throw err;
|
|
514
521
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
clone.value = node.value;
|
|
522
|
-
Array.from(clone.options).forEach((opt) => {
|
|
523
|
-
if (opt.value === node.value) {
|
|
524
|
-
opt.setAttribute("selected", "");
|
|
525
|
-
} else {
|
|
526
|
-
opt.removeAttribute("selected");
|
|
522
|
+
if (node instanceof HTMLInputElement) {
|
|
523
|
+
clone.value = node.value;
|
|
524
|
+
clone.setAttribute("value", node.value);
|
|
525
|
+
if (node.checked !== void 0) {
|
|
526
|
+
clone.checked = node.checked;
|
|
527
|
+
if (node.checked) clone.setAttribute("checked", "");
|
|
527
528
|
}
|
|
528
|
-
})
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const baseChildren = node.shadowRoot ? node.shadowRoot.childNodes : node.childNodes;
|
|
543
|
-
for (const child of baseChildren) {
|
|
544
|
-
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
545
|
-
if (clonedChild) clone.appendChild(clonedChild);
|
|
529
|
+
} else if (node instanceof HTMLTextAreaElement) {
|
|
530
|
+
const rect = node.getBoundingClientRect();
|
|
531
|
+
clone.textContent = node.value;
|
|
532
|
+
clone.style.width = `${rect.width}px`;
|
|
533
|
+
clone.style.height = `${rect.height}px`;
|
|
534
|
+
} else if (node instanceof HTMLSelectElement) {
|
|
535
|
+
clone.value = node.value;
|
|
536
|
+
Array.from(clone.options).forEach((opt) => {
|
|
537
|
+
if (opt.value === node.value) {
|
|
538
|
+
opt.setAttribute("selected", "");
|
|
539
|
+
} else {
|
|
540
|
+
opt.removeAttribute("selected");
|
|
541
|
+
}
|
|
542
|
+
});
|
|
546
543
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const
|
|
551
|
-
|
|
544
|
+
inlineAllStyles(node, clone, compress);
|
|
545
|
+
try {
|
|
546
|
+
if (isSlotElement(node)) {
|
|
547
|
+
const assigned = node.assignedNodes?.({ flatten: true }) || [];
|
|
548
|
+
const nodesToClone = assigned.length > 0 ? assigned : Array.from(node.childNodes);
|
|
549
|
+
const fragment = document.createDocumentFragment();
|
|
550
|
+
for (const child of nodesToClone) {
|
|
551
|
+
try {
|
|
552
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
553
|
+
if (clonedChild) fragment.appendChild(clonedChild);
|
|
554
|
+
} catch (err) {
|
|
555
|
+
console.warn("[Snapdom] Failed to clone slot content:", child, err);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return fragment;
|
|
559
|
+
} else {
|
|
560
|
+
const baseChildren = node.shadowRoot ? node.shadowRoot.childNodes : node.childNodes;
|
|
561
|
+
for (const child of baseChildren) {
|
|
562
|
+
try {
|
|
563
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
564
|
+
if (clonedChild) clone.appendChild(clonedChild);
|
|
565
|
+
} catch (err) {
|
|
566
|
+
console.warn("[Snapdom] Failed to clone child node:", child, err);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (node.shadowRoot && node.childNodes.length > 0 && !node.shadowRoot.querySelector("slot")) {
|
|
570
|
+
const lightDomContent = document.createDocumentFragment();
|
|
571
|
+
for (const child of node.childNodes) {
|
|
572
|
+
try {
|
|
573
|
+
const clonedChild = deepClone(child, compress, options, originalRoot || node);
|
|
574
|
+
if (clonedChild) lightDomContent.appendChild(clonedChild);
|
|
575
|
+
} catch (err) {
|
|
576
|
+
console.warn("[Snapdom] Failed to clone light DOM child:", child, err);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
clone.appendChild(lightDomContent);
|
|
580
|
+
}
|
|
552
581
|
}
|
|
553
|
-
|
|
582
|
+
} catch (err) {
|
|
583
|
+
console.error("[Snapdom] Error cloning children:", err);
|
|
584
|
+
throw err;
|
|
554
585
|
}
|
|
586
|
+
return clone;
|
|
587
|
+
} catch (error) {
|
|
588
|
+
console.error("[Snapdom] Error in deepClone:", error);
|
|
589
|
+
throw error;
|
|
555
590
|
}
|
|
556
|
-
return clone;
|
|
557
591
|
}
|
|
558
592
|
|
|
559
593
|
// src/modules/iconFonts.js
|
|
@@ -940,7 +974,8 @@ function inlineExternalDef(root) {
|
|
|
940
974
|
|
|
941
975
|
// src/core/prepare.js
|
|
942
976
|
async function prepareClone(element, compress = false, embedFonts = false, options = {}) {
|
|
943
|
-
let clone
|
|
977
|
+
let clone;
|
|
978
|
+
let classCSS = "";
|
|
944
979
|
try {
|
|
945
980
|
clone = deepClone(element, compress, options, element);
|
|
946
981
|
} catch (e) {
|
|
@@ -1247,8 +1282,10 @@ async function createBackground(url, { dpr = 1, scale = 1 }, backgroundColor) {
|
|
|
1247
1282
|
ctx.drawImage(baseCanvas, 0, 0);
|
|
1248
1283
|
return temp;
|
|
1249
1284
|
}
|
|
1250
|
-
async function toRasterImg(url, { dpr = 1, scale = 1, backgroundColor
|
|
1251
|
-
const
|
|
1285
|
+
async function toRasterImg(url, { dpr = 1, scale = 1, backgroundColor, quality }, format = "png") {
|
|
1286
|
+
const defaultBg = ["jpg", "jpeg", "webp"].includes(format) ? "#fff" : void 0;
|
|
1287
|
+
const finalBg = backgroundColor ?? defaultBg;
|
|
1288
|
+
const canvas = await createBackground(url, { dpr, scale }, finalBg);
|
|
1252
1289
|
const img = new Image();
|
|
1253
1290
|
img.src = canvas.toDataURL(`image/${format}`, quality);
|
|
1254
1291
|
await img.decode();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zumer/snapdom",
|
|
3
|
-
"version": "1.9.6-dev.
|
|
3
|
+
"version": "1.9.6-dev.2",
|
|
4
4
|
"description": "snapDOM captures HTML elements to images with exceptional speed and accuracy.",
|
|
5
5
|
"main": "dist/snapdom.js",
|
|
6
6
|
"module": "dist/snapdom.mjs",
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
"bump": "npx @zumerbox/bump && npx @zumerbox/changelog",
|
|
16
16
|
"prebuild": "git add CHANGELOG.md && git commit -m \"Bumped version\" && git push --follow-tags"
|
|
17
17
|
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">= 20"
|
|
20
|
+
},
|
|
18
21
|
"repository": {
|
|
19
22
|
"type": "git",
|
|
20
23
|
"url": "git+https://github.com/zumerlab/snapdom.git"
|
package/types/snapdom.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ declare module "@zumer/snapdom" {
|
|
|
23
23
|
toRaw(): string;
|
|
24
24
|
toImg(): Promise<HTMLImageElement>;
|
|
25
25
|
toCanvas(): Promise<HTMLCanvasElement>;
|
|
26
|
-
toBlob(): Promise<Blob>;
|
|
26
|
+
toBlob(options?: SnapOptions): Promise<Blob>;
|
|
27
27
|
toPng(options?: SnapOptions): Promise<HTMLImageElement>;
|
|
28
28
|
toJpg(options?: SnapOptions): Promise<HTMLImageElement>;
|
|
29
29
|
toWebp(options?: SnapOptions): Promise<HTMLImageElement>;
|