@zumer/snapdom 1.9.12-dev.0 → 1.9.12-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/snapdom.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.9.12-dev.0
4
+ * v.1.9.12-dev.2
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
@@ -673,7 +673,10 @@
673
673
  }
674
674
  }
675
675
  function isSafari() {
676
- return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
676
+ const ua = typeof navigator !== "undefined" && navigator.userAgent ? navigator.userAgent : "";
677
+ const isSafariUA = /^((?!chrome|android).)*safari/i.test(ua);
678
+ const isWeChatUA = /(MicroMessenger|wxwork|WeCom|WindowsWechat|MacWechat)/i.test(ua);
679
+ return isSafariUA || isWeChatUA;
677
680
  }
678
681
 
679
682
  // src/modules/styles.js
@@ -708,7 +711,7 @@
708
711
  } catch (e) {
709
712
  }
710
713
  }
711
- function snapshotComputedStyleFull(style) {
714
+ function snapshotComputedStyleFull(style, options = {}) {
712
715
  const out = {};
713
716
  const vis = style.getPropertyValue("visibility");
714
717
  for (let i = 0; i < style.length; i++) {
@@ -719,6 +722,24 @@
719
722
  }
720
723
  out[prop] = val;
721
724
  }
725
+ if (options.embedFonts) {
726
+ const EXTRA_FONT_PROPS = [
727
+ "font-feature-settings",
728
+ "font-variation-settings",
729
+ "font-kerning",
730
+ "font-variant",
731
+ "font-variant-ligatures",
732
+ "font-optical-sizing"
733
+ ];
734
+ for (const prop of EXTRA_FONT_PROPS) {
735
+ if (out[prop]) continue;
736
+ try {
737
+ const v = style.getPropertyValue(prop);
738
+ if (v) out[prop] = v;
739
+ } catch (e) {
740
+ }
741
+ }
742
+ }
722
743
  if (vis === "hidden") out.opacity = "0";
723
744
  return out;
724
745
  }
@@ -731,11 +752,12 @@
731
752
  __snapshotSig.set(snap, sig);
732
753
  return sig;
733
754
  }
734
- function getSnapshot(el, preStyle = null) {
755
+ function getSnapshot(el, preStyle = null, options = {}) {
735
756
  const rec = snapshotCache.get(el);
736
757
  if (rec && rec.epoch === __epoch) return rec.snapshot;
737
758
  const style = preStyle || getComputedStyle(el);
738
- const snap = snapshotComputedStyleFull(style);
759
+ const snap = snapshotComputedStyleFull(style, options);
760
+ stripHeightForWrappers(el, style, snap);
739
761
  snapshotCache.set(el, { epoch: __epoch, snapshot: snap });
740
762
  return snap;
741
763
  }
@@ -791,7 +813,7 @@
791
813
  session.styleCache.set(source, getComputedStyle(source));
792
814
  }
793
815
  const pre = session.styleCache.get(source);
794
- const snap = getSnapshot(source, pre);
816
+ const snap = getSnapshot(source, pre, ctx.options);
795
817
  const sig = styleSignature(snap);
796
818
  let key = persist.snapshotKeyCache.get(sig);
797
819
  if (!key) {
@@ -802,6 +824,49 @@
802
824
  session.styleMap.set(clone, key);
803
825
  });
804
826
  }
