@zumer/snapdom 1.9.5 → 1.9.6-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/snapdom.mjs CHANGED
@@ -1,20 +1,36 @@
1
1
 
2
2
  /*
3
3
  * snapdom
4
- * v.1.9.5
4
+ * v.1.9.6-dev.0
5
5
  * Author Juan Martin Muda
6
6
  * License MIT
7
7
  **/
8
8
 
9
9
 
10
10
  // src/core/cache.js
11
- var imageCache = /* @__PURE__ */ new Map();
12
- var bgCache = /* @__PURE__ */ new Map();
13
- var resourceCache = /* @__PURE__ */ new Map();
14
- var defaultStylesCache = /* @__PURE__ */ new Map();
15
- var baseCSSCache = /* @__PURE__ */ new Map();
16
- var computedStyleCache = /* @__PURE__ */ new WeakMap();
17
- var processedFontURLs = /* @__PURE__ */ new Set();
11
+ var cache = {
12
+ image: /* @__PURE__ */ new Map(),
13
+ background: /* @__PURE__ */ new Map(),
14
+ resource: /* @__PURE__ */ new Map(),
15
+ defaultStyle: /* @__PURE__ */ new Map(),
16
+ baseStyle: /* @__PURE__ */ new Map(),
17
+ computedStyle: /* @__PURE__ */ new WeakMap(),
18
+ font: /* @__PURE__ */ new Set(),
19
+ snapshot: /* @__PURE__ */ new WeakMap(),
20
+ snapshotKey: /* @__PURE__ */ new Map(),
21
+ preStyleMap: /* @__PURE__ */ new Map(),
22
+ preStyle: /* @__PURE__ */ new WeakMap(),
23
+ preNodeMap: /* @__PURE__ */ new Map(),
24
+ reset: resetCache
25
+ };
26
+ function resetCache() {
27
+ cache.computedStyle = /* @__PURE__ */ new WeakMap();
28
+ cache.snapshot = /* @__PURE__ */ new WeakMap();
29
+ cache.snapshotKey.clear();
30
+ cache.preStyleMap.clear();
31
+ cache.preStyle = /* @__PURE__ */ new WeakMap();
32
+ cache.preNodeMap.clear();
33
+ }
18
34
 
19
35
  // src/utils/cssTools.js
20
36
  var commonTags = [
@@ -62,13 +78,13 @@ function precacheCommonTags() {
62
78
  }
63
79
  }
