@zumer/snapdom 1.2.2 → 1.3.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 CHANGED
@@ -39,7 +39,7 @@ yarn add @zumer/snapdom
39
39
  ### CDN
40
40
 
41
41
  ```html
42
- <script src="https://unpkg.com/@zumer/snapdom@latest/dist/snapdom.min.js"></script>
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://unpkg.com/@zumer/snapdom@latest/dist/snapdom.mjs';
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.2
4
+ * v.1.3.0
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 extractUrl(cssValue) {
190
- const m = cssValue.match(/url\(["']?([^"')]+)["']?\)/);
191
- return m ? m[1] : null;
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 = [
@@ -221,7 +227,7 @@
221
227
  canvas.width = image.width;
222
228
  canvas.height = image.height;
223
229
  const ctx = canvas.getContext("2d");
224
- ctx.drawImage(image, 0, 0);
230
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
225
231
  try {
226
232
  const dataURL = canvas.toDataURL("image/png");
227
233
  imageCache.set(src, dataURL);
@@ -309,6 +315,26 @@
309
315
  if (node.nodeType !== Node.ELEMENT_NODE) return node.cloneNode(true);
310
316
  const clone = node.cloneNode(false);
311
317
  nodeMap.set(clone, node);
318
+ if (node instanceof HTMLInputElement) {
319
+ clone.value = node.value;
320
+ clone.setAttribute("value", node.value);
321
+ if (node.checked !== void 0) {
322
+ clone.checked = node.checked;
323
+ if (node.checked) clone.setAttribute("checked", "");
324
+ }
325
+ } else if (node instanceof HTMLTextAreaElement) {
326
+ clone.value = node.value;
327
+ clone.textContent = node.value;
328
+ } else if (node instanceof HTMLSelectElement) {
329
+ clone.value = node.value;
330
+ Array.from(clone.options).forEach((opt) => {
331
+ if (opt.value === node.value) {
332
+ opt.setAttribute("selected", "");
333
+ } else {
334
+ opt.removeAttribute("selected");
335
+ }
336
+ });
337
+ }
312
338
  inlineAllStyles(node, clone, styleMap, styleCache, compress);
313
339
  const frag = document.createDocumentFragment();
314
340
  node.childNodes.forEach((child) => {
@@ -362,10 +388,17 @@
362
388
  const urlRegex = /url\(([^)]+)\)/g;
363
389
  const inlinedCSS = await Promise.all(
364
390
  Array.from(cssText.matchAll(urlRegex)).map(async (match) => {
365
- let url = match[1].replace(/["']/g, "");
391
+ let rawUrl = extractURL(match[0]);
392
+ if (!rawUrl) return null;
393
+ let url = rawUrl;
366
394
  if (!url.startsWith("http")) {
367
395
  url = new URL(url, link.href).href;
368
396
  }
397
+ try {
398
+ url = encodeURI(url);
399
+ } catch (e) {
400
+ console.warn("[snapdom] Failed to encode font URL:", url);
401
+ }
369
402
  if (ignoreIconFonts && isIconFont(url)) {
370
403
  return null;
371
404
  }
@@ -429,19 +462,27 @@
429
462
  const snapshot = snapshotComputedStyle(style);
430
463
  const key = getStyleKey(snapshot, "span", compress);
431
464
  styleMap.set(pseudoEl, key);
432
- const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(fontFamily);
465
+ const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
466
+ fontFamily
467
+ );
433
468
  let cleanContent = parseContent(content);
434
469
  if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
435
470
  const imgEl = document.createElement("img");
436
- imgEl.src = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color);
471
+ imgEl.src = await iconToImage(
472
+ cleanContent,
473
+ fontFamily,
474
+ fontWeight,
475
+ fontSize,
476
+ color
477
+ );
437
478
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
438
479
  pseudoEl.appendChild(imgEl);
439
480
  } else if (cleanContent.startsWith("url(")) {
440
- const match = cleanContent.match(/url\(["']?([^"')]+)["']?\)/);
441
- if (match?.[1]) {
481
+ const rawUrl = extractURL(cleanContent);
482
+ if (rawUrl) {
442
483
  try {
443
484
  const imgEl = document.createElement("img");
444
- const dataUrl = await fetchImage(match[1]);
485
+ const dataUrl = await fetchImage(encodeURI(rawUrl));
445
486
  imgEl.src = dataUrl;
446
487
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
447
488
  pseudoEl.appendChild(imgEl);
@@ -449,9 +490,22 @@
449
490
  console.error(`[snapdom] Error in pseudo ${pseudo} for`, source, e);
450
491
  }
451
492
  }
452
- } else if (cleanContent && cleanContent !== "none") {
493
+ } else if (!isIconFont2 && cleanContent && cleanContent !== "none") {
453
494
  pseudoEl.textContent = cleanContent;
454
495
  }
496
+ if (hasBg && bg) {
497
+ const rawUrl = extractURL(bg);
498
+ if (rawUrl) {
499
+ try {
500
+ const dataUrl = await fetchImage(encodeURI(rawUrl));
501
+ pseudoEl.style.backgroundImage = `url(${dataUrl})`;
502
+ } catch (e) {
503
+ console.warn(`[snapdom] Failed to inline background-image for ${pseudo}`, e);
504
+ }
505
+ }
506
+ }
507
+ const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent && pseudoEl.textContent.trim() !== "";
508
+ if (!hasContent2 && !hasBg) continue;
455
509
  if (pseudo === "::before") {
456
510
  clone.insertBefore(pseudoEl, clone.firstChild);
457
511
  } else {
@@ -463,11 +517,16 @@
463
517
  }
464
518
  }
465
519
  const sChildren = Array.from(source.children);
466
- const cChildren = Array.from(clone.children).filter(
467
- (child) => !child.dataset.snapdomPseudo
468
- );
520
+ const cChildren = Array.from(clone.children).filter((child) => !child.dataset.snapdomPseudo);
469
521
  for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
470
- await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress, embedFonts);
522
+ await inlinePseudoElements(
523
+ sChildren[i],
524
+ cChildren[i],
525
+ styleMap,
526
+ styleCache,
527
+ compress,
528
+ embedFonts
529
+ );
471
530
  }
472
531
  }
473
532
 
@@ -559,22 +618,20 @@
559
618
  const style = styleCache.get(srcNode) || getStyle(srcNode);
560
619
  if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
561
620
  const bg = style.getPropertyValue("background-image");
562
- if (bg && bg.includes("url(")) {
563
- const match = bg.match(/url\(["']?([^"')]+)["']?\)/);
564
- if (match?.[1]) {
565
- try {
566
- const bgUrl = match[1];
567
- let dataUrl;
568
- if (bgCache.has(bgUrl)) {
569
- dataUrl = bgCache.get(bgUrl);
570
- } else {
571
- dataUrl = await fetchImage(bgUrl);
572
- bgCache.set(bgUrl, dataUrl);
573
- }
574
- cloneNode.style.backgroundImage = `url(${dataUrl})`;
575
- } catch {
576
- cloneNode.style.backgroundImage = "none";
621
+ const rawUrl = extractURL(bg);
622
+ if (rawUrl) {
623
+ try {
624
+ let bgUrl = encodeURI(rawUrl);
625
+ let dataUrl;
626
+ if (bgCache.has(bgUrl)) {
627
+ dataUrl = bgCache.get(bgUrl);
628
+ } else {
629
+ dataUrl = await fetchImage(bgUrl);
630
+ bgCache.set(bgUrl, dataUrl);
577
631
  }
632
+ cloneNode.style.backgroundImage = `url(${dataUrl})`;
633
+ } catch {
634
+ cloneNode.style.backgroundImage = "none";
578
635
  }
579
636
  }
580
637
  const sChildren = Array.from(srcNode.children);
@@ -676,18 +733,20 @@
676
733
  }
677
734
  return img;
678
735
  }
679
- async function toCanvas(url, { dpr = 1, scale = 1 }) {
736
+ async function toCanvas(url, { dpr = 1, scale = 1 } = {}) {
680
737
  const img = new Image();
681
738
  img.src = url;
682
739
  await img.decode();
683
740
  const canvas = document.createElement("canvas");
684
- const width = img.width * scale * dpr;
685
- const height = img.height * scale * dpr;
686
- canvas.width = Math.ceil(width);
687
- canvas.height = Math.ceil(height);
741
+ const width = img.width * scale;
742
+ const height = img.height * scale;
743
+ canvas.width = Math.ceil(width * dpr);
744
+ canvas.height = Math.ceil(height * dpr);
688
745
  const ctx = canvas.getContext("2d");
689
- ctx.scale(scale * dpr, scale * dpr);
690
- ctx.drawImage(img, 0, 0);
746
+ ctx.scale(dpr, dpr);
747
+ ctx.drawImage(img, 0, 0, width, height);
748
+ canvas.style.width = `${width}px`;
749
+ canvas.style.height = `${height}px`;
691
750
  return canvas;
692
751
  }
693
752
  async function toBlob(url) {
@@ -811,7 +870,7 @@
811
870
  }
812
871
  for (const el of allEls) {
813
872
  const bg = getComputedStyle(el).backgroundImage;
814
- const url = extractUrl(bg);
873
+ const url = extractURL(bg);
815
874
  if (url && !bgCache.has(url)) {
816
875
  promises.push(
817
876
  fetchImage(url).then((dataURL) => bgCache.set(url, dataURL)).catch(() => {
@@ -1,3 +1,3 @@
1
- (()=>{var b=new Map,S=new Map,I=new Map,T=new Map,k=new Map,R=new WeakMap;var ie=["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 z(){for(let e of ie)_(e)}function _(e){if(T.has(e))return T.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let i={};return T.set(e,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(e);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(e,r),r}function U(e,t,o=!1){let n=[],a=_(t);for(let[r,i]of Object.entries(e))if(!o)i&&n.push(`${r}:${i}`);else{let c=a[r];i&&i!==c&&n.push(`${r}:${i}`)}return n.sort().join(";")}function H(e){let t=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&t.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>t.add(o.tagName.toLowerCase())),Array.from(t))}function Y(e){let t=new Map;for(let n of e){let a=T.get(n);if(!a)continue;let r=Object.entries(a).map(([i,c])=>`${i}:${c};`).sort().join("");t.has(r)||t.set(r,[]),t.get(r).push(n)}let o="";for(let[n,a]of t.entries())o+=`${a.join(",")} { ${n} }
2
- `;return o}function K(e){let t=new Set(e.values()),o=new Map,n=1;for(let a of t)o.set(a,`c${n++}`);return o}function N(e,{fast:t=!1}={}){if(t)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,t=null){if(!(e instanceof Element))return window.getComputedStyle(e,t);let o=R.get(e);if(o||(o=new Map,R.set(e,o)),!o.has(t)){let n=window.getComputedStyle(e,t);o.set(t,n)}return o.get(t)}function J(e){let t=e.replace(/^['"]|['"]$/g,"");if(t.startsWith("\\"))try{return String.fromCharCode(parseInt(t.replace("\\",""),16))}catch{return t}return t}function X(e){let t=e.match(/url\(["']?([^"')]+)["']?\)/);return t?t[1]:null}function B(e){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(e))}function x(e,t=3e3){return b.has(e)?Promise.resolve(b.get(e)):new Promise((o,n)=>{let a=setTimeout(()=>{n(new Error("Image load timed out"))},t),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");b.set(e,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=e})}function M(e){let t={};for(let o of e)t[o]=e.getPropertyValue(o);return t}function F(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function O(e,t,o,n,a){if(e.tagName==="STYLE")return;n.has(e)||n.set(e,A(e));let r=n.get(e),i=M(r),c=e.tagName?.toLowerCase()||"div",s=U(i,c,a);o.set(t,s)}function D(e,t,o,n,a){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(e.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${e.offsetWidth}px; height: ${e.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(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="placeholder"){let c=e.cloneNode(!1);n.set(c,e),O(e,c,t,o,a);let s=document.createElement("div");return s.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),s=document.createElement("img");return s.src=c,s.width=e.width,s.height=e.height,s.style.display="inline-block",s.style.width=`${e.width}px`,s.style.height=`${e.height}px`,s}if(e.nodeType===Node.TEXT_NODE){if(e.parentElement?.shadowRoot){let c=e.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let r=e.cloneNode(!1);n.set(r,e),O(e,r,t,o,a);let i=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let s=D(c,t,o,n,a);s&&i.appendChild(s)}),r.appendChild(i),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>D(l,t,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),r.appendChild(s)}return r}async function G(e,t,o,n=32,a="#000"){t=t.replace(/^['"]+|['"]+$/g,"");let r=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${t}"`:`${n}px "${t}"`;let s=c.measureText(e),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,m=l+d,h=s.width,p=document.createElement("canvas");p.width=Math.ceil(h*r),p.height=Math.ceil(m*r);let f=p.getContext("2d");return f.scale(r,r),f.font=c.font,f.textAlign="left",f.textBaseline="alphabetic",f.fillStyle=a,f.fillText(e,0,l),p.toDataURL()}async function j({ignoreIconFonts:e=!0,preCached:t=!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(e&&(B(a.href)||B(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let m=d[1].replace(/["']/g,"");if(m.startsWith("http")||(m=new URL(m,a.href).href),e&&B(m))return null;if(I.has(m))return{original:d[0],inlined:`url(${I.get(m)})`};try{let p=await(await fetch(m)).blob(),f=await new Promise(u=>{let w=new FileReader;w.onload=()=>u(w.result),w.readAsDataURL(p)});return I.set(m,f),{original:d[0],inlined:`url(${f})`}}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&&t){let a=document.createElement("style");a.setAttribute("data-snapdom","embedFonts"),a.textContent=n,document.head.appendChild(a)}return n}async function W(e,t,o,n,a,r=!1){if(!(e instanceof Element)||!(t instanceof Element))return;for(let s of["::before","::after"])try{let l=A(e,s);if(!l)continue;let d=l.getPropertyValue("content"),m=l.getPropertyValue("background-image"),h=d&&d!=="none"&&d!=='""'&&d!=="''",p=m&&m.startsWith("url(");if(h||p){let f=l.getPropertyValue("font-family"),u=parseInt(l.getPropertyValue("font-size"))||32,w=parseInt(l.getPropertyValue("font-weight"))||!1,L=l.getPropertyValue("color")||"#000",y=document.createElement("span");y.dataset.snapdomPseudo=s;let E=M(l),P=U(E,"span",a);o.set(y,P);let q=f&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(f),C=J(d);if(!r&&q&&C.length===1){let v=document.createElement("img");v.src=await G(C,f,w,u,L),v.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(v)}else if(C.startsWith("url(")){let v=C.match(/url\(["']?([^"')]+)["']?\)/);if(v?.[1])try{let $=document.createElement("img"),se=await x(v[1]);$.src=se,$.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild($)}catch($){console.error(`[snapdom] Error in pseudo ${s} for`,e,$)}}else C&&C!=="none"&&(y.textContent=C);s==="::before"?t.insertBefore(y,t.firstChild):t.appendChild(y)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,e,l)}let i=Array.from(e.children),c=Array.from(t.children).filter(s=>!s.dataset.snapdomPseudo);for(let s=0;s<Math.min(i.length,c.length);s++)await W(i[s],c[s],o,n,a,r)}async function Q(e,t=!1,o=!1){let n=new Map,a=new WeakMap,r=new Map,i;try{i=D(e,n,a,r,t)}catch(s){throw console.warn("deepClone failed:",s),s}try{await W(e,i,n,a,t,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(t){let s=K(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 m=s.get(d);m&&l.classList.add(m);let h=l.style?.backgroundImage;l.removeAttribute("style"),h&&h!=="none"&&(l.style.backgroundImage=h)}}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,m=l.scrollTop;if((d||m)&&s instanceof HTMLElement){s.style.overflow="hidden",s.style.scrollbarWidth="none",s.style.msOverflowStyle="none";let p=document.createElement("div");for(p.style.transform=`translate(${-d}px, ${-m}px)`,p.style.willChange="transform",p.style.display="inline-block",p.style.width="100%";s.firstChild;)p.appendChild(s.firstChild);s.appendChild(p)}}return{clone:i,classCSS:c,styleCache:a}}async function Z(e){let t=Array.from(e.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<t.length;n+=4){let a=t.slice(n,n+4).map(o);await Promise.allSettled(a)}}async function ee(e,t,o){let n=[[e,t]];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");if(c&&c.includes("url(")){let d=c.match(/url\(["']?([^"')]+)["']?\)/);if(d?.[1])try{let m=d[1],h;S.has(m)?h=S.get(m):(h=await x(m),S.set(m,h)),r.style.backgroundImage=`url(${h})`}catch{r.style.backgroundImage="none"}}let s=Array.from(a.children),l=Array.from(r.children);for(let d=0;d<Math.min(s.length,l.length);d++)n.push([s[d],l[d]])}}async function te(e,t={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:a=!0,scale:r=1}=t,i,c,s,l="",d="",m,h;if({clone:i,classCSS:c,styleCache:s}=await Q(e,o,n),await new Promise(f=>{N(async()=>{await Z(i),f()},{fast:a})}),await new Promise(f=>{N(async()=>{await ee(e,i,s),f()},{fast:a})}),n&&await new Promise(f=>{N(async()=>{l=await j({ignoreIconFonts:!n}),f()},{fast:a})}),o){let f=H(i).sort(),u=f.join(",");k.has(u)?d=k.get(u):await new Promise(w=>{N(()=>{d=Y(f),k.set(u,d),w()},{fast:a})})}await new Promise(f=>{N(()=>{let u=e.getBoundingClientRect(),w=Math.ceil(u.width),L=Math.ceil(u.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",r!==1&&F()&&(i.style.scale=`${r}`);let y="http://www.w3.org/2000/svg",E=document.createElementNS(y,"foreignObject");E.setAttribute("width","100%"),E.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,E.appendChild(P),E.appendChild(i);let C=new XMLSerializer().serializeToString(E);h=`<svg xmlns="${y}" width="${w}" height="${L}" viewBox="0 0 ${w} ${L}">`+C+"</svg>",m=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(h)}`,f()},{fast:a})});let p=document.getElementById("snapdom-sandbox");return p&&p.style.position==="absolute"&&p.remove(),m}async function ce(e,{dpr:t=1,scale:o=1}){let n=new Image;return n.src=e,await n.decode(),F?(n.width=n.width*o,n.height=n.height*o):(n.width=n.width/o,n.height=n.height/o),n}async function ne(e,{dpr:t=1,scale:o=1}){let n=new Image;n.src=e,await n.decode();let a=document.createElement("canvas"),r=n.width*o*t,i=n.height*o*t;a.width=Math.ceil(r),a.height=Math.ceil(i);let c=a.getContext("2d");return c.scale(o*t,o*t),c.drawImage(n,0,0),a}async function oe(e){let t=decodeURIComponent(e.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})}async function ae(e,{dpr:t=1,scale:o=1},n){let a=await ne(e,{dpr:t,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 V(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let i=await ae(e,{dpr:t,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${i.width/t}px`,c.style.height=`${i.height/t}px`,c}async function le(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let h=await oe(e),p=URL.createObjectURL(h),f=document.createElement("a");f.href=p,f.download=`${r}.svg`,f.click(),URL.revokeObjectURL(p);return}let i=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,s=await ae(e,{dpr:t,scale:o},n??i),l={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[a]||"image/png",d=s.toDataURL(l),m=document.createElement("a");m.href=d,m.download=`${r}.${a}`,m.click()}async function g(e,t={}){if(t={scale:1,...t},!e)throw new Error("Element cannot be null or undefined");return await g.capture(e,t)}g.capture=async(e,t={})=>{let o=await te(e,t),n=window.devicePixelRatio||1,a=t.scale||1;return{url:o,options:t,toRaw:()=>o,toImg:()=>ce(o,{dpr:n,scale:a}),toCanvas:()=>ne(o,{dpr:n,scale:a}),toBlob:()=>oe(o),toPng:r=>V(o,{dpr:n,scale:a,...r},"png"),toJpg:r=>V(o,{dpr:n,scale:a,...r},"jpeg"),toWebp:r=>V(o,{dpr:n,scale:a,...r},"webp"),download:({format:r="png",filename:i="capture",backgroundColor:c}={})=>le(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:i})}};g.toRaw=async(e,t)=>(await g.capture(e,t)).toRaw();g.toImg=async(e,t)=>(await g.capture(e,t)).toImg();g.toCanvas=async(e,t)=>(await g.capture(e,t)).toCanvas();g.toBlob=async(e,t)=>(await g.capture(e,t)).toBlob();g.toPng=async(e,t)=>(await g.capture(e,t)).toPng(t);g.toJpg=async(e,t)=>(await g.capture(e,t)).toJpg(t);g.toWebp=async(e,t)=>(await g.capture(e,t)).toWebp(t);g.download=async(e,t={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=t;return await(await g.capture(e,r)).download({format:o,filename:n,backgroundColor:a})};async function re(e=document,t={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=t;if(n){b.clear(),S.clear(),I.clear(),k.clear(),R.clear();return}await document.fonts.ready,z();let r=[],i=[];e?.querySelectorAll&&(r=Array.from(e.querySelectorAll("img[src]")),i=Array.from(e.querySelectorAll("*")));let c=[];for(let s of r){let l=s.src;b.has(l)||c.push(x(l).then(d=>b.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=X(l);d&&!S.has(d)&&c.push(x(d).then(m=>S.set(d,m)).catch(()=>{}))}o&&await j({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}window.snapdom=g;window.preCache=re;})();
1
+ (()=>{var I=new Map,$=new Map,T=new Map,R=new Map,A=new Map,U=new WeakMap;var ce=["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 z(){for(let e of ce)_(e)}function _(e){if(R.has(e))return R.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let i={};return R.set(e,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(e);n.style.all="initial",o.appendChild(n);let r=getComputedStyle(n),a={};for(let i of r)a[i]=r.getPropertyValue(i);return o.removeChild(n),R.set(e,a),a}function M(e,t,o=!1){let n=[],r=_(t);for(let[a,i]of Object.entries(e))if(!o)i&&n.push(`${a}:${i}`);else{let c=r[a];i&&i!==c&&n.push(`${a}:${i}`)}return n.sort().join(";")}function Y(e){let t=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&t.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>t.add(o.tagName.toLowerCase())),Array.from(t))}function K(e){let t=new Map;for(let n of e){let r=R.get(n);if(!r)continue;let a=Object.entries(r).map(([i,c])=>`${i}:${c};`).sort().join("");t.has(a)||t.set(a,[]),t.get(a).push(n)}let o="";for(let[n,r]of t.entries())o+=`${r.join(",")} { ${n} }
2
+ `;return o}function J(e){let t=new Set(e.values()),o=new Map,n=1;for(let r of t)o.set(r,`c${n++}`);return o}function L(e,{fast:t=!1}={}){if(t)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function N(e,t=null){if(!(e instanceof Element))return window.getComputedStyle(e,t);let o=U.get(e);if(o||(o=new Map,U.set(e,o)),!o.has(t)){let n=window.getComputedStyle(e,t);o.set(t,n)}return o.get(t)}function X(e){let t=e.replace(/^['"]|['"]$/g,"");if(t.startsWith("\\"))try{return String.fromCharCode(parseInt(t.replace("\\",""),16))}catch{return t}return t}function S(e){let t=e.indexOf("url(");if(t===-1)return null;let o=e.slice(t+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 B(e){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(e))}function x(e,t=3e3){return I.has(e)?Promise.resolve(I.get(e)):new Promise((o,n)=>{let r=setTimeout(()=>{n(new Error("Image load timed out"))},t),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(r);try{await a.decode();let i=document.createElement("canvas");i.width=a.width,i.height=a.height,i.getContext("2d").drawImage(a,0,0,i.width,i.height);try{let s=i.toDataURL("image/png");I.set(e,s),o(s)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(i){n(i)}},a.onerror=i=>{clearTimeout(r),n(new Error("Failed to load image: "+(i.message||"Unknown error")))},a.src=e})}function F(e){let t={};for(let o of e)t[o]=e.getPropertyValue(o);return t}function D(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function V(e,t,o,n,r){if(e.tagName==="STYLE")return;n.has(e)||n.set(e,N(e));let a=n.get(e),i=F(a),c=e.tagName?.toLowerCase()||"div",s=M(i,c,r);o.set(t,s)}function O(e,t,o,n,r){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(e.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${e.offsetWidth}px; height: ${e.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(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="placeholder"){let c=e.cloneNode(!1);n.set(c,e),V(e,c,t,o,r);let s=document.createElement("div");return s.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),s=document.createElement("img");return s.src=c,s.width=e.width,s.height=e.height,s.style.display="inline-block",s.style.width=`${e.width}px`,s.style.height=`${e.height}px`,s}if(e.nodeType===Node.TEXT_NODE){if(e.parentElement?.shadowRoot){let c=e.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);n.set(a,e),e instanceof HTMLInputElement?(a.value=e.value,a.setAttribute("value",e.value),e.checked!==void 0&&(a.checked=e.checked,e.checked&&a.setAttribute("checked",""))):e instanceof HTMLTextAreaElement?(a.value=e.value,a.textContent=e.value):e instanceof HTMLSelectElement&&(a.value=e.value,Array.from(a.options).forEach(c=>{c.value===e.value?c.setAttribute("selected",""):c.removeAttribute("selected")})),V(e,a,t,o,r);let i=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let s=O(c,t,o,n,r);s&&i.appendChild(s)}),a.appendChild(i),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>O(l,t,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),a.appendChild(s)}return a}async function G(e,t,o,n=32,r="#000"){t=t.replace(/^['"]+|['"]+$/g,"");let a=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${t}"`:`${n}px "${t}"`;let s=c.measureText(e),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,f=l+d,m=s.width,p=document.createElement("canvas");p.width=Math.ceil(m*a),p.height=Math.ceil(f*a);let h=p.getContext("2d");return h.scale(a,a),h.font=c.font,h.textAlign="left",h.textBaseline="alphabetic",h.fillStyle=r,h.fillText(e,0,l),p.toDataURL()}async function W({ignoreIconFonts:e=!0,preCached:t=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(r=>r.href),n="";for(let r of o)try{let i=await(await fetch(r.href)).text();if(e&&(B(r.href)||B(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let f=S(d[0]);if(!f)return null;let m=f;m.startsWith("http")||(m=new URL(m,r.href).href);try{m=encodeURI(m)}catch{console.warn("[snapdom] Failed to encode font URL:",m)}if(e&&B(m))return null;if(T.has(m))return{original:d[0],inlined:`url(${T.get(m)})`};try{let h=await(await fetch(m)).blob(),w=await new Promise(E=>{let v=new FileReader;v.onload=()=>E(v.result),v.readAsDataURL(h)});return T.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:",r.href)}if(n&&t){let r=document.createElement("style");r.setAttribute("data-snapdom","embedFonts"),r.textContent=n,document.head.appendChild(r)}return n}async function q(e,t,o,n,r,a=!1){if(!(e instanceof Element)||!(t instanceof Element))return;for(let s of["::before","::after"])try{let l=N(e,s);if(!l)continue;let d=l.getPropertyValue("content"),f=l.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",p=f&&f.startsWith("url(");if(m||p){let h=l.getPropertyValue("font-family"),w=parseInt(l.getPropertyValue("font-size"))||32,E=parseInt(l.getPropertyValue("font-weight"))||!1,v=l.getPropertyValue("color")||"#000",g=document.createElement("span");g.dataset.snapdomPseudo=s;let k=F(l),P=M(k,"span",r);o.set(g,P);let j=h&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(h),C=X(d);if(!a&&j&&C.length===1){let y=document.createElement("img");y.src=await G(C,h,E,w,v),y.style="display:block;width:100%;height:100%;object-fit:contain;",g.appendChild(y)}else if(C.startsWith("url(")){let y=S(C);if(y)try{let b=document.createElement("img"),ie=await x(encodeURI(y));b.src=ie,b.style="display:block;width:100%;height:100%;object-fit:contain;",g.appendChild(b)}catch(b){console.error(`[snapdom] Error in pseudo ${s} for`,e,b)}}else!j&&C&&C!=="none"&&(g.textContent=C);if(p&&f){let y=S(f);if(y)try{let b=await x(encodeURI(y));g.style.backgroundImage=`url(${b})`}catch(b){console.warn(`[snapdom] Failed to inline background-image for ${s}`,b)}}if(!(g.childNodes.length>0||g.textContent&&g.textContent.trim()!=="")&&!p)continue;s==="::before"?t.insertBefore(g,t.firstChild):t.appendChild(g)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,e,l)}let i=Array.from(e.children),c=Array.from(t.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,r,a)}async function Q(e,t=!1,o=!1){let n=new Map,r=new WeakMap,a=new Map,i;try{i=O(e,n,r,a,t)}catch(s){throw console.warn("deepClone failed:",s),s}try{await q(e,i,n,r,t,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(t){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 a.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 p=document.createElement("div");for(p.style.transform=`translate(${-d}px, ${-f}px)`,p.style.willChange="transform",p.style.display="inline-block",p.style.width="100%";s.firstChild;)p.appendChild(s.firstChild);s.appendChild(p)}}return{clone:i,classCSS:c,styleCache:r}}async function Z(e){let t=Array.from(e.querySelectorAll("img")),o=async n=>{let r=n.src;try{let a=await x(r);n.src=a,n.width||(n.width=n.naturalWidth||100),n.height||(n.height=n.naturalHeight||100)}catch{let a=document.createElement("div");a.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;`,a.innerText="img",n.replaceWith(a)}};for(let n=0;n<t.length;n+=4){let r=t.slice(n,n+4).map(o);await Promise.allSettled(r)}}async function ee(e,t,o){let n=[[e,t]];for(;n.length;){let[r,a]=n.shift(),i=o.get(r)||N(r);o.has(r)||o.set(r,i);let c=i.getPropertyValue("background-image"),s=S(c);if(s)try{let f=encodeURI(s),m;$.has(f)?m=$.get(f):(m=await x(f),$.set(f,m)),a.style.backgroundImage=`url(${m})`}catch{a.style.backgroundImage="none"}let l=Array.from(r.children),d=Array.from(a.children);for(let f=0;f<Math.min(l.length,d.length);f++)n.push([l[f],d[f]])}}async function te(e,t={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:r=!0,scale:a=1}=t,i,c,s,l="",d="",f,m;if({clone:i,classCSS:c,styleCache:s}=await Q(e,o,n),await new Promise(h=>{L(async()=>{await Z(i),h()},{fast:r})}),await new Promise(h=>{L(async()=>{await ee(e,i,s),h()},{fast:r})}),n&&await new Promise(h=>{L(async()=>{l=await W({ignoreIconFonts:!n}),h()},{fast:r})}),o){let h=Y(i).sort(),w=h.join(",");A.has(w)?d=A.get(w):await new Promise(E=>{L(()=>{d=K(h),A.set(w,d),E()},{fast:r})})}await new Promise(h=>{L(()=>{let w=e.getBoundingClientRect(),E=Math.ceil(w.width),v=Math.ceil(w.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",a!==1&&D()&&(i.style.scale=`${a}`);let g="http://www.w3.org/2000/svg",k=document.createElementNS(g,"foreignObject");k.setAttribute("width","100%"),k.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,k.appendChild(P),k.appendChild(i);let C=new XMLSerializer().serializeToString(k);m=`<svg xmlns="${g}" width="${E}" height="${v}" viewBox="0 0 ${E} ${v}">`+C+"</svg>",f=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(m)}`,h()},{fast:r})});let p=document.getElementById("snapdom-sandbox");return p&&p.style.position==="absolute"&&p.remove(),f}async function le(e,{dpr:t=1,scale:o=1}){let n=new Image;return n.src=e,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 ne(e,{dpr:t=1,scale:o=1}={}){let n=new Image;n.src=e,await n.decode();let r=document.createElement("canvas"),a=n.width*o,i=n.height*o;r.width=Math.ceil(a*t),r.height=Math.ceil(i*t);let c=r.getContext("2d");return c.scale(t,t),c.drawImage(n,0,0,a,i),r.style.width=`${a}px`,r.style.height=`${i}px`,r}async function oe(e){let t=decodeURIComponent(e.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})}async function ae(e,{dpr:t=1,scale:o=1},n){let r=await ne(e,{dpr:t,scale:o});if(!n)return r;let a=document.createElement("canvas");a.width=r.width,a.height=r.height;let i=a.getContext("2d");return i.fillStyle=n,i.fillRect(0,0,a.width,a.height),i.drawImage(r,0,0),a}async function H(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",quality:r},a="png"){let i=await ae(e,{dpr:t,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${a}`,r),await c.decode(),c.style.width=`${i.width/t}px`,c.style.height=`${i.height/t}px`,c}async function de(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",format:r="png",filename:a="capture"}={}){if(r==="svg"){let m=await oe(e),p=URL.createObjectURL(m),h=document.createElement("a");h.href=p,h.download=`${a}.svg`,h.click(),URL.revokeObjectURL(p);return}let i=["jpg","jpeg","webp"].includes(r)?"#fff":void 0,s=await ae(e,{dpr:t,scale:o},n??i),l={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[r]||"image/png",d=s.toDataURL(l),f=document.createElement("a");f.href=d,f.download=`${a}.${r}`,f.click()}async function u(e,t={}){if(t={scale:1,...t},!e)throw new Error("Element cannot be null or undefined");return await u.capture(e,t)}u.capture=async(e,t={})=>{let o=await te(e,t),n=window.devicePixelRatio||1,r=t.scale||1;return{url:o,options:t,toRaw:()=>o,toImg:()=>le(o,{dpr:n,scale:r}),toCanvas:()=>ne(o,{dpr:n,scale:r}),toBlob:()=>oe(o),toPng:a=>H(o,{dpr:n,scale:r,...a},"png"),toJpg:a=>H(o,{dpr:n,scale:r,...a},"jpeg"),toWebp:a=>H(o,{dpr:n,scale:r,...a},"webp"),download:({format:a="png",filename:i="capture",backgroundColor:c}={})=>de(o,{dpr:n,scale:r,backgroundColor:c,format:a,filename:i})}};u.toRaw=async(e,t)=>(await u.capture(e,t)).toRaw();u.toImg=async(e,t)=>(await u.capture(e,t)).toImg();u.toCanvas=async(e,t)=>(await u.capture(e,t)).toCanvas();u.toBlob=async(e,t)=>(await u.capture(e,t)).toBlob();u.toPng=async(e,t)=>(await u.capture(e,t)).toPng(t);u.toJpg=async(e,t)=>(await u.capture(e,t)).toJpg(t);u.toWebp=async(e,t)=>(await u.capture(e,t)).toWebp(t);u.download=async(e,t={})=>{let{format:o="png",filename:n="capture",backgroundColor:r,...a}=t;return await(await u.capture(e,a)).download({format:o,filename:n,backgroundColor:r})};async function re(e=document,t={}){let{embedFonts:o=!0,reset:n=!1,preWarm:r=!0}=t;if(n){I.clear(),$.clear(),T.clear(),A.clear(),U.clear();return}await document.fonts.ready,z();let a=[],i=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),i=Array.from(e.querySelectorAll("*")));let c=[];for(let s of a){let l=s.src;I.has(l)||c.push(x(l).then(d=>I.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=S(l);d&&!$.has(d)&&c.push(x(d).then(f=>$.set(d,f)).catch(()=>{}))}o&&await W({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}window.snapdom=u;window.preCache=re;})();
@@ -1,3 +1,3 @@
1
- var b=new Map,S=new Map,I=new Map,T=new Map,k=new Map,R=new WeakMap;var se=["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 z(){for(let e of se)_(e)}function _(e){if(T.has(e))return T.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let i={};return T.set(e,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(e);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(e,r),r}function U(e,t,o=!1){let n=[],a=_(t);for(let[r,i]of Object.entries(e))if(!o)i&&n.push(`${r}:${i}`);else{let c=a[r];i&&i!==c&&n.push(`${r}:${i}`)}return n.sort().join(";")}function H(e){let t=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&t.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>t.add(o.tagName.toLowerCase())),Array.from(t))}function Y(e){let t=new Map;for(let n of e){let a=T.get(n);if(!a)continue;let r=Object.entries(a).map(([i,c])=>`${i}:${c};`).sort().join("");t.has(r)||t.set(r,[]),t.get(r).push(n)}let o="";for(let[n,a]of t.entries())o+=`${a.join(",")} { ${n} }
2
- `;return o}function K(e){let t=new Set(e.values()),o=new Map,n=1;for(let a of t)o.set(a,`c${n++}`);return o}function N(e,{fast:t=!1}={}){if(t)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,t=null){if(!(e instanceof Element))return window.getComputedStyle(e,t);let o=R.get(e);if(o||(o=new Map,R.set(e,o)),!o.has(t)){let n=window.getComputedStyle(e,t);o.set(t,n)}return o.get(t)}function J(e){let t=e.replace(/^['"]|['"]$/g,"");if(t.startsWith("\\"))try{return String.fromCharCode(parseInt(t.replace("\\",""),16))}catch{return t}return t}function X(e){let t=e.match(/url\(["']?([^"')]+)["']?\)/);return t?t[1]:null}function B(e){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(e))}function x(e,t=3e3){return b.has(e)?Promise.resolve(b.get(e)):new Promise((o,n)=>{let a=setTimeout(()=>{n(new Error("Image load timed out"))},t),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");b.set(e,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=e})}function M(e){let t={};for(let o of e)t[o]=e.getPropertyValue(o);return t}function F(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function O(e,t,o,n,a){if(e.tagName==="STYLE")return;n.has(e)||n.set(e,A(e));let r=n.get(e),i=M(r),c=e.tagName?.toLowerCase()||"div",s=U(i,c,a);o.set(t,s)}function D(e,t,o,n,a){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(e.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${e.offsetWidth}px; height: ${e.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(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="placeholder"){let c=e.cloneNode(!1);n.set(c,e),O(e,c,t,o,a);let s=document.createElement("div");return s.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),s=document.createElement("img");return s.src=c,s.width=e.width,s.height=e.height,s.style.display="inline-block",s.style.width=`${e.width}px`,s.style.height=`${e.height}px`,s}if(e.nodeType===Node.TEXT_NODE){if(e.parentElement?.shadowRoot){let c=e.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let r=e.cloneNode(!1);n.set(r,e),O(e,r,t,o,a);let i=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let s=D(c,t,o,n,a);s&&i.appendChild(s)}),r.appendChild(i),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>D(l,t,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),r.appendChild(s)}return r}async function G(e,t,o,n=32,a="#000"){t=t.replace(/^['"]+|['"]+$/g,"");let r=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${t}"`:`${n}px "${t}"`;let s=c.measureText(e),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,f=l+d,h=s.width,p=document.createElement("canvas");p.width=Math.ceil(h*r),p.height=Math.ceil(f*r);let m=p.getContext("2d");return m.scale(r,r),m.font=c.font,m.textAlign="left",m.textBaseline="alphabetic",m.fillStyle=a,m.fillText(e,0,l),p.toDataURL()}async function j({ignoreIconFonts:e=!0,preCached:t=!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(e&&(B(a.href)||B(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let f=d[1].replace(/["']/g,"");if(f.startsWith("http")||(f=new URL(f,a.href).href),e&&B(f))return null;if(I.has(f))return{original:d[0],inlined:`url(${I.get(f)})`};try{let p=await(await fetch(f)).blob(),m=await new Promise(u=>{let w=new FileReader;w.onload=()=>u(w.result),w.readAsDataURL(p)});return I.set(f,m),{original:d[0],inlined:`url(${m})`}}catch{return console.warn("\u274C Failed to fetch font:",f),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&&t){let a=document.createElement("style");a.setAttribute("data-snapdom","embedFonts"),a.textContent=n,document.head.appendChild(a)}return n}async function W(e,t,o,n,a,r=!1){if(!(e instanceof Element)||!(t instanceof Element))return;for(let s of["::before","::after"])try{let l=A(e,s);if(!l)continue;let d=l.getPropertyValue("content"),f=l.getPropertyValue("background-image"),h=d&&d!=="none"&&d!=='""'&&d!=="''",p=f&&f.startsWith("url(");if(h||p){let m=l.getPropertyValue("font-family"),u=parseInt(l.getPropertyValue("font-size"))||32,w=parseInt(l.getPropertyValue("font-weight"))||!1,L=l.getPropertyValue("color")||"#000",y=document.createElement("span");y.dataset.snapdomPseudo=s;let E=M(l),P=U(E,"span",a);o.set(y,P);let q=m&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(m),C=J(d);if(!r&&q&&C.length===1){let v=document.createElement("img");v.src=await G(C,m,w,u,L),v.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(v)}else if(C.startsWith("url(")){let v=C.match(/url\(["']?([^"')]+)["']?\)/);if(v?.[1])try{let $=document.createElement("img"),re=await x(v[1]);$.src=re,$.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild($)}catch($){console.error(`[snapdom] Error in pseudo ${s} for`,e,$)}}else C&&C!=="none"&&(y.textContent=C);s==="::before"?t.insertBefore(y,t.firstChild):t.appendChild(y)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,e,l)}let i=Array.from(e.children),c=Array.from(t.children).filter(s=>!s.dataset.snapdomPseudo);for(let s=0;s<Math.min(i.length,c.length);s++)await W(i[s],c[s],o,n,a,r)}async function Q(e,t=!1,o=!1){let n=new Map,a=new WeakMap,r=new Map,i;try{i=D(e,n,a,r,t)}catch(s){throw console.warn("deepClone failed:",s),s}try{await W(e,i,n,a,t,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(t){let s=K(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 h=l.style?.backgroundImage;l.removeAttribute("style"),h&&h!=="none"&&(l.style.backgroundImage=h)}}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 p=document.createElement("div");for(p.style.transform=`translate(${-d}px, ${-f}px)`,p.style.willChange="transform",p.style.display="inline-block",p.style.width="100%";s.firstChild;)p.appendChild(s.firstChild);s.appendChild(p)}}return{clone:i,classCSS:c,styleCache:a}}async function Z(e){let t=Array.from(e.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<t.length;n+=4){let a=t.slice(n,n+4).map(o);await Promise.allSettled(a)}}async function ee(e,t,o){let n=[[e,t]];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");if(c&&c.includes("url(")){let d=c.match(/url\(["']?([^"')]+)["']?\)/);if(d?.[1])try{let f=d[1],h;S.has(f)?h=S.get(f):(h=await x(f),S.set(f,h)),r.style.backgroundImage=`url(${h})`}catch{r.style.backgroundImage="none"}}let s=Array.from(a.children),l=Array.from(r.children);for(let d=0;d<Math.min(s.length,l.length);d++)n.push([s[d],l[d]])}}async function te(e,t={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:a=!0,scale:r=1}=t,i,c,s,l="",d="",f,h;if({clone:i,classCSS:c,styleCache:s}=await Q(e,o,n),await new Promise(m=>{N(async()=>{await Z(i),m()},{fast:a})}),await new Promise(m=>{N(async()=>{await ee(e,i,s),m()},{fast:a})}),n&&await new Promise(m=>{N(async()=>{l=await j({ignoreIconFonts:!n}),m()},{fast:a})}),o){let m=H(i).sort(),u=m.join(",");k.has(u)?d=k.get(u):await new Promise(w=>{N(()=>{d=Y(m),k.set(u,d),w()},{fast:a})})}await new Promise(m=>{N(()=>{let u=e.getBoundingClientRect(),w=Math.ceil(u.width),L=Math.ceil(u.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",r!==1&&F()&&(i.style.scale=`${r}`);let y="http://www.w3.org/2000/svg",E=document.createElementNS(y,"foreignObject");E.setAttribute("width","100%"),E.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,E.appendChild(P),E.appendChild(i);let C=new XMLSerializer().serializeToString(E);h=`<svg xmlns="${y}" width="${w}" height="${L}" viewBox="0 0 ${w} ${L}">`+C+"</svg>",f=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(h)}`,m()},{fast:a})});let p=document.getElementById("snapdom-sandbox");return p&&p.style.position==="absolute"&&p.remove(),f}async function ie(e,{dpr:t=1,scale:o=1}){let n=new Image;return n.src=e,await n.decode(),F?(n.width=n.width*o,n.height=n.height*o):(n.width=n.width/o,n.height=n.height/o),n}async function ne(e,{dpr:t=1,scale:o=1}){let n=new Image;n.src=e,await n.decode();let a=document.createElement("canvas"),r=n.width*o*t,i=n.height*o*t;a.width=Math.ceil(r),a.height=Math.ceil(i);let c=a.getContext("2d");return c.scale(o*t,o*t),c.drawImage(n,0,0),a}async function oe(e){let t=decodeURIComponent(e.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})}async function ae(e,{dpr:t=1,scale:o=1},n){let a=await ne(e,{dpr:t,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 V(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let i=await ae(e,{dpr:t,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${i.width/t}px`,c.style.height=`${i.height/t}px`,c}async function ce(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let h=await oe(e),p=URL.createObjectURL(h),m=document.createElement("a");m.href=p,m.download=`${r}.svg`,m.click(),URL.revokeObjectURL(p);return}let i=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,s=await ae(e,{dpr:t,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(e,t={}){if(t={scale:1,...t},!e)throw new Error("Element cannot be null or undefined");return await g.capture(e,t)}g.capture=async(e,t={})=>{let o=await te(e,t),n=window.devicePixelRatio||1,a=t.scale||1;return{url:o,options:t,toRaw:()=>o,toImg:()=>ie(o,{dpr:n,scale:a}),toCanvas:()=>ne(o,{dpr:n,scale:a}),toBlob:()=>oe(o),toPng:r=>V(o,{dpr:n,scale:a,...r},"png"),toJpg:r=>V(o,{dpr:n,scale:a,...r},"jpeg"),toWebp:r=>V(o,{dpr:n,scale:a,...r},"webp"),download:({format:r="png",filename:i="capture",backgroundColor:c}={})=>ce(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:i})}};g.toRaw=async(e,t)=>(await g.capture(e,t)).toRaw();g.toImg=async(e,t)=>(await g.capture(e,t)).toImg();g.toCanvas=async(e,t)=>(await g.capture(e,t)).toCanvas();g.toBlob=async(e,t)=>(await g.capture(e,t)).toBlob();g.toPng=async(e,t)=>(await g.capture(e,t)).toPng(t);g.toJpg=async(e,t)=>(await g.capture(e,t)).toJpg(t);g.toWebp=async(e,t)=>(await g.capture(e,t)).toWebp(t);g.download=async(e,t={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=t;return await(await g.capture(e,r)).download({format:o,filename:n,backgroundColor:a})};async function le(e=document,t={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=t;if(n){b.clear(),S.clear(),I.clear(),k.clear(),R.clear();return}await document.fonts.ready,z();let r=[],i=[];e?.querySelectorAll&&(r=Array.from(e.querySelectorAll("img[src]")),i=Array.from(e.querySelectorAll("*")));let c=[];for(let s of r){let l=s.src;b.has(l)||c.push(x(l).then(d=>b.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=X(l);d&&!S.has(d)&&c.push(x(d).then(f=>S.set(d,f)).catch(()=>{}))}o&&await j({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}export{le as preCache,g as snapdom};
1
+ var I=new Map,$=new Map,T=new Map,R=new Map,A=new Map,U=new WeakMap;var ie=["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 z(){for(let e of ie)_(e)}function _(e){if(R.has(e))return R.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let i={};return R.set(e,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(e);n.style.all="initial",o.appendChild(n);let r=getComputedStyle(n),a={};for(let i of r)a[i]=r.getPropertyValue(i);return o.removeChild(n),R.set(e,a),a}function M(e,t,o=!1){let n=[],r=_(t);for(let[a,i]of Object.entries(e))if(!o)i&&n.push(`${a}:${i}`);else{let c=r[a];i&&i!==c&&n.push(`${a}:${i}`)}return n.sort().join(";")}function Y(e){let t=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&t.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>t.add(o.tagName.toLowerCase())),Array.from(t))}function K(e){let t=new Map;for(let n of e){let r=R.get(n);if(!r)continue;let a=Object.entries(r).map(([i,c])=>`${i}:${c};`).sort().join("");t.has(a)||t.set(a,[]),t.get(a).push(n)}let o="";for(let[n,r]of t.entries())o+=`${r.join(",")} { ${n} }
2
+ `;return o}function J(e){let t=new Set(e.values()),o=new Map,n=1;for(let r of t)o.set(r,`c${n++}`);return o}function L(e,{fast:t=!1}={}){if(t)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function N(e,t=null){if(!(e instanceof Element))return window.getComputedStyle(e,t);let o=U.get(e);if(o||(o=new Map,U.set(e,o)),!o.has(t)){let n=window.getComputedStyle(e,t);o.set(t,n)}return o.get(t)}function X(e){let t=e.replace(/^['"]|['"]$/g,"");if(t.startsWith("\\"))try{return String.fromCharCode(parseInt(t.replace("\\",""),16))}catch{return t}return t}function S(e){let t=e.indexOf("url(");if(t===-1)return null;let o=e.slice(t+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 B(e){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(e))}function x(e,t=3e3){return I.has(e)?Promise.resolve(I.get(e)):new Promise((o,n)=>{let r=setTimeout(()=>{n(new Error("Image load timed out"))},t),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(r);try{await a.decode();let i=document.createElement("canvas");i.width=a.width,i.height=a.height,i.getContext("2d").drawImage(a,0,0,i.width,i.height);try{let s=i.toDataURL("image/png");I.set(e,s),o(s)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(i){n(i)}},a.onerror=i=>{clearTimeout(r),n(new Error("Failed to load image: "+(i.message||"Unknown error")))},a.src=e})}function F(e){let t={};for(let o of e)t[o]=e.getPropertyValue(o);return t}function D(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function V(e,t,o,n,r){if(e.tagName==="STYLE")return;n.has(e)||n.set(e,N(e));let a=n.get(e),i=F(a),c=e.tagName?.toLowerCase()||"div",s=M(i,c,r);o.set(t,s)}function O(e,t,o,n,r){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),s=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${s.width}px; height: ${s.height}px; visibility: hidden;`,c}if(e.tagName==="IFRAME"){let c=document.createElement("div");return c.textContent="",c.style.cssText=`width: ${e.offsetWidth}px; height: ${e.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(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="placeholder"){let c=e.cloneNode(!1);n.set(c,e),V(e,c,t,o,r);let s=document.createElement("div");return s.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),s=document.createElement("img");return s.src=c,s.width=e.width,s.height=e.height,s.style.display="inline-block",s.style.width=`${e.width}px`,s.style.height=`${e.height}px`,s}if(e.nodeType===Node.TEXT_NODE){if(e.parentElement?.shadowRoot){let c=e.parentElement.tagName.toLowerCase();if(customElements.get(c))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);n.set(a,e),e instanceof HTMLInputElement?(a.value=e.value,a.setAttribute("value",e.value),e.checked!==void 0&&(a.checked=e.checked,e.checked&&a.setAttribute("checked",""))):e instanceof HTMLTextAreaElement?(a.value=e.value,a.textContent=e.value):e instanceof HTMLSelectElement&&(a.value=e.value,Array.from(a.options).forEach(c=>{c.value===e.value?c.setAttribute("selected",""):c.removeAttribute("selected")})),V(e,a,t,o,r);let i=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let s=O(c,t,o,n,r);s&&i.appendChild(s)}),a.appendChild(i),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(l=>l.tagName!=="STYLE").map(l=>O(l,t,o,n)).filter(Boolean),s=document.createDocumentFragment();c.forEach(l=>s.appendChild(l)),a.appendChild(s)}return a}async function G(e,t,o,n=32,r="#000"){t=t.replace(/^['"]+|['"]+$/g,"");let a=window.devicePixelRatio||1,c=document.createElement("canvas").getContext("2d");c.font=o?`${o} ${n}px "${t}"`:`${n}px "${t}"`;let s=c.measureText(e),l=s.actualBoundingBoxAscent||n*.8,d=s.actualBoundingBoxDescent||n*.2,f=l+d,m=s.width,p=document.createElement("canvas");p.width=Math.ceil(m*a),p.height=Math.ceil(f*a);let h=p.getContext("2d");return h.scale(a,a),h.font=c.font,h.textAlign="left",h.textBaseline="alphabetic",h.fillStyle=r,h.fillText(e,0,l),p.toDataURL()}async function W({ignoreIconFonts:e=!0,preCached:t=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(r=>r.href),n="";for(let r of o)try{let i=await(await fetch(r.href)).text();if(e&&(B(r.href)||B(i)))continue;let c=/url\(([^)]+)\)/g,s=await Promise.all(Array.from(i.matchAll(c)).map(async d=>{let f=S(d[0]);if(!f)return null;let m=f;m.startsWith("http")||(m=new URL(m,r.href).href);try{m=encodeURI(m)}catch{console.warn("[snapdom] Failed to encode font URL:",m)}if(e&&B(m))return null;if(T.has(m))return{original:d[0],inlined:`url(${T.get(m)})`};try{let h=await(await fetch(m)).blob(),w=await new Promise(E=>{let v=new FileReader;v.onload=()=>E(v.result),v.readAsDataURL(h)});return T.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:",r.href)}if(n&&t){let r=document.createElement("style");r.setAttribute("data-snapdom","embedFonts"),r.textContent=n,document.head.appendChild(r)}return n}async function q(e,t,o,n,r,a=!1){if(!(e instanceof Element)||!(t instanceof Element))return;for(let s of["::before","::after"])try{let l=N(e,s);if(!l)continue;let d=l.getPropertyValue("content"),f=l.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",p=f&&f.startsWith("url(");if(m||p){let h=l.getPropertyValue("font-family"),w=parseInt(l.getPropertyValue("font-size"))||32,E=parseInt(l.getPropertyValue("font-weight"))||!1,v=l.getPropertyValue("color")||"#000",g=document.createElement("span");g.dataset.snapdomPseudo=s;let k=F(l),P=M(k,"span",r);o.set(g,P);let j=h&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(h),C=X(d);if(!a&&j&&C.length===1){let y=document.createElement("img");y.src=await G(C,h,E,w,v),y.style="display:block;width:100%;height:100%;object-fit:contain;",g.appendChild(y)}else if(C.startsWith("url(")){let y=S(C);if(y)try{let b=document.createElement("img"),se=await x(encodeURI(y));b.src=se,b.style="display:block;width:100%;height:100%;object-fit:contain;",g.appendChild(b)}catch(b){console.error(`[snapdom] Error in pseudo ${s} for`,e,b)}}else!j&&C&&C!=="none"&&(g.textContent=C);if(p&&f){let y=S(f);if(y)try{let b=await x(encodeURI(y));g.style.backgroundImage=`url(${b})`}catch(b){console.warn(`[snapdom] Failed to inline background-image for ${s}`,b)}}if(!(g.childNodes.length>0||g.textContent&&g.textContent.trim()!=="")&&!p)continue;s==="::before"?t.insertBefore(g,t.firstChild):t.appendChild(g)}}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,e,l)}let i=Array.from(e.children),c=Array.from(t.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,r,a)}async function Q(e,t=!1,o=!1){let n=new Map,r=new WeakMap,a=new Map,i;try{i=O(e,n,r,a,t)}catch(s){throw console.warn("deepClone failed:",s),s}try{await q(e,i,n,r,t,o)}catch(s){console.warn("inlinePseudoElements failed:",s)}let c="";if(t){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 a.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 p=document.createElement("div");for(p.style.transform=`translate(${-d}px, ${-f}px)`,p.style.willChange="transform",p.style.display="inline-block",p.style.width="100%";s.firstChild;)p.appendChild(s.firstChild);s.appendChild(p)}}return{clone:i,classCSS:c,styleCache:r}}async function Z(e){let t=Array.from(e.querySelectorAll("img")),o=async n=>{let r=n.src;try{let a=await x(r);n.src=a,n.width||(n.width=n.naturalWidth||100),n.height||(n.height=n.naturalHeight||100)}catch{let a=document.createElement("div");a.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;`,a.innerText="img",n.replaceWith(a)}};for(let n=0;n<t.length;n+=4){let r=t.slice(n,n+4).map(o);await Promise.allSettled(r)}}async function ee(e,t,o){let n=[[e,t]];for(;n.length;){let[r,a]=n.shift(),i=o.get(r)||N(r);o.has(r)||o.set(r,i);let c=i.getPropertyValue("background-image"),s=S(c);if(s)try{let f=encodeURI(s),m;$.has(f)?m=$.get(f):(m=await x(f),$.set(f,m)),a.style.backgroundImage=`url(${m})`}catch{a.style.backgroundImage="none"}let l=Array.from(r.children),d=Array.from(a.children);for(let f=0;f<Math.min(l.length,d.length);f++)n.push([l[f],d[f]])}}async function te(e,t={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:n=!1,fast:r=!0,scale:a=1}=t,i,c,s,l="",d="",f,m;if({clone:i,classCSS:c,styleCache:s}=await Q(e,o,n),await new Promise(h=>{L(async()=>{await Z(i),h()},{fast:r})}),await new Promise(h=>{L(async()=>{await ee(e,i,s),h()},{fast:r})}),n&&await new Promise(h=>{L(async()=>{l=await W({ignoreIconFonts:!n}),h()},{fast:r})}),o){let h=Y(i).sort(),w=h.join(",");A.has(w)?d=A.get(w):await new Promise(E=>{L(()=>{d=K(h),A.set(w,d),E()},{fast:r})})}await new Promise(h=>{L(()=>{let w=e.getBoundingClientRect(),E=Math.ceil(w.width),v=Math.ceil(w.height);i.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),i.style.transformOrigin="top left",a!==1&&D()&&(i.style.scale=`${a}`);let g="http://www.w3.org/2000/svg",k=document.createElementNS(g,"foreignObject");k.setAttribute("width","100%"),k.setAttribute("height","100%");let P=document.createElement("style");P.textContent=d+l+"svg{overflow:visible;}"+c,k.appendChild(P),k.appendChild(i);let C=new XMLSerializer().serializeToString(k);m=`<svg xmlns="${g}" width="${E}" height="${v}" viewBox="0 0 ${E} ${v}">`+C+"</svg>",f=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(m)}`,h()},{fast:r})});let p=document.getElementById("snapdom-sandbox");return p&&p.style.position==="absolute"&&p.remove(),f}async function ce(e,{dpr:t=1,scale:o=1}){let n=new Image;return n.src=e,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 ne(e,{dpr:t=1,scale:o=1}={}){let n=new Image;n.src=e,await n.decode();let r=document.createElement("canvas"),a=n.width*o,i=n.height*o;r.width=Math.ceil(a*t),r.height=Math.ceil(i*t);let c=r.getContext("2d");return c.scale(t,t),c.drawImage(n,0,0,a,i),r.style.width=`${a}px`,r.style.height=`${i}px`,r}async function oe(e){let t=decodeURIComponent(e.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})}async function ae(e,{dpr:t=1,scale:o=1},n){let r=await ne(e,{dpr:t,scale:o});if(!n)return r;let a=document.createElement("canvas");a.width=r.width,a.height=r.height;let i=a.getContext("2d");return i.fillStyle=n,i.fillRect(0,0,a.width,a.height),i.drawImage(r,0,0),a}async function H(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",quality:r},a="png"){let i=await ae(e,{dpr:t,scale:o},n),c=new Image;return c.src=i.toDataURL(`image/${a}`,r),await c.decode(),c.style.width=`${i.width/t}px`,c.style.height=`${i.height/t}px`,c}async function le(e,{dpr:t=1,scale:o=1,backgroundColor:n="#fff",format:r="png",filename:a="capture"}={}){if(r==="svg"){let m=await oe(e),p=URL.createObjectURL(m),h=document.createElement("a");h.href=p,h.download=`${a}.svg`,h.click(),URL.revokeObjectURL(p);return}let i=["jpg","jpeg","webp"].includes(r)?"#fff":void 0,s=await ae(e,{dpr:t,scale:o},n??i),l={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[r]||"image/png",d=s.toDataURL(l),f=document.createElement("a");f.href=d,f.download=`${a}.${r}`,f.click()}async function u(e,t={}){if(t={scale:1,...t},!e)throw new Error("Element cannot be null or undefined");return await u.capture(e,t)}u.capture=async(e,t={})=>{let o=await te(e,t),n=window.devicePixelRatio||1,r=t.scale||1;return{url:o,options:t,toRaw:()=>o,toImg:()=>ce(o,{dpr:n,scale:r}),toCanvas:()=>ne(o,{dpr:n,scale:r}),toBlob:()=>oe(o),toPng:a=>H(o,{dpr:n,scale:r,...a},"png"),toJpg:a=>H(o,{dpr:n,scale:r,...a},"jpeg"),toWebp:a=>H(o,{dpr:n,scale:r,...a},"webp"),download:({format:a="png",filename:i="capture",backgroundColor:c}={})=>le(o,{dpr:n,scale:r,backgroundColor:c,format:a,filename:i})}};u.toRaw=async(e,t)=>(await u.capture(e,t)).toRaw();u.toImg=async(e,t)=>(await u.capture(e,t)).toImg();u.toCanvas=async(e,t)=>(await u.capture(e,t)).toCanvas();u.toBlob=async(e,t)=>(await u.capture(e,t)).toBlob();u.toPng=async(e,t)=>(await u.capture(e,t)).toPng(t);u.toJpg=async(e,t)=>(await u.capture(e,t)).toJpg(t);u.toWebp=async(e,t)=>(await u.capture(e,t)).toWebp(t);u.download=async(e,t={})=>{let{format:o="png",filename:n="capture",backgroundColor:r,...a}=t;return await(await u.capture(e,a)).download({format:o,filename:n,backgroundColor:r})};async function de(e=document,t={}){let{embedFonts:o=!0,reset:n=!1,preWarm:r=!0}=t;if(n){I.clear(),$.clear(),T.clear(),A.clear(),U.clear();return}await document.fonts.ready,z();let a=[],i=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),i=Array.from(e.querySelectorAll("*")));let c=[];for(let s of a){let l=s.src;I.has(l)||c.push(x(l).then(d=>I.set(l,d)).catch(()=>{}))}for(let s of i){let l=getComputedStyle(s).backgroundImage,d=S(l);d&&!$.has(d)&&c.push(x(d).then(f=>$.set(d,f)).catch(()=>{}))}o&&await W({ignoreIconFonts:!o,preCached:!0}),await Promise.all(c)}export{de as preCache,u as snapdom};
package/dist/snapdom.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.2.2
4
+ * v.1.3.0
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 extractUrl(cssValue) {
190
- const m = cssValue.match(/url\(["']?([^"')]+)["']?\)/);
191
- return m ? m[1] : null;
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 = [
@@ -221,7 +227,7 @@ function fetchImage(src, timeout = 3e3) {
221
227
  canvas.width = image.width;
222
228
  canvas.height = image.height;
223
229
  const ctx = canvas.getContext("2d");
224
- ctx.drawImage(image, 0, 0);
230
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
225
231
  try {
226
232
  const dataURL = canvas.toDataURL("image/png");
227
233
  imageCache.set(src, dataURL);
@@ -309,6 +315,26 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress) {
309
315
  if (node.nodeType !== Node.ELEMENT_NODE) return node.cloneNode(true);
310
316
  const clone = node.cloneNode(false);
311
317
  nodeMap.set(clone, node);
318
+ if (node instanceof HTMLInputElement) {
319
+ clone.value = node.value;
320
+ clone.setAttribute("value", node.value);
321
+ if (node.checked !== void 0) {
322
+ clone.checked = node.checked;
323
+ if (node.checked) clone.setAttribute("checked", "");
324
+ }
325
+ } else if (node instanceof HTMLTextAreaElement) {
326
+ clone.value = node.value;
327
+ clone.textContent = node.value;
328
+ } else if (node instanceof HTMLSelectElement) {
329
+ clone.value = node.value;
330
+ Array.from(clone.options).forEach((opt) => {
331
+ if (opt.value === node.value) {
332
+ opt.setAttribute("selected", "");
333
+ } else {
334
+ opt.removeAttribute("selected");
335
+ }
336
+ });
337
+ }
312
338
  inlineAllStyles(node, clone, styleMap, styleCache, compress);
313
339
  const frag = document.createDocumentFragment();
314
340
  node.childNodes.forEach((child) => {
@@ -362,10 +388,17 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
362
388
  const urlRegex = /url\(([^)]+)\)/g;
363
389
  const inlinedCSS = await Promise.all(
364
390
  Array.from(cssText.matchAll(urlRegex)).map(async (match) => {
365
- let url = match[1].replace(/["']/g, "");
391
+ let rawUrl = extractURL(match[0]);
392
+ if (!rawUrl) return null;
393
+ let url = rawUrl;
366
394
  if (!url.startsWith("http")) {
367
395
  url = new URL(url, link.href).href;
368
396
  }
397
+ try {
398
+ url = encodeURI(url);
399
+ } catch (e) {
400
+ console.warn("[snapdom] Failed to encode font URL:", url);
401
+ }
369
402
  if (ignoreIconFonts && isIconFont(url)) {
370
403
  return null;
371
404
  }
@@ -429,19 +462,27 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
429
462
  const snapshot = snapshotComputedStyle(style);
430
463
  const key = getStyleKey(snapshot, "span", compress);
431
464
  styleMap.set(pseudoEl, key);
432
- const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(fontFamily);
465
+ const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(
466
+ fontFamily
467
+ );
433
468
  let cleanContent = parseContent(content);
434
469
  if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
435
470
  const imgEl = document.createElement("img");
436
- imgEl.src = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color);
471
+ imgEl.src = await iconToImage(
472
+ cleanContent,
473
+ fontFamily,
474
+ fontWeight,
475
+ fontSize,
476
+ color
477
+ );
437
478
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
438
479
  pseudoEl.appendChild(imgEl);
439
480
  } else if (cleanContent.startsWith("url(")) {
440
- const match = cleanContent.match(/url\(["']?([^"')]+)["']?\)/);
441
- if (match?.[1]) {
481
+ const rawUrl = extractURL(cleanContent);
482
+ if (rawUrl) {
442
483
  try {
443
484
  const imgEl = document.createElement("img");
444
- const dataUrl = await fetchImage(match[1]);
485
+ const dataUrl = await fetchImage(encodeURI(rawUrl));
445
486
  imgEl.src = dataUrl;
446
487
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
447
488
  pseudoEl.appendChild(imgEl);
@@ -449,9 +490,22 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
449
490
  console.error(`[snapdom] Error in pseudo ${pseudo} for`, source, e);
450
491
  }
451
492
  }
452
- } else if (cleanContent && cleanContent !== "none") {
493
+ } else if (!isIconFont2 && cleanContent && cleanContent !== "none") {
453
494
  pseudoEl.textContent = cleanContent;
454
495
  }
496
+ if (hasBg && bg) {
497
+ const rawUrl = extractURL(bg);
498
+ if (rawUrl) {
499
+ try {
500
+ const dataUrl = await fetchImage(encodeURI(rawUrl));
501
+ pseudoEl.style.backgroundImage = `url(${dataUrl})`;
502
+ } catch (e) {
503
+ console.warn(`[snapdom] Failed to inline background-image for ${pseudo}`, e);
504
+ }
505
+ }
506
+ }
507
+ const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent && pseudoEl.textContent.trim() !== "";
508
+ if (!hasContent2 && !hasBg) continue;
455
509
  if (pseudo === "::before") {
456
510
  clone.insertBefore(pseudoEl, clone.firstChild);
457
511
  } else {
@@ -463,11 +517,16 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
463
517
  }
464
518
  }
465
519
  const sChildren = Array.from(source.children);
466
- const cChildren = Array.from(clone.children).filter(
467
- (child) => !child.dataset.snapdomPseudo
468
- );
520
+ const cChildren = Array.from(clone.children).filter((child) => !child.dataset.snapdomPseudo);
469
521
  for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
470
- await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress, embedFonts);
522
+ await inlinePseudoElements(
523
+ sChildren[i],
524
+ cChildren[i],
525
+ styleMap,
526
+ styleCache,
527
+ compress,
528
+ embedFonts
529
+ );
471
530
  }
472
531
  }
473
532
 
@@ -559,22 +618,20 @@ async function inlineBackgroundImages(source, clone, styleCache) {
559
618
  const style = styleCache.get(srcNode) || getStyle(srcNode);
560
619
  if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
561
620
  const bg = style.getPropertyValue("background-image");
562
- if (bg && bg.includes("url(")) {
563
- const match = bg.match(/url\(["']?([^"')]+)["']?\)/);
564
- if (match?.[1]) {
565
- try {
566
- const bgUrl = match[1];
567
- let dataUrl;
568
- if (bgCache.has(bgUrl)) {
569
- dataUrl = bgCache.get(bgUrl);
570
- } else {
571
- dataUrl = await fetchImage(bgUrl);
572
- bgCache.set(bgUrl, dataUrl);
573
- }
574
- cloneNode.style.backgroundImage = `url(${dataUrl})`;
575
- } catch {
576
- cloneNode.style.backgroundImage = "none";
621
+ const rawUrl = extractURL(bg);
622
+ if (rawUrl) {
623
+ try {
624
+ let bgUrl = encodeURI(rawUrl);
625
+ let dataUrl;
626
+ if (bgCache.has(bgUrl)) {
627
+ dataUrl = bgCache.get(bgUrl);
628
+ } else {
629
+ dataUrl = await fetchImage(bgUrl);
630
+ bgCache.set(bgUrl, dataUrl);
577
631
  }
632
+ cloneNode.style.backgroundImage = `url(${dataUrl})`;
633
+ } catch {
634
+ cloneNode.style.backgroundImage = "none";
578
635
  }
579
636
  }
580
637
  const sChildren = Array.from(srcNode.children);
@@ -676,18 +733,20 @@ async function toImg(url, { dpr = 1, scale = 1 }) {
676
733
  }
677
734
  return img;
678
735
  }
679
- async function toCanvas(url, { dpr = 1, scale = 1 }) {
736
+ async function toCanvas(url, { dpr = 1, scale = 1 } = {}) {
680
737
  const img = new Image();
681
738
  img.src = url;
682
739
  await img.decode();
683
740
  const canvas = document.createElement("canvas");
684
- const width = img.width * scale * dpr;
685
- const height = img.height * scale * dpr;
686
- canvas.width = Math.ceil(width);
687
- canvas.height = Math.ceil(height);
741
+ const width = img.width * scale;
742
+ const height = img.height * scale;
743
+ canvas.width = Math.ceil(width * dpr);
744
+ canvas.height = Math.ceil(height * dpr);
688
745
  const ctx = canvas.getContext("2d");
689
- ctx.scale(scale * dpr, scale * dpr);
690
- ctx.drawImage(img, 0, 0);
746
+ ctx.scale(dpr, dpr);
747
+ ctx.drawImage(img, 0, 0, width, height);
748
+ canvas.style.width = `${width}px`;
749
+ canvas.style.height = `${height}px`;
691
750
  return canvas;
692
751
  }
693
752
  async function toBlob(url) {
@@ -811,7 +870,7 @@ async function preCache(root = document, options = {}) {
811
870
  }
812
871
  for (const el of allEls) {
813
872
  const bg = getComputedStyle(el).backgroundImage;
814
- const url = extractUrl(bg);
873
+ const url = extractURL(bg);
815
874
  if (url && !bgCache.has(url)) {
816
875
  promises.push(
817
876
  fetchImage(url).then((dataURL) => bgCache.set(url, dataURL)).catch(() => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zumer/snapdom",
3
- "version": "1.2.2",
4
- "description": "snapDOM captures DOM elements as images with exceptional speed and minimal overhead. Designed to avoid bottlenecks and long tasks.",
3
+ "version": "1.3.0",
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",
7
7
  "scripts": {
@@ -63,7 +63,7 @@
63
63
  "bugs": {
64
64
  "url": "https://github.com/zumerlab/snapdom/issues"
65
65
  },
66
- "homepage": "https://github.com/zumerlab/snapdom#readme",
66
+ "homepage": "https://zumerlab.github.io/snapdom/",
67
67
  "devDependencies": {
68
68
  "@vitest/browser": "^3.1.2",
69
69
  "playwright": "^1.52.0"