827
+ function isReplaced(el) {
828
+ return el instanceof HTMLImageElement || el instanceof HTMLCanvasElement || el instanceof HTMLVideoElement || el instanceof HTMLIFrameElement || el instanceof SVGElement || el instanceof HTMLObjectElement || el instanceof HTMLEmbedElement;
829
+ }
830
+ function hasBox(cs) {
831
+ if (cs.backgroundImage && cs.backgroundImage !== "none") return true;
832
+ if (cs.backgroundColor && cs.backgroundColor !== "rgba(0, 0, 0, 0)" && cs.backgroundColor !== "transparent") return true;
833
+ if ((parseFloat(cs.borderTopWidth) || 0) > 0) return true;
834
+ if ((parseFloat(cs.borderBottomWidth) || 0) > 0) return true;
835
+ if ((parseFloat(cs.paddingTop) || 0) > 0) return true;
836
+ if ((parseFloat(cs.paddingBottom) || 0) > 0) return true;
837
+ const ob = cs.overflowBlock || cs.overflowY || "visible";
838
+ return ob !== "visible";
839
+ }
840
+ function isFlexOrGridItem(el) {
841
+ const p = el.parentElement;
842
+ if (!p) return false;
843
+ const pd = getComputedStyle(p).display || "";
844
+ return pd.includes("flex") || pd.includes("grid");
845
+ }
846
+ function hasFlowFast(el, cs) {
847
+ if (el.textContent && /\S/.test(el.textContent)) return true;
848
+ const f = el.firstElementChild, l = el.lastElementChild;
849
+ if (f && f.tagName === "BR" || l && l.tagName === "BR") return true;
850
+ const sh = el.scrollHeight;
851
+ if (sh === 0) return false;
852
+ const pt = parseFloat(cs.paddingTop) || 0;
853
+ const pb = parseFloat(cs.paddingBottom) || 0;
854
+ return sh > pt + pb;
855
+ }
856
+ function stripHeightForWrappers(el, cs, snap) {
857
+ if (el instanceof HTMLElement && el.style && el.style.height) return;
858
+ const disp = cs.display || "";
859
+ if (disp.includes("flex") || disp.includes("grid")) return;
860
+ if (isReplaced(el)) return;
861
+ const pos = cs.position;
862
+ if (pos === "absolute" || pos === "fixed" || pos === "sticky") return;
863
+ if (cs.transform !== "none") return;
864
+ if (hasBox(cs)) return;
865
+ if (isFlexOrGridItem(el)) return;
866
+ if (!hasFlowFast(el, cs)) return;
867
+ delete snap.height;
868
+ delete snap["block-size"];
869
+ }
805
870
 
806
871
  // src/core/clone.js
807
872
  function idleCallback(childList, callback, fast) {
@@ -1043,7 +1108,7 @@
1043
1108
  return node.cloneNode(true);
1044
1109
  }
