@zumer/snapdom 0.9.7 → 0.9.9

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
@@ -25,6 +25,9 @@ It converts any HTML element into a scalable SVG image, preserving styles, fonts
25
25
  - ⚡ Ultra fast, no dependencies
26
26
  - 📦 100% based on standard Web APIs
27
27
 
28
+ ## Demo
29
+
30
+ https://zumerlab.github.io/snapdom/
28
31
 
29
32
  ## Installation
30
33
 
package/dist/snapdom.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.0.9.7
4
+ * v.0.9.9
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -112,12 +112,15 @@
112
112
  }
113
113
  function collectUsedTagNames(root) {
114
114
  const tagSet = /* @__PURE__ */ new Set();
115
+ if (root.nodeType !== Node.ELEMENT_NODE && root.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
116
+ return [];
117
+ }
115
118
  if (root.tagName) {
116
119
  tagSet.add(root.tagName.toLowerCase());
117
120
  }
118
- root.querySelectorAll("*").forEach((el) => {
119
- tagSet.add(el.tagName.toLowerCase());
120
- });
121
+ if (typeof root.querySelectorAll === "function") {
122
+ root.querySelectorAll("*").forEach((el) => tagSet.add(el.tagName.toLowerCase()));
123
+ }
121
124
  return Array.from(tagSet);
122
125
  }
123
126
  function generateDedupedBaseCSS(usedTagNames) {
@@ -552,7 +555,7 @@
552
555
  let clone, classCSS, styleCache;
553
556
  let fontsCSS = "";
554
557
  let baseCSS = "";
555
- let dataBlob;
558
+ let dataURL;
556
559
  let svgString;
557
560
  ({ clone, classCSS, styleCache } = await prepareClone(element, compress));
558
561
  await new Promise((resolve) => {
@@ -615,18 +618,13 @@
615
618
  const svgHeader = `<svg xmlns="${svgNS}" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">`;
616
619
  const svgFooter = "</svg>";
617
620
  svgString = svgHeader + foString + svgFooter;
618
- const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
619
- dataBlob = URL.createObjectURL(blob);
621
+ dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
620
622
  resolve();
621
623
  }, { fast });
622
624
  });
623
625
  const sandbox = document.getElementById("snapdom-sandbox");
624
626
  if (sandbox && sandbox.style.position === "absolute") sandbox.remove();
625
- if (options.dataURL) {
626
- return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
627
- } else {
628
- return dataBlob;
629
- }
627
+ return dataURL;
630
628
  }
631
629
 
632
630
  // src/api/snapdom.js
