@zumer/snapdom 2.0.1 → 2.1.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.
Files changed (45) hide show
  1. package/README.md +156 -73
  2. package/dist/{modules/chunks/chunk-DTQFIIVX.js → plugins.mjs} +2 -2
  3. package/dist/preCache.mjs +10 -0
  4. package/dist/snapdom.js +6 -6
  5. package/dist/snapdom.mjs +6 -6
  6. package/package.json +5 -5
  7. package/dist/modules/chunks/chunk-3JLSSUO4.js +0 -7
  8. package/dist/modules/chunks/chunk-3PHM6WOF.js +0 -7
  9. package/dist/modules/chunks/chunk-3VYIPD3A.js +0 -7
  10. package/dist/modules/chunks/chunk-4E2QQYX5.js +0 -7
  11. package/dist/modules/chunks/chunk-4IERUYP4.js +0 -7
  12. package/dist/modules/chunks/chunk-4Z46XXMY.js +0 -10
  13. package/dist/modules/chunks/chunk-53XQJAU5.js +0 -7
  14. package/dist/modules/chunks/chunk-5ZWTRQ52.js +0 -10
  15. package/dist/modules/chunks/chunk-ANSXOGKI.js +0 -7
  16. package/dist/modules/chunks/chunk-BF74J4A5.js +0 -8
  17. package/dist/modules/chunks/chunk-BUMT6T6O.js +0 -10
  18. package/dist/modules/chunks/chunk-CNTQFGEZ.js +0 -10
  19. package/dist/modules/chunks/chunk-CRBLWEX6.js +0 -10
  20. package/dist/modules/chunks/chunk-EBDTZNMR.js +0 -7
  21. package/dist/modules/chunks/chunk-FQK3JDTN.js +0 -10
  22. package/dist/modules/chunks/chunk-FTKOXG2W.js +0 -7
  23. package/dist/modules/chunks/chunk-G4EP52KJ.js +0 -10
  24. package/dist/modules/chunks/chunk-GZX3IERM.js +0 -8
  25. package/dist/modules/chunks/chunk-N2KKO64J.js +0 -10
  26. package/dist/modules/chunks/chunk-NM4NY5FQ.js +0 -7
  27. package/dist/modules/chunks/chunk-PZIG3IRP.js +0 -10
  28. package/dist/modules/chunks/chunk-Q55H7S7M.js +0 -7
  29. package/dist/modules/chunks/chunk-QBJ6HQLA.js +0 -10
  30. package/dist/modules/chunks/chunk-SSUBCN7X.js +0 -7
  31. package/dist/modules/chunks/chunk-T4JIPPZO.js +0 -7
  32. package/dist/modules/chunks/chunk-X6RBKLFD.js +0 -10
  33. package/dist/modules/chunks/rasterize-JS5G2XHH.js +0 -7
  34. package/dist/modules/chunks/rasterize-WOXTJCMX.js +0 -7
  35. package/dist/modules/exporters/download.js +0 -7
  36. package/dist/modules/exporters/toBlob.js +0 -7
  37. package/dist/modules/exporters/toCanvas.js +0 -7
  38. package/dist/modules/exporters/toImg.js +0 -7
  39. package/dist/modules/exporters/toJpg.js +0 -7
  40. package/dist/modules/exporters/toPng.js +0 -7
  41. package/dist/modules/exporters/toSvg.js +0 -7
  42. package/dist/modules/exporters/toWebp.js +0 -7
  43. package/dist/modules/plugins.js +0 -7
  44. package/dist/modules/preCache.js +0 -7
  45. package/dist/modules/snapdom.js +0 -7
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  <img alt="NPM version" src="https://img.shields.io/npm/v/@zumer/snapdom?style=flat-square&label=Version">
10
10
  </a>
11
11
  <a href="https://www.npmjs.com/package/@zumer/snapdom">
12
- <img alt="NPM version" src="https://img.shields.io/npm/v/@zumer/snapdom/dev?style=flat-square&label=Dev">
12
+ <img alt="NPM weekly downloads" src="https://img.shields.io/npm/dw/@zumer/snapdom?style=flat-square&label=Downloads">
13
13
  </a>
14
14
  <a href="https://github.com/zumerlab/snapdom/graphs/contributors">
15
15
  <img alt="GitHub contributors" src="https://img.shields.io/github/contributors/zumerlab/snapdom?style=flat-square&label=Contributors">
