@zumer/snapdom 1.2.1 → 1.2.5
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 +2 -2
- package/dist/snapdom.js +63 -29
- package/dist/snapdom.min.js +3 -3
- package/dist/snapdom.min.mjs +3 -3
- package/dist/snapdom.mjs +63 -29
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ yarn add @zumer/snapdom
|
|
|
39
39
|
### CDN
|
|
40
40
|
|
|
41
41
|
```html
|
|
42
|
-
<script src="https://
|
|
42
|
+
<script src="https://cdn.jsdelivr.net/npm/@zumer/snapdom/dist/snapdom.min.js"></script>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### Script tag (local)
|
|
@@ -58,7 +58,7 @@ import { snapdom } from './snapdom.mjs';
|
|
|
58
58
|
|
|
59
59
|
```html
|
|
60
60
|
<script type="module">
|
|
61
|
-
import { snapdom } from 'https://
|
|
61
|
+
import { snapdom } from 'https://cdn.jsdelivr.net/npm/@zumer/snapdom/dist/snapdom.mjs';
|
|
62
62
|
</script>
|
|
63
63
|
```
|
|
64
64
|
|
package/dist/snapdom.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.2.
|
|
4
|
+
* v.1.2.5
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -186,9 +186,15 @@
|
|
|
186
186
|
}
|
|
187
187
|
return clean;
|
|
188
188
|
}
|
|
189
|
-
function
|
|
190
|
-
const
|
|
191
|
-
|
|
189
|
+
function extractURL(value) {
|
|
190
|
+
const urlStart = value.indexOf("url(");
|
|
191
|
+
if (urlStart === -1) return null;
|
|
192
|
+
let url = value.slice(urlStart + 4).trim();
|
|
193
|
+
if (url.endsWith(")")) url = url.slice(0, -1).trim();
|
|
194
|
+
if (url.startsWith('"') && url.endsWith('"') || url.startsWith("'") && url.endsWith("'")) {
|
|
195
|
+
url = url.slice(1, -1);
|
|
196
|
+
}
|
|
197
|
+
return url;
|
|
192
198
|
}
|
|
193
199
|
function isIconFont(familyOrUrl) {
|
|
194
200
|
const iconFontPatterns = [
|
|
@@ -362,10 +368,17 @@
|
|
|
362
368
|
const urlRegex = /url\(([^)]+)\)/g;
|
|
363
369
|
const inlinedCSS = await Promise.all(
|
|
364
370
|
Array.from(cssText.matchAll(urlRegex)).map(async (match) => {
|
|
365
|
-
let
|
|
371
|
+
let rawUrl = extractURL(match[0]);
|
|
372
|
+
if (!rawUrl) return null;
|
|
373
|
+
let url = rawUrl;
|
|
366
374
|
if (!url.startsWith("http")) {
|
|
367
375
|
url = new URL(url, link.href).href;
|
|
368
376
|
}
|
|
377
|
+
try {
|
|
378
|
+
url = encodeURI(url);
|
|
379
|
+
} catch (e) {
|
|
380
|
+
console.warn("[snapdom] Failed to encode font URL:", url);
|
|
381
|
+
}
|
|
369
382
|
if (ignoreIconFonts && isIconFont(url)) {
|
|
370
383
|
return null;
|
|
371
384
|
}
|
|
@@ -429,29 +442,43 @@
|
|
|
429
442
|
const snapshot = snapshotComputedStyle(style);
|
|
430
443
|
const key = getStyleKey(snapshot, "span", compress);
|
|
431
444
|
styleMap.set(pseudoEl, key);
|
|
432
|
-
const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
|
|
445
|
+
const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
|
|
446
|
+
fontFamily
|
|
447
|
+
);
|
|
433
448
|
let cleanContent = parseContent(content);
|
|
434
449
|
if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
|
|
435
450
|
const imgEl = document.createElement("img");
|
|
436
|
-
imgEl.src = await iconToImage(
|
|
451
|
+
imgEl.src = await iconToImage(
|
|
452
|
+
cleanContent,
|
|
453
|
+
fontFamily,
|
|
454
|
+
fontWeight,
|
|
455
|
+
fontSize,
|
|
456
|
+
color
|
|
457
|
+
);
|
|
437
458
|
imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
|
|
438
459
|
pseudoEl.appendChild(imgEl);
|
|
439
460
|
} else if (cleanContent.startsWith("url(")) {
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
461
|
+
const rawUrl = extractURL(cleanContent);
|
|
462
|
+
if (rawUrl) {
|
|
442
463
|
try {
|
|
443
464
|
const imgEl = document.createElement("img");
|
|
444
|
-
const dataUrl = await fetchImage(
|
|
465
|
+
const dataUrl = await fetchImage(encodeURI(rawUrl));
|
|
445
466
|
imgEl.src = dataUrl;
|
|
446
467
|
imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
|
|
447
468
|
pseudoEl.appendChild(imgEl);
|
|
448
469
|
} catch (e) {
|
|
449
|
-
console.error(
|
|
470
|
+
console.error(
|
|
471
|
+
`[snapdom] Error in pseudo ${pseudo} for`,
|
|
472
|
+
source,
|
|
473
|
+
e
|
|
474
|
+
);
|
|
450
475
|
}
|
|
451
476
|
}
|
|
452
|
-
} else if (cleanContent && cleanContent !== "none") {
|
|
477
|
+
} else if (!isIconFont2 && cleanContent && cleanContent !== "none") {
|
|
453
478
|
pseudoEl.textContent = cleanContent;
|
|
454
479
|
}
|
|
480
|
+
const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent && pseudoEl.textContent.trim() !== "";
|
|
481
|
+
if (!hasContent2) continue;
|
|
455
482
|
if (pseudo === "::before") {
|
|
456
483
|
clone.insertBefore(pseudoEl, clone.firstChild);
|
|
457
484
|
} else {
|
|
@@ -467,7 +494,14 @@
|
|
|
467
494
|
(child) => !child.dataset.snapdomPseudo
|
|
468
495
|
);
|
|
469
496
|
for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
|
|
470
|
-
await inlinePseudoElements(
|
|
497
|
+
await inlinePseudoElements(
|
|
498
|
+
sChildren[i],
|
|
499
|
+
cChildren[i],
|
|
500
|
+
styleMap,
|
|
501
|
+
styleCache,
|
|
502
|
+
compress,
|
|
503
|
+
embedFonts
|
|
504
|
+
);
|
|
471
505
|
}
|
|
472
506
|
}
|
|
473
507
|
|
|
@@ -559,22 +593,20 @@
|
|
|
559
593
|
const style = styleCache.get(srcNode) || getStyle(srcNode);
|
|
560
594
|
if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
|
|
561
595
|
const bg = style.getPropertyValue("background-image");
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
bgCache.set(bgUrl, dataUrl);
|
|
573
|
-
}
|
|
574
|
-
cloneNode.style.backgroundImage = `url(${dataUrl})`;
|
|
575
|
-
} catch {
|
|
576
|
-
cloneNode.style.backgroundImage = "none";
|
|
596
|
+
const rawUrl = extractURL(bg);
|
|
597
|
+
if (rawUrl) {
|
|
598
|
+
try {
|
|
599
|
+
let bgUrl = encodeURI(rawUrl);
|
|
600
|
+
let dataUrl;
|
|
601
|
+
if (bgCache.has(bgUrl)) {
|
|
602
|
+
dataUrl = bgCache.get(bgUrl);
|
|
603
|
+
} else {
|
|
604
|
+
dataUrl = await fetchImage(bgUrl);
|
|
605
|
+
bgCache.set(bgUrl, dataUrl);
|
|
577
606
|
}
|
|
607
|
+
cloneNode.style.backgroundImage = `url(${dataUrl})`;
|
|
608
|
+
} catch {
|
|
609
|
+
cloneNode.style.backgroundImage = "none";
|
|
578
610
|
}
|
|
579
611
|
}
|
|
580
612
|
const sChildren = Array.from(srcNode.children);
|
|
@@ -688,6 +720,8 @@
|
|
|
688
720
|
const ctx = canvas.getContext("2d");
|
|
689
721
|
ctx.scale(scale * dpr, scale * dpr);
|
|
690
722
|
ctx.drawImage(img, 0, 0);
|
|
723
|
+
canvas.style.width = `${canvas.width / dpr}px`;
|
|
724
|
+
canvas.style.height = `${canvas.height / dpr}px`;
|
|
691
725
|
return canvas;
|
|
692
726
|
}
|
|
693
727
|
async function toBlob(url) {
|
|
@@ -811,7 +845,7 @@
|
|
|
811
845
|
}
|
|
812
846
|
for (const el of allEls) {
|
|
813
847
|
const bg = getComputedStyle(el).backgroundImage;
|
|
814
|
-
const url =
|
|
848
|
+
const url = extractURL(bg);
|
|
815
849
|
if (url && !bgCache.has(url)) {
|
|
816
850
|
promises.push(
|
|
817
851
|
fetchImage(url).then((dataURL) => bgCache.set(url, dataURL)).catch(() => {
|
package/dist/snapdom.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
(()=>{var
|
|
2
|
-
`;return o}function
|
|
3
|
-
`}catch{console.warn("\u274C Failed to fetch CSS:",a.href)}if(n&&
|
|
1
|
+
(()=>{var S=new Map,E=new Map,R=new Map,T=new Map,k=new Map,U=new WeakMap;var ct=["div","span","p","a","img","ul","li","button","input","select","textarea","label","section","article","header","footer","nav","main","aside","h1","h2","h3","h4","h5","h6","svg","path","circle","rect","line","g","table","thead","tbody","tr","td","th"];function _(){for(let t of ct)H(t)}function H(t){if(T.has(t))return T.get(t);if(new Set(["script","style","meta","link","noscript","template"]).has(t)){let i={};return T.set(t,i),i}let o=document.getElementById("snapdom-sandbox");o||(o=document.createElement("div"),o.id="snapdom-sandbox",o.style.position="absolute",o.style.left="-9999px",o.style.top="-9999px",o.style.width="0",o.style.height="0",o.style.overflow="hidden",document.body.appendChild(o));let n=document.createElement(t);n.style.all="initial",o.appendChild(n);let a=getComputedStyle(n),r={};for(let i of a)r[i]=a.getPropertyValue(i);return o.removeChild(n),T.set(t,r),r}function B(t,e,o=!1){let n=[],a=H(e);for(let[r,i]of Object.entries(t))if(!o)i&&n.push(`${r}:${i}`);else{let c=a[r];i&&i!==c&&n.push(`${r}:${i}`)}return n.sort().join(";")}function Y(t){let e=new Set;return t.nodeType!==Node.ELEMENT_NODE&&t.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(t.tagName&&e.add(t.tagName.toLowerCase()),typeof t.querySelectorAll=="function"&&t.querySelectorAll("*").forEach(o=>e.add(o.tagName.toLowerCase())),Array.from(e))}function K(t){let e=new Map;for(let n of t){let a=T.get(n);if(!a)continue;let r=Object.entries(a).map(([i,c])=>`${i}:${c};`).sort().join("");e.has(r)||e.set(r,[]),e.get(r).push(n)}let o="";for(let[n,a]of e.entries())o+=`${a.join(",")} { ${n} }
|
|
2
|
+
`;return o}function J(t){let e=new Set(t.values()),o=new Map,n=1;for(let a of e)o.set(a,`c${n++}`);return o}function N(t,{fast:e=!1}={}){if(e)return t();"requestIdleCallback"in window?requestIdleCallback(t,{timeout:50}):setTimeout(t,1)}function A(t,e=null){if(!(t instanceof Element))return window.getComputedStyle(t,e);let o=U.get(t);if(o||(o=new Map,U.set(t,o)),!o.has(e)){let n=window.getComputedStyle(t,e);o.set(e,n)}return o.get(e)}function X(t){let e=t.replace(/^['"]|['"]$/g,"");if(e.startsWith("\\"))try{return String.fromCharCode(parseInt(e.replace("\\",""),16))}catch{return e}return e}function v(t){let e=t.indexOf("url(");if(e===-1)return null;let o=t.slice(e+4).trim();return o.endsWith(")")&&(o=o.slice(0,-1).trim()),(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),o}function M(t){return[/font\s*awesome/i,/material\s*icons/i,/ionicons/i,/glyphicons/i,/feather/i,/bootstrap\s*icons/i,/remix\s*icons/i,/heroicons/i].some(o=>o.test(t))}function x(t,e=3e3){return S.has(t)?Promise.resolve(S.get(t)):new Promise((o,n)=>{let a=setTimeout(()=>{n(new Error("Image load timed out"))},e),r=new Image;r.crossOrigin="anonymous",r.onload=async()=>{clearTimeout(a);try{await r.decode();let i=document.createElement("canvas");i.width=r.width,i.height=r.height,i.getContext("2d").drawImage(r,0,0);try{let s=i.toDataURL("image/png");S.set(t,s),o(s)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(i){n(i)}},r.onerror=i=>{clearTimeout(a),n(new Error("Failed to load image: "+(i.message||"Unknown error")))},r.src=t})}function F(t){let e={};for(let o of t)e[o]=t.getPropertyValue(o);return e}function D(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function V(t,e,o,n,a){if(t.tagName==="STYLE")return;n.has(t)||n.set(t,A(t));let r=n.get(t),i=F(r),c=t.tagName?.toLowerCase()||"div",s=B(i,c,a);o.set(e,s)}function O(t,e,o,n,a){if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=t.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(t.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${t.offsetWidth}px; height: ${t.offsetHeight}px; background: 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;`,c}if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="placeholder"){let c=t.cloneNode(!1);n.set(c,t),V(t,c,e,o,a);let s=document.createElement("div");return s.textContent=t.getAttribute("data-placeholder-text")||"",s.style.cssText="color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;",c.appendChild(s),c}if(t.tagName==="CANVAS"){let c=t.toDataURL(),s=document.createElement("img");return s.src=c,s.width=t.width,s.height=t.height,s.style.display="inline-block",s.style.width=`${t.width}px`,s.style.height=`${t.height}px`,s}if(t.nodeType===Node.TEXT_NODE){if(t.parentElement?.shadowRoot){let c=t.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return t.cloneNode(!0)}if(t.nodeType!==Node.ELEMENT_NODE)return t.cloneNode(!0);let r=t.cloneNode(!1);n.set(r,t),V(t,r,e,o,a);let i=document.createDocumentFragment();if(t.childNodes.forEach(c=>{let s=O(c,e,o,n,a);s&&i.appendChild(s)}),r.appendChild(i),t.shadowRoot){let c=Array.from(t.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>O(l,e,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),r.appendChild(s)}return r}async function G(t,e,o,n=32,a="#000"){e=e.replace(/^['"]+|['"]+$/g,"");let r=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${e}"`:`${n}px "${e}"`;let s=c.measureText(t),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,f=l+d,m=s.width,h=document.createElement("canvas");h.width=Math.ceil(m*r),h.height=Math.ceil(f*r);let p=h.getContext("2d");return p.scale(r,r),p.font=c.font,p.textAlign="left",p.textBaseline="alphabetic",p.fillStyle=a,p.fillText(t,0,l),h.toDataURL()}async function W({ignoreIconFonts:t=!0,preCached:e=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(a=>a.href),n="";for(let a of o)try{let i=await(await fetch(a.href)).text();if(t&&(M(a.href)||M(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let f=v(d[0]);if(!f)return null;let m=f;m.startsWith("http")||(m=new URL(m,a.href).href);try{m=encodeURI(m)}catch{console.warn("[snapdom] Failed to encode font URL:",m)}if(t&&M(m))return null;if(R.has(m))return{original:d[0],inlined:`url(${R.get(m)})`};try{let p=await(await fetch(m)).blob(),w=await new Promise(C=>{let b=new FileReader;b.onload=()=>C(b.result),b.readAsDataURL(p)});return R.set(m,w),{original:d[0],inlined:`url(${w})`}}catch{return console.warn("\u274C Failed to fetch font:",m),null}})),l=i;for(let d of s)d&&(l=l.replace(d.original,d.inlined));n+=l+`
|
|
3
|
+
`}catch{console.warn("\u274C Failed to fetch CSS:",a.href)}if(n&&e){let a=document.createElement("style");a.setAttribute("data-snapdom","embedFonts"),a.textContent=n,document.head.appendChild(a)}return n}async function q(t,e,o,n,a,r=!1){if(!(t instanceof Element)||!(e instanceof Element))return;for(let s of["::before","::after"])try{let l=A(t,s);if(!l)continue;let d=l.getPropertyValue("content"),f=l.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",h=f&&f.startsWith("url(");if(m||h){let p=l.getPropertyValue("font-family"),w=parseInt(l.getPropertyValue("font-size"))||32,C=parseInt(l.getPropertyValue("font-weight"))||!1,b=l.getPropertyValue("color")||"#000",u=document.createElement("span");u.dataset.snapdomPseudo=s;let I=F(l),P=B(I,"span",a);o.set(u,P);let j=p&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(p),y=X(d);if(!r&&j&&y.length===1){let $=document.createElement("img");$.src=await G(y,p,C,w,b),$.style="display:block;width:100%;height:100%;object-fit:contain;",u.appendChild($)}else if(y.startsWith("url(")){let $=v(y);if($)try{let L=document.createElement("img"),it=await x(encodeURI($));L.src=it,L.style="display:block;width:100%;height:100%;object-fit:contain;",u.appendChild(L)}catch(L){console.error(`[snapdom] Error in pseudo ${s} for`,t,L)}}else!j&&y&&y!=="none"&&(u.textContent=y);if(!(u.childNodes.length>0||u.textContent&&u.textContent.trim()!==""))continue;s==="::before"?e.insertBefore(u,e.firstChild):e.appendChild(u)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,t,l)}let i=Array.from(t.children),c=Array.from(e.children).filter(s=>!s.dataset.snapdomPseudo);for(let s=0;s<Math.min(i.length,c.length);s++)await q(i[s],c[s],o,n,a,r)}async function Q(t,e=!1,o=!1){let n=new Map,a=new WeakMap,r=new Map,i;try{i=O(t,n,a,r,e)}catch(s){throw console.warn("deepClone failed:",s),s}try{await q(t,i,n,a,e,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(e){let s=J(n);c=Array.from(s.entries()).map(([l,d])=>`.${d}{${l}}`).join("");for(let[l,d]of n.entries()){if(l.tagName==="STYLE")continue;let f=s.get(d);f&&l.classList.add(f);let m=l.style?.backgroundImage;l.removeAttribute("style"),m&&m!=="none"&&(l.style.backgroundImage=m)}}else for(let[s,l]of n.entries())s.tagName!=="STYLE"&&s.setAttribute("style",l.replace(/;/g,"; "));for(let[s,l]of r.entries()){let d=l.scrollLeft,f=l.scrollTop;if((d||f)&&s instanceof HTMLElement){s.style.overflow="hidden",s.style.scrollbarWidth="none",s.style.msOverflowStyle="none";let h=document.createElement("div");for(h.style.transform=`translate(${-d}px, ${-f}px)`,h.style.willChange="transform",h.style.display="inline-block",h.style.width="100%";s.firstChild;)h.appendChild(s.firstChild);s.appendChild(h)}}return{clone:i,classCSS:c,styleCache:a}}async function Z(t){let e=Array.from(t.querySelectorAll("img")),o=async n=>{let a=n.src;try{let r=await x(a);n.src=r,n.width||(n.width=n.naturalWidth||100),n.height||(n.height=n.naturalHeight||100)}catch{let r=document.createElement("div");r.style=`width: ${n.width||100}px; height: ${n.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${n.height||100}px; color: #666; font-size: 12px;`,r.innerText="img",n.replaceWith(r)}};for(let n=0;n<e.length;n+=4){let a=e.slice(n,n+4).map(o);await Promise.allSettled(a)}}async function tt(t,e,o){let n=[[t,e]];for(;n.length;){let[a,r]=n.shift(),i=o.get(a)||A(a);o.has(a)||o.set(a,i);let c=i.getPropertyValue("background-image"),s=v(c);if(s)try{let f=encodeURI(s),m;E.has(f)?m=E.get(f):(m=await x(f),E.set(f,m)),r.style.backgroundImage=`url(${m})`}catch{r.style.backgroundImage="none"}let l=Array.from(a.children),d=Array.from(r.children);for(let f=0;f<Math.min(l.length,d.length);f++)n.push([l[f],d[f]])}}async function et(t,e={}){if(!t)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:a=!0,scale:r=1}=e,i,c,s,l="",d="",f,m;if({clone:i,classCSS:c,styleCache:s}=await Q(t,o,n),await new Promise(p=>{N(async()=>{await Z(i),p()},{fast:a})}),await new Promise(p=>{N(async()=>{await tt(t,i,s),p()},{fast:a})}),n&&await new Promise(p=>{N(async()=>{l=await W({ignoreIconFonts:!n}),p()},{fast:a})}),o){let p=Y(i).sort(),w=p.join(",");k.has(w)?d=k.get(w):await new Promise(C=>{N(()=>{d=K(p),k.set(w,d),C()},{fast:a})})}await new Promise(p=>{N(()=>{let w=t.getBoundingClientRect(),C=Math.ceil(w.width),b=Math.ceil(w.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",r!==1&&D()&&(i.style.scale=`${r}`);let u="http://www.w3.org/2000/svg",I=document.createElementNS(u,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,I.appendChild(P),I.appendChild(i);let y=new XMLSerializer().serializeToString(I);m=`<svg xmlns="${u}" width="${C}" height="${b}" viewBox="0 0 ${C} ${b}">`+y+"</svg>",f=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(m)}`,p()},{fast:a})});let h=document.getElementById("snapdom-sandbox");return h&&h.style.position==="absolute"&&h.remove(),f}async function lt(t,{dpr:e=1,scale:o=1}){let n=new Image;return n.src=t,await n.decode(),D?(n.width=n.width*o,n.height=n.height*o):(n.width=n.width/o,n.height=n.height/o),n}async function nt(t,{dpr:e=1,scale:o=1}){let n=new Image;n.src=t,await n.decode();let a=document.createElement("canvas"),r=n.width*o*e,i=n.height*o*e;a.width=Math.ceil(r),a.height=Math.ceil(i);let c=a.getContext("2d");return c.scale(o*e,o*e),c.drawImage(n,0,0),a.style.width=`${a.width/e}px`,a.style.height=`${a.height/e}px`,a}async function ot(t){let e=decodeURIComponent(t.split(",")[1]);return new Blob([e],{type:"image/svg+xml"})}async function at(t,{dpr:e=1,scale:o=1},n){let a=await nt(t,{dpr:e,scale:o});if(!n)return a;let r=document.createElement("canvas");r.width=a.width,r.height=a.height;let i=r.getContext("2d");return i.fillStyle=n,i.fillRect(0,0,r.width,r.height),i.drawImage(a,0,0),r}async function z(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let i=await at(t,{dpr:e,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${i.width/e}px`,c.style.height=`${i.height/e}px`,c}async function dt(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let m=await ot(t),h=URL.createObjectURL(m),p=document.createElement("a");p.href=h,p.download=`${r}.svg`,p.click(),URL.revokeObjectURL(h);return}let i=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,s=await at(t,{dpr:e,scale:o},n??i),l={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[a]||"image/png",d=s.toDataURL(l),f=document.createElement("a");f.href=d,f.download=`${r}.${a}`,f.click()}async function g(t,e={}){if(e={scale:1,...e},!t)throw new Error("Element cannot be null or undefined");return await g.capture(t,e)}g.capture=async(t,e={})=>{let o=await et(t,e),n=window.devicePixelRatio||1,a=e.scale||1;return{url:o,options:e,toRaw:()=>o,toImg:()=>lt(o,{dpr:n,scale:a}),toCanvas:()=>nt(o,{dpr:n,scale:a}),toBlob:()=>ot(o),toPng:r=>z(o,{dpr:n,scale:a,...r},"png"),toJpg:r=>z(o,{dpr:n,scale:a,...r},"jpeg"),toWebp:r=>z(o,{dpr:n,scale:a,...r},"webp"),download:({format:r="png",filename:i="capture",backgroundColor:c}={})=>dt(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:i})}};g.toRaw=async(t,e)=>(await g.capture(t,e)).toRaw();g.toImg=async(t,e)=>(await g.capture(t,e)).toImg();g.toCanvas=async(t,e)=>(await g.capture(t,e)).toCanvas();g.toBlob=async(t,e)=>(await g.capture(t,e)).toBlob();g.toPng=async(t,e)=>(await g.capture(t,e)).toPng(e);g.toJpg=async(t,e)=>(await g.capture(t,e)).toJpg(e);g.toWebp=async(t,e)=>(await g.capture(t,e)).toWebp(e);g.download=async(t,e={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=e;return await(await g.capture(t,r)).download({format:o,filename:n,backgroundColor:a})};async function rt(t=document,e={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=e;if(n){S.clear(),E.clear(),R.clear(),k.clear(),U.clear();return}await document.fonts.ready,_();let r=[],i=[];t?.querySelectorAll&&(r=Array.from(t.querySelectorAll("img[src]")),i=Array.from(t.querySelectorAll("*")));let c=[];for(let s of r){let l=s.src;S.has(l)||c.push(x(l).then(d=>S.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=v(l);d&&!E.has(d)&&c.push(x(d).then(f=>E.set(d,f)).catch(()=>{}))}o&&await W({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}window.snapdom=g;window.preCache=rt;})();
|
package/dist/snapdom.min.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
2
|
-
`;return o}function
|
|
3
|
-
`}catch{console.warn("\u274C Failed to fetch CSS:",a.href)}if(n&&
|
|
1
|
+
var S=new Map,E=new Map,R=new Map,T=new Map,k=new Map,U=new WeakMap;var it=["div","span","p","a","img","ul","li","button","input","select","textarea","label","section","article","header","footer","nav","main","aside","h1","h2","h3","h4","h5","h6","svg","path","circle","rect","line","g","table","thead","tbody","tr","td","th"];function _(){for(let t of it)H(t)}function H(t){if(T.has(t))return T.get(t);if(new Set(["script","style","meta","link","noscript","template"]).has(t)){let i={};return T.set(t,i),i}let o=document.getElementById("snapdom-sandbox");o||(o=document.createElement("div"),o.id="snapdom-sandbox",o.style.position="absolute",o.style.left="-9999px",o.style.top="-9999px",o.style.width="0",o.style.height="0",o.style.overflow="hidden",document.body.appendChild(o));let n=document.createElement(t);n.style.all="initial",o.appendChild(n);let a=getComputedStyle(n),r={};for(let i of a)r[i]=a.getPropertyValue(i);return o.removeChild(n),T.set(t,r),r}function B(t,e,o=!1){let n=[],a=H(e);for(let[r,i]of Object.entries(t))if(!o)i&&n.push(`${r}:${i}`);else{let c=a[r];i&&i!==c&&n.push(`${r}:${i}`)}return n.sort().join(";")}function Y(t){let e=new Set;return t.nodeType!==Node.ELEMENT_NODE&&t.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(t.tagName&&e.add(t.tagName.toLowerCase()),typeof t.querySelectorAll=="function"&&t.querySelectorAll("*").forEach(o=>e.add(o.tagName.toLowerCase())),Array.from(e))}function K(t){let e=new Map;for(let n of t){let a=T.get(n);if(!a)continue;let r=Object.entries(a).map(([i,c])=>`${i}:${c};`).sort().join("");e.has(r)||e.set(r,[]),e.get(r).push(n)}let o="";for(let[n,a]of e.entries())o+=`${a.join(",")} { ${n} }
|
|
2
|
+
`;return o}function J(t){let e=new Set(t.values()),o=new Map,n=1;for(let a of e)o.set(a,`c${n++}`);return o}function N(t,{fast:e=!1}={}){if(e)return t();"requestIdleCallback"in window?requestIdleCallback(t,{timeout:50}):setTimeout(t,1)}function A(t,e=null){if(!(t instanceof Element))return window.getComputedStyle(t,e);let o=U.get(t);if(o||(o=new Map,U.set(t,o)),!o.has(e)){let n=window.getComputedStyle(t,e);o.set(e,n)}return o.get(e)}function X(t){let e=t.replace(/^['"]|['"]$/g,"");if(e.startsWith("\\"))try{return String.fromCharCode(parseInt(e.replace("\\",""),16))}catch{return e}return e}function v(t){let e=t.indexOf("url(");if(e===-1)return null;let o=t.slice(e+4).trim();return o.endsWith(")")&&(o=o.slice(0,-1).trim()),(o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'"))&&(o=o.slice(1,-1)),o}function M(t){return[/font\s*awesome/i,/material\s*icons/i,/ionicons/i,/glyphicons/i,/feather/i,/bootstrap\s*icons/i,/remix\s*icons/i,/heroicons/i].some(o=>o.test(t))}function x(t,e=3e3){return S.has(t)?Promise.resolve(S.get(t)):new Promise((o,n)=>{let a=setTimeout(()=>{n(new Error("Image load timed out"))},e),r=new Image;r.crossOrigin="anonymous",r.onload=async()=>{clearTimeout(a);try{await r.decode();let i=document.createElement("canvas");i.width=r.width,i.height=r.height,i.getContext("2d").drawImage(r,0,0);try{let s=i.toDataURL("image/png");S.set(t,s),o(s)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(i){n(i)}},r.onerror=i=>{clearTimeout(a),n(new Error("Failed to load image: "+(i.message||"Unknown error")))},r.src=t})}function F(t){let e={};for(let o of t)e[o]=t.getPropertyValue(o);return e}function D(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function V(t,e,o,n,a){if(t.tagName==="STYLE")return;n.has(t)||n.set(t,A(t));let r=n.get(t),i=F(r),c=t.tagName?.toLowerCase()||"div",s=B(i,c,a);o.set(e,s)}function O(t,e,o,n,a){if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=t.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(t.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${t.offsetWidth}px; height: ${t.offsetHeight}px; background: 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;`,c}if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="placeholder"){let c=t.cloneNode(!1);n.set(c,t),V(t,c,e,o,a);let s=document.createElement("div");return s.textContent=t.getAttribute("data-placeholder-text")||"",s.style.cssText="color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;",c.appendChild(s),c}if(t.tagName==="CANVAS"){let c=t.toDataURL(),s=document.createElement("img");return s.src=c,s.width=t.width,s.height=t.height,s.style.display="inline-block",s.style.width=`${t.width}px`,s.style.height=`${t.height}px`,s}if(t.nodeType===Node.TEXT_NODE){if(t.parentElement?.shadowRoot){let c=t.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return t.cloneNode(!0)}if(t.nodeType!==Node.ELEMENT_NODE)return t.cloneNode(!0);let r=t.cloneNode(!1);n.set(r,t),V(t,r,e,o,a);let i=document.createDocumentFragment();if(t.childNodes.forEach(c=>{let s=O(c,e,o,n,a);s&&i.appendChild(s)}),r.appendChild(i),t.shadowRoot){let c=Array.from(t.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>O(l,e,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),r.appendChild(s)}return r}async function G(t,e,o,n=32,a="#000"){e=e.replace(/^['"]+|['"]+$/g,"");let r=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${e}"`:`${n}px "${e}"`;let s=c.measureText(t),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,f=l+d,m=s.width,h=document.createElement("canvas");h.width=Math.ceil(m*r),h.height=Math.ceil(f*r);let p=h.getContext("2d");return p.scale(r,r),p.font=c.font,p.textAlign="left",p.textBaseline="alphabetic",p.fillStyle=a,p.fillText(t,0,l),h.toDataURL()}async function W({ignoreIconFonts:t=!0,preCached:e=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(a=>a.href),n="";for(let a of o)try{let i=await(await fetch(a.href)).text();if(t&&(M(a.href)||M(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let f=v(d[0]);if(!f)return null;let m=f;m.startsWith("http")||(m=new URL(m,a.href).href);try{m=encodeURI(m)}catch{console.warn("[snapdom] Failed to encode font URL:",m)}if(t&&M(m))return null;if(R.has(m))return{original:d[0],inlined:`url(${R.get(m)})`};try{let p=await(await fetch(m)).blob(),w=await new Promise(C=>{let b=new FileReader;b.onload=()=>C(b.result),b.readAsDataURL(p)});return R.set(m,w),{original:d[0],inlined:`url(${w})`}}catch{return console.warn("\u274C Failed to fetch font:",m),null}})),l=i;for(let d of s)d&&(l=l.replace(d.original,d.inlined));n+=l+`
|
|
3
|
+
`}catch{console.warn("\u274C Failed to fetch CSS:",a.href)}if(n&&e){let a=document.createElement("style");a.setAttribute("data-snapdom","embedFonts"),a.textContent=n,document.head.appendChild(a)}return n}async function q(t,e,o,n,a,r=!1){if(!(t instanceof Element)||!(e instanceof Element))return;for(let s of["::before","::after"])try{let l=A(t,s);if(!l)continue;let d=l.getPropertyValue("content"),f=l.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",h=f&&f.startsWith("url(");if(m||h){let p=l.getPropertyValue("font-family"),w=parseInt(l.getPropertyValue("font-size"))||32,C=parseInt(l.getPropertyValue("font-weight"))||!1,b=l.getPropertyValue("color")||"#000",u=document.createElement("span");u.dataset.snapdomPseudo=s;let I=F(l),P=B(I,"span",a);o.set(u,P);let j=p&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(p),y=X(d);if(!r&&j&&y.length===1){let $=document.createElement("img");$.src=await G(y,p,C,w,b),$.style="display:block;width:100%;height:100%;object-fit:contain;",u.appendChild($)}else if(y.startsWith("url(")){let $=v(y);if($)try{let L=document.createElement("img"),st=await x(encodeURI($));L.src=st,L.style="display:block;width:100%;height:100%;object-fit:contain;",u.appendChild(L)}catch(L){console.error(`[snapdom] Error in pseudo ${s} for`,t,L)}}else!j&&y&&y!=="none"&&(u.textContent=y);if(!(u.childNodes.length>0||u.textContent&&u.textContent.trim()!==""))continue;s==="::before"?e.insertBefore(u,e.firstChild):e.appendChild(u)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,t,l)}let i=Array.from(t.children),c=Array.from(e.children).filter(s=>!s.dataset.snapdomPseudo);for(let s=0;s<Math.min(i.length,c.length);s++)await q(i[s],c[s],o,n,a,r)}async function Q(t,e=!1,o=!1){let n=new Map,a=new WeakMap,r=new Map,i;try{i=O(t,n,a,r,e)}catch(s){throw console.warn("deepClone failed:",s),s}try{await q(t,i,n,a,e,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(e){let s=J(n);c=Array.from(s.entries()).map(([l,d])=>`.${d}{${l}}`).join("");for(let[l,d]of n.entries()){if(l.tagName==="STYLE")continue;let f=s.get(d);f&&l.classList.add(f);let m=l.style?.backgroundImage;l.removeAttribute("style"),m&&m!=="none"&&(l.style.backgroundImage=m)}}else for(let[s,l]of n.entries())s.tagName!=="STYLE"&&s.setAttribute("style",l.replace(/;/g,"; "));for(let[s,l]of r.entries()){let d=l.scrollLeft,f=l.scrollTop;if((d||f)&&s instanceof HTMLElement){s.style.overflow="hidden",s.style.scrollbarWidth="none",s.style.msOverflowStyle="none";let h=document.createElement("div");for(h.style.transform=`translate(${-d}px, ${-f}px)`,h.style.willChange="transform",h.style.display="inline-block",h.style.width="100%";s.firstChild;)h.appendChild(s.firstChild);s.appendChild(h)}}return{clone:i,classCSS:c,styleCache:a}}async function Z(t){let e=Array.from(t.querySelectorAll("img")),o=async n=>{let a=n.src;try{let r=await x(a);n.src=r,n.width||(n.width=n.naturalWidth||100),n.height||(n.height=n.naturalHeight||100)}catch{let r=document.createElement("div");r.style=`width: ${n.width||100}px; height: ${n.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${n.height||100}px; color: #666; font-size: 12px;`,r.innerText="img",n.replaceWith(r)}};for(let n=0;n<e.length;n+=4){let a=e.slice(n,n+4).map(o);await Promise.allSettled(a)}}async function tt(t,e,o){let n=[[t,e]];for(;n.length;){let[a,r]=n.shift(),i=o.get(a)||A(a);o.has(a)||o.set(a,i);let c=i.getPropertyValue("background-image"),s=v(c);if(s)try{let f=encodeURI(s),m;E.has(f)?m=E.get(f):(m=await x(f),E.set(f,m)),r.style.backgroundImage=`url(${m})`}catch{r.style.backgroundImage="none"}let l=Array.from(a.children),d=Array.from(r.children);for(let f=0;f<Math.min(l.length,d.length);f++)n.push([l[f],d[f]])}}async function et(t,e={}){if(!t)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:a=!0,scale:r=1}=e,i,c,s,l="",d="",f,m;if({clone:i,classCSS:c,styleCache:s}=await Q(t,o,n),await new Promise(p=>{N(async()=>{await Z(i),p()},{fast:a})}),await new Promise(p=>{N(async()=>{await tt(t,i,s),p()},{fast:a})}),n&&await new Promise(p=>{N(async()=>{l=await W({ignoreIconFonts:!n}),p()},{fast:a})}),o){let p=Y(i).sort(),w=p.join(",");k.has(w)?d=k.get(w):await new Promise(C=>{N(()=>{d=K(p),k.set(w,d),C()},{fast:a})})}await new Promise(p=>{N(()=>{let w=t.getBoundingClientRect(),C=Math.ceil(w.width),b=Math.ceil(w.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",r!==1&&D()&&(i.style.scale=`${r}`);let u="http://www.w3.org/2000/svg",I=document.createElementNS(u,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,I.appendChild(P),I.appendChild(i);let y=new XMLSerializer().serializeToString(I);m=`<svg xmlns="${u}" width="${C}" height="${b}" viewBox="0 0 ${C} ${b}">`+y+"</svg>",f=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(m)}`,p()},{fast:a})});let h=document.getElementById("snapdom-sandbox");return h&&h.style.position==="absolute"&&h.remove(),f}async function ct(t,{dpr:e=1,scale:o=1}){let n=new Image;return n.src=t,await n.decode(),D?(n.width=n.width*o,n.height=n.height*o):(n.width=n.width/o,n.height=n.height/o),n}async function nt(t,{dpr:e=1,scale:o=1}){let n=new Image;n.src=t,await n.decode();let a=document.createElement("canvas"),r=n.width*o*e,i=n.height*o*e;a.width=Math.ceil(r),a.height=Math.ceil(i);let c=a.getContext("2d");return c.scale(o*e,o*e),c.drawImage(n,0,0),a.style.width=`${a.width/e}px`,a.style.height=`${a.height/e}px`,a}async function ot(t){let e=decodeURIComponent(t.split(",")[1]);return new Blob([e],{type:"image/svg+xml"})}async function at(t,{dpr:e=1,scale:o=1},n){let a=await nt(t,{dpr:e,scale:o});if(!n)return a;let r=document.createElement("canvas");r.width=a.width,r.height=a.height;let i=r.getContext("2d");return i.fillStyle=n,i.fillRect(0,0,r.width,r.height),i.drawImage(a,0,0),r}async function z(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let i=await at(t,{dpr:e,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${i.width/e}px`,c.style.height=`${i.height/e}px`,c}async function lt(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let m=await ot(t),h=URL.createObjectURL(m),p=document.createElement("a");p.href=h,p.download=`${r}.svg`,p.click(),URL.revokeObjectURL(h);return}let i=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,s=await at(t,{dpr:e,scale:o},n??i),l={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[a]||"image/png",d=s.toDataURL(l),f=document.createElement("a");f.href=d,f.download=`${r}.${a}`,f.click()}async function g(t,e={}){if(e={scale:1,...e},!t)throw new Error("Element cannot be null or undefined");return await g.capture(t,e)}g.capture=async(t,e={})=>{let o=await et(t,e),n=window.devicePixelRatio||1,a=e.scale||1;return{url:o,options:e,toRaw:()=>o,toImg:()=>ct(o,{dpr:n,scale:a}),toCanvas:()=>nt(o,{dpr:n,scale:a}),toBlob:()=>ot(o),toPng:r=>z(o,{dpr:n,scale:a,...r},"png"),toJpg:r=>z(o,{dpr:n,scale:a,...r},"jpeg"),toWebp:r=>z(o,{dpr:n,scale:a,...r},"webp"),download:({format:r="png",filename:i="capture",backgroundColor:c}={})=>lt(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:i})}};g.toRaw=async(t,e)=>(await g.capture(t,e)).toRaw();g.toImg=async(t,e)=>(await g.capture(t,e)).toImg();g.toCanvas=async(t,e)=>(await g.capture(t,e)).toCanvas();g.toBlob=async(t,e)=>(await g.capture(t,e)).toBlob();g.toPng=async(t,e)=>(await g.capture(t,e)).toPng(e);g.toJpg=async(t,e)=>(await g.capture(t,e)).toJpg(e);g.toWebp=async(t,e)=>(await g.capture(t,e)).toWebp(e);g.download=async(t,e={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=e;return await(await g.capture(t,r)).download({format:o,filename:n,backgroundColor:a})};async function dt(t=document,e={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=e;if(n){S.clear(),E.clear(),R.clear(),k.clear(),U.clear();return}await document.fonts.ready,_();let r=[],i=[];t?.querySelectorAll&&(r=Array.from(t.querySelectorAll("img[src]")),i=Array.from(t.querySelectorAll("*")));let c=[];for(let s of r){let l=s.src;S.has(l)||c.push(x(l).then(d=>S.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=v(l);d&&!E.has(d)&&c.push(x(d).then(f=>E.set(d,f)).catch(()=>{}))}o&&await W({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}export{dt as preCache,g as snapdom};
|
package/dist/snapdom.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
3
|
* snapdom
|
|
4
|
-
* v.1.2.
|
|
4
|
+
* v.1.2.5
|
|
5
5
|
* Author Juan Martin Muda
|
|
6
6
|
* License MIT
|
|
7
7
|
**/
|
|
@@ -186,9 +186,15 @@ function parseContent(content) {
|
|
|
186
186
|
}
|
|
187
187
|
return clean;
|
|
188
188
|
}
|
|
189
|
-
function
|
|
190
|
-
const
|
|
191
|
-
|
|
189
|
+
function extractURL(value) {
|
|
190
|
+
const urlStart = value.indexOf("url(");
|
|
191
|
+
if (urlStart === -1) return null;
|
|
192
|
+
let url = value.slice(urlStart + 4).trim();
|
|
193
|
+
if (url.endsWith(")")) url = url.slice(0, -1).trim();
|
|
194
|
+
if (url.startsWith('"') && url.endsWith('"') || url.startsWith("'") && url.endsWith("'")) {
|
|
195
|
+
url = url.slice(1, -1);
|
|
196
|
+
}
|
|
197
|
+
return url;
|
|
192
198
|
}
|
|
193
199
|
function isIconFont(familyOrUrl) {
|
|
194
200
|
const iconFontPatterns = [
|
|
@@ -362,10 +368,17 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
|
|
|
362
368
|
const urlRegex = /url\(([^)]+)\)/g;
|
|
363
369
|
const inlinedCSS = await Promise.all(
|
|
364
370
|
Array.from(cssText.matchAll(urlRegex)).map(async (match) => {
|
|
365
|
-
let
|
|
371
|
+
let rawUrl = extractURL(match[0]);
|
|
372
|
+
if (!rawUrl) return null;
|
|
373
|
+
let url = rawUrl;
|
|
366
374
|
if (!url.startsWith("http")) {
|
|
367
375
|
url = new URL(url, link.href).href;
|
|
368
376
|
}
|
|
377
|
+
try {
|
|
378
|
+
url = encodeURI(url);
|
|
379
|
+
} catch (e) {
|
|
380
|
+
console.warn("[snapdom] Failed to encode font URL:", url);
|
|
381
|
+
}
|
|
369
382
|
if (ignoreIconFonts && isIconFont(url)) {
|
|
370
383
|
return null;
|
|
371
384
|
}
|
|
@@ -429,29 +442,43 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
|
|
|
429
442
|
const snapshot = snapshotComputedStyle(style);
|
|
430
443
|
const key = getStyleKey(snapshot, "span", compress);
|
|
431
444
|
styleMap.set(pseudoEl, key);
|
|
432
|
-
const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
|
|
445
|
+
const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
|
|
446
|
+
fontFamily
|
|
447
|
+
);
|
|
433
448
|
let cleanContent = parseContent(content);
|
|
434
449
|
if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
|
|
435
450
|
const imgEl = document.createElement("img");
|
|
436
|
-
imgEl.src = await iconToImage(
|
|
451
|
+
imgEl.src = await iconToImage(
|
|
452
|
+
cleanContent,
|
|
453
|
+
fontFamily,
|
|
454
|
+
fontWeight,
|
|
455
|
+
fontSize,
|
|
456
|
+
color
|
|
457
|
+
);
|
|
437
458
|
imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
|
|
438
459
|
pseudoEl.appendChild(imgEl);
|
|
439
460
|
} else if (cleanContent.startsWith("url(")) {
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
461
|
+
const rawUrl = extractURL(cleanContent);
|
|
462
|
+
if (rawUrl) {
|
|
442
463
|
try {
|
|
443
464
|
const imgEl = document.createElement("img");
|
|
444
|
-
const dataUrl = await fetchImage(
|
|
465
|
+
const dataUrl = await fetchImage(encodeURI(rawUrl));
|
|
445
466
|
imgEl.src = dataUrl;
|
|
446
467
|
imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
|
|
447
468
|
pseudoEl.appendChild(imgEl);
|
|
448
469
|
} catch (e) {
|
|
449
|
-
console.error(
|
|
470
|
+
console.error(
|
|
471
|
+
`[snapdom] Error in pseudo ${pseudo} for`,
|
|
472
|
+
source,
|
|
473
|
+
e
|
|
474
|
+
);
|
|
450
475
|
}
|
|
451
476
|
}
|
|
452
|
-
} else if (cleanContent && cleanContent !== "none") {
|
|
477
|
+
} else if (!isIconFont2 && cleanContent && cleanContent !== "none") {
|
|
453
478
|
pseudoEl.textContent = cleanContent;
|
|
454
479
|
}
|
|
480
|
+
const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent && pseudoEl.textContent.trim() !== "";
|
|
481
|
+
if (!hasContent2) continue;
|
|
455
482
|
if (pseudo === "::before") {
|
|
456
483
|
clone.insertBefore(pseudoEl, clone.firstChild);
|
|
457
484
|
} else {
|
|
@@ -467,7 +494,14 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
|
|
|
467
494
|
(child) => !child.dataset.snapdomPseudo
|
|
468
495
|
);
|
|
469
496
|
for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
|
|
470
|
-
await inlinePseudoElements(
|
|
497
|
+
await inlinePseudoElements(
|
|
498
|
+
sChildren[i],
|
|
499
|
+
cChildren[i],
|
|
500
|
+
styleMap,
|
|
501
|
+
styleCache,
|
|
502
|
+
compress,
|
|
503
|
+
embedFonts
|
|
504
|
+
);
|
|
471
505
|
}
|
|
472
506
|
}
|
|
473
507
|
|
|
@@ -559,22 +593,20 @@ async function inlineBackgroundImages(source, clone, styleCache) {
|
|
|
559
593
|
const style = styleCache.get(srcNode) || getStyle(srcNode);
|
|
560
594
|
if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
|
|
561
595
|
const bg = style.getPropertyValue("background-image");
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
bgCache.set(bgUrl, dataUrl);
|
|
573
|
-
}
|
|
574
|
-
cloneNode.style.backgroundImage = `url(${dataUrl})`;
|
|
575
|
-
} catch {
|
|
576
|
-
cloneNode.style.backgroundImage = "none";
|
|
596
|
+
const rawUrl = extractURL(bg);
|
|
597
|
+
if (rawUrl) {
|
|
598
|
+
try {
|
|
599
|
+
let bgUrl = encodeURI(rawUrl);
|
|
600
|
+
let dataUrl;
|
|
601
|
+
if (bgCache.has(bgUrl)) {
|
|
602
|
+
dataUrl = bgCache.get(bgUrl);
|
|
603
|
+
} else {
|
|
604
|
+
dataUrl = await fetchImage(bgUrl);
|
|
605
|
+
bgCache.set(bgUrl, dataUrl);
|
|
577
606
|
}
|
|
607
|
+
cloneNode.style.backgroundImage = `url(${dataUrl})`;
|
|
608
|
+
} catch {
|
|
609
|
+
cloneNode.style.backgroundImage = "none";
|
|
578
610
|
}
|
|
579
611
|
}
|
|
580
612
|
const sChildren = Array.from(srcNode.children);
|
|
@@ -688,6 +720,8 @@ async function toCanvas(url, { dpr = 1, scale = 1 }) {
|
|
|
688
720
|
const ctx = canvas.getContext("2d");
|
|
689
721
|
ctx.scale(scale * dpr, scale * dpr);
|
|
690
722
|
ctx.drawImage(img, 0, 0);
|
|
723
|
+
canvas.style.width = `${canvas.width / dpr}px`;
|
|
724
|
+
canvas.style.height = `${canvas.height / dpr}px`;
|
|
691
725
|
return canvas;
|
|
692
726
|
}
|
|
693
727
|
async function toBlob(url) {
|
|
@@ -811,7 +845,7 @@ async function preCache(root = document, options = {}) {
|
|
|
811
845
|
}
|
|
812
846
|
for (const el of allEls) {
|
|
813
847
|
const bg = getComputedStyle(el).backgroundImage;
|
|
814
|
-
const url =
|
|
848
|
+
const url = extractURL(bg);
|
|
815
849
|
if (url && !bgCache.has(url)) {
|
|
816
850
|
promises.push(
|
|
817
851
|
fetchImage(url).then((dataURL) => bgCache.set(url, dataURL)).catch(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zumer/snapdom",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "snapDOM captures DOM elements as images with exceptional speed and minimal overhead. Designed to avoid bottlenecks and long tasks.",
|
|
5
5
|
"main": "dist/snapdom.js",
|
|
6
6
|
"module": "dist/snapdom.mjs",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"types": "types/snapdom.d.ts",
|
|
23
23
|
"exports": {
|
|
24
24
|
".": {
|
|
25
|
+
"types": "./types/snapdom.d.ts",
|
|
25
26
|
"import": "./dist/snapdom.mjs",
|
|
26
27
|
"require": "./dist/snapdom.js"
|
|
27
28
|
}
|
|
@@ -62,7 +63,7 @@
|
|
|
62
63
|
"bugs": {
|
|
63
64
|
"url": "https://github.com/zumerlab/snapdom/issues"
|
|
64
65
|
},
|
|
65
|
-
"homepage": "https://github.
|
|
66
|
+
"homepage": "https://zumerlab.github.io/snapdom/",
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@vitest/browser": "^3.1.2",
|
|
68
69
|
"playwright": "^1.52.0"
|