1045
1110
  if (node.getAttribute("data-capture") === "exclude") {
1046
- if (options.excludeMode === "visuallyHide") {
1111
+ if (options.excludeMode === "hide") {
1047
1112
  const spacer = document.createElement("div");
1048
1113
  const rect = node.getBoundingClientRect();
1049
1114
  spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
@@ -1056,7 +1121,7 @@
1056
1121
  for (const selector of options.exclude) {
1057
1122
  try {
1058
1123
  if ((_a = node.matches) == null ? void 0 : _a.call(node, selector)) {
1059
- if (options.excludeMode === "visuallyHide") {
1124
+ if (options.excludeMode === "hide") {
1060
1125
  const spacer = document.createElement("div");
1061
1126
  const rect = node.getBoundingClientRect();
1062
1127
  spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
@@ -1073,7 +1138,7 @@
1073
1138
  if (typeof options.filter === "function") {
1074
1139
  try {
1075
1140
  if (!options.filter(node)) {
1076
- if (options.filterMode === "visuallyHide") {
1141
+ if (options.filterMode === "hide") {
1077
1142
  const spacer = document.createElement("div");
1078
1143
  const rect = node.getBoundingClientRect();
1079
1144
  spacer.style.cssText = `display:inline-block;width:${rect.width}px;height:${rect.height}px;visibility:hidden;`;
@@ -1969,7 +2034,186 @@
1969
2034
  });
1970
2035
  }
1971
2036
 
2037
+ // src/modules/counter.js
2038
+ function hasCounters(input) {
2039
+ return /\bcounter\s*\(|\bcounters\s*\(/.test(input || "");
2040
+ }
2041
+ function unquoteDoubleStrings(s) {
2042
+ return (s || "").replace(/"([^"]*)"/g, "$1");
2043
+ }
2044
+ function alpha(n, upper = false) {
2045
+ let s = "", x = Math.max(1, n);
2046
+ while (x > 0) {
2047
+ x--;
2048
+ s = String.fromCharCode(97 + x % 26) + s;
2049
+ x = Math.floor(x / 26);
2050
+ }
2051
+ return upper ? s.toUpperCase() : s;
2052
+ }
2053
+ function roman(n, upper = true) {
2054
+ 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"]];
2055
+ let num = Math.max(1, Math.min(3999, n)), out = "";
2056
+ for (const [v, sym] of map) while (num >= v) {
2057
+ out += sym;
2058
+ num -= v;
2059
+ }
2060
+ return upper ? out : out.toLowerCase();
2061
+ }
2062
+ function formatCounter(value, style) {
2063
+ switch ((style || "decimal").toLowerCase()) {
2064
+ case "decimal":
2065
+ return String(Math.max(0, value));
2066
+ case "decimal-leading-zero":
2067
+ return (value < 10 ? "0" : "") + String(Math.max(0, value));
2068
+ case "lower-alpha":
2069
+ return alpha(value, false);
2070
+ case "upper-alpha":
2071
+ return alpha(value, true);
2072
+ case "lower-roman":
2073
+ return roman(value, false);
2074
+ case "upper-roman":
2075
+ return roman(value, true);
2076
+ default:
2077
+ return String(Math.max(0, value));
2078
+ }
2079
+ }
2080
+ function buildCounterContext(root) {
2081
+ const nodeCounters = /* @__PURE__ */ new WeakMap();
2082
+ const rootEl = root instanceof Document ? root.documentElement : root;
2083
+ const isLi = (el) => el && el.tagName === "LI";
2084
+ const countPrevLi = (li) => {
2085
+ let c = 0, p = li == null ? void 0 : li.parentElement;
2086
+ if (!p) return 0;
2087
+ for (const sib of p.children) {
2088
+ if (sib === li) break;
2089
+ if (sib.tagName === "LI") c++;
2090
+ }
2091
+ return c;
2092
+ };
2093
+ const cloneMap = (m) => {
2094
+ const out = /* @__PURE__ */ new Map();
2095
+ for (const [k, arr] of m) out.set(k, arr.slice());
2096
+ return out;
2097
+ };
2098
+ const applyTo = (baseMap, parentMap, el) => {
2099
+ var _a, _b;
2100
+ const map = cloneMap(baseMap);
2101
+ let reset;
2102
+ try {
2103
+ reset = ((_a = el.style) == null ? void 0 : _a.counterReset) || getComputedStyle(el).counterReset;
2104
+ } catch (e) {
2105
+ }
2106
+ if (reset && reset !== "none") {
2107
+ for (const part of reset.split(",")) {
2108
+ const toks = part.trim().split(/\s+/);
2109
+ const name = toks[0];
2110
+ const val = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 0;
2111
+ if (!name) continue;
2112
+ const parentStack = parentMap.get(name);
2113
+ if (parentStack && parentStack.length) {
2114
+ const s = parentStack.slice();
2115
+ s.push(val);
2116
+ map.set(name, s);
2117
+ } else {
2118
+ map.set(name, [val]);
2119
+ }
2120
+ }
2121
+ }
2122
+ let inc;
2123
+ try {
2124
+ inc = ((_b = el.style) == null ? void 0 : _b.counterIncrement) || getComputedStyle(el).counterIncrement;
2125
+ } catch (e) {
2126
+ }
2127
+ if (inc && inc !== "none") {
2128
+ for (const part of inc.split(",")) {
2129
+ const toks = part.trim().split(/\s+/);
2130
+ const name = toks[0];
2131
+ const by = Number.isFinite(Number(toks[1])) ? Number(toks[1]) : 1;
2132
+ if (!name) continue;
2133
+ const stack = map.get(name) || [];
2134
+ if (stack.length === 0) stack.push(0);
2135
+ stack[stack.length - 1] += by;
2136
+ map.set(name, stack);
2137
+ }
2138
+ }
2139
+ try {
2140
+ const cs = getComputedStyle(el);
2141
+ if (cs.display === "list-item" && isLi(el)) {
2142
+ const p = el.parentElement;
2143
+ let idx = 1;
2144
+ if (p && p.tagName === "OL") {
2145
+ const startAttr = p.getAttribute("start");
2146
+ const start = Number.isFinite(Number(startAttr)) ? Number(startAttr) : 1;
2147
+ const prev = countPrevLi(el);
2148
+ const ownAttr = el.getAttribute("value");
2149
+ idx = Number.isFinite(Number(ownAttr)) ? Number(ownAttr) : start + prev;
2150
+ } else {
2151
+ idx = 1 + countPrevLi(el);
2152
+ }
2153
+ const s = map.get("list-item") || [];
2154
+ if (s.length === 0) s.push(0);
2155
+ s[s.length - 1] = idx;
2156
+ map.set("list-item", s);
2157
+ }
2158
+ } catch (e) {
2159
+ }
2160
+ return map;
2161
+ };
2162
+ const build = (el, parentMap, carryMap) => {
2163
+ const curr = applyTo(carryMap, parentMap, el);
2164
+ nodeCounters.set(el, curr);
2165
+ let nextCarry = curr;
2166
+ for (const child of el.children) {
2167
+ const childCarry = build(child, curr, nextCarry);
2168
+ nextCarry = childCarry;
2169
+ }
2170
+ return curr;
2171
+ };
2172
+ const empty = /* @__PURE__ */ new Map();
2173
+ build(rootEl, empty, empty);
2174
+ return {
2175
+ get(node, name) {
2176
+ var _a;
2177
+ const s = (_a = nodeCounters.get(node)) == null ? void 0 : _a.get(name);
2178
+ return s && s.length ? s[s.length - 1] : 0;
2179
+ },
2180
+ getStack(node, name) {
2181
+ var _a;
2182
+ const s = (_a = nodeCounters.get(node)) == null ? void 0 : _a.get(name);
2183
+ return s ? s.slice() : [];
2184
+ }
2185
+ };
2186
+ }
2187
+ function resolveCountersInContent(raw, node, ctx) {
2188
+ if (!raw || raw === "none") return raw;
2189
+ try {
2190
+ const RX = /\b(counter|counters)\s*\(([^)]+)\)/g;
2191
+ let out = raw.replace(RX, (_, fn, args) => {
2192
+ var _a, _b, _c, _d;
2193
+ const parts = String(args).split(",").map((s) => s.trim());
2194
+ if (fn === "counter") {
2195
+ const name = (_a = parts[0]) == null ? void 0 : _a.replace(/^["']|["']$/g, "");
2196
+ const style = (parts[1] || "decimal").toLowerCase();
2197
+ const v = ctx.get(node, name);
2198
+ return formatCounter(v, style);
2199
+ } else {
2200
+ const name = (_b = parts[0]) == null ? void 0 : _b.replace(/^["']|["']$/g, "");
2201
+ const sep = (_d = (_c = parts[1]) == null ? void 0 : _c.replace(/^["']|["']$/g, "")) != null ? _d : "";
2202
+ const style = (parts[2] || "decimal").toLowerCase();
2203
+ const stack = ctx.getStack(node, name);
2204
+ if (!stack.length) return "";
2205
+ const pieces = stack.map((v) => formatCounter(v, style));
2206
+ return pieces.join(sep);
2207
+ }
2208
+ });
2209
+ return unquoteDoubleStrings(out);
2210
+ } catch (e) {
2211
+ return "- ";
2212
+ }
2213
+ }
2214
+
1972
2215
  // src/modules/pseudo.js
2216
+ var counterCtx = null;
1973
2217
  function inlinePseudoElements(source, clone, sessionCache, options) {
1974
2218
  return __async(this, null, function* () {
1975
2219
  var _a;
@@ -2008,7 +2252,11 @@
2008
2252
  continue;
2009
2253
  }
2010
2254
  const content = style.content;
2011
- const cleanContent = /counter\s*\(|counters\s*\(/.test(content) ? "- " : parseContent(content);
2255
+ let cleanContent = parseContent(content);
2256
+ if (hasCounters(content)) {
2257
+ counterCtx = buildCounterContext(source.ownerDocument || document);
2258
+ cleanContent = resolveCountersInContent(cleanContent, source, counterCtx);
2259
+ }
2012
2260
  const bg = style.backgroundImage;
2013
2261
  const bgColor = style.backgroundColor;
2014
2262
  const fontFamily = style.fontFamily;
@@ -2025,10 +2273,10 @@
2025
2273
  const hasExplicitContent = content !== "none" && cleanContent !== "";
2026
2274
  const hasBg = bg && bg !== "none";
2027
2275
  const hasBgColor = bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)";
2028
- const hasBox = display !== "inline" && (width > 0 || height > 0);
2276
+ const hasBox2 = display !== "inline" && (width > 0 || height > 0);
2029
2277
  const hasBorder = borderStyle && borderStyle !== "none" && borderWidth > 0;
2030
2278
  const hasTransform = transform && transform !== "none";
2031
- const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBox || hasBorder || hasTransform;
2279
+ const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBox2 || hasBorder || hasTransform;
2032
2280
  if (!shouldRender) continue;
2033
2281
  const pseudoEl = document.createElement("span");
2034
2282
  pseudoEl.dataset.snapdomPseudo = pseudo;
@@ -2070,7 +2318,7 @@
2070
2318
  }
2071
2319
  if (hasBgColor) pseudoEl.style.backgroundColor = bgColor;
2072
2320
  const hasContent2 = pseudoEl.childNodes.length > 0 || ((_a = pseudoEl.textContent) == null ? void 0 : _a.trim()) !== "";
2073
- const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBox || hasBorder || hasTransform;
2321
+ const hasVisibleBox = hasContent2 || hasBg || hasBgColor || hasBox2 || hasBorder || hasTransform;
2074
2322
  if (!hasVisibleBox) continue;
2075
2323
  if (pseudo === "::before") {
2076
2324
  clone.insertBefore(pseudoEl, clone.firstChild);
@@ -2408,8 +2656,8 @@
2408
2656
  if (!img.height) img.height = img.naturalHeight || 100;
2409
2657
  return;
2410
2658
  }
2411
- const { defaultImageUrl } = options || {};
2412
- if (defaultImageUrl) {
2659
+ const { fallbackURL } = options || {};
2660
+ if (fallbackURL) {
2413
2661
  try {
2414
2662
  const dsW = parseInt(((_a = img.dataset) == null ? void 0 : _a.snapdomWidth) || "", 10) || 0;
2415
2663
  const dsH = parseInt(((_b = img.dataset) == null ? void 0 : _b.snapdomHeight) || "", 10) || 0;
@@ -2417,14 +2665,14 @@
2417
2665
  const attrH = parseInt(img.getAttribute("height") || "", 10) || 0;
2418
2666
  const styleW = parseFloat(((_c = img.style) == null ? void 0 : _c.width) || "") || 0;
2419
2667
  const styleH = parseFloat(((_d = img.style) == null ? void 0 : _d.height) || "") || 0;
2420
- const width = dsW || styleW || attrW || img.width || void 0;
2421
- const height = dsH || styleH || attrH || img.height || void 0;
2422
- const fallbackUrl = typeof defaultImageUrl === "function" ? yield defaultImageUrl({ width, height, src, element: img }) : defaultImageUrl;
2668
+ const fbW = dsW || styleW || attrW || img.width || void 0;
2669
+ const fbH = dsH || styleH || attrH || img.height || void 0;
2670
+ const fallbackUrl = typeof fallbackURL === "function" ? yield fallbackURL({ width: fbW, height: fbH, src, element: img }) : fallbackURL;
2423
2671
  if (fallbackUrl) {
2424
2672
  const fallbackData = yield snapFetch(fallbackUrl, { as: "dataURL", useProxy: options.useProxy });
2425
2673
  img.src = fallbackData.data;
2426
- if (!img.width && width) img.width = width;
2427
- if (!img.height && height) img.height = height;
2674
+ if (!img.width && fbW) img.width = fbW;
2675
+ if (!img.height && fbH) img.height = fbH;
2428
2676
  if (!img.width) img.width = img.naturalWidth || 100;
2429
2677
  if (!img.height) img.height = img.naturalHeight || 100;
2430
2678
  return;
@@ -2546,6 +2794,64 @@
2546
2794
  });
2547
2795
  }
2548
2796
 
2797
+ // src/modules/lineClamp.js
2798
+ function lineClamp(el) {
2799
+ var _a;
2800
+ if (!el) return () => {
2801
+ };
2802
+ const lines = getClamp(el);
2803
+ if (lines <= 0) return () => {
2804
+ };
2805
+ if (!isPlainTextContainer(el)) return () => {
2806
+ };
2807
+ const cs = getComputedStyle(el);
2808
+ const targetH = Math.round(usedLineHeightPx(cs) * lines + vpad(cs));
2809
+ const original = (_a = el.textContent) != null ? _a : "";
2810
+ const prevText = original;
2811
+ if (el.scrollHeight <= targetH + 0.5) {
2812
+ return () => {
2813
+ };
2814
+ }
2815
+ let lo = 0, hi = original.length, best = -1;
2816
+ while (lo <= hi) {
2817
+ const mid = lo + hi >> 1;
2818
+ el.textContent = original.slice(0, mid) + "\u2026";
2819
+ if (el.scrollHeight <= targetH + 0.5) {
2820
+ best = mid;
2821
+ lo = mid + 1;
2822
+ } else {
2823
+ hi = mid - 1;
2824
+ }
2825
+ }
2826
+ el.textContent = (best >= 0 ? original.slice(0, best) : "") + "\u2026";
2827
+ return () => {
2828
+ el.textContent = prevText;
2829
+ };
2830
+ }
2831
+ function getClamp(el) {
2832
+ const cs = getComputedStyle(el);
2833
+ let v = cs.getPropertyValue("-webkit-line-clamp") || cs.getPropertyValue("line-clamp");
2834
+ v = (v || "").trim();
2835
+ const n = parseInt(v, 10);
2836
+ return Number.isFinite(n) && n > 0 ? n : 0;
2837
+ }
2838
+ function usedLineHeightPx(cs) {
2839
+ const lh = (cs.lineHeight || "").trim();
2840
+ const fs = parseFloat(cs.fontSize) || 16;
2841
+ if (!lh || lh === "normal") return Math.round(fs * 1.2);
2842
+ if (lh.endsWith("px")) return parseFloat(lh);
2843
+ if (/^\d+(\.\d+)?$/.test(lh)) return Math.round(parseFloat(lh) * fs);
2844
+ if (lh.endsWith("%")) return Math.round(parseFloat(lh) / 100 * fs);
2845
+ return Math.round(fs * 1.2);
2846
+ }
2847
+ function vpad(cs) {
2848
+ return (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);
2849
+ }
2850
+ function isPlainTextContainer(el) {
2851
+ if (el.childElementCount > 0) return false;
2852
+ return Array.from(el.childNodes).some((n) => n.nodeType === Node.TEXT_NODE);
2853
+ }
2854
+
2549
2855
  // src/core/capture.js
2550
2856
  function captureDOM(element, options) {
2551
2857
  return __async(this, null, function* () {
@@ -2557,7 +2863,12 @@
2557
2863
  let baseCSS = "";
2558
2864
  let dataURL;
2559
2865
  let svgString;
2560
- ({ clone, classCSS, styleCache } = yield prepareClone(element, options));
2866
+ const undoClamp = lineClamp(element);
2867
+ try {
2868
+ ({ clone, classCSS, styleCache } = yield prepareClone(element, options));
2869
+ } finally {
2870
+ undoClamp();
2871
+ }
2561
2872
  yield new Promise((resolve) => {
2562
2873
  idle(() => __async(null, null, function* () {
2563
2874
  yield inlineImages(clone, options);
@@ -2608,28 +2919,28 @@
2608
2919
  yield new Promise((resolve) => {
2609
2920
  idle(() => {
2610
2921
  var _a, _b, _c, _d, _e;
2611
- const rect = getNaturalBorderBoxSize(element);
2612
- let w = rect.width;
2613
- let h = rect.height;
2922
+ const rect = element.getBoundingClientRect();
2923
+ let w = Number(rect.width) || 0;
2924
+ let h = Number(rect.height) || 0;
2614
2925
  const hasW = Number.isFinite(options.width);
2615
2926
  const hasH = Number.isFinite(options.height);
2616
2927
  const scaleOpt = (_a = options.scale) != null ? _a : 1;
2617
2928
  const hasScale = typeof scaleOpt === "number" && scaleOpt !== 1;
2618
2929
  if (!hasScale) {
2619
- const aspect = rect.width / rect.height;
2930
+ const aspect = h > 0 ? w / h : 1;
2620
2931
  if (hasW && hasH) {
2621
- w = options.width;
2622
- h = options.height;
2932
+ w = Number(options.width);
2933
+ h = Number(options.height);
2623
2934
  } else if (hasW) {
2624
- w = options.width;
2625
- h = w / aspect;
2935
+ w = Number(options.width);
2936
+ h = w / (aspect || 1);
2626
2937
  } else if (hasH) {
2627
- h = options.height;
2628
- w = h * aspect;
2938
+ h = Number(options.height);
2939
+ w = h * (aspect || 1);
2629
2940
  }
2630
2941
  }
2631
- w = Math.max(1, Math.ceil(w));
2632
- h = Math.max(1, Math.ceil(h));
2942
+ w = Math.max(1, Math.ceil(Number.isFinite(w) ? w : 1));
2943
+ h = Math.max(1, Math.ceil(Number.isFinite(h) ? h : 1));
2633
2944
  const csEl = getComputedStyle(element);
2634
2945
  const baseTransform = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
2635
2946
  const ind = readIndividualTransforms(element);
@@ -2700,7 +3011,9 @@
2700
3011
  fo.appendChild(container);
2701
3012
  const serializer = new XMLSerializer();
2702
3013
  const foString = serializer.serializeToString(fo);
2703
- const svgHeader = `<svg xmlns="${svgNS}" width="${outW}" height="${outH}" viewBox="0 0 ${outW} ${outH}">`;
3014
+ const finalW = !hasScale && (hasW || hasH) ? w : outW;
3015
+ const finalH = !hasScale && (hasH || hasW) ? h : outH;
3016
+ const svgHeader = `<svg xmlns="${svgNS}" width="${finalW}" height="${finalH}" viewBox="0 0 ${outW} ${outH}">`;
2704
3017
  const svgFooter = "</svg>";
2705
3018
  svgString = svgHeader + foString + svgFooter;
2706
3019
  dataURL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}`;
@@ -2712,17 +3025,6 @@
2712
3025
  return dataURL;
2713
3026
  });
2714
3027
  }
2715
- function getNaturalBorderBoxSize(el) {
2716
- const cs = getComputedStyle(el);
2717
- const px = (v) => parseFloat(v) || 0;
2718
- let w = px(cs.width);
2719
- let h = px(cs.height);
2720
- if (cs.boxSizing === "content-box") {
2721
- w += px(cs.paddingLeft) + px(cs.paddingRight) + px(cs.borderLeftWidth) + px(cs.borderRightWidth);
2722
- h += px(cs.paddingTop) + px(cs.paddingBottom) + px(cs.borderTopWidth) + px(cs.borderBottomWidth);
2723
- }
2724
- return { width: w, height: h };
2725
- }
2726
3028
  function matrixFromComputed(el) {
2727
3029
  const tr = getComputedStyle(el).transform;
2728
3030
  if (!tr || tr === "none") return new DOMMatrix();
@@ -2753,31 +3055,40 @@
2753
3055
  return { minX, minY, width: maxX - minX, height: maxY - minY };
2754
3056
  }
2755
3057
  function readIndividualTransforms(el) {
2756
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
3058
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
2757
3059
  const out = { rotate: "0deg", scale: null, translate: null };
2758
- const map = (_a = el.computedStyleMap) == null ? void 0 : _a.call(el);
3060
+ const map = typeof el.computedStyleMap === "function" ? el.computedStyleMap() : null;
2759
3061
  if (map) {
2760
- const rot = map.get("rotate");
3062
+ const safeGet = (prop) => {
3063
+ try {
3064
+ if (typeof map.has === "function" && !map.has(prop)) return null;
3065
+ if (typeof map.get !== "function") return null;
3066
+ return map.get(prop);
3067
+ } catch (e) {
3068
+ return null;
3069
+ }
3070
+ };
3071
+ const rot = safeGet("rotate");
2761
3072
  if (rot) {
2762
- const ang = (_b = rot.angle) != null ? _b : rot;
2763
- if (ang && "unit" in ang) {
3073
+ const ang = (_a = rot.angle) != null ? _a : rot;
3074
+ if (ang && typeof ang === "object" && "unit" in ang) {
2764
3075
  out.rotate = ang.unit === "rad" ? ang.value * 180 / Math.PI + "deg" : ang.value + ang.unit;
2765
3076
  } else {
2766
3077
  out.rotate = String(rot);
2767
3078
  }
2768
3079
  }
2769
- const sc = map.get("scale");
3080
+ const sc = safeGet("scale");
2770
3081
  if (sc && sc.length) {
2771
- const sx = (_d = (_c = sc[0]) == null ? void 0 : _c.value) != null ? _d : 1;
2772
- const sy = (_f = (_e = sc[1]) == null ? void 0 : _e.value) != null ? _f : sx;
3082
+ const sx = (_c = (_b = sc[0]) == null ? void 0 : _b.value) != null ? _c : 1;
3083
+ const sy = (_e = (_d = sc[1]) == null ? void 0 : _d.value) != null ? _e : sx;
2773
3084
  out.scale = `${sx} ${sy}`;
2774
3085
  }
2775
- const tr = map.get("translate");
3086
+ const tr = safeGet("translate");
2776
3087
  if (tr && tr.length) {
2777
- const tx = (_h = (_g = tr[0]) == null ? void 0 : _g.value) != null ? _h : 0;
2778
- const ty = (_j = (_i = tr[1]) == null ? void 0 : _i.value) != null ? _j : 0;
2779
- const ux = (_l = (_k = tr[0]) == null ? void 0 : _k.unit) != null ? _l : "px";
2780
- const uy = (_n = (_m = tr[1]) == null ? void 0 : _m.unit) != null ? _n : "px";
3088
+ const tx = (_g = (_f = tr[0]) == null ? void 0 : _f.value) != null ? _g : 0;
3089
+ const ty = (_i = (_h = tr[1]) == null ? void 0 : _h.value) != null ? _i : 0;
3090
+ const ux = (_k = (_j = tr[0]) == null ? void 0 : _j.unit) != null ? _k : "px";
3091
+ const uy = (_m = (_l = tr[1]) == null ? void 0 : _l.unit) != null ? _m : "px";
2781
3092
  out.translate = `${tx}${ux} ${ty}${uy}`;
2782
3093
  }
2783
3094
  return out;
@@ -2858,9 +3169,9 @@
2858
3169
  scale: (_d = options.scale) != null ? _d : 1,
2859
3170
  // DOM filters
2860
3171
  exclude: (_e = options.exclude) != null ? _e : [],
2861
- excludeMode: (_f = options.excludeMode) != null ? _f : "visuallyHide",
3172
+ excludeMode: (_f = options.excludeMode) != null ? _f : "hide",
2862
3173
  filter: (_g = options.filter) != null ? _g : null,
2863
- filterMode: (_h = options.filterMode) != null ? _h : "visuallyHide",
3174
+ filterMode: (_h = options.filterMode) != null ? _h : "hide",
2864
3175
  placeholders: options.placeholders !== false,
2865
3176
  // default true
2866
3177
  // Fuentes
@@ -2868,7 +3179,7 @@
2868
3179
  iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
2869
3180
  localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
2870
3181
  excludeFonts: (_j = options.excludeFonts) != null ? _j : void 0,
2871
- defaultImageUrl: (_k = options.defaultImageUrl) != null ? _k : void 0,
3182
+ fallbackURL: (_k = options.fallbackURL) != null ? _k : void 0,
2872
3183
  /** Cache policy (disabled|full|auto|soft). Default: "soft" */
2873
3184
  /** @type {CachePolicy} */
2874
3185
  cache: cachePolicy,
@@ -2963,6 +3274,7 @@
2963
3274
  // src/exporters/download.js
2964
3275
  function download(url, options) {
2965
3276
  return __async(this, null, function* () {
3277
+ options.dpr = 1;
2966
3278
  if (options.format === "svg") {
2967
3279
  const blob = yield toBlob(url, __spreadProps(__spreadValues({}, options), { type: "svg" }));
2968
3280
  const objectURL = URL.createObjectURL(blob);