diff --git a/src/components/BootstrapBlazor.Dom2Image/BootstrapBlazor.Dom2Image.csproj b/src/components/BootstrapBlazor.Dom2Image/BootstrapBlazor.Dom2Image.csproj index e5e5e629..125c6c30 100644 --- a/src/components/BootstrapBlazor.Dom2Image/BootstrapBlazor.Dom2Image.csproj +++ b/src/components/BootstrapBlazor.Dom2Image/BootstrapBlazor.Dom2Image.csproj @@ -1,7 +1,7 @@  - 10.0.0 + 10.0.1 diff --git a/src/components/BootstrapBlazor.Dom2Image/wwwroot/dom2image.js b/src/components/BootstrapBlazor.Dom2Image/wwwroot/dom2image.js index e11bf5ef..21f4b3d9 100644 --- a/src/components/BootstrapBlazor.Dom2Image/wwwroot/dom2image.js +++ b/src/components/BootstrapBlazor.Dom2Image/wwwroot/dom2image.js @@ -1,4 +1,4 @@ -import { snapdom } from './lib/snapdom.min.mjs' +import { snapdom } from './lib/snapdom.mjs' export async function getUrl(selector, options) { let data = null; diff --git a/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.min.mjs b/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.min.mjs deleted file mode 100644 index 61929a31..00000000 --- a/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.min.mjs +++ /dev/null @@ -1,8 +0,0 @@ -var w={image:new Map,background:new Map,resource:new Map,defaultStyle:new Map,baseStyle:new Map,computedStyle:new WeakMap,font:new Set,session:{styleMap:new Map,styleCache:new WeakMap,nodeMap:new Map}};function Mt(t="soft"){switch(t){case"auto":{w.session.styleMap=new Map,w.session.nodeMap=new Map;return}case"soft":{w.session.styleMap=new Map,w.session.nodeMap=new Map,w.session.styleCache=new WeakMap;return}case"full":return;case"disabled":{w.session.styleMap=new Map,w.session.nodeMap=new Map,w.session.styleCache=new WeakMap,w.computedStyle=new WeakMap,w.baseStyle=new Map,w.defaultStyle=new Map,w.image=new Map,w.background=new Map,w.resource=new Map,w.font=new Set;return}default:{w.session.styleMap=new Map,w.session.nodeMap=new Map,w.session.styleCache=new WeakMap;return}}}function tt(t){let e=t.match(/url\((['"]?)(.*?)(\1)\)/);if(!e)return null;let n=e[2].trim();return n.startsWith("#")?null:n}function jt(t){if(!t||t==="none")return"";let e=t.replace(/translate[XY]?\([^)]*\)/g,"");return e=e.replace(/matrix\(([^)]+)\)/g,(n,r)=>{let o=r.split(",").map(a=>a.trim());return o.length!==6?`matrix(${r})`:(o[4]="0",o[5]="0",`matrix(${o.join(", ")})`)}),e=e.replace(/matrix3d\(([^)]+)\)/g,(n,r)=>{let o=r.split(",").map(a=>a.trim());return o.length!==16?`matrix3d(${r})`:(o[12]="0",o[13]="0",`matrix3d(${o.join(", ")})`)}),e.trim().replace(/\s{2,}/g," ")}function Y(t){if(/%[0-9A-Fa-f]{2}/.test(t))return t;try{return encodeURI(t)}catch{return t}}function on(t="[snapDOM]",{ttlMs:e=5*6e4,maxEntries:n=12}={}){let r=new Map,o=0;function a(s,l,i){if(o>=n)return;let c=Date.now();(r.get(l)||0)>c||(r.set(l,c+e),o++,s==="warn"&&console&&console.warn?console.warn(`${t} ${i}`):console&&console.error&&console.error(`${t} ${i}`))}return{warnOnce(s,l){a("warn",s,l)},errorOnce(s,l){a("error",s,l)},reset(){r.clear(),o=0}}}var pe=on("[snapDOM]",{ttlMs:3*6e4,maxEntries:10}),Vt=new Map,kt=new Map;function sn(t){return/^data:|^blob:|^about:blank$/i.test(t)}function an(t,e){try{let n=typeof location<"u"&&location.href?location.href:"http://localhost/",r=e.includes("{url}")?e.split("{url}")[0]:e,o=new URL(r||".",n),a=new URL(t,n);if(a.origin===o.origin)return!0;let s=a.searchParams;if(s&&(s.has("url")||s.has("target")))return!0}catch{}return!1}function cn(t,e){if(!e||sn(t)||an(t,e))return!1;try{let n=typeof location<"u"&&location.href?location.href:"http://localhost/",r=new URL(t,n);return typeof location<"u"?r.origin!==location.origin:!0}catch{return!!e}}function ln(t,e){if(!e)return t;if(e.includes("{url}"))return e.replace("{urlRaw}",Y(t)).replace("{url}",encodeURIComponent(t));if(/[?&]url=?$/.test(e))return`${e}${encodeURIComponent(t)}`;if(e.endsWith("?"))return`${e}url=${encodeURIComponent(t)}`;if(e.endsWith("/"))return`${e}${Y(t)}`;let n=e.includes("?")?"&":"?";return`${e}${n}url=${encodeURIComponent(t)}`}function ge(t){return new Promise((e,n)=>{let r=new FileReader;r.onload=()=>e(String(r.result||"")),r.onerror=()=>n(new Error("read_failed")),r.readAsDataURL(t)})}function un(t,e){return[e.as||"blob",e.timeout??3e3,e.useProxy||"",e.errorTTL??8e3,t].join("|")}async function L(t,e={}){let n=e.as??"blob",r=e.timeout??3e3,o=e.useProxy||"",a=e.errorTTL??8e3,s=e.headers||{},l=!!e.silent;if(/^data:/i.test(t))try{if(n==="text")return{ok:!0,data:String(t),status:200,url:t,fromCache:!1};if(n==="dataURL")return{ok:!0,data:String(t),status:200,url:t,fromCache:!1,mime:String(t).slice(5).split(";")[0]||""};let[,h="",p=""]=String(t).match(/^data:([^,]*),(.*)$/)||[],S=/;base64/i.test(h)?atob(p):decodeURIComponent(p),x=new Uint8Array([...S].map(M=>M.charCodeAt(0))),C=new Blob([x],{type:(h||"").split(";")[0]||""});return{ok:!0,data:C,status:200,url:t,fromCache:!1,mime:C.type||""}}catch{return{ok:!1,data:null,status:0,url:t,fromCache:!1,reason:"special_url_error"}}if(/^blob:/i.test(t))try{let h=await fetch(t);if(!h.ok)return{ok:!1,data:null,status:h.status,url:t,fromCache:!1,reason:"http_error"};let p=await h.blob(),g=p.type||h.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await ge(p),status:h.status,url:t,fromCache:!1,mime:g}:n==="text"?{ok:!0,data:await p.text(),status:h.status,url:t,fromCache:!1,mime:g}:{ok:!0,data:p,status:h.status,url:t,fromCache:!1,mime:g}}catch{return{ok:!1,data:null,status:0,url:t,fromCache:!1,reason:"network"}}if(/^about:blank$/i.test(t))return n==="dataURL"?{ok:!0,data:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==",status:200,url:t,fromCache:!1,mime:"image/png"}:{ok:!0,data:n==="text"?"":new Blob([]),status:200,url:t,fromCache:!1};let i=un(t,{as:n,timeout:r,useProxy:o,errorTTL:a}),c=kt.get(i);if(c&&c.until>Date.now())return{...c.result,fromCache:!0};c&&kt.delete(i);let u=Vt.get(i);if(u)return u;let f=cn(t,o)?ln(t,o):t,m=e.credentials;if(!m)try{let h=typeof location<"u"&&location.href?location.href:"http://localhost/",p=new URL(t,h);m=typeof location<"u"&&p.origin===location.origin?"include":"omit"}catch{m="omit"}let y=new AbortController,b=setTimeout(()=>y.abort("timeout"),r),d=(async()=>{try{let h=await fetch(f,{signal:y.signal,credentials:m,headers:s});if(!h.ok){let S={ok:!1,data:null,status:h.status,url:f,fromCache:!1,reason:"http_error"};if(a>0&&kt.set(i,{until:Date.now()+a,result:S}),!l){let x=`${h.status} ${h.statusText||""}`.trim();pe.warnOnce(`http:${h.status}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,`HTTP error ${x} while fetching ${n} ${t}`)}return e.onError&&e.onError(S),S}if(n==="text")return{ok:!0,data:await h.text(),status:h.status,url:f,fromCache:!1};let p=await h.blob(),g=p.type||h.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await ge(p),status:h.status,url:f,fromCache:!1,mime:g}:{ok:!0,data:p,status:h.status,url:f,fromCache:!1,mime:g}}catch(h){let p=h&&typeof h=="object"&&"name"in h&&h.name==="AbortError"?String(h.message||"").includes("timeout")?"timeout":"abort":"network",g={ok:!1,data:null,status:0,url:f,fromCache:!1,reason:p};if(!/^blob:/i.test(t)&&a>0&&kt.set(i,{until:Date.now()+a,result:g}),!l){let S=`${p}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,x=p==="timeout"?`Timeout after ${r}ms. Consider increasing timeout or using a proxy for ${t}`:p==="abort"?`Request aborted while fetching ${n} ${t}`:`Network/CORS issue while fetching ${n} ${t}. A proxy may be required`;pe.errorOnce(S,x)}return e.onError&&e.onError(g),g}finally{clearTimeout(b),Vt.delete(i)}})();return Vt.set(i,d),d}function et(t,e){if(!e||!t.width||!t.height)return t;let n=document.createElement("canvas");n.width=t.width,n.height=t.height;let r=n.getContext("2d");return r.fillStyle=e,r.fillRect(0,0,n.width,n.height),r.drawImage(t,0,0),n}async function nt(t,e={}){if(/^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(t)||t.trim()==="none")return t;let r=tt(t);if(!r)return t;let o=Y(r);if(w.background.has(o)){let a=w.background.get(o);return a?`url("${a}")`:"none"}try{let a=await L(o,{as:"dataURL",useProxy:e.useProxy});return a.ok?(w.background.set(o,a.data),`url("${a.data}")`):(w.background.set(o,null),"none")}catch{return w.background.set(o,null),"none"}}var At=new Set(["meta","script","noscript","title","link","template"]),lt=new Set(["meta","link","style","title","noscript","script","template","g","defs","use","marker","mask","clipPath","pattern","path","polygon","polyline","line","circle","ellipse","rect","filter","lineargradient","radialgradient","stop"]),fn=["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","table","thead","tbody","tr","td","th"];function zt(){for(let t of fn){let e=String(t).toLowerCase();At.has(e)||lt.has(e)||Xt(e)}}function Xt(t){if(t=String(t).toLowerCase(),lt.has(t)){let a={};return w.defaultStyle.set(t,a),a}if(w.defaultStyle.has(t))return w.defaultStyle.get(t);let e=document.getElementById("snapdom-sandbox");e||(e=document.createElement("div"),e.id="snapdom-sandbox",e.setAttribute("data-snapdom-sandbox","true"),e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.left="-9999px",e.style.top="-9999px",e.style.width="0px",e.style.height="0px",e.style.overflow="hidden",document.body.appendChild(e));let n=document.createElement(t);n.style.all="initial",e.appendChild(n);let r=getComputedStyle(n),o={};for(let a of r){if(ye(a))continue;let s=r.getPropertyValue(a);o[a]=s}return e.removeChild(n),w.defaultStyle.set(t,o),o}var dn=/(?:^|-)(animation|transition)(?:-|$)/i,mn=/^(--|view-timeline|scroll-timeline|animation-trigger|offset-|position-try|app-region|interactivity|overlay|view-transition|-webkit-locale|-webkit-user-(?:drag|modify)|-webkit-tap-highlight-color|-webkit-text-security)$/i,hn=new Set(["cursor","pointer-events","touch-action","user-select","print-color-adjust","speak","reading-flow","reading-order","anchor-name","anchor-scope","container-name","container-type","timeline-scope"]);function ye(t){let e=String(t).toLowerCase();return!!(hn.has(e)||mn.test(e)||dn.test(e))}function ut(t,e){if(e=String(e||"").toLowerCase(),lt.has(e))return"";let n=[],r=Xt(e);for(let[o,a]of Object.entries(t)){if(ye(o))continue;let s=r[o];a&&a!==s&&n.push(`${o}:${a}`)}return n.sort(),n.join(";")}function Yt(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(n=>e.add(n.tagName.toLowerCase())),Array.from(e))}function Gt(t){let e=new Map;for(let r of t){let o=w.defaultStyle.get(r);if(!o)continue;let a=Object.entries(o).map(([s,l])=>`${s}:${l};`).sort().join("");a&&(e.has(a)||e.set(a,[]),e.get(a).push(r))}let n="";for(let[r,o]of e.entries())n+=`${o.join(",")} { ${r} } -`;return n}function Kt(t){let e=Array.from(new Set(t.values())).filter(Boolean).sort(),n=new Map,r=1;for(let o of e)n.set(o,`c${r++}`);return n}function rt(t,e=null){if(!(t instanceof Element))return window.getComputedStyle(t,e);let n=w.computedStyle.get(t);if(n||(n=new Map,w.computedStyle.set(t,n)),!n.has(e)){let r=window.getComputedStyle(t,e);n.set(e,r)}return n.get(e)}function $t(t){let e={};for(let n of t)e[n]=t.getPropertyValue(n);return e}function ot(t){let e=[],n=0,r=0;for(let o=0;opt()).observe(t,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}catch{}try{new MutationObserver(()=>pt()).observe(document.head,{subtree:!0,childList:!0,characterData:!0,attributes:!0})}catch{}try{let e=document.fonts;e&&(e.addEventListener?.("loadingdone",pt),e.ready?.then(()=>pt()).catch(()=>{}))}catch{}}}function gn(t,e={}){let n={},r=t.getPropertyValue("visibility");for(let o=0;or[0]o[0]?1:0).map(([r,o])=>`${r}:${o}`).join(";"),Se.set(t,e),e)}function wn(t,e=null,n={}){let r=we.get(t);if(r&&r.epoch===Qt)return r.snapshot;let o=e||getComputedStyle(t),a=gn(o,n);return kn(t,o,a),we.set(t,{epoch:Qt,snapshot:a}),a}function bn(t,e){return t&&t.session&&t.persist?t:t&&(t.styleMap||t.styleCache||t.nodeMap)?{session:t,persist:{snapshotKeyCache:Jt,defaultStyle:w.defaultStyle,baseStyle:w.baseStyle,image:w.image,resource:w.resource,background:w.background,font:w.font},options:e||{}}:{session:w.session,persist:{snapshotKeyCache:Jt,defaultStyle:w.defaultStyle,baseStyle:w.baseStyle,image:w.image,resource:w.resource,background:w.background,font:w.font},options:t||e||{}}}async function st(t,e,n,r){if(t.tagName==="STYLE")return;let o=bn(n,r),a=o.options&&o.options.cache||"auto";if(a!=="disabled"&&pn(document.documentElement),a==="disabled"&&!o.session.__bumpedForDisabled&&(pt(),Jt.clear(),o.session.__bumpedForDisabled=!0),lt.has(t.tagName?.toLowerCase())){let m=t.getAttribute?.("style");m&&e.setAttribute("style",m)}let{session:s,persist:l}=o;s.styleCache.has(t)||s.styleCache.set(t,getComputedStyle(t));let i=s.styleCache.get(t),c=wn(t,i,o.options),u=yn(c),f=l.snapshotKeyCache.get(u);if(!f){let m=t.tagName?.toLowerCase()||"div";f=ut(c,m),l.snapshotKeyCache.set(u,f)}s.styleMap.set(e,f)}function Sn(t){return t instanceof HTMLImageElement||t instanceof HTMLCanvasElement||t instanceof HTMLVideoElement||t instanceof HTMLIFrameElement||t instanceof SVGElement||t instanceof HTMLObjectElement||t instanceof HTMLEmbedElement}function xn(t){return t.backgroundImage&&t.backgroundImage!=="none"||t.backgroundColor&&t.backgroundColor!=="rgba(0, 0, 0, 0)"&&t.backgroundColor!=="transparent"||(parseFloat(t.borderTopWidth)||0)>0||(parseFloat(t.borderBottomWidth)||0)>0||(parseFloat(t.paddingTop)||0)>0||(parseFloat(t.paddingBottom)||0)>0?!0:(t.overflowBlock||t.overflowY||"visible")!=="visible"}function Cn(t){let e=t.parentElement;if(!e)return!1;let n=getComputedStyle(e).display||"";return n.includes("flex")||n.includes("grid")}function Mn(t,e){if(t.textContent&&/\S/.test(t.textContent))return!0;let n=t.firstElementChild,r=t.lastElementChild;if(n&&n.tagName==="BR"||r&&r.tagName==="BR")return!0;let o=t.scrollHeight;if(o===0)return!1;let a=parseFloat(e.paddingTop)||0,s=parseFloat(e.paddingBottom)||0;return o>a+s}function kn(t,e,n){if(t instanceof HTMLElement&&t.style&&t.style.height)return;let r=e.display||"";if(r.includes("flex")||r.includes("grid")||Sn(t))return;let o=e.position;o==="absolute"||o==="fixed"||o==="sticky"||e.transform==="none"&&(xn(e)||Cn(t)||Mn(t,e)&&(delete n.height,delete n["block-size"]))}function xe(t,e){if(!(t instanceof Element)||!(e instanceof Element))return;let n=t.getAttribute?.("style"),r=!!(n&&n.includes("var("));if(!r&&t.attributes?.length){let s=t.attributes;for(let l=0;lnew Promise(o=>{function a(){j(s=>{(s&&typeof s.timeRemaining=="function"?s.timeRemaining()>0:!0)?e(r,o):a()},{fast:n})}a()})))}function An(t){return t=t.trim(),!t||/:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(t)?t:`${t}:not([data-sd-slotted])`}function $n(t,e,n=!0){return t.split(",").map(r=>r.trim()).filter(Boolean).map(r=>{if(r.startsWith(":where(")||r.startsWith("@"))return r;let o=n?An(r):r;return`:where(${e} ${o})`}).join(", ")}function vn(t,e){return t?(t=t.replace(/:host\(([^)]+)\)/g,(n,r)=>`:where(${e}:is(${r.trim()}))`),t=t.replace(/:host\b/g,`:where(${e})`),t=t.replace(/:host-context\(([^)]+)\)/g,(n,r)=>`:where(:where(${r.trim()}) ${e})`),t=t.replace(/::slotted\(([^)]+)\)/g,(n,r)=>`:where(${e} ${r.trim()})`),t=t.replace(/(^|})(\s*)([^@}{]+){/g,(n,r,o,a)=>{let s=$n(a,e,!0);return`${r}${o}${s}{`}),t):""}function En(t){return t.shadowScopeSeq=(t.shadowScopeSeq||0)+1,`s${t.shadowScopeSeq}`}function Fn(t){let e="";try{t.querySelectorAll("style").forEach(r=>{e+=(r.textContent||"")+` -`});let n=t.adoptedStyleSheets||[];for(let r of n)try{if(r&&r.cssRules)for(let o of r.cssRules)e+=o.cssText+` -`}catch{}}catch{}return e}function Nn(t,e,n){if(!e)return;let r=document.createElement("style");r.setAttribute("data-sd",n),r.textContent=e,t.insertBefore(r,t.firstChild||null)}function Ln(t,e){try{let n=t.currentSrc||t.src||"";if(!n)return;e.setAttribute("src",n),e.removeAttribute("srcset"),e.removeAttribute("sizes"),e.loading="eager",e.decoding="sync"}catch{}}function Rn(t){let e=new Set;if(!t)return e;let n=/var\(\s*(--[A-Za-z0-9_-]+)\b/g,r;for(;r=n.exec(t);)e.add(r[1]);return e}function In(t,e){try{let r=getComputedStyle(t).getPropertyValue(e).trim();if(r)return r}catch{}try{let r=getComputedStyle(document.documentElement).getPropertyValue(e).trim();if(r)return r}catch{}return""}function Tn(t,e,n){let r=[];for(let o of e){let a=In(t,o);a&&r.push(`${o}: ${a};`)}return r.length?`${n}{${r.join("")}} -`:""}function Pn(t){t&&(t.nodeType===Node.ELEMENT_NODE&&t.setAttribute("data-sd-slotted",""),t.querySelectorAll&&t.querySelectorAll("*").forEach(e=>e.setAttribute("data-sd-slotted","")))}async function _n(t,e=3){let n=()=>{try{return t.contentDocument||t.contentWindow?.document||null}catch{return null}},r=n(),o=0;for(;osetTimeout(a,0)),r=n(),o++;return r&&(r.body||r.documentElement)?r:null}function Wn(t){let e=t.getBoundingClientRect(),n=0,r=0,o=0,a=0;try{let i=getComputedStyle(t);n=parseFloat(i.borderLeftWidth)||0,r=parseFloat(i.borderRightWidth)||0,o=parseFloat(i.borderTopWidth)||0,a=parseFloat(i.borderBottomWidth)||0}catch{}let s=Math.max(0,Math.round(e.width-(n+r))),l=Math.max(0,Math.round(e.height-(o+a)));return{contentWidth:s,contentHeight:l,rect:e}}function Un(t,e,n){let r=t.createElement("style");return r.setAttribute("data-sd-iframe-pin",""),r.textContent=`html, body {margin: 0 !important;padding: 0 !important;width: ${e}px !important;height: ${n}px !important;min-width: ${e}px !important;min-height: ${n}px !important;box-sizing: border-box !important;overflow: hidden !important;background-clip: border-box !important;}`,(t.head||t.documentElement).appendChild(r),()=>{try{r.remove()}catch{}}}async function Bn(t,e,n){let r=await _n(t,3);if(!r)throw new Error("iframe document not accessible/ready");let{contentWidth:o,contentHeight:a,rect:s}=Wn(t),l=n?.snap;if(!l||typeof l.toPng!="function")throw new Error("snapdom.toPng not available in iframe or window");let i={...n,scale:1},c=Un(r,o,a),u;try{u=await l.toPng(r.documentElement,i)}finally{c()}u.style.display="block",u.style.width=`${o}px`,u.style.height=`${a}px`;let f=document.createElement("div");return e.nodeMap.set(f,t),st(t,f,e,n),f.style.overflow="hidden",f.style.display="block",f.style.width||(f.style.width=`${Math.round(s.width)}px`),f.style.height||(f.style.height=`${Math.round(s.height)}px`),f.appendChild(u),f}async function gt(t,e,n){if(!t)throw new Error("Invalid node");let r=new Set,o=null,a=null;if(t.nodeType===Node.ELEMENT_NODE){let c=(t.localName||t.tagName||"").toLowerCase();if(t.id==="snapdom-sandbox"||t.hasAttribute("data-snapdom-sandbox")||At.has(c))return null}if(t.nodeType===Node.TEXT_NODE||t.nodeType!==Node.ELEMENT_NODE)return t.cloneNode(!0);if(t.getAttribute("data-capture")==="exclude"){if(n.excludeMode==="hide"){let c=document.createElement("div"),u=t.getBoundingClientRect();return c.style.cssText=`display:inline-block;width:${u.width}px;height:${u.height}px;visibility:hidden;`,c}else if(n.excludeMode==="remove")return null}if(n.exclude&&Array.isArray(n.exclude))for(let c of n.exclude)try{if(t.matches?.(c)){if(n.excludeMode==="hide"){let u=document.createElement("div"),f=t.getBoundingClientRect();return u.style.cssText=`display:inline-block;width:${f.width}px;height:${f.height}px;visibility:hidden;`,u}else if(n.excludeMode==="remove")return null}}catch(u){console.warn(`Invalid selector in exclude option: ${c}`,u)}if(typeof n.filter=="function")try{if(!n.filter(t)){if(n.filterMode==="hide"){let c=document.createElement("div"),u=t.getBoundingClientRect();return c.style.cssText=`display:inline-block;width:${u.width}px;height:${u.height}px;visibility:hidden;`,c}else if(n.filterMode==="remove")return null}}catch(c){console.warn("Error in filter function:",c)}if(t.tagName==="IFRAME"){let c=!1;try{c=!!(t.contentDocument||t.contentWindow?.document)}catch{c=!1}if(c)try{return await Bn(t,e,n)}catch(u){console.warn("[SnapDOM] iframe rasterization failed, fallback:",u)}if(n.placeholders){let u=document.createElement("div");return u.style.cssText=`width:${t.offsetWidth}px;height:${t.offsetHeight}px;background-image:repeating-linear-gradient(45deg,#ddd,#ddd 5px,#f9f9f9 5px,#f9f9f9 10px);display:flex;align-items:center;justify-content:center;font-size:12px;color:#555;border:1px solid #aaa;`,st(t,u,e,n),u}else{let u=t.getBoundingClientRect(),f=document.createElement("div");return f.style.cssText=`display:inline-block;width:${u.width}px;height:${u.height}px;visibility:hidden;`,st(t,f,e,n),f}}if(t.getAttribute("data-capture")==="placeholder"){let c=t.cloneNode(!1);e.nodeMap.set(c,t),st(t,c,e,n);let u=document.createElement("div");return u.textContent=t.getAttribute("data-placeholder-text")||"",u.style.cssText="color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;",c.appendChild(u),c}if(t.tagName==="CANVAS"){let c=t.toDataURL(),u=document.createElement("img");return u.src=c,u.width=t.width,u.height=t.height,e.nodeMap.set(u,t),st(t,u,e,n),u}let s;try{if(s=t.cloneNode(!1),xe(t,s),e.nodeMap.set(s,t),t.tagName==="IMG"){Ln(t,s);try{let c=t.getBoundingClientRect(),u=Math.round(c.width||0),f=Math.round(c.height||0);if(!u||!f){let m=window.getComputedStyle(t),y=parseFloat(m.width)||0,b=parseFloat(m.height)||0,d=parseInt(t.getAttribute("width")||"",10)||0,h=parseInt(t.getAttribute("height")||"",10)||0,p=t.width||t.naturalWidth||0,g=t.height||t.naturalHeight||0;u=Math.round(u||y||d||p||0),f=Math.round(f||b||h||g||0)}u&&(s.dataset.snapdomWidth=String(u)),f&&(s.dataset.snapdomHeight=String(f))}catch{}}}catch(c){throw console.error("[Snapdom] Failed to clone node:",t,c),c}if(t instanceof HTMLTextAreaElement){let c=t.getBoundingClientRect();s.style.width=`${c.width}px`,s.style.height=`${c.height}px`}if(t instanceof HTMLInputElement&&(s.value=t.value,s.setAttribute("value",t.value),t.checked!==void 0&&(s.checked=t.checked,t.checked&&s.setAttribute("checked",""),t.indeterminate&&(s.indeterminate=t.indeterminate))),t instanceof HTMLSelectElement&&(o=t.value),t instanceof HTMLTextAreaElement&&(a=t.value),st(t,s,e,n),t.shadowRoot){let h=function(g,S){if(g.nodeType===Node.ELEMENT_NODE&&g.tagName==="STYLE")return S(null);gt(g,e,n).then(x=>{S(x||null)}).catch(()=>{S(null)})};try{let g=t.shadowRoot.querySelectorAll("slot");for(let S of g){let x=[];try{x=S.assignedNodes?.({flatten:!0})||S.assignedNodes?.()||[]}catch{x=S.assignedNodes?.()||[]}for(let C of x)r.add(C)}}catch{}let c=En(e),u=`[data-sd="${c}"]`;try{s.setAttribute("data-sd",c)}catch{}let f=Fn(t.shadowRoot),m=vn(f,u),y=Rn(f),b=Tn(t,y,u);Nn(s,b+m,c);let d=document.createDocumentFragment(),p=await Zt(Array.from(t.shadowRoot.childNodes),h,n.fast);d.append(...p.filter(g=>!!g)),s.appendChild(d)}if(t.tagName==="SLOT"){let m=function(b,d){gt(b,e,n).then(h=>{h&&Pn(h),d(h||null)}).catch(()=>{d(null)})},c=t.assignedNodes?.({flatten:!0})||[],u=c.length>0?c:Array.from(t.childNodes),f=document.createDocumentFragment(),y=await Zt(Array.from(u),m,n.fast);return f.append(...y.filter(b=>!!b)),f}function l(c,u){if(r.has(c))return u(null);gt(c,e,n).then(f=>{u(f||null)}).catch(()=>{u(null)})}let i=await Zt(Array.from(t.childNodes),l,n.fast);if(s.append(...i.filter(c=>!!c)),o!==null&&s instanceof HTMLSelectElement){s.value=o;for(let c of s.options)c.value===o?c.setAttribute("selected",""):c.removeAttribute("selected")}return a!==null&&s instanceof HTMLTextAreaElement&&(s.textContent=a),s}var On=[/font\s*awesome/i,/material\s*icons/i,/ionicons/i,/glyphicons/i,/feather/i,/bootstrap\s*icons/i,/remix\s*icons/i,/heroicons/i,/layui/i,/lucide/i],te=[];function Ce(t){let e=Array.isArray(t)?t:[t];for(let n of e)n instanceof RegExp?te.push(n):typeof n=="string"?te.push(new RegExp(n,"i")):console.warn("[snapdom] Ignored invalid iconFont value:",n)}function B(t){let e=typeof t=="string"?t:"",n=[...On,...te];for(let r of n)if(r instanceof RegExp&&r.test(e))return!0;return!!(/icon/i.test(e)||/glyph/i.test(e)||/symbols/i.test(e)||/feather/i.test(e)||/fontawesome/i.test(e))}async function Ae(t,e,n,r=32,o="#000"){e=e.replace(/^['"]+|['"]+$/g,"");let a=window.devicePixelRatio||1;try{await document.fonts.ready}catch{}let s=document.createElement("span");s.textContent=t,s.style.position="absolute",s.style.visibility="hidden",s.style.fontFamily=`"${e}"`,s.style.fontWeight=n||"normal",s.style.fontSize=`${r}px`,s.style.lineHeight="1",s.style.whiteSpace="nowrap",s.style.padding="0",s.style.margin="0",document.body.appendChild(s);let l=s.getBoundingClientRect(),i=Math.ceil(l.width),c=Math.ceil(l.height);document.body.removeChild(s);let u=document.createElement("canvas");u.width=Math.max(1,i*a),u.height=Math.max(1,c*a);let f=u.getContext("2d");return f.scale(a,a),f.font=n?`${n} ${r}px "${e}"`:`${r}px "${e}"`,f.textAlign="left",f.textBaseline="top",f.fillStyle=o,f.fillText(t,0,0),{dataUrl:u.toDataURL(),width:i,height:c}}var Dn=new Set(["serif","sans-serif","monospace","cursive","fantasy","system-ui","emoji","math","fangsong","ui-serif","ui-sans-serif","ui-monospace","ui-rounded"]);function Ft(t){if(!t)return"";for(let e of t.split(",")){let n=e.trim().replace(/^['"]+|['"]+$/g,"");if(n&&!Dn.has(n.toLowerCase()))return n}return""}function vt(t){let e=String(t??"400").trim().toLowerCase();if(e==="normal")return 400;if(e==="bold")return 700;let n=parseInt(e,10);return Number.isFinite(n)?Math.min(900,Math.max(100,n)):400}function ee(t){let e=String(t??"normal").trim().toLowerCase();return e.startsWith("italic")?"italic":e.startsWith("oblique")?"oblique":"normal"}function Hn(t){let e=String(t??"100%").match(/(\d+(?:\.\d+)?)\s*%/);return e?Math.max(50,Math.min(200,parseFloat(e[1]))):100}function qn(t){let e=String(t||"400").trim(),n=e.match(/^(\d{2,3})\s+(\d{2,3})$/);if(n){let o=vt(n[1]),a=vt(n[2]);return{min:Math.min(o,a),max:Math.max(o,a)}}let r=vt(e);return{min:r,max:r}}function jn(t){let e=String(t||"normal").trim().toLowerCase();return e==="italic"?{kind:"italic"}:e.startsWith("oblique")?{kind:"oblique"}:{kind:"normal"}}function Vn(t){let e=String(t||"100%").trim(),n=e.match(/(\d+(?:\.\d+)?)\s*%\s+(\d+(?:\.\d+)?)\s*%/);if(n){let a=parseFloat(n[1]),s=parseFloat(n[2]);return{min:Math.min(a,s),max:Math.max(a,s)}}let r=e.match(/(\d+(?:\.\d+)?)\s*%/),o=r?parseFloat(r[1]):100;return{min:o,max:o}}function zn(t,e){if(!t)return!1;try{let n=new URL(t,location.href);if(n.origin===location.origin)return!0;let o=n.host.toLowerCase();if(["fonts.googleapis.com","fonts.gstatic.com","use.typekit.net","p.typekit.net","kit.fontawesome.com","use.fontawesome.com"].some(l=>o.endsWith(l)))return!0;let s=(n.pathname+n.search).toLowerCase();if(/\bfont(s)?\b/.test(s)||/\.woff2?(\b|$)/.test(s))return!0;for(let l of e){let i=l.toLowerCase().replace(/\s+/g,"+"),c=l.toLowerCase().replace(/\s+/g,"-");if(s.includes(i)||s.includes(c))return!0}return!1}catch{return!1}}function Xn(t){let e=new Set;for(let n of t||[]){let r=String(n).split("__")[0]?.trim();r&&e.add(r)}return e}function Me(t,e){return t&&t.replace(/url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,(n,r,o)=>{let a=(o||"").trim();if(!a||/^data:|^blob:|^https?:|^file:|^about:/i.test(a))return n;let s=a;try{s=new URL(a,e||location.href).href}catch{}return`url("${s}")`})}var ne=/@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g,Et=4;async function Yn(t,e,n){if(!t)return t;let r=new Set;function o(l,i){try{return new URL(l,i||location.href).href}catch{return l}}async function a(l,i,c=0){if(c>Et)return console.warn(`[snapDOM] @import depth exceeded (${Et}) at ${i}`),l;let u="",f=0,m;for(;m=ne.exec(l);){u+=l.slice(f,m.index),f=ne.lastIndex;let y=(m[2]||m[4]||"").trim(),b=o(y,i);if(r.has(b)){console.warn(`[snapDOM] Skipping circular @import: ${b}`);continue}r.add(b);let d="";try{let h=await L(b,{as:"text",useProxy:n,silent:!0});h.ok&&typeof h.data=="string"&&(d=h.data)}catch{}d?(d=Me(d,b),d=await a(d,b,c+1),u+=` -/* inlined: ${b} */ -${d} -`):u+=m[0]}return u+=l.slice(f),u}let s=Me(t,e||location.href);return s=await a(s,e||location.href,0),s}var $e=/url\((["']?)([^"')]+)\1\)/g,Gn=/@font-face[^{}]*\{[^}]*\}/g;function ve(t){if(!t)return[];let e=[],n=t.split(",").map(r=>r.trim()).filter(Boolean);for(let r of n){let o=r.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);if(!o)continue;let a=o[1],s=o[2],l=i=>{if(!i.includes("?"))return parseInt(i,16);let c=parseInt(i.replace(/\?/g,"0"),16),u=parseInt(i.replace(/\?/g,"F"),16);return[c,u]};if(s){let i=l(a),c=l(s),u=Array.isArray(i)?i[0]:i,f=Array.isArray(c)?c[1]:c;e.push([Math.min(u,f),Math.max(u,f)])}else{let i=l(a);Array.isArray(i)?e.push([i[0],i[1]]):e.push([i,i])}}return e}function Ee(t,e){if(!e.length||!t||t.size===0)return!0;for(let n of t)for(let[r,o]of e)if(n>=r&&n<=o)return!0;return!1}function re(t,e){let n=[];if(!t)return n;for(let r of t.matchAll($e)){let o=(r[2]||"").trim();if(!(!o||o.startsWith("data:"))){if(!/^https?:/i.test(o))try{o=new URL(o,e||location.href).href}catch{}n.push(o)}}return n}async function Fe(t,e,n=""){let r=t;for(let o of t.matchAll($e)){let a=tt(o[0]);if(!a)continue;let s=a;if(!s.startsWith("http")&&!s.startsWith("data:"))try{s=new URL(s,e||location.href).href}catch{}if(!B(s)){if(w.resource?.has(s)){w.font?.add(s),r=r.replace(o[0],`url(${w.resource.get(s)})`);continue}if(!w.font?.has(s))try{let l=await L(s,{as:"dataURL",useProxy:n,silent:!0});if(l.ok&&typeof l.data=="string"){let i=l.data;w.resource?.set(s,i),w.font?.add(s),r=r.replace(o[0],`url(${i})`)}}catch{console.warn("[snapDOM] Failed to fetch font resource:",s)}}}return r}function Kn(t){if(!t.length)return null;let e=(l,i)=>t.some(([c,u])=>!(ui)),n=e(0,255)||e(305,305),r=e(256,591)||e(7680,7935),o=e(880,1023),a=e(1024,1279);return e(7840,7929)||e(258,259)||e(416,417)||e(431,432)?"vietnamese":a?"cyrillic":o?"greek":r?"latin-ext":n?"latin":null}function ke(t={}){let e=new Set((t.families||[]).map(o=>String(o).toLowerCase())),n=new Set((t.domains||[]).map(o=>String(o).toLowerCase())),r=new Set((t.subsets||[]).map(o=>String(o).toLowerCase()));return(o,a)=>{if(e.size&&e.has(o.family.toLowerCase()))return!0;if(n.size)for(let s of o.srcUrls)try{if(n.has(new URL(s).host.toLowerCase()))return!0}catch{}if(r.size){let s=Kn(a);if(s&&r.has(s))return!0}return!1}}function Jn(t){if(!t)return t;let e=/@font-face[^{}]*\{[^}]*\}/gi,n=new Set,r=[];for(let a of t.match(e)||[]){let s=a.match(/font-family:\s*([^;]+);/i)?.[1]||"",l=Ft(s),i=(a.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),c=(a.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),u=(a.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),f=(a.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),m=(a.match(/src\s*:\s*([^;]+);/i)?.[1]||"").trim(),y=re(m,location.href),b=y.length?y.map(h=>String(h).toLowerCase()).sort().join("|"):m.toLowerCase(),d=[String(l||"").toLowerCase(),i,c,u,f.toLowerCase(),b].join("|");n.has(d)||(n.add(d),r.push(a))}if(r.length===0)return t;let o=0;return t.replace(e,()=>r[o++]||"")}function Qn(t,e,n,r){let o=Array.from(t||[]).sort().join("|"),a=e?JSON.stringify({families:(e.families||[]).map(i=>String(i).toLowerCase()).sort(),domains:(e.domains||[]).map(i=>String(i).toLowerCase()).sort(),subsets:(e.subsets||[]).map(i=>String(i).toLowerCase()).sort()}):"",s=(n||[]).map(i=>`${(i.family||"").toLowerCase()}::${i.weight||"normal"}::${i.style||"normal"}::${i.src||""}`).sort().join("|");return`fonts-embed-css::req=${o}::ex=${a}::lf=${s}::px=${r||""}`}async function Ne(t,e,n,r){let o;try{o=t.cssRules||[]}catch{return}let a=(s,l)=>{try{return new URL(s,l||location.href).href}catch{return s}};for(let s of o){if(s.type===CSSRule.IMPORT_RULE&&s.styleSheet){let l=s.href?a(s.href,e):e;if(r.depth>=Et){console.warn(`[snapDOM] CSSOM import depth exceeded (${Et}) at ${l}`);continue}if(l&&r.visitedSheets.has(l)){console.warn(`[snapDOM] Skipping circular CSSOM import: ${l}`);continue}l&&r.visitedSheets.add(l);let i={...r,depth:(r.depth||0)+1};await Ne(s.styleSheet,l,n,i);continue}if(s.type===CSSRule.FONT_FACE_RULE){let l=(s.style.getPropertyValue("font-family")||"").trim(),i=Ft(l);if(!i||B(i))continue;let c=(s.style.getPropertyValue("font-weight")||"400").trim(),u=(s.style.getPropertyValue("font-style")||"normal").trim(),f=(s.style.getPropertyValue("font-stretch")||"100%").trim(),m=(s.style.getPropertyValue("src")||"").trim(),y=(s.style.getPropertyValue("unicode-range")||"").trim();if(!r.faceMatchesRequired(i,u,c,f))continue;let b=ve(y);if(!Ee(r.usedCodepoints,b))continue;let d={family:i,weightSpec:c,styleSpec:u,stretchSpec:f,unicodeRange:y,srcRaw:m,srcUrls:re(m,e||location.href),href:e||location.href};if(r.simpleExcluder&&r.simpleExcluder(d,b))continue;if(/url\(/i.test(m)){let h=await Fe(m,e||location.href,r.useProxy);await n(`@font-face{font-family:${i};src:${h};font-style:${u};font-weight:${c};font-stretch:${f};${y?`unicode-range:${y};`:""}}`)}else await n(`@font-face{font-family:${i};src:${m};font-style:${u};font-weight:${c};font-stretch:${f};${y?`unicode-range:${y};`:""}}`)}}}async function Nt({required:t,usedCodepoints:e,exclude:n=void 0,localFonts:r=[],useProxy:o=""}={}){t instanceof Set||(t=new Set),e instanceof Set||(e=new Set);let a=new Map;for(let d of t){let[h,p,g,S]=String(d).split("__");if(!h)continue;let x=a.get(h)||[];x.push({w:parseInt(p,10),s:g,st:parseInt(S,10)}),a.set(h,x)}function s(d,h,p,g){if(!a.has(d))return!1;let S=a.get(d),x=qn(p),C=jn(h),M=Vn(g),A=x.min!==x.max,P=x.min,W=$=>C.kind==="normal"&&$==="normal"||C.kind!=="normal"&&($==="italic"||$==="oblique"),N=!1;for(let $ of S){let k=A?$.w>=x.min&&$.w<=x.max:$.w===P,_=W(ee($.s)),O=$.st>=M.min&&$.st<=M.max;if(k&&_&&O){N=!0;break}}if(N)return!0;if(!A)for(let $ of S){let k=W(ee($.s)),_=$.st>=M.min&&$.st<=M.max;if(Math.abs(P-$.w)<=300&&k&&_)return!0}return!1}let l=ke(n),i=Qn(t,n,r,o);if(w.resource?.has(i))return w.resource.get(i);let c=Xn(t),u=[],f=ne;for(let d of document.querySelectorAll("style")){let h=d.textContent||"";for(let p of h.matchAll(f)){let g=(p[2]||p[4]||"").trim();if(!g||B(g))continue;!!document.querySelector(`link[rel="stylesheet"][href="${g}"]`)||u.push(g)}}u.length&&await Promise.all(u.map(d=>new Promise(h=>{if(document.querySelector(`link[rel="stylesheet"][href="${d}"]`))return h(null);let p=document.createElement("link");p.rel="stylesheet",p.href=d,p.setAttribute("data-snapdom","injected-import"),p.onload=()=>h(p),p.onerror=()=>h(null),document.head.appendChild(p)})));let m="",y=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(d=>!!d.href);for(let d of y)try{if(B(d.href))continue;let h="",p=!1;try{p=new URL(d.href,location.href).origin===location.origin}catch{}if(!p&&!zn(d.href,c))continue;if(p){let S=Array.from(document.styleSheets).find(x=>x.href===d.href);if(S)try{let x=S.cssRules||[];h=Array.from(x).map(C=>C.cssText).join("")}catch{}}if(!h&&(h=(await L(d.href,{as:"text",useProxy:o})).data,B(d.href)))continue;h=await Yn(h,d.href,o);let g="";for(let S of h.match(Gn)||[]){let x=(S.match(/font-family:\s*([^;]+);/i)?.[1]||"").trim(),C=Ft(x);if(!C||B(C))continue;let M=(S.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),A=(S.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),P=(S.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),W=(S.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),N=(S.match(/src\s*:\s*([^;]+);/i)?.[1]||"").trim(),$=re(N,d.href);if(!s(C,A,M,P))continue;let k=ve(W);if(!Ee(e,k))continue;let _={family:C,weightSpec:M,styleSpec:A,stretchSpec:P,unicodeRange:W,srcRaw:N,srcUrls:$,href:d.href};if(n&&l(_,k))continue;let O=/url\(/i.test(N)?await Fe(S,d.href,o):S;g+=O}g.trim()&&(m+=g)}catch{console.warn("[snapDOM] Failed to process stylesheet:",d.href)}let b={requiredIndex:a,usedCodepoints:e,faceMatchesRequired:s,simpleExcluder:n?ke(n):null,useProxy:o,visitedSheets:new Set,depth:0};for(let d of document.styleSheets)if(!(d.href&&y.some(h=>h.href===d.href)))try{let h=d.href||location.href;h&&b.visitedSheets.add(h),await Ne(d,h,async p=>{m+=p},b)}catch{}try{for(let d of document.fonts||[]){if(!d||!d.family||d.status!=="loaded"||!d._snapdomSrc)continue;let h=String(d.family).replace(/^['"]+|['"]+$/g,"");if(B(h)||!a.has(h)||n?.families&&n.families.some(g=>String(g).toLowerCase()===h.toLowerCase()))continue;let p=d._snapdomSrc;if(!String(p).startsWith("data:")){if(w.resource?.has(d._snapdomSrc))p=w.resource.get(d._snapdomSrc),w.font?.add(d._snapdomSrc);else if(!w.font?.has(d._snapdomSrc))try{let g=await L(d._snapdomSrc,{as:"dataURL",useProxy:o,silent:!0});if(g.ok&&typeof g.data=="string")p=g.data,w.resource?.set(d._snapdomSrc,p),w.font?.add(d._snapdomSrc);else continue}catch{console.warn("[snapDOM] Failed to fetch dynamic font src:",d._snapdomSrc);continue}}m+=`@font-face{font-family:'${h}';src:url(${p});font-style:${d.style||"normal"};font-weight:${d.weight||"normal"};}`}}catch{}for(let d of r){if(!d||typeof d!="object")continue;let h=String(d.family||"").replace(/^['"]+|['"]+$/g,"");if(!h||B(h)||!a.has(h)||n?.families&&n.families.some(M=>String(M).toLowerCase()===h.toLowerCase()))continue;let p=d.weight!=null?String(d.weight):"normal",g=d.style!=null?String(d.style):"normal",S=d.stretchPct!=null?`${d.stretchPct}%`:"100%",x=String(d.src||""),C=x;if(!C.startsWith("data:")){if(w.resource?.has(x))C=w.resource.get(x),w.font?.add(x);else if(!w.font?.has(x))try{let M=await L(x,{as:"dataURL",useProxy:o,silent:!0});if(M.ok&&typeof M.data=="string")C=M.data,w.resource?.set(x,C),w.font?.add(x);else continue}catch{console.warn("[snapDOM] Failed to fetch localFonts src:",x);continue}}m+=`@font-face{font-family:'${h}';src:url(${C});font-style:${g};font-weight:${p};font-stretch:${S};}`}return m&&(m=Jn(m),w.resource?.set(i,m)),m}function Lt(t){let e=new Set;if(!t)return e;let n=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT,null),r=s=>{let l=Ft(s.fontFamily);if(!l)return;let i=(c,u,f)=>`${l}__${vt(c)}__${ee(u)}__${Hn(f)}`;e.add(i(s.fontWeight,s.fontStyle,s.fontStretch))};r(getComputedStyle(t));let o=getComputedStyle(t,"::before");o&&o.content&&o.content!=="none"&&r(o);let a=getComputedStyle(t,"::after");for(a&&a.content&&a.content!=="none"&&r(a);n.nextNode();){let s=n.currentNode,l=getComputedStyle(s);r(l);let i=getComputedStyle(s,"::before");i&&i.content&&i.content!=="none"&&r(i);let c=getComputedStyle(s,"::after");c&&c.content&&c.content!=="none"&&r(c)}return e}function Rt(t){let e=new Set,n=o=>{if(o)for(let a of o)e.add(a.codePointAt(0))},r=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT,null);for(;r.nextNode();){let o=r.currentNode;if(o.nodeType===Node.TEXT_NODE)n(o.nodeValue||"");else if(o.nodeType===Node.ELEMENT_NODE){let a=o;for(let s of["::before","::after"]){let i=getComputedStyle(a,s)?.getPropertyValue("content");if(!(!i||i==="none"))if(/^"/.test(i)||/^'/.test(i))n(i.slice(1,-1));else{let c=i.match(/\\[0-9A-Fa-f]{1,6}/g);if(c)for(let u of c)try{e.add(parseInt(u.slice(1),16))}catch{}}}}}return e}async function It(t,e=2){try{await document.fonts.ready}catch{}let n=Array.from(t||[]).filter(Boolean);if(n.length===0)return;let r=()=>{let o=document.createElement("div");o.style.cssText="position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;";for(let a of n){let s=document.createElement("span");s.textContent="AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E",s.style.fontFamily=`"${a}"`,s.style.fontWeight="700",s.style.fontStyle="italic",s.style.fontSize="32px",s.style.lineHeight="1",s.style.whiteSpace="nowrap",s.style.margin="0",s.style.padding="0",o.appendChild(s)}document.body.appendChild(o),o.offsetWidth,document.body.removeChild(o)};for(let o=0;orequestAnimationFrame(()=>requestAnimationFrame(a)))}function Te(t){return/\bcounter\s*\(|\bcounters\s*\(/.test(t||"")}function Zn(t){return(t||"").replace(/"([^"]*)"/g,"$1")}function Le(t,e=!1){let n="",r=Math.max(1,t);for(;r>0;)r--,n=String.fromCharCode(97+r%26)+n,r=Math.floor(r/26);return e?n.toUpperCase():n}function Re(t,e=!0){let n=[[1e3,"M"],[900,"CM"],[500,"D"],[400,"CD"],[100,"C"],[90,"XC"],[50,"L"],[40,"XL"],[10,"X"],[9,"IX"],[5,"V"],[4,"IV"],[1,"I"]],r=Math.max(1,Math.min(3999,t)),o="";for(let[a,s]of n)for(;r>=a;)o+=s,r-=a;return e?o:o.toLowerCase()}function Ie(t,e){switch((e||"decimal").toLowerCase()){case"decimal":return String(Math.max(0,t));case"decimal-leading-zero":return(t<10?"0":"")+String(Math.max(0,t));case"lower-alpha":return Le(t,!1);case"upper-alpha":return Le(t,!0);case"lower-roman":return Re(t,!1);case"upper-roman":return Re(t,!0);default:return String(Math.max(0,t))}}function Pe(t){let e=new WeakMap,n=t instanceof Document?t.documentElement:t,r=c=>c&&c.tagName==="LI",o=c=>{let u=0,f=c?.parentElement;if(!f)return 0;for(let m of f.children){if(m===c)break;m.tagName==="LI"&&u++}return u},a=c=>{let u=new Map;for(let[f,m]of c)u.set(f,m.slice());return u},s=(c,u,f)=>{let m=a(c),y;try{y=f.style?.counterReset||getComputedStyle(f).counterReset}catch{}if(y&&y!=="none")for(let d of y.split(",")){let h=d.trim().split(/\s+/),p=h[0],g=Number.isFinite(Number(h[1]))?Number(h[1]):0;if(!p)continue;let S=u.get(p);if(S&&S.length){let x=S.slice();x.push(g),m.set(p,x)}else m.set(p,[g])}let b;try{b=f.style?.counterIncrement||getComputedStyle(f).counterIncrement}catch{}if(b&&b!=="none")for(let d of b.split(",")){let h=d.trim().split(/\s+/),p=h[0],g=Number.isFinite(Number(h[1]))?Number(h[1]):1;if(!p)continue;let S=m.get(p)||[];S.length===0&&S.push(0),S[S.length-1]+=g,m.set(p,S)}try{if(getComputedStyle(f).display==="list-item"&&r(f)){let h=f.parentElement,p=1;if(h&&h.tagName==="OL"){let S=h.getAttribute("start"),x=Number.isFinite(Number(S))?Number(S):1,C=o(f),M=f.getAttribute("value");p=Number.isFinite(Number(M))?Number(M):x+C}else p=1+o(f);let g=m.get("list-item")||[];g.length===0&&g.push(0),g[g.length-1]=p,m.set("list-item",g)}}catch{}return m},l=(c,u,f)=>{let m=s(f,u,c);e.set(c,m);let y=m;for(let b of c.children)y=l(b,m,y);return m},i=new Map;return l(n,i,i),{get(c,u){let f=e.get(c)?.get(u);return f&&f.length?f[f.length-1]:0},getStack(c,u){let f=e.get(c)?.get(u);return f?f.slice():[]}}}function _e(t,e,n){if(!t||t==="none")return t;try{let r=/\b(counter|counters)\s*\(([^)]+)\)/g,o=t.replace(r,(a,s,l)=>{let i=String(l).split(",").map(c=>c.trim());if(s==="counter"){let c=i[0]?.replace(/^["']|["']$/g,""),u=(i[1]||"decimal").toLowerCase(),f=n.get(e,c);return Ie(f,u)}else{let c=i[0]?.replace(/^["']|["']$/g,""),u=i[1]?.replace(/^["']|["']$/g,"")??"",f=(i[2]||"decimal").toLowerCase(),m=n.getStack(e,c);return m.length?m.map(b=>Ie(b,f)).join(u):""}});return Zn(o)}catch{return"- "}}var yt=null,wt=new WeakMap;function tr(t){return(t||"").replace(/"([^"]*)"/g,"$1")}function er(t){if(!t)return"";let e=[],n=/"([^"]*)"/g,r;for(;r=n.exec(t);)e.push(r[1]);return e.length?e.join(""):tr(t)}function oe(t,e){let n=t.parentElement,r=n?wt.get(n):null;return r?{get(o,a){let s=e.get(o,a),l=r.get(a);return typeof l=="number"?Math.max(s,l):s},getStack(o,a){let s=e.getStack(o,a);if(!s.length)return s;let l=r.get(a);if(typeof l=="number"){let i=s.slice();return i[i.length-1]=Math.max(i[i.length-1],l),i}return s}}:e}function se(t,e,n){let r=new Map;function o(i){let c=[];if(!i||i==="none")return c;for(let u of String(i).split(",")){let f=u.trim().split(/\s+/),m=f[0],y=Number.isFinite(Number(f[1]))?Number(f[1]):void 0;m&&c.push({name:m,num:y})}return c}let a=o(e?.counterReset),s=o(e?.counterIncrement);function l(i){if(r.has(i))return r.get(i).slice();let c=n.getStack(t,i);c=c.length?c.slice():[];let u=a.find(m=>m.name===i);if(u){let m=Number.isFinite(u.num)?u.num:0;c=c.length?[...c,m]:[m]}let f=s.find(m=>m.name===i);if(f){let m=Number.isFinite(f.num)?f.num:1;c.length===0&&(c=[0]),c[c.length-1]+=m}return r.set(i,c.slice()),c}return{get(i,c){let u=l(c);return u.length?u[u.length-1]:0},getStack(i,c){return l(c)},__incs:s}}function nr(t,e,n){let r;try{r=getComputedStyle(t,e)}catch{}let o=r?.content;if(!o||o==="none"||o==="normal")return{text:"",incs:[]};let a=oe(t,n),s=se(t,r,a),l=Te(o)?_e(o,t,s):o;return{text:er(l),incs:s.__incs||[]}}async function ae(t,e,n,r){if(!(t instanceof Element)||!(e instanceof Element))return;if(!yt)try{yt=Pe(t.ownerDocument||document)}catch{}for(let s of["::before","::after","::first-letter"])try{let l=rt(t,s);if(!l||typeof l[Symbol.iterator]!="function"||l.content==="none"&&l.backgroundImage==="none"&&l.backgroundColor==="transparent"&&(l.borderStyle==="none"||parseFloat(l.borderWidth)===0)&&(!l.transform||l.transform==="none")&&l.display==="inline")continue;if(s==="::first-letter"){let v=getComputedStyle(t);if(!(l.color!==v.color||l.fontSize!==v.fontSize||l.fontWeight!==v.fontWeight))continue;let R=Array.from(e.childNodes).find(ft=>ft.nodeType===Node.TEXT_NODE&&ft.textContent?.trim().length>0);if(!R)continue;let I=R.textContent,H=I.match(/^([^\p{L}\p{N}\s]*[\p{L}\p{N}](?:['’])?)/u)?.[0],it=I.slice(H?.length||0);if(!H||/[\uD800-\uDFFF]/.test(H))continue;let J=document.createElement("span");J.textContent=H,J.dataset.snapdomPseudo="::first-letter";let xt=$t(l),Bt=ut(xt,"span");n.styleMap.set(J,Bt);let Ct=document.createTextNode(it);e.replaceChild(Ct,R),e.insertBefore(J,Ct);continue}let c=l.content,{text:u,incs:f}=nr(t,s,yt),m=l.backgroundImage,y=l.backgroundColor,b=l.fontFamily,d=parseInt(l.fontSize)||32,h=parseInt(l.fontWeight)||!1,p=l.color||"#000",g=l.borderStyle,S=parseFloat(l.borderWidth),x=l.transform,C=B(b),M=c!=="none"&&u!=="",A=m&&m!=="none",P=y&&y!=="transparent"&&y!=="rgba(0, 0, 0, 0)",W=g&&g!=="none"&&S>0,N=x&&x!=="none";if(!(M||A||P||W||N)){if(f&&f.length&&t.parentElement){let v=wt.get(t.parentElement)||new Map;for(let{name:F}of f){if(!F)continue;let R=oe(t,yt),D=se(t,getComputedStyle(t,s),R).get(t,F);v.set(F,D)}wt.set(t.parentElement,v)}continue}let k=document.createElement("span");k.dataset.snapdomPseudo=s,k.style.verticalAlign="middle",k.style.pointerEvents="none";let _=$t(l),O=ut(_,"span");if(n.styleMap.set(k,O),C&&u&&u.length===1){let{dataUrl:v,width:F,height:R}=await Ae(u,b,h,d,p),I=document.createElement("img");I.src=v,I.style=`height:${d}px;width:${F/R*d}px;object-fit:contain;`,k.appendChild(I),e.dataset.snapdomHasIcon="true"}else if(u&&u.startsWith("url(")){let v=tt(u);if(v?.trim())try{let F=document.createElement("img"),R=await L(Y(v),{as:"dataURL",useProxy:r.useProxy});F.src=R.data,F.style=`width:${d}px;height:auto;object-fit:contain;`,k.appendChild(F)}catch(F){console.error(`[snapdom] Error in pseudo ${s} for`,t,F)}}else!C&&M&&(k.textContent=u);if(k.style.background="none","mask"in k.style&&(k.style.mask="none"),A)try{let v=ot(m),F=await Promise.all(v.map(nt));k.style.backgroundImage=F.join(", ")}catch(v){console.warn(`[snapdom] Failed to inline background-image for ${s}`,v)}P&&(k.style.backgroundColor=y);let K=k.childNodes.length>0||k.textContent?.trim()!==""||A||P||W||N;if(f&&f.length&&t.parentElement){let v=wt.get(t.parentElement)||new Map,F=oe(t,yt),R=se(t,getComputedStyle(t,s),F);for(let{name:I}of f){if(!I)continue;let D=R.get(t,I);v.set(I,D)}wt.set(t.parentElement,v)}if(!K)continue;s==="::before"?e.insertBefore(k,e.firstChild):e.appendChild(k)}catch(l){console.warn(`[snapdom] Failed to capture ${s} for`,t,l)}let o=Array.from(t.children),a=Array.from(e.children).filter(s=>!s.dataset.snapdomPseudo);for(let s=0;s{let i=l.getAttribute("xlink:href")||l.getAttribute("href");i&&i.startsWith("#")&&e.add(i.slice(1))}),!e.size)return;let n=Array.from(document.querySelectorAll("svg > symbol, svg > defs")),r=n.filter(l=>l.tagName.toLowerCase()==="symbol"),o=n.filter(l=>l.tagName.toLowerCase()==="defs"),a=t.querySelector("svg.inline-defs-container");a||(a=document.createElementNS("http://www.w3.org/2000/svg","svg"),a.setAttribute("aria-hidden","true"),a.setAttribute("style","position: absolute; width: 0; height: 0; overflow: hidden;"),a.classList.add("inline-defs-container"),t.insertBefore(a,t.firstChild));let s=new Set;t.querySelectorAll("symbol[id], defs > *[id]").forEach(l=>{s.add(l.id)}),e.forEach(l=>{if(s.has(l))return;let i=r.find(c=>c.id===l);if(i){a.appendChild(i.cloneNode(!0)),s.add(l);return}for(let c of o){let u=c.querySelector(`#${CSS.escape(l)}`);if(u){let f=a.querySelector("defs");f||(f=document.createElementNS("http://www.w3.org/2000/svg","defs"),a.appendChild(f)),f.appendChild(u.cloneNode(!0)),s.add(l);break}}})}function Be(t,e){if(!t||!e)return;let n=t.scrollTop||0;if(!n)return;getComputedStyle(e).position==="static"&&(e.style.position="relative");let r=t.getBoundingClientRect(),o=t.clientHeight,a="data-snap-ph",s=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT);for(;s.nextNode();){let l=s.currentNode,i=getComputedStyle(l),c=i.position;if(c!=="sticky"&&c!=="-webkit-sticky")continue;let u=Ue(i.top),f=Ue(i.bottom);if(u==null&&f==null)continue;let m=rr(l,t),y=or(e,m,a);if(!y)continue;let b=l.getBoundingClientRect(),d=b.width,h=b.height,p=b.left-r.left;if(!(d>0&&h>0)||!Number.isFinite(p))continue;let g=u!=null?u+n:n+(o-h-f);if(!Number.isFinite(g))continue;let S=Number.parseInt(i.zIndex,10),x=Number.isFinite(S),C=x?Math.max(S,1)+1:2,M=x?S-1:0,A=y.cloneNode(!1);A.setAttribute(a,"1"),A.style.position="sticky",A.style.left=`${p}px`,A.style.top=`${g}px`,A.style.width=`${d}px`,A.style.height=`${h}px`,A.style.visibility="hidden",A.style.zIndex=String(M),A.style.overflow="hidden",A.style.background="transparent",A.style.boxShadow="none",A.style.filter="none",y.parentElement?.insertBefore(A,y),y.style.position="absolute",y.style.left=`${p}px`,y.style.top=`${g}px`,y.style.bottom="auto",y.style.zIndex=String(C),y.style.pointerEvents="none"}}function Ue(t){if(!t||t==="auto")return null;let e=Number.parseFloat(t);return Number.isFinite(e)?e:null}function rr(t,e){let n=[];for(let r=t;r&&r!==e;){let o=r.parentElement;if(!o)break;n.push(Array.prototype.indexOf.call(o.children,r)),r=o}return n.reverse()}function or(t,e,n){let r=t;for(let o=0;o`.${c}{${i}}`).join(""),o=a+o;for(let[i,c]of n.styleMap.entries()){if(i.tagName==="STYLE")continue;if(i.getRootNode&&i.getRootNode()instanceof ShadowRoot){i.setAttribute("style",c.replace(/;/g,"; "));continue}let u=s.get(c);u&&i.classList.add(u);let f=i.style?.backgroundImage,m=i.dataset?.snapdomHasIcon;f&&f!=="none"&&(i.style.backgroundImage=f),m&&(i.style.verticalAlign="middle",i.style.display="inline")}for(let[i,c]of n.nodeMap.entries()){let u=c.scrollLeft,f=c.scrollTop;if((u||f)&&i instanceof HTMLElement){i.style.overflow="hidden",i.style.scrollbarWidth="none",i.style.msOverflowStyle="none";let y=document.createElement("div");for(y.style.transform=`translate(${-u}px, ${-f}px)`,y.style.willChange="transform",y.style.display="inline-block",y.style.width="100%";i.firstChild;)y.appendChild(i.firstChild);i.appendChild(y)}}let l=r instanceof HTMLElement&&r.firstElementChild instanceof HTMLElement?r.firstElementChild:r;if(Be(t,l),t===n.nodeMap.get(r)){let i=n.styleCache.get(t)||window.getComputedStyle(t);n.styleCache.set(t,i);let c=jt(i.transform);r.style.margin="0",r.style.top="auto",r.style.left="auto",r.style.right="auto",r.style.bottom="auto",r.style.animation="none",r.style.transition="none",r.style.willChange="auto",r.style.float="none",r.style.clear="none",r.style.transform=c||""}for(let[i,c]of n.nodeMap.entries())c.tagName==="PRE"&&(i.style.marginTop="0",i.style.marginBlockStart="0");return{clone:r,classCSS:o,styleCache:n.styleCache}}function ar(t){let e=getComputedStyle(t),n=e.outlineStyle,r=e.outlineWidth,o=e.borderStyle,a=e.borderWidth,s=n!=="none"&&parseFloat(r)>0,l=o==="none"||parseFloat(a)===0;s&&l&&(t.style.border=`${r} solid transparent`)}var bt=new Map;async function St(t){if(w.resource?.has(t))return w.resource.get(t);if(bt.has(t))return bt.get(t);let e=(async()=>{let n=await L(t,{as:"dataURL",silent:!0});if(!n.ok||typeof n.data!="string")throw new Error(`[snapDOM] Failed to read blob URL: ${t}`);return w.resource?.set(t,n.data),n.data})();bt.set(t,e);try{let n=await e;return bt.set(t,n),n}catch(n){throw bt.delete(t),n}}var ir=/\bblob:[^)"'\s]+/g;async function Oe(t){if(!t||t.indexOf("blob:")===-1)return t;let e=Array.from(new Set(t.match(ir)||[]));if(e.length===0)return t;let n=t;for(let r of e)try{let o=await St(r);n=n.split(r).join(o)}catch{}return n}function Tt(t){return typeof t=="string"&&t.startsWith("blob:")}function cr(t){return(t||"").split(",").map(e=>e.trim()).filter(Boolean).map(e=>{let n=e.match(/^(\S+)(\s+.+)?$/);return n?{url:n[1],desc:n[2]||""}:null}).filter(Boolean)}function lr(t){return t.map(e=>e.desc?`${e.url} ${e.desc.trim()}`:e.url).join(", ")}async function ur(t){if(!t)return;let e=t.querySelectorAll?t.querySelectorAll("img"):[];for(let s of e)try{let i=s.getAttribute("src")||s.currentSrc||"";if(Tt(i)){let u=await St(i);s.setAttribute("src",u)}let c=s.getAttribute("srcset");if(c&&c.includes("blob:")){let u=cr(c),f=!1;for(let m of u)if(Tt(m.url))try{m.url=await St(m.url),f=!0}catch{}f&&s.setAttribute("srcset",lr(u))}}catch{}let n=t.querySelectorAll?t.querySelectorAll("image"):[];for(let s of n)try{let l="http://www.w3.org/1999/xlink",i=s.getAttribute("href")||s.getAttributeNS?.(l,"href");if(Tt(i)){let c=await St(i);s.setAttribute("href",c),s.removeAttributeNS?.(l,"href")}}catch{}let r=t.querySelectorAll?t.querySelectorAll("[style*='blob:']"):[];for(let s of r)try{let l=s.getAttribute("style");if(l&&l.includes("blob:")){let i=await Oe(l);s.setAttribute("style",i)}}catch{}let o=t.querySelectorAll?t.querySelectorAll("style"):[];for(let s of o)try{let l=s.textContent||"";l.includes("blob:")&&(s.textContent=await Oe(l))}catch{}let a=["poster"];for(let s of a){let l=t.querySelectorAll?t.querySelectorAll(`[${s}^='blob:']`):[];for(let i of l)try{let c=i.getAttribute(s);Tt(c)&&i.setAttribute(s,await St(c))}catch{}}}async function He(t,e={}){let n=Array.from(t.querySelectorAll("img")),r=async o=>{if(!o.getAttribute("src")){let u=o.currentSrc||o.src||"";u&&o.setAttribute("src",u)}o.removeAttribute("srcset"),o.removeAttribute("sizes");let a=o.src||"";if(!a)return;let s=await L(a,{as:"dataURL",useProxy:e.useProxy});if(s.ok&&typeof s.data=="string"&&s.data.startsWith("data:")){o.src=s.data,o.width||(o.width=o.naturalWidth||100),o.height||(o.height=o.naturalHeight||100);return}let{fallbackURL:l}=e||{};if(l)try{let u=parseInt(o.dataset?.snapdomWidth||"",10)||0,f=parseInt(o.dataset?.snapdomHeight||"",10)||0,m=parseInt(o.getAttribute("width")||"",10)||0,y=parseInt(o.getAttribute("height")||"",10)||0,b=parseFloat(o.style?.width||"")||0,d=parseFloat(o.style?.height||"")||0,h=u||b||m||o.width||void 0,p=f||d||y||o.height||void 0,g=typeof l=="function"?await l({width:h,height:p,src:a,element:o}):l;if(g){let S=await L(g,{as:"dataURL",useProxy:e.useProxy});o.src=S.data,!o.width&&h&&(o.width=h),!o.height&&p&&(o.height=p),o.width||(o.width=o.naturalWidth||100),o.height||(o.height=o.naturalHeight||100);return}}catch{}let i=o.width||o.naturalWidth||100,c=o.height||o.naturalHeight||100;if(e.placeholders!==!1){let u=document.createElement("div");u.style.cssText=[`width:${i}px`,`height:${c}px`,"background:#ccc","display:inline-block","text-align:center",`line-height:${c}px`,"color:#666","font-size:12px","overflow:hidden"].join(";"),u.textContent="img",o.replaceWith(u)}else{let u=document.createElement("div");u.style.cssText=`display:inline-block;width:${i}px;height:${c}px;visibility:hidden;`,o.replaceWith(u)}};for(let o=0;o{let b=u.getPropertyValue("border-image"),d=u.getPropertyValue("border-image-source");return b&&b!=="none"||d&&d!=="none"})();for(let b of a){let d=u.getPropertyValue(b);if(!d||d==="none")continue;let h=ot(d),p=await Promise.all(h.map(g=>nt(g,r)));p.some(g=>g&&g!=="none"&&!/^url\(undefined/.test(g))&&c.style.setProperty(b,p.join(", "))}for(let b of s){let d=u.getPropertyValue(b);!d||d==="initial"||c.style.setProperty(b,d)}if(f)for(let b of l){let d=u.getPropertyValue(b);!d||d==="initial"||c.style.setProperty(b,d)}let m=Array.from(i.children),y=Array.from(c.children);for(let b=0;b{};let e=fr(t);if(e<=0)return()=>{};if(!hr(t))return()=>{};let n=getComputedStyle(t),r=Math.round(dr(n)*e+mr(n)),o=t.textContent??"",a=o;if(t.scrollHeight<=r+.5)return()=>{};let s=0,l=o.length,i=-1;for(;s<=l;){let c=s+l>>1;t.textContent=o.slice(0,c)+"\u2026",t.scrollHeight<=r+.5?(i=c,s=c+1):l=c-1}return t.textContent=(i>=0?o.slice(0,i):"")+"\u2026",()=>{t.textContent=a}}function fr(t){let e=getComputedStyle(t),n=e.getPropertyValue("-webkit-line-clamp")||e.getPropertyValue("line-clamp");n=(n||"").trim();let r=parseInt(n,10);return Number.isFinite(r)&&r>0?r:0}function dr(t){let e=(t.lineHeight||"").trim(),n=parseFloat(t.fontSize)||16;return!e||e==="normal"?Math.round(n*1.2):e.endsWith("px")?parseFloat(e):/^\d+(\.\d+)?$/.test(e)?Math.round(parseFloat(e)*n):e.endsWith("%")?Math.round(parseFloat(e)/100*n):Math.round(n*1.2)}function mr(t){return(parseFloat(t.paddingTop)||0)+(parseFloat(t.paddingBottom)||0)}function hr(t){return t.childElementCount>0?!1:Array.from(t.childNodes).some(e=>e.nodeType===Node.TEXT_NODE)}function pr(t,e){if(!t||!e||!e.style)return;let n=getComputedStyle(t);try{e.style.boxShadow="none"}catch{}try{e.style.textShadow="none"}catch{}try{e.style.outline="none"}catch{}let o=(n.filter||"").replace(/\bblur\([^()]*\)\s*/gi,"").replace(/\bdrop-shadow\([^()]*\)\s*/gi,"").trim().replace(/\s+/g," ");try{e.style.filter=o.length?o:"none"}catch{}}async function ce(t,e){if(!t)throw new Error("Element cannot be null or undefined");Mt(e.cache);let n=e.fast,r=!!e.straighten,o=!!e.noShadows,a,s,l,i="",c="",u,f,m=null,y=qe(t);try{({clone:a,classCSS:s,styleCache:l}=await De(t,e)),r&&a&&(m=gr(t,a)),o&&a&&pr(t,a)}finally{y()}await new Promise(p=>{j(async()=>{await He(a,e),p()},{fast:n})}),await new Promise(p=>{j(async()=>{await Pt(t,a,l,e),p()},{fast:n})}),e.embedFonts&&await new Promise(p=>{j(async()=>{let g=Lt(t),S=Rt(t);if(T()){let x=new Set(Array.from(g).map(C=>String(C).split("__")[0]).filter(Boolean));await It(x,1)}i=await Nt({required:g,usedCodepoints:S,preCached:!1,exclude:e.excludeFonts,useProxy:e.useProxy}),p()},{fast:n})});let b=Yt(a).sort(),d=b.join(",");w.baseStyle.has(d)?c=w.baseStyle.get(d):await new Promise(p=>{j(()=>{c=Gt(b),w.baseStyle.set(d,c),p()},{fast:n})}),await new Promise(p=>{j(()=>{let g=getComputedStyle(t);function S(q){let U=`${q.filter||""} ${q.webkitFilter||""}`.trim();if(!U||U==="none")return{bleed:{top:0,right:0,bottom:0,left:0},has:!1};let X=U.match(/drop-shadow\((?:[^()]|\([^()]*\))*\)/gi)||[],Q=0,dt=0,mt=0,ht=0,Z=!1;for(let en of X){Z=!0;let nn=en.match(/-?\d+(?:\.\d+)?px/gi)?.map(rn=>parseFloat(rn))||[],[Ht=0,qt=0,de=0]=nn,me=Math.abs(Ht)+de,he=Math.abs(qt)+de;dt=Math.max(dt,me+Math.max(Ht,0)),ht=Math.max(ht,me+Math.max(-Ht,0)),mt=Math.max(mt,he+Math.max(qt,0)),Q=Math.max(Q,he+Math.max(-qt,0))}return{bleed:{top:Math.ceil(Q),right:Math.ceil(dt),bottom:Math.ceil(mt),left:Math.ceil(ht)},has:Z}}let x=t.getBoundingClientRect(),C=Math.max(1,Math.ceil(t.offsetWidth||parseFloat(g.width)||x.width||1)),M=Math.max(1,Math.ceil(t.offsetHeight||parseFloat(g.height)||x.height||1)),A=(q,U=NaN)=>{let X=typeof q=="string"?parseFloat(q):q;return Number.isFinite(X)?X:U},P=A(e.width),W=A(e.height),N=C,$=M,k=Number.isFinite(P),_=Number.isFinite(W),O=M>0?C/M:1;k&&_?(N=Math.max(1,Math.ceil(P)),$=Math.max(1,Math.ceil(W))):k?(N=Math.max(1,Math.ceil(P)),$=Math.max(1,Math.ceil(N/(O||1)))):_?($=Math.max(1,Math.ceil(W)),N=Math.max(1,Math.ceil($*(O||1)))):(N=C,$=M);let at=0,K=0,v=C,F=M;if(r&&m&&Number.isFinite(m.a)){let q={a:m.a,b:m.b||0,c:m.c||0,d:m.d||1,e:0,f:0},U=je(C,M,q,0,0);at=U.minX,K=U.minY,v=U.maxX,F=U.maxY}else if(!r&&Sr(t)){let U=g.transform&&g.transform!=="none"?g.transform:"",X=xr(t),Q=Ar({baseTransform:U,rotate:X.rotate||"0deg",scale:X.scale,translate:X.translate}),{ox:dt,oy:mt}=Mr(g,C,M),ht=Q.is2D?Q:new DOMMatrix(Q.toString()),Z=je(C,M,ht,dt,mt);at=Z.minX,K=Z.minY,v=Z.maxX,F=Z.maxY}let R=yr(g),I=wr(g),D=br(g),H=S(g),it=o?{top:0,right:0,bottom:0,left:0}:{top:R.top+I.top+D.top+H.bleed.top,right:R.right+I.right+D.right+H.bleed.right,bottom:R.bottom+I.bottom+D.bottom+H.bleed.bottom,left:R.left+I.left+D.left+H.bleed.left};at-=it.left,K-=it.top,v+=it.right,F+=it.bottom;let J=Math.max(1,Math.ceil(v-at)),xt=Math.max(1,Math.ceil(F-K)),Bt=Math.max(1,Math.round(J*(k||_?N/C:1))),Ct=Math.max(1,Math.round(xt*(_||k?$/M:1))),ft="http://www.w3.org/2000/svg",V=(T()?1:0)+(r?1:0),z=document.createElementNS(ft,"foreignObject"),Ke=Math.floor(at),Je=Math.floor(K);z.setAttribute("x",String(-(Ke-V))),z.setAttribute("y",String(-(Je-V))),z.setAttribute("width",String(Math.ceil(C+V*2))),z.setAttribute("height",String(Math.ceil(M+V*2))),z.style.overflow="visible";let ue=document.createElement("style");ue.textContent=c+i+"svg{overflow:visible;} foreignObject{overflow:visible;}"+s,z.appendChild(ue);let ct=document.createElement("div");ct.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),ct.style.width=`${C}px`,ct.style.height=`${M}px`,ct.style.overflow="visible",a.setAttribute("xmlns","http://www.w3.org/1999/xhtml"),ct.appendChild(a),z.appendChild(ct);let Qe=new XMLSerializer().serializeToString(z),Ot=J+V*2,Dt=xt+V*2,fe=k||_;e.meta={w0:C,h0:M,vbW:Ot,vbH:Dt,targetW:N,targetH:$};let Ze=T()&&fe?Ot:Bt+V*2,tn=T()&&fe?Dt:Ct+V*2;f=``+Qe+"",u=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(f)}`,p()},{fast:n})});let h=document.getElementById("snapdom-sandbox");return h&&h.style.position==="absolute"&&h.remove(),u}function gr(t,e){if(!t||!e||!e.style)return null;let n=getComputedStyle(t);try{e.style.transformOrigin="0 0"}catch{}try{"translate"in e.style&&(e.style.translate="none"),"rotate"in e.style&&(e.style.rotate="none")}catch{}let r=n.transform||"none";if(!r||r==="none")try{let a=Ve(t);if(a.a===1&&a.b===0&&a.c===0&&a.d===1)return e.style.transform="none",{a:1,b:0,c:0,d:1}}catch{}let o=r.match(/^matrix\(\s*([^)]+)\)$/i);if(o){let a=o[1].split(",").map(s=>parseFloat(s.trim()));if(a.length===6&&a.every(Number.isFinite)){let[s,l,i,c]=a,u=Math.sqrt(s*s+l*l)||0,f=0,m=0,y=0,b=0,d=0,h=0;u>0&&(f=s/u,m=l/u,y=f*i+m*c,b=i-f*y,d=c-m*y,h=Math.sqrt(b*b+d*d)||0,h>0?y=y/h:y=0);let p=u,g=0,S=y*h,x=h;try{e.style.transform=`matrix(${p}, ${g}, ${S}, ${x}, 0, 0)`}catch{}return{a:p,b:g,c:S,d:x}}}try{let a=String(r).trim();return e.style.transform=a+" translate(0px, 0px) rotate(0deg)",null}catch{return null}}function yr(t){let e=t.boxShadow||"";if(!e||e==="none")return{top:0,right:0,bottom:0,left:0};let n=e.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map(l=>l.trim()),r=0,o=0,a=0,s=0;for(let l of n){let i=l.match(/-?\d+(\.\d+)?px/g)?.map(d=>parseFloat(d))||[];if(i.length<2)continue;let[c,u,f=0,m=0]=i,y=Math.abs(c)+f+m,b=Math.abs(u)+f+m;o=Math.max(o,y+Math.max(c,0)),s=Math.max(s,y+Math.max(-c,0)),a=Math.max(a,b+Math.max(u,0)),r=Math.max(r,b+Math.max(-u,0))}return{top:Math.ceil(r),right:Math.ceil(o),bottom:Math.ceil(a),left:Math.ceil(s)}}function wr(t){let e=(t.filter||"").match(/blur\(\s*([0-9.]+)px\s*\)/),n=e?Math.ceil(parseFloat(e[1])||0):0;return{top:n,right:n,bottom:n,left:n}}function br(t){if((t.outlineStyle||"none")==="none")return{top:0,right:0,bottom:0,left:0};let e=Math.ceil(parseFloat(t.outlineWidth||"0")||0);return{top:e,right:e,bottom:e,left:e}}function je(t,e,n,r,o){let a=n.a,s=n.b,l=n.c,i=n.d,c=n.e||0,u=n.f||0;function f(p,g){let S=p-r,x=g-o,C=a*S+l*x,M=s*S+i*x;return C+=r+c,M+=o+u,[C,M]}let m=[f(0,0),f(t,0),f(0,e),f(t,e)],y=1/0,b=1/0,d=-1/0,h=-1/0;for(let[p,g]of m)pd&&(d=p),g>h&&(h=g);return{minX:y,minY:b,maxX:d,maxY:h,width:d-y,height:h-b}}function Sr(t){return Cr(t)}function Ve(t){let e=getComputedStyle(t).transform;if(!e||e==="none")return new DOMMatrix;try{return new DOMMatrix(e)}catch{return new WebKitCSSMatrix(e)}}function xr(t){let e={rotate:"0deg",scale:null,translate:null},n=typeof t.computedStyleMap=="function"?t.computedStyleMap():null;if(n){let o=i=>{try{return typeof n.has=="function"&&!n.has(i)||typeof n.get!="function"?null:n.get(i)}catch{return null}},a=o("rotate");if(a)if(a.angle){let i=a.angle;e.rotate=i.unit==="rad"?i.value*180/Math.PI+"deg":i.value+i.unit}else a.unit?e.rotate=a.unit==="rad"?a.value*180/Math.PI+"deg":a.value+a.unit:e.rotate=String(a);else{let i=getComputedStyle(t);e.rotate=i.rotate&&i.rotate!=="none"?i.rotate:"0deg"}let s=o("scale");if(s){let i="x"in s&&s.x?.value!=null?s.x.value:Array.isArray(s)?s[0]?.value:Number(s)||1,c="y"in s&&s.y?.value!=null?s.y.value:Array.isArray(s)?s[1]?.value:i;e.scale=`${i} ${c}`}else{let i=getComputedStyle(t);e.scale=i.scale&&i.scale!=="none"?i.scale:null}let l=o("translate");if(l){let i="x"in l&&"value"in l.x?l.x.value:Array.isArray(l)?l[0]?.value:0,c="y"in l&&"value"in l.y?l.y.value:Array.isArray(l)?l[1]?.value:0,u="x"in l&&l.x?.unit?l.x.unit:"px",f="y"in l&&l.y?.unit?l.y.unit:"px";e.translate=`${i}${u} ${c}${f}`}else{let i=getComputedStyle(t);e.translate=i.translate&&i.translate!=="none"?i.translate:null}return e}let r=getComputedStyle(t);return e.rotate=r.rotate&&r.rotate!=="none"?r.rotate:"0deg",e.scale=r.scale&&r.scale!=="none"?r.scale:null,e.translate=r.translate&&r.translate!=="none"?r.translate:null,e}function Cr(t){let e=getComputedStyle(t),n=e.transform||"none";if(n!=="none"&&!/^matrix\(\s*1\s*,\s*0\s*,\s*0\s*,\s*1\s*,\s*0\s*,\s*0\s*\)$/i.test(n))return!0;let o=e.rotate&&e.rotate!=="none"&&e.rotate!=="0deg",a=e.scale&&e.scale!=="none"&&e.scale!=="1",s=e.translate&&e.translate!=="none"&&e.translate!=="0px 0px";return!!(o||a||s)}function Mr(t,e,n){let r=(t.transformOrigin||"0 0").trim().split(/\s+/),[o,a]=[r[0]||"0",r[1]||"0"],s=(l,i)=>{let c=l.toLowerCase();return c==="left"||c==="top"?0:c==="center"?i/2:c==="right"||c==="bottom"?i:c.endsWith("px")?parseFloat(c)||0:c.endsWith("%")?(parseFloat(c)||0)*i/100:/^-?\d+(\.\d+)?$/.test(c)&&parseFloat(c)||0};return{ox:s(o,e),oy:s(a,n)}}var ie=null;function kr(){if(ie)return ie;let t=document.createElement("div");return t.id="snapdom-measure-slot",t.setAttribute("aria-hidden","true"),Object.assign(t.style,{position:"absolute",left:"-99999px",top:"0px",width:"0px",height:"0px",overflow:"hidden",opacity:"0",pointerEvents:"none",contain:"size layout style"}),document.documentElement.appendChild(t),ie=t,t}function Ar(t){let e=kr(),n=document.createElement("div");n.style.transformOrigin="0 0",t.baseTransform&&(n.style.transform=t.baseTransform),t.rotate&&(n.style.rotate=t.rotate),t.scale&&(n.style.scale=t.scale),t.translate&&(n.style.translate=t.translate),e.appendChild(n);let r=Ve(n);return e.removeChild(n),r}function $r(t){if(typeof t=="string"){let e=t.toLowerCase().trim();if(e==="disabled"||e==="full"||e==="auto"||e==="soft")return e}return"soft"}function ze(t={}){let e=t.format??"png",n=$r(t.cache);return{debug:t.debug??!1,fast:t.fast??!0,scale:t.scale??1,exclude:t.exclude??[],excludeMode:t.excludeMode??"hide",filter:t.filter??null,filterMode:t.filterMode??"hide",placeholders:t.placeholders!==!1,embedFonts:t.embedFonts??!1,iconFonts:Array.isArray(t.iconFonts)?t.iconFonts:t.iconFonts?[t.iconFonts]:[],localFonts:Array.isArray(t.localFonts)?t.localFonts:[],excludeFonts:t.excludeFonts??void 0,fallbackURL:t.fallbackURL??void 0,cache:n,useProxy:typeof t.useProxy=="string"?t.useProxy:"",width:t.width??null,height:t.height??null,format:e,type:t.type??"svg",quality:t.quality??.92,dpr:t.dpr??(window.devicePixelRatio||1),backgroundColor:t.backgroundColor??(["jpg","jpeg","webp"].includes(e)?"#ffffff":null),filename:t.filename??"snapDOM",straighten:t.straighten??!1,noShadows:t.noShadows??!1}}function vr(t){return typeof t=="string"&&/^data:image\/svg\+xml/i.test(t)}function Er(t){let e=t.indexOf(",");return e>=0?decodeURIComponent(t.slice(e+1)):""}function Fr(t){return`data:image/svg+xml;charset=utf-8,${encodeURIComponent(t)}`}function Nr(t){let e=[],n="",r=0;for(let o=0;oo.trim()).filter(Boolean)}function Lr(t){let e=[],n="",r=0;for(let a=0;a`${l}:${i}`).join(";")}function Rr(t){return t.replace(/([^{}]+)\{([^}]*)\}/g,(e,n,r)=>`${n}{${Xe(r)}}`)}function Ir(t){return t=t.replace(/]*>([\s\S]*?)<\/style>/gi,(e,n)=>e.replace(n,Rr(n))),t=t.replace(/style=(['"])([\s\S]*?)\1/gi,(e,n,r)=>`style=${n}${Xe(r)}${n}`),t}function Tr(t){if(!T()||!vr(t))return t;try{let e=Er(t),n=Ir(e);return Fr(n)}catch{return t}}async function G(t,e){let{width:n,height:r,scale:o=1,dpr:a=1,meta:s={}}=e;t=Tr(t);let l=new Image;l.loading="eager",l.decoding="sync",l.crossOrigin="anonymous",l.src=t,await l.decode();let i=l.naturalWidth,c=l.naturalHeight,u=Number.isFinite(s.w0)?s.w0:i,f=Number.isFinite(s.h0)?s.h0:c,m,y,b=Number.isFinite(n),d=Number.isFinite(r);if(b&&d)m=Math.max(1,n),y=Math.max(1,r);else if(b){let g=n/Math.max(1,u);m=n,y=Math.round(f*g)}else if(d){let g=r/Math.max(1,f);y=r,m=Math.round(u*g)}else m=i,y=c;m=Math.round(m*o),y=Math.round(y*o);let h=document.createElement("canvas");h.width=Math.ceil(m*a),h.height=Math.ceil(y*a),h.style.width=`${m}px`,h.style.height=`${y}px`;let p=h.getContext("2d");return a!==1&&p.scale(a,a),p.drawImage(l,0,0,m,y),h}async function _t(t,e){let n=await G(t,e),r=e.backgroundColor?et(n,e.backgroundColor):n,o=new Image;return o.src=r.toDataURL(`image/${e.format}`,e.quality),await o.decode(),o.style.width=`${r.width/e.dpr}px`,o.style.height=`${r.height/e.dpr}px`,o}async function Wt(t,e){let{scale:n=1,width:r,height:o,meta:a={}}=e,s=Number.isFinite(r),l=Number.isFinite(o),i=Number.isFinite(n)&&n!==1||s||l;if(T()&&i)return await _t(t,{...e,format:"png",quality:1,meta:a});let c=new Image;if(c.decoding="sync",c.loading="eager",c.src=t,await c.decode(),s&&l)c.style.width=`${r}px`,c.style.height=`${o}px`;else if(s){let u=Number.isFinite(a.w0)?a.w0:c.naturalWidth,f=Number.isFinite(a.h0)?a.h0:c.naturalHeight,m=r/Math.max(1,u);c.style.width=`${r}px`,c.style.height=`${Math.round(f*m)}px`}else if(l){let u=Number.isFinite(a.w0)?a.w0:c.naturalWidth,f=Number.isFinite(a.h0)?a.h0:c.naturalHeight,m=o/Math.max(1,f);c.style.height=`${o}px`,c.style.width=`${Math.round(u*m)}px`}else{let u=Math.round(c.naturalWidth*n),f=Math.round(c.naturalHeight*n);if(c.style.width=`${u}px`,c.style.height=`${f}px`,typeof t=="string"&&t.startsWith("data:image/svg+xml"))try{let y=decodeURIComponent(t.split(",")[1]).replace(/width="[^"]*"/,`width="${u}"`).replace(/height="[^"]*"/,`height="${f}"`);t=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(y)}`,c.src=t}catch{}}return c}async function Ut(t,e){let n=e.type;if(n==="svg"){let a=decodeURIComponent(t.split(",")[1]);return new Blob([a],{type:"image/svg+xml"})}let r=await G(t,e),o=e.backgroundColor?et(r,e.backgroundColor):r;return new Promise(a=>o.toBlob(s=>a(s),`image/${n}`,e.quality))}async function Ye(t,e){if(e.dpr=1,e.format==="svg"){let a=await Ut(t,{...e,type:"svg"}),s=URL.createObjectURL(a),l=document.createElement("a");l.href=s,l.download=e.filename,l.click(),URL.revokeObjectURL(s);return}let n=await G(t,e),r=e.backgroundColor?et(n,e.backgroundColor):n,o=document.createElement("a");o.href=r.toDataURL(`image/${e.format}`,e.quality),o.download=e.filename,o.click()}var Ge=Symbol("snapdom.internal"),le=!1;async function E(t,e){if(!t)throw new Error("Element cannot be null or undefined");let n=ze(e);if(T()&&(n.embedFonts===!0||_r(t)))for(let r=0;r<3;r++)try{await Pr(t,e),console.log("Iteraci\xF3n n\xFAmero:",r),le=!1}catch{}return n.iconFonts&&n.iconFonts.length>0&&Ce(n.iconFonts),n.snap||(n.snap={toPng:(r,o)=>E.toPng(r,o),toSvg:(r,o)=>E.toSvg(r,o)}),E.capture(t,n,Ge)}E.capture=async(t,e,n)=>{if(n!==Ge)throw new Error("[snapdom.capture] is internal. Use snapdom(...) instead.");let r=await ce(t,e),o=s=>({...e,...s||{}}),a=s=>l=>{let i=o({...l||{},format:s}),c=s==="jpeg"||s==="jpg",u=i.backgroundColor==null||i.backgroundColor==="transparent";return c&&u&&(i.backgroundColor="#ffffff"),_t(r,i)};return{url:r,toRaw:()=>r,toImg:s=>Wt(r,o(s)),toSvg:s=>Wt(r,o(s)),toCanvas:s=>G(r,o(s)),toBlob:s=>Ut(r,o(s)),toPng:a("png"),toJpg:a("jpeg"),toWebp:a("webp"),download:s=>Ye(r,o(s))}};E.toRaw=(t,e)=>E(t,e).then(n=>n.toRaw());E.toImg=(t,e)=>E(t,e).then(n=>n.toImg());E.toSvg=(t,e)=>E(t,e).then(n=>n.toSvg());E.toCanvas=(t,e)=>E(t,e).then(n=>n.toCanvas());E.toBlob=(t,e)=>E(t,e).then(n=>n.toBlob());E.toPng=(t,e)=>E(t,{...e,format:"png"}).then(n=>n.toPng());E.toJpg=(t,e)=>E(t,{...e,format:"jpeg"}).then(n=>n.toJpg());E.toWebp=(t,e)=>E(t,{...e,format:"webp"}).then(n=>n.toWebp());E.download=(t,e)=>E(t,e).then(n=>n.download());async function Pr(t,e){if(le)return;let n={...e,fast:!0,embedFonts:!0,scale:.2},r;try{r=await ce(t,n)}catch{return}await new Promise(o=>{let a=new Image;a.decoding="sync",a.loading="eager",a.style.position="fixed",a.style.left=0,a.style.top=0,a.style.width="10px",a.style.height="10px",a.style.opacity="0.01",a.style.transform="translateZ(10px)",a.style.willChange="transform,opacity;",a.src=r;let s=async()=>{await new Promise(l=>setTimeout(l,100)),a&&a.parentNode&&a.parentNode.removeChild(a),le=!0,o()};document.body.appendChild(a),s()})}function _r(t){let e=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT);for(;e.nextNode();){let n=e.currentNode,r=getComputedStyle(n),o=r.backgroundImage&&r.backgroundImage!=="none",a=r.maskImage&&r.maskImage!=="none"||r.webkitMaskImage&&r.webkitMaskImage!=="none";if(o||a)return!0}return!1}async function Wr(t=document,e={}){let{embedFonts:n=!0,useProxy:r=""}=e,o=e.cache??e.cacheOpt??"full";Mt(o);try{await document.fonts?.ready}catch{}try{zt()}catch{}w.session=w.session||{},w.session.styleCache||(w.session.styleCache=new WeakMap),w.image=w.image||new Map;try{await Pt(t,void 0,w.session.styleCache,{useProxy:r})}catch{}let a=[],s=[];try{t?.querySelectorAll&&(a=Array.from(t.querySelectorAll("img[src]")),s=Array.from(t.querySelectorAll("*")))}catch{}let l=[];for(let i of a){let c=i?.currentSrc||i?.src;if(c&&!w.image.has(c)){let u=Promise.resolve().then(async()=>{let f=await L(c,{as:"dataURL",useProxy:r});f?.ok&&typeof f.data=="string"&&w.image.set(c,f.data)}).catch(()=>{});l.push(u)}}for(let i of s){let c="";try{c=rt(i).backgroundImage}catch{}if(c&&c!=="none"){let u=ot(c);for(let f of u)if(f.startsWith("url(")){let m=Promise.resolve().then(()=>nt(f,{...e,useProxy:r})).catch(()=>{});l.push(m)}}}if(n)try{let i=Lt(t),c=Rt(t);if(typeof T=="function"?T():!!T){let f=new Set(Array.from(i).map(m=>String(m).split("__")[0]).filter(Boolean));await It(f,3)}await Nt({required:i,usedCodepoints:c,exclude:e.excludeFonts,localFonts:e.localFonts,useProxy:e.useProxy??r})}catch{}await Promise.allSettled(l)}export{Wr as preCache,E as snapdom}; diff --git a/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.mjs b/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.mjs new file mode 100644 index 00000000..c5795729 --- /dev/null +++ b/src/components/BootstrapBlazor.Dom2Image/wwwroot/lib/snapdom.mjs @@ -0,0 +1,5257 @@ +/* +* SnapDOM +* v2.0.0 +* Author: Juan Martin Muda +* License: MIT +*/ +var __defProp = Object.defineProperty; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; + +// src/core/cache.js +function applyCachePolicy(policy = "soft") { + cache.session.__counterEpoch = (cache.session.__counterEpoch || 0) + 1; + switch (policy) { + case "auto": { + cache.session.styleMap = /* @__PURE__ */ new Map(); + cache.session.nodeMap = /* @__PURE__ */ new Map(); + return; + } + case "soft": { + cache.session.styleMap = /* @__PURE__ */ new Map(); + cache.session.nodeMap = /* @__PURE__ */ new Map(); + cache.session.styleCache = /* @__PURE__ */ new WeakMap(); + return; + } + case "full": { + return; + } + case "disabled": { + cache.session.styleMap = /* @__PURE__ */ new Map(); + cache.session.nodeMap = /* @__PURE__ */ new Map(); + cache.session.styleCache = /* @__PURE__ */ new WeakMap(); + cache.computedStyle = /* @__PURE__ */ new WeakMap(); + cache.baseStyle = /* @__PURE__ */ new Map(); + cache.defaultStyle = /* @__PURE__ */ new Map(); + cache.image = /* @__PURE__ */ new Map(); + cache.background = /* @__PURE__ */ new Map(); + cache.resource = /* @__PURE__ */ new Map(); + cache.font = /* @__PURE__ */ new Set(); + return; + } + default: { + cache.session.styleMap = /* @__PURE__ */ new Map(); + cache.session.nodeMap = /* @__PURE__ */ new Map(); + cache.session.styleCache = /* @__PURE__ */ new WeakMap(); + return; + } + } +} +var cache; +var init_cache = __esm({ + "src/core/cache.js"() { + cache = { + image: /* @__PURE__ */ new Map(), + background: /* @__PURE__ */ new Map(), + resource: /* @__PURE__ */ new Map(), + defaultStyle: /* @__PURE__ */ new Map(), + baseStyle: /* @__PURE__ */ new Map(), + computedStyle: /* @__PURE__ */ new WeakMap(), + font: /* @__PURE__ */ new Set(), + session: { + styleMap: /* @__PURE__ */ new Map(), + styleCache: /* @__PURE__ */ new WeakMap(), + nodeMap: /* @__PURE__ */ new Map() + } + }; + } +}); + +// src/utils/helpers.js +function extractURL(value) { + const match = value.match(/url\((['"]?)(.*?)(\1)\)/); + if (!match) return null; + const url = match[2].trim(); + if (url.startsWith("#")) return null; + return url; +} +function stripTranslate(transform) { + if (!transform || transform === "none") return ""; + let cleaned = transform.replace(/translate[XY]?\([^)]*\)/g, ""); + cleaned = cleaned.replace(/matrix\(([^)]+)\)/g, (_, values) => { + const parts = values.split(",").map((s) => s.trim()); + if (parts.length !== 6) return `matrix(${values})`; + parts[4] = "0"; + parts[5] = "0"; + return `matrix(${parts.join(", ")})`; + }); + cleaned = cleaned.replace(/matrix3d\(([^)]+)\)/g, (_, values) => { + const parts = values.split(",").map((s) => s.trim()); + if (parts.length !== 16) return `matrix3d(${values})`; + parts[12] = "0"; + parts[13] = "0"; + return `matrix3d(${parts.join(", ")})`; + }); + return cleaned.trim().replace(/\s{2,}/g, " "); +} +function safeEncodeURI(uri) { + if (/%[0-9A-Fa-f]{2}/.test(uri)) return uri; + try { + return encodeURI(uri); + } catch { + return uri; + } +} +var init_helpers = __esm({ + "src/utils/helpers.js"() { + } +}); + +// src/modules/snapFetch.js +function createSnapLogger(prefix = "[snapDOM]", { ttlMs = 5 * 6e4, maxEntries = 12 } = {}) { + const seen = /* @__PURE__ */ new Map(); + let emitted = 0; + function log(level, key, msg) { + if (emitted >= maxEntries) return; + const now = Date.now(); + const until = seen.get(key) || 0; + if (until > now) return; + seen.set(key, now + ttlMs); + emitted++; + if (level === "warn" && console && console.warn) console.warn(`${prefix} ${msg}`); + else if (console && console.error) console.error(`${prefix} ${msg}`); + } + return { + warnOnce(key, msg) { + log("warn", key, msg); + }, + errorOnce(key, msg) { + log("error", key, msg); + }, + reset() { + seen.clear(); + emitted = 0; + } + }; +} +function isSpecialURL(url) { + return /^data:|^blob:|^about:blank$/i.test(url); +} +function isAlreadyProxied(url, useProxy) { + try { + const baseHref = typeof location !== "undefined" && location.href ? location.href : "http://localhost/"; + const proxyBaseRaw = useProxy.includes("{url}") ? useProxy.split("{url}")[0] : useProxy; + const proxyBase = new URL(proxyBaseRaw || ".", baseHref); + const u = new URL(url, baseHref); + if (u.origin === proxyBase.origin) return true; + const sp = u.searchParams; + if (sp && (sp.has("url") || sp.has("target"))) return true; + } catch { + } + return false; +} +function shouldProxy(url, useProxy) { + if (!useProxy) return false; + if (isSpecialURL(url)) return false; + if (isAlreadyProxied(url, useProxy)) return false; + try { + const base = typeof location !== "undefined" && location.href ? location.href : "http://localhost/"; + const u = new URL(url, base); + return typeof location !== "undefined" ? u.origin !== location.origin : true; + } catch { + return !!useProxy; + } +} +function applyProxy(url, useProxy) { + if (!useProxy) return url; + if (useProxy.includes("{url}")) { + return useProxy.replace("{urlRaw}", safeEncodeURI(url)).replace("{url}", encodeURIComponent(url)); + } + if (/[?&]url=?$/.test(useProxy)) { + return `${useProxy}${encodeURIComponent(url)}`; + } + if (useProxy.endsWith("?")) { + return `${useProxy}url=${encodeURIComponent(url)}`; + } + if (useProxy.endsWith("/")) { + return `${useProxy}${safeEncodeURI(url)}`; + } + const sep = useProxy.includes("?") ? "&" : "?"; + return `${useProxy}${sep}url=${encodeURIComponent(url)}`; +} +function blobToDataURL(blob) { + return new Promise((res, rej) => { + const fr = new FileReader(); + fr.onload = () => res(String(fr.result || "")); + fr.onerror = () => rej(new Error("read_failed")); + fr.readAsDataURL(blob); + }); +} +function makeKey(url, o) { + return [ + o.as || "blob", + o.timeout ?? 3e3, + o.useProxy || "", + o.errorTTL ?? 8e3, + url + ].join("|"); +} +async function snapFetch(url, options = {}) { + const as = options.as ?? "blob"; + const timeout = options.timeout ?? 3e3; + const useProxy = options.useProxy || ""; + const errorTTL = options.errorTTL ?? 8e3; + const headers = options.headers || {}; + const silent = !!options.silent; + if (/^data:/i.test(url)) { + try { + if (as === "text") { + return { ok: true, data: String(url), status: 200, url, fromCache: false }; + } + if (as === "dataURL") { + return { + ok: true, + data: String(url), + status: 200, + url, + fromCache: false, + mime: String(url).slice(5).split(";")[0] || "" + }; + } + const [, meta = "", data = ""] = String(url).match(/^data:([^,]*),(.*)$/) || []; + const isBase64 = /;base64/i.test(meta); + const bin = isBase64 ? atob(data) : decodeURIComponent(data); + const bytes = new Uint8Array([...bin].map((c) => c.charCodeAt(0))); + const b = new Blob([bytes], { type: (meta || "").split(";")[0] || "" }); + return { ok: true, data: b, status: 200, url, fromCache: false, mime: b.type || "" }; + } catch { + return { ok: false, data: null, status: 0, url, fromCache: false, reason: "special_url_error" }; + } + } + if (/^blob:/i.test(url)) { + try { + const resp = await fetch(url); + if (!resp.ok) { + return { ok: false, data: null, status: resp.status, url, fromCache: false, reason: "http_error" }; + } + const blob = await resp.blob(); + const mime = blob.type || resp.headers.get("content-type") || ""; + if (as === "dataURL") { + const dataURL = await blobToDataURL(blob); + return { ok: true, data: dataURL, status: resp.status, url, fromCache: false, mime }; + } + if (as === "text") { + const text = await blob.text(); + return { ok: true, data: text, status: resp.status, url, fromCache: false, mime }; + } + return { ok: true, data: blob, status: resp.status, url, fromCache: false, mime }; + } catch { + return { ok: false, data: null, status: 0, url, fromCache: false, reason: "network" }; + } + } + if (/^about:blank$/i.test(url)) { + if (as === "dataURL") { + return { + ok: true, + data: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", + status: 200, + url, + fromCache: false, + mime: "image/png" + }; + } + return { ok: true, data: as === "text" ? "" : new Blob([]), status: 200, url, fromCache: false }; + } + const key = makeKey(url, { as, timeout, useProxy, errorTTL }); + const e = _errorCache.get(key); + if (e && e.until > Date.now()) { + return { ...e.result, fromCache: true }; + } else if (e) { + _errorCache.delete(key); + } + const inflight = _inflight.get(key); + if (inflight) return inflight; + const finalURL = shouldProxy(url, useProxy) ? applyProxy(url, useProxy) : url; + let cred = options.credentials; + if (!cred) { + try { + const base = typeof location !== "undefined" && location.href ? location.href : "http://localhost/"; + const u = new URL(url, base); + const sameOrigin = typeof location !== "undefined" && u.origin === location.origin; + cred = sameOrigin ? "include" : "omit"; + } catch { + cred = "omit"; + } + } + const ctrl = new AbortController(); + const timer = setTimeout(() => ctrl.abort("timeout"), timeout); + const p = (async () => { + try { + const resp = await fetch(finalURL, { signal: ctrl.signal, credentials: cred, headers }); + if (!resp.ok) { + const result = { ok: false, data: null, status: resp.status, url: finalURL, fromCache: false, reason: "http_error" }; + if (errorTTL > 0) _errorCache.set(key, { until: Date.now() + errorTTL, result }); + if (!silent) { + const short = `${resp.status} ${resp.statusText || ""}`.trim(); + snapLogger.warnOnce( + `http:${resp.status}:${as}:${new URL(url, location?.href ?? "http://localhost/").origin}`, + `HTTP error ${short} while fetching ${as} ${url}` + ); + } + options.onError && options.onError(result); + return result; + } + if (as === "text") { + const text = await resp.text(); + return { ok: true, data: text, status: resp.status, url: finalURL, fromCache: false }; + } + const blob = await resp.blob(); + const mime = blob.type || resp.headers.get("content-type") || ""; + if (as === "dataURL") { + const dataURL = await blobToDataURL(blob); + return { ok: true, data: dataURL, status: resp.status, url: finalURL, fromCache: false, mime }; + } + return { ok: true, data: blob, status: resp.status, url: finalURL, fromCache: false, mime }; + } catch (err) { + const reason = err && typeof err === "object" && "name" in err && err.name === "AbortError" ? String(err.message || "").includes("timeout") ? "timeout" : "abort" : "network"; + const result = { ok: false, data: null, status: 0, url: finalURL, fromCache: false, reason }; + if (!/^blob:/i.test(url) && errorTTL > 0) { + _errorCache.set(key, { until: Date.now() + errorTTL, result }); + } + if (!silent) { + const k = `${reason}:${as}:${new URL(url, location?.href ?? "http://localhost/").origin}`; + const tips = reason === "timeout" ? `Timeout after ${timeout}ms. Consider increasing timeout or using a proxy for ${url}` : reason === "abort" ? `Request aborted while fetching ${as} ${url}` : `Network/CORS issue while fetching ${as} ${url}. A proxy may be required`; + snapLogger.errorOnce(k, tips); + } + options.onError && options.onError(result); + return result; + } finally { + clearTimeout(timer); + _inflight.delete(key); + } + })(); + _inflight.set(key, p); + return p; +} +var snapLogger, _inflight, _errorCache; +var init_snapFetch = __esm({ + "src/modules/snapFetch.js"() { + init_helpers(); + snapLogger = createSnapLogger("[snapDOM]", { ttlMs: 3 * 6e4, maxEntries: 10 }); + _inflight = /* @__PURE__ */ new Map(); + _errorCache = /* @__PURE__ */ new Map(); + } +}); + +// src/utils/image.js +async function inlineSingleBackgroundEntry(entry, options = {}) { + const isGradient = /^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(entry); + if (isGradient || entry.trim() === "none") { + return entry; + } + const rawUrl = extractURL(entry); + if (!rawUrl) { + return entry; + } + const encodedUrl = safeEncodeURI(rawUrl); + if (cache.background.has(encodedUrl)) { + const dataUrl = cache.background.get(encodedUrl); + return dataUrl ? `url("${dataUrl}")` : "none"; + } + try { + const dataUrl = await snapFetch(encodedUrl, { as: "dataURL", useProxy: options.useProxy }); + if (dataUrl.ok) { + cache.background.set(encodedUrl, dataUrl.data); + return `url("${dataUrl.data}")`; + } + cache.background.set(encodedUrl, null); + return "none"; + } catch { + cache.background.set(encodedUrl, null); + return "none"; + } +} +var init_image = __esm({ + "src/utils/image.js"() { + init_cache(); + init_helpers(); + init_snapFetch(); + } +}); + +// src/utils/css.js +function precacheCommonTags() { + for (let tag of commonTags) { + const t = String(tag).toLowerCase(); + if (NO_CAPTURE_TAGS.has(t)) continue; + if (NO_DEFAULTS_TAGS.has(t)) continue; + getDefaultStyleForTag(t); + } +} +function getDefaultStyleForTag(tagName) { + tagName = String(tagName).toLowerCase(); + if (NO_DEFAULTS_TAGS.has(tagName)) { + const empty = {}; + cache.defaultStyle.set(tagName, empty); + return empty; + } + if (cache.defaultStyle.has(tagName)) { + return cache.defaultStyle.get(tagName); + } + let sandbox = document.getElementById("snapdom-sandbox"); + if (!sandbox) { + sandbox = document.createElement("div"); + sandbox.id = "snapdom-sandbox"; + sandbox.setAttribute("data-snapdom-sandbox", "true"); + sandbox.setAttribute("aria-hidden", "true"); + sandbox.style.position = "absolute"; + sandbox.style.left = "-9999px"; + sandbox.style.top = "-9999px"; + sandbox.style.width = "0px"; + sandbox.style.height = "0px"; + sandbox.style.overflow = "hidden"; + document.body.appendChild(sandbox); + } + const el = document.createElement(tagName); + el.style.all = "initial"; + sandbox.appendChild(el); + const styles = getComputedStyle(el); + const defaults = {}; + for (let prop of styles) { + if (shouldIgnoreProp(prop)) continue; + const value = styles.getPropertyValue(prop); + defaults[prop] = value; + } + sandbox.removeChild(el); + cache.defaultStyle.set(tagName, defaults); + return defaults; +} +function shouldIgnoreProp(prop) { + const p = String(prop).toLowerCase(); + if (NO_PAINT_EXACT.has(p)) return true; + if (NO_PAINT_PREFIX.test(p)) return true; + if (NO_PAINT_TOKEN.test(p)) return true; + return false; +} +function getStyleKey(snapshot, tagName) { + tagName = String(tagName || "").toLowerCase(); + if (NO_DEFAULTS_TAGS.has(tagName)) { + return ""; + } + const entries = []; + const defaults = getDefaultStyleForTag(tagName); + for (let [prop, value] of Object.entries(snapshot)) { + if (shouldIgnoreProp(prop)) continue; + const def = defaults[prop]; + if (value && value !== def) entries.push(`${prop}:${value}`); + } + entries.sort(); + return entries.join(";"); +} +function collectUsedTagNames(root) { + const tagSet = /* @__PURE__ */ new Set(); + if (root.nodeType !== Node.ELEMENT_NODE && root.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) { + return []; + } + if (root.tagName) { + tagSet.add(root.tagName.toLowerCase()); + } + if (typeof root.querySelectorAll === "function") { + root.querySelectorAll("*").forEach((el) => tagSet.add(el.tagName.toLowerCase())); + } + return Array.from(tagSet); +} +function generateDedupedBaseCSS(usedTagNames) { + const groups = /* @__PURE__ */ new Map(); + for (let tagName of usedTagNames) { + const styles = cache.defaultStyle.get(tagName); + if (!styles) continue; + const key = Object.entries(styles).map(([k, v]) => `${k}:${v};`).sort().join(""); + if (!key) continue; + if (!groups.has(key)) { + groups.set(key, []); + } + groups.get(key).push(tagName); + } + let css = ""; + for (let [styleBlock, tagList] of groups.entries()) { + css += `${tagList.join(",")} { ${styleBlock} } +`; + } + return css; +} +function generateCSSClasses(styleMap) { + const keys = Array.from(new Set(styleMap.values())).filter(Boolean).sort(); + const classMap = /* @__PURE__ */ new Map(); + let i = 1; + for (const k of keys) classMap.set(k, `c${i++}`); + return classMap; +} +function getStyle(el, pseudo = null) { + if (!(el instanceof Element)) { + return window.getComputedStyle(el, pseudo); + } + let map = cache.computedStyle.get(el); + if (!map) { + map = /* @__PURE__ */ new Map(); + cache.computedStyle.set(el, map); + } + if (!map.has(pseudo)) { + const st = window.getComputedStyle(el, pseudo); + map.set(pseudo, st); + } + return map.get(pseudo); +} +function snapshotComputedStyle(style) { + const snap = {}; + for (let prop of style) { + snap[prop] = style.getPropertyValue(prop); + } + return snap; +} +function splitBackgroundImage(bg) { + const parts = []; + let depth = 0; + let lastIndex = 0; + for (let i = 0; i < bg.length; i++) { + const char = bg[i]; + if (char === "(") depth++; + if (char === ")") depth--; + if (char === "," && depth === 0) { + parts.push(bg.slice(lastIndex, i).trim()); + lastIndex = i + 1; + } + } + parts.push(bg.slice(lastIndex).trim()); + return parts; +} +var NO_CAPTURE_TAGS, NO_DEFAULTS_TAGS, commonTags, NO_PAINT_TOKEN, NO_PAINT_PREFIX, NO_PAINT_EXACT; +var init_css = __esm({ + "src/utils/css.js"() { + init_cache(); + NO_CAPTURE_TAGS = /* @__PURE__ */ new Set([ + "meta", + "script", + "noscript", + "title", + "link", + "template" + ]); + NO_DEFAULTS_TAGS = /* @__PURE__ */ new Set([ + // non-painting / head stuff + "meta", + "link", + "style", + "title", + "noscript", + "script", + "template", + // SVG whole namespace (safe for LeaderLine/presentation attrs) + "g", + "defs", + "use", + "marker", + "mask", + "clipPath", + "pattern", + "path", + "polygon", + "polyline", + "line", + "circle", + "ellipse", + "rect", + "filter", + "lineargradient", + "radialgradient", + "stop" + ]); + commonTags = [ + "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", + "table", + "thead", + "tbody", + "tr", + "td", + "th" + ]; + NO_PAINT_TOKEN = /(?:^|-)(animation|transition)(?:-|$)/i; + NO_PAINT_PREFIX = /^(--|view-timeline|scroll-timeline|animation-trigger|offset-|position-try|app-region|interactivity|overlay|view-transition|-webkit-locale|-webkit-user-(?:drag|modify)|-webkit-tap-highlight-color|-webkit-text-security)$/i; + NO_PAINT_EXACT = /* @__PURE__ */ new Set([ + // Interaction hints + "cursor", + "pointer-events", + "touch-action", + "user-select", + // Printing/speech/reading-mode hints + "print-color-adjust", + "speak", + "reading-flow", + "reading-order", + // Anchoring/container/timeline scopes (metadata for layout queries) + "anchor-name", + "anchor-scope", + "container-name", + "container-type", + "timeline-scope" + ]); + } +}); + +// src/utils/browser.js +function idle(fn, { fast = false } = {}) { + if (fast) return fn(); + if ("requestIdleCallback" in window) { + requestIdleCallback(fn, { timeout: 50 }); + } else { + setTimeout(fn, 1); + } +} +function isSafari() { + if (typeof navigator === "undefined") return false; + const ua = navigator.userAgent || ""; + const uaLower = ua.toLowerCase(); + const isSafariUA = uaLower.includes("safari") && !uaLower.includes("chrome") && !uaLower.includes("crios") && // Chrome on iOS + !uaLower.includes("fxios") && // Firefox on iOS + !uaLower.includes("android"); + const isWebKit = /applewebkit/i.test(ua); + const isMobile = /mobile/i.test(ua); + const missingSafariToken = !/safari/i.test(ua); + const isUIWebView = isWebKit && isMobile && missingSafariToken; + const isWeChatUA = /(micromessenger|wxwork|wecom|windowswechat|macwechat)/i.test(ua); + const isBaiduUA = /(baiduboxapp|baidubrowser|baidusearch|baiduboxlite)/i.test(uaLower); + const isIOSWebKit = /ipad|iphone|ipod/.test(uaLower) && isWebKit; + return isSafariUA || isUIWebView || isWeChatUA || isBaiduUA || isIOSWebKit; +} +var init_browser = __esm({ + "src/utils/browser.js"() { + } +}); + +// src/utils/index.js +var init_utils = __esm({ + "src/utils/index.js"() { + init_image(); + init_css(); + init_browser(); + init_helpers(); + } +}); + +// src/exporters/toCanvas.js +var toCanvas_exports = {}; +__export(toCanvas_exports, { + toCanvas: () => toCanvas +}); +function isSvgDataURL(u) { + return typeof u === "string" && /^data:image\/svg\+xml/i.test(u); +} +function decodeSvgFromDataURL(u) { + const i = u.indexOf(","); + return i >= 0 ? decodeURIComponent(u.slice(i + 1)) : ""; +} +function encodeSvgToDataURL(svgText) { + return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgText)}`; +} +function splitDecls(s) { + let parts = [], buf = "", depth = 0; + for (let i = 0; i < s.length; i++) { + const ch = s[i]; + if (ch === "(") depth++; + if (ch === ")") depth = Math.max(0, depth - 1); + if (ch === ";" && depth === 0) { + parts.push(buf); + buf = ""; + } else buf += ch; + } + if (buf.trim()) parts.push(buf); + return parts.map((x) => x.trim()).filter(Boolean); +} +function boxShadowToDropShadow(value) { + const layers = []; + let buf = "", depth = 0; + for (let i = 0; i < value.length; i++) { + const ch = value[i]; + if (ch === "(") depth++; + if (ch === ")") depth = Math.max(0, depth - 1); + if (ch === "," && depth === 0) { + layers.push(buf.trim()); + buf = ""; + } else buf += ch; + } + if (buf.trim()) layers.push(buf.trim()); + const fns = []; + for (const layer of layers) { + if (/\binset\b/i.test(layer)) continue; + const nums = layer.match(/-?\d+(?:\.\d+)?px/gi) || []; + const [ox = "0px", oy = "0px", blur = "0px"] = nums; + let color = layer.replace(/-?\d+(?:\.\d+)?px/gi, "").replace(/\binset\b/ig, "").trim().replace(/\s{2,}/g, " "); + const hasColor = !!color && color !== ","; + fns.push(`drop-shadow(${ox} ${oy} ${blur}${hasColor ? ` ${color}` : ""})`); + } + return fns.join(" "); +} +function rewriteDeclList(list) { + const decls = splitDecls(list); + let filter = null, wfilter = null, box = null; + const rest = []; + for (const d of decls) { + const idx = d.indexOf(":"); + if (idx < 0) continue; + const prop = d.slice(0, idx).trim().toLowerCase(); + const val = d.slice(idx + 1).trim(); + if (prop === "box-shadow") box = val; + else if (prop === "filter") filter = val; + else if (prop === "-webkit-filter") wfilter = val; + else rest.push([prop, val]); + } + if (box) { + const ds = boxShadowToDropShadow(box); + if (ds) { + filter = filter ? `${filter} ${ds}` : ds; + wfilter = wfilter ? `${wfilter} ${ds}` : ds; + } + } + const out = [...rest]; + if (filter) out.push(["filter", filter]); + if (wfilter) out.push(["-webkit-filter", wfilter]); + return out.map(([k, v]) => `${k}:${v}`).join(";"); +} +function rewriteCssBlock(css) { + return css.replace(/([^{}]+)\{([^}]*)\}/g, (_m, sel, body) => `${sel}{${rewriteDeclList(body)}}`); +} +function rewriteSvgBoxShadowToDropShadow(svgText) { + svgText = svgText.replace( + /]*>([\s\S]*?)<\/style>/gi, + (m, css) => m.replace(css, rewriteCssBlock(css)) + ); + svgText = svgText.replace( + /style=(['"])([\s\S]*?)\1/gi, + (m, q, body) => `style=${q}${rewriteDeclList(body)}${q}` + ); + return svgText; +} +function maybeConvertBoxShadowForSafari(url) { + if (!isSafari() || !isSvgDataURL(url)) return url; + try { + const svg = decodeSvgFromDataURL(url); + const fixed = rewriteSvgBoxShadowToDropShadow(svg); + return encodeSvgToDataURL(fixed); + } catch { + return url; + } +} +async function toCanvas(url, options) { + let { width: optW, height: optH, scale = 1, dpr = 1, meta = {}, backgroundColor } = options; + url = maybeConvertBoxShadowForSafari(url); + const img = new Image(); + img.loading = "eager"; + img.decoding = "sync"; + img.crossOrigin = "anonymous"; + img.src = url; + await img.decode(); + const natW = img.naturalWidth; + const natH = img.naturalHeight; + const refW = Number.isFinite(meta.w0) ? meta.w0 : natW; + const refH = Number.isFinite(meta.h0) ? meta.h0 : natH; + let outW, outH; + const hasW = Number.isFinite(optW); + const hasH = Number.isFinite(optH); + if (hasW && hasH) { + outW = Math.max(1, optW); + outH = Math.max(1, optH); + } else if (hasW) { + const k = optW / Math.max(1, refW); + outW = optW; + outH = refH * k; + } else if (hasH) { + const k = optH / Math.max(1, refH); + outH = optH; + outW = refW * k; + } else { + outW = natW; + outH = natH; + } + outW = outW * scale; + outH = outH * scale; + const canvas = document.createElement("canvas"); + canvas.width = outW * dpr; + canvas.height = outH * dpr; + canvas.style.width = `${outW}px`; + canvas.style.height = `${outH}px`; + const ctx = canvas.getContext("2d"); + if (dpr !== 1) ctx.scale(dpr, dpr); + if (backgroundColor) { + ctx.save(); + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, outW, outH); + ctx.restore(); + } + ctx.drawImage(img, 0, 0, outW, outH); + return canvas; +} +var init_toCanvas = __esm({ + "src/exporters/toCanvas.js"() { + init_browser(); + } +}); + +// src/modules/rasterize.js +var rasterize_exports = {}; +__export(rasterize_exports, { + rasterize: () => rasterize +}); +async function rasterize(url, options) { + const canvas = await toCanvas(url, options); + const img = new Image(); + img.src = canvas.toDataURL(`image/${options.format}`, options.quality); + await img.decode(); + img.style.width = `${canvas.width / options.dpr}px`; + img.style.height = `${canvas.height / options.dpr}px`; + return img; +} +var init_rasterize = __esm({ + "src/modules/rasterize.js"() { + init_toCanvas(); + } +}); + +// src/exporters/toImg.js +var toImg_exports = {}; +__export(toImg_exports, { + toImg: () => toImg, + toSvg: () => toImg +}); +async function toImg(url, options) { + const { scale = 1, width, height, meta = {} } = options; + const hasW = Number.isFinite(width); + const hasH = Number.isFinite(height); + const wantsScale = Number.isFinite(scale) && scale !== 1 || hasW || hasH; + if (isSafari() && wantsScale) { + const pngUrl = await rasterize(url, { ...options, format: "png", quality: 1, meta }); + return pngUrl; + } + const img = new Image(); + img.decoding = "sync"; + img.loading = "eager"; + img.src = url; + await img.decode(); + if (hasW && hasH) { + img.style.width = `${width}px`; + img.style.height = `${height}px`; + } else if (hasW) { + const refW = Number.isFinite(meta.w0) ? meta.w0 : img.naturalWidth; + const refH = Number.isFinite(meta.h0) ? meta.h0 : img.naturalHeight; + const k = width / Math.max(1, refW); + img.style.width = `${width}px`; + img.style.height = `${Math.round(refH * k)}px`; + } else if (hasH) { + const refW = Number.isFinite(meta.w0) ? meta.w0 : img.naturalWidth; + const refH = Number.isFinite(meta.h0) ? meta.h0 : img.naturalHeight; + const k = height / Math.max(1, refH); + img.style.height = `${height}px`; + img.style.width = `${Math.round(refW * k)}px`; + } else { + const cssW = Math.round(img.naturalWidth * scale); + const cssH = Math.round(img.naturalHeight * scale); + img.style.width = `${cssW}px`; + img.style.height = `${cssH}px`; + if (typeof url === "string" && url.startsWith("data:image/svg+xml")) { + try { + const decoded = decodeURIComponent(url.split(",")[1]); + const patched = decoded.replace(/width="[^"]*"/, `width="${cssW}"`).replace(/height="[^"]*"/, `height="${cssH}"`); + url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(patched)}`; + img.src = url; + } catch { + } + } + } + return img; +} +var init_toImg = __esm({ + "src/exporters/toImg.js"() { + init_utils(); + init_rasterize(); + } +}); + +// src/exporters/toBlob.js +var toBlob_exports = {}; +__export(toBlob_exports, { + toBlob: () => toBlob +}); +async function toBlob(url, options) { + const type = options.type; + if (type === "svg") { + const svgText = decodeURIComponent(url.split(",")[1]); + return new Blob([svgText], { type: "image/svg+xml" }); + } + const canvas = await toCanvas(url, options); + return new Promise( + (resolve) => canvas.toBlob((blob) => resolve(blob), `image/${type}`, options.quality) + ); +} +var init_toBlob = __esm({ + "src/exporters/toBlob.js"() { + init_toCanvas(); + } +}); + +// src/exporters/download.js +var download_exports = {}; +__export(download_exports, { + download: () => download +}); +async function download(url, options) { + options.dpr = 1; + if (options.format === "svg") { + const blob = await toBlob(url, { ...options, type: "svg" }); + const objectURL = URL.createObjectURL(blob); + const a2 = document.createElement("a"); + a2.href = objectURL; + a2.download = options.filename; + a2.click(); + URL.revokeObjectURL(objectURL); + return; + } + const canvas = await toCanvas(url, options); + const a = document.createElement("a"); + a.href = canvas.toDataURL(`image/${options.format}`, options.quality); + a.download = options.filename; + a.click(); +} +var init_download = __esm({ + "src/exporters/download.js"() { + init_toBlob(); + init_toCanvas(); + } +}); + +// src/core/prepare.js +init_utils(); + +// src/modules/styles.js +init_utils(); +init_cache(); +var snapshotCache = /* @__PURE__ */ new WeakMap(); +var snapshotKeyCache = /* @__PURE__ */ new Map(); +var __epoch = 0; +function bumpEpoch() { + __epoch++; +} +var __wired = false; +function setupInvalidationOnce(root = document.documentElement) { + if (__wired) return; + __wired = true; + try { + const domObs = new MutationObserver(() => bumpEpoch()); + domObs.observe(root, { subtree: true, childList: true, characterData: true, attributes: true }); + } catch { + } + try { + const headObs = new MutationObserver(() => bumpEpoch()); + headObs.observe(document.head, { subtree: true, childList: true, characterData: true, attributes: true }); + } catch { + } + try { + const f = document.fonts; + if (f) { + f.addEventListener?.("loadingdone", bumpEpoch); + f.ready?.then(() => bumpEpoch()).catch(() => { + }); + } + } catch { + } +} +function snapshotComputedStyleFull(style, options = {}) { + const out = {}; + const vis = style.getPropertyValue("visibility"); + for (let i = 0; i < style.length; i++) { + const prop = style[i]; + let val = style.getPropertyValue(prop); + if ((prop === "background-image" || prop === "content") && val.includes("url(") && !val.includes("data:")) { + val = "none"; + } + out[prop] = val; + } + const EXTRA_TEXT_DECORATION_PROPS = [ + "text-decoration-line", + "text-decoration-color", + "text-decoration-style", + "text-decoration-thickness", + "text-underline-offset", + "text-decoration-skip-ink" + ]; + for (const prop of EXTRA_TEXT_DECORATION_PROPS) { + if (out[prop]) continue; + try { + const v = style.getPropertyValue(prop); + if (v) out[prop] = v; + } catch { + } + } + if (options.embedFonts) { + const EXTRA_FONT_PROPS = [ + "font-feature-settings", + "font-variation-settings", + "font-kerning", + "font-variant", + "font-variant-ligatures", + "font-optical-sizing" + ]; + for (const prop of EXTRA_FONT_PROPS) { + if (out[prop]) continue; + try { + const v = style.getPropertyValue(prop); + if (v) out[prop] = v; + } catch { + } + } + } + if (vis === "hidden") out.opacity = "0"; + return out; +} +var __snapshotSig = /* @__PURE__ */ new WeakMap(); +function styleSignature(snap) { + let sig = __snapshotSig.get(snap); + if (sig) return sig; + const entries = Object.entries(snap).sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0); + sig = entries.map(([k, v]) => `${k}:${v}`).join(";"); + __snapshotSig.set(snap, sig); + return sig; +} +function getSnapshot(el, preStyle = null, options = {}) { + const rec = snapshotCache.get(el); + if (rec && rec.epoch === __epoch) return rec.snapshot; + const style = preStyle || getComputedStyle(el); + const snap = snapshotComputedStyleFull(style, options); + stripHeightForWrappers(el, style, snap); + snapshotCache.set(el, { epoch: __epoch, snapshot: snap }); + return snap; +} +function _resolveCtx(sessionOrCtx, opts) { + if (sessionOrCtx && sessionOrCtx.session && sessionOrCtx.persist) return sessionOrCtx; + if (sessionOrCtx && (sessionOrCtx.styleMap || sessionOrCtx.styleCache || sessionOrCtx.nodeMap)) { + return { + session: sessionOrCtx, + persist: { + snapshotKeyCache, + defaultStyle: cache.defaultStyle, + baseStyle: cache.baseStyle, + image: cache.image, + resource: cache.resource, + background: cache.background, + font: cache.font + }, + options: opts || {} + }; + } + return { + session: cache.session, + persist: { + snapshotKeyCache, + defaultStyle: cache.defaultStyle, + baseStyle: cache.baseStyle, + image: cache.image, + resource: cache.resource, + background: cache.background, + font: cache.font + }, + options: sessionOrCtx || opts || {} + }; +} +async function inlineAllStyles(source, clone, sessionOrCtx, opts) { + if (source.tagName === "STYLE") return; + const ctx = _resolveCtx(sessionOrCtx, opts); + const resetMode = ctx.options && ctx.options.cache || "auto"; + if (resetMode !== "disabled") setupInvalidationOnce(document.documentElement); + if (resetMode === "disabled" && !ctx.session.__bumpedForDisabled) { + bumpEpoch(); + snapshotKeyCache.clear(); + ctx.session.__bumpedForDisabled = true; + } + if (NO_DEFAULTS_TAGS.has(source.tagName?.toLowerCase())) { + const author = source.getAttribute?.("style"); + if (author) clone.setAttribute("style", author); + } + const { session, persist } = ctx; + if (!session.styleCache.has(source)) { + session.styleCache.set(source, getComputedStyle(source)); + } + const pre = session.styleCache.get(source); + const snap = getSnapshot(source, pre, ctx.options); + const sig = styleSignature(snap); + let key = persist.snapshotKeyCache.get(sig); + if (!key) { + const tag = source.tagName?.toLowerCase() || "div"; + key = getStyleKey(snap, tag); + persist.snapshotKeyCache.set(sig, key); + } + session.styleMap.set(clone, key); +} +function isReplaced(el) { + return el instanceof HTMLImageElement || el instanceof HTMLCanvasElement || el instanceof HTMLVideoElement || el instanceof HTMLIFrameElement || el instanceof SVGElement || el instanceof HTMLObjectElement || el instanceof HTMLEmbedElement; +} +function hasBox(cs) { + if (cs.backgroundImage && cs.backgroundImage !== "none") return true; + if (cs.backgroundColor && cs.backgroundColor !== "rgba(0, 0, 0, 0)" && cs.backgroundColor !== "transparent") return true; + if ((parseFloat(cs.borderTopWidth) || 0) > 0) return true; + if ((parseFloat(cs.borderBottomWidth) || 0) > 0) return true; + if ((parseFloat(cs.paddingTop) || 0) > 0) return true; + if ((parseFloat(cs.paddingBottom) || 0) > 0) return true; + const ob = cs.overflowBlock || cs.overflowY || "visible"; + return ob !== "visible"; +} +function isFlexOrGridItem(el) { + const p = el.parentElement; + if (!p) return false; + const pd = getComputedStyle(p).display || ""; + return pd.includes("flex") || pd.includes("grid"); +} +function hasFlowFast(el, cs) { + if (el.textContent && /\S/.test(el.textContent)) return true; + const f = el.firstElementChild, l = el.lastElementChild; + if (f && f.tagName === "BR" || l && l.tagName === "BR") return true; + const sh = el.scrollHeight; + if (sh === 0) return false; + const pt = parseFloat(cs.paddingTop) || 0; + const pb = parseFloat(cs.paddingBottom) || 0; + return sh > pt + pb; +} +function stripHeightForWrappers(el, cs, snap) { + if (el instanceof HTMLElement && el.style && el.style.height) return; + const tag = el.tagName && el.tagName.toLowerCase(); + if (!tag || tag !== "div" && tag !== "section" && tag !== "article" && tag !== "main" && tag !== "aside" && tag !== "header" && tag !== "footer" && tag !== "nav") { + return; + } + const disp = cs.display || ""; + if (disp.includes("flex") || disp.includes("grid")) return; + if (isReplaced(el)) return; + const pos = cs.position; + if (pos === "absolute" || pos === "fixed" || pos === "sticky") return; + if (cs.transform !== "none") return; + if (hasBox(cs)) return; + if (isFlexOrGridItem(el)) return; + const overflowX = cs.overflowX || cs.overflow || "visible"; + const overflowY = cs.overflowY || cs.overflow || "visible"; + if (overflowX !== "visible" || overflowY !== "visible") return; + const clip = cs.clip; + if (clip && clip !== "auto" && clip !== "rect(auto, auto, auto, auto)") return; + if (cs.visibility === "hidden" || cs.opacity === "0") return; + if (!hasFlowFast(el, cs)) return; + delete snap.height; + delete snap["block-size"]; +} + +// src/core/clone.js +init_css(); + +// src/modules/CSSVar.js +var KEY_PROPS = ["fill", "stroke", "color", "background-color", "stop-color"]; +var __BASELINE_CACHE = /* @__PURE__ */ new Map(); +function getBaselineComputed(tagName, ns) { + const key = ns + "::" + tagName.toLowerCase(); + let entry = __BASELINE_CACHE.get(key); + if (entry) return entry; + const doc = document; + const el = ns === "http://www.w3.org/2000/svg" ? doc.createElementNS(ns, tagName) : doc.createElement(tagName); + const holder = doc.createElement("div"); + holder.style.cssText = "position:absolute;left:-99999px;top:-99999px;contain:strict;display:block;"; + holder.appendChild(el); + doc.documentElement.appendChild(holder); + const cs = getComputedStyle(el); + const base = {}; + for (const p of KEY_PROPS) { + base[p] = cs.getPropertyValue(p) || ""; + } + holder.remove(); + __BASELINE_CACHE.set(key, base); + return base; +} +function resolveCSSVars(sourceEl, cloneEl) { + if (!(sourceEl instanceof Element) || !(cloneEl instanceof Element)) return; + const styleAttr = sourceEl.getAttribute?.("style"); + let hasVar = !!(styleAttr && styleAttr.includes("var(")); + if (!hasVar && sourceEl.attributes?.length) { + const attrs = sourceEl.attributes; + for (let i = 0; i < attrs.length; i++) { + const a = attrs[i]; + if (a && typeof a.value === "string" && a.value.includes("var(")) { + hasVar = true; + break; + } + } + } + let cs = null; + if (hasVar) { + try { + cs = getComputedStyle(sourceEl); + } catch { + } + } + if (hasVar) { + const author = sourceEl.style; + if (author && author.length) { + for (let i = 0; i < author.length; i++) { + const prop = author[i]; + const val = author.getPropertyValue(prop); + if (!val || !val.includes("var(")) continue; + const resolved = cs && cs.getPropertyValue(prop); + if (resolved) { + try { + cloneEl.style.setProperty(prop, resolved.trim(), author.getPropertyPriority(prop)); + } catch { + } + } + } + } + } + if (hasVar && sourceEl.attributes?.length) { + const attrs = sourceEl.attributes; + for (let i = 0; i < attrs.length; i++) { + const a = attrs[i]; + if (!a || typeof a.value !== "string" || !a.value.includes("var(")) continue; + const propName = a.name; + const resolved = cs && cs.getPropertyValue(propName); + if (resolved) { + try { + cloneEl.style.setProperty(propName, resolved.trim()); + } catch { + } + } + } + } + if (!hasVar) { + if (!cs) { + try { + cs = getComputedStyle(sourceEl); + } catch { + cs = null; + } + } + if (!cs) return; + const ns = sourceEl.namespaceURI || "html"; + const base = getBaselineComputed(sourceEl.tagName, ns); + for (const prop of KEY_PROPS) { + const v = cs.getPropertyValue(prop) || ""; + const b = base[prop] || ""; + if (v && v !== b) { + try { + cloneEl.style.setProperty(prop, v.trim()); + } catch { + } + } + } + } +} + +// src/utils/clone.helpers.js +init_utils(); +init_cache(); +init_snapFetch(); +function idleCallback(childList, callback, fast) { + return Promise.all(childList.map((child) => { + return new Promise((resolve) => { + function deal() { + idle((deadline) => { + const hasIdleBudget = deadline && typeof deadline.timeRemaining === "function" ? deadline.timeRemaining() > 0 : true; + if (hasIdleBudget) { + callback(child, resolve); + } else { + deal(); + } + }, { fast }); + } + deal(); + }); + })); +} +function addNotSlottedRightmost(sel) { + sel = sel.trim(); + if (!sel) return sel; + if (/:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(sel)) return sel; + return `${sel}:not([data-sd-slotted])`; +} +function wrapWithScope(selectorList, scopeSelector, excludeSlotted = true) { + return selectorList.split(",").map((s) => s.trim()).filter(Boolean).map((s) => { + if (s.startsWith(":where(")) return s; + if (s.startsWith("@")) return s; + const body = excludeSlotted ? addNotSlottedRightmost(s) : s; + return `:where(${scopeSelector} ${body})`; + }).join(", "); +} +function rewriteShadowCSS(cssText, scopeSelector) { + if (!cssText) return ""; + cssText = cssText.replace(/:host\(([^)]+)\)/g, (_, sel) => { + return `:where(${scopeSelector}:is(${sel.trim()}))`; + }); + cssText = cssText.replace(/:host\b/g, `:where(${scopeSelector})`); + cssText = cssText.replace(/:host-context\(([^)]+)\)/g, (_, sel) => { + return `:where(:where(${sel.trim()}) ${scopeSelector})`; + }); + cssText = cssText.replace(/::slotted\(([^)]+)\)/g, (_, sel) => { + return `:where(${scopeSelector} ${sel.trim()})`; + }); + cssText = cssText.replace(/(^|})(\s*)([^@}{]+){/g, (_, brace, ws, selectorList) => { + const wrapped = wrapWithScope( + selectorList, + scopeSelector, + /*excludeSlotted*/ + true + ); + return `${brace}${ws}${wrapped}{`; + }); + return cssText; +} +function nextShadowScopeId(sessionCache) { + sessionCache.shadowScopeSeq = (sessionCache.shadowScopeSeq || 0) + 1; + return `s${sessionCache.shadowScopeSeq}`; +} +function extractShadowCSS(sr) { + let css = ""; + try { + sr.querySelectorAll("style").forEach((s) => { + css += (s.textContent || "") + "\n"; + }); + const sheets = sr.adoptedStyleSheets || []; + for (const sh of sheets) { + try { + if (sh && sh.cssRules) { + for (const rule of sh.cssRules) css += rule.cssText + "\n"; + } + } catch { + } + } + } catch { + } + return css; +} +function injectScopedStyle(hostClone, cssText, scopeId) { + if (!cssText) return; + const style = document.createElement("style"); + style.setAttribute("data-sd", scopeId); + style.textContent = cssText; + hostClone.insertBefore(style, hostClone.firstChild || null); +} +function freezeImgSrcset(original, cloned) { + try { + const chosen = original.currentSrc || original.src || ""; + if (!chosen) return; + cloned.setAttribute("src", chosen); + cloned.removeAttribute("srcset"); + cloned.removeAttribute("sizes"); + cloned.loading = "eager"; + cloned.decoding = "sync"; + } catch { + } +} +function collectCustomPropsFromCSS(cssText) { + const out = /* @__PURE__ */ new Set(); + if (!cssText) return out; + const re = /var\(\s*(--[A-Za-z0-9_-]+)\b/g; + let m; + while (m = re.exec(cssText)) out.add(m[1]); + return out; +} +function resolveCustomProp(el, name) { + try { + const cs = getComputedStyle(el); + let v = cs.getPropertyValue(name).trim(); + if (v) return v; + } catch { + } + try { + const rootCS = getComputedStyle(document.documentElement); + let v = rootCS.getPropertyValue(name).trim(); + if (v) return v; + } catch { + } + return ""; +} +function buildSeedCustomPropsRule(hostEl, names, scopeSelector) { + const decls = []; + for (const name of names) { + const val = resolveCustomProp(hostEl, name); + if (val) decls.push(`${name}: ${val};`); + } + if (!decls.length) return ""; + return `${scopeSelector}{${decls.join("")}} +`; +} +function markSlottedSubtree(root) { + if (!root) return; + if (root.nodeType === Node.ELEMENT_NODE) { + root.setAttribute("data-sd-slotted", ""); + } + if (root.querySelectorAll) { + root.querySelectorAll("*").forEach((el) => el.setAttribute("data-sd-slotted", "")); + } +} +async function getAccessibleIframeDocument(iframe, attempts = 3) { + const probe = () => { + try { + return iframe.contentDocument || iframe.contentWindow?.document || null; + } catch { + return null; + } + }; + let doc = probe(); + let i = 0; + while (i < attempts && (!doc || !doc.body && !doc.documentElement)) { + await new Promise((r) => setTimeout(r, 0)); + doc = probe(); + i++; + } + return doc && (doc.body || doc.documentElement) ? doc : null; +} +function measureContentBox(el) { + const rect = el.getBoundingClientRect(); + let bl = 0, br = 0, bt = 0, bb = 0; + try { + const cs = getComputedStyle(el); + bl = parseFloat(cs.borderLeftWidth) || 0; + br = parseFloat(cs.borderRightWidth) || 0; + bt = parseFloat(cs.borderTopWidth) || 0; + bb = parseFloat(cs.borderBottomWidth) || 0; + } catch { + } + const contentWidth = Math.max(0, Math.round(rect.width - (bl + br))); + const contentHeight = Math.max(0, Math.round(rect.height - (bt + bb))); + return { contentWidth, contentHeight, rect }; +} +function pinIframeViewport(doc, w, h) { + const style = doc.createElement("style"); + style.setAttribute("data-sd-iframe-pin", ""); + style.textContent = `html, body {margin: 0 !important;padding: 0 !important;width: ${w}px !important;height: ${h}px !important;min-width: ${w}px !important;min-height: ${h}px !important;box-sizing: border-box !important;overflow: hidden !important;background-clip: border-box !important;}`; + (doc.head || doc.documentElement).appendChild(style); + return () => { + try { + style.remove(); + } catch { + } + }; +} +async function rasterizeIframe(iframe, sessionCache, options) { + const doc = await getAccessibleIframeDocument(iframe, 3); + if (!doc) throw new Error("iframe document not accessible/ready"); + const { contentWidth, contentHeight, rect } = measureContentBox(iframe); + const snap = options?.snap; + if (!snap || typeof snap.toPng !== "function") { + throw new Error("snapdom.toPng not available in iframe or window"); + } + const nested = { ...options, scale: 1 }; + const unpin = pinIframeViewport(doc, contentWidth, contentHeight); + let imgEl; + try { + imgEl = await snap.toPng(doc.documentElement, nested); + } finally { + unpin(); + } + imgEl.style.display = "block"; + imgEl.style.width = `${contentWidth}px`; + imgEl.style.height = `${contentHeight}px`; + const wrapper = document.createElement("div"); + sessionCache.nodeMap.set(wrapper, iframe); + inlineAllStyles(iframe, wrapper, sessionCache, options); + wrapper.style.overflow = "hidden"; + wrapper.style.display = "block"; + if (!wrapper.style.width) wrapper.style.width = `${Math.round(rect.width)}px`; + if (!wrapper.style.height) wrapper.style.height = `${Math.round(rect.height)}px`; + wrapper.appendChild(imgEl); + return wrapper; +} +var _blobToDataUrlCache = /* @__PURE__ */ new Map(); +async function blobUrlToDataUrl(blobUrl) { + if (cache.resource?.has(blobUrl)) return cache.resource.get(blobUrl); + if (_blobToDataUrlCache.has(blobUrl)) return _blobToDataUrlCache.get(blobUrl); + const p = (async () => { + const r = await snapFetch(blobUrl, { as: "dataURL", silent: true }); + if (!r.ok || typeof r.data !== "string") { + throw new Error(`[snapDOM] Failed to read blob URL: ${blobUrl}`); + } + cache.resource?.set(blobUrl, r.data); + return r.data; + })(); + _blobToDataUrlCache.set(blobUrl, p); + try { + const data = await p; + _blobToDataUrlCache.set(blobUrl, data); + return data; + } catch (e) { + _blobToDataUrlCache.delete(blobUrl); + throw e; + } +} +var BLOB_URL_RE = /\bblob:[^)"'\s]+/g; +async function replaceBlobUrlsInCssText(cssText) { + if (!cssText || cssText.indexOf("blob:") === -1) return cssText; + const uniques = Array.from(new Set(cssText.match(BLOB_URL_RE) || [])); + if (uniques.length === 0) return cssText; + let out = cssText; + for (const u of uniques) { + try { + const d = await blobUrlToDataUrl(u); + out = out.split(u).join(d); + } catch { + } + } + return out; +} +function isBlobUrl(u) { + return typeof u === "string" && u.startsWith("blob:"); +} +function parseSrcset(srcset) { + return (srcset || "").split(",").map((s) => s.trim()).filter(Boolean).map((item) => { + const m = item.match(/^(\S+)(\s+.+)?$/); + return m ? { url: m[1], desc: m[2] || "" } : null; + }).filter(Boolean); +} +function stringifySrcset(parts) { + return parts.map((p) => p.desc ? `${p.url} ${p.desc.trim()}` : p.url).join(", "); +} +async function resolveBlobUrlsInTree(root) { + if (!root) return; + const imgs = root.querySelectorAll ? root.querySelectorAll("img") : []; + for (const img of imgs) { + try { + const srcAttr = img.getAttribute("src"); + const effective = srcAttr || img.currentSrc || ""; + if (isBlobUrl(effective)) { + const data = await blobUrlToDataUrl(effective); + img.setAttribute("src", data); + } + const srcset = img.getAttribute("srcset"); + if (srcset && srcset.includes("blob:")) { + const parts = parseSrcset(srcset); + let changed = false; + for (const p of parts) { + if (isBlobUrl(p.url)) { + try { + p.url = await blobUrlToDataUrl(p.url); + changed = true; + } catch { + } + } + } + if (changed) img.setAttribute("srcset", stringifySrcset(parts)); + } + } catch { + } + } + const svgImages = root.querySelectorAll ? root.querySelectorAll("image") : []; + for (const node of svgImages) { + try { + const XLINK_NS = "http://www.w3.org/1999/xlink"; + const href = node.getAttribute("href") || node.getAttributeNS?.(XLINK_NS, "href"); + if (isBlobUrl(href)) { + const d = await blobUrlToDataUrl(href); + node.setAttribute("href", d); + node.removeAttributeNS?.(XLINK_NS, "href"); + } + } catch { + } + } + const styled = root.querySelectorAll ? root.querySelectorAll("[style*='blob:']") : []; + for (const el of styled) { + try { + const styleText = el.getAttribute("style"); + if (styleText && styleText.includes("blob:")) { + const replaced = await replaceBlobUrlsInCssText(styleText); + el.setAttribute("style", replaced); + } + } catch { + } + } + const styleTags = root.querySelectorAll ? root.querySelectorAll("style") : []; + for (const s of styleTags) { + try { + const css = s.textContent || ""; + if (css.includes("blob:")) { + s.textContent = await replaceBlobUrlsInCssText(css); + } + } catch { + } + } + const urlAttrs = ["poster"]; + for (const attr of urlAttrs) { + const nodes = root.querySelectorAll ? root.querySelectorAll(`[${attr}^='blob:']`) : []; + for (const n of nodes) { + try { + const u = n.getAttribute(attr); + if (isBlobUrl(u)) { + n.setAttribute(attr, await blobUrlToDataUrl(u)); + } + } catch { + } + } + } +} + +// src/core/clone.js +async function deepClone(node, sessionCache, options) { + if (!node) throw new Error("Invalid node"); + const clonedAssignedNodes = /* @__PURE__ */ new Set(); + let pendingSelectValue = null; + let pendingTextAreaValue = null; + if (node.nodeType === Node.ELEMENT_NODE) { + const tag = (node.localName || node.tagName || "").toLowerCase(); + if (node.id === "snapdom-sandbox" || node.hasAttribute("data-snapdom-sandbox")) { + return null; + } + if (NO_CAPTURE_TAGS.has(tag)) { + return null; + } + } + if (node.nodeType === Node.TEXT_NODE) { + return node.cloneNode(true); + } + if (node.nodeType !== Node.ELEMENT_NODE) { + return node.cloneNode(true); + } + if (node.getAttribute("data-capture") === "exclude") { + if (options.excludeMode === "hide") { + const spacer = document.createElement("div"); + const rect = node.getBoundingClientRect(); + spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`; + return spacer; + } else if (options.excludeMode === "remove") { + return null; + } + } + if (options.exclude && Array.isArray(options.exclude)) { + for (const selector of options.exclude) { + try { + if (node.matches?.(selector)) { + if (options.excludeMode === "hide") { + const spacer = document.createElement("div"); + const rect = node.getBoundingClientRect(); + spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`; + return spacer; + } else if (options.excludeMode === "remove") { + return null; + } + } + } catch (err) { + console.warn(`Invalid selector in exclude option: ${selector}`, err); + } + } + } + if (typeof options.filter === "function") { + try { + if (!options.filter(node)) { + if (options.filterMode === "hide") { + const spacer = document.createElement("div"); + const rect = node.getBoundingClientRect(); + spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`; + return spacer; + } else if (options.filterMode === "remove") { + return null; + } + } + } catch (err) { + console.warn("Error in filter function:", err); + } + } + if (node.tagName === "IFRAME") { + let sameOrigin = false; + try { + sameOrigin = !!(node.contentDocument || node.contentWindow?.document); + } catch { + sameOrigin = false; + } + if (sameOrigin) { + try { + const wrapper = await rasterizeIframe(node, sessionCache, options); + return wrapper; + } catch (err) { + console.warn("[SnapDOM] iframe rasterization failed, fallback:", err); + } + } + if (options.placeholders) { + const fallback = document.createElement("div"); + fallback.style.cssText = `width:${node.offsetWidth}px;height:${node.offsetHeight}px;background-image:repeating-linear-gradient(45deg,#ddd,#ddd 5px,#f9f9f9 5px,#f9f9f9 10px);display:flex;align-items:center;justify-content:center;font-size:12px;color:#555;border:1px solid #aaa;`; + inlineAllStyles(node, fallback, sessionCache, options); + return fallback; + } else { + const rect = node.getBoundingClientRect(); + const spacer = document.createElement("div"); + spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`; + inlineAllStyles(node, spacer, sessionCache, options); + return spacer; + } + } + if (node.getAttribute("data-capture") === "placeholder") { + const clone2 = node.cloneNode(false); + sessionCache.nodeMap.set(clone2, node); + inlineAllStyles(node, clone2, sessionCache, options); + const placeholder = document.createElement("div"); + placeholder.textContent = node.getAttribute("data-placeholder-text") || ""; + placeholder.style.cssText = "color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;"; + clone2.appendChild(placeholder); + return clone2; + } + if (node.tagName === "CANVAS") { + let url = ""; + try { + const ctx = node.getContext("2d", { willReadFrequently: true }); + try { + ctx && ctx.getImageData(0, 0, 1, 1); + } catch { + } + await new Promise((r) => requestAnimationFrame(r)); + url = node.toDataURL("image/png"); + if (!url || url === "data:,") { + try { + ctx && ctx.getImageData(0, 0, 1, 1); + } catch { + } + await new Promise((r) => requestAnimationFrame(r)); + url = node.toDataURL("image/png"); + if (!url || url === "data:,") { + const scratch = document.createElement("canvas"); + scratch.width = node.width; + scratch.height = node.height; + const sctx = scratch.getContext("2d"); + if (sctx) { + sctx.drawImage(node, 0, 0); + url = scratch.toDataURL("image/png"); + } + } + } + } catch { + } + const img = document.createElement("img"); + try { + img.decoding = "sync"; + img.loading = "eager"; + } catch { + } + if (url) img.src = url; + img.width = node.width; + img.height = node.height; + try { + const cs = getComputedStyle(node); + if (cs.width) img.style.width = cs.width; + if (cs.height) img.style.height = cs.height; + } catch { + } + sessionCache.nodeMap.set(img, node); + inlineAllStyles(node, img, sessionCache, options); + return img; + } + let clone; + try { + clone = node.cloneNode(false); + resolveCSSVars(node, clone); + sessionCache.nodeMap.set(clone, node); + if (node.tagName === "IMG") { + freezeImgSrcset(node, clone); + try { + const rect = node.getBoundingClientRect(); + let w = Math.round(rect.width || 0); + let h = Math.round(rect.height || 0); + if (!w || !h) { + const computed = window.getComputedStyle(node); + const cssW = parseFloat(computed.width) || 0; + const cssH = parseFloat(computed.height) || 0; + const attrW = parseInt(node.getAttribute("width") || "", 10) || 0; + const attrH = parseInt(node.getAttribute("height") || "", 10) || 0; + const propW = node.width || node.naturalWidth || 0; + const propH = node.height || node.naturalHeight || 0; + w = Math.round(w || cssW || attrW || propW || 0); + h = Math.round(h || cssH || attrH || propH || 0); + } + if (w) clone.dataset.snapdomWidth = String(w); + if (h) clone.dataset.snapdomHeight = String(h); + } catch { + } + try { + const authored = node.getAttribute("style") || ""; + const cs = window.getComputedStyle(node); + const usesPercentOrAuto = (prop) => { + const a = authored.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i")); + const v = a ? a[1].trim() : cs.getPropertyValue(prop); + return /%|auto/i.test(String(v || "")); + }; + const w = parseInt(clone.dataset.snapdomWidth || "0", 10); + const h = parseInt(clone.dataset.snapdomHeight || "0", 10); + const needFreezeW = usesPercentOrAuto("width") || !w; + const needFreezeH = usesPercentOrAuto("height") || !h; + if (needFreezeW && w) clone.style.width = `${w}px`; + if (needFreezeH && h) clone.style.height = `${h}px`; + if (w) clone.style.minWidth = `${w}px`; + if (h) clone.style.minHeight = `${h}px`; + } catch { + } + } + } catch (err) { + console.error("[Snapdom] Failed to clone node:", node, err); + throw err; + } + if (node instanceof HTMLTextAreaElement) { + const rect = node.getBoundingClientRect(); + clone.style.width = `${rect.width}px`; + clone.style.height = `${rect.height}px`; + } + if (node instanceof HTMLInputElement) { + clone.value = node.value; + clone.setAttribute("value", node.value); + if (node.checked !== void 0) { + clone.checked = node.checked; + if (node.checked) clone.setAttribute("checked", ""); + if (node.indeterminate) clone.indeterminate = node.indeterminate; + } + } + if (node instanceof HTMLSelectElement) { + pendingSelectValue = node.value; + } + if (node instanceof HTMLTextAreaElement) { + pendingTextAreaValue = node.value; + } + inlineAllStyles(node, clone, sessionCache, options); + if (node.shadowRoot) { + let callback2 = function(child, resolve) { + if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "STYLE") { + return resolve(null); + } else { + deepClone(child, sessionCache, options).then((clonedChild) => { + resolve(clonedChild || null); + }).catch(() => { + resolve(null); + }); + } + }; + try { + const slots = node.shadowRoot.querySelectorAll("slot"); + for (const s of slots) { + let assigned = []; + try { + assigned = s.assignedNodes?.({ flatten: true }) || s.assignedNodes?.() || []; + } catch { + assigned = s.assignedNodes?.() || []; + } + for (const an of assigned) clonedAssignedNodes.add(an); + } + } catch { + } + const scopeId = nextShadowScopeId(sessionCache); + const scopeSelector = `[data-sd="${scopeId}"]`; + try { + clone.setAttribute("data-sd", scopeId); + } catch { + } + const rawCSS = extractShadowCSS(node.shadowRoot); + const rewritten = rewriteShadowCSS(rawCSS, scopeSelector); + const neededVars = collectCustomPropsFromCSS(rawCSS); + const seed = buildSeedCustomPropsRule(node, neededVars, scopeSelector); + injectScopedStyle(clone, seed + rewritten, scopeId); + const shadowFrag = document.createDocumentFragment(); + const cloneList2 = await idleCallback(Array.from(node.shadowRoot.childNodes), callback2, options.fast); + shadowFrag.append(...cloneList2.filter((clonedChild) => !!clonedChild)); + clone.appendChild(shadowFrag); + } + if (node.tagName === "SLOT") { + let callback2 = function(child, resolve) { + deepClone(child, sessionCache, options).then((clonedChild) => { + if (clonedChild) { + markSlottedSubtree(clonedChild); + } + resolve(clonedChild || null); + }).catch(() => { + resolve(null); + }); + }; + const assigned = node.assignedNodes?.({ flatten: true }) || []; + const nodesToClone = assigned.length > 0 ? assigned : Array.from(node.childNodes); + const fragment = document.createDocumentFragment(); + const cloneList2 = await idleCallback(Array.from(nodesToClone), callback2, options.fast); + fragment.append(...cloneList2.filter((clonedChild) => !!clonedChild)); + return fragment; + } + function callback(child, resolve) { + if (clonedAssignedNodes.has(child)) return resolve(null); + deepClone(child, sessionCache, options).then((clonedChild) => { + resolve(clonedChild || null); + }).catch(() => { + resolve(null); + }); + } + const cloneList = await idleCallback(Array.from(node.childNodes), callback, options.fast); + clone.append(...cloneList.filter((clonedChild) => !!clonedChild)); + if (pendingSelectValue !== null && clone instanceof HTMLSelectElement) { + clone.value = pendingSelectValue; + for (const opt of clone.options) { + if (opt.value === pendingSelectValue) { + opt.setAttribute("selected", ""); + } else { + opt.removeAttribute("selected"); + } + } + } + if (pendingTextAreaValue !== null && clone instanceof HTMLTextAreaElement) { + clone.textContent = pendingTextAreaValue; + } + return clone; +} + +// src/modules/pseudo.js +init_utils(); + +// src/modules/fonts.js +init_helpers(); +init_cache(); + +// src/modules/iconFonts.js +var defaultIconFonts = [ + // /uicons/i, + /font\s*awesome/i, + /material\s*icons/i, + /ionicons/i, + /glyphicons/i, + /feather/i, + /bootstrap\s*icons/i, + /remix\s*icons/i, + /heroicons/i, + /layui/i, + /lucide/i +]; +var ICON_FONT_URLS = Object.assign({ + materialIconsFilled: "https://fonts.gstatic.com/s/materialicons/v48/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2", + materialIconsOutlined: "https://fonts.gstatic.com/s/materialiconsoutlined/v110/gok-H7zzDkdnRel8-DQ6KAXJ69wP1tGnf4ZGhUcel5euIg.woff2", + materialIconsRound: "https://fonts.gstatic.com/s/materialiconsround/v109/LDItaoyNOAY6Uewc665JcIzCKsKc_M9flwmPq_HTTw.woff2", + materialIconsSharp: "https://fonts.gstatic.com/s/materialiconssharp/v110/oPWQ_lt5nv4pWNJpghLP75WiFR4kLh3kvmvRImcycg.woff2" +}, typeof window !== "undefined" && window.__SNAPDOM_ICON_FONTS__ || {}); +var userIconFonts = []; +function extendIconFonts(fonts) { + const list = Array.isArray(fonts) ? fonts : [fonts]; + for (const f of list) { + if (f instanceof RegExp) userIconFonts.push(f); + else if (typeof f === "string") userIconFonts.push(new RegExp(f, "i")); + else console.warn("[snapdom] Ignored invalid iconFont value:", f); + } +} +function isIconFont2(input) { + const text = typeof input === "string" ? input : ""; + const candidates = [...defaultIconFonts, ...userIconFonts]; + for (const rx of candidates) { + if (rx instanceof RegExp && rx.test(text)) return true; + } + if (/icon/i.test(text) || /glyph/i.test(text) || /symbols/i.test(text) || /feather/i.test(text) || /fontawesome/i.test(text)) return true; + return false; +} +function isMaterialFamily(family = "") { + const s = String(family).toLowerCase(); + return /\bmaterial\s*icons\b/.test(s) || /\bmaterial\s*symbols\b/.test(s); +} +var loadedCanvasFamilies = /* @__PURE__ */ new Map(); +function parseAxes(variation = "") { + const out = /* @__PURE__ */ Object.create(null); + const v = String(variation || ""); + const rx = /['"]?\s*([A-Za-z]{3,4})\s*['"]?\s*([+-]?\d+(?:\.\d+)?)\s*/g; + let m; + while (m = rx.exec(v)) out[m[1].toUpperCase()] = Number(m[2]); + return out; +} +async function ensureLigatureCanvasFont(cssFamily, className, axes) { + const fam = String(cssFamily || ""); + const lowerFam = fam.toLowerCase(); + const cls = String(className || "").toLowerCase(); + if (/\bmaterial\s*icons\b/.test(lowerFam) && !/\bsymbols\b/.test(lowerFam)) { + return { familyForMeasure: fam, familyForCanvas: fam }; + } + const isSymbols = /\bmaterial\s*symbols\b/.test(lowerFam); + if (!isSymbols) { + return { familyForMeasure: fam, familyForCanvas: fam }; + } + const FILL = axes && (axes.FILL ?? axes.fill); + let style = "outlined"; + if (/\brounded\b/.test(cls) || /\bround\b/.test(cls)) style = "rounded"; + else if (/\bsharp\b/.test(cls)) style = "sharp"; + else if (/\boutlined\b/.test(cls)) style = "outlined"; + const filled = FILL === 1; + let pick = null; + if (filled) { + if (style === "outlined" && ICON_FONT_URLS.materialIconsFilled) { + pick = { url: ICON_FONT_URLS.materialIconsFilled, alias: "snapdom-mi-filled" }; + } else if (style === "rounded" && ICON_FONT_URLS.materialIconsRound) { + pick = { url: ICON_FONT_URLS.materialIconsRound, alias: "snapdom-mi-round" }; + } else if (style === "sharp" && ICON_FONT_URLS.materialIconsSharp) { + pick = { url: ICON_FONT_URLS.materialIconsSharp, alias: "snapdom-mi-sharp" }; + } + } + if (!pick) { + return { familyForMeasure: fam, familyForCanvas: fam }; + } + if (!loadedCanvasFamilies.has(pick.alias)) { + try { + const ff = new FontFace(pick.alias, `url(${pick.url})`, { style: "normal", weight: "400" }); + document.fonts.add(ff); + await ff.load(); + loadedCanvasFamilies.set(pick.alias, true); + } catch { + return { familyForMeasure: fam, familyForCanvas: fam }; + } + } + const quoted = `"${pick.alias}"`; + return { familyForMeasure: quoted, familyForCanvas: quoted }; +} +async function ensureMaterialFontsReady(family = "Material Icons", px = 24) { + try { + await Promise.all([ + document.fonts.load(`400 ${px}px "${String(family).replace(/["']/g, "")}"`), + document.fonts.ready + ]); + } catch { + } +} +function resolvePaintColor(cs) { + let fill = cs.getPropertyValue("-webkit-text-fill-color")?.trim() || ""; + const isTransparent = /^transparent$/i.test(fill) || /rgba?\(\s*0\s*,\s*0\s*,\s*0\s*,\s*0\s*\)/i.test(fill); + if (fill && !isTransparent && fill.toLowerCase() !== "currentcolor") return fill; + const c = cs.color?.trim(); + return c && c !== "inherit" ? c : "#000"; +} +async function materialIconToImage(ligatureText, { + family = "Material Icons", + weight = "normal", + fontSize = 32, + color = "#000", + variation = "", + className = "" +} = {}) { + const fam = String(family || "").replace(/^['"]+|['"]+$/g, ""); + const dpr = window.devicePixelRatio || 1; + const axes = parseAxes(variation); + const { familyForMeasure, familyForCanvas } = await ensureLigatureCanvasFont(fam, className, axes); + await ensureMaterialFontsReady(familyForCanvas.replace(/^["']+|["']+$/g, ""), fontSize); + const span = document.createElement("span"); + span.textContent = ligatureText; + span.style.position = "absolute"; + span.style.visibility = "hidden"; + span.style.left = "-99999px"; + span.style.whiteSpace = "nowrap"; + span.style.fontFamily = familyForMeasure; + span.style.fontWeight = String(weight || "normal"); + span.style.fontSize = `${fontSize}px`; + span.style.lineHeight = "1"; + span.style.margin = "0"; + span.style.padding = "0"; + span.style.fontFeatureSettings = "'liga' 1"; + span.style.fontVariantLigatures = "normal"; + span.style.color = color; + document.body.appendChild(span); + const rect = span.getBoundingClientRect(); + const width = Math.max(1, Math.ceil(rect.width)); + const height = Math.max(1, Math.ceil(rect.height)); + document.body.removeChild(span); + const canvas = document.createElement("canvas"); + canvas.width = width * dpr; + canvas.height = height * dpr; + const ctx = canvas.getContext("2d"); + ctx.scale(dpr, dpr); + ctx.font = `${weight ? `${weight} ` : ""}${fontSize}px ${familyForCanvas}`; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillStyle = color; + try { + ctx.fontKerning = "normal"; + } catch { + } + ctx.fillText(ligatureText, 0, 0); + return { + dataUrl: canvas.toDataURL(), + width, + height + }; +} +async function ligatureIconToImage(cloneRoot, sourceRoot) { + if (!(cloneRoot instanceof Element)) return 0; + const selector = '.material-icons, [class*="material-symbols"]'; + const cloneNodes = Array.from( + cloneRoot.querySelectorAll(selector) + ).filter((n) => n && n.textContent && n.textContent.trim()); + if (cloneNodes.length === 0) return 0; + const sourceNodes = sourceRoot instanceof Element ? Array.from(sourceRoot.querySelectorAll(selector)).filter((n) => n && n.textContent && n.textContent.trim()) : []; + let replaced = 0; + for (let i = 0; i < cloneNodes.length; i++) { + const el = cloneNodes[i]; + const src = sourceNodes[i] || null; + try { + const cs = src ? getComputedStyle(src) : getComputedStyle(el); + const family = cs.fontFamily || "Material Icons"; + if (!isMaterialFamily(family)) continue; + const text = (src || el).textContent.trim(); + if (!text) continue; + const size = parseInt(cs.fontSize, 10) || 24; + const weight = cs.fontWeight && cs.fontWeight !== "normal" ? cs.fontWeight : "normal"; + const color = resolvePaintColor(cs); + const variation = cs.fontVariationSettings && cs.fontVariationSettings !== "normal" ? cs.fontVariationSettings : ""; + const className = (src || el).className || ""; + const { dataUrl, width, height } = await materialIconToImage(text, { + family, + weight, + fontSize: size, + color, + variation, + className + }); + el.textContent = ""; + const img = el.ownerDocument.createElement("img"); + img.src = dataUrl; + img.alt = text; + img.style.height = `${size}px`; + img.style.width = `${Math.max(1, Math.round(width / height * size))}px`; + img.style.objectFit = "contain"; + img.style.verticalAlign = getComputedStyle(el).verticalAlign || "baseline"; + el.appendChild(img); + replaced++; + } catch { + } + } + return replaced; +} + +// src/modules/fonts.js +init_snapFetch(); +async function iconToImage(unicodeChar, fontFamily, fontWeight, fontSize = 32, color = "#000") { + fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, ""); + const dpr = window.devicePixelRatio || 1; + try { + await document.fonts.ready; + } catch { + } + const span = document.createElement("span"); + span.textContent = unicodeChar; + span.style.position = "absolute"; + span.style.visibility = "hidden"; + span.style.fontFamily = `"${fontFamily}"`; + span.style.fontWeight = fontWeight || "normal"; + span.style.fontSize = `${fontSize}px`; + span.style.lineHeight = "1"; + span.style.whiteSpace = "nowrap"; + span.style.padding = "0"; + span.style.margin = "0"; + document.body.appendChild(span); + const rect = span.getBoundingClientRect(); + const width = Math.ceil(rect.width); + const height = Math.ceil(rect.height); + document.body.removeChild(span); + const canvas = document.createElement("canvas"); + canvas.width = Math.max(1, width * dpr); + canvas.height = Math.max(1, height * dpr); + const ctx = canvas.getContext("2d"); + ctx.scale(dpr, dpr); + ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`; + ctx.textAlign = "left"; + ctx.textBaseline = "top"; + ctx.fillStyle = color; + ctx.fillText(unicodeChar, 0, 0); + return { + dataUrl: canvas.toDataURL(), + width, + height + }; +} +var GENERIC_FAMILIES = /* @__PURE__ */ new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "emoji", + "math", + "fangsong", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded" +]); +function pickPrimaryFamily(familyList) { + if (!familyList) return ""; + for (let raw of familyList.split(",")) { + let f = raw.trim().replace(/^['"]+|['"]+$/g, ""); + if (!f) continue; + if (!GENERIC_FAMILIES.has(f.toLowerCase())) return f; + } + return ""; +} +function normWeight(w) { + const t = String(w ?? "400").trim().toLowerCase(); + if (t === "normal") return 400; + if (t === "bold") return 700; + const n = parseInt(t, 10); + return Number.isFinite(n) ? Math.min(900, Math.max(100, n)) : 400; +} +function normStyle(s) { + const t = String(s ?? "normal").trim().toLowerCase(); + if (t.startsWith("italic")) return "italic"; + if (t.startsWith("oblique")) return "oblique"; + return "normal"; +} +function normStretchPct(st) { + const m = String(st ?? "100%").match(/(\d+(?:\.\d+)?)\s*%/); + return m ? Math.max(50, Math.min(200, parseFloat(m[1]))) : 100; +} +function parseWeightSpec(spec) { + const s = String(spec || "400").trim(); + const m = s.match(/^(\d{2,3})\s+(\d{2,3})$/); + if (m) { + const a = normWeight(m[1]), b = normWeight(m[2]); + return { min: Math.min(a, b), max: Math.max(a, b) }; + } + const v = normWeight(s); + return { min: v, max: v }; +} +function parseStyleSpec(spec) { + const t = String(spec || "normal").trim().toLowerCase(); + if (t === "italic") return { kind: "italic" }; + if (t.startsWith("oblique")) return { kind: "oblique" }; + return { kind: "normal" }; +} +function parseStretchSpec(spec) { + const s = String(spec || "100%").trim(); + const mm = s.match(/(\d+(?:\.\d+)?)\s*%\s+(\d+(?:\.\d+)?)\s*%/); + if (mm) { + const a = parseFloat(mm[1]), b = parseFloat(mm[2]); + return { min: Math.min(a, b), max: Math.max(a, b) }; + } + const m = s.match(/(\d+(?:\.\d+)?)\s*%/); + const v = m ? parseFloat(m[1]) : 100; + return { min: v, max: v }; +} +function isLikelyFontStylesheet(href, requiredFamilies) { + if (!href) return false; + try { + const u = new URL(href, location.href); + const sameOrigin = u.origin === location.origin; + if (sameOrigin) return true; + const host = u.host.toLowerCase(); + const FONT_HOSTS = [ + "fonts.googleapis.com", + "fonts.gstatic.com", + "use.typekit.net", + "p.typekit.net", + "kit.fontawesome.com", + "use.fontawesome.com" + ]; + if (FONT_HOSTS.some((h) => host.endsWith(h))) return true; + const path = (u.pathname + u.search).toLowerCase(); + if (/\bfont(s)?\b/.test(path) || /\.woff2?(\b|$)/.test(path)) return true; + for (const fam of requiredFamilies) { + const tokenA = fam.toLowerCase().replace(/\s+/g, "+"); + const tokenB = fam.toLowerCase().replace(/\s+/g, "-"); + if (path.includes(tokenA) || path.includes(tokenB)) return true; + } + return false; + } catch { + return false; + } +} +function familiesFromRequired(required) { + const out = /* @__PURE__ */ new Set(); + for (const k of required || []) { + const fam = String(k).split("__")[0]?.trim(); + if (fam) out.add(fam); + } + return out; +} +function rewriteRelativeUrls(cssText, baseHref) { + if (!cssText) return cssText; + return cssText.replace( + /url\(\s*(['"]?)([^)'"]+)\1\s*\)/g, + (m, q, u) => { + const src = (u || "").trim(); + if (!src || /^data:|^blob:|^https?:|^file:|^about:/i.test(src)) return m; + let abs = src; + try { + abs = new URL(src, baseHref || location.href).href; + } catch { + } + return `url("${abs}")`; + } + ); +} +var IMPORT_ANY_RE = /@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g; +var MAX_IMPORT_DEPTH = 4; +async function inlineImportsAndRewrite(cssText, ownerHref, useProxy) { + if (!cssText) return cssText; + const visited = /* @__PURE__ */ new Set(); + function normalizeUrl(u, base) { + try { + return new URL(u, base || location.href).href; + } catch { + return u; + } + } + async function resolveOnce(text, baseHref, depth = 0) { + if (depth > MAX_IMPORT_DEPTH) { + console.warn(`[snapDOM] @import depth exceeded (${MAX_IMPORT_DEPTH}) at ${baseHref}`); + return text; + } + let out = ""; + let last = 0; + let m; + while (m = IMPORT_ANY_RE.exec(text)) { + out += text.slice(last, m.index); + last = IMPORT_ANY_RE.lastIndex; + const rawUrl = (m[2] || m[4] || "").trim(); + const absUrl = normalizeUrl(rawUrl, baseHref); + if (visited.has(absUrl)) { + console.warn(`[snapDOM] Skipping circular @import: ${absUrl}`); + continue; + } + visited.add(absUrl); + let imported = ""; + try { + const r = await snapFetch(absUrl, { as: "text", useProxy, silent: true }); + if (r.ok && typeof r.data === "string") imported = r.data; + } catch { + } + if (imported) { + imported = rewriteRelativeUrls(imported, absUrl); + imported = await resolveOnce(imported, absUrl, depth + 1); + out += ` +/* inlined: ${absUrl} */ +${imported} +`; + } else { + out += m[0]; + } + } + out += text.slice(last); + return out; + } + let rewritten = rewriteRelativeUrls(cssText, ownerHref || location.href); + rewritten = await resolveOnce(rewritten, ownerHref || location.href, 0); + return rewritten; +} +var URL_RE = /url\((["']?)([^"')]+)\1\)/g; +var FACE_RE = /@font-face[^{}]*\{[^}]*\}/g; +function parseUnicodeRange(ur) { + if (!ur) return []; + const ranges = []; + const parts = ur.split(",").map((s) => s.trim()).filter(Boolean); + for (const p of parts) { + const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/); + if (!m) continue; + const a = m[1], b = m[2]; + const expand = (hex) => { + if (!hex.includes("?")) return parseInt(hex, 16); + const min = parseInt(hex.replace(/\?/g, "0"), 16); + const max = parseInt(hex.replace(/\?/g, "F"), 16); + return [min, max]; + }; + if (b) { + const A = expand(a), B = expand(b); + const min = Array.isArray(A) ? A[0] : A; + const max = Array.isArray(B) ? B[1] : B; + ranges.push([Math.min(min, max), Math.max(min, max)]); + } else { + const X = expand(a); + if (Array.isArray(X)) ranges.push([X[0], X[1]]); + else ranges.push([X, X]); + } + } + return ranges; +} +function unicodeIntersects(used, ranges) { + if (!ranges.length) return true; + if (!used || used.size === 0) return true; + for (const cp of used) { + for (const [a, b] of ranges) if (cp >= a && cp <= b) return true; + } + return false; +} +function extractSrcUrls(srcValue, baseHref) { + const urls = []; + if (!srcValue) return urls; + for (const m of srcValue.matchAll(URL_RE)) { + let u = (m[2] || "").trim(); + if (!u || u.startsWith("data:")) continue; + if (!/^https?:/i.test(u)) { + try { + u = new URL(u, baseHref || location.href).href; + } catch { + } + } + urls.push(u); + } + return urls; +} +async function inlineUrlsInCssBlock(cssBlock, baseHref, useProxy = "") { + let out = cssBlock; + for (const m of cssBlock.matchAll(URL_RE)) { + const raw = extractURL(m[0]); + if (!raw) continue; + let abs = raw; + if (!abs.startsWith("http") && !abs.startsWith("data:")) { + try { + abs = new URL(abs, baseHref || location.href).href; + } catch { + } + } + if (isIconFont2(abs)) continue; + if (cache.resource?.has(abs)) { + cache.font?.add(abs); + out = out.replace(m[0], `url(${cache.resource.get(abs)})`); + continue; + } + if (cache.font?.has(abs)) continue; + try { + const r = await snapFetch(abs, { as: "dataURL", useProxy, silent: true }); + if (r.ok && typeof r.data === "string") { + const b64 = r.data; + cache.resource?.set(abs, b64); + cache.font?.add(abs); + out = out.replace(m[0], `url(${b64})`); + } + } catch { + console.warn("[snapDOM] Failed to fetch font resource:", abs); + } + } + return out; +} +function subsetFromRanges(ranges) { + if (!ranges.length) return null; + const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b)); + const latin = hit(0, 255) || hit(305, 305); + const latinExt = hit(256, 591) || hit(7680, 7935); + const greek = hit(880, 1023); + const cyr = hit(1024, 1279); + const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432); + if (viet) return "vietnamese"; + if (cyr) return "cyrillic"; + if (greek) return "greek"; + if (latinExt) return "latin-ext"; + if (latin) return "latin"; + return null; +} +function buildSimpleExcluder(ex = {}) { + const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase())); + const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase())); + const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase())); + return (meta, parsedRanges) => { + if (famSet.size && famSet.has(meta.family.toLowerCase())) return true; + if (domSet.size) { + for (const u of meta.srcUrls) { + try { + if (domSet.has(new URL(u).host.toLowerCase())) return true; + } catch { + } + } + } + if (subSet.size) { + const label = subsetFromRanges(parsedRanges); + if (label && subSet.has(label)) return true; + } + return false; + }; +} +function dedupeFontFaces(cssText) { + if (!cssText) return cssText; + const FACE_RE_G = /@font-face[^{}]*\{[^}]*\}/gi; + const seen = /* @__PURE__ */ new Set(); + const out = []; + for (const block of cssText.match(FACE_RE_G) || []) { + const familyRaw = block.match(/font-family:\s*([^;]+);/i)?.[1] || ""; + const family = pickPrimaryFamily(familyRaw); + const weightSpec = (block.match(/font-weight:\s*([^;]+);/i)?.[1] || "400").trim(); + const styleSpec = (block.match(/font-style:\s*([^;]+);/i)?.[1] || "normal").trim(); + const stretchSpec = (block.match(/font-stretch:\s*([^;]+);/i)?.[1] || "100%").trim(); + const urange = (block.match(/unicode-range:\s*([^;]+);/i)?.[1] || "").trim(); + const srcRaw = (block.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1] || "").trim(); + const urls = extractSrcUrls(srcRaw, location.href); + const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase(); + const key = [ + String(family || "").toLowerCase(), + weightSpec, + styleSpec, + stretchSpec, + urange.toLowerCase(), + srcPart + ].join("|"); + if (!seen.has(key)) { + seen.add(key); + out.push(block); + } + } + if (out.length === 0) return cssText; + let i = 0; + return cssText.replace(FACE_RE_G, () => out[i++] || ""); +} +function buildFontsCacheKey(required, exclude, localFonts, useProxy) { + const req = Array.from(required || []).sort().join("|"); + const ex = exclude ? JSON.stringify({ + families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(), + domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(), + subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort() + }) : ""; + const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|"); + const px = useProxy || ""; + return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`; +} +async function collectFacesFromSheet(sheet, baseHref, emitFace, ctx) { + let rules; + try { + rules = sheet.cssRules || []; + } catch { + return; + } + const normalizeUrl = (u, base) => { + try { + return new URL(u, base || location.href).href; + } catch { + return u; + } + }; + for (const rule of rules) { + if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet) { + const childHref = rule.href ? normalizeUrl(rule.href, baseHref) : baseHref; + if (ctx.depth >= MAX_IMPORT_DEPTH) { + console.warn(`[snapDOM] CSSOM import depth exceeded (${MAX_IMPORT_DEPTH}) at ${childHref}`); + continue; + } + if (childHref && ctx.visitedSheets.has(childHref)) { + console.warn(`[snapDOM] Skipping circular CSSOM import: ${childHref}`); + continue; + } + if (childHref) ctx.visitedSheets.add(childHref); + const nextCtx = { ...ctx, depth: (ctx.depth || 0) + 1 }; + await collectFacesFromSheet(rule.styleSheet, childHref, emitFace, nextCtx); + continue; + } + if (rule.type === CSSRule.FONT_FACE_RULE) { + const famRaw = (rule.style.getPropertyValue("font-family") || "").trim(); + const family = pickPrimaryFamily(famRaw); + if (!family || isIconFont2(family)) continue; + const weightSpec = (rule.style.getPropertyValue("font-weight") || "400").trim(); + const styleSpec = (rule.style.getPropertyValue("font-style") || "normal").trim(); + const stretchSpec = (rule.style.getPropertyValue("font-stretch") || "100%").trim(); + const srcRaw = (rule.style.getPropertyValue("src") || "").trim(); + const urange = (rule.style.getPropertyValue("unicode-range") || "").trim(); + if (!ctx.faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue; + const ranges = parseUnicodeRange(urange); + if (!unicodeIntersects(ctx.usedCodepoints, ranges)) continue; + const meta = { + family, + weightSpec, + styleSpec, + stretchSpec, + unicodeRange: urange, + srcRaw, + srcUrls: extractSrcUrls(srcRaw, baseHref || location.href), + href: baseHref || location.href + }; + if (ctx.simpleExcluder && ctx.simpleExcluder(meta, ranges)) continue; + if (/url\(/i.test(srcRaw)) { + const inlinedSrc = await inlineUrlsInCssBlock(srcRaw, baseHref || location.href, ctx.useProxy); + await emitFace(`@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`); + } else { + await emitFace(`@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`); + } + } + } +} +async function embedCustomFonts({ + required, + usedCodepoints, + exclude = void 0, + localFonts = [], + useProxy = "" +} = {}) { + if (!(required instanceof Set)) required = /* @__PURE__ */ new Set(); + if (!(usedCodepoints instanceof Set)) usedCodepoints = /* @__PURE__ */ new Set(); + const requiredIndex = /* @__PURE__ */ new Map(); + for (const key of required) { + const [fam, w, s, st] = String(key).split("__"); + if (!fam) continue; + const arr = requiredIndex.get(fam) || []; + arr.push({ w: parseInt(w, 10), s, st: parseInt(st, 10) }); + requiredIndex.set(fam, arr); + } + function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) { + if (!requiredIndex.has(fam)) return false; + const need = requiredIndex.get(fam); + const ws = parseWeightSpec(weightSpec); + const ss = parseStyleSpec(styleSpec); + const ts = parseStretchSpec(stretchSpec); + const faceIsRange = ws.min !== ws.max; + const faceSingleW = ws.min; + const styleOK = (reqKind) => ss.kind === "normal" && reqKind === "normal" || ss.kind !== "normal" && (reqKind === "italic" || reqKind === "oblique"); + let exactMatched = false; + for (const r of need) { + const wOk = faceIsRange ? r.w >= ws.min && r.w <= ws.max : r.w === faceSingleW; + const sOk = styleOK(normStyle(r.s)); + const tOk = r.st >= ts.min && r.st <= ts.max; + if (wOk && sOk && tOk) { + exactMatched = true; + break; + } + } + if (exactMatched) return true; + if (!faceIsRange) { + for (const r of need) { + const sOk = styleOK(normStyle(r.s)); + const tOk = r.st >= ts.min && r.st <= ts.max; + const nearWeight = Math.abs(faceSingleW - r.w) <= 300; + if (nearWeight && sOk && tOk) return true; + } + } + if (!faceIsRange && ss.kind === "normal") { + const hasItalicRequest = need.some((r) => normStyle(r.s) !== "normal"); + if (hasItalicRequest) { + for (const r of need) { + const nearWeight = Math.abs(faceSingleW - r.w) <= 300; + const stretchOK = r.st >= ts.min && r.st <= ts.max; + if (nearWeight && stretchOK) { + return true; + } + } + } + } + return false; + } + const simpleExcluder = buildSimpleExcluder(exclude); + const cacheKey = buildFontsCacheKey(required, exclude, localFonts, useProxy); + if (cache.resource?.has(cacheKey)) { + return cache.resource.get(cacheKey); + } + const requiredFamilies = familiesFromRequired(required); + const importUrls = []; + const IMPORT_ANY_RE_LOCAL = IMPORT_ANY_RE; + for (const styleTag of document.querySelectorAll("style")) { + const cssText = styleTag.textContent || ""; + for (const m of cssText.matchAll(IMPORT_ANY_RE_LOCAL)) { + const u = (m[2] || m[4] || "").trim(); + if (!u || isIconFont2(u)) continue; + const hasLink = !!document.querySelector(`link[rel="stylesheet"][href="${u}"]`); + if (!hasLink) importUrls.push(u); + } + } + if (importUrls.length) { + await Promise.all(importUrls.map((u) => new Promise((resolve) => { + if (document.querySelector(`link[rel="stylesheet"][href="${u}"]`)) return resolve(null); + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = u; + link.setAttribute("data-snapdom", "injected-import"); + link.onload = () => resolve(link); + link.onerror = () => resolve(null); + document.head.appendChild(link); + }))); + } + let finalCSS = ""; + const linkNodes = Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter((l) => !!l.href); + for (const link of linkNodes) { + try { + if (isIconFont2(link.href)) continue; + let cssText = ""; + let sameOrigin = false; + try { + sameOrigin = new URL(link.href, location.href).origin === location.origin; + } catch { + } + if (!sameOrigin) { + if (!isLikelyFontStylesheet(link.href, requiredFamilies)) continue; + } + if (sameOrigin) { + const sheet = Array.from(document.styleSheets).find((s) => s.href === link.href); + if (sheet) { + try { + const rules = sheet.cssRules || []; + cssText = Array.from(rules).map((r) => r.cssText).join(""); + } catch { + } + } + } + if (!cssText) { + const res = await snapFetch(link.href, { as: "text", useProxy }); + cssText = res.data; + if (isIconFont2(link.href)) continue; + } + cssText = await inlineImportsAndRewrite(cssText, link.href, useProxy); + let facesOut = ""; + for (const face of cssText.match(FACE_RE) || []) { + const famRaw = (face.match(/font-family:\s*([^;]+);/i)?.[1] || "").trim(); + const family = pickPrimaryFamily(famRaw); + if (!family || isIconFont2(family)) continue; + const weightSpec = (face.match(/font-weight:\s*([^;]+);/i)?.[1] || "400").trim(); + const styleSpec = (face.match(/font-style:\s*([^;]+);/i)?.[1] || "normal").trim(); + const stretchSpec = (face.match(/font-stretch:\s*([^;]+);/i)?.[1] || "100%").trim(); + const urange = (face.match(/unicode-range:\s*([^;]+);/i)?.[1] || "").trim(); + const srcRaw = (face.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1] || "").trim(); + const srcUrls = extractSrcUrls(srcRaw, link.href); + if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue; + const ranges = parseUnicodeRange(urange); + if (!unicodeIntersects(usedCodepoints, ranges)) continue; + const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: link.href }; + if (exclude && simpleExcluder(meta, ranges)) continue; + const newFace = /url\(/i.test(srcRaw) ? await inlineUrlsInCssBlock(face, link.href, useProxy) : face; + facesOut += newFace; + } + if (facesOut.trim()) finalCSS += facesOut; + } catch { + console.warn("[snapDOM] Failed to process stylesheet:", link.href); + } + } + const ctx = { + requiredIndex, + usedCodepoints, + faceMatchesRequired, + simpleExcluder: exclude ? buildSimpleExcluder(exclude) : null, + useProxy, + visitedSheets: /* @__PURE__ */ new Set(), + depth: 0 + }; + for (const sheet of document.styleSheets) { + if (sheet.href && linkNodes.some((l) => l.href === sheet.href)) continue; + try { + const rootHref = sheet.href || location.href; + if (rootHref) ctx.visitedSheets.add(rootHref); + await collectFacesFromSheet( + sheet, + rootHref, + async (faceCss) => { + finalCSS += faceCss; + }, + ctx + ); + } catch { + } + } + try { + for (const f of document.fonts || []) { + if (!f || !f.family || f.status !== "loaded" || !f._snapdomSrc) continue; + const fam = String(f.family).replace(/^['"]+|['"]+$/g, ""); + if (isIconFont2(fam)) continue; + if (!requiredIndex.has(fam)) continue; + if (exclude?.families && exclude.families.some((n) => String(n).toLowerCase() === fam.toLowerCase())) { + continue; + } + let b64 = f._snapdomSrc; + if (!String(b64).startsWith("data:")) { + if (cache.resource?.has(f._snapdomSrc)) { + b64 = cache.resource.get(f._snapdomSrc); + cache.font?.add(f._snapdomSrc); + } else if (!cache.font?.has(f._snapdomSrc)) { + try { + const r = await snapFetch(f._snapdomSrc, { as: "dataURL", useProxy, silent: true }); + if (r.ok && typeof r.data === "string") { + b64 = r.data; + cache.resource?.set(f._snapdomSrc, b64); + cache.font?.add(f._snapdomSrc); + } else { + continue; + } + } catch { + console.warn("[snapDOM] Failed to fetch dynamic font src:", f._snapdomSrc); + continue; + } + } + } + finalCSS += `@font-face{font-family:'${fam}';src:url(${b64});font-style:${f.style || "normal"};font-weight:${f.weight || "normal"};}`; + } + } catch { + } + for (const font of localFonts) { + if (!font || typeof font !== "object") continue; + const family = String(font.family || "").replace(/^['"]+|['"]+$/g, ""); + if (!family || isIconFont2(family)) continue; + if (!requiredIndex.has(family)) continue; + if (exclude?.families && exclude.families.some((n) => String(n).toLowerCase() === family.toLowerCase())) continue; + const weight = font.weight != null ? String(font.weight) : "normal"; + const style = font.style != null ? String(font.style) : "normal"; + const stretch = font.stretchPct != null ? `${font.stretchPct}%` : "100%"; + const src = String(font.src || ""); + let b64 = src; + if (!b64.startsWith("data:")) { + if (cache.resource?.has(src)) { + b64 = cache.resource.get(src); + cache.font?.add(src); + } else if (!cache.font?.has(src)) { + try { + const r = await snapFetch(src, { as: "dataURL", useProxy, silent: true }); + if (r.ok && typeof r.data === "string") { + b64 = r.data; + cache.resource?.set(src, b64); + cache.font?.add(src); + } else { + continue; + } + } catch { + console.warn("[snapDOM] Failed to fetch localFonts src:", src); + continue; + } + } + } + finalCSS += `@font-face{font-family:'${family}';src:url(${b64});font-style:${style};font-weight:${weight};font-stretch:${stretch};}`; + } + if (finalCSS) { + finalCSS = dedupeFontFaces(finalCSS); + cache.resource?.set(cacheKey, finalCSS); + } + return finalCSS; +} +function collectUsedFontVariants(root) { + const req = /* @__PURE__ */ new Set(); + if (!root) return req; + const tw = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null); + const addFromStyle = (cs) => { + const family = pickPrimaryFamily(cs.fontFamily); + if (!family) return; + const key = (w, s, st) => `${family}__${normWeight(w)}__${normStyle(s)}__${normStretchPct(st)}`; + req.add(key(cs.fontWeight, cs.fontStyle, cs.fontStretch)); + }; + addFromStyle(getComputedStyle(root)); + const csBeforeRoot = getComputedStyle(root, "::before"); + if (csBeforeRoot && csBeforeRoot.content && csBeforeRoot.content !== "none") addFromStyle(csBeforeRoot); + const csAfterRoot = getComputedStyle(root, "::after"); + if (csAfterRoot && csAfterRoot.content && csAfterRoot.content !== "none") addFromStyle(csAfterRoot); + while (tw.nextNode()) { + const el = ( + /** @type {Element} */ + tw.currentNode + ); + const cs = getComputedStyle(el); + addFromStyle(cs); + const b = getComputedStyle(el, "::before"); + if (b && b.content && b.content !== "none") addFromStyle(b); + const a = getComputedStyle(el, "::after"); + if (a && a.content && a.content !== "none") addFromStyle(a); + } + return req; +} +function collectUsedCodepoints(root) { + const used = /* @__PURE__ */ new Set(); + const pushText = (txt) => { + if (!txt) return; + for (const ch of txt) used.add(ch.codePointAt(0)); + }; + const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null); + while (walker.nextNode()) { + const n = walker.currentNode; + if (n.nodeType === Node.TEXT_NODE) { + pushText(n.nodeValue || ""); + } else if (n.nodeType === Node.ELEMENT_NODE) { + const el = ( + /** @type {Element} */ + n + ); + for (const pseudo of ["::before", "::after"]) { + const cs = getComputedStyle(el, pseudo); + const c = cs?.getPropertyValue("content"); + if (!c || c === "none") continue; + if (/^"/.test(c) || /^'/.test(c)) { + pushText(c.slice(1, -1)); + } else { + const matches = c.match(/\\[0-9A-Fa-f]{1,6}/g); + if (matches) { + for (const m of matches) { + try { + used.add(parseInt(m.slice(1), 16)); + } catch { + } + } + } + } + } + } + } + return used; +} +async function ensureFontsReady(families, warmupRepetitions = 2) { + try { + await document.fonts.ready; + } catch { + } + const fams = Array.from(families || []).filter(Boolean); + if (fams.length === 0) return; + const warmupOnce = () => { + const container = document.createElement("div"); + container.style.cssText = "position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;"; + for (const fam of fams) { + const span = document.createElement("span"); + span.textContent = "AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E"; + span.style.fontFamily = `"${fam}"`; + span.style.fontWeight = "700"; + span.style.fontStyle = "italic"; + span.style.fontSize = "32px"; + span.style.lineHeight = "1"; + span.style.whiteSpace = "nowrap"; + span.style.margin = "0"; + span.style.padding = "0"; + container.appendChild(span); + } + document.body.appendChild(container); + container.offsetWidth; + document.body.removeChild(container); + }; + for (let i = 0; i < Math.max(1, warmupRepetitions); i++) { + warmupOnce(); + await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); + } +} + +// src/modules/counter.js +init_cache(); +function hasCounters(input) { + return /\bcounter\s*\(|\bcounters\s*\(/.test(input || ""); +} +function unquoteDoubleStrings(s) { + return (s || "").replace(/"([^"]*)"/g, "$1"); +} +function alpha(n, upper = false) { + let s = "", x = Math.max(1, n); + while (x > 0) { + x--; + s = String.fromCharCode(97 + x % 26) + s; + x = Math.floor(x / 26); + } + return upper ? s.toUpperCase() : s; +} +function roman(n, upper = true) { + const map = [[1e3, "M"], [900, "CM"], [500, "D"], [400, "CD"], [100, "C"], [90, "XC"], [50, "L"], [40, "XL"], [10, "X"], [9, "IX"], [5, "V"], [4, "IV"], [1, "I"]]; + let num = Math.max(1, Math.min(3999, n)), out = ""; + for (const [v, sym] of map) while (num >= v) { + out += sym; + num -= v; + } + return upper ? out : out.toLowerCase(); +} +function formatCounter(value, style) { + switch ((style || "decimal").toLowerCase()) { + case "decimal": + return String(Math.max(0, value)); + case "decimal-leading-zero": + return (value < 10 ? "0" : "") + String(Math.max(0, value)); + case "lower-alpha": + return alpha(value, false); + case "upper-alpha": + return alpha(value, true); + case "lower-roman": + return roman(value, false); + case "upper-roman": + return roman(value, true); + default: + return String(Math.max(0, value)); + } +} +function buildCounterContext(root) { + const getEpoch = () => cache?.session?.__counterEpoch ?? 0; + let run = getEpoch(); + const nodeCounters = /* @__PURE__ */ new WeakMap(); + const rootEl = root instanceof Document ? root.documentElement : root; + const isLi = (el) => el && el.tagName === "LI"; + const countPrevLi = (li) => { + let c = 0, p = li?.parentElement; + if (!p) return 0; + for (const sib of p.children) { + if (sib === li) break; + if (sib.tagName === "LI") c++; + } + return c; + }; + const cloneMap = (m) => { + const out = /* @__PURE__ */ new Map(); + for (const [k, arr] of m) out.set(k, arr.slice()); + return out; + }; + const applyTo = (baseMap, parentMap, el) => { + const map = cloneMap(baseMap); + let reset; + try { + reset = el.style?.counterReset || getComputedStyle(el).counterReset; + } catch { + } + if (reset && reset !== "none") { + for (const part of reset.split(",")) { + const toks = part.trim().split(/\s+/); + const name = toks[0]; + const val = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 0; + if (!name) continue; + const parentStack = parentMap.get(name); + if (parentStack && parentStack.length) { + const s = parentStack.slice(); + s.push(val); + map.set(name, s); + } else { + map.set(name, [val]); + } + } + } + let inc; + try { + inc = el.style?.counterIncrement || getComputedStyle(el).counterIncrement; + } catch { + } + if (inc && inc !== "none") { + for (const part of inc.split(",")) { + const toks = part.trim().split(/\s+/); + const name = toks[0]; + const by = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 1; + if (!name) continue; + const stack = map.get(name) || []; + if (stack.length === 0) stack.push(0); + stack[stack.length - 1] += by; + map.set(name, stack); + } + } + try { + const cs = getComputedStyle(el); + if (cs.display === "list-item" && isLi(el)) { + const p = el.parentElement; + let idx = 1; + if (p && p.tagName === "OL") { + const startAttr = p.getAttribute("start"); + const start = Number.isFinite(Number(startAttr)) ? Number(startAttr) : 1; + const prev = countPrevLi(el); + const ownAttr = el.getAttribute("value"); + idx = Number.isFinite(Number(ownAttr)) ? Number(ownAttr) : start + prev; + } else { + idx = 1 + countPrevLi(el); + } + const s = map.get("list-item") || []; + if (s.length === 0) s.push(0); + s[s.length - 1] = idx; + map.set("list-item", s); + } + } catch { + } + return map; + }; + const build = (el, parentMap, carryMap) => { + const curr = applyTo(carryMap, parentMap, el); + nodeCounters.set(el, curr); + let nextCarry = curr; + for (const child of el.children) { + const childCarry = build(child, curr, nextCarry); + nextCarry = childCarry; + } + return curr; + }; + const empty = /* @__PURE__ */ new Map(); + build(rootEl, empty, empty); + function ensureFresh() { + const now = getEpoch(); + if (now !== run) { + run = now; + const empty2 = /* @__PURE__ */ new Map(); + build(rootEl, empty2, empty2); + } + } + return { + /** + * Get top value for counter name at given node. + * @param {Element} node + * @param {string} name + */ + get(node, name) { + ensureFresh(); + const s = nodeCounters.get(node)?.get(name); + return s && s.length ? s[s.length - 1] : 0; + }, + /** + * Get full stack for counter name at given node. + * @param {Element} node + * @param {string} name + */ + getStack(node, name) { + ensureFresh(); + const s = nodeCounters.get(node)?.get(name); + return s ? s.slice() : []; + } + }; +} +function resolveCountersInContent(raw, node, ctx) { + if (!raw || raw === "none") return raw; + try { + const RX = /\b(counter|counters)\s*\(([^)]+)\)/g; + let out = raw.replace(RX, (_, fn, args) => { + const parts = String(args).split(",").map((s) => s.trim()); + if (fn === "counter") { + const name = parts[0]?.replace(/^["']|["']$/g, ""); + const style = (parts[1] || "decimal").toLowerCase(); + const v = ctx.get(node, name); + return formatCounter(v, style); + } else { + const name = parts[0]?.replace(/^["']|["']$/g, ""); + const sep = parts[1]?.replace(/^["']|["']$/g, "") ?? ""; + const style = (parts[2] || "decimal").toLowerCase(); + const stack = ctx.getStack(node, name); + if (!stack.length) return ""; + const pieces = stack.map((v) => formatCounter(v, style)); + return pieces.join(sep); + } + }); + return unquoteDoubleStrings(out); + } catch { + return "- "; + } +} + +// src/modules/pseudo.js +init_snapFetch(); +init_cache(); +var __preflightMemo = /* @__PURE__ */ new WeakMap(); +var CSS_RULE_SCAN_BUDGET = 300; +function preflightWithFp(doc, sessionCache) { + const fp = styleFingerprint(doc); + if (!sessionCache) return shouldProcessPseudos(doc); + if (sessionCache.__pseudoPreflightFp !== fp) { + sessionCache.__pseudoPreflight = shouldProcessPseudos(doc); + sessionCache.__pseudoPreflightFp = fp; + } + return !!sessionCache.__pseudoPreflight; +} +function safeRules(sheet) { + try { + return sheet && sheet.cssRules ? sheet.cssRules : null; + } catch { + return null; + } +} +function styleFingerprint(doc) { + const nodes = doc.querySelectorAll('style,link[rel~="stylesheet"]'); + let fp = `n:${nodes.length}|`; + let totalRules = 0; + for (let i = 0; i < nodes.length; i++) { + const n = nodes[i]; + if (n.tagName === "STYLE") { + const len = n.textContent ? n.textContent.length : 0; + fp += `S${len}|`; + const sheet = ( + /** @type {HTMLStyleElement} */ + n.sheet + ); + const rules = sheet ? safeRules(sheet) : null; + if (rules) totalRules += rules.length; + } else { + const href = n.getAttribute("href") || ""; + const media = n.getAttribute("media") || "all"; + fp += `L${href}|m:${media}|`; + const sheet = ( + /** @type {HTMLLinkElement} */ + n.sheet + ); + const rules = sheet ? safeRules(sheet) : null; + if (rules) totalRules += rules.length; + } + } + const ass = ( + /** @type {any} */ + doc.adoptedStyleSheets + ); + fp += `ass:${Array.isArray(ass) ? ass.length : 0}|tr:${totalRules}`; + return fp; +} +function sheetHasNeedles(sheet, needles, state) { + const rules = safeRules(sheet); + if (!rules) return false; + for (let i = 0; i < rules.length; i++) { + if (state.budget <= 0) return false; + const rule = rules[i]; + const css = rule && rule.cssText ? rule.cssText : ""; + state.budget--; + for (const k of needles) { + if (css.includes(k)) return true; + } + if (rule && rule.cssRules && rule.cssRules.length) { + for (let j = 0; j < rule.cssRules.length && state.budget > 0; j++) { + const inner = rule.cssRules[j]; + const innerCss = inner && inner.cssText ? inner.cssText : ""; + state.budget--; + for (const k of needles) { + if (innerCss.includes(k)) return true; + } + } + } + if (state.budget <= 0) return false; + } + return false; +} +function shouldProcessPseudos(doc = document) { + const fp = styleFingerprint(doc); + const memo = __preflightMemo.get(doc); + if (memo && memo.fingerprint === fp) return memo.result; + const NEEDLES = [ + // double-colon + "::before", + "::after", + "::first-letter", + // single-colon robustness + ":before", + ":after", + ":first-letter", + // counters + "counter(", + "counters(", + "counter-increment", + "counter-reset" + ]; + const styleEls = doc.querySelectorAll("style"); + for (let i = 0; i < styleEls.length; i++) { + const t = styleEls[i].textContent || ""; + for (const k of NEEDLES) if (t.includes(k)) { + __preflightMemo.set(doc, { fingerprint: fp, result: true }); + return true; + } + } + const ass = ( + /** @type {any} */ + doc.adoptedStyleSheets + ); + if (Array.isArray(ass) && ass.length) { + const state = { budget: CSS_RULE_SCAN_BUDGET }; + try { + for (const sheet of ass) { + if (sheetHasNeedles(sheet, NEEDLES, state)) { + __preflightMemo.set(doc, { fingerprint: fp, result: true }); + return true; + } + } + } catch { + } + } + { + const nodes = doc.querySelectorAll('style,link[rel~="stylesheet"]'); + const state = { budget: CSS_RULE_SCAN_BUDGET }; + for (let i = 0; i < nodes.length && state.budget > 0; i++) { + const n = nodes[i]; + let sheet = null; + if (n.tagName === "STYLE") { + sheet = /** @type {HTMLStyleElement} */ + n.sheet || null; + } else { + sheet = /** @type {HTMLLinkElement} */ + n.sheet || null; + } + if (sheet && sheetHasNeedles(sheet, NEEDLES, state)) { + __preflightMemo.set(doc, { fingerprint: fp, result: true }); + return true; + } + } + } + if (doc.querySelector('[style*="counter("], [style*="counters("]')) { + __preflightMemo.set(doc, { fingerprint: fp, result: true }); + return true; + } + __preflightMemo.set(doc, { fingerprint: fp, result: false }); + return false; +} +var __siblingCounters = /* @__PURE__ */ new WeakMap(); +var __pseudoEpoch = -1; +function unquoteDoubleStrings2(s) { + return (s || "").replace(/"([^"]*)"/g, "$1"); +} +function collapseCssContent(raw) { + if (!raw) return ""; + const tokens = []; + const rx = /"([^"]*)"/g; + let m; + while (m = rx.exec(raw)) tokens.push(m[1]); + if (tokens.length) return tokens.join(""); + return unquoteDoubleStrings2(raw); +} +function withSiblingOverrides(node, base) { + const parent = node.parentElement; + const map = parent ? __siblingCounters.get(parent) : null; + if (!map) return base; + return { + get(n, name) { + const v = base.get(n, name); + const ov = map.get(name); + return typeof ov === "number" ? Math.max(v, ov) : v; + }, + getStack(n, name) { + const s = base.getStack(n, name); + if (!s.length) return s; + const ov = map.get(name); + if (typeof ov === "number") { + const out = s.slice(); + out[out.length - 1] = Math.max(out[out.length - 1], ov); + return out; + } + return s; + } + }; +} +function deriveCounterCtxForPseudo(node, pseudoStyle, baseCtx) { + const modStacks = /* @__PURE__ */ new Map(); + function parseListDecl(value) { + const out = []; + if (!value || value === "none") return out; + for (const part of String(value).split(",")) { + const toks = part.trim().split(/\s+/); + const name = toks[0]; + const num = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : void 0; + if (name) out.push({ name, num }); + } + return out; + } + const resets = parseListDecl(pseudoStyle?.counterReset); + const incs = parseListDecl(pseudoStyle?.counterIncrement); + function getStackDerived(name) { + if (modStacks.has(name)) return modStacks.get(name).slice(); + let stack = baseCtx.getStack(node, name); + stack = stack.length ? stack.slice() : []; + const r = resets.find((x) => x.name === name); + if (r) { + const val = Number.isFinite(r.num) ? r.num : 0; + stack = stack.length ? [...stack, val] : [val]; + } + const inc = incs.find((x) => x.name === name); + if (inc) { + const by = Number.isFinite(inc.num) ? inc.num : 1; + if (stack.length === 0) stack = [0]; + stack[stack.length - 1] += by; + } + modStacks.set(name, stack.slice()); + return stack; + } + return { + get(_node, name) { + const s = getStackDerived(name); + return s.length ? s[s.length - 1] : 0; + }, + getStack(_node, name) { + return getStackDerived(name); + }, + /** expone increments del pseudo para que el caller pueda propagar a hermanos */ + __incs: incs + }; +} +function resolvePseudoContentAndIncs(node, pseudo, baseCtx) { + let ps; + try { + ps = getComputedStyle(node, pseudo); + } catch { + } + const raw = ps?.content; + if (!raw || raw === "none" || raw === "normal") return { text: "", incs: [] }; + const baseWithSiblings = withSiblingOverrides(node, baseCtx); + const derived = deriveCounterCtxForPseudo(node, ps, baseWithSiblings); + let resolved = hasCounters(raw) ? resolveCountersInContent(raw, node, derived) : raw; + const text = collapseCssContent(resolved); + return { text, incs: derived.__incs || [] }; +} +async function inlinePseudoElements(source, clone, sessionCache, options) { + if (!(source instanceof Element) || !(clone instanceof Element)) return; + const doc = source.ownerDocument || document; + if (!preflightWithFp(doc, sessionCache)) { + return; + } + const epoch = cache?.session?.__counterEpoch ?? 0; + if (__pseudoEpoch !== epoch) { + __siblingCounters = /* @__PURE__ */ new WeakMap(); + if (sessionCache) sessionCache.__counterCtx = null; + __pseudoEpoch = epoch; + } + if (!sessionCache.__counterCtx) { + try { + sessionCache.__counterCtx = buildCounterContext(source.ownerDocument || document); + } catch { + } + } + const counterCtx = sessionCache.__counterCtx; + for (const pseudo of ["::before", "::after", "::first-letter"]) { + try { + const style = getStyle(source, pseudo); + if (!style) continue; + const isEmptyPseudo = style.content === "none" && style.backgroundImage === "none" && style.backgroundColor === "transparent" && (style.borderStyle === "none" || parseFloat(style.borderWidth) === 0) && (!style.transform || style.transform === "none") && style.display === "inline"; + if (isEmptyPseudo) continue; + if (pseudo === "::first-letter") { + const normal = getComputedStyle(source); + const isMeaningful = style.color !== normal.color || style.fontSize !== normal.fontSize || style.fontWeight !== normal.fontWeight; + if (!isMeaningful) continue; + const textNode = Array.from(clone.childNodes).find( + (n) => n.nodeType === Node.TEXT_NODE && n.textContent?.trim().length > 0 + ); + if (!textNode) continue; + const text = textNode.textContent; + const match = text.match(/^([^\p{L}\p{N}\s]*[\p{L}\p{N}](?:['’])?)/u); + const first = match?.[0]; + const rest = text.slice(first?.length || 0); + if (!first || /[\uD800-\uDFFF]/.test(first)) continue; + const span = document.createElement("span"); + span.textContent = first; + span.dataset.snapdomPseudo = "::first-letter"; + const snapshot2 = snapshotComputedStyle(style); + const key2 = getStyleKey(snapshot2, "span"); + sessionCache.styleMap.set(span, key2); + const restNode = document.createTextNode(rest); + clone.replaceChild(restNode, textNode); + clone.insertBefore(span, restNode); + continue; + } + const rawContent = style.content ?? ""; + const isNoExplicitContent = rawContent === "" || rawContent === "none" || rawContent === "normal"; + const { text: cleanContent, incs } = resolvePseudoContentAndIncs(source, pseudo, counterCtx); + const bg = style.backgroundImage; + const bgColor = style.backgroundColor; + const fontFamily = style.fontFamily; + const fontSize = parseInt(style.fontSize) || 32; + const fontWeight = parseInt(style.fontWeight) || false; + const color = style.color || "#000"; + const borderStyle = style.borderStyle; + const borderWidth = parseFloat(style.borderWidth); + const transform = style.transform; + const isIconFont22 = isIconFont2(fontFamily); + const hasExplicitContent = !isNoExplicitContent && cleanContent !== ""; + const hasBg = bg && bg !== "none"; + const hasBgColor = bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)"; + const hasBorder = borderStyle && borderStyle !== "none" && borderWidth > 0; + const hasTransform = transform && transform !== "none"; + const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBorder || hasTransform; + if (!shouldRender) { + if (incs && incs.length && source.parentElement) { + const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map(); + for (const { name } of incs) { + if (!name) continue; + const baseWithSibs = withSiblingOverrides(source, counterCtx); + const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs); + const finalVal = derived.get(source, name); + map.set(name, finalVal); + } + __siblingCounters.set(source.parentElement, map); + } + continue; + } + const pseudoEl = document.createElement("span"); + pseudoEl.dataset.snapdomPseudo = pseudo; + pseudoEl.style.pointerEvents = "none"; + const snapshot = snapshotComputedStyle(style); + const key = getStyleKey(snapshot, "span"); + sessionCache.styleMap.set(pseudoEl, key); + if (isIconFont22 && cleanContent && cleanContent.length === 1) { + const { dataUrl, width: w, height: h } = await iconToImage(cleanContent, fontFamily, fontWeight, fontSize, color); + const imgEl = document.createElement("img"); + imgEl.src = dataUrl; + imgEl.style = `height:${fontSize}px;width:${w / h * fontSize}px;object-fit:contain;`; + pseudoEl.appendChild(imgEl); + clone.dataset.snapdomHasIcon = "true"; + } else if (cleanContent && cleanContent.startsWith("url(")) { + const rawUrl = extractURL(cleanContent); + if (rawUrl?.trim()) { + try { + const imgEl = document.createElement("img"); + const dataUrl = await snapFetch(safeEncodeURI(rawUrl), { as: "dataURL", useProxy: options.useProxy }); + imgEl.src = dataUrl.data; + imgEl.style = `width:${fontSize}px;height:auto;object-fit:contain;`; + pseudoEl.appendChild(imgEl); + } catch (e) { + console.error(`[snapdom] Error in pseudo ${pseudo} for`, source, e); + } + } + } else if (!isIconFont22 && hasExplicitContent) { + pseudoEl.textContent = cleanContent; + } + pseudoEl.style.backgroundImage = "none"; + if ("maskImage" in pseudoEl.style) pseudoEl.style.maskImage = "none"; + if ("webkitMaskImage" in pseudoEl.style) pseudoEl.style.webkitMaskImage = "none"; + try { + pseudoEl.style.backgroundRepeat = style.backgroundRepeat; + pseudoEl.style.backgroundSize = style.backgroundSize; + if (style.backgroundPositionX && style.backgroundPositionY) { + pseudoEl.style.backgroundPositionX = style.backgroundPositionX; + pseudoEl.style.backgroundPositionY = style.backgroundPositionY; + } else { + pseudoEl.style.backgroundPosition = style.backgroundPosition; + } + pseudoEl.style.backgroundOrigin = style.backgroundOrigin; + pseudoEl.style.backgroundClip = style.backgroundClip; + pseudoEl.style.backgroundAttachment = style.backgroundAttachment; + pseudoEl.style.backgroundBlendMode = style.backgroundBlendMode; + } catch { + } + if (hasBg) { + try { + const bgSplits = splitBackgroundImage(bg); + const newBgParts = await Promise.all(bgSplits.map(inlineSingleBackgroundEntry)); + pseudoEl.style.backgroundImage = newBgParts.join(", "); + } catch (e) { + console.warn(`[snapdom] Failed to inline background-image for ${pseudo}`, e); + } + } + if (hasBgColor) pseudoEl.style.backgroundColor = bgColor; + const hasContent2 = pseudoEl.childNodes.length > 0 || pseudoEl.textContent?.trim() !== ""; + const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBorder || hasTransform; + if (incs && incs.length && source.parentElement) { + const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map(); + const baseWithSibs = withSiblingOverrides(source, counterCtx); + const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs); + for (const { name } of incs) { + if (!name) continue; + const finalVal = derived.get(source, name); + map.set(name, finalVal); + } + __siblingCounters.set(source.parentElement, map); + } + if (!hasVisibleBox) continue; + if (pseudo === "::before") { + clone.insertBefore(pseudoEl, clone.firstChild); + } else { + clone.appendChild(pseudoEl); + } + } catch (e) { + console.warn(`[snapdom] Failed to capture ${pseudo} for`, source, e); + } + } + const sChildren = Array.from(source.children); + const cChildren = Array.from(clone.children).filter((child) => !child.dataset.snapdomPseudo); + for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) { + await inlinePseudoElements(sChildren[i], cChildren[i], sessionCache, options); + } +} + +// src/modules/svgDefs.js +function inlineExternalDefsAndSymbols(element, lookupRoot) { + if (!element || !(element instanceof Element)) return; + const doc = element.ownerDocument || document; + const searchRoot = lookupRoot || doc; + const svgRoots = element instanceof SVGSVGElement ? [element] : Array.from(element.querySelectorAll("svg")); + if (svgRoots.length === 0) return; + const URL_ID_RE = /url\(\s*#([^)]+)\)/g; + const URL_ATTRS = [ + "fill", + "stroke", + "filter", + "clip-path", + "mask", + "marker", + "marker-start", + "marker-mid", + "marker-end" + ]; + const cssEscape = (s) => window.CSS && CSS.escape ? CSS.escape(s) : s.replace(/[^a-zA-Z0-9_-]/g, "\\$&"); + const XLINK_NS = "http://www.w3.org/1999/xlink"; + const getHrefAttr = (el) => { + if (!el || !el.getAttribute) return null; + let href = el.getAttribute("href") || el.getAttribute("xlink:href") || (typeof el.getAttributeNS === "function" ? el.getAttributeNS(XLINK_NS, "href") : null); + if (href) return href; + const attrs = el.attributes; + if (!attrs) return null; + for (let i = 0; i < attrs.length; i++) { + const a = attrs[i]; + if (!a || !a.name) continue; + if (a.name === "href") return a.value; + const idx = a.name.indexOf(":"); + if (idx !== -1 && a.name.slice(idx + 1) === "href") { + return a.value; + } + } + return null; + }; + const globalExistingIds = new Set( + Array.from(element.querySelectorAll("[id]")).map((n) => n.id) + ); + const neededIds = /* @__PURE__ */ new Set(); + let sawAnyReference = false; + const addUrlIdsFromValue = (val, queueForResolve = null) => { + if (!val) return; + URL_ID_RE.lastIndex = 0; + let m; + while (m = URL_ID_RE.exec(val)) { + sawAnyReference = true; + const id = (m[1] || "").trim(); + if (!id) continue; + if (!globalExistingIds.has(id)) { + neededIds.add(id); + if (queueForResolve && !queueForResolve.has(id)) { + queueForResolve.add(id); + } + } + } + }; + const collectReferencesInSvg = (rootSvg) => { + const uses = rootSvg.querySelectorAll("use"); + for (const u of uses) { + const href = getHrefAttr(u); + if (!href || !href.startsWith("#")) continue; + sawAnyReference = true; + const id = href.slice(1).trim(); + if (id && !globalExistingIds.has(id)) neededIds.add(id); + } + const query = '*[style*="url("],*[fill^="url("], *[stroke^="url("],*[filter^="url("],*[clip-path^="url("],*[mask^="url("],*[marker^="url("],*[marker-start^="url("],*[marker-mid^="url("],*[marker-end^="url("]'; + const candidates = rootSvg.querySelectorAll(query); + for (const el of candidates) { + addUrlIdsFromValue(el.getAttribute("style") || ""); + for (const a of URL_ATTRS) addUrlIdsFromValue(el.getAttribute(a)); + } + }; + for (const svg of svgRoots) collectReferencesInSvg(svg); + if (!sawAnyReference) return; + let defsHost = element.querySelector("svg.inline-defs-container"); + if (!defsHost) { + defsHost = doc.createElementNS("http://www.w3.org/2000/svg", "svg"); + defsHost.classList.add("inline-defs-container"); + defsHost.setAttribute("aria-hidden", "true"); + defsHost.setAttribute("style", "position:absolute;width:0;height:0;overflow:hidden"); + element.insertBefore(defsHost, element.firstChild || null); + } + let localDefs = defsHost.querySelector("defs") || null; + const findGlobalById = (id) => { + if (!id) return null; + if (globalExistingIds.has(id)) return null; + const esc = cssEscape(id); + const tryFind = (sel) => { + const el = searchRoot.querySelector(sel); + return el && !element.contains(el) ? el : null; + }; + return tryFind(`svg defs > *#${esc}`) || tryFind(`svg > symbol#${esc}`) || tryFind(`*#${esc}`); + }; + if (!neededIds.size) return; + const queued = new Set(neededIds); + const inlined = /* @__PURE__ */ new Set(); + while (queued.size) { + const id = queued.values().next().value; + queued.delete(id); + if (!id || globalExistingIds.has(id) || inlined.has(id)) continue; + const source = findGlobalById(id); + if (!source) { + inlined.add(id); + continue; + } + if (!localDefs) { + localDefs = doc.createElementNS("http://www.w3.org/2000/svg", "defs"); + defsHost.appendChild(localDefs); + } + const clone = source.cloneNode(true); + if (!clone.id) clone.setAttribute("id", id); + localDefs.appendChild(clone); + inlined.add(id); + globalExistingIds.add(id); + const walk = [clone, ...clone.querySelectorAll("*")]; + for (const node of walk) { + const href = getHrefAttr(node); + if (href && href.startsWith("#")) { + const ref = href.slice(1).trim(); + if (ref && !globalExistingIds.has(ref) && !inlined.has(ref)) { + queued.add(ref); + } + } + const style = node.getAttribute?.("style") || ""; + if (style) addUrlIdsFromValue(style, queued); + for (const a of URL_ATTRS) { + const v = node.getAttribute?.(a); + if (v) addUrlIdsFromValue(v, queued); + } + } + } +} + +// src/core/prepare.js +init_cache(); + +// src/modules/changeCSS.js +function freezeSticky(originalRoot, cloneRoot) { + if (!originalRoot || !cloneRoot) return; + const scrollTop = originalRoot.scrollTop || 0; + if (!scrollTop) return; + if (getComputedStyle(cloneRoot).position === "static") { + cloneRoot.style.position = "relative"; + } + const rootRect = originalRoot.getBoundingClientRect(); + const viewportH = originalRoot.clientHeight; + const PH_ATTR = "data-snap-ph"; + const walker = document.createTreeWalker(originalRoot, NodeFilter.SHOW_ELEMENT); + while (walker.nextNode()) { + const el = ( + /** @type {HTMLElement} */ + walker.currentNode + ); + const cs = getComputedStyle(el); + const pos = cs.position; + if (pos !== "sticky" && pos !== "-webkit-sticky") continue; + const topInit = _toPx(cs.top); + const bottomInit = _toPx(cs.bottom); + if (topInit == null && bottomInit == null) continue; + const path = _pathOf(el, originalRoot); + const cloneEl = _findByPathIgnoringPlaceholders(cloneRoot, path, PH_ATTR); + if (!cloneEl) continue; + const elRect = el.getBoundingClientRect(); + const widthPx = elRect.width; + const heightPx = elRect.height; + const leftPx = elRect.left - rootRect.left; + if (!(widthPx > 0 && heightPx > 0)) continue; + if (!Number.isFinite(leftPx)) continue; + const topAbsPx = topInit != null ? topInit + scrollTop : scrollTop + (viewportH - heightPx - /** bottomInit non-null */ + bottomInit); + if (!Number.isFinite(topAbsPx)) continue; + const zParsed = Number.parseInt(cs.zIndex, 10); + const hasZ = Number.isFinite(zParsed); + const overlayZ = hasZ ? Math.max(zParsed, 1) + 1 : 2; + const placeholderZ = hasZ ? zParsed - 1 : 0; + const ph = cloneEl.cloneNode(false); + ph.setAttribute(PH_ATTR, "1"); + ph.style.position = "sticky"; + ph.style.left = `${leftPx}px`; + ph.style.top = `${topAbsPx}px`; + ph.style.width = `${widthPx}px`; + ph.style.height = `${heightPx}px`; + ph.style.visibility = "hidden"; + ph.style.zIndex = String(placeholderZ); + ph.style.overflow = "hidden"; + ph.style.background = "transparent"; + ph.style.boxShadow = "none"; + ph.style.filter = "none"; + cloneEl.parentElement?.insertBefore(ph, cloneEl); + cloneEl.style.position = "absolute"; + cloneEl.style.left = `${leftPx}px`; + cloneEl.style.top = `${topAbsPx}px`; + cloneEl.style.bottom = "auto"; + cloneEl.style.zIndex = String(overlayZ); + cloneEl.style.pointerEvents = "none"; + } +} +function _toPx(v) { + if (!v || v === "auto") return null; + const n = Number.parseFloat(v); + return Number.isFinite(n) ? n : null; +} +function _pathOf(el, root) { + const path = []; + for (let cur = el; cur && cur !== root; ) { + const p = cur.parentElement; + if (!p) break; + path.push(Array.prototype.indexOf.call(p.children, cur)); + cur = p; + } + return path.reverse(); +} +function _findByPathIgnoringPlaceholders(root, path, phAttr) { + let cur = root; + for (let i = 0; i < path.length; i++) { + const kids = _childrenWithoutPlaceholders(cur, phAttr); + cur = /** @type {HTMLElement|undefined} */ + kids[path[i]]; + if (!cur) return null; + } + return cur instanceof HTMLElement ? cur : null; +} +function _childrenWithoutPlaceholders(el, phAttr) { + const out = []; + const ch = el.children; + for (let i = 0; i < ch.length; i++) { + const c = ch[i]; + if (!c.hasAttribute(phAttr)) out.push(c); + } + return out; +} + +// src/utils/prepare.helpers.js +function stabilizeLayout(element) { + const style = getComputedStyle(element); + const outlineStyle = style.outlineStyle; + const outlineWidth = style.outlineWidth; + const borderStyle = style.borderStyle; + const borderWidth = style.borderWidth; + const outlineVisible = outlineStyle !== "none" && parseFloat(outlineWidth) > 0; + const borderAbsent = borderStyle === "none" || parseFloat(borderWidth) === 0; + if (outlineVisible && borderAbsent) { + element.style.border = `${outlineWidth} solid transparent`; + } +} + +// src/core/prepare.js +async function prepareClone(element, options = {}) { + const sessionCache = { + styleMap: cache.session.styleMap, + styleCache: cache.session.styleCache, + nodeMap: cache.session.nodeMap + }; + let clone; + let classCSS = ""; + let shadowScopedCSS = ""; + stabilizeLayout(element); + try { + inlineExternalDefsAndSymbols(element); + } catch (e) { + console.warn("inlineExternal defs or symbol failed:", e); + } + try { + clone = await deepClone(element, sessionCache, options, element); + } catch (e) { + console.warn("deepClone failed:", e); + throw e; + } + try { + await inlinePseudoElements(element, clone, sessionCache, options); + } catch (e) { + console.warn("inlinePseudoElements failed:", e); + } + await resolveBlobUrlsInTree(clone); + try { + const styleNodes = clone.querySelectorAll("style[data-sd]"); + for (const s of styleNodes) { + shadowScopedCSS += s.textContent || ""; + s.remove(); + } + } catch { + } + const keyToClass = generateCSSClasses(sessionCache.styleMap); + classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join(""); + classCSS = shadowScopedCSS + classCSS; + for (const [node, key] of sessionCache.styleMap.entries()) { + if (node.tagName === "STYLE") continue; + if (node.getRootNode && node.getRootNode() instanceof ShadowRoot) { + node.setAttribute("style", key.replace(/;/g, "; ")); + continue; + } + const className = keyToClass.get(key); + if (className) node.classList.add(className); + const bgImage = node.style?.backgroundImage; + const hasIcon = node.dataset?.snapdomHasIcon; + if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage; + if (hasIcon) { + node.style.verticalAlign = "middle"; + node.style.display = "inline"; + } + } + for (const [cloneNode, originalNode] of sessionCache.nodeMap.entries()) { + const scrollX = originalNode.scrollLeft; + const scrollY = originalNode.scrollTop; + const hasScroll = scrollX || scrollY; + if (hasScroll && cloneNode instanceof HTMLElement) { + cloneNode.style.overflow = "hidden"; + cloneNode.style.scrollbarWidth = "none"; + cloneNode.style.msOverflowStyle = "none"; + const inner = document.createElement("div"); + inner.style.transform = `translate(${-scrollX}px, ${-scrollY}px)`; + inner.style.willChange = "transform"; + inner.style.display = "inline-block"; + inner.style.width = "100%"; + while (cloneNode.firstChild) { + inner.appendChild(cloneNode.firstChild); + } + cloneNode.appendChild(inner); + } + } + const contentRoot = clone instanceof HTMLElement && clone.firstElementChild instanceof HTMLElement ? clone.firstElementChild : clone; + freezeSticky(element, contentRoot); + if (element === sessionCache.nodeMap.get(clone)) { + const computed = sessionCache.styleCache.get(element) || window.getComputedStyle(element); + sessionCache.styleCache.set(element, computed); + const transform = stripTranslate(computed.transform); + clone.style.margin = "0"; + clone.style.top = "auto"; + clone.style.left = "auto"; + clone.style.right = "auto"; + clone.style.bottom = "auto"; + clone.style.animation = "none"; + clone.style.transition = "none"; + clone.style.willChange = "auto"; + clone.style.float = "none"; + clone.style.clear = "none"; + clone.style.transform = transform || ""; + } + for (const [cloneNode, originalNode] of sessionCache.nodeMap.entries()) { + if (originalNode.tagName === "PRE") { + cloneNode.style.marginTop = "0"; + cloneNode.style.marginBlockStart = "0"; + } + } + return { clone, classCSS, styleCache: sessionCache.styleCache }; +} + +// src/modules/images.js +init_snapFetch(); +function extractImageDimensions(img) { + const dsW = parseInt(img.dataset?.snapdomWidth || "", 10) || 0; + const dsH = parseInt(img.dataset?.snapdomHeight || "", 10) || 0; + const attrW = parseInt(img.getAttribute("width") || "", 10) || 0; + const attrH = parseInt(img.getAttribute("height") || "", 10) || 0; + const styleW = parseFloat(img.style?.width || "") || 0; + const styleH = parseFloat(img.style?.height || "") || 0; + const w = dsW || styleW || attrW || img.width || img.naturalWidth || 100; + const h = dsH || styleH || attrH || img.height || img.naturalHeight || 100; + return { width: w, height: h }; +} +async function inlineImages(clone, options = {}) { + const imgs = Array.from(clone.querySelectorAll("img")); + const processImg = async (img) => { + if (!img.getAttribute("src")) { + const eff = img.currentSrc || img.src || ""; + if (eff) img.setAttribute("src", eff); + } + img.removeAttribute("srcset"); + img.removeAttribute("sizes"); + const src = img.src || ""; + if (!src) return; + const r = await snapFetch(src, { as: "dataURL", useProxy: options.useProxy }); + if (r.ok && typeof r.data === "string" && r.data.startsWith("data:")) { + img.src = r.data; + if (!img.width) img.width = img.naturalWidth || 100; + if (!img.height) img.height = img.naturalHeight || 100; + return; + } + const { width: fbW, height: fbH } = extractImageDimensions(img); + const { fallbackURL } = options || {}; + if (fallbackURL) { + try { + const fallbackUrl = typeof fallbackURL === "function" ? await fallbackURL({ width: fbW, height: fbH, src, element: img }) : fallbackURL; + if (fallbackUrl) { + const fallbackData = await snapFetch(fallbackUrl, { as: "dataURL", useProxy: options.useProxy }); + img.src = fallbackData.data; + if (!img.width) img.width = fbW; + if (!img.height) img.height = fbH; + return; + } + } catch { + } + } + if (options.placeholders !== false) { + const fallback = document.createElement("div"); + fallback.style.cssText = [ + `width:${fbW}px`, + `height:${fbH}px`, + "background:#ccc", + "display:inline-block", + "text-align:center", + `line-height:${fbH}px`, + "color:#666", + "font-size:12px", + "overflow:hidden" + ].join(";"); + fallback.textContent = "img"; + img.replaceWith(fallback); + } else { + const spacer = document.createElement("div"); + spacer.style.cssText = `display:inline-block;width:${fbW}px;height:${fbH}px;visibility:hidden;`; + img.replaceWith(spacer); + } + }; + for (let i = 0; i < imgs.length; i += 4) { + const group = imgs.slice(i, i + 4).map(processImg); + await Promise.allSettled(group); + } +} + +// src/modules/background.js +init_utils(); +async function inlineBackgroundImages(source, clone, styleCache, options = {}) { + const queue = [[source, clone]]; + const URL_PROPS = [ + "background-image", + // Mask shorthands & images (both standard and WebKit) + "mask", + "mask-image", + "-webkit-mask", + "-webkit-mask-image", + // Mask sources (rare, but keep) + "mask-source", + "mask-box-image-source", + "mask-border-source", + "-webkit-mask-box-image-source", + // Border image + "border-image", + "border-image-source" + ]; + const MASK_LAYOUT_PROPS = [ + "mask-position", + "mask-size", + "mask-repeat", + // WebKit variants + "-webkit-mask-position", + "-webkit-mask-size", + "-webkit-mask-repeat", + // Extra (optional but helpful across engines) + "mask-origin", + "mask-clip", + "-webkit-mask-origin", + "-webkit-mask-clip", + // Some engines expose X/Y position separately: + "-webkit-mask-position-x", + "-webkit-mask-position-y" + ]; + const BG_LAYOUT_PROPS = [ + "background-position", + "background-position-x", + "background-position-y", + "background-size", + "background-repeat", + "background-origin", + "background-clip", + "background-attachment", + "background-blend-mode" + ]; + const BORDER_AUX_PROPS = [ + "border-image-slice", + "border-image-width", + "border-image-outset", + "border-image-repeat" + ]; + while (queue.length) { + const [srcNode, cloneNode] = queue.shift(); + const style = styleCache.get(srcNode) || getStyle(srcNode); + if (!styleCache.has(srcNode)) styleCache.set(srcNode, style); + const hasBorderImage = (() => { + const bi = style.getPropertyValue("border-image"); + const bis = style.getPropertyValue("border-image-source"); + return bi && bi !== "none" || bis && bis !== "none"; + })(); + for (const prop of BG_LAYOUT_PROPS) { + const v = style.getPropertyValue(prop); + if (!v) continue; + cloneNode.style.setProperty(prop, v); + } + for (const prop of URL_PROPS) { + const val = style.getPropertyValue(prop); + if (!val || val === "none") continue; + const splits = splitBackgroundImage(val); + const inlined = await Promise.all( + splits.map((entry) => inlineSingleBackgroundEntry(entry, options)) + ); + if (inlined.some((p) => p && p !== "none" && !/^url\(undefined/.test(p))) { + cloneNode.style.setProperty(prop, inlined.join(", ")); + } + } + for (const prop of MASK_LAYOUT_PROPS) { + const val = style.getPropertyValue(prop); + if (!val || val === "initial") continue; + cloneNode.style.setProperty(prop, val); + } + if (hasBorderImage) { + for (const prop of BORDER_AUX_PROPS) { + const val = style.getPropertyValue(prop); + if (!val || val === "initial") continue; + cloneNode.style.setProperty(prop, val); + } + } + const sChildren = Array.from(srcNode.children); + const cChildren = Array.from(cloneNode.children).filter((el) => !(el.dataset && el.dataset.snapdomPseudo)); + for (let i = 0; i < Math.min(sChildren.length, cChildren.length); i++) { + queue.push([sChildren[i], cChildren[i]]); + } + } +} + +// src/core/capture.js +init_utils(); +init_cache(); + +// src/modules/lineClamp.js +function lineClamp(el) { + if (!el) return () => { + }; + const lines = getClamp(el); + if (lines <= 0) return () => { + }; + if (!isPlainTextContainer(el)) return () => { + }; + const cs = getComputedStyle(el); + const targetH = Math.round(usedLineHeightPx(cs) * lines + vpad(cs)); + const original = el.textContent ?? ""; + const prevText = original; + if (el.scrollHeight <= targetH + 0.5) { + return () => { + }; + } + let lo = 0, hi = original.length, best = -1; + while (lo <= hi) { + const mid = lo + hi >> 1; + el.textContent = original.slice(0, mid) + "\u2026"; + if (el.scrollHeight <= targetH + 0.5) { + best = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + el.textContent = (best >= 0 ? original.slice(0, best) : "") + "\u2026"; + return () => { + el.textContent = prevText; + }; +} +function getClamp(el) { + const cs = getComputedStyle(el); + let v = cs.getPropertyValue("-webkit-line-clamp") || cs.getPropertyValue("line-clamp"); + v = (v || "").trim(); + const n = parseInt(v, 10); + return Number.isFinite(n) && n > 0 ? n : 0; +} +function usedLineHeightPx(cs) { + const lh = (cs.lineHeight || "").trim(); + const fs = parseFloat(cs.fontSize) || 16; + if (!lh || lh === "normal") return Math.round(fs * 1.2); + if (lh.endsWith("px")) return parseFloat(lh); + if (/^\d+(\.\d+)?$/.test(lh)) return Math.round(parseFloat(lh) * fs); + if (lh.endsWith("%")) return Math.round(parseFloat(lh) / 100 * fs); + return Math.round(fs * 1.2); +} +function vpad(cs) { + return (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0); +} +function isPlainTextContainer(el) { + if (el.childElementCount > 0) return false; + return Array.from(el.childNodes).some((n) => n.nodeType === Node.TEXT_NODE); +} + +// src/core/plugins.js +var __plugins = []; +function normalizePlugin(spec) { + if (!spec) return null; + if (Array.isArray(spec)) { + const [factory, options] = spec; + return typeof factory === "function" ? factory(options) : factory; + } + if (typeof spec === "object" && "plugin" in spec) { + const { plugin, options } = spec; + return typeof plugin === "function" ? plugin(options) : plugin; + } + if (typeof spec === "function") return spec(); + return spec; +} +function registerPlugins(...defs) { + const flat = defs.flat(); + for (const d of flat) { + const inst = normalizePlugin(d); + if (!inst) continue; + if (!__plugins.some((p) => p && p.name && inst.name && p.name === inst.name)) { + __plugins.push(inst); + } + } +} +function getContextPlugins(context) { + const arr = context && Array.isArray(context.plugins) ? context.plugins : __plugins; + return arr || __plugins; +} +async function runHook(name, context, payload) { + let acc = payload; + const list = getContextPlugins(context); + for (const p of list) { + const fn = p && typeof p[name] === "function" ? p[name] : null; + if (!fn) continue; + const out = await fn(context, acc); + if (typeof out !== "undefined") acc = out; + } + return acc; +} +async function runAll(name, context, payload) { + const outs = []; + const list = getContextPlugins(context); + for (const p of list) { + const fn = p && typeof p[name] === "function" ? p[name] : null; + if (!fn) continue; + const out = await fn(context, payload); + if (typeof out !== "undefined") outs.push(out); + } + return outs; +} +function mergePlugins(localDefs) { + const out = []; + if (Array.isArray(localDefs)) { + for (const d of localDefs) { + const inst = normalizePlugin(d); + if (!inst || !inst.name) continue; + const i = out.findIndex((x) => x && x.name === inst.name); + if (i >= 0) out.splice(i, 1); + out.push(inst); + } + } + for (const g of __plugins) { + if (g && g.name && !out.some((x) => x.name === g.name)) { + out.push(g); + } + } + return Object.freeze(out); +} +function attachSessionPlugins(context, localDefs, force = false) { + if (!context || context.plugins && !force) return context; + context.plugins = mergePlugins(localDefs); + return context; +} + +// src/utils/capture.helpers.js +function stripRootShadows(originalEl, cloneRoot) { + if (!originalEl || !cloneRoot || !cloneRoot.style) return; + const cs = getComputedStyle(originalEl); + try { + cloneRoot.style.boxShadow = "none"; + } catch { + } + try { + cloneRoot.style.textShadow = "none"; + } catch { + } + try { + cloneRoot.style.outline = "none"; + } catch { + } + const f = cs.filter || ""; + const cleaned = f.replace(/\bblur\([^()]*\)\s*/gi, "").replace(/\bdrop-shadow\([^()]*\)\s*/gi, "").trim().replace(/\s+/g, " "); + try { + cloneRoot.style.filter = cleaned.length ? cleaned : "none"; + } catch { + } +} +function removeAllComments(root) { + const it = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT); + const toRemove = []; + while (it.nextNode()) toRemove.push(it.currentNode); + for (const n of toRemove) n.remove(); +} +function sanitizeAttributesForXHTML(root, opts = {}) { + const { stripFrameworkDirectives = true } = opts; + const ALLOWED_PREFIXES = /* @__PURE__ */ new Set(["xml", "xlink"]); + const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); + while (walker.nextNode()) { + const el = walker.currentNode; + for (const attr of Array.from(el.attributes)) { + const name = attr.name; + if (name.includes("@")) { + el.removeAttribute(name); + continue; + } + if (name.includes(":")) { + const prefix = name.split(":", 1)[0]; + if (!ALLOWED_PREFIXES.has(prefix)) { + el.removeAttribute(name); + continue; + } + } + if (!stripFrameworkDirectives) continue; + if (name.startsWith("x-") || // Alpine + name.startsWith("v-") || // Vue + name.startsWith(":") || // Vue/Alpine shorthand + name.startsWith("on:") || // Svelte + name.startsWith("bind:") || // Svelte + name.startsWith("let:") || // Svelte + name.startsWith("class:")) { + el.removeAttribute(name); + continue; + } + } + } +} +function sanitizeCloneForXHTML(root, opts = {}) { + if (!root) return; + sanitizeAttributesForXHTML(root, opts); + removeAllComments(root); +} +function authorHasExplicitSize(el) { + try { + const s = el.getAttribute?.("style") || ""; + return /\b(height|width|block-size|inline-size)\s*:/.test(s); + } catch { + return false; + } +} +function isReplacedElement(el) { + return el instanceof HTMLImageElement || el instanceof HTMLCanvasElement || el instanceof HTMLVideoElement || el instanceof HTMLIFrameElement || el instanceof SVGElement || el instanceof HTMLObjectElement || el instanceof HTMLEmbedElement; +} +function shouldShrinkBox(srcEl, cs) { + if (!(srcEl instanceof Element)) return false; + if (authorHasExplicitSize(srcEl)) return false; + if (isReplacedElement(srcEl)) return false; + const pos = cs.position; + if (pos === "absolute" || pos === "fixed" || pos === "sticky") return false; + const disp = cs.display || ""; + if (disp.includes("flex") || disp.includes("grid") || disp.startsWith("table")) return false; + if (cs.transform && cs.transform !== "none") return false; + return true; +} +function shrinkAutoSizeBoxes(sourceRoot, cloneRoot, styleCache = /* @__PURE__ */ new Map()) { + function walk(src, cln) { + if (!(src instanceof Element) || !(cln instanceof Element)) return; + const lostKids = src.childElementCount > cln.childElementCount; + const cs = styleCache.get(src) || getComputedStyle(src); + if (!styleCache.has(src)) styleCache.set(src, cs); + if (lostKids && shouldShrinkBox(src, cs)) { + if (!cln.style.height) cln.style.height = "auto"; + if (!cln.style.width) cln.style.width = "auto"; + cln.style.removeProperty("block-size"); + cln.style.removeProperty("inline-size"); + if (!cln.style.minHeight) cln.style.minHeight = "0"; + if (!cln.style.minWidth) cln.style.minWidth = "0"; + if (!cln.style.maxHeight) cln.style.maxHeight = "none"; + if (!cln.style.maxWidth) cln.style.maxWidth = "none"; + const oy = cs.overflowY || cs.overflowBlock || "visible"; + const ox = cs.overflowX || cs.overflowInline || "visible"; + if (oy !== "visible" || ox !== "visible") { + cln.style.overflow = "visible"; + } + } + const sKids = Array.from(src.children); + const cKids = Array.from(cln.children); + for (let i = 0; i < Math.min(sKids.length, cKids.length); i++) { + walk(sKids[i], cKids[i]); + } + } + walk(sourceRoot, cloneRoot); +} +function isInNormalFlow(el) { + const cs = getComputedStyle(el); + if (cs.display === "none") return false; + if (cs.position === "absolute" || cs.position === "fixed" || cs.position === "sticky") return false; + if ((cs.cssFloat || cs.float || "none") !== "none") return false; + if (cs.transform && cs.transform !== "none") return false; + return true; +} +function willBeExcluded(el, options) { + if (!(el instanceof Element)) return false; + if (el.getAttribute("data-capture") === "exclude" && options?.excludeMode === "remove") return true; + if (Array.isArray(options?.exclude)) { + for (const sel of options.exclude) { + try { + if (el.matches(sel)) return options.excludeMode === "remove"; + } catch { + } + } + } + return false; +} +function estimateKeptHeight(container, options) { + const csC = getComputedStyle(container); + const rC = container.getBoundingClientRect(); + let minTop = Infinity; + let maxBottom = -Infinity; + let found = false; + const kids = Array.from(container.children); + for (const k of kids) { + if (willBeExcluded(k, options)) continue; + if (!isInNormalFlow(k)) continue; + const rk = k.getBoundingClientRect(); + const top = rk.top - rC.top; + const bottom = rk.bottom - rC.top; + if (bottom <= top) continue; + if (top < minTop) minTop = top; + if (bottom > maxBottom) maxBottom = bottom; + found = true; + } + const contentSpan = found ? Math.max(0, maxBottom - minTop) : 0; + const bt = parseFloat(csC.borderTopWidth) || 0; + const bb = parseFloat(csC.borderBottomWidth) || 0; + const pt = parseFloat(csC.paddingTop) || 0; + const pb = parseFloat(csC.paddingBottom) || 0; + return bt + bb + pt + pb + contentSpan; +} +var limitDecimals = (v, n = 3) => Number.isFinite(v) ? Math.round(v * 10 ** n) / 10 ** n : v; + +// src/utils/transforms.helpers.js +function parseBoxShadow(cs) { + const v = cs.boxShadow || ""; + if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 }; + const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim()); + let t = 0, r = 0, b2 = 0, l = 0; + for (const part of parts) { + const nums = part.match(/-?\d+(\.\d+)?px/g)?.map((n) => parseFloat(n)) || []; + if (nums.length < 2) continue; + const [ox2, oy2, blur = 0, spread = 0] = nums; + const extX = Math.abs(ox2) + blur + spread; + const extY = Math.abs(oy2) + blur + spread; + r = Math.max(r, extX + Math.max(ox2, 0)); + l = Math.max(l, extX + Math.max(-ox2, 0)); + b2 = Math.max(b2, extY + Math.max(oy2, 0)); + t = Math.max(t, extY + Math.max(-oy2, 0)); + } + return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) }; +} +function parseFilterBlur(cs) { + const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/); + const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0; + return { top: b2, right: b2, bottom: b2, left: b2 }; +} +function parseOutline(cs) { + if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 }; + const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0); + return { top: w2, right: w2, bottom: w2, left: w2 }; +} +function parseFilterDropShadows(cs) { + const raw = `${cs.filter || ""} ${cs.webkitFilter || ""}`.trim(); + if (!raw || raw === "none") { + return { bleed: { top: 0, right: 0, bottom: 0, left: 0 }, has: false }; + } + const tokens = raw.match(/drop-shadow\((?:[^()]|\([^()]*\))*\)/gi) || []; + let t = 0, r = 0, b = 0, l = 0; + let found = false; + for (const tok of tokens) { + found = true; + const nums = tok.match(/-?\d+(?:\.\d+)?px/gi)?.map((v) => parseFloat(v)) || []; + const [ox = 0, oy = 0, blur = 0] = nums; + const extX = Math.abs(ox) + blur; + const extY = Math.abs(oy) + blur; + r = Math.max(r, extX + Math.max(ox, 0)); + l = Math.max(l, extX + Math.max(-ox, 0)); + b = Math.max(b, extY + Math.max(oy, 0)); + t = Math.max(t, extY + Math.max(-oy, 0)); + } + return { + bleed: { + top: limitDecimals(t), + right: limitDecimals(r), + bottom: limitDecimals(b), + left: limitDecimals(l) + }, + has: found + }; +} +function normalizeRootTransforms(originalEl, cloneRoot) { + if (!originalEl || !cloneRoot || !cloneRoot.style) return null; + const cs = getComputedStyle(originalEl); + try { + cloneRoot.style.transformOrigin = "0 0"; + } catch { + } + try { + if ("translate" in cloneRoot.style) cloneRoot.style.translate = "none"; + if ("rotate" in cloneRoot.style) cloneRoot.style.rotate = "none"; + } catch { + } + const tr = cs.transform || "none"; + if (!tr || tr === "none") { + try { + const M = matrixFromComputed(originalEl); + if (M.a === 1 && M.b === 0 && M.c === 0 && M.d === 1) { + cloneRoot.style.transform = "none"; + return { a: 1, b: 0, c: 0, d: 1 }; + } + } catch { + } + } + const m2d = tr.match(/^matrix\(\s*([^)]+)\)$/i); + if (m2d) { + const nums = m2d[1].split(",").map((v) => parseFloat(v.trim())); + if (nums.length === 6 && nums.every(Number.isFinite)) { + const [a, b, c, d] = nums; + const scaleX = Math.sqrt(a * a + b * b) || 0; + let a1 = 0, b1 = 0, shear = 0, c2 = 0, d2 = 0, scaleY = 0; + if (scaleX > 0) { + a1 = a / scaleX; + b1 = b / scaleX; + shear = a1 * c + b1 * d; + c2 = c - a1 * shear; + d2 = d - b1 * shear; + scaleY = Math.sqrt(c2 * c2 + d2 * d2) || 0; + if (scaleY > 0) shear = shear / scaleY; + else shear = 0; + } + const aP = scaleX; + const bP = 0; + const cP = shear * scaleY; + const dP = scaleY; + try { + cloneRoot.style.transform = `matrix(${aP}, ${bP}, ${cP}, ${dP}, 0, 0)`; + } catch { + } + return { a: aP, b: bP, c: cP, d: dP }; + } + } + try { + const legacy = String(tr).trim(); + cloneRoot.style.transform = legacy + " translate(0px, 0px) rotate(0deg)"; + return null; + } catch { + return null; + } +} +function bboxWithOriginFull(w2, h2, M, ox2, oy2) { + const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0; + function pt(x, y) { + let X = x - ox2, Y = y - oy2; + let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y; + X2 += ox2 + e2; + Y2 += oy2 + f2; + return [X2, Y2]; + } + const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)]; + let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity; + for (const [X, Y] of P) { + if (X < minX2) minX2 = X; + if (Y < minY2) minY2 = Y; + if (X > maxX2) maxX2 = X; + if (Y > maxY2) maxY2 = Y; + } + return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 }; +} +function parseTransformOriginPx(cs, w, h) { + const raw = (cs.transformOrigin || "0 0").trim().split(/\s+/); + const [oxRaw, oyRaw] = [raw[0] || "0", raw[1] || "0"]; + const toPx = (token, size) => { + const t = token.toLowerCase(); + if (t === "left" || t === "top") return 0; + if (t === "center") return size / 2; + if (t === "right") return size; + if (t === "bottom") return size; + if (t.endsWith("px")) return parseFloat(t) || 0; + if (t.endsWith("%")) return (parseFloat(t) || 0) * size / 100; + if (/^-?\d+(\.\d+)?$/.test(t)) return parseFloat(t) || 0; + return 0; + }; + return { + ox: toPx(oxRaw, w), + oy: toPx(oyRaw, h) + }; +} +function readIndividualTransforms(el) { + const out = { rotate: "0deg", scale: null, translate: null }; + const map = typeof el.computedStyleMap === "function" ? el.computedStyleMap() : null; + if (map) { + const safeGet = (prop) => { + try { + if (typeof map.has === "function" && !map.has(prop)) return null; + if (typeof map.get !== "function") return null; + return map.get(prop); + } catch { + return null; + } + }; + const rot = safeGet("rotate"); + if (rot) { + if (rot.angle) { + const ang = rot.angle; + out.rotate = ang.unit === "rad" ? ang.value * 180 / Math.PI + "deg" : ang.value + ang.unit; + } else if (rot.unit) { + out.rotate = rot.unit === "rad" ? rot.value * 180 / Math.PI + "deg" : rot.value + rot.unit; + } else { + out.rotate = String(rot); + } + } else { + const cs2 = getComputedStyle(el); + out.rotate = cs2.rotate && cs2.rotate !== "none" ? cs2.rotate : "0deg"; + } + const sc = safeGet("scale"); + if (sc) { + const sx = "x" in sc && sc.x?.value != null ? sc.x.value : Array.isArray(sc) ? sc[0]?.value : Number(sc) || 1; + const sy = "y" in sc && sc.y?.value != null ? sc.y.value : Array.isArray(sc) ? sc[1]?.value : sx; + out.scale = `${sx} ${sy}`; + } else { + const cs2 = getComputedStyle(el); + out.scale = cs2.scale && cs2.scale !== "none" ? cs2.scale : null; + } + const tr = safeGet("translate"); + if (tr) { + const tx = "x" in tr && "value" in tr.x ? tr.x.value : Array.isArray(tr) ? tr[0]?.value : 0; + const ty = "y" in tr && "value" in tr.y ? tr.y.value : Array.isArray(tr) ? tr[1]?.value : 0; + const ux = "x" in tr && tr.x?.unit ? tr.x.unit : "px"; + const uy = "y" in tr && tr.y?.unit ? tr.y.unit : "px"; + out.translate = `${tx}${ux} ${ty}${uy}`; + } else { + const cs2 = getComputedStyle(el); + out.translate = cs2.translate && cs2.translate !== "none" ? cs2.translate : null; + } + return out; + } + const cs = getComputedStyle(el); + out.rotate = cs.rotate && cs.rotate !== "none" ? cs.rotate : "0deg"; + out.scale = cs.scale && cs.scale !== "none" ? cs.scale : null; + out.translate = cs.translate && cs.translate !== "none" ? cs.translate : null; + return out; +} +var __measureHost = null; +function getMeasureHost() { + if (__measureHost) return __measureHost; + const n = document.createElement("div"); + n.id = "snapdom-measure-slot"; + n.setAttribute("aria-hidden", "true"); + Object.assign(n.style, { + position: "absolute", + left: "-99999px", + top: "0px", + width: "0px", + height: "0px", + overflow: "hidden", + opacity: "0", + pointerEvents: "none", + contain: "size layout style" + }); + document.documentElement.appendChild(n); + __measureHost = n; + return n; +} +function readTotalTransformMatrix(t) { + const host = getMeasureHost(); + const tmp = document.createElement("div"); + tmp.style.transformOrigin = "0 0"; + if (t.baseTransform) tmp.style.transform = t.baseTransform; + if (t.rotate) tmp.style.rotate = t.rotate; + if (t.scale) tmp.style.scale = t.scale; + if (t.translate) tmp.style.translate = t.translate; + host.appendChild(tmp); + const M = matrixFromComputed(tmp); + host.removeChild(tmp); + return M; +} +function hasBBoxAffectingTransform(el) { + const cs = getComputedStyle(el); + const t = cs.transform || "none"; + const hasMatrix = t !== "none" && !/^matrix\(\s*1\s*,\s*0\s*,\s*0\s*,\s*1\s*,\s*0\s*,\s*0\s*\)$/i.test(t); + if (hasMatrix) return true; + const r = cs.rotate && cs.rotate !== "none" && cs.rotate !== "0deg"; + const s = cs.scale && cs.scale !== "none" && cs.scale !== "1"; + const tr = cs.translate && cs.translate !== "none" && cs.translate !== "0px 0px"; + return Boolean(r || s || tr); +} +function matrixFromComputed(el) { + const tr = getComputedStyle(el).transform; + if (!tr || tr === "none") return new DOMMatrix(); + try { + return new DOMMatrix(tr); + } catch { + return new WebKitCSSMatrix(tr); + } +} + +// src/core/capture.js +async function captureDOM(element, options) { + if (!element) throw new Error("Element cannot be null or undefined"); + applyCachePolicy(options.cache); + const fast = options.fast; + const outerTransforms = options.outerTransforms !== false; + const outerShadows = !!options.outerShadows; + let state = { element, options, plugins: options.plugins }; + let clone, classCSS, styleCache; + let fontsCSS = ""; + let baseCSS = ""; + let dataURL; + let svgString; + let rootTransform2D = null; + await runHook("beforeSnap", state); + await runHook("beforeClone", state); + const undoClamp = lineClamp(state.element); + try { + ({ clone, classCSS, styleCache } = await prepareClone(state.element, state.options)); + if (!outerTransforms && clone) { + rootTransform2D = normalizeRootTransforms(state.element, clone); + } + if (!outerShadows && clone) { + stripRootShadows(state.element, clone); + } + } finally { + undoClamp(); + } + state = { clone, classCSS, styleCache, ...state }; + await runHook("afterClone", state); + sanitizeCloneForXHTML(state.clone); + if (state.options?.excludeMode === "remove") { + try { + shrinkAutoSizeBoxes(state.element, state.clone, state.styleCache); + } catch (e) { + console.warn("[snapdom] shrink pass failed:", e); + } + } + try { + await ligatureIconToImage(state.clone, state.element); + } catch { + } + await new Promise((resolve) => { + idle(async () => { + await inlineImages(state.clone, state.options); + resolve(); + }, { fast }); + }); + await new Promise((resolve) => { + idle(async () => { + await inlineBackgroundImages(state.element, state.clone, state.styleCache, state.options); + resolve(); + }, { fast }); + }); + if (options.embedFonts) { + await new Promise((resolve) => { + idle(async () => { + const required = collectUsedFontVariants(state.element); + const usedCodepoints = collectUsedCodepoints(state.element); + if (isSafari()) { + const families = new Set( + Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean) + ); + await ensureFontsReady(families, 1); + } + fontsCSS = await embedCustomFonts({ + required, + usedCodepoints, + preCached: false, + exclude: state.options.excludeFonts, + useProxy: state.options.useProxy + }); + resolve(); + }, { fast }); + }); + } + const usedTags = collectUsedTagNames(state.clone).sort(); + const tagKey = usedTags.join(","); + if (cache.baseStyle.has(tagKey)) { + baseCSS = cache.baseStyle.get(tagKey); + } else { + await new Promise((resolve) => { + idle(() => { + baseCSS = generateDedupedBaseCSS(usedTags); + cache.baseStyle.set(tagKey, baseCSS); + resolve(); + }, { fast }); + }); + } + state = { fontsCSS, baseCSS, ...state }; + await runHook("beforeRender", state); + await new Promise((resolve) => { + idle(() => { + const csEl = getComputedStyle(state.element); + const rect = state.element.getBoundingClientRect(); + let w0 = Math.max(1, limitDecimals(state.element.offsetWidth || parseFloat(csEl.width) || rect.width || 1)); + let h0 = Math.max(1, limitDecimals(state.element.offsetHeight || parseFloat(csEl.height) || rect.height || 1)); + if (state.options?.excludeMode === "remove") { + const hEst = estimateKeptHeight(state.element, state.options); + const EPS = 1; + if (Number.isFinite(hEst) && hEst > 0) { + h0 = Math.max(1, Math.min(h0, limitDecimals(hEst + EPS))); + } + } + const coerceNum = (v, def = NaN) => { + const n = typeof v === "string" ? parseFloat(v) : v; + return Number.isFinite(n) ? n : def; + }; + const optW = coerceNum(state.options.width); + const optH = coerceNum(state.options.height); + let w = w0, h = h0; + const hasW = Number.isFinite(optW); + const hasH = Number.isFinite(optH); + const aspect0 = h0 > 0 ? w0 / h0 : 1; + if (hasW && hasH) { + w = Math.max(1, limitDecimals(optW)); + h = Math.max(1, limitDecimals(optH)); + } else if (hasW) { + w = Math.max(1, limitDecimals(optW)); + h = Math.max(1, limitDecimals(w / (aspect0 || 1))); + } else if (hasH) { + h = Math.max(1, limitDecimals(optH)); + w = Math.max(1, limitDecimals(h * (aspect0 || 1))); + } else { + w = w0; + h = h0; + } + let minX = 0, minY = 0, maxX = w0, maxY = h0; + if (!outerTransforms && rootTransform2D && Number.isFinite(rootTransform2D.a)) { + const M2 = { + a: rootTransform2D.a, + b: rootTransform2D.b || 0, + c: rootTransform2D.c || 0, + d: rootTransform2D.d || 1, + e: 0, + f: 0 + }; + const bb2 = bboxWithOriginFull(w0, h0, M2, 0, 0); + minX = limitDecimals(bb2.minX); + minY = limitDecimals(bb2.minY); + maxX = limitDecimals(bb2.maxX); + maxY = limitDecimals(bb2.maxY); + } else { + const useTFBBox = outerTransforms && hasTFBBox(state.element); + if (useTFBBox) { + const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : ""; + const ind2 = readIndividualTransforms(state.element); + const TOTAL = readTotalTransformMatrix({ + baseTransform: baseTransform2, + rotate: ind2.rotate || "0deg", + scale: ind2.scale, + translate: ind2.translate + }); + const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0); + const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString()); + const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2); + minX = limitDecimals(bb.minX); + minY = limitDecimals(bb.minY); + maxX = limitDecimals(bb.maxX); + maxY = limitDecimals(bb.maxY); + } + } + const bleedShadow = parseBoxShadow(csEl); + const bleedBlur = parseFilterBlur(csEl); + const bleedOutline = parseOutline(csEl); + const drop = parseFilterDropShadows(csEl); + const bleed = !outerShadows ? { top: 0, right: 0, bottom: 0, left: 0 } : { + top: limitDecimals(bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top), + right: limitDecimals(bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right), + bottom: limitDecimals(bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom), + left: limitDecimals(bleedShadow.left + bleedBlur.left + bleedOutline.left + drop.bleed.left) + }; + minX = limitDecimals(minX - bleed.left); + minY = limitDecimals(minY - bleed.top); + maxX = limitDecimals(maxX + bleed.right); + maxY = limitDecimals(maxY + bleed.bottom); + const vbW0 = Math.max(1, limitDecimals(maxX - minX)); + const vbH0 = Math.max(1, limitDecimals(maxY - minY)); + const scaleW = hasW || hasH ? limitDecimals(w / w0) : 1; + const scaleH = hasH || hasW ? limitDecimals(h / h0) : 1; + const outW = Math.max(1, limitDecimals(vbW0 * scaleW)); + const outH = Math.max(1, limitDecimals(vbH0 * scaleH)); + const svgNS = "http://www.w3.org/2000/svg"; + const basePad = isSafari() ? 1 : 0; + const extraPad = !outerTransforms ? 1 : 0; + const pad = limitDecimals(basePad + extraPad); + const fo = document.createElementNS(svgNS, "foreignObject"); + const vbMinX = limitDecimals(minX); + const vbMinY = limitDecimals(minY); + fo.setAttribute("x", String(limitDecimals(-(vbMinX - pad)))); + fo.setAttribute("y", String(limitDecimals(-(vbMinY - pad)))); + fo.setAttribute("width", String(limitDecimals(w0 + pad * 2))); + fo.setAttribute("height", String(limitDecimals(h0 + pad * 2))); + fo.style.overflow = "visible"; + const styleTag = document.createElement("style"); + styleTag.textContent = state.baseCSS + state.fontsCSS + "svg{overflow:visible;} foreignObject{overflow:visible;}" + state.classCSS; + fo.appendChild(styleTag); + const container = document.createElement("div"); + container.setAttribute("xmlns", "http://www.w3.org/1999/xhtml"); + container.style.width = `${limitDecimals(w0)}px`; + container.style.height = `${limitDecimals(h0)}px`; + container.style.overflow = "visible"; + state.clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml"); + container.appendChild(state.clone); + fo.appendChild(container); + const serializer = new XMLSerializer(); + const foString = serializer.serializeToString(fo); + const vbW = limitDecimals(vbW0 + pad * 2); + const vbH = limitDecimals(vbH0 + pad * 2); + const wantsSize = hasW || hasH; + options.meta = { w0, h0, vbW, vbH, targetW: w, targetH: h }; + const svgOutW = isSafari() && wantsSize ? vbW : limitDecimals(outW + pad * 2); + const svgOutH = isSafari() && wantsSize ? vbH : limitDecimals(outH + pad * 2); + const svgHeader = ``; + const svgFooter = ""; + svgString = svgHeader + foString + svgFooter; + dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`; + state = { svgString, dataURL, ...state }; + resolve(); + }, { fast }); + }); + await runHook("afterRender", state); + const sandbox = document.getElementById("snapdom-sandbox"); + if (sandbox && sandbox.style.position === "absolute") sandbox.remove(); + return state.dataURL; +} +function hasTFBBox(el) { + return hasBBoxAffectingTransform(el); +} + +// src/core/context.js +function normalizeCachePolicy(v) { + if (typeof v === "string") { + const s = v.toLowerCase().trim(); + if (s === "disabled" || s === "full" || s === "auto" || s === "soft") return ( + /** @type {CachePolicy} */ + s + ); + } + return "soft"; +} +function createContext(options = {}) { + let resolvedFormat = options.format ?? "png"; + if (resolvedFormat === "jpg") resolvedFormat = "jpeg"; + const cachePolicy = normalizeCachePolicy(options.cache); + return { + // Debug & perf + debug: options.debug ?? false, + fast: options.fast ?? true, + scale: options.scale ?? 1, + // DOM filters + exclude: options.exclude ?? [], + excludeMode: options.excludeMode ?? "hide", + filter: options.filter ?? null, + filterMode: options.filterMode ?? "hide", + // Placeholders + placeholders: options.placeholders !== false, + // default true + // Fonts + embedFonts: options.embedFonts ?? false, + iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [], + localFonts: Array.isArray(options.localFonts) ? options.localFonts : [], + excludeFonts: options.excludeFonts ?? void 0, + fallbackURL: options.fallbackURL ?? void 0, + /** @type {CachePolicy} */ + cache: cachePolicy, + // Network + useProxy: typeof options.useProxy === "string" ? options.useProxy : "", + // Output + width: options.width ?? null, + height: options.height ?? null, + format: resolvedFormat, + type: options.type ?? "svg", + quality: options.quality ?? 0.92, + dpr: options.dpr ?? (window.devicePixelRatio || 1), + backgroundColor: options.backgroundColor ?? (["jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null), + filename: options.filename ?? "snapDOM", + // NEW flags (user-friendly) + outerTransforms: options.outerTransforms ?? true, + outerShadows: options.outerShadows ?? false + // Plugins (reservado) + // plugins: normalizePlugins(...), + }; +} + +// src/api/snapdom.js +init_browser(); +function plugins(...defs) { + registerPlugins(...defs); + return snapdom; +} +var snapdom = Object.assign(main, { plugins }); +var INTERNAL_TOKEN = Symbol("snapdom.internal"); +var INTERNAL_EXPORT_TOKEN = Symbol("snapdom.internal.silent"); +var _safariWarmup = false; +async function main(element, userOptions) { + if (!element) throw new Error("Element cannot be null or undefined"); + const context = createContext(userOptions); + attachSessionPlugins(context, userOptions && userOptions.plugins); + if (isSafari() && (context.embedFonts === true || hasBackgroundOrMask(element))) { + for (let i = 0; i < 3; i++) { + try { + await safariWarmup(element, userOptions); + _safariWarmup = false; + } catch { + } + } + } + if (context.iconFonts && context.iconFonts.length > 0) extendIconFonts(context.iconFonts); + if (!context.snap) { + context.snap = { + toPng: (el, opts) => snapdom.toPng(el, opts), + toSvg: (el, opts) => snapdom.toSvg(el, opts) + }; + } + return snapdom.capture(element, context, INTERNAL_TOKEN); +} +snapdom.capture = async (el, context, _token) => { + if (_token !== INTERNAL_TOKEN) throw new Error("[snapdom.capture] is internal. Use snapdom(...) instead."); + const url = await captureDOM(el, context); + const coreExports = { + img: async (ctx, opts) => { + const { toImg: toImg2 } = await Promise.resolve().then(() => (init_toImg(), toImg_exports)); + return toImg2(url, { ...ctx, ...opts || {} }); + }, + svg: async (ctx, opts) => { + const { toSvg } = await Promise.resolve().then(() => (init_toImg(), toImg_exports)); + return toSvg(url, { ...ctx, ...opts || {} }); + }, + canvas: async (ctx, opts) => { + const { toCanvas: toCanvas2 } = await Promise.resolve().then(() => (init_toCanvas(), toCanvas_exports)); + return toCanvas2(url, { ...ctx, ...opts || {} }); + }, + blob: async (ctx, opts) => { + const { toBlob: toBlob2 } = await Promise.resolve().then(() => (init_toBlob(), toBlob_exports)); + return toBlob2(url, { ...ctx, ...opts || {} }); + }, + png: async (ctx, opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...ctx, ...opts || {}, format: "png" }); + }, + jpeg: async (ctx, opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...ctx, ...opts || {}, format: "jpeg" }); + }, + webp: async (ctx, opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...ctx, ...opts || {}, format: "webp" }); + }, + download: async (ctx, opts) => { + const { download: download2 } = await Promise.resolve().then(() => (init_download(), download_exports)); + return download2(url, { ...ctx, ...opts || {} }); + } + }; + const _pluginExports = { + svg: async (opts) => { + const { toSvg } = await Promise.resolve().then(() => (init_toImg(), toImg_exports)); + return toSvg(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }); + }, + canvas: async (opts) => { + const { toCanvas: toCanvas2 } = await Promise.resolve().then(() => (init_toCanvas(), toCanvas_exports)); + return toCanvas2(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }); + }, + png: async (opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...context, ...opts || {}, format: "png", [INTERNAL_EXPORT_TOKEN]: true }); + }, + jpeg: async (opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...context, ...opts || {}, format: "jpeg", [INTERNAL_EXPORT_TOKEN]: true }); + }, + jpg: async (opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...context, ...opts || {}, format: "jpeg", [INTERNAL_EXPORT_TOKEN]: true }); + }, + webp: async (opts) => { + const { rasterize: rasterize2 } = await Promise.resolve().then(() => (init_rasterize(), rasterize_exports)); + return rasterize2(url, { ...context, ...opts || {}, format: "webp", [INTERNAL_EXPORT_TOKEN]: true }); + }, + blob: async (opts) => { + const { toBlob: toBlob2 } = await Promise.resolve().then(() => (init_toBlob(), toBlob_exports)); + return toBlob2(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }); + }, + img: async (opts) => { + const { toImg: toImg2 } = await Promise.resolve().then(() => (init_toImg(), toImg_exports)); + return toImg2(url, { ...context, ...opts || {}, [INTERNAL_EXPORT_TOKEN]: true }); + } + }; + const _defineCtx = { ...context, export: { url }, exports: _pluginExports }; + const providedMaps = await runAll("defineExports", _defineCtx); + const provided = Object.assign({}, ...providedMaps.filter((x) => x && typeof x === "object")); + const exportsMap = { ...coreExports, ...provided }; + if (exportsMap.jpeg && !exportsMap.jpg) { + exportsMap.jpg = (ctx, opts) => exportsMap.jpeg(ctx, opts); + } + function normalizeExportOptions(type, opts) { + const next = { ...context, ...opts || {} }; + if (type === "jpeg" || type === "jpg") { + const noBg = next.backgroundColor == null || next.backgroundColor === "transparent"; + if (noBg) next.backgroundColor = "#ffffff"; + } + return next; + } + let afterSnapFired = false; + let _exportQueue = Promise.resolve(); + async function runExport(type, opts) { + const job = async () => { + const work = exportsMap[type]; + if (!work) throw new Error(`[snapdom] Unknown export type: ${type}`); + const nextOpts = normalizeExportOptions(type, opts); + const ctx = { ...context, export: { type, options: nextOpts, url } }; + await runHook("beforeExport", ctx); + const result2 = await work(ctx, nextOpts); + await runHook("afterExport", ctx, result2); + if (!afterSnapFired) { + afterSnapFired = true; + await runHook("afterSnap", context); + } + return result2; + }; + return _exportQueue = _exportQueue.then(job); + } + const result = { + url, + toRaw: () => url, + to: (type, opts) => runExport(type, opts), + // Métodos “clásicos” que los tests esperan: + toImg: (opts) => runExport("img", opts), + toSvg: (opts) => runExport("svg", opts), + toCanvas: (opts) => runExport("canvas", opts), + toBlob: (opts) => runExport("blob", opts), + toPng: (opts) => runExport("png", opts), + toJpg: (opts) => runExport("jpg", opts), + // alias requerido por tests + toWebp: (opts) => runExport("webp", opts), + download: (opts) => runExport("download", opts) + }; + for (const key of Object.keys(exportsMap)) { + const helper = "to" + key.charAt(0).toUpperCase() + key.slice(1); + if (!result[helper]) { + result[helper] = (opts) => runExport(key, opts); + } + } + return result; +}; +snapdom.toRaw = (el, options) => snapdom(el, options).then((result) => result.toRaw()); +snapdom.toImg = (el, options) => snapdom(el, options).then((result) => result.toImg()); +snapdom.toSvg = (el, options) => snapdom(el, options).then((result) => result.toSvg()); +snapdom.toCanvas = (el, options) => snapdom(el, options).then((result) => result.toCanvas()); +snapdom.toBlob = (el, options) => snapdom(el, options).then((result) => result.toBlob()); +snapdom.toPng = (el, options) => snapdom(el, { ...options, format: "png" }).then((result) => result.toPng()); +snapdom.toJpg = (el, options) => snapdom(el, { ...options, format: "jpeg" }).then((result) => result.toJpg()); +snapdom.toWebp = (el, options) => snapdom(el, { ...options, format: "webp" }).then((result) => result.toWebp()); +snapdom.download = (el, options) => snapdom(el, options).then((result) => result.download()); +async function safariWarmup(element, baseOptions) { + if (_safariWarmup) return; + const preflight = { + ...baseOptions, + fast: true, + embedFonts: true, + scale: 0.2 + }; + let url; + try { + url = await captureDOM(element, preflight); + } catch { + } + await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); + if (url) { + await new Promise((resolve) => { + const img = new Image(); + try { + img.decoding = "sync"; + img.loading = "eager"; + } catch { + } + img.style.cssText = "position:fixed;left:0px;top:0px;width:10px;height:10px;opacity:0.01;pointer-events:none;"; + img.src = url; + document.body.appendChild(img); + (async () => { + try { + if (typeof img.decode === "function") await img.decode(); + } catch { + } + const start = performance.now(); + while (!(img.complete && img.naturalWidth > 0) && performance.now() - start < 900) { + await new Promise((r) => setTimeout(r, 50)); + } + await new Promise((r) => requestAnimationFrame(r)); + try { + img.remove(); + } catch { + } + resolve(); + })(); + }); + } + element.querySelectorAll("canvas").forEach((c) => { + try { + const ctx = c.getContext("2d", { willReadFrequently: true }); + if (ctx) { + ctx.getImageData(0, 0, 1, 1); + } + } catch { + } + }); + _safariWarmup = true; +} +function hasBackgroundOrMask(el) { + const walker = document.createTreeWalker(el, NodeFilter.SHOW_ELEMENT); + while (walker.nextNode()) { + const node = ( + /** @type {Element} */ + walker.currentNode + ); + const cs = getComputedStyle(node); + const bg = cs.backgroundImage && cs.backgroundImage !== "none"; + const mask = cs.maskImage && cs.maskImage !== "none" || cs.webkitMaskImage && cs.webkitMaskImage !== "none"; + if (bg || mask) return true; + if (node.tagName === "CANVAS") return true; + } + return false; +} + +// src/api/preCache.js +init_utils(); +init_snapFetch(); +init_cache(); +async function preCache(root = document, options = {}) { + const { + embedFonts = true, + useProxy = "" + } = options; + const cacheMode = options.cache ?? options.cacheOpt ?? "full"; + applyCachePolicy(cacheMode); + try { + await document.fonts?.ready; + } catch { + } + try { + precacheCommonTags(); + } catch { + } + cache.session = cache.session || {}; + if (!cache.session.styleCache) { + cache.session.styleCache = /* @__PURE__ */ new WeakMap(); + } + cache.image = cache.image || /* @__PURE__ */ new Map(); + cache.background = cache.background || /* @__PURE__ */ new Map(); + try { + await inlineBackgroundImages( + root, + /* mirror */ + void 0, + cache.session.styleCache, + { useProxy } + ); + } catch { + } + let imgEls = [], allEls = []; + try { + if (root && root.nodeType === 1) { + const descendants = root.querySelectorAll ? Array.from(root.querySelectorAll("*")) : []; + allEls = [root, ...descendants]; + imgEls = []; + if (root.tagName === "IMG" && root.getAttribute("src")) imgEls.push(root); + imgEls.push(...Array.from(root.querySelectorAll?.("img[src]") || [])); + } else if (root?.querySelectorAll) { + imgEls = Array.from(root.querySelectorAll("img[src]")); + allEls = Array.from(root.querySelectorAll("*")); + } + } catch { + } + const promises = []; + for (const img of imgEls) { + const src = img?.currentSrc || img?.src; + if (!src) continue; + if (!cache.image.has(src)) { + const p = Promise.resolve().then(async () => { + const res = await snapFetch(src, { as: "dataURL", useProxy }); + if (res?.ok && typeof res.data === "string") { + cache.image.set(src, res.data); + } + }).catch(() => { + }); + promises.push(p); + } + } + for (const el of allEls) { + let bg = ""; + try { + bg = el?.style?.backgroundImage || ""; + if (!bg || bg === "none") { + bg = getStyle(el).backgroundImage; + } + } catch { + } + if (bg && bg !== "none") { + const urlEntries = bg.match(/url\((?:[^()"']+|"(?:[^"]*)"|'(?:[^']*)')\)/gi) || []; + for (const entry of urlEntries) { + const p = Promise.resolve().then(() => inlineSingleBackgroundEntry(entry, { ...options, useProxy })).catch(() => { + }); + promises.push(p); + } + } + } + if (embedFonts) { + try { + const required = collectUsedFontVariants(root); + const usedCodepoints = collectUsedCodepoints(root); + const safari = typeof isSafari === "function" ? isSafari() : !!isSafari; + if (safari) { + const families = new Set( + Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean) + ); + await ensureFontsReady(families, 3); + } + await embedCustomFonts({ + required, + usedCodepoints, + exclude: options.excludeFonts, + localFonts: options.localFonts, + useProxy: options.useProxy ?? useProxy + }); + } catch { + } + } + await Promise.allSettled(promises); +} +export { + preCache, + snapdom +};