64
80
  function getDefaultStyleForTag(tagName) {
65
- if (defaultStylesCache.has(tagName)) {
66
- return defaultStylesCache.get(tagName);
81
+ if (cache.defaultStyle.has(tagName)) {
82
+ return cache.defaultStyle.get(tagName);
67
83
  }
68
84
  const skipTags = /* @__PURE__ */ new Set(["script", "style", "meta", "link", "noscript", "template"]);
69
85
  if (skipTags.has(tagName)) {
70
86
  const empty = {};
71
- defaultStylesCache.set(tagName, empty);
87
+ cache.defaultStyle.set(tagName, empty);
72
88
  return empty;
73
89
  }
74
90
  let sandbox = document.getElementById("snapdom-sandbox");
@@ -92,7 +108,7 @@ function getDefaultStyleForTag(tagName) {
92
108
  defaults[prop] = styles.getPropertyValue(prop);
93
109
  }
94
110
  sandbox.removeChild(el);
95
- defaultStylesCache.set(tagName, defaults);
111
+ cache.defaultStyle.set(tagName, defaults);
96
112
  return defaults;
97
113
  }
98
114
  function getStyleKey(snapshot, tagName, compress = false) {
@@ -128,7 +144,7 @@ function collectUsedTagNames(root) {
128
144
  function generateDedupedBaseCSS(usedTagNames) {
129
145
  const groups = /* @__PURE__ */ new Map();
130
146
  for (let tagName of usedTagNames) {
131
- const styles = defaultStylesCache.get(tagName);
147
+ const styles = cache.defaultStyle.get(tagName);
132
148
  if (!styles) continue;
133
149
  const key = Object.entries(styles).map(([k, v]) => `${k}:${v};`).sort().join("");
134
150
  if (!groups.has(key)) {
@@ -143,8 +159,8 @@ function generateDedupedBaseCSS(usedTagNames) {
143
159
  }
144
160
  return css;
145
161
  }
146
- function generateCSSClasses(styleMap) {
147
- const keySet = new Set(styleMap.values());
162
+ function generateCSSClasses() {
163
+ const keySet = new Set(cache.preStyleMap.values());
148
164
  const classMap = /* @__PURE__ */ new Map();
149
165
  let counter = 1;
150
166
  for (const key of keySet) {
@@ -155,16 +171,15 @@ function generateCSSClasses(styleMap) {
155
171
 
156
172
  // src/utils/helpers.js
157
173
  async function inlineSingleBackgroundEntry(entry, options = {}) {
158
- const match = entry.match(/url\(["']?(.*?)["']?\)/);
159
- const rawUrl = match?.[1];
174
+ const rawUrl = extractURL(entry);
160
175
  const isGradient = /^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(entry);
161
176
  if (rawUrl) {
162
177
  const encodedUrl = safeEncodeURI(rawUrl);
163
- if (bgCache.has(encodedUrl)) {
164
- return options.skipInline ? void 0 : `url(${bgCache.get(encodedUrl)})`;
178
+ if (cache.background.has(encodedUrl)) {
179
+ return options.skipInline ? void 0 : `url(${cache.background.get(encodedUrl)})`;
165
180
  } else {
166
181
  const dataUrl = await fetchImage(encodedUrl, { useProxy: options.useProxy });
167
- bgCache.set(encodedUrl, dataUrl);
182
+ cache.background.set(encodedUrl, dataUrl);
168
183
  return options.skipInline ? void 0 : `url("${dataUrl}")`;
169
184
  }
170
185
  }
@@ -185,10 +200,10 @@ function getStyle(el, pseudo = null) {
185
200
  if (!(el instanceof Element)) {
186
201
  return window.getComputedStyle(el, pseudo);
187
202
  }
188
- let map = computedStyleCache.get(el);
203
+ let map = cache.computedStyle.get(el);
189
204
  if (!map) {
190
205
  map = /* @__PURE__ */ new Map();
191
- computedStyleCache.set(el, map);
206
+ cache.computedStyle.set(el, map);
192
207
  }
193
208
  if (!map.has(pseudo)) {
194
209
  const st = window.getComputedStyle(el, pseudo);
@@ -262,13 +277,13 @@ function fetchImage(src, { timeout = 3e3, useProxy = "" } = {}) {
262
277
  }
263
278
  const crossOriginValue = getCrossOriginMode(src);
264
279
  console.log(`[SnapDOM - fetchImage] Start loading image: ${src} with crossOrigin=${crossOriginValue}`);
265
- if (imageCache.has(src)) {
280
+ if (cache.image.has(src)) {
266
281
  console.log(`[SnapDOM - fetchImage] Cache hit for: ${src}`);
267
- return Promise.resolve(imageCache.get(src));
282
+ return Promise.resolve(cache.image.get(src));
268
283
  }
269
284
  const isDataURI = src.startsWith("data:image/");
270
285
  if (isDataURI) {
271
- imageCache.set(src, src);
286
+ cache.image.set(src, src);
272
287
  return Promise.resolve(src);
273
288
  }
274
289
  const isSVG = /\.svg(\?.*)?$/i.test(src);
@@ -281,7 +296,7 @@ function fetchImage(src, { timeout = 3e3, useProxy = "" } = {}) {
281
296
  });
282
297
  const svgText = await response.text();
283
298
  const encoded = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgText)}`;
284
- imageCache.set(src, encoded);
299
+ cache.image.set(src, encoded);
285
300
  return encoded;
286
301
  } catch {
287
302
  return fetchWithFallback(src);
@@ -305,12 +320,12 @@ function fetchImage(src, { timeout = 3e3, useProxy = "" } = {}) {
305
320
  const ctx = canvas.getContext("2d");
306
321
  ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
307
322
  const dataURL = canvas.toDataURL("image/png");
308
- imageCache.set(src, dataURL);
323
+ cache.image.set(src, dataURL);
309
324
  resolve(dataURL);
310
325
  } catch {
311
326
  try {
312
327
  const fallbackDataURL = await fetchWithFallback(src);
313
- imageCache.set(src, fallbackDataURL);
328
+ cache.image.set(src, fallbackDataURL);
314
329
  resolve(fallbackDataURL);
315
330
  } catch (e) {
316
331
  reject(e);
@@ -322,7 +337,7 @@ function fetchImage(src, { timeout = 3e3, useProxy = "" } = {}) {
322
337
  console.error(`[SnapDOM - fetchImage] Image failed to load: ${src}`);
323
338
  try {
324
339
  const fallbackDataURL = await fetchWithFallback(src);
325
- imageCache.set(src, fallbackDataURL);
340
+ cache.image.set(src, fallbackDataURL);
326
341
  resolve(fallbackDataURL);
327
342
  } catch (e) {
328
343
  reject(e);
@@ -386,8 +401,6 @@ function splitBackgroundImage(bg) {
386
401
  }
387
402
 
388
403
  // src/modules/styles.js
389
- var snapshotCache = /* @__PURE__ */ new WeakMap();
390
- var snapshotKeyCache = /* @__PURE__ */ new Map();
391
404
  function snapshotComputedStyleFull(style) {
392
405
  const result = {};
393
406
  for (let i = 0; i < style.length; i++) {
@@ -400,33 +413,33 @@ function snapshotComputedStyleFull(style) {
400
413
  }
401
414
  return result;
402
415
  }
403
- function inlineAllStyles(source, clone, styleMap, cache, compress) {
416
+ function inlineAllStyles(source, clone, compress) {
404
417
  if (source.tagName === "STYLE") return;
405
- if (!cache.has(source)) {
406
- cache.set(source, getStyle(source));
418
+ if (!cache.preStyle.has(source)) {
419
+ cache.preStyle.set(source, getStyle(source));
407
420
  }
408
- const style = cache.get(source);
409
- if (!snapshotCache.has(source)) {
421
+ const style = cache.preStyle.get(source);
422
+ if (!cache.snapshot.has(source)) {
410
423
  const snapshot2 = snapshotComputedStyleFull(style);
411
- snapshotCache.set(source, snapshot2);
424
+ cache.snapshot.set(source, snapshot2);
412
425
  }
413
- const snapshot = snapshotCache.get(source);
426
+ const snapshot = cache.snapshot.get(source);
414
427
  const hash = Object.entries(snapshot).sort(([a], [b]) => a.localeCompare(b)).map(([prop, val]) => `${prop}:${val}`).join(";");
415
- if (snapshotKeyCache.has(hash)) {
416
- styleMap.set(clone, snapshotKeyCache.get(hash));
428
+ if (cache.snapshotKey.has(hash)) {
429
+ cache.preStyleMap.set(clone, cache.snapshotKey.get(hash));
417
430
  return;
418
431
  }
419
432
  const tagName = source.tagName?.toLowerCase() || "div";
420
433
  const key = getStyleKey(snapshot, tagName, compress);
421
- snapshotKeyCache.set(hash, key);
422
- styleMap.set(clone, key);
434
+ cache.snapshotKey.set(hash, key);
435
+ cache.preStyleMap.set(clone, key);
423
436
  }
424
437
 
425
438
  // src/core/clone.js
426
439
  function isSlotElement(node) {
427
440
  return node.nodeType === Node.ELEMENT_NODE && node.tagName === "SLOT";
428
441
  }
429
- function deepClone(node, styleMap, styleCache, nodeMap, compress, options = {}, originalRoot) {
442
+ function deepClone(node, compress, options = {}, originalRoot) {
430
443
  if (node.nodeType === Node.TEXT_NODE) {
431
444
  return node.cloneNode(true);
432
445
  }
@@ -471,8 +484,8 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress, options = {},
471
484
  }
472
485
  if (node.getAttribute("data-capture") === "placeholder") {
473
486
  const clone2 = node.cloneNode(false);
474
- nodeMap.set(clone2, node);
475
- inlineAllStyles(node, clone2, styleMap, styleCache, compress);
487
+ cache.preNodeMap.set(clone2, node);
488
+ inlineAllStyles(node, clone2, compress);
476
489
  const placeholder = document.createElement("div");
477
490
  placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
478
491
  placeholder.style.cssText = `color: #666;font-size: 12px;text-align: center;line-height: 1.4;padding: 0.5em;box-sizing: border-box;`;
@@ -491,7 +504,7 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress, options = {},
491
504
  return img;
492
505
  }
493
506
  const clone = node.cloneNode(false);
494
- nodeMap.set(clone, node);
507
+ cache.preNodeMap.set(clone, node);
495
508
  if (node instanceof HTMLInputElement) {
496
509
  clone.value = node.value;
497
510
  clone.setAttribute("value", node.value);
@@ -514,13 +527,13 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress, options = {},
514
527
  }
515
528
  });
516
529
  }
517
- inlineAllStyles(node, clone, styleMap, styleCache, compress);
530
+ inlineAllStyles(node, clone, compress);
518
531
  if (isSlotElement(node)) {
519
532
  const assigned = node.assignedNodes?.({ flatten: true }) || [];
520
533
  const nodesToClone = assigned.length > 0 ? assigned : Array.from(node.childNodes);
521
534
  const fragment = document.createDocumentFragment();
522
535
  for (const child of nodesToClone) {
523
- const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
536
+ const clonedChild = deepClone(child, compress, options, originalRoot || node);
524
537
  if (clonedChild) fragment.appendChild(clonedChild);
525
538
  }
526
539
  return fragment;
@@ -528,13 +541,13 @@ function deepClone(node, styleMap, styleCache, nodeMap, compress, options = {},
528
541
  } else {
529
542
  const baseChildren = node.shadowRoot ? node.shadowRoot.childNodes : node.childNodes;
530
543
  for (const child of baseChildren) {
531
- const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
544
+ const clonedChild = deepClone(child, compress, options, originalRoot || node);
532
545
  if (clonedChild) clone.appendChild(clonedChild);
533
546
  }
534
547
  if (node.shadowRoot && node.childNodes.length > 0 && !node.shadowRoot.querySelector("slot")) {
535
548
  const lightDomContent = document.createDocumentFragment();
536
549
  for (const child of node.childNodes) {
537
- const clonedChild = deepClone(child, styleMap, styleCache, nodeMap, compress, options, originalRoot || node);
550
+ const clonedChild = deepClone(child, compress, options, originalRoot || node);
538
551
  if (clonedChild) lightDomContent.appendChild(clonedChild);
539
552
  }
540
553
  clone.appendChild(lightDomContent);
@@ -620,14 +633,14 @@ function injectLinkIfMissing(href) {
620
633
  });
621
634
  }
622
635
  async function embedCustomFonts({ preCached = false } = {}) {
623
- if (resourceCache.has("fonts-embed-css")) {
636
+ if (cache.resource.has("fonts-embed-css")) {
624
637
  if (preCached) {
625
638
  const style = document.createElement("style");
626
639
  style.setAttribute("data-snapdom", "embedFonts");
627
- style.textContent = resourceCache.get("fonts-embed-css");
640
+ style.textContent = cache.resource.get("fonts-embed-css");
628
641
  document.head.appendChild(style);
629
642
  }
630
- return resourceCache.get("fonts-embed-css");
643
+ return cache.resource.get("fonts-embed-css");
631
644
  }
632
645
  const importRegex = /@import\s+url\(["']?([^"')]+)["']?\)/g;
633
646
  const styleImports = [];
@@ -660,11 +673,11 @@ async function embedCustomFonts({ preCached = false } = {}) {
660
673
  url = new URL(url, link.href).href;
661
674
  }
662
675
  if (isIconFont(url)) return null;
663
- if (resourceCache.has(url)) {
664
- processedFontURLs.add(url);
665
- return { original: match[0], inlined: `url(${resourceCache.get(url)})` };
676
+ if (cache.resource.has(url)) {
677
+ cache.font.add(url);
678
+ return { original: match[0], inlined: `url(${cache.resource.get(url)})` };
666
679
  }
667
- if (processedFontURLs.has(url)) return null;
680
+ if (cache.font.has(url)) return null;
668
681
  try {
669
682
  const fontRes = await fetch(url);
670
683
  const blob = await fontRes.blob();
@@ -673,8 +686,8 @@ async function embedCustomFonts({ preCached = false } = {}) {
673
686
  reader.onload = () => resolve(reader.result);
674
687
  reader.readAsDataURL(blob);
675
688
  });
676
- resourceCache.set(url, b64);
677
- processedFontURLs.add(url);
689
+ cache.resource.set(url, b64);
690
+ cache.font.add(url);
678
691
  return { original: match[0], inlined: `url(${b64})` };
679
692
  } catch (e) {
680
693
  console.warn("[snapdom] Failed to fetch font resource:", url);
@@ -710,12 +723,12 @@ async function embedCustomFonts({ preCached = false } = {}) {
710
723
  url = new URL(url, sheet.href || location.href).href;
711
724
  }
712
725
  if (isIconFont(url)) continue;
713
- if (resourceCache.has(url)) {
714
- processedFontURLs.add(url);
715
- inlinedSrc = inlinedSrc.replace(match[0], `url(${resourceCache.get(url)})`);
726
+ if (cache.resource.has(url)) {
727
+ cache.font.add(url);
728
+ inlinedSrc = inlinedSrc.replace(match[0], `url(${cache.resource.get(url)})`);
716
729
  continue;
717
730
  }
718
- if (processedFontURLs.has(url)) continue;
731
+ if (cache.font.has(url)) continue;
719
732
  try {
720
733
  const res = await fetch(url);
721
734
  const blob = await res.blob();
@@ -724,8 +737,8 @@ async function embedCustomFonts({ preCached = false } = {}) {
724
737
  reader.onload = () => resolve(reader.result);
725
738
  reader.readAsDataURL(blob);
726
739
  });
727
- resourceCache.set(url, b64);
728
- processedFontURLs.add(url);
740
+ cache.resource.set(url, b64);
741
+ cache.font.add(url);
729
742
  inlinedSrc = inlinedSrc.replace(match[0], `url(${b64})`);
730
743
  } catch (e) {
731
744
  console.warn("[snapdom] Failed to fetch font URL:", url);
@@ -750,10 +763,10 @@ async function embedCustomFonts({ preCached = false } = {}) {
750
763
  if (isIconFont(font.family)) continue;
751
764
  let b64 = font._snapdomSrc;
752
765
  if (!b64.startsWith("data:")) {
753
- if (resourceCache.has(font._snapdomSrc)) {
754
- b64 = resourceCache.get(font._snapdomSrc);
755
- processedFontURLs.add(font._snapdomSrc);
756
- } else if (!processedFontURLs.has(font._snapdomSrc)) {
766
+ if (cache.resource.has(font._snapdomSrc)) {
767
+ b64 = cache.resource.get(font._snapdomSrc);
768
+ cache.font.add(font._snapdomSrc);
769
+ } else if (!cache.font.has(font._snapdomSrc)) {
757
770
  try {
758
771
  const res = await fetch(font._snapdomSrc);
759
772
  const blob = await res.blob();
@@ -762,8 +775,8 @@ async function embedCustomFonts({ preCached = false } = {}) {
762
775
  reader.onload = () => resolve(reader.result);
763
776
  reader.readAsDataURL(blob);
764
777
  });
765
- resourceCache.set(font._snapdomSrc, b64);
766
- processedFontURLs.add(font._snapdomSrc);
778
+ cache.resource.set(font._snapdomSrc, b64);
779
+ cache.font.add(font._snapdomSrc);
767
780
  } catch (e) {
768
781
  console.warn("[snapdom] Failed to fetch dynamic font src:", font._snapdomSrc);
769
782
  continue;
@@ -780,7 +793,7 @@ async function embedCustomFonts({ preCached = false } = {}) {
780
793
  }
781
794
  }
782
795
  if (finalCSS) {
783
- resourceCache.set("fonts-embed-css", finalCSS);
796
+ cache.resource.set("fonts-embed-css", finalCSS);
784
797
  if (preCached) {
785
798
  const style = document.createElement("style");
786
799
  style.setAttribute("data-snapdom", "embedFonts");
@@ -792,7 +805,7 @@ async function embedCustomFonts({ preCached = false } = {}) {
792
805
  }
793
806
 
794
807
  // src/modules/pseudo.js
795
- async function inlinePseudoElements(source, clone, styleMap, styleCache, compress, embedFonts = false, useProxy) {
808
+ async function inlinePseudoElements(source, clone, compress, embedFonts = false, useProxy) {
796
809
  if (!(source instanceof Element) || !(clone instanceof Element)) return;
797
810
  for (const pseudo of ["::before", "::after", "::first-letter"]) {
798
811
  try {
@@ -816,7 +829,7 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
816
829
  span.dataset.snapdomPseudo = "::first-letter";
817
830
  const snapshot = snapshotComputedStyle(style);
818
831
  const key = getStyleKey(snapshot, "span", compress);
819
- styleMap.set(span, key);
832
+ cache.preStyleMap.set(span, key);
820
833
  const restNode = document.createTextNode(rest);
821
834
  clone.replaceChild(restNode, textNode);
822
835
  clone.insertBefore(span, restNode);
@@ -837,7 +850,7 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
837
850
  pseudoEl.dataset.snapdomPseudo = pseudo;
838
851
  const snapshot = snapshotComputedStyle(style);
839
852
  const key = getStyleKey(snapshot, "span", compress);
840
- styleMap.set(pseudoEl, key);
853
+ cache.preStyleMap.set(pseudoEl, key);
841
854
  const isIconFont2 = isIconFont(fontFamily);
842
855
  const cleanContent = parseContent(content);
843
856
  if (isIconFont2 && cleanContent.length === 1) {
@@ -888,8 +901,6 @@ async function inlinePseudoElements(source, clone, styleMap, styleCache, compres
888
901
  await inlinePseudoElements(
889
902
  sChildren[i],
890
903
  cChildren[i],
891
- styleMap,
892
- styleCache,
893
904
  compress,
894
905
  embedFonts,
895
906
  useProxy
@@ -929,18 +940,15 @@ function inlineExternalDef(root) {
929
940
 
930
941
  // src/core/prepare.js
931
942
  async function prepareClone(element, compress = false, embedFonts = false, options = {}) {
932
- const styleMap = /* @__PURE__ */ new Map();
933
- const styleCache = /* @__PURE__ */ new WeakMap();
934
- const nodeMap = /* @__PURE__ */ new Map();
935
- let clone;
943
+ let clone, classCSS;
936
944
  try {
937
- clone = deepClone(element, styleMap, styleCache, nodeMap, compress, options, element);
945
+ clone = deepClone(element, compress, options, element);
938
946
  } catch (e) {
939
947
  console.warn("deepClone failed:", e);
940
948
  throw e;
941
949
  }
942
950
  try {
943
- await inlinePseudoElements(element, clone, styleMap, styleCache, compress, embedFonts, options.useProxy);
951
+ await inlinePseudoElements(element, clone, compress, embedFonts, options.useProxy);
944
952
  } catch (e) {
945
953
  console.warn("inlinePseudoElements failed:", e);
946
954
  }
@@ -949,11 +957,10 @@ async function prepareClone(element, compress = false, embedFonts = false, optio
949
957
  } catch (e) {
950
958
  console.warn("inlineExternalDef failed:", e);
951
959
  }
952
- let classCSS = "";
953
960
  if (compress) {
954
- const keyToClass = generateCSSClasses(styleMap);
961
+ const keyToClass = generateCSSClasses();
955
962
  classCSS = Array.from(keyToClass.entries()).map(([key, className]) => `.${className}{${key}}`).join("");
956
- for (const [node, key] of styleMap.entries()) {
963
+ for (const [node, key] of cache.preStyleMap.entries()) {
957
964
  if (node.tagName === "STYLE") continue;
958
965
  const className = keyToClass.get(key);
959
966
  if (className) node.classList.add(className);
@@ -962,12 +969,12 @@ async function prepareClone(element, compress = false, embedFonts = false, optio
962
969
  if (bgImage && bgImage !== "none") node.style.backgroundImage = bgImage;
963
970
  }
964
971
  } else {
965
- for (const [node, key] of styleMap.entries()) {
972
+ for (const [node, key] of cache.preStyleMap.entries()) {
966
973
  if (node.tagName === "STYLE") continue;
967
974
  node.setAttribute("style", key.replace(/;/g, "; "));
968
975
  }
969
976
  }
970
- for (const [cloneNode, originalNode] of nodeMap.entries()) {
977
+ for (const [cloneNode, originalNode] of cache.preNodeMap.entries()) {
971
978
  const scrollX = originalNode.scrollLeft;
972
979
  const scrollY = originalNode.scrollTop;
973
980
  const hasScroll = scrollX || scrollY;
@@ -986,9 +993,9 @@ async function prepareClone(element, compress = false, embedFonts = false, optio
986
993
  cloneNode.appendChild(inner);
987
994
  }
988
995
  }
989
- if (element === nodeMap.get(clone)) {
990
- const computed = styleCache.get(element) || window.getComputedStyle(element);
991
- styleCache.set(element, computed);
996
+ if (element === cache.preNodeMap.get(clone)) {
997
+ const computed = cache.preStyle.get(element) || window.getComputedStyle(element);
998
+ cache.preStyle.set(element, computed);
992
999
  const transform = stripTranslate(computed.transform);
993
1000
  clone.style.margin = "0";
994
1001
  clone.style.position = "static";
@@ -1001,13 +1008,13 @@ async function prepareClone(element, compress = false, embedFonts = false, optio
1001
1008
  clone.style.clear = "none";
1002
1009
  clone.style.transform = transform || "";
1003
1010
  }
1004
- for (const [cloneNode, originalNode] of nodeMap.entries()) {
1011
+ for (const [cloneNode, originalNode] of cache.preNodeMap.entries()) {
1005
1012
  if (originalNode.tagName === "PRE") {
1006
1013
  cloneNode.style.marginTop = "0";
1007
1014
  cloneNode.style.marginBlockStart = "0";
1008
1015
  }
1009
1016
  }
1010
- return { clone, classCSS, styleCache };
1017
+ return { clone, classCSS };
1011
1018
  }
1012
1019
 
1013
1020
  // src/modules/images.js
@@ -1034,7 +1041,7 @@ async function inlineImages(clone, options = {}) {
1034
1041
  }
1035
1042
 
1036
1043
  // src/modules/background.js
1037
- async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
1044
+ async function inlineBackgroundImages(source, clone, options = {}) {
1038
1045
  const queue = [[source, clone]];
1039
1046
  const imageProps = [
1040
1047
  "background-image",
@@ -1048,8 +1055,8 @@ async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
1048
1055
  ];
1049
1056
  while (queue.length) {
1050
1057
  const [srcNode, cloneNode] = queue.shift();
1051
- const style = styleCache.get(srcNode) || getStyle(srcNode);
1052
- if (!styleCache.has(srcNode)) styleCache.set(srcNode, style);
1058
+ const style = cache.preStyle.get(srcNode) || getStyle(srcNode);
1059
+ if (!cache.preStyle.has(srcNode)) cache.preStyle.set(srcNode, style);
1053
1060
  for (const prop of imageProps) {
1054
1061
  const val = style.getPropertyValue(prop);
1055
1062
  if (!val || val === "none") continue;
@@ -1076,13 +1083,14 @@ async function inlineBackgroundImages(source, clone, styleCache, options = {}) {
1076
1083
  // src/core/capture.js
1077
1084
  async function captureDOM(element, options = {}) {
1078
1085
  if (!element) throw new Error("Element cannot be null or undefined");
1086
+ cache.reset();
1079
1087
  const { compress = true, embedFonts = false, fast = true, scale = 1, useProxy = "" } = options;
1080
- let clone, classCSS, styleCache;
1088
+ let clone, classCSS;
1081
1089
  let fontsCSS = "";
1082
1090
  let baseCSS = "";
1083
1091
  let dataURL;
1084
1092
  let svgString;
1085
- ({ clone, classCSS, styleCache } = await prepareClone(element, compress, embedFonts, options));
1093
+ ({ clone, classCSS } = await prepareClone(element, compress, embedFonts, options));
1086
1094
  await new Promise((resolve) => {
1087
1095
  idle(async () => {
1088
1096
  await inlineImages(clone, options);
@@ -1091,7 +1099,7 @@ async function captureDOM(element, options = {}) {
1091
1099
  });
1092
1100
  await new Promise((resolve) => {
1093
1101
  idle(async () => {
1094
- await inlineBackgroundImages(element, clone, styleCache, options);
1102
+ await inlineBackgroundImages(element, clone, options);
1095
1103
  resolve();
1096
1104
  }, { fast });
1097
1105
  });
@@ -1106,13 +1114,13 @@ async function captureDOM(element, options = {}) {
1106
1114
  if (compress) {
1107
1115
  const usedTags = collectUsedTagNames(clone).sort();
1108
1116
  const tagKey = usedTags.join(",");
1109
- if (baseCSSCache.has(tagKey)) {
1110
- baseCSS = baseCSSCache.get(tagKey);
1117
+ if (cache.baseStyle.has(tagKey)) {
1118
+ baseCSS = cache.baseStyle.get(tagKey);
1111
1119
  } else {
1112
1120
  await new Promise((resolve) => {
1113
1121
  idle(() => {
1114
1122
  baseCSS = generateDedupedBaseCSS(usedTags);
1115
- baseCSSCache.set(tagKey, baseCSS);
1123
+ cache.baseStyle.set(tagKey, baseCSS);
1116
1124
  resolve();
1117
1125
  }, { fast });
1118
1126
  });
@@ -1321,10 +1329,7 @@ snapdom.download = async (el, options = {}) => {
1321
1329
  async function preCache(root = document, options = {}) {
1322
1330
  const { embedFonts = true, reset = false } = options;
1323
1331
  if (reset) {
1324
- imageCache.clear();
1325
- bgCache.clear();
1326
- resourceCache.clear();
1327
- baseCSSCache.clear();
1332
+ cache.reset();
1328
1333
  return;
1329
1334
  }
1330
1335
  await document.fonts.ready;
@@ -1337,9 +1342,9 @@ async function preCache(root = document, options = {}) {
1337
1342
  const promises = [];
1338
1343
  for (const img of imgEls) {
1339
1344
  const src = img.src;
1340
- if (!imageCache.has(src)) {
1345
+ if (!cache.image.has(src)) {
1341
1346
  promises.push(
1342
- fetchImage(src, { useProxy: options.useProxy }).then((dataURL) => imageCache.set(src, dataURL)).catch(() => {
1347
+ fetchImage(src, { useProxy: options.useProxy }).then((dataURL) => cache.image.set(src, dataURL)).catch(() => {
1343
1348
  })
1344
1349
  );
1345
1350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zumer/snapdom",
3
- "version": "1.9.5",
3
+ "version": "1.9.6-dev.0",
4
4
  "description": "snapDOM captures HTML elements to images with exceptional speed and accuracy.",
5
5
  "main": "dist/snapdom.js",
6
6
  "module": "dist/snapdom.mjs",