@@ -1,3 +1,3 @@
1
- (()=>{var S=new Map,E=new Map,k=new Map,T=new Map,v=new Map,P=new WeakMap;var te=["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 K(){for(let e of te)H(e)}function H(e){if(T.has(e))return T.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let r={};return T.set(e,r),r}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 t=document.createElement(e);t.style.all="initial",o.appendChild(t);let s=getComputedStyle(t),a={};for(let r of s)a[r]=s.getPropertyValue(r);return o.removeChild(t),T.set(e,a),a}function F(e,n,o=!1){let t=[],s=H(n);for(let[a,r]of Object.entries(e))if(!o)r&&t.push(`${a}:${r}`);else{let c=s[a];r&&r!==c&&t.push(`${a}:${r}`)}return t.sort().join(";")}function B(e){let n=new Set;return e.tagName&&n.add(e.tagName.toLowerCase()),e.querySelectorAll("*").forEach(o=>{n.add(o.tagName.toLowerCase())}),Array.from(n)}function D(e){let n=new Map;for(let t of e){let s=T.get(t);if(!s)continue;let a=Object.entries(s).map(([r,c])=>`${r}:${c};`).sort().join("");n.has(a)||n.set(a,[]),n.get(a).push(t)}let o="";for(let[t,s]of n.entries())o+=`${s.join(",")} { ${t} }
2
- `;return o}function _(e){let n=new Set(e.values()),o=new Map,t=1;for(let s of n)o.set(s,`c${t++}`);return o}function N(e,{fast:n=!1}={}){if(n)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,n=null){if(!(e instanceof Element))return window.getComputedStyle(e,n);let o=P.get(e);if(o||(o=new Map,P.set(e,o)),!o.has(n)){let t=window.getComputedStyle(e,n);o.set(n,t)}return o.get(n)}function Y(e){let n=e.replace(/^['"]|['"]$/g,"");if(n.startsWith("\\"))try{return String.fromCharCode(parseInt(n.replace("\\",""),16))}catch{return n}return n}function X(e){let n=e.match(/url\(["']?([^"')]+)["']?\)/);return n?n[1]:null}function M(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 C(e,n=3e3){return S.has(e)?Promise.resolve(S.get(e)):new Promise((o,t)=>{let s=setTimeout(()=>{t(new Error("Image load timed out"))},n),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(s);try{await a.decode();let r=document.createElement("canvas");r.width=a.width,r.height=a.height,r.getContext("2d").drawImage(a,0,0);try{let i=r.toDataURL("image/png");S.set(e,i),o(i)}catch{t(new Error("CORS restrictions prevented image capture"))}}catch(r){t(r)}},a.onerror=r=>{clearTimeout(s),t(new Error("Failed to load image: "+(r.message||"Unknown error")))},a.src=e})}function W(e){let n={};for(let o of e)n[o]=e.getPropertyValue(o);return n}function V(e,n,o,t,s){if(e.tagName==="STYLE")return;t.has(e)||t.set(e,A(e));let a=t.get(e),r=W(a),c=e.tagName?.toLowerCase()||"div",i=F(r,c,s);o.set(n,i)}function O(e,n,o,t,s){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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);t.set(c,e),V(e,c,n,o,s);let i=document.createElement("div");return i.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),i=document.createElement("img");return i.src=c,i.width=e.width,i.height=e.height,i}if(e.nodeType===Node.TEXT_NODE){if(!e.textContent.trim())return null;if(e.parentElement?.shadowRoot){let i=e.parentElement.tagName.toLowerCase();if(customElements.get(i))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);t.set(a,e),V(e,a,n,o,s);let r=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let i=O(c,n,o,t,s);i&&r.appendChild(i)}),a.appendChild(r),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(m=>m.tagName!=="STYLE").map(m=>O(m,n,o,t)).filter(Boolean),i=document.createDocumentFragment();c.forEach(m=>i.appendChild(m)),a.appendChild(i)}return a}async function J(e,n,o,t=32,s="#000"){n=n.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${t}px "${n}"`);let a=document.createElement("canvas");a.width=t,a.height=t;let r=a.getContext("2d");return r.font=o?`${o} ${t}px "${n}"`:` ${t}px "${n}"`,r.textAlign="center",r.textBaseline="middle",r.fillStyle=s,r.fillText(e,a.width/2,a.height/2),a.toDataURL()}async function j({ignoreIconFonts:e=!0,preCached:n=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(s=>s.href),t="";for(let s of o)try{let r=await(await fetch(s.href)).text();if(e&&(M(s.href)||M(r))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",s.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(r.matchAll(c)).map(async l=>{let d=l[1].replace(/["']/g,"");if(d.startsWith("http")||(d=new URL(d,s.href).href),e&&M(d))return console.log("\u23ED\uFE0F Ignorando icon font URL:",d),null;if(k.has(d))return{original:l[0],inlined:`url(${k.get(d)})`};try{let y=await(await fetch(d)).blob(),f=await new Promise(g=>{let u=new FileReader;u.onload=()=>g(u.result),u.readAsDataURL(y)});return k.set(d,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",d),null}})),m=r;for(let l of i)l&&(m=m.replace(l.original,l.inlined));t+=m+`
3
- `}catch{console.warn("\u274C No pude fetch CSS",s.href)}if(t&&n){let s=document.createElement("style");s.setAttribute("data-snapdom","embedFonts"),s.textContent=t,document.head.appendChild(s)}return t}async function R(e,n,o,t,s){if(!(e instanceof Element)||!(n instanceof Element))return;for(let c of["::before","::after"])try{let i=A(e,c);if(!i)continue;let m=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),d=m&&m!=="none"&&m!=='""'&&m!=="''",h=l&&l.startsWith("url(");if(d||h){let y=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,g=parseInt(i.getPropertyValue("font-weight"))||!1,u=i.getPropertyValue("color")||"#000",w=document.createElement("span");w.dataset.snapdomPseudo=c;let L=W(i),I=F(L,"span",s);o.set(w,I);let U=y&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(y),x=Y(m);if(U&&x.length===1){let b=document.createElement("img");b.src=await J(x,y,g,f,u),b.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let $=document.createElement("img"),z=await C(b[1]);$.src=z,$.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild($)}catch($){console.error(`[snapdom] Error in pseudo ${c} for`,e,$)}}else x&&x!=="none"&&(w.textContent=x);c==="::before"?n.insertBefore(w,n.firstChild):n.appendChild(w)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,e,i)}let a=Array.from(e.children),r=Array.from(n.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(a.length,r.length);c++)await R(a[c],r[c],o,t,s)}async function q(e,n=!1){let o=new Map,t=new WeakMap,s=new WeakMap,a;try{a=O(e,o,t,s,n)}catch(i){throw console.warn("deepClone failed:",i),i}try{await R(e,a,o,t,n)}catch(i){console.warn("inlinePseudoElements failed:",i)}let r=_(o),c=Array.from(r.entries()).map(([i,m])=>`.${m}{${i}}`).join("");for(let[i,m]of o.entries()){if(i.tagName==="STYLE")continue;let l=r.get(m);l&&i.classList.add(l);let d=i.style?.backgroundImage;i.removeAttribute("style"),d&&d!=="none"&&(i.style.backgroundImage=d)}return{clone:a,classCSS:c,styleCache:t}}async function G(e){let n=Array.from(e.querySelectorAll("img")),o=async t=>{let s=t.src;try{let a=await C(s);t.src=a,t.width||(t.width=t.naturalWidth||100),t.height||(t.height=t.naturalHeight||100)}catch{let a=document.createElement("div");a.style=`width: ${t.width||100}px; height: ${t.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${t.height||100}px; color: #666; font-size: 12px;`,a.innerText="img",t.replaceWith(a)}};for(let t=0;t<n.length;t+=4){let s=n.slice(t,t+4).map(o);await Promise.allSettled(s)}}async function Q(e,n,o){let t=[[e,n]];for(;t.length;){let[s,a]=t.shift(),r=o.get(s)||A(s);o.has(s)||o.set(s,r);let c=r.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let d=l[1],h;E.has(d)?h=E.get(d):(h=await C(d),E.set(d,h)),a.style.backgroundImage=`url(${h})`}catch{a.style.backgroundImage="none"}}let i=Array.from(s.children),m=Array.from(a.children);for(let l=0;l<Math.min(i.length,m.length);l++)t.push([i[l],m[l]])}}async function Z(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:t=!1,fast:s=!0,scale:a=1}=n,r,c,i,m="",l="",d,h;if({clone:r,classCSS:c,styleCache:i}=await q(e,o),await new Promise(f=>{N(async()=>{await G(r),f()},{fast:s})}),await new Promise(f=>{N(async()=>{await Q(e,r,i),f()},{fast:s})}),t&&await new Promise(f=>{N(async()=>{m=await j({ignoreIconFonts:!0}),f()},{fast:s})}),o){let f=B(r).sort(),g=f.join(",");v.has(g)?l=v.get(g):await new Promise(u=>{N(()=>{l=D(f),v.set(g,l),u()},{fast:s})})}await new Promise(f=>{N(()=>{let g=e.getBoundingClientRect(),u=g.width*a,w=g.height*a;a!==1&&(r.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),r.style.transform=`scale(${a})`,r.style.transformOrigin="top left",r.style.width=`${g.width}px`,r.style.height=`${g.height}px`);let L="http://www.w3.org/2000/svg",I=document.createElementNS(L,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let U=document.createElement("style");U.textContent=l+m+"svg{overflow:visible;}"+c,I.appendChild(U),I.appendChild(r);let b=new XMLSerializer().serializeToString(I);h=`<svg xmlns="${L}" width="${u}" height="${w}" viewBox="0 0 ${u} ${w}">`+b+"</svg>";let ee=new Blob([h],{type:"image/svg+xml;charset=utf-8"});d=URL.createObjectURL(ee),f()},{fast:s})});let y=document.getElementById("snapdom-sandbox");return y&&y.style.position==="absolute"&&y.remove(),n.dataURL?`data:image/svg+xml;charset=utf-8,${encodeURIComponent(h)}`:d}async function p(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");return await Z(e,n)}p.toImg=async(e,n={})=>{let o=await p(e,n),t=new Image;return t.src=o,await t.decode(),t};p.toCanvas=async(e,n={})=>{let o=await p.toImg(e,n),t=document.createElement("canvas");return t.width=o.width,t.height=o.height,t.getContext("2d").drawImage(o,0,0),t};p.toPng=async(e,n={})=>{let o=await p.toCanvas(e,n),t=new Image;return t.src=o.toDataURL("image/png"),await t.decode(),t};p.toJpg=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/jpeg",t),await c.decode(),c};p.toWebp=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/webp",t),await c.decode(),c};p.toBlob=async(e,n={})=>{let o=await p(e,n),t=decodeURIComponent(o.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})};async function ne(e=document,n={}){let{embedFonts:o=!0,reset:t=!1,preWarm:s=!0}=n;if(t){S.clear(),E.clear(),k.clear(),v.clear(),P.clear();return}await document.fonts.ready,K();let a=[],r=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),r=Array.from(e.querySelectorAll("*")));let c=[];for(let i of a){let m=i.src;S.has(m)||c.push(C(m).then(l=>S.set(m,l)).catch(()=>{}))}for(let i of r){let m=getComputedStyle(i).backgroundImage,l=X(m);l&&!E.has(l)&&c.push(C(l).then(d=>E.set(l,d)).catch(()=>{}))}if(o&&await j({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c),s){let i=B(e).sort(),m=i.join(",");if(!v.has(m)){let d=D(i);v.set(m,d)}let l=e.cloneNode(!1);await R(e,l,new Map,new WeakMap,!1)}if(s)try{await q(e,n.preWarm)}catch{}}})();
1
+ (()=>{var S=new Map,E=new Map,N=new Map,$=new Map,v=new Map,P=new WeakMap;var ee=["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 ee)K(e)}function K(e){if($.has(e))return $.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let r={};return $.set(e,r),r}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 t=document.createElement(e);t.style.all="initial",o.appendChild(t);let s=getComputedStyle(t),a={};for(let r of s)a[r]=s.getPropertyValue(r);return o.removeChild(t),$.set(e,a),a}function D(e,n,o=!1){let t=[],s=K(n);for(let[a,r]of Object.entries(e))if(!o)r&&t.push(`${a}:${r}`);else{let c=s[a];r&&r!==c&&t.push(`${a}:${r}`)}return t.sort().join(";")}function M(e){let n=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&n.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>n.add(o.tagName.toLowerCase())),Array.from(n))}function F(e){let n=new Map;for(let t of e){let s=$.get(t);if(!s)continue;let a=Object.entries(s).map(([r,c])=>`${r}:${c};`).sort().join("");n.has(a)||n.set(a,[]),n.get(a).push(t)}let o="";for(let[t,s]of n.entries())o+=`${s.join(",")} { ${t} }
2
+ `;return o}function H(e){let n=new Set(e.values()),o=new Map,t=1;for(let s of n)o.set(s,`c${t++}`);return o}function k(e,{fast:n=!1}={}){if(n)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,n=null){if(!(e instanceof Element))return window.getComputedStyle(e,n);let o=P.get(e);if(o||(o=new Map,P.set(e,o)),!o.has(n)){let t=window.getComputedStyle(e,n);o.set(n,t)}return o.get(n)}function Y(e){let n=e.replace(/^['"]|['"]$/g,"");if(n.startsWith("\\"))try{return String.fromCharCode(parseInt(n.replace("\\",""),16))}catch{return n}return n}function X(e){let n=e.match(/url\(["']?([^"')]+)["']?\)/);return n?n[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 C(e,n=3e3){return S.has(e)?Promise.resolve(S.get(e)):new Promise((o,t)=>{let s=setTimeout(()=>{t(new Error("Image load timed out"))},n),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(s);try{await a.decode();let r=document.createElement("canvas");r.width=a.width,r.height=a.height,r.getContext("2d").drawImage(a,0,0);try{let i=r.toDataURL("image/png");S.set(e,i),o(i)}catch{t(new Error("CORS restrictions prevented image capture"))}}catch(r){t(r)}},a.onerror=r=>{clearTimeout(s),t(new Error("Failed to load image: "+(r.message||"Unknown error")))},a.src=e})}function O(e){let n={};for(let o of e)n[o]=e.getPropertyValue(o);return n}function j(e,n,o,t,s){if(e.tagName==="STYLE")return;t.has(e)||t.set(e,A(e));let a=t.get(e),r=O(a),c=e.tagName?.toLowerCase()||"div",i=D(r,c,s);o.set(n,i)}function W(e,n,o,t,s){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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);t.set(c,e),j(e,c,n,o,s);let i=document.createElement("div");return i.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),i=document.createElement("img");return i.src=c,i.width=e.width,i.height=e.height,i}if(e.nodeType===Node.TEXT_NODE){if(!e.textContent.trim())return null;if(e.parentElement?.shadowRoot){let i=e.parentElement.tagName.toLowerCase();if(customElements.get(i))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);t.set(a,e),j(e,a,n,o,s);let r=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let i=W(c,n,o,t,s);i&&r.appendChild(i)}),a.appendChild(r),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(m=>m.tagName!=="STYLE").map(m=>W(m,n,o,t)).filter(Boolean),i=document.createDocumentFragment();c.forEach(m=>i.appendChild(m)),a.appendChild(i)}return a}async function G(e,n,o,t=32,s="#000"){n=n.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${t}px "${n}"`);let a=document.createElement("canvas");a.width=t,a.height=t;let r=a.getContext("2d");return r.font=o?`${o} ${t}px "${n}"`:` ${t}px "${n}"`,r.textAlign="center",r.textBaseline="middle",r.fillStyle=s,r.fillText(e,a.width/2,a.height/2),a.toDataURL()}async function q({ignoreIconFonts:e=!0,preCached:n=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(s=>s.href),t="";for(let s of o)try{let r=await(await fetch(s.href)).text();if(e&&(B(s.href)||B(r))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",s.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(r.matchAll(c)).map(async l=>{let d=l[1].replace(/["']/g,"");if(d.startsWith("http")||(d=new URL(d,s.href).href),e&&B(d))return console.log("\u23ED\uFE0F Ignorando icon font URL:",d),null;if(N.has(d))return{original:l[0],inlined:`url(${N.get(d)})`};try{let y=await(await fetch(d)).blob(),f=await new Promise(h=>{let u=new FileReader;u.onload=()=>h(u.result),u.readAsDataURL(y)});return N.set(d,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",d),null}})),m=r;for(let l of i)l&&(m=m.replace(l.original,l.inlined));t+=m+`
3
+ `}catch{console.warn("\u274C No pude fetch CSS",s.href)}if(t&&n){let s=document.createElement("style");s.setAttribute("data-snapdom","embedFonts"),s.textContent=t,document.head.appendChild(s)}return t}async function R(e,n,o,t,s){if(!(e instanceof Element)||!(n instanceof Element))return;for(let c of["::before","::after"])try{let i=A(e,c);if(!i)continue;let m=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),d=m&&m!=="none"&&m!=='""'&&m!=="''",g=l&&l.startsWith("url(");if(d||g){let y=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,h=parseInt(i.getPropertyValue("font-weight"))||!1,u=i.getPropertyValue("color")||"#000",w=document.createElement("span");w.dataset.snapdomPseudo=c;let L=O(i),I=D(L,"span",s);o.set(w,I);let U=y&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(y),x=Y(m);if(U&&x.length===1){let b=document.createElement("img");b.src=await G(x,y,h,f,u),b.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let T=document.createElement("img"),_=await C(b[1]);T.src=_,T.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(T)}catch(T){console.error(`[snapdom] Error in pseudo ${c} for`,e,T)}}else x&&x!=="none"&&(w.textContent=x);c==="::before"?n.insertBefore(w,n.firstChild):n.appendChild(w)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,e,i)}let a=Array.from(e.children),r=Array.from(n.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(a.length,r.length);c++)await R(a[c],r[c],o,t,s)}async function V(e,n=!1){let o=new Map,t=new WeakMap,s=new WeakMap,a;try{a=W(e,o,t,s,n)}catch(i){throw console.warn("deepClone failed:",i),i}try{await R(e,a,o,t,n)}catch(i){console.warn("inlinePseudoElements failed:",i)}let r=H(o),c=Array.from(r.entries()).map(([i,m])=>`.${m}{${i}}`).join("");for(let[i,m]of o.entries()){if(i.tagName==="STYLE")continue;let l=r.get(m);l&&i.classList.add(l);let d=i.style?.backgroundImage;i.removeAttribute("style"),d&&d!=="none"&&(i.style.backgroundImage=d)}return{clone:a,classCSS:c,styleCache:t}}async function J(e){let n=Array.from(e.querySelectorAll("img")),o=async t=>{let s=t.src;try{let a=await C(s);t.src=a,t.width||(t.width=t.naturalWidth||100),t.height||(t.height=t.naturalHeight||100)}catch{let a=document.createElement("div");a.style=`width: ${t.width||100}px; height: ${t.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${t.height||100}px; color: #666; font-size: 12px;`,a.innerText="img",t.replaceWith(a)}};for(let t=0;t<n.length;t+=4){let s=n.slice(t,t+4).map(o);await Promise.allSettled(s)}}async function Q(e,n,o){let t=[[e,n]];for(;t.length;){let[s,a]=t.shift(),r=o.get(s)||A(s);o.has(s)||o.set(s,r);let c=r.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let d=l[1],g;E.has(d)?g=E.get(d):(g=await C(d),E.set(d,g)),a.style.backgroundImage=`url(${g})`}catch{a.style.backgroundImage="none"}}let i=Array.from(s.children),m=Array.from(a.children);for(let l=0;l<Math.min(i.length,m.length);l++)t.push([i[l],m[l]])}}async function Z(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:t=!1,fast:s=!0,scale:a=1}=n,r,c,i,m="",l="",d,g;if({clone:r,classCSS:c,styleCache:i}=await V(e,o),await new Promise(f=>{k(async()=>{await J(r),f()},{fast:s})}),await new Promise(f=>{k(async()=>{await Q(e,r,i),f()},{fast:s})}),t&&await new Promise(f=>{k(async()=>{m=await q({ignoreIconFonts:!0}),f()},{fast:s})}),o){let f=M(r).sort(),h=f.join(",");v.has(h)?l=v.get(h):await new Promise(u=>{k(()=>{l=F(f),v.set(h,l),u()},{fast:s})})}await new Promise(f=>{k(()=>{let h=e.getBoundingClientRect(),u=h.width*a,w=h.height*a;a!==1&&(r.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),r.style.transform=`scale(${a})`,r.style.transformOrigin="top left",r.style.width=`${h.width}px`,r.style.height=`${h.height}px`);let L="http://www.w3.org/2000/svg",I=document.createElementNS(L,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let U=document.createElement("style");U.textContent=l+m+"svg{overflow:visible;}"+c,I.appendChild(U),I.appendChild(r);let b=new XMLSerializer().serializeToString(I);g=`<svg xmlns="${L}" width="${u}" height="${w}" viewBox="0 0 ${u} ${w}">`+b+"</svg>",d=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(g)}`,f()},{fast:s})});let y=document.getElementById("snapdom-sandbox");return y&&y.style.position==="absolute"&&y.remove(),d}async function p(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");return await Z(e,n)}p.toImg=async(e,n={})=>{let o=await p(e,n),t=new Image;return t.src=o,await t.decode(),t};p.toCanvas=async(e,n={})=>{let o=await p.toImg(e,n),t=document.createElement("canvas");return t.width=o.width,t.height=o.height,t.getContext("2d").drawImage(o,0,0),t};p.toPng=async(e,n={})=>{let o=await p.toCanvas(e,n),t=new Image;return t.src=o.toDataURL("image/png"),await t.decode(),t};p.toJpg=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/jpeg",t),await c.decode(),c};p.toWebp=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/webp",t),await c.decode(),c};p.toBlob=async(e,n={})=>{let o=await p(e,n),t=decodeURIComponent(o.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})};async function te(e=document,n={}){let{embedFonts:o=!0,reset:t=!1,preWarm:s=!0}=n;if(t){S.clear(),E.clear(),N.clear(),v.clear(),P.clear();return}await document.fonts.ready,z();let a=[],r=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),r=Array.from(e.querySelectorAll("*")));let c=[];for(let i of a){let m=i.src;S.has(m)||c.push(C(m).then(l=>S.set(m,l)).catch(()=>{}))}for(let i of r){let m=getComputedStyle(i).backgroundImage,l=X(m);l&&!E.has(l)&&c.push(C(l).then(d=>E.set(l,d)).catch(()=>{}))}if(o&&await q({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c),s){let i=M(e).sort(),m=i.join(",");if(!v.has(m)){let d=F(i);v.set(m,d)}let l=e.cloneNode(!1);await R(e,l,new Map,new WeakMap,!1)}if(s)try{await V(e,n.preWarm)}catch{}}})();
@@ -1,3 +1,3 @@
1
- var S=new Map,E=new Map,k=new Map,T=new Map,v=new Map,P=new WeakMap;var te=["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 K(){for(let e of te)H(e)}function H(e){if(T.has(e))return T.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let r={};return T.set(e,r),r}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 t=document.createElement(e);t.style.all="initial",o.appendChild(t);let s=getComputedStyle(t),a={};for(let r of s)a[r]=s.getPropertyValue(r);return o.removeChild(t),T.set(e,a),a}function F(e,n,o=!1){let t=[],s=H(n);for(let[a,r]of Object.entries(e))if(!o)r&&t.push(`${a}:${r}`);else{let c=s[a];r&&r!==c&&t.push(`${a}:${r}`)}return t.sort().join(";")}function B(e){let n=new Set;return e.tagName&&n.add(e.tagName.toLowerCase()),e.querySelectorAll("*").forEach(o=>{n.add(o.tagName.toLowerCase())}),Array.from(n)}function D(e){let n=new Map;for(let t of e){let s=T.get(t);if(!s)continue;let a=Object.entries(s).map(([r,c])=>`${r}:${c};`).sort().join("");n.has(a)||n.set(a,[]),n.get(a).push(t)}let o="";for(let[t,s]of n.entries())o+=`${s.join(",")} { ${t} }
2
- `;return o}function _(e){let n=new Set(e.values()),o=new Map,t=1;for(let s of n)o.set(s,`c${t++}`);return o}function N(e,{fast:n=!1}={}){if(n)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,n=null){if(!(e instanceof Element))return window.getComputedStyle(e,n);let o=P.get(e);if(o||(o=new Map,P.set(e,o)),!o.has(n)){let t=window.getComputedStyle(e,n);o.set(n,t)}return o.get(n)}function Y(e){let n=e.replace(/^['"]|['"]$/g,"");if(n.startsWith("\\"))try{return String.fromCharCode(parseInt(n.replace("\\",""),16))}catch{return n}return n}function X(e){let n=e.match(/url\(["']?([^"')]+)["']?\)/);return n?n[1]:null}function M(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 C(e,n=3e3){return S.has(e)?Promise.resolve(S.get(e)):new Promise((o,t)=>{let s=setTimeout(()=>{t(new Error("Image load timed out"))},n),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(s);try{await a.decode();let r=document.createElement("canvas");r.width=a.width,r.height=a.height,r.getContext("2d").drawImage(a,0,0);try{let i=r.toDataURL("image/png");S.set(e,i),o(i)}catch{t(new Error("CORS restrictions prevented image capture"))}}catch(r){t(r)}},a.onerror=r=>{clearTimeout(s),t(new Error("Failed to load image: "+(r.message||"Unknown error")))},a.src=e})}function W(e){let n={};for(let o of e)n[o]=e.getPropertyValue(o);return n}function V(e,n,o,t,s){if(e.tagName==="STYLE")return;t.has(e)||t.set(e,A(e));let a=t.get(e),r=W(a),c=e.tagName?.toLowerCase()||"div",i=F(r,c,s);o.set(n,i)}function O(e,n,o,t,s){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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);t.set(c,e),V(e,c,n,o,s);let i=document.createElement("div");return i.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),i=document.createElement("img");return i.src=c,i.width=e.width,i.height=e.height,i}if(e.nodeType===Node.TEXT_NODE){if(!e.textContent.trim())return null;if(e.parentElement?.shadowRoot){let i=e.parentElement.tagName.toLowerCase();if(customElements.get(i))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);t.set(a,e),V(e,a,n,o,s);let r=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let i=O(c,n,o,t,s);i&&r.appendChild(i)}),a.appendChild(r),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(m=>m.tagName!=="STYLE").map(m=>O(m,n,o,t)).filter(Boolean),i=document.createDocumentFragment();c.forEach(m=>i.appendChild(m)),a.appendChild(i)}return a}async function J(e,n,o,t=32,s="#000"){n=n.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${t}px "${n}"`);let a=document.createElement("canvas");a.width=t,a.height=t;let r=a.getContext("2d");return r.font=o?`${o} ${t}px "${n}"`:` ${t}px "${n}"`,r.textAlign="center",r.textBaseline="middle",r.fillStyle=s,r.fillText(e,a.width/2,a.height/2),a.toDataURL()}async function j({ignoreIconFonts:e=!0,preCached:n=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(s=>s.href),t="";for(let s of o)try{let r=await(await fetch(s.href)).text();if(e&&(M(s.href)||M(r))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",s.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(r.matchAll(c)).map(async l=>{let d=l[1].replace(/["']/g,"");if(d.startsWith("http")||(d=new URL(d,s.href).href),e&&M(d))return console.log("\u23ED\uFE0F Ignorando icon font URL:",d),null;if(k.has(d))return{original:l[0],inlined:`url(${k.get(d)})`};try{let y=await(await fetch(d)).blob(),f=await new Promise(g=>{let u=new FileReader;u.onload=()=>g(u.result),u.readAsDataURL(y)});return k.set(d,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",d),null}})),m=r;for(let l of i)l&&(m=m.replace(l.original,l.inlined));t+=m+`
3
- `}catch{console.warn("\u274C No pude fetch CSS",s.href)}if(t&&n){let s=document.createElement("style");s.setAttribute("data-snapdom","embedFonts"),s.textContent=t,document.head.appendChild(s)}return t}async function R(e,n,o,t,s){if(!(e instanceof Element)||!(n instanceof Element))return;for(let c of["::before","::after"])try{let i=A(e,c);if(!i)continue;let m=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),d=m&&m!=="none"&&m!=='""'&&m!=="''",h=l&&l.startsWith("url(");if(d||h){let y=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,g=parseInt(i.getPropertyValue("font-weight"))||!1,u=i.getPropertyValue("color")||"#000",w=document.createElement("span");w.dataset.snapdomPseudo=c;let L=W(i),I=F(L,"span",s);o.set(w,I);let U=y&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(y),x=Y(m);if(U&&x.length===1){let b=document.createElement("img");b.src=await J(x,y,g,f,u),b.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let $=document.createElement("img"),z=await C(b[1]);$.src=z,$.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild($)}catch($){console.error(`[snapdom] Error in pseudo ${c} for`,e,$)}}else x&&x!=="none"&&(w.textContent=x);c==="::before"?n.insertBefore(w,n.firstChild):n.appendChild(w)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,e,i)}let a=Array.from(e.children),r=Array.from(n.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(a.length,r.length);c++)await R(a[c],r[c],o,t,s)}async function q(e,n=!1){let o=new Map,t=new WeakMap,s=new WeakMap,a;try{a=O(e,o,t,s,n)}catch(i){throw console.warn("deepClone failed:",i),i}try{await R(e,a,o,t,n)}catch(i){console.warn("inlinePseudoElements failed:",i)}let r=_(o),c=Array.from(r.entries()).map(([i,m])=>`.${m}{${i}}`).join("");for(let[i,m]of o.entries()){if(i.tagName==="STYLE")continue;let l=r.get(m);l&&i.classList.add(l);let d=i.style?.backgroundImage;i.removeAttribute("style"),d&&d!=="none"&&(i.style.backgroundImage=d)}return{clone:a,classCSS:c,styleCache:t}}async function G(e){let n=Array.from(e.querySelectorAll("img")),o=async t=>{let s=t.src;try{let a=await C(s);t.src=a,t.width||(t.width=t.naturalWidth||100),t.height||(t.height=t.naturalHeight||100)}catch{let a=document.createElement("div");a.style=`width: ${t.width||100}px; height: ${t.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${t.height||100}px; color: #666; font-size: 12px;`,a.innerText="img",t.replaceWith(a)}};for(let t=0;t<n.length;t+=4){let s=n.slice(t,t+4).map(o);await Promise.allSettled(s)}}async function Q(e,n,o){let t=[[e,n]];for(;t.length;){let[s,a]=t.shift(),r=o.get(s)||A(s);o.has(s)||o.set(s,r);let c=r.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let d=l[1],h;E.has(d)?h=E.get(d):(h=await C(d),E.set(d,h)),a.style.backgroundImage=`url(${h})`}catch{a.style.backgroundImage="none"}}let i=Array.from(s.children),m=Array.from(a.children);for(let l=0;l<Math.min(i.length,m.length);l++)t.push([i[l],m[l]])}}async function Z(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:t=!1,fast:s=!0,scale:a=1}=n,r,c,i,m="",l="",d,h;if({clone:r,classCSS:c,styleCache:i}=await q(e,o),await new Promise(f=>{N(async()=>{await G(r),f()},{fast:s})}),await new Promise(f=>{N(async()=>{await Q(e,r,i),f()},{fast:s})}),t&&await new Promise(f=>{N(async()=>{m=await j({ignoreIconFonts:!0}),f()},{fast:s})}),o){let f=B(r).sort(),g=f.join(",");v.has(g)?l=v.get(g):await new Promise(u=>{N(()=>{l=D(f),v.set(g,l),u()},{fast:s})})}await new Promise(f=>{N(()=>{let g=e.getBoundingClientRect(),u=g.width*a,w=g.height*a;a!==1&&(r.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),r.style.transform=`scale(${a})`,r.style.transformOrigin="top left",r.style.width=`${g.width}px`,r.style.height=`${g.height}px`);let L="http://www.w3.org/2000/svg",I=document.createElementNS(L,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let U=document.createElement("style");U.textContent=l+m+"svg{overflow:visible;}"+c,I.appendChild(U),I.appendChild(r);let b=new XMLSerializer().serializeToString(I);h=`<svg xmlns="${L}" width="${u}" height="${w}" viewBox="0 0 ${u} ${w}">`+b+"</svg>";let ee=new Blob([h],{type:"image/svg+xml;charset=utf-8"});d=URL.createObjectURL(ee),f()},{fast:s})});let y=document.getElementById("snapdom-sandbox");return y&&y.style.position==="absolute"&&y.remove(),n.dataURL?`data:image/svg+xml;charset=utf-8,${encodeURIComponent(h)}`:d}async function p(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");return await Z(e,n)}p.toImg=async(e,n={})=>{let o=await p(e,n),t=new Image;return t.src=o,await t.decode(),t};p.toCanvas=async(e,n={})=>{let o=await p.toImg(e,n),t=document.createElement("canvas");return t.width=o.width,t.height=o.height,t.getContext("2d").drawImage(o,0,0),t};p.toPng=async(e,n={})=>{let o=await p.toCanvas(e,n),t=new Image;return t.src=o.toDataURL("image/png"),await t.decode(),t};p.toJpg=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/jpeg",t),await c.decode(),c};p.toWebp=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/webp",t),await c.decode(),c};p.toBlob=async(e,n={})=>{let o=await p(e,n),t=decodeURIComponent(o.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})};async function ne(e=document,n={}){let{embedFonts:o=!0,reset:t=!1,preWarm:s=!0}=n;if(t){S.clear(),E.clear(),k.clear(),v.clear(),P.clear();return}await document.fonts.ready,K();let a=[],r=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),r=Array.from(e.querySelectorAll("*")));let c=[];for(let i of a){let m=i.src;S.has(m)||c.push(C(m).then(l=>S.set(m,l)).catch(()=>{}))}for(let i of r){let m=getComputedStyle(i).backgroundImage,l=X(m);l&&!E.has(l)&&c.push(C(l).then(d=>E.set(l,d)).catch(()=>{}))}if(o&&await j({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c),s){let i=B(e).sort(),m=i.join(",");if(!v.has(m)){let d=D(i);v.set(m,d)}let l=e.cloneNode(!1);await R(e,l,new Map,new WeakMap,!1)}if(s)try{await q(e,n.preWarm)}catch{}}export{ne as preCache,p as snapdom};
1
+ var S=new Map,E=new Map,N=new Map,$=new Map,v=new Map,P=new WeakMap;var ee=["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 ee)K(e)}function K(e){if($.has(e))return $.get(e);if(new Set(["script","style","meta","link","noscript","template"]).has(e)){let r={};return $.set(e,r),r}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 t=document.createElement(e);t.style.all="initial",o.appendChild(t);let s=getComputedStyle(t),a={};for(let r of s)a[r]=s.getPropertyValue(r);return o.removeChild(t),$.set(e,a),a}function D(e,n,o=!1){let t=[],s=K(n);for(let[a,r]of Object.entries(e))if(!o)r&&t.push(`${a}:${r}`);else{let c=s[a];r&&r!==c&&t.push(`${a}:${r}`)}return t.sort().join(";")}function M(e){let n=new Set;return e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE?[]:(e.tagName&&n.add(e.tagName.toLowerCase()),typeof e.querySelectorAll=="function"&&e.querySelectorAll("*").forEach(o=>n.add(o.tagName.toLowerCase())),Array.from(n))}function F(e){let n=new Map;for(let t of e){let s=$.get(t);if(!s)continue;let a=Object.entries(s).map(([r,c])=>`${r}:${c};`).sort().join("");n.has(a)||n.set(a,[]),n.get(a).push(t)}let o="";for(let[t,s]of n.entries())o+=`${s.join(",")} { ${t} }
2
+ `;return o}function H(e){let n=new Set(e.values()),o=new Map,t=1;for(let s of n)o.set(s,`c${t++}`);return o}function k(e,{fast:n=!1}={}){if(n)return e();"requestIdleCallback"in window?requestIdleCallback(e,{timeout:50}):setTimeout(e,1)}function A(e,n=null){if(!(e instanceof Element))return window.getComputedStyle(e,n);let o=P.get(e);if(o||(o=new Map,P.set(e,o)),!o.has(n)){let t=window.getComputedStyle(e,n);o.set(n,t)}return o.get(n)}function Y(e){let n=e.replace(/^['"]|['"]$/g,"");if(n.startsWith("\\"))try{return String.fromCharCode(parseInt(n.replace("\\",""),16))}catch{return n}return n}function X(e){let n=e.match(/url\(["']?([^"')]+)["']?\)/);return n?n[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 C(e,n=3e3){return S.has(e)?Promise.resolve(S.get(e)):new Promise((o,t)=>{let s=setTimeout(()=>{t(new Error("Image load timed out"))},n),a=new Image;a.crossOrigin="anonymous",a.onload=async()=>{clearTimeout(s);try{await a.decode();let r=document.createElement("canvas");r.width=a.width,r.height=a.height,r.getContext("2d").drawImage(a,0,0);try{let i=r.toDataURL("image/png");S.set(e,i),o(i)}catch{t(new Error("CORS restrictions prevented image capture"))}}catch(r){t(r)}},a.onerror=r=>{clearTimeout(s),t(new Error("Failed to load image: "+(r.message||"Unknown error")))},a.src=e})}function O(e){let n={};for(let o of e)n[o]=e.getPropertyValue(o);return n}function j(e,n,o,t,s){if(e.tagName==="STYLE")return;t.has(e)||t.set(e,A(e));let a=t.get(e),r=O(a),c=e.tagName?.toLowerCase()||"div",i=D(r,c,s);o.set(n,i)}function W(e,n,o,t,s){if(e.nodeType===Node.ELEMENT_NODE&&e.getAttribute("data-capture")==="exclude"){let c=document.createElement("div"),i=e.getBoundingClientRect();return c.style.cssText=`display: inline-block; width: ${i.width}px; height: ${i.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);t.set(c,e),j(e,c,n,o,s);let i=document.createElement("div");return i.textContent=e.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(e.tagName==="CANVAS"){let c=e.toDataURL(),i=document.createElement("img");return i.src=c,i.width=e.width,i.height=e.height,i}if(e.nodeType===Node.TEXT_NODE){if(!e.textContent.trim())return null;if(e.parentElement?.shadowRoot){let i=e.parentElement.tagName.toLowerCase();if(customElements.get(i))return null}return e.cloneNode(!0)}if(e.nodeType!==Node.ELEMENT_NODE)return e.cloneNode(!0);let a=e.cloneNode(!1);t.set(a,e),j(e,a,n,o,s);let r=document.createDocumentFragment();if(e.childNodes.forEach(c=>{let i=W(c,n,o,t,s);i&&r.appendChild(i)}),a.appendChild(r),e.shadowRoot){let c=Array.from(e.shadowRoot.children).filter(m=>m.tagName!=="STYLE").map(m=>W(m,n,o,t)).filter(Boolean),i=document.createDocumentFragment();c.forEach(m=>i.appendChild(m)),a.appendChild(i)}return a}async function G(e,n,o,t=32,s="#000"){n=n.replace(/^['"]+|['"]+$/g,""),await document.fonts.ready,await document.fonts.load(`${t}px "${n}"`);let a=document.createElement("canvas");a.width=t,a.height=t;let r=a.getContext("2d");return r.font=o?`${o} ${t}px "${n}"`:` ${t}px "${n}"`,r.textAlign="center",r.textBaseline="middle",r.fillStyle=s,r.fillText(e,a.width/2,a.height/2),a.toDataURL()}async function q({ignoreIconFonts:e=!0,preCached:n=!1}){let o=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(s=>s.href),t="";for(let s of o)try{let r=await(await fetch(s.href)).text();if(e&&(B(s.href)||B(r))){console.log("\u23ED\uFE0F Ignorando icon font CSS:",s.href);continue}let c=/url\(([^)]+)\)/g,i=await Promise.all(Array.from(r.matchAll(c)).map(async l=>{let d=l[1].replace(/["']/g,"");if(d.startsWith("http")||(d=new URL(d,s.href).href),e&&B(d))return console.log("\u23ED\uFE0F Ignorando icon font URL:",d),null;if(N.has(d))return{original:l[0],inlined:`url(${N.get(d)})`};try{let y=await(await fetch(d)).blob(),f=await new Promise(h=>{let u=new FileReader;u.onload=()=>h(u.result),u.readAsDataURL(y)});return N.set(d,f),{original:l[0],inlined:`url(${f})`}}catch{return console.warn("\u274C No pude fetch font",d),null}})),m=r;for(let l of i)l&&(m=m.replace(l.original,l.inlined));t+=m+`
3
+ `}catch{console.warn("\u274C No pude fetch CSS",s.href)}if(t&&n){let s=document.createElement("style");s.setAttribute("data-snapdom","embedFonts"),s.textContent=t,document.head.appendChild(s)}return t}async function R(e,n,o,t,s){if(!(e instanceof Element)||!(n instanceof Element))return;for(let c of["::before","::after"])try{let i=A(e,c);if(!i)continue;let m=i.getPropertyValue("content"),l=i.getPropertyValue("background-image"),d=m&&m!=="none"&&m!=='""'&&m!=="''",g=l&&l.startsWith("url(");if(d||g){let y=i.getPropertyValue("font-family"),f=parseInt(i.getPropertyValue("font-size"))||32,h=parseInt(i.getPropertyValue("font-weight"))||!1,u=i.getPropertyValue("color")||"#000",w=document.createElement("span");w.dataset.snapdomPseudo=c;let L=O(i),I=D(L,"span",s);o.set(w,I);let U=y&&/font.*awesome|material|bootstrap|glyphicons|ionicons|remixicon|simple-line-icons|octicons|feather|typicons|weathericons/i.test(y),x=Y(m);if(U&&x.length===1){let b=document.createElement("img");b.src=await G(x,y,h,f,u),b.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(b)}else if(x.startsWith("url(")){let b=x.match(/url\(["']?([^"')]+)["']?\)/);if(b?.[1])try{let T=document.createElement("img"),_=await C(b[1]);T.src=_,T.style="display:block;width:100%;height:100%;object-fit:contain;",w.appendChild(T)}catch(T){console.error(`[snapdom] Error in pseudo ${c} for`,e,T)}}else x&&x!=="none"&&(w.textContent=x);c==="::before"?n.insertBefore(w,n.firstChild):n.appendChild(w)}}catch(i){console.warn(`[snapdom] Failed to capture ${c} for`,e,i)}let a=Array.from(e.children),r=Array.from(n.children).filter(c=>!c.dataset.snapdomPseudo);for(let c=0;c<Math.min(a.length,r.length);c++)await R(a[c],r[c],o,t,s)}async function V(e,n=!1){let o=new Map,t=new WeakMap,s=new WeakMap,a;try{a=W(e,o,t,s,n)}catch(i){throw console.warn("deepClone failed:",i),i}try{await R(e,a,o,t,n)}catch(i){console.warn("inlinePseudoElements failed:",i)}let r=H(o),c=Array.from(r.entries()).map(([i,m])=>`.${m}{${i}}`).join("");for(let[i,m]of o.entries()){if(i.tagName==="STYLE")continue;let l=r.get(m);l&&i.classList.add(l);let d=i.style?.backgroundImage;i.removeAttribute("style"),d&&d!=="none"&&(i.style.backgroundImage=d)}return{clone:a,classCSS:c,styleCache:t}}async function J(e){let n=Array.from(e.querySelectorAll("img")),o=async t=>{let s=t.src;try{let a=await C(s);t.src=a,t.width||(t.width=t.naturalWidth||100),t.height||(t.height=t.naturalHeight||100)}catch{let a=document.createElement("div");a.style=`width: ${t.width||100}px; height: ${t.height||100}px; background: #ccc; display: inline-block; text-align: center; line-height: ${t.height||100}px; color: #666; font-size: 12px;`,a.innerText="img",t.replaceWith(a)}};for(let t=0;t<n.length;t+=4){let s=n.slice(t,t+4).map(o);await Promise.allSettled(s)}}async function Q(e,n,o){let t=[[e,n]];for(;t.length;){let[s,a]=t.shift(),r=o.get(s)||A(s);o.has(s)||o.set(s,r);let c=r.getPropertyValue("background-image");if(c&&c.includes("url(")){let l=c.match(/url\(["']?([^"')]+)["']?\)/);if(l?.[1])try{let d=l[1],g;E.has(d)?g=E.get(d):(g=await C(d),E.set(d,g)),a.style.backgroundImage=`url(${g})`}catch{a.style.backgroundImage="none"}}let i=Array.from(s.children),m=Array.from(a.children);for(let l=0;l<Math.min(i.length,m.length);l++)t.push([i[l],m[l]])}}async function Z(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");let{compress:o=!0,embedFonts:t=!1,fast:s=!0,scale:a=1}=n,r,c,i,m="",l="",d,g;if({clone:r,classCSS:c,styleCache:i}=await V(e,o),await new Promise(f=>{k(async()=>{await J(r),f()},{fast:s})}),await new Promise(f=>{k(async()=>{await Q(e,r,i),f()},{fast:s})}),t&&await new Promise(f=>{k(async()=>{m=await q({ignoreIconFonts:!0}),f()},{fast:s})}),o){let f=M(r).sort(),h=f.join(",");v.has(h)?l=v.get(h):await new Promise(u=>{k(()=>{l=F(f),v.set(h,l),u()},{fast:s})})}await new Promise(f=>{k(()=>{let h=e.getBoundingClientRect(),u=h.width*a,w=h.height*a;a!==1&&(r.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),r.style.transform=`scale(${a})`,r.style.transformOrigin="top left",r.style.width=`${h.width}px`,r.style.height=`${h.height}px`);let L="http://www.w3.org/2000/svg",I=document.createElementNS(L,"foreignObject");I.setAttribute("width","100%"),I.setAttribute("height","100%");let U=document.createElement("style");U.textContent=l+m+"svg{overflow:visible;}"+c,I.appendChild(U),I.appendChild(r);let b=new XMLSerializer().serializeToString(I);g=`<svg xmlns="${L}" width="${u}" height="${w}" viewBox="0 0 ${u} ${w}">`+b+"</svg>",d=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(g)}`,f()},{fast:s})});let y=document.getElementById("snapdom-sandbox");return y&&y.style.position==="absolute"&&y.remove(),d}async function p(e,n={}){if(!e)throw new Error("Element cannot be null or undefined");return await Z(e,n)}p.toImg=async(e,n={})=>{let o=await p(e,n),t=new Image;return t.src=o,await t.decode(),t};p.toCanvas=async(e,n={})=>{let o=await p.toImg(e,n),t=document.createElement("canvas");return t.width=o.width,t.height=o.height,t.getContext("2d").drawImage(o,0,0),t};p.toPng=async(e,n={})=>{let o=await p.toCanvas(e,n),t=new Image;return t.src=o.toDataURL("image/png"),await t.decode(),t};p.toJpg=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/jpeg",t),await c.decode(),c};p.toWebp=async(e,n={})=>{let{backgroundColor:o="#fff",quality:t=1}=n,s=await p.toCanvas(e,n),a=document.createElement("canvas");a.width=s.width,a.height=s.height;let r=a.getContext("2d");r.fillStyle=o,r.fillRect(0,0,a.width,a.height),r.drawImage(s,0,0);let c=new Image;return c.src=a.toDataURL("image/webp",t),await c.decode(),c};p.toBlob=async(e,n={})=>{let o=await p(e,n),t=decodeURIComponent(o.split(",")[1]);return new Blob([t],{type:"image/svg+xml"})};async function te(e=document,n={}){let{embedFonts:o=!0,reset:t=!1,preWarm:s=!0}=n;if(t){S.clear(),E.clear(),N.clear(),v.clear(),P.clear();return}await document.fonts.ready,z();let a=[],r=[];e?.querySelectorAll&&(a=Array.from(e.querySelectorAll("img[src]")),r=Array.from(e.querySelectorAll("*")));let c=[];for(let i of a){let m=i.src;S.has(m)||c.push(C(m).then(l=>S.set(m,l)).catch(()=>{}))}for(let i of r){let m=getComputedStyle(i).backgroundImage,l=X(m);l&&!E.has(l)&&c.push(C(l).then(d=>E.set(l,d)).catch(()=>{}))}if(o&&await q({ignoreIconFonts:!0,preCached:!0}),await Promise.all(c),s){let i=M(e).sort(),m=i.join(",");if(!v.has(m)){let d=F(i);v.set(m,d)}let l=e.cloneNode(!1);await R(e,l,new Map,new WeakMap,!1)}if(s)try{await V(e,n.preWarm)}catch{}}export{te as preCache,p as snapdom};
package/dist/snapdom.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.0.9.7
4
+ * v.0.9.9
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -112,12 +112,15 @@ function getStyleKey(snapshot, tagName, compress = false) {
112
112
  }
113
113
  function collectUsedTagNames(root) {
114
114
  const tagSet = /* @__PURE__ */ new Set();
115
+ if (root.nodeType !== Node.ELEMENT_NODE && root.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
116
+ return [];
117
+ }
115
118
  if (root.tagName) {
116
119
  tagSet.add(root.tagName.toLowerCase());
117
120
  }
118
- root.querySelectorAll("*").forEach((el) => {
119
- tagSet.add(el.tagName.toLowerCase());
120
- });
121
+ if (typeof root.querySelectorAll === "function") {
122
+ root.querySelectorAll("*").forEach((el) => tagSet.add(el.tagName.toLowerCase()));
123
+ }
121
124
  return Array.from(tagSet);
122
125
  }
123
126
  function generateDedupedBaseCSS(usedTagNames) {
@@ -552,7 +555,7 @@ async function captureDOM(element, options = {}) {
552
555
  let clone, classCSS, styleCache;
553
556
  let fontsCSS = "";
554
557
  let baseCSS = "";
555
- let dataBlob;
558
+ let dataURL;
556
559
  let svgString;
557
560
  ({ clone, classCSS, styleCache } = await prepareClone(element, compress));
558
561
  await new Promise((resolve) => {
@@ -615,18 +618,13 @@ async function captureDOM(element, options = {}) {
615
618
  const svgHeader = `<svg xmlns="${svgNS}" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">`;
616
619
  const svgFooter = "</svg>";
617
620
  svgString = svgHeader + foString + svgFooter;
618
- const blob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
619
- dataBlob = URL.createObjectURL(blob);
621
+ dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
620
622
  resolve();
621
623
  }, { fast });
622
624
  });
623
625
  const sandbox = document.getElementById("snapdom-sandbox");
624
626
  if (sandbox && sandbox.style.position === "absolute") sandbox.remove();
625
- if (options.dataURL) {
626
- return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
627
- } else {
628
- return dataBlob;
629
- }
627
+ return dataURL;
630
628
  }
631
629
 
632
630
  // src/api/snapdom.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zumer/snapdom",
3
- "version": "0.9.7",
3
+ "version": "0.9.9",
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",