@zumer/snapdom 1.0.0 → 1.2.1

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
@@ -1,7 +1,7 @@
1
1
  # snapDOM
2
2
 
3
3
  <p align="center">
4
- <a href="http://zumerlab.github.io/orbit-docs">
4
+ <a href="http://zumerlab.github.io/snapdom">
5
5
  <img src="https://raw.githubusercontent.com/zumerlab/snapdom/main/docs/assets/hero.png" width="80%">
6
6
  </a>
7
7
  </p>
@@ -64,7 +64,7 @@ import { snapdom } from './snapdom.mjs';
64
64
 
65
65
  ## Basic usage
66
66
 
67
- ### Reusable result (recommended)
67
+ ### Reusable capture
68
68
 
69
69
  ```js
70
70
  const el = document.querySelector('#target');
package/dist/snapdom.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.0.0
4
+ * v.1.2.1
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -300,8 +300,6 @@
300
300
  return img;
301
301
  }
302
302
  if (node.nodeType === Node.TEXT_NODE) {
303
- const trimmed = node.textContent.trim();
304
- if (!trimmed) return null;
305
303
  if (node.parentElement?.shadowRoot) {
306
304
  const tag = node.parentElement.tagName.toLowerCase();
307
305
  if (customElements.get(tag)) return null;
@@ -330,17 +328,25 @@
330
328
  // src/modules/fonts.js
331
329
  async function iconToImage(unicodeChar, fontFamily, fontWeight, fontSize = 32, color = "#000") {
332
330
  fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, "");
333
- await document.fonts.ready;
334
- await document.fonts.load(`${fontSize}px "${fontFamily}"`);
331
+ const dpr = window.devicePixelRatio || 1;
332
+ const tempCanvas = document.createElement("canvas");
333
+ const tempCtx = tempCanvas.getContext("2d");
334
+ tempCtx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`;
335
+ const metrics = tempCtx.measureText(unicodeChar);
336
+ const ascent = metrics.actualBoundingBoxAscent || fontSize * 0.8;
337
+ const descent = metrics.actualBoundingBoxDescent || fontSize * 0.2;
338
+ const height = ascent + descent;
339
+ const width = metrics.width;
335
340
  const canvas = document.createElement("canvas");
336
- canvas.width = fontSize;
337
- canvas.height = fontSize;
341
+ canvas.width = Math.ceil(width * dpr);
342
+ canvas.height = Math.ceil(height * dpr);
338
343
  const ctx = canvas.getContext("2d");
339
- ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : ` ${fontSize}px "${fontFamily}"`;
340
- ctx.textAlign = "center";
341
- ctx.textBaseline = "middle";
344
+ ctx.scale(dpr, dpr);
345
+ ctx.font = tempCtx.font;
346
+ ctx.textAlign = "left";
347
+ ctx.textBaseline = "alphabetic";
342
348
  ctx.fillStyle = color;
343
- ctx.fillText(unicodeChar, canvas.width / 2, canvas.height / 2);
349
+ ctx.fillText(unicodeChar, 0, ascent);
344
350
  return canvas.toDataURL();
345
351
  }
346
352
  async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
@@ -351,7 +357,6 @@
351
357
  const res = await fetch(link.href);
352
358
  const cssText = await res.text();
353
359
  if (ignoreIconFonts && (isIconFont(link.href) || isIconFont(cssText))) {
354
- console.log("\u23ED\uFE0F Ignorando icon font CSS:", link.href);
355
360
  continue;
356
361
  }
357
362
  const urlRegex = /url\(([^)]+)\)/g;
@@ -362,7 +367,6 @@
362
367
  url = new URL(url, link.href).href;
363
368
  }
364
369
  if (ignoreIconFonts && isIconFont(url)) {
365
- console.log("\u23ED\uFE0F Ignorando icon font URL:", url);
366
370
  return null;
367
371
  }
368
372
  if (resourceCache.has(url)) {
@@ -379,7 +383,7 @@
379
383
  resourceCache.set(url, b64);
380
384
  return { original: match[0], inlined: `url(${b64})` };
381
385
  } catch (err) {
382
- console.warn("\u274C No pude fetch font", url);
386
+ console.warn("\u274C Failed to fetch font:", url);
383
387
  return null;
384
388
  }
385
389
  })
@@ -392,7 +396,7 @@
392
396
  }
393
397
  finalCSS += cssFinal + "\n";
394
398
  } catch (e) {
395
- console.warn("\u274C No pude fetch CSS", link.href);
399
+ console.warn("\u274C Failed to fetch CSS:", link.href);
396
400
  }
397
401
  }
398
402
  if (finalCSS && preCached) {
@@ -405,7 +409,7 @@
405
409
  }
406
410
 
407
411
  // src/modules/pseudo.js
408
- async function inlinePseudoElements(source, clone, styleMap, styleCache, compress) {
412
+ async function inlinePseudoElements(source, clone, styleMap, styleCache, compress, embedFonts = false) {
409
413
  if (!(source instanceof Element) || !(clone instanceof Element)) return;
410
414
  for (const pseudo of ["::before", "::after"]) {
411
415
  try {
@@ -427,7 +431,7 @@
427
431
  styleMap.set(pseudoEl, key);
428
432
  const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(fontFamily);
429
433
  let cleanContent = parseContent(content);
430
- if (isIconFont2 && cleanContent.length === 1) {
434
+ if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
431
435
  const imgEl = document.createElement("img");
432
436
  imgEl.src = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color);
433
437
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
@@ -463,15 +467,15 @@
463
467
  (child) => !child.dataset.snapdomPseudo
464
468
  );
465
469
  for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
466
- await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress);
470
+ await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress, embedFonts);
467
471
  }
468
472
  }
469
473
 
470
474
  // src/core/prepare.js