@@ -50,15 +50,76 @@ It converts any DOM subtree into a self-contained representation that can be exp
50
50
  [https://snapdom.dev](https://snapdom.dev)
51
51
 
52
52
 
53
+ ## Quick Start
54
+
55
+ **Capture any DOM element to PNG in one line:**
56
+
57
+ ```js
58
+ import { snapdom } from '@zumer/snapdom';
59
+
60
+ const img = await snapdom.toPng(document.querySelector('#card'));
61
+ document.body.appendChild(img);
62
+ ```
63
+
64
+ **Reusable capture** (one clone, multiple exports):
65
+
66
+ ```js
67
+ const result = await snapdom(document.querySelector('#card'));
68
+ await result.toPng(); // → HTMLImageElement
69
+ await result.toSvg(); // → SVG as Image
70
+ await result.download({ format: 'jpg', filename: 'card.jpg' });
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Capture Flow
76
+
77
+ SnapDOM transforms your DOM element through these stages:
78
+
79
+ ```mermaid
80
+ flowchart LR
81
+ subgraph Input
82
+ A[DOM Element]
83
+ end
84
+
85
+ subgraph Capture
86
+ B[Clone] --> C[Styles & Pseudo]
87
+ C --> D[Images & Backgrounds]
88
+ D --> E[Fonts]
89
+ E --> F[SVG foreignObject]
90
+ end
91
+
92
+ subgraph Output
93
+ F --> G[data:image/svg+xml]
94
+ G --> H[toPng / toSvg / toBlob / download]
95
+ end
96
+
97
+ A --> B
98
+ ```
99
+
100
+ | Stage | What happens |
101
+ |-------|--------------|
102
+ | **Clone** | Deep clone with styles, Shadow DOM, iframes. Exclude/filter nodes. |
103
+ | **Styles & Pseudo** | Inline `::before`/`::after` as elements, resolve `counter()`/`counters()`. |
104
+ | **Images & Backgrounds** | Fetch and inline external images/backgrounds as data URLs. |
105
+ | **Fonts** | Embed `@font-face` (optional) and icon fonts. |
106
+ | **SVG** | Wrap clone in `<foreignObject>`, serialize to `data:image/svg+xml`. |
107
+ | **Export** | Convert SVG to PNG/JPG/WebP/Blob or trigger download. |
108
+
109
+ Plugin hooks: `beforeSnap` → `beforeClone` → `afterClone` → `beforeRender` → `afterRender` → `beforeExport` → `afterExport`.
110
+
111
+
53
112
  ## Table of Contents
54
113
 
114
+ - [Quick Start](#quick-start)
115
+ - [Capture Flow](#capture-flow)
55
116
  - [Installation](#installation)
56
117
  - [NPM / Yarn (stable)](#npm--yarn-stable)
57
118
  - [NPM / Yarn (dev builds)](#npm--yarn-dev-builds)
58
119
  - [CDN (stable)](#cdn-stable)
59
120
  - [CDN (dev builds)](#cdn-dev-builds)
60
- - [Build Outputs & Tree-Shaking](#build-outputs--tree-shaking)
61
- - [Basic usage](#basic-usage)
121
+ - [Build Outputs](#build-outputs--tree-shaking)
122
+ - [Usage](#usage)
62
123
  - [Reusable capture](#reusable-capture)
63
124
  - [One-step shortcuts](#one-step-shortcuts)
64
125
  - [API](#api)
@@ -144,68 +205,59 @@ yarn add @zumer/snapdom@dev
144
205
  </script>
145
206
  ```
146
207
 
147
- ## Build Outputs & Tree-Shaking
148
-
149
- SnapDOM ships multiple build variants, but using it is simple.
208
+ ## Build Outputs
150
209
 
151
- ### npm usage → ESM modular build (tree-shakeable)
152
-
153
- When you import SnapDOM in a project with a bundler:
210
+ | Variant | File | Use case |
211
+ |---------|------|----------|
212
+ | **ESM** (tree-shakeable) | `dist/snapdom.mjs` | Bundlers (Vite, webpack), `import` |
213
+ | **IIFE** (global) | `dist/snapdom.js` | Script tag, legacy `require` |
154
214
 
215
+ **Bundler (npm):**
155
216
  ```js
156
- import { snapdom } from '@zumer/snapdom';
217
+ import { snapdom } from '@zumer/snapdom'; // → dist/snapdom.mjs
157
218
  ```
158
219
 
159
- your environment automatically loads:
160
-
161
- ```sh
162
- dist/modules/snapdom.js
163
- ```
164
-
165
- This is the modular ESM build, enabling:
166
-
167
- - Tree-shaking
168
-
169
- - Code-splitting
170
-
171
- - Lazy loading of exporters (toPng, toJpg, toWebp, etc.)
172
-
173
- You do not need to configure anything; bundlers pick this build automatically.
174
-
175
- ### Script tag usage → Global build
176
-
220
+ **Script tag (CDN):**
177
221
  ```html
178
222
  <script src="https://unpkg.com/@zumer/snapdom/dist/snapdom.js"></script>
179
- <script>
180
- snapdom.toPng(document.body).then(img => {
181
- document.body.appendChild(img);
182
- });
183
- </script>
223
+ <script> snapdom.toPng(document.body).then(img => document.body.appendChild(img)); </script>
224
+ ```
225
+
226
+ **Subpath imports** (lighter bundle if you only need one):
227
+ ```js
228
+ import { preCache } from '@zumer/snapdom/preCache';
229
+ import { plugins } from '@zumer/snapdom/plugins';
184
230
  ```
185
231
 
186
- This loads the monolithic global build and exposes snapdom on window.
187
232
 
233
+ ## Usage
188
234
 
189
- ## Basic usage
235
+ | Pattern | When to use |
236
+ |---------|-------------|
237
+ | **Reusable** `snapdom(el)` | One clone → many exports (PNG + JPG + download). |
238
+ | **Shortcuts** `snapdom.toPng(el)` | Single export, less code. |
190
239
 
191
240
  ### Reusable capture
241
+
242
+ Capture once, export many times (no re-clone):
243
+
192
244
  ```js
193
245
  const el = document.querySelector('#target');
194
246
  const result = await snapdom(el);
195
247
 
196
248
  const img = await result.toPng();
197
249
  document.body.appendChild(img);
198
-
199
- await result.download({ format: 'jpg', filename: 'my-capture' });
250
+ await result.download({ format: 'jpg', filename: 'my-capture.jpg' });
200
251
  ```
201
252
 
202
253
  ### One-step shortcuts
254
+
255
+ Direct export when you need a single format:
256
+
203
257
  ```js
204
- const el = document.querySelector('#target');
205
258
  const png = await snapdom.toPng(el);
206
- document.body.appendChild(png);
207
-
208
259
  const blob = await snapdom.toBlob(el);
260
+ document.body.appendChild(png);
209
261
  ```
210
262
 
211
263
  ## API
@@ -242,9 +294,40 @@ Returns an object with reusable export methods:
242
294
  | `snapdom.toWebp(el, options?)` | Returns a WebP image |
243
295
  | `snapdom.download(el, options?)` | Triggers a download |
244
296
 
245
- ## Options
297
+ ### Exporter-specific options
298
+
299
+ Some exporters accept a small set of **export-only options** in addition to the global capture options.
300
+
301
+ #### `download()`
302
+
303
+ | Option | Type | Default | Description |
304
+ | --- | --- | --- | --- |
305
+ | `filename` | `string` | `snapdom` | Download name. |
306
+ | `format` | `"png" \| "jpeg" \| "jpg" \| "webp" \| "svg"` | `"png"` | Output format for the downloaded file. |
307
+
308
+ **Example:**
309
+
310
+ ```js
311
+ await result.download({
312
+ format: 'jpg',
313
+ quality: 0.92,
314
+ filename: 'my-capture'
315
+ });
316
+ ```
317
+
318
+ #### `toBlob()`
319
+
320
+ | Option | Type | Default | Description |
321
+ | --- | --- | --- | --- |
322
+ | `type` | `"svg" \| "png" \| "jpeg" \| "jpg" \| "webp"` | `"svg"` | Blob type to generate. |
246
323
 
247
- > ✅ **Note:** Style compression is now always on internally. The `compress` option has been removed.
324
+ **Example:**
325
+
326
+ ```js
327
+ const blob = await result.toBlob({ type: 'jpeg', quality: 0.92 });
328
+ ```
329
+
330
+ ## Options
248
331
 
249
332
  All capture methods accept an `options` object:
250
333
 
@@ -263,7 +346,6 @@ All capture methods accept an `options` object:
263
346
  | `backgroundColor` | string | `"#fff"` | Fallback color for JPG/WebP |
264
347
  | `quality` | number | `1` | Quality for JPG/WebP (0 to 1) |
265
348
  | `useProxy` | string | `''` | Proxy base for CORS fallbacks |
266
- | `type` | string | `svg` | Default Blob type (`svg`\|`png`\|`jpg`\|`webp`) |
267
349
  | `exclude` | string[] | - | CSS selectors to exclude |
268
350
  | `excludeMode` | `"hide"`\|`"remove"` | `"hide"` | How `exclude` is applied |
269
351
  | `filter` | function | - | Custom predicate `(el) => boolean` |
@@ -497,17 +579,19 @@ const out = await snapdom(element, {
497
579
 
498
580
  ### Plugin Lifecycle Hooks
499
581
 
500
- | Hook | Purpose |
501
- | ------------------------------ | ------------------------------------------------------------------------------------ |
502
- | `beforeSnap(context)` | Before any clone/style work. Ideal for adjusting global capture options. |
503
- | `beforeClone(context)` | Before DOM cloning. Can modify live DOM (use carefully). |
504
- | `afterClone(context)` | After the element subtree has been cloned. Safe to modify styles in the cloned tree. |
505
- | `beforeRender(context)` | Right before SVG/dataURL serialization. |
506
- | `afterRender(context)` | After serialization (you can inspect `context.svgString` or `context.dataURL`). |
507
- | `beforeExport(context)` | Before each export call (`toPng`, `toSvg`, etc.). |
508
- | `afterExport(context, result)` | After each export call — can transform the returned result. |
509
- | `afterSnap(context)` | Runs **once**, after the **first export** finishes. Perfect for cleanup. |
510
- | `defineExports(context)` | Returns a map of **custom exporters**, e.g. `{ pdf: async (ctx, opts) => Blob }`. |
582
+ Hooks run in capture order (see [Capture Flow](#capture-flow)):
583
+
584
+ | Hook | Stage | Purpose |
585
+ |------|-------|---------|
586
+ | `beforeSnap` | Start | Adjust options before any work. |
587
+ | `beforeClone` | Pre-clone | Before DOM clone (modify live DOM carefully). |
588
+ | `afterClone` | Post-clone | Modify cloned tree safely (e.g. inject overlay). |
589
+ | `beforeRender` | Pre-serialize | Right before SVG → data URL. |
590
+ | `afterRender` | Post-serialize | Inspect `context.svgString` / `context.dataURL`. |
591
+ | `beforeExport` | Per export | Before each `toPng`, `toSvg`, etc. |
592
+ | `afterExport` | Per export | Transform returned result. |
593
+ | `afterSnap` | Once | After first export; cleanup. |
594
+ | `defineExports` | Setup | Add custom exporters (e.g. `toPdf`). |
511
595
 
512
596
  > Returned values from `afterExport` are chained to the next plugin (transform pipeline).
513
597
 
@@ -756,35 +840,30 @@ Feel free to share suggestions or feedback in [GitHub Discussions](https://githu
756
840
 
757
841
  ## Development
758
842
 
759
- To contribute or build snapDOM locally:
843
+ **Source layout:**
844
+ - `src/api/` – Public API (`snapdom`, `preCache`)
845
+ - `src/core/` – Capture pipeline, clone, prepare, plugins
846
+ - `src/modules/` – Images, fonts, pseudo-elements, backgrounds, SVG
847
+ - `src/exporters/` – toPng, toSvg, toBlob, etc.
848
+ - `dist/` – Build output (`snapdom.js`, `snapdom.mjs`, `preCache.mjs`, `plugins.mjs`)
760
849
 
850
+ **Build:**
761
851
  ```sh
762
- # Clone the repository
763
852
  git clone https://github.com/zumerlab/snapdom.git
764
853
  cd snapdom
765
-
766
- # Switch to dev branch
767
854
  git checkout dev
768
-
769
- # Install dependencies
770
855
  npm install
771
-
772
- # Compile the library (ESM, CJS, and minified versions)
773
856
  npm run compile
857
+ ```
774
858
 
775
- # Install playwright browsers (necessary for running tests)
776
- npx playwright install
777
-
778
- # Run tests
859
+ **Test:**
860
+ ```sh
861
+ npx playwright install # Required for browser tests
779
862
  npm test
780
-
781
- # Run Benchmarks
782
863
  npm run test:benchmark
783
864
  ```
784
865
 
785
- The main entry point is in `src/`, and output bundles are generated in the `dist/` folder.
786
-
787
- For detailed contribution guidelines, please see [CONTRIBUTING](https://github.com/zumerlab/snapdom/blob/main/CONTRIBUTING.md).
866
+ For detailed guidelines, see [CONTRIBUTING](https://github.com/zumerlab/snapdom/blob/main/CONTRIBUTING.md).
788
867
 
789
868
 
790
869
  ## Contributors
@@ -794,9 +873,12 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
794
873
  <a href="https://github.com/tinchox5" title="tinchox5"><img src="https://avatars.githubusercontent.com/u/11557901?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="tinchox5"/></a>
795
874
  <a href="https://github.com/Jarvis2018" title="Jarvis2018"><img src="https://avatars.githubusercontent.com/u/36788851?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Jarvis2018"/></a>
796
875
  <a href="https://github.com/tarwin" title="tarwin"><img src="https://avatars.githubusercontent.com/u/646149?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="tarwin"/></a>
876
+ <a href="https://github.com/Amyuan23" title="Amyuan23"><img src="https://avatars.githubusercontent.com/u/25892910?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Amyuan23"/></a>
877
+ <a href="https://github.com/airamhr9" title="airamhr9"><img src="https://avatars.githubusercontent.com/u/57371081?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="airamhr9"/></a>
878
+ <a href="https://github.com/FlavioLimaMindera" title="FlavioLimaMindera"><img src="https://avatars.githubusercontent.com/u/96424442?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="FlavioLimaMindera"/></a>
797
879
  <a href="https://github.com/jswhisperer" title="jswhisperer"><img src="https://avatars.githubusercontent.com/u/1177690?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="jswhisperer"/></a>
798
880
  <a href="https://github.com/K1ender" title="K1ender"><img src="https://avatars.githubusercontent.com/u/146767945?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="K1ender"/></a>
799
- <a href="https://github.com/Amyuan23" title="Amyuan23"><img src="https://avatars.githubusercontent.com/u/25892910?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="Amyuan23"/></a>
881
+ <a href="https://github.com/kohaiy" title="kohaiy"><img src="https://avatars.githubusercontent.com/u/15622127?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="kohaiy"/></a>
800
882
  <a href="https://github.com/17biubiu" title="17biubiu"><img src="https://avatars.githubusercontent.com/u/13295895?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="17biubiu"/></a>
801
883
  <a href="https://github.com/av01d" title="av01d"><img src="https://avatars.githubusercontent.com/u/6247646?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="av01d"/></a>
802
884
  <a href="https://github.com/CHOYSEN" title="CHOYSEN"><img src="https://avatars.githubusercontent.com/u/25995358?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="CHOYSEN"/></a>
@@ -807,13 +889,14 @@ For detailed contribution guidelines, please see [CONTRIBUTING](https://github.c
807
889
  <a href="https://github.com/sharuzzaman" title="sharuzzaman"><img src="https://avatars.githubusercontent.com/u/7421941?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="sharuzzaman"/></a>
808
890
  <a href="https://github.com/simon1uo" title="simon1uo"><img src="https://avatars.githubusercontent.com/u/60037549?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="simon1uo"/></a>
809
891
  <a href="https://github.com/titoBouzout" title="titoBouzout"><img src="https://avatars.githubusercontent.com/u/64156?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="titoBouzout"/></a>
892
+ <a href="https://github.com/ZiuChen" title="ZiuChen"><img src="https://avatars.githubusercontent.com/u/64892985?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="ZiuChen"/></a>
810
893
  <a href="https://github.com/harshasiddartha" title="harshasiddartha"><img src="https://avatars.githubusercontent.com/u/147021873?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="harshasiddartha"/></a>
894
+ <a href="https://github.com/karasHou" title="karasHou"><img src="https://avatars.githubusercontent.com/u/27048083?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="karasHou"/></a>
811
895
  <a href="https://github.com/jhbae200" title="jhbae200"><img src="https://avatars.githubusercontent.com/u/20170610?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="jhbae200"/></a>
812
896
  <a href="https://github.com/xiaobai-web715" title="xiaobai-web715"><img src="https://avatars.githubusercontent.com/u/81091224?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="xiaobai-web715"/></a>
813
897
  <a href="https://github.com/miusuncle" title="miusuncle"><img src="https://avatars.githubusercontent.com/u/7549857?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="miusuncle"/></a>
814
898
  <a href="https://github.com/rbbydotdev" title="rbbydotdev"><img src="https://avatars.githubusercontent.com/u/101137670?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="rbbydotdev"/></a>
815
899
  <a href="https://github.com/zhanghaotian2018" title="zhanghaotian2018"><img src="https://avatars.githubusercontent.com/u/169218899?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="zhanghaotian2018"/></a>
816
- <a href="https://github.com/kohaiy" title="kohaiy"><img src="https://avatars.githubusercontent.com/u/15622127?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="kohaiy"/></a>
817
900
  <a href="https://github.com/fu050409" title="fu050409"><img src="https://avatars.githubusercontent.com/u/46275354?v=4&s=100" style="border-radius:10px; width:60px; height:60px; object-fit:cover; margin:5px;" alt="fu050409"/></a>
818
901
  </p>
819
902
  <!-- CONTRIBUTORS:END -->
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * SnapDOM
3
- * v2.0.1
3
+ * v2.1.0
4
4
  * Author: Juan Martin Muda
5
5
  * License: MIT
6
6
  */
7
- var f=[];function c(n){if(!n)return null;if(Array.isArray(n)){let[t,o]=n;return typeof t=="function"?t(o):t}if(typeof n=="object"&&"plugin"in n){let{plugin:t,options:o}=n;return typeof t=="function"?t(o):t}return typeof n=="function"?n():n}function p(...n){let t=n.flat();for(let o of t){let i=c(o);i&&(f.some(r=>r&&r.name&&i.name&&r.name===i.name)||f.push(i))}}function l(n){return(n&&Array.isArray(n.plugins)?n.plugins:f)||f}async function g(n,t,o){let i=o,r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,i);typeof s<"u"&&(i=s)}return i}async function y(n,t,o){let i=[],r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,o);typeof s<"u"&&i.push(s)}return i}function m(){return f.slice()}function d(){f.length=0}function a(n){let t=[];if(Array.isArray(n))for(let o of n){let i=c(o);if(!i||!i.name)continue;let r=t.findIndex(u=>u&&u.name===i.name);r>=0&&t.splice(r,1),t.push(i)}for(let o of f)o&&o.name&&!t.some(i=>i.name===o.name)&&t.push(o);return Object.freeze(t)}function A(n,t,o=!1){return!n||n.plugins&&!o||(n.plugins=a(t)),n}function P(){return f.slice()}export{c as a,p as b,g as c,y as d,m as e,d as f,a as g,A as h,P as i};
7
+ var f=[];function c(n){if(!n)return null;if(Array.isArray(n)){let[t,o]=n;return typeof t=="function"?t(o):t}if(typeof n=="object"&&"plugin"in n){let{plugin:t,options:o}=n;return typeof t=="function"?t(o):t}return typeof n=="function"?n():n}function p(...n){let t=n.flat();for(let o of t){let i=c(o);i&&(f.some(r=>r&&r.name&&i.name&&r.name===i.name)||f.push(i))}}function l(n){return(n&&Array.isArray(n.plugins)?n.plugins:f)||f}async function g(n,t,o){let i=o,r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,i);typeof s<"u"&&(i=s)}return i}async function y(n,t,o){let i=[],r=l(t);for(let u of r){let e=u&&typeof u[n]=="function"?u[n]:null;if(!e)continue;let s=await e(t,o);typeof s<"u"&&i.push(s)}return i}function m(){return f.slice()}function d(){f.length=0}function a(n){let t=[];if(Array.isArray(n))for(let o of n){let i=c(o);if(!i||!i.name)continue;let r=t.findIndex(u=>u&&u.name===i.name);r>=0&&t.splice(r,1),t.push(i)}for(let o of f)o&&o.name&&!t.some(i=>i.name===o.name)&&t.push(o);return Object.freeze(t)}function A(n,t,o=!1){return!n||n.plugins&&!o||(n.plugins=a(t)),n}function P(){return f.slice()}export{A as attachSessionPlugins,d as clearPlugins,P as getGlobalPlugins,a as mergePlugins,c as normalizePlugin,m as pluginsList,p as registerPlugins,y as runAll,g as runHook};
@@ -0,0 +1,10 @@
1
+ /*
2
+ * SnapDOM
3
+ * v2.1.0
4
+ * Author: Juan Martin Muda
5
+ * License: MIT
6
+ */
7
+ var f={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 X(t="soft"){switch(f.session.__counterEpoch=(f.session.__counterEpoch||0)+1,t){case"auto":{f.session.styleMap=new Map,f.session.nodeMap=new Map;return}case"soft":{f.session.styleMap=new Map,f.session.nodeMap=new Map,f.session.styleCache=new WeakMap;return}case"full":return;case"disabled":{f.session.styleMap=new Map,f.session.nodeMap=new Map,f.session.styleCache=new WeakMap,f.computedStyle=new WeakMap,f.baseStyle=new Map,f.defaultStyle=new Map,f.image=new Map,f.background=new Map,f.resource=new Map,f.font=new Set;return}default:{f.session.styleMap=new Map,f.session.nodeMap=new Map,f.session.styleCache=new WeakMap;return}}}function N(t){let e=t.match(/url\((['"]?)(.*?)(\1)\)/);if(!e)return null;let n=e[2].trim();return n.startsWith("#")?null:n}function O(t){if(/%[0-9A-Fa-f]{2}/.test(t))return t;try{return encodeURI(t)}catch{return t}}function dt(t="[snapDOM]",{ttlMs:e=5*6e4,maxEntries:n=12}={}){let r=new Map,o=0;function i(s,u,c){if(o>=n)return;let m=Date.now();(r.get(u)||0)>m||(r.set(u,m+e),o++,s==="warn"&&console&&console.warn?console.warn(`${t} ${c}`):console&&console.error&&console.error(`${t} ${c}`))}return{warnOnce(s,u){i("warn",s,u)},errorOnce(s,u){i("error",s,u)},reset(){r.clear(),o=0}}}var Y=dt("[snapDOM]",{ttlMs:3*6e4,maxEntries:10}),j=new Map,W=new Map;function pt(t){return/^data:|^blob:|^about:blank$/i.test(t)}function ht(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),i=new URL(t,n);if(i.origin===o.origin)return!0;let s=i.searchParams;if(s&&(s.has("url")||s.has("target")))return!0}catch{}return!1}function gt(t,e){if(!e||pt(t)||ht(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 yt(t,e){if(!e)return t;if(e.includes("{url}"))return e.replace("{urlRaw}",O(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}${O(t)}`;let n=e.includes("?")?"&":"?";return`${e}${n}url=${encodeURIComponent(t)}`}function J(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 wt(t,e){return[e.as||"blob",e.timeout??3e3,e.useProxy||"",e.errorTTL??8e3,t].join("|")}async function R(t,e={}){let n=e.as??"blob",r=e.timeout??3e3,o=e.useProxy||"",i=e.errorTTL??8e3,s=e.headers||{},u=!!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[,l="",d=""]=String(t).match(/^data:([^,]*),(.*)$/)||[],h=/;base64/i.test(l)?atob(d):decodeURIComponent(d),S=new Uint8Array([...h].map(A=>A.charCodeAt(0))),k=new Blob([S],{type:(l||"").split(";")[0]||""});return{ok:!0,data:k,status:200,url:t,fromCache:!1,mime:k.type||""}}catch{return{ok:!1,data:null,status:0,url:t,fromCache:!1,reason:"special_url_error"}}if(/^blob:/i.test(t))try{let l=await fetch(t);if(!l.ok)return{ok:!1,data:null,status:l.status,url:t,fromCache:!1,reason:"http_error"};let d=await l.blob(),y=d.type||l.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await J(d),status:l.status,url:t,fromCache:!1,mime:y}:n==="text"?{ok:!0,data:await d.text(),status:l.status,url:t,fromCache:!1,mime:y}:{ok:!0,data:d,status:l.status,url:t,fromCache:!1,mime:y}}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 c=wt(t,{as:n,timeout:r,useProxy:o,errorTTL:i}),m=W.get(c);if(m&&m.until>Date.now())return{...m.result,fromCache:!0};m&&W.delete(c);let p=j.get(c);if(p)return p;let g=gt(t,o)?yt(t,o):t,w=e.credentials;if(!w)try{let l=typeof location<"u"&&location.href?location.href:"http://localhost/",d=new URL(t,l);w=typeof location<"u"&&d.origin===location.origin?"include":"omit"}catch{w="omit"}let b=new AbortController,C=setTimeout(()=>b.abort("timeout"),r),a=(async()=>{try{let l=await fetch(g,{signal:b.signal,credentials:w,headers:s});if(!l.ok){let h={ok:!1,data:null,status:l.status,url:g,fromCache:!1,reason:"http_error"};if(i>0&&W.set(c,{until:Date.now()+i,result:h}),!u){let S=`${l.status} ${l.statusText||""}`.trim();Y.warnOnce(`http:${l.status}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,`HTTP error ${S} while fetching ${n} ${t}`)}return e.onError&&e.onError(h),h}if(n==="text")return{ok:!0,data:await l.text(),status:l.status,url:g,fromCache:!1};let d=await l.blob(),y=d.type||l.headers.get("content-type")||"";return n==="dataURL"?{ok:!0,data:await J(d),status:l.status,url:g,fromCache:!1,mime:y}:{ok:!0,data:d,status:l.status,url:g,fromCache:!1,mime:y}}catch(l){let d=l&&typeof l=="object"&&"name"in l&&l.name==="AbortError"?String(l.message||"").includes("timeout")?"timeout":"abort":"network",y={ok:!1,data:null,status:0,url:g,fromCache:!1,reason:d};if(!/^blob:/i.test(t)&&i>0&&W.set(c,{until:Date.now()+i,result:y}),!u){let h=`${d}:${n}:${new URL(t,location?.href??"http://localhost/").origin}`,S=d==="timeout"?`Timeout after ${r}ms. Consider increasing timeout or using a proxy for ${t}`:d==="abort"?`Request aborted while fetching ${n} ${t}`:`Network/CORS issue while fetching ${n} ${t}. A proxy may be required`;Y.errorOnce(h,S)}return e.onError&&e.onError(y),y}finally{clearTimeout(C),j.delete(c)}})();return j.set(c,a),a}async function T(t,e={}){if(/^((repeating-)?(linear|radial|conic)-gradient)\(/i.test(t)||t.trim()==="none")return t;let r=N(t);if(!r)return t;let o=O(r);if(f.background.has(o)){let i=f.background.get(o);return i?`url("${i}")`:"none"}try{let i=await R(o,{as:"dataURL",useProxy:e.useProxy});return i.ok?(f.background.set(o,i.data),`url("${i.data}")`):(f.background.set(o,null),"none")}catch{return f.background.set(o,null),"none"}}var Z=new Set(["meta","script","noscript","title","link","template"]),z=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"]),St=["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 G(){for(let t of St){let e=String(t).toLowerCase();Z.has(e)||z.has(e)||tt(e)}}function tt(t){if(t=String(t).toLowerCase(),z.has(t)){let i={};return f.defaultStyle.set(t,i),i}if(f.defaultStyle.has(t))return f.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 i of r){if(xt(i))continue;let s=r.getPropertyValue(i);o[i]=s}return e.removeChild(n),f.defaultStyle.set(t,o),o}var bt=/(?:^|-)(animation|transition)(?:-|$)/i,Ct=/^(--|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,kt=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 xt(t){let e=String(t).toLowerCase();return!!(kt.has(e)||Ct.test(e)||bt.test(e))}function P(t,e=null){if(!(t instanceof Element))return window.getComputedStyle(t,e);let n=f.computedStyle.get(t);if(n||(n=new Map,f.computedStyle.set(t,n)),!n.has(e)){let r=window.getComputedStyle(t,e);n.set(e,r)}return n.get(e)}function K(t){let e=[],n=0,r=0;for(let o=0;o<t.length;o++){let i=t[o];i==="("&&n++,i===")"&&n--,i===","&&n===0&&(e.push(t.slice(r,o).trim()),r=o+1)}return e.push(t.slice(r).trim()),e}function v(){if(typeof navigator>"u")return!1;let t=navigator.userAgent||"",e=t.toLowerCase(),n=e.includes("safari")&&!e.includes("chrome")&&!e.includes("crios")&&!e.includes("fxios")&&!e.includes("android"),r=/applewebkit/i.test(t),o=/mobile/i.test(t),i=!/safari/i.test(t),s=r&&o&&i,u=/(micromessenger|wxwork|wecom|windowswechat|macwechat)/i.test(t),c=/(baiduboxapp|baidubrowser|baidusearch|baiduboxlite)/i.test(e),m=/ipad|iphone|ipod/.test(e)&&r;return n||s||u||c||m}var At=[/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],ie=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<"u"&&window.__SNAPDOM_ICON_FONTS__||{}),$t=[];function M(t){let e=typeof t=="string"?t:"",n=[...At,...$t];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))}var Rt=new Set(["serif","sans-serif","monospace","cursive","fantasy","system-ui","emoji","math","fangsong","ui-serif","ui-sans-serif","ui-monospace","ui-rounded"]),Mt=["katex","mathjax","mathml"];function V(t){if(!t)return"";for(let e of t.split(",")){let n=e.trim().replace(/^['"]+|['"]+$/g,"");if(n&&!Rt.has(n.toLowerCase()))return n}return""}function B(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 D(t){let e=String(t??"normal").trim().toLowerCase();return e.startsWith("italic")?"italic":e.startsWith("oblique")?"oblique":"normal"}function Lt(t){let e=String(t??"100%").match(/(\d+(?:\.\d+)?)\s*%/);return e?Math.max(50,Math.min(200,parseFloat(e[1]))):100}function Ft(t){let e=String(t||"400").trim(),n=e.match(/^(\d{2,3})\s+(\d{2,3})$/);if(n){let o=B(n[1]),i=B(n[2]);return{min:Math.min(o,i),max:Math.max(o,i)}}let r=B(e);return{min:r,max:r}}function Et(t){let e=String(t||"normal").trim().toLowerCase();return e==="italic"?{kind:"italic"}:e.startsWith("oblique")?{kind:"oblique"}:{kind:"normal"}}function Ut(t){let e=String(t||"100%").trim(),n=e.match(/(\d+(?:\.\d+)?)\s*%\s+(\d+(?:\.\d+)?)\s*%/);if(n){let i=parseFloat(n[1]),s=parseFloat(n[2]);return{min:Math.min(i,s),max:Math.max(i,s)}}let r=e.match(/(\d+(?:\.\d+)?)\s*%/),o=r?parseFloat(r[1]):100;return{min:o,max:o}}function _t(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(u=>o.endsWith(u)))return!0;let s=(n.pathname+n.search).toLowerCase();if(/\bfont(s)?\b/.test(s)||/\.woff2?(\b|$)/.test(s)||Mt.some(u=>s.includes(u)))return!0;for(let u of e){let c=u.toLowerCase().replace(/\s+/g,"+"),m=u.toLowerCase().replace(/\s+/g,"-");if(s.includes(c)||s.includes(m))return!0}return!1}catch{return!1}}function It(t){let e=new Set;for(let n of t||[]){let r=String(n).split("__")[0]?.trim();r&&e.add(r)}return e}function et(t,e){return t&&t.replace(/url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,(n,r,o)=>{let i=(o||"").trim();if(!i||/^data:|^blob:|^https?:|^file:|^about:/i.test(i))return n;let s=i;try{s=new URL(i,e||location.href).href}catch{}return`url("${s}")`})}var H=/@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g,q=4;async function Ot(t,e,n){if(!t)return t;let r=new Set;function o(u,c){try{return new URL(u,c||location.href).href}catch{return u}}async function i(u,c,m=0){if(m>q)return console.warn(`[snapDOM] @import depth exceeded (${q}) at ${c}`),u;let p="",g=0,w;for(;w=H.exec(u);){p+=u.slice(g,w.index),g=H.lastIndex;let b=(w[2]||w[4]||"").trim(),C=o(b,c);if(r.has(C)){console.warn(`[snapDOM] Skipping circular @import: ${C}`);continue}r.add(C);let a="";try{let l=await R(C,{as:"text",useProxy:n,silent:!0});l.ok&&typeof l.data=="string"&&(a=l.data)}catch{}a?(a=et(a,C),a=await i(a,C,m+1),p+=`
8
+ /* inlined: ${C} */
9
+ ${a}
10
+ `):p+=w[0]}return p+=u.slice(g),p}let s=et(t,e||location.href);return s=await i(s,e||location.href,0),s}var ot=/url\((["']?)([^"')]+)\1\)/g,Tt=/@font-face[^{}]*\{[^}]*\}/g;function rt(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 i=o[1],s=o[2],u=c=>{if(!c.includes("?"))return parseInt(c,16);let m=parseInt(c.replace(/\?/g,"0"),16),p=parseInt(c.replace(/\?/g,"F"),16);return[m,p]};if(s){let c=u(i),m=u(s),p=Array.isArray(c)?c[0]:c,g=Array.isArray(m)?m[1]:m;e.push([Math.min(p,g),Math.max(p,g)])}else{let c=u(i);Array.isArray(c)?e.push([c[0],c[1]]):e.push([c,c])}}return e}function st(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 Q(t,e){let n=[];if(!t)return n;for(let r of t.matchAll(ot)){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 at(t,e,n=""){let r=t;for(let o of t.matchAll(ot)){let i=N(o[0]);if(!i)continue;let s=i;if(!s.startsWith("http")&&!s.startsWith("data:"))try{s=new URL(s,e||location.href).href}catch{}if(!M(s)){if(f.resource?.has(s)){f.font?.add(s),r=r.replace(o[0],`url(${f.resource.get(s)})`);continue}if(!f.font?.has(s))try{let u=await R(s,{as:"dataURL",useProxy:n,silent:!0});if(u.ok&&typeof u.data=="string"){let c=u.data;f.resource?.set(s,c),f.font?.add(s),r=r.replace(o[0],`url(${c})`)}}catch{console.warn("[snapDOM] Failed to fetch font resource:",s)}}}return r}function Pt(t){if(!t.length)return null;let e=(u,c)=>t.some(([m,p])=>!(p<u||m>c)),n=e(0,255)||e(305,305),r=e(256,591)||e(7680,7935),o=e(880,1023),i=e(1024,1279);return e(7840,7929)||e(258,259)||e(416,417)||e(431,432)?"vietnamese":i?"cyrillic":o?"greek":r?"latin-ext":n?"latin":null}function nt(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,i)=>{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=Pt(i);if(s&&r.has(s))return!0}return!1}}function vt(t){if(!t)return t;let e=/@font-face[^{}]*\{[^}]*\}/gi,n=new Set,r=[];for(let i of t.match(e)||[]){let s=i.match(/font-family:\s*([^;]+);/i)?.[1]||"",u=V(s),c=(i.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),m=(i.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),p=(i.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),g=(i.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),w=(i.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1]||"").trim(),b=Q(w,location.href),C=b.length?b.map(l=>String(l).toLowerCase()).sort().join("|"):w.toLowerCase(),a=[String(u||"").toLowerCase(),c,m,p,g.toLowerCase(),C].join("|");n.has(a)||(n.add(a),r.push(i))}if(r.length===0)return t;let o=0;return t.replace(e,()=>r[o++]||"")}function Nt(t,e,n,r){let o=Array.from(t||[]).sort().join("|"),i=e?JSON.stringify({families:(e.families||[]).map(c=>String(c).toLowerCase()).sort(),domains:(e.domains||[]).map(c=>String(c).toLowerCase()).sort(),subsets:(e.subsets||[]).map(c=>String(c).toLowerCase()).sort()}):"",s=(n||[]).map(c=>`${(c.family||"").toLowerCase()}::${c.weight||"normal"}::${c.style||"normal"}::${c.src||""}`).sort().join("|");return`fonts-embed-css::req=${o}::ex=${i}::lf=${s}::px=${r||""}`}async function it(t,e,n,r){let o;try{o=t.cssRules||[]}catch{return}let i=(s,u)=>{try{return new URL(s,u||location.href).href}catch{return s}};for(let s of o){if(s.type===CSSRule.IMPORT_RULE&&s.styleSheet){let u=s.href?i(s.href,e):e;if(r.depth>=q){console.warn(`[snapDOM] CSSOM import depth exceeded (${q}) at ${u}`);continue}if(u&&r.visitedSheets.has(u)){console.warn(`[snapDOM] Skipping circular CSSOM import: ${u}`);continue}u&&r.visitedSheets.add(u);let c={...r,depth:(r.depth||0)+1};await it(s.styleSheet,u,n,c);continue}if(s.type===CSSRule.FONT_FACE_RULE){let u=(s.style.getPropertyValue("font-family")||"").trim(),c=V(u);if(!c||M(c))continue;let m=(s.style.getPropertyValue("font-weight")||"400").trim(),p=(s.style.getPropertyValue("font-style")||"normal").trim(),g=(s.style.getPropertyValue("font-stretch")||"100%").trim(),w=(s.style.getPropertyValue("src")||"").trim(),b=(s.style.getPropertyValue("unicode-range")||"").trim();if(!r.faceMatchesRequired(c,p,m,g))continue;let C=rt(b);if(!st(r.usedCodepoints,C))continue;let a={family:c,weightSpec:m,styleSpec:p,stretchSpec:g,unicodeRange:b,srcRaw:w,srcUrls:Q(w,e||location.href),href:e||location.href};if(r.simpleExcluder&&r.simpleExcluder(a,C))continue;if(/url\(/i.test(w)){let l=await at(w,e||location.href,r.useProxy);await n(`@font-face{font-family:${c};src:${l};font-style:${p};font-weight:${m};font-stretch:${g};${b?`unicode-range:${b};`:""}}`)}else await n(`@font-face{font-family:${c};src:${w};font-style:${p};font-weight:${m};font-stretch:${g};${b?`unicode-range:${b};`:""}}`)}}}async function ct({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 i=new Map;for(let a of t){let[l,d,y,h]=String(a).split("__");if(!l)continue;let S=i.get(l)||[];S.push({w:parseInt(d,10),s:y,st:parseInt(h,10)}),i.set(l,S)}function s(a,l,d,y){if(!i.has(a))return!1;let h=i.get(a),S=Ft(d),k=Et(l),A=Ut(y),F=S.min!==S.max,E=S.min,I=x=>k.kind==="normal"&&x==="normal"||k.kind!=="normal"&&(x==="italic"||x==="oblique"),U=!1;for(let x of h){let $=F?x.w>=S.min&&x.w<=S.max:x.w===E,L=I(D(x.s)),_=x.st>=A.min&&x.st<=A.max;if($&&L&&_){U=!0;break}}if(U)return!0;if(!F)for(let x of h){let $=I(D(x.s)),L=x.st>=A.min&&x.st<=A.max;if(Math.abs(E-x.w)<=300&&$&&L)return!0}if(!F&&k.kind==="normal"&&h.some($=>D($.s)!=="normal"))for(let $ of h){let L=Math.abs(E-$.w)<=300,_=$.st>=A.min&&$.st<=A.max;if(L&&_)return!0}return!1}let u=nt(n),c=Nt(t,n,r,o);if(f.resource?.has(c))return f.resource.get(c);let m=It(t),p=[],g=H;for(let a of document.querySelectorAll("style")){let l=a.textContent||"";for(let d of l.matchAll(g)){let y=(d[2]||d[4]||"").trim();if(!y||M(y))continue;!!document.querySelector(`link[rel="stylesheet"][href="${y}"]`)||p.push(y)}}p.length&&await Promise.all(p.map(a=>new Promise(l=>{if(document.querySelector(`link[rel="stylesheet"][href="${a}"]`))return l(null);let d=document.createElement("link");d.rel="stylesheet",d.href=a,d.setAttribute("data-snapdom","injected-import"),d.onload=()=>l(d),d.onerror=()=>l(null),document.head.appendChild(d)})));let w="",b=Array.from(document.querySelectorAll('link[rel="stylesheet"]')).filter(a=>!!a.href);for(let a of b)try{if(M(a.href))continue;let l="",d=!1;try{d=new URL(a.href,location.href).origin===location.origin}catch{}if(!d&&!_t(a.href,m))continue;if(d){let h=Array.from(document.styleSheets).find(S=>S.href===a.href);if(h)try{let S=h.cssRules||[];l=Array.from(S).map(k=>k.cssText).join("")}catch{}}if(!l){let h=await R(a.href,{as:"text",useProxy:o});if(h?.ok&&typeof h.data=="string"&&(l=h.data),M(a.href))continue}l=await Ot(l,a.href,o);let y="";for(let h of l.match(Tt)||[]){let S=(h.match(/font-family:\s*([^;]+);/i)?.[1]||"").trim(),k=V(S);if(!k||M(k))continue;let A=(h.match(/font-weight:\s*([^;]+);/i)?.[1]||"400").trim(),F=(h.match(/font-style:\s*([^;]+);/i)?.[1]||"normal").trim(),E=(h.match(/font-stretch:\s*([^;]+);/i)?.[1]||"100%").trim(),I=(h.match(/unicode-range:\s*([^;]+);/i)?.[1]||"").trim(),U=(h.match(/src\s*:\s*([^;}]+)[;}]/i)?.[1]||"").trim(),x=Q(U,a.href);if(!s(k,F,A,E))continue;let $=rt(I);if(!st(e,$))continue;let L={family:k,weightSpec:A,styleSpec:F,stretchSpec:E,unicodeRange:I,srcRaw:U,srcUrls:x,href:a.href};if(n&&u(L,$))continue;let _=/url\(/i.test(U)?await at(h,a.href,o):h;y+=_}y.trim()&&(w+=y)}catch{console.warn("[snapDOM] Failed to process stylesheet:",a.href)}let C={requiredIndex:i,usedCodepoints:e,faceMatchesRequired:s,simpleExcluder:n?nt(n):null,useProxy:o,visitedSheets:new Set,depth:0};for(let a of document.styleSheets)if(!(a.href&&b.some(l=>l.href===a.href)))try{let l=a.href||location.origin+"/";l&&C.visitedSheets.add(l),await it(a,l,async d=>{w+=d},C)}catch{}try{for(let a of document.fonts||[]){if(!a||!a.family||a.status!=="loaded"||!a._snapdomSrc)continue;let l=String(a.family).replace(/^['"]+|['"]+$/g,"");if(M(l)||!i.has(l)||n?.families&&n.families.some(y=>String(y).toLowerCase()===l.toLowerCase()))continue;let d=a._snapdomSrc;if(!String(d).startsWith("data:")){if(f.resource?.has(a._snapdomSrc))d=f.resource.get(a._snapdomSrc),f.font?.add(a._snapdomSrc);else if(!f.font?.has(a._snapdomSrc))try{let y=await R(a._snapdomSrc,{as:"dataURL",useProxy:o,silent:!0});if(y.ok&&typeof y.data=="string")d=y.data,f.resource?.set(a._snapdomSrc,d),f.font?.add(a._snapdomSrc);else continue}catch{console.warn("[snapDOM] Failed to fetch dynamic font src:",a._snapdomSrc);continue}}w+=`@font-face{font-family:'${l}';src:url(${d});font-style:${a.style||"normal"};font-weight:${a.weight||"normal"};}`}}catch{}for(let a of r){if(!a||typeof a!="object")continue;let l=String(a.family||"").replace(/^['"]+|['"]+$/g,"");if(!l||M(l)||!i.has(l)||n?.families&&n.families.some(A=>String(A).toLowerCase()===l.toLowerCase()))continue;let d=a.weight!=null?String(a.weight):"normal",y=a.style!=null?String(a.style):"normal",h=a.stretchPct!=null?`${a.stretchPct}%`:"100%",S=String(a.src||""),k=S;if(!k.startsWith("data:")){if(f.resource?.has(S))k=f.resource.get(S),f.font?.add(S);else if(!f.font?.has(S))try{let A=await R(S,{as:"dataURL",useProxy:o,silent:!0});if(A.ok&&typeof A.data=="string")k=A.data,f.resource?.set(S,k),f.font?.add(S);else continue}catch{console.warn("[snapDOM] Failed to fetch localFonts src:",S);continue}}w+=`@font-face{font-family:'${l}';src:url(${k});font-style:${y};font-weight:${d};font-stretch:${h};}`}return w&&(w=vt(w),f.resource?.set(c,w)),w}function lt(t){let e=new Set;if(!t)return e;let n=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT,null),r=s=>{let u=V(s.fontFamily);if(!u)return;let c=(m,p,g)=>`${u}__${B(m)}__${D(p)}__${Lt(g)}`;e.add(c(s.fontWeight,s.fontStyle,s.fontStretch))};r(getComputedStyle(t));let o=getComputedStyle(t,"::before");o&&o.content&&o.content!=="none"&&r(o);let i=getComputedStyle(t,"::after");for(i&&i.content&&i.content!=="none"&&r(i);n.nextNode();){let s=n.currentNode,u=getComputedStyle(s);r(u);let c=getComputedStyle(s,"::before");c&&c.content&&c.content!=="none"&&r(c);let m=getComputedStyle(s,"::after");m&&m.content&&m.content!=="none"&&r(m)}return e}function ft(t){let e=new Set,n=o=>{if(o)for(let i of o)e.add(i.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 i=o;for(let s of["::before","::after"]){let c=getComputedStyle(i,s)?.getPropertyValue("content");if(!(!c||c==="none"))if(/^"/.test(c)||/^'/.test(c))n(c.slice(1,-1));else{let m=c.match(/\\[0-9A-Fa-f]{1,6}/g);if(m)for(let p of m)try{e.add(parseInt(p.slice(1),16))}catch{}}}}}return e}async function ut(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 i of n){let s=document.createElement("span");s.textContent="AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E",s.style.fontFamily=`"${i}"`,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;o<Math.max(1,e);o++)r(),await new Promise(i=>requestAnimationFrame(()=>requestAnimationFrame(i)))}async function mt(t,e,n,r={}){let o=[[t,e]],i=["background-image","mask","mask-image","-webkit-mask","-webkit-mask-image","mask-source","mask-box-image-source","mask-border-source","-webkit-mask-box-image-source","border-image","border-image-source"],s=["mask-position","mask-size","mask-repeat","-webkit-mask-position","-webkit-mask-size","-webkit-mask-repeat","mask-origin","mask-clip","-webkit-mask-origin","-webkit-mask-clip","-webkit-mask-position-x","-webkit-mask-position-y"],u=["background-position","background-position-x","background-position-y","background-size","background-repeat","background-origin","background-clip","background-attachment","background-blend-mode"],c=["border-image-slice","border-image-width","border-image-outset","border-image-repeat"];for(;o.length;){let[m,p]=o.shift();if(!p)continue;let g=n.get(m)||P(m);n.has(m)||n.set(m,g);let w=(()=>{let a=g.getPropertyValue("border-image"),l=g.getPropertyValue("border-image-source");return a&&a!=="none"||l&&l!=="none"})();for(let a of u){let l=g.getPropertyValue(a);l&&p.style.setProperty(a,l)}for(let a of i){let l=g.getPropertyValue(a);if(!l||l==="none")continue;let d=K(l),y=await Promise.all(d.map(h=>T(h,r)));y.some(h=>h&&h!=="none"&&!/^url\(undefined/.test(h))&&p.style.setProperty(a,y.join(", "))}for(let a of s){let l=g.getPropertyValue(a);!l||l==="initial"||p.style.setProperty(a,l)}if(w)for(let a of c){let l=g.getPropertyValue(a);!l||l==="initial"||p.style.setProperty(a,l)}let b=m.shadowRoot?Array.from(m.shadowRoot.children).filter(a=>a.tagName!=="STYLE"):Array.from(m.children),C=Array.from(p.children).filter(a=>!(a.dataset?.snapdomPseudo||a.tagName==="STYLE"&&a.dataset?.sd));for(let a=0;a<Math.min(b.length,C.length);a++)o.push([b[a],C[a]])}}async function Ce(t=document,e={}){let{embedFonts:n=!0,useProxy:r=""}=e,o=e.cache??e.cacheOpt??"full";X(o);try{await document.fonts?.ready}catch{}try{G()}catch{}f.session=f.session||{},f.session.styleCache||(f.session.styleCache=new WeakMap),f.image=f.image||new Map,f.background=f.background||new Map;try{await mt(t,void 0,f.session.styleCache,{useProxy:r})}catch{}let i=[],s=[];try{if(t&&t.nodeType===1){let c=t.querySelectorAll?Array.from(t.querySelectorAll("*")):[];s=[t,...c],i=[],t.tagName==="IMG"&&t.getAttribute("src")&&i.push(t),i.push(...Array.from(t.querySelectorAll?.("img[src]")||[]))}else t?.querySelectorAll&&(i=Array.from(t.querySelectorAll("img[src]")),s=Array.from(t.querySelectorAll("*")))}catch{}let u=[];for(let c of i){let m=c?.currentSrc||c?.src;if(m&&!f.image.has(m)){let p=Promise.resolve().then(async()=>{let g=await R(m,{as:"dataURL",useProxy:r});g?.ok&&typeof g.data=="string"&&f.image.set(m,g.data)}).catch(()=>{});u.push(p)}}for(let c of s){let m="";try{m=c?.style?.backgroundImage||"",(!m||m==="none")&&(m=P(c).backgroundImage)}catch{}if(m&&m!=="none"){let p=m.match(/url\((?:[^()"']+|"(?:[^"]*)"|'(?:[^']*)')\)/gi)||[];for(let g of p){let w=Promise.resolve().then(()=>T(g,{...e,useProxy:r})).catch(()=>{});u.push(w)}}}if(n)try{let c=lt(t),m=ft(t);if(typeof v=="function"?v():!!v){let g=new Set(Array.from(c).map(w=>String(w).split("__")[0]).filter(Boolean));await ut(g,3)}await ct({required:c,usedCodepoints:m,exclude:e.excludeFonts,localFonts:e.localFonts,useProxy:e.useProxy??r})}catch{}await Promise.allSettled(u)}export{Ce as preCache};