471
- async function prepareClone(element, compress = false) {
475
+ async function prepareClone(element, compress = false, embedFonts = false) {
472
476
  const styleMap = /* @__PURE__ */ new Map();
473
477
  const styleCache = /* @__PURE__ */ new WeakMap();
474
- const nodeMap = /* @__PURE__ */ new WeakMap();
478
+ const nodeMap = /* @__PURE__ */ new Map();
475
479
  let clone;
476
480
  try {
477
481
  clone = deepClone(element, styleMap, styleCache, nodeMap, compress);
@@ -480,19 +484,46 @@
480
484
  throw e;
481
485
  }
482
486
  try {
483
- await inlinePseudoElements(element, clone, styleMap, styleCache, compress);
487
+ await inlinePseudoElements(element, clone, styleMap, styleCache, compress, embedFonts);
484
488
  } catch (e) {
485
489
  console.warn("inlinePseudoElements failed:", e);
486
490
  }
487
- const keyToClass = generateCSSClasses(styleMap);
488
- const classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
489
- for (const [node, key] of styleMap.entries()) {
490
- if (node.tagName === "STYLE") continue;
491
- const className = keyToClass.get(key);
492
- if (className) node.classList.add(className);
493
- const bgImage = node.style?.backgroundImage;
494
- node.removeAttribute("style");
495
- if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
491
+ let classCSS = "";
492
+ if (compress) {
493
+ const keyToClass = generateCSSClasses(styleMap);
494
+ classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
495
+ for (const [node, key] of styleMap.entries()) {
496
+ if (node.tagName === "STYLE") continue;
497
+ const className = keyToClass.get(key);
498
+ if (className) node.classList.add(className);
499
+ const bgImage = node.style?.backgroundImage;
500
+ node.removeAttribute("style");
501
+ if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
502
+ }
503
+ } else {
504
+ for (const [node, key] of styleMap.entries()) {
505
+ if (node.tagName === "STYLE") continue;
506
+ node.setAttribute("style", key.replace(/;/g, "; "));
507
+ }
508
+ }
509
+ for (const [cloneNode, originalNode] of nodeMap.entries()) {
510
+ const scrollX = originalNode.scrollLeft;
511
+ const scrollY = originalNode.scrollTop;
512
+ const hasScroll = scrollX || scrollY;
513
+ if (hasScroll && cloneNode instanceof HTMLElement) {
514
+ cloneNode.style.overflow = "hidden";
515
+ cloneNode.style.scrollbarWidth = "none";
516
+ cloneNode.style.msOverflowStyle = "none";
517
+ const inner = document.createElement("div");
518
+ inner.style.transform = `translate(${-scrollX}px, ${-scrollY}px)`;
519
+ inner.style.willChange = "transform";
520
+ inner.style.display = "inline-block";
521
+ inner.style.width = "100%";
522
+ while (cloneNode.firstChild) {
523
+ inner.appendChild(cloneNode.firstChild);
524
+ }
525
+ cloneNode.appendChild(inner);
526
+ }
496
527
  }
497
528
  return { clone, classCSS, styleCache };
498
529
  }
@@ -563,7 +594,7 @@
563
594
  let baseCSS = "";
564
595
  let dataURL;
565
596
  let svgString;
566
- ({ clone, classCSS, styleCache } = await prepareClone(element, compress));
597
+ ({ clone, classCSS, styleCache } = await prepareClone(element, compress, embedFonts));
567
598
  await new Promise((resolve) => {
568
599
  idle(async () => {
569
600
  await inlineImages(clone);
@@ -579,7 +610,7 @@
579
610
  if (embedFonts) {
580
611
  await new Promise((resolve) => {
581
612
  idle(async () => {
582
- fontsCSS = await embedCustomFonts({ ignoreIconFonts: true });
613
+ fontsCSS = await embedCustomFonts({ ignoreIconFonts: !embedFonts });
583
614
  resolve();
584
615
  }, { fast });
585
616
  });
@@ -726,7 +757,7 @@
726
757
  toImg: () => toImg(url, { dpr, scale }),
727
758
  toCanvas: () => toCanvas(url, { dpr, scale }),
728
759
  toBlob: () => toBlob(url),
729
- toPng: () => toRasterImg(url, { dpr, scale }, "png"),
760
+ toPng: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "png"),
730
761
  toJpg: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "jpeg"),
731
762
  toWebp: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "webp"),
732
763
  download: ({ format = "png", filename = "capture", backgroundColor } = {}) => download(url, { dpr, scale, backgroundColor, format, filename })
@@ -789,8 +820,12 @@
789
820
  }
790
821
  }
791
822
  if (embedFonts) {
792
- await embedCustomFonts({ ignoreIconFonts: true, preCached: true });
823
+ await embedCustomFonts({ ignoreIconFonts: !embedFonts, preCached: true });
793
824
  }
794
825
  await Promise.all(promises);
795
826
  }
827
+
828
+ // src/index.browser.js
829
+ window.snapdom = snapdom;
830
+ window.preCache = preCache;
796
831
  })();
@@ -1,3 +1,3 @@
1
- (()=>{var S=new Map,E=new Map,$=new Map,k=new Map,T=new Map,R=new WeakMap;var rt=["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 rt)z(t)}function z(t){if(k.has(t))return k.get(t);if(new Set(["script","style","meta","link","noscript","template"]).has(t)){let s={};return k.set(t,s),s}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 s of a)r[s]=a.getPropertyValue(s);return o.removeChild(n),k.set(t,r),r}function U(t,e,o=!1){let n=[],a=z(e);for(let[r,s]of Object.entries(t))if(!o)s&&n.push(`${r}:${s}`);else{let c=a[r];s&&s!==c&&n.push(`${r}:${s}`)}return n.sort().join(";")}function H(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=k.get(n);if(!a)continue;let r=Object.entries(a).map(([s,c])=>`${s}:${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=R.get(t);if(o||(o=new Map,R.set(t,o)),!o.has(e)){let n=window.getComputedStyle(t,e);o.set(e,n)}return o.get(e)}function Y(t){let e=t.replace(/^['"]|['"]$/g,"");if(e.startsWith("\\"))try{return String.fromCharCode(parseInt(e.replace("\\",""),16))}catch{return e}return e}function X(t){let e=t.match(/url\(["']?([^"')]+)["']?\)/);return e?e[1]:null}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 C(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 s=document.createElement("canvas");s.width=r.width,s.height=r.height,s.getContext("2d").drawImage(r,0,0);try{let i=s.toDataURL("image/png");S.set(t,i),o(i)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(s){n(s)}},r.onerror=s=>{clearTimeout(a),n(new Error("Failed to load image: "+(s.message||"Unknown error")))},r.src=t})}function B(t){let e={};for(let o of t)e[o]=t.getPropertyValue(o);return e}function F(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function O(t,e,o,n,a){if(t.tagName==="STYLE")return;n.has(t)||n.set(t,A(t));let r=n.get(t),s=B(r),c=t.tagName?.toLowerCase()||"div",i=U(s,c,a);o.set(e,i)}function D(t,e,o,n,a){if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=t.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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),O(t,c,e,o,a);let i=document.createElement("div");return i.textContent=t.getAttribute("data-placeholder-text")||"",i.style.cssText="color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;",c.appendChild(i),c}if(t.tagName==="CANVAS"){let c=t.toDataURL(),i=document.createElement("img");return i.src=c,i.width=t.width,i.height=t.height,i.style.display="inline-block",i.style.width=`${t.width}px`,i.style.height=`${t.height}px`,i}if(t.nodeType===Node.TEXT_NODE){if(!t.textContent.trim())return null;if(t.parentElement?.shadowRoot){let i=t.parentElement.tagName.toLowerCase();if(customElements.get(i))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),O(t,r,e,o,a);let s=document.createDocumentFragment();if(t.childNodes.forEach(c=>{let i=D(c,e,o,n,a);i&&s.appendChild(i)}),r.appendChild(s),t.shadowRoot){let c=Array.from(t.shadowRoot.children).filter(d=>d.tagName!=="STYLE").map(d=>D(d,e,o,n)).filter(Boolean),i=document.createDocumentFragment();c.forEach(d=>i.appendChild(d)),r.appendChild(i)}return r}async function G(t,e,o,n=32,a="#000"){e=e.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${n}px "${e}"`);let r=document.createElement("canvas");r.width=n,r.height=n;let s=r.getContext("2d");return s.font=o?`${o} ${n}px "${e}"`:` ${n}px "${e}"`,s.textAlign="center",s.textBaseline="middle",s.fillStyle=a,s.fillText(t,r.width/2,r.height/2),r.toDataURL()}async function j({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 s=await(await fetch(a.href)).text();if(t&&(M(a.href)||M(s))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",a.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(s.matchAll(c)).map(async l=>{let m=l[1].replace(/["']/g,"");if(m.startsWith("http")||(m=new URL(m,a.href).href),t&&M(m))return console.log("\u23ED\uFE0F Ignorando icon font URL:",m),null;if($.has(m))return{original:l[0],inlined:`url(${$.get(m)})`};try{let h=await(await fetch(m)).blob(),f=await new Promise(u=>{let w=new FileReader;w.onload=()=>u(w.result),w.readAsDataURL(h)});return $.set(m,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",m),null}})),d=s;for(let l of i)l&&(d=d.replace(l.original,l.inlined));n+=d+`
3
- `}catch{console.warn("\u274C No pude 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 W(t,e,o,n,a){if(!(t instanceof Element)||!(e instanceof Element))return;for(let c of["::before","::after"])try{let i=A(t,c);if(!i)continue;let d=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",g=l&&l.startsWith("url(");if(m||g){let h=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,u=parseInt(i.getPropertyValue("font-weight"))||!1,w=i.getPropertyValue("color")||"#000",y=document.createElement("span");y.dataset.snapdomPseudo=c;let L=B(i),v=U(L,"span",a);o.set(y,v);let P=h&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(h),x=Y(d);if(P&&x.length===1){let b=document.createElement("img");b.src=await G(x,h,u,f,w),b.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let I=document.createElement("img"),q=await C(b[1]);I.src=q,I.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(I)}catch(I){console.error(`[snapdom] Error in pseudo ${c} for`,t,I)}}else x&&x!=="none"&&(y.textContent=x);c==="::before"?e.insertBefore(y,e.firstChild):e.appendChild(y)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,t,i)}let r=Array.from(t.children),s=Array.from(e.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(r.length,s.length);c++)await W(r[c],s[c],o,n,a)}async function Q(t,e=!1){let o=new Map,n=new WeakMap,a=new WeakMap,r;try{r=D(t,o,n,a,e)}catch(i){throw console.warn("deepClone failed:",i),i}try{await W(t,r,o,n,e)}catch(i){console.warn("inlinePseudoElements failed:",i)}let s=J(o),c=Array.from(s.entries()).map(([i,d])=>`.${d}{${i}}`).join("");for(let[i,d]of o.entries()){if(i.tagName==="STYLE")continue;let l=s.get(d);l&&i.classList.add(l);let m=i.style?.backgroundImage;i.removeAttribute("style"),m&&m!=="none"&&(i.style.backgroundImage=m)}return{clone:r,classCSS:c,styleCache:n}}async function Z(t){let e=Array.from(t.querySelectorAll("img")),o=async n=>{let a=n.src;try{let r=await C(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(),s=o.get(a)||A(a);o.has(a)||o.set(a,s);let c=s.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let m=l[1],g;E.has(m)?g=E.get(m):(g=await C(m),E.set(m,g)),r.style.backgroundImage=`url(${g})`}catch{r.style.backgroundImage="none"}}let i=Array.from(a.children),d=Array.from(r.children);for(let l=0;l<Math.min(i.length,d.length);l++)n.push([i[l],d[l]])}}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,s,c,i,d="",l="",m,g;if({clone:s,classCSS:c,styleCache:i}=await Q(t,o),await new Promise(f=>{N(async()=>{await Z(s),f()},{fast:a})}),await new Promise(f=>{N(async()=>{await tt(t,s,i),f()},{fast:a})}),n&&await new Promise(f=>{N(async()=>{d=await j({ignoreIconFonts:!0}),f()},{fast:a})}),o){let f=H(s).sort(),u=f.join(",");T.has(u)?l=T.get(u):await new Promise(w=>{N(()=>{l=K(f),T.set(u,l),w()},{fast:a})})}await new Promise(f=>{N(()=>{let u=t.getBoundingClientRect(),w=Math.ceil(u.width),y=Math.ceil(u.height);s.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),s.style.transformOrigin="top left",r!==1&&F()&&(s.style.scale=`${r}`);let L="http://www.w3.org/2000/svg",v=document.createElementNS(L,"foreignObject");v.setAttribute("width","100%"),v.setAttribute("height","100%");let P=document.createElement("style");P.textContent=l+d+"svg{overflow:visible;}"+c,v.appendChild(P),v.appendChild(s);let b=new XMLSerializer().serializeToString(v);g=`<svg xmlns="${L}" width="${w}" height="${y}" viewBox="0 0 ${w} ${y}">`+b+"</svg>",m=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(g)}`,f()},{fast:a})});let h=document.getElementById("snapdom-sandbox");return h&&h.style.position==="absolute"&&h.remove(),m}async function st(t,{dpr:e=1,scale:o=1}){let n=new Image;return n.src=t,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 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,s=n.height*o*e;a.width=Math.ceil(r),a.height=Math.ceil(s);let c=a.getContext("2d");return c.scale(o*e,o*e),c.drawImage(n,0,0),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 s=r.getContext("2d");return s.fillStyle=n,s.fillRect(0,0,r.width,r.height),s.drawImage(a,0,0),r}async function V(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let s=await at(t,{dpr:e,scale:o},n),c=new Image;return c.src=s.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${s.width/e}px`,c.style.height=`${s.height/e}px`,c}async function it(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let g=await ot(t),h=URL.createObjectURL(g),f=document.createElement("a");f.href=h,f.download=`${r}.svg`,f.click(),URL.revokeObjectURL(h);return}let s=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,i=await at(t,{dpr:e,scale:o},n??s),d={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[a]||"image/png",l=i.toDataURL(d),m=document.createElement("a");m.href=l,m.download=`${r}.${a}`,m.click()}async function p(t,e={}){if(e={scale:1,...e},!t)throw new Error("Element cannot be null or undefined");return await p.capture(t,e)}p.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:()=>st(o,{dpr:n,scale:a}),toCanvas:()=>nt(o,{dpr:n,scale:a}),toBlob:()=>ot(o),toPng:()=>V(o,{dpr:n,scale:a},"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:s="capture",backgroundColor:c}={})=>it(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:s})}};p.toRaw=async(t,e)=>(await p.capture(t,e)).toRaw();p.toImg=async(t,e)=>(await p.capture(t,e)).toImg();p.toCanvas=async(t,e)=>(await p.capture(t,e)).toCanvas();p.toBlob=async(t,e)=>(await p.capture(t,e)).toBlob();p.toPng=async(t,e)=>(await p.capture(t,e)).toPng(e);p.toJpg=async(t,e)=>(await p.capture(t,e)).toJpg(e);p.toWebp=async(t,e)=>(await p.capture(t,e)).toWebp(e);p.download=async(t,e={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=e;return await(await p.capture(t,r)).download({format:o,filename:n,backgroundColor:a})};async function ct(t=document,e={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=e;if(n){S.clear(),E.clear(),$.clear(),T.clear(),R.clear();return}await document.fonts.ready,_();let r=[],s=[];t?.querySelectorAll&&(r=Array.from(t.querySelectorAll("img[src]")),s=Array.from(t.querySelectorAll("*")));let c=[];for(let i of r){let d=i.src;S.has(d)||c.push(C(d).then(l=>S.set(d,l)).catch(()=>{}))}for(let i of s){let d=getComputedStyle(i).backgroundImage,l=X(d);l&&!E.has(l)&&c.push(C(l).then(m=>E.set(l,m)).catch(()=>{}))}o&&await j({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c)}})();
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,3 +1,3 @@
1
- var S=new Map,E=new Map,$=new Map,k=new Map,T=new Map,R=new WeakMap;var rt=["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 rt)z(t)}function z(t){if(k.has(t))return k.get(t);if(new Set(["script","style","meta","link","noscript","template"]).has(t)){let s={};return k.set(t,s),s}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 s of a)r[s]=a.getPropertyValue(s);return o.removeChild(n),k.set(t,r),r}function U(t,e,o=!1){let n=[],a=z(e);for(let[r,s]of Object.entries(t))if(!o)s&&n.push(`${r}:${s}`);else{let c=a[r];s&&s!==c&&n.push(`${r}:${s}`)}return n.sort().join(";")}function H(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=k.get(n);if(!a)continue;let r=Object.entries(a).map(([s,c])=>`${s}:${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=R.get(t);if(o||(o=new Map,R.set(t,o)),!o.has(e)){let n=window.getComputedStyle(t,e);o.set(e,n)}return o.get(e)}function Y(t){let e=t.replace(/^['"]|['"]$/g,"");if(e.startsWith("\\"))try{return String.fromCharCode(parseInt(e.replace("\\",""),16))}catch{return e}return e}function X(t){let e=t.match(/url\(["']?([^"')]+)["']?\)/);return e?e[1]:null}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 C(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 s=document.createElement("canvas");s.width=r.width,s.height=r.height,s.getContext("2d").drawImage(r,0,0);try{let i=s.toDataURL("image/png");S.set(t,i),o(i)}catch{n(new Error("CORS restrictions prevented image capture"))}}catch(s){n(s)}},r.onerror=s=>{clearTimeout(a),n(new Error("Failed to load image: "+(s.message||"Unknown error")))},r.src=t})}function B(t){let e={};for(let o of t)e[o]=t.getPropertyValue(o);return e}function F(){return/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}function O(t,e,o,n,a){if(t.tagName==="STYLE")return;n.has(t)||n.set(t,A(t));let r=n.get(t),s=B(r),c=t.tagName?.toLowerCase()||"div",i=U(s,c,a);o.set(e,i)}function D(t,e,o,n,a){if(t.nodeType===Node.ELEMENT_NODE&&t.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=t.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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),O(t,c,e,o,a);let i=document.createElement("div");return i.textContent=t.getAttribute("data-placeholder-text")||"",i.style.cssText="color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;",c.appendChild(i),c}if(t.tagName==="CANVAS"){let c=t.toDataURL(),i=document.createElement("img");return i.src=c,i.width=t.width,i.height=t.height,i.style.display="inline-block",i.style.width=`${t.width}px`,i.style.height=`${t.height}px`,i}if(t.nodeType===Node.TEXT_NODE){if(!t.textContent.trim())return null;if(t.parentElement?.shadowRoot){let i=t.parentElement.tagName.toLowerCase();if(customElements.get(i))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),O(t,r,e,o,a);let s=document.createDocumentFragment();if(t.childNodes.forEach(c=>{let i=D(c,e,o,n,a);i&&s.appendChild(i)}),r.appendChild(s),t.shadowRoot){let c=Array.from(t.shadowRoot.children).filter(d=>d.tagName!=="STYLE").map(d=>D(d,e,o,n)).filter(Boolean),i=document.createDocumentFragment();c.forEach(d=>i.appendChild(d)),r.appendChild(i)}return r}async function G(t,e,o,n=32,a="#000"){e=e.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${n}px "${e}"`);let r=document.createElement("canvas");r.width=n,r.height=n;let s=r.getContext("2d");return s.font=o?`${o} ${n}px "${e}"`:` ${n}px "${e}"`,s.textAlign="center",s.textBaseline="middle",s.fillStyle=a,s.fillText(t,r.width/2,r.height/2),r.toDataURL()}async function j({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 s=await(await fetch(a.href)).text();if(t&&(M(a.href)||M(s))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",a.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(s.matchAll(c)).map(async l=>{let m=l[1].replace(/["']/g,"");if(m.startsWith("http")||(m=new URL(m,a.href).href),t&&M(m))return console.log("\u23ED\uFE0F Ignorando icon font URL:",m),null;if($.has(m))return{original:l[0],inlined:`url(${$.get(m)})`};try{let h=await(await fetch(m)).blob(),f=await new Promise(u=>{let w=new FileReader;w.onload=()=>u(w.result),w.readAsDataURL(h)});return $.set(m,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",m),null}})),d=s;for(let l of i)l&&(d=d.replace(l.original,l.inlined));n+=d+`
3
- `}catch{console.warn("\u274C No pude 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 W(t,e,o,n,a){if(!(t instanceof Element)||!(e instanceof Element))return;for(let c of["::before","::after"])try{let i=A(t,c);if(!i)continue;let d=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),m=d&&d!=="none"&&d!=='""'&&d!=="''",g=l&&l.startsWith("url(");if(m||g){let h=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,u=parseInt(i.getPropertyValue("font-weight"))||!1,w=i.getPropertyValue("color")||"#000",y=document.createElement("span");y.dataset.snapdomPseudo=c;let L=B(i),v=U(L,"span",a);o.set(y,v);let P=h&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(h),x=Y(d);if(P&&x.length===1){let b=document.createElement("img");b.src=await G(x,h,u,f,w),b.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let I=document.createElement("img"),q=await C(b[1]);I.src=q,I.style="display:block;width:100%;height:100%;object-fit:contain;",y.appendChild(I)}catch(I){console.error(`[snapdom] Error in pseudo ${c} for`,t,I)}}else x&&x!=="none"&&(y.textContent=x);c==="::before"?e.insertBefore(y,e.firstChild):e.appendChild(y)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,t,i)}let r=Array.from(t.children),s=Array.from(e.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(r.length,s.length);c++)await W(r[c],s[c],o,n,a)}async function Q(t,e=!1){let o=new Map,n=new WeakMap,a=new WeakMap,r;try{r=D(t,o,n,a,e)}catch(i){throw console.warn("deepClone failed:",i),i}try{await W(t,r,o,n,e)}catch(i){console.warn("inlinePseudoElements failed:",i)}let s=J(o),c=Array.from(s.entries()).map(([i,d])=>`.${d}{${i}}`).join("");for(let[i,d]of o.entries()){if(i.tagName==="STYLE")continue;let l=s.get(d);l&&i.classList.add(l);let m=i.style?.backgroundImage;i.removeAttribute("style"),m&&m!=="none"&&(i.style.backgroundImage=m)}return{clone:r,classCSS:c,styleCache:n}}async function Z(t){let e=Array.from(t.querySelectorAll("img")),o=async n=>{let a=n.src;try{let r=await C(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(),s=o.get(a)||A(a);o.has(a)||o.set(a,s);let c=s.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let m=l[1],g;E.has(m)?g=E.get(m):(g=await C(m),E.set(m,g)),r.style.backgroundImage=`url(${g})`}catch{r.style.backgroundImage="none"}}let i=Array.from(a.children),d=Array.from(r.children);for(let l=0;l<Math.min(i.length,d.length);l++)n.push([i[l],d[l]])}}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,s,c,i,d="",l="",m,g;if({clone:s,classCSS:c,styleCache:i}=await Q(t,o),await new Promise(f=>{N(async()=>{await Z(s),f()},{fast:a})}),await new Promise(f=>{N(async()=>{await tt(t,s,i),f()},{fast:a})}),n&&await new Promise(f=>{N(async()=>{d=await j({ignoreIconFonts:!0}),f()},{fast:a})}),o){let f=H(s).sort(),u=f.join(",");T.has(u)?l=T.get(u):await new Promise(w=>{N(()=>{l=K(f),T.set(u,l),w()},{fast:a})})}await new Promise(f=>{N(()=>{let u=t.getBoundingClientRect(),w=Math.ceil(u.width),y=Math.ceil(u.height);s.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),s.style.transformOrigin="top left",r!==1&&F()&&(s.style.scale=`${r}`);let L="http://www.w3.org/2000/svg",v=document.createElementNS(L,"foreignObject");v.setAttribute("width","100%"),v.setAttribute("height","100%");let P=document.createElement("style");P.textContent=l+d+"svg{overflow:visible;}"+c,v.appendChild(P),v.appendChild(s);let b=new XMLSerializer().serializeToString(v);g=`<svg xmlns="${L}" width="${w}" height="${y}" viewBox="0 0 ${w} ${y}">`+b+"</svg>",m=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(g)}`,f()},{fast:a})});let h=document.getElementById("snapdom-sandbox");return h&&h.style.position==="absolute"&&h.remove(),m}async function st(t,{dpr:e=1,scale:o=1}){let n=new Image;return n.src=t,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 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,s=n.height*o*e;a.width=Math.ceil(r),a.height=Math.ceil(s);let c=a.getContext("2d");return c.scale(o*e,o*e),c.drawImage(n,0,0),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 s=r.getContext("2d");return s.fillStyle=n,s.fillRect(0,0,r.width,r.height),s.drawImage(a,0,0),r}async function V(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",quality:a},r="png"){let s=await at(t,{dpr:e,scale:o},n),c=new Image;return c.src=s.toDataURL(`image/${r}`,a),await c.decode(),c.style.width=`${s.width/e}px`,c.style.height=`${s.height/e}px`,c}async function it(t,{dpr:e=1,scale:o=1,backgroundColor:n="#fff",format:a="png",filename:r="capture"}={}){if(a==="svg"){let g=await ot(t),h=URL.createObjectURL(g),f=document.createElement("a");f.href=h,f.download=`${r}.svg`,f.click(),URL.revokeObjectURL(h);return}let s=["jpg","jpeg","webp"].includes(a)?"#fff":void 0,i=await at(t,{dpr:e,scale:o},n??s),d={jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",webp:"image/webp"}[a]||"image/png",l=i.toDataURL(d),m=document.createElement("a");m.href=l,m.download=`${r}.${a}`,m.click()}async function p(t,e={}){if(e={scale:1,...e},!t)throw new Error("Element cannot be null or undefined");return await p.capture(t,e)}p.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:()=>st(o,{dpr:n,scale:a}),toCanvas:()=>nt(o,{dpr:n,scale:a}),toBlob:()=>ot(o),toPng:()=>V(o,{dpr:n,scale:a},"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:s="capture",backgroundColor:c}={})=>it(o,{dpr:n,scale:a,backgroundColor:c,format:r,filename:s})}};p.toRaw=async(t,e)=>(await p.capture(t,e)).toRaw();p.toImg=async(t,e)=>(await p.capture(t,e)).toImg();p.toCanvas=async(t,e)=>(await p.capture(t,e)).toCanvas();p.toBlob=async(t,e)=>(await p.capture(t,e)).toBlob();p.toPng=async(t,e)=>(await p.capture(t,e)).toPng(e);p.toJpg=async(t,e)=>(await p.capture(t,e)).toJpg(e);p.toWebp=async(t,e)=>(await p.capture(t,e)).toWebp(e);p.download=async(t,e={})=>{let{format:o="png",filename:n="capture",backgroundColor:a,...r}=e;return await(await p.capture(t,r)).download({format:o,filename:n,backgroundColor:a})};async function ct(t=document,e={}){let{embedFonts:o=!0,reset:n=!1,preWarm:a=!0}=e;if(n){S.clear(),E.clear(),$.clear(),T.clear(),R.clear();return}await document.fonts.ready,_();let r=[],s=[];t?.querySelectorAll&&(r=Array.from(t.querySelectorAll("img[src]")),s=Array.from(t.querySelectorAll("*")));let c=[];for(let i of r){let d=i.src;S.has(d)||c.push(C(d).then(l=>S.set(d,l)).catch(()=>{}))}for(let i of s){let d=getComputedStyle(i).backgroundImage,l=X(d);l&&!E.has(l)&&c.push(C(l).then(m=>E.set(l,m)).catch(()=>{}))}o&&await j({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c)}export{ct as preCache,p as snapdom};
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};
package/dist/snapdom.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.0.0
4
+ * v.1.2.1
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -300,8 +300,6 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress) {
300
300
  return img;
301
301
  }
302
302
  if (node.nodeType === Node.TEXT_NODE) {
303
- const trimmed = node.textContent.trim();
304
- if (!trimmed) return null;
305
303
  if (node.parentElement?.shadowRoot) {
306
304
  const tag = node.parentElement.tagName.toLowerCase();
307
305
  if (customElements.get(tag)) return null;
@@ -330,17 +328,25 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress) {
330
328
  // src/modules/fonts.js
331
329
  async function iconToImage(unicodeChar, fontFamily, fontWeight, fontSize = 32, color = "#000") {
332
330
  fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, "");
333
- await document.fonts.ready;
334
- await document.fonts.load(`${fontSize}px "${fontFamily}"`);
331
+ const dpr = window.devicePixelRatio || 1;
332
+ const tempCanvas = document.createElement("canvas");
333
+ const tempCtx = tempCanvas.getContext("2d");
334
+ tempCtx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`;
335
+ const metrics = tempCtx.measureText(unicodeChar);
336
+ const ascent = metrics.actualBoundingBoxAscent || fontSize * 0.8;
337
+ const descent = metrics.actualBoundingBoxDescent || fontSize * 0.2;
338
+ const height = ascent + descent;
339
+ const width = metrics.width;
335
340
  const canvas = document.createElement("canvas");
336
- canvas.width = fontSize;
337
- canvas.height = fontSize;
341
+ canvas.width = Math.ceil(width * dpr);
342
+ canvas.height = Math.ceil(height * dpr);
338
343
  const ctx = canvas.getContext("2d");
339
- ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : ` ${fontSize}px "${fontFamily}"`;
340
- ctx.textAlign = "center";
341
- ctx.textBaseline = "middle";
344
+ ctx.scale(dpr, dpr);
345
+ ctx.font = tempCtx.font;
346
+ ctx.textAlign = "left";
347
+ ctx.textBaseline = "alphabetic";
342
348
  ctx.fillStyle = color;
343
- ctx.fillText(unicodeChar, canvas.width / 2, canvas.height / 2);
349
+ ctx.fillText(unicodeChar, 0, ascent);
344
350
  return canvas.toDataURL();
345
351
  }
346
352
  async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
@@ -351,7 +357,6 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
351
357
  const res = await fetch(link.href);
352
358
  const cssText = await res.text();
353
359
  if (ignoreIconFonts && (isIconFont(link.href) || isIconFont(cssText))) {
354
- console.log("\u23ED\uFE0F Ignorando icon font CSS:", link.href);
355
360
  continue;
356
361
  }
357
362
  const urlRegex = /url\(([^)]+)\)/g;
@@ -362,7 +367,6 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
362
367
  url = new URL(url, link.href).href;
363
368
  }
364
369
  if (ignoreIconFonts && isIconFont(url)) {
365
- console.log("\u23ED\uFE0F Ignorando icon font URL:", url);
366
370
  return null;
367
371
  }
368
372
  if (resourceCache.has(url)) {
@@ -379,7 +383,7 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
379
383
  resourceCache.set(url, b64);
380
384
  return { original: match[0], inlined: `url(${b64})` };
381
385
  } catch (err) {
382
- console.warn("\u274C No pude fetch font", url);
386
+ console.warn("\u274C Failed to fetch font:", url);
383
387
  return null;
384
388
  }
385
389
  })
@@ -392,7 +396,7 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
392
396
  }
393
397
  finalCSS += cssFinal + "\n";
394
398
  } catch (e) {
395
- console.warn("\u274C No pude fetch CSS", link.href);
399
+ console.warn("\u274C Failed to fetch CSS:", link.href);
396
400
  }
397
401
  }
398
402
  if (finalCSS && preCached) {
@@ -405,7 +409,7 @@ async function embedCustomFonts({ ignoreIconFonts = true, preCached = false }) {
405
409
  }
406
410
 
407
411
  // src/modules/pseudo.js
408
- async function inlinePseudoElements(source, clone, styleMap, styleCache, compress) {
412
+ async function inlinePseudoElements(source, clone, styleMap, styleCache, compress, embedFonts = false) {
409
413
  if (!(source instanceof Element) || !(clone instanceof Element)) return;
410
414
  for (const pseudo of ["::before", "::after"]) {
411
415
  try {
@@ -427,7 +431,7 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
427
431
  styleMap.set(pseudoEl, key);
428
432
  const isIconFont2 = fontFamily && /font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(fontFamily);
429
433
  let cleanContent = parseContent(content);
430
- if (isIconFont2 && cleanContent.length === 1) {
434
+ if (!embedFonts && isIconFont2 && cleanContent.length === 1) {
431
435
  const imgEl = document.createElement("img");
432
436
  imgEl.src = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color);
433
437
  imgEl.style = "display:block;width:100%;height:100%;object-fit:contain;";
@@ -463,15 +467,15 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
463
467
  (child) => !child.dataset.snapdomPseudo
464
468
  );
465
469
  for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) {
466
- await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress);
470
+ await inlinePseudoElements(sChildren[i], cChildren[i], styleMap, styleCache, compress, embedFonts);
467
471
  }
468
472
  }
469
473
 
470
474
  // src/core/prepare.js
471
- async function prepareClone(element, compress = false) {
475
+ async function prepareClone(element, compress = false, embedFonts = false) {
472
476
  const styleMap = /* @__PURE__ */ new Map();
473
477
  const styleCache = /* @__PURE__ */ new WeakMap();
474
- const nodeMap = /* @__PURE__ */ new WeakMap();
478
+ const nodeMap = /* @__PURE__ */ new Map();
475
479
  let clone;
476
480
  try {
477
481
  clone = deepClone(element, styleMap, styleCache, nodeMap, compress);
@@ -480,19 +484,46 @@ async function prepareClone(element, compress = false) {
480
484
  throw e;
481
485
  }
482
486
  try {
483
- await inlinePseudoElements(element, clone, styleMap, styleCache, compress);
487
+ await inlinePseudoElements(element, clone, styleMap, styleCache, compress, embedFonts);
484
488
  } catch (e) {
485
489
  console.warn("inlinePseudoElements failed:", e);
486
490
  }
487
- const keyToClass = generateCSSClasses(styleMap);
488
- const classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
489
- for (const [node, key] of styleMap.entries()) {
490
- if (node.tagName === "STYLE") continue;
491
- const className = keyToClass.get(key);
492
- if (className) node.classList.add(className);
493
- const bgImage = node.style?.backgroundImage;
494
- node.removeAttribute("style");
495
- if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
491
+ let classCSS = "";
492
+ if (compress) {
493
+ const keyToClass = generateCSSClasses(styleMap);
494
+ classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
495
+ for (const [node, key] of styleMap.entries()) {
496
+ if (node.tagName === "STYLE") continue;
497
+ const className = keyToClass.get(key);
498
+ if (className) node.classList.add(className);
499
+ const bgImage = node.style?.backgroundImage;
500
+ node.removeAttribute("style");
501
+ if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
502
+ }
503
+ } else {
504
+ for (const [node, key] of styleMap.entries()) {
505
+ if (node.tagName === "STYLE") continue;
506
+ node.setAttribute("style", key.replace(/;/g, "; "));
507
+ }
508
+ }
509
+ for (const [cloneNode, originalNode] of nodeMap.entries()) {
510
+ const scrollX = originalNode.scrollLeft;
511
+ const scrollY = originalNode.scrollTop;
512
+ const hasScroll = scrollX || scrollY;
513
+ if (hasScroll && cloneNode instanceof HTMLElement) {
514
+ cloneNode.style.overflow = "hidden";
515
+ cloneNode.style.scrollbarWidth = "none";
516
+ cloneNode.style.msOverflowStyle = "none";
517
+ const inner = document.createElement("div");
518
+ inner.style.transform = `translate(${-scrollX}px, ${-scrollY}px)`;
519
+ inner.style.willChange = "transform";
520
+ inner.style.display = "inline-block";
521
+ inner.style.width = "100%";
522
+ while (cloneNode.firstChild) {
523
+ inner.appendChild(cloneNode.firstChild);
524
+ }
525
+ cloneNode.appendChild(inner);
526
+ }
496
527
  }
497
528
  return { clone, classCSS, styleCache };
498
529
  }
@@ -563,7 +594,7 @@ async function captureDOM(element, options = {}) {
563
594
  let baseCSS = "";
564
595
  let dataURL;
565
596
  let svgString;
566
- ({ clone, classCSS, styleCache } = await prepareClone(element, compress));
597
+ ({ clone, classCSS, styleCache } = await prepareClone(element, compress, embedFonts));
567
598
  await new Promise((resolve) => {
568
599
  idle(async () => {
569
600
  await inlineImages(clone);
@@ -579,7 +610,7 @@ async function captureDOM(element, options = {}) {
579
610
  if (embedFonts) {
580
611
  await new Promise((resolve) => {
581
612
  idle(async () => {
582
- fontsCSS = await embedCustomFonts({ ignoreIconFonts: true });
613
+ fontsCSS = await embedCustomFonts({ ignoreIconFonts: !embedFonts });
583
614
  resolve();
584
615
  }, { fast });
585
616
  });
@@ -726,7 +757,7 @@ snapdom.capture = async (el, options = {}) => {
726
757
  toImg: () => toImg(url, { dpr, scale }),
727
758
  toCanvas: () => toCanvas(url, { dpr, scale }),
728
759
  toBlob: () => toBlob(url),
729
- toPng: () => toRasterImg(url, { dpr, scale }, "png"),
760
+ toPng: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "png"),
730
761
  toJpg: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "jpeg"),
731
762
  toWebp: (options2) => toRasterImg(url, { dpr, scale, ...options2 }, "webp"),
732
763
  download: ({ format = "png", filename = "capture", backgroundColor } = {}) => download(url, { dpr, scale, backgroundColor, format, filename })
@@ -789,7 +820,7 @@ async function preCache(root = document, options = {}) {
789
820
  }
790
821
  }
791
822
  if (embedFonts) {
792
- await embedCustomFonts({ ignoreIconFonts: true, preCached: true });
823
+ await embedCustomFonts({ ignoreIconFonts: !embedFonts, preCached: true });
793
824
  }
794
825
  await Promise.all(promises);
795
826
  }
package/package.json CHANGED
@@ -1,22 +1,17 @@
1
1
  {
2
2
  "name": "@zumer/snapdom",
3
- "version": "1.0.0",
3
+ "version": "1.2.1",
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",
7
- "exports": {
8
- ".": {
9
- "import": "./dist/snapdom.mjs",
10
- "require": "./dist/snapdom.js"
11
- }
12
- },
13
7
  "scripts": {
14
8
  "test": "npx vitest run --browser.headless --reporter=verbose",
15
9
  "test:benchmark": "npx vitest bench --browser.headless --watch=false",
16
- "compile-browser": "npx @zumerbox/build -n snapdom -j src/index.js",
10
+ "compile-browser": "npx @zumerbox/build -n snapdom -j src/index.browser.js",
17
11
  "compile-esm": "npx @zumerbox/build -n snapdom -j src/index.js -p neutral -x",
18
12
  "compile": "npm run compile-browser && npm run compile-esm",
19
13
  "build": "npm run compile && npm pack",
14
+ "bump:dry": "npx @zumerbox/bump -d",
20
15
  "bump": "npx @zumerbox/bump && npx @zumerbox/changelog",
21
16
  "prebuild": "git add CHANGELOG.md && git commit -m \"Bumped version\" && git push --follow-tags"
22
17
  },
@@ -24,11 +19,19 @@
24
19
  "type": "git",
25
20
  "url": "git+https://github.com/zumerlab/snapdom.git"
26
21
  },
22
+ "types": "types/snapdom.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "import": "./dist/snapdom.mjs",
26
+ "require": "./dist/snapdom.js"
27
+ }
28
+ },
27
29
  "files": [
28
30
  "dist/snapdom.js",
29
31
  "dist/snapdom.min.js",
30
32
  "dist/snapdom.min.mjs",
31
33
  "dist/snapdom.mjs",
34
+ "types/snapdom.d.ts",
32
35
  "README.md"
33
36
  ],
34
37
  "keywords": [
@@ -0,0 +1,56 @@
1
+ declare module "@zumer/snapdom" {
2
+ export interface SnapOptions {
3
+ compress?: boolean;
4
+ embedFonts?: boolean;
5
+ fast?: boolean;
6
+ scale?: number;
7
+ backgroundColor?: string;
8
+ format?: "png" | "jpeg" | "jpg" | "webp" | "svg";
9
+ filename?: string;
10
+ dpr?: number;
11
+ quality?: number;
12
+ }
13
+
14
+ export interface SnapResult {
15
+ url: string;
16
+ options: SnapOptions;
17
+ toRaw(): string;
18
+ toImg(): Promise<HTMLImageElement>;
19
+ toCanvas(): Promise<HTMLCanvasElement>;
20
+ toBlob(): Promise<Blob>;
21
+ toPng(options?: SnapOptions): Promise<HTMLImageElement>;
22
+ toJpg(options?: SnapOptions): Promise<HTMLImageElement>;
23
+ toWebp(options?: SnapOptions): Promise<HTMLImageElement>;
24
+ download(options?: SnapOptions): Promise<void>;
25
+ }
26
+
27
+ /**
28
+ * Captura un elemento del DOM como imagen SVG + métodos de exportación.
29
+ */
30
+ export function snapdom(
31
+ element: HTMLElement,
32
+ options?: SnapOptions
33
+ ): Promise<SnapResult>;
34
+
35
+ export namespace snapdom {
36
+ function capture(element: HTMLElement, options?: SnapOptions): Promise<SnapResult>;
37
+ function toRaw(element: HTMLElement, options?: SnapOptions): Promise<string>;
38
+ function toImg(element: HTMLElement, options?: SnapOptions): Promise<HTMLImageElement>;
39
+ function toCanvas(element: HTMLElement, options?: SnapOptions): Promise<HTMLCanvasElement>;
40
+ function toBlob(element: HTMLElement, options?: SnapOptions): Promise<Blob>;
41
+ function toPng(element: HTMLElement, options?: SnapOptions): Promise<HTMLImageElement>;
42
+ function toJpg(element: HTMLElement, options?: SnapOptions): Promise<HTMLImageElement>;
43
+ function toWebp(element: HTMLElement, options?: SnapOptions): Promise<HTMLImageElement>;
44
+ function download(element: HTMLElement, options?: SnapOptions): Promise<void>;
45
+ }
46
+
47
+ /**
48
+ * Precarga imágenes, fondos y fuentes para acelerar capturas posteriores.
49
+ */
50
+ export function preCache(
51
+ root?: Document | HTMLElement,
52
+ options?: {
53
+ embedFonts?: boolean;
54
+ }
55
+ ): Promise<void>;
56
+ }