concept-collection / numbl-figure-viewer
numbl figure viewer: upload a numbl .h5 figure and render it via numbl/graphics
Jeremy Magland <jmagland@flatironinstitute.org> committed commit a9daa5b15414 Browse files
15 changed files+2382−0
.github/workflows/deploy.ymladded+86−0View file
@@ -0,0 +1,86 @@
1+name: Deploy to GitHub Pages
2+
3+# Builds this app against the development version of numbl (its `main` branch),
4+# which is checked out as a sibling directory so the `numbl` file: dependency
5+# (../../numbl) resolves exactly as it does in local development. Runs on every
6+# push, on a daily schedule (to pick up numbl `main` changes), and on demand.
7+
8+on:
9+ push:
10+ branches: [main]
11+ schedule:
12+ - cron: "0 6 * * *"
13+ workflow_dispatch:
14+
15+permissions:
16+ contents: read
17+ pages: write
18+ id-token: write
19+
20+# Allow one concurrent deployment; don't cancel an in-progress production deploy.
21+concurrency:
22+ group: pages
23+ cancel-in-progress: false
24+
25+jobs:
26+ build:
27+ runs-on: ubuntu-latest
28+ steps:
29+ # Lay the two repos out as siblings matching local dev:
30+ # <workspace>/concept-collection/numbl-figure-viewer (this app)
31+ # <workspace>/numbl (numbl main)
32+ # so the app's `"numbl": "file:../../numbl"` resolves to <workspace>/numbl.
33+ - name: Checkout app
34+ uses: actions/checkout@v4
35+ with:
36+ path: concept-collection/numbl-figure-viewer
37+
38+ - name: Checkout numbl (main)
39+ uses: actions/checkout@v4
40+ with:
41+ repository: flatironinstitute/numbl
42+ ref: main
43+ path: numbl
44+
45+ - uses: actions/setup-node@v4
46+ with:
47+ node-version: 22
48+ cache: npm
49+ cache-dependency-path: |
50+ numbl/package-lock.json
51+ concept-collection/numbl-figure-viewer/package-lock.json
52+
53+ # Build the numbl/graphics browser bundle the app imports. (HUSKY=0 skips
54+ # the git-hook setup in numbl's prepare script; numbl's own install script
55+ # is a no-op, so no native addon is built.)
56+ - name: Build numbl/graphics
57+ working-directory: numbl
58+ env:
59+ HUSKY: 0
60+ run: |
61+ npm ci
62+ npm run build:graphics
63+
64+ - name: Install app dependencies
65+ working-directory: concept-collection/numbl-figure-viewer
66+ run: npm install
67+
68+ - name: Build app
69+ working-directory: concept-collection/numbl-figure-viewer
70+ run: npm run build:pages
71+
72+ - uses: actions/configure-pages@v5
73+
74+ - uses: actions/upload-pages-artifact@v3
75+ with:
76+ path: concept-collection/numbl-figure-viewer/dist
77+
78+ deploy:
79+ needs: build
80+ runs-on: ubuntu-latest
81+ environment:
82+ name: github-pages
83+ url: ${{ steps.deployment.outputs.page_url }}
84+ steps:
85+ - id: deployment
86+ uses: actions/deploy-pages@v4
.gitignoreadded+6−0View file
@@ -0,0 +1,6 @@
1+node_modules
2+dist
3+dist-ssr
4+*.local
5+*.tsbuildinfo
6+.DS_Store
README.mdadded+39−0View file
@@ -0,0 +1,39 @@
1+# numbl figure viewer
2+
3+A small browser app that opens a `.h5` **figure file** exported from
4+[numbl](https://numbl.org) and renders it — reusing numbl's own figure
5+components via the `numbl/graphics` package export.
6+
7+In numbl (or its IDE / plot viewer) you can download any figure's data as a
8+self-describing HDF5 file (numeric data as gzip-compressed datasets, styling as
9+attributes). Drop that file here to view it again outside numbl.
10+
11+## How it works
12+
13+```ts
14+import { importFigureHdf5, FigureView } from "numbl/graphics";
15+
16+const figure = await importFigureHdf5(bytes); // .h5 → FigureState
17+// <FigureView figure={figure} />
18+```
19+
20+`importFigureHdf5` parses the HDF5 file (via lazily-loaded h5wasm) into the same
21+`FigureState` numbl renders internally, and `FigureView` draws it.
22+
23+## Develop
24+
25+```bash
26+npm install # numbl is a local file: dependency (../../numbl)
27+npm run dev
28+```
29+
30+> This app consumes `numbl` as `file:../../numbl`. Build the numbl graphics
31+> bundle first (`npm run build:graphics` in the numbl repo) so
32+> `numbl/graphics` resolves.
33+
34+## Build
35+
36+```bash
37+npm run build # → dist/
38+npm run build:pages # base path for GitHub Pages project site
39+```
index.htmladded+12−0View file
@@ -0,0 +1,12 @@
1+<!doctype html>
2+<html lang="en">
3+ <head>
4+ <meta charset="UTF-8" />
5+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+ <title>numbl figure viewer</title>
7+ </head>
8+ <body>
9+ <div id="root"></div>
10+ <script type="module" src="/src/main.tsx"></script>
11+ </body>
12+</html>
package-lock.jsonadded+1943−0View file
@@ -0,0 +1,1943 @@
1+{
2+ "name": "numbl-figure-viewer",
3+ "version": "0.0.0",
4+ "lockfileVersion": 3,
5+ "requires": true,
6+ "packages": {
7+ "": {
8+ "name": "numbl-figure-viewer",
9+ "version": "0.0.0",
10+ "dependencies": {
11+ "numbl": "file:../../numbl",
12+ "react": "^19.2.0",
13+ "react-dom": "^19.2.0"
14+ },
15+ "devDependencies": {
16+ "@types/react": "^19.2.5",
17+ "@types/react-dom": "^19.2.3",
18+ "@vitejs/plugin-react": "^5.1.1",
19+ "typescript": "~5.9.3",
20+ "vite": "^7.2.4"
21+ }
22+ },
23+ "../../numbl": {
24+ "version": "0.4.6",
25+ "hasInstallScript": true,
26+ "license": "Apache-2.0",
27+ "dependencies": {
28+ "fflate": "^0.8.2",
29+ "h5wasm": "^0.10.3",
30+ "node-addon-api": "^8.3.0",
31+ "pako": "^2.1.0",
32+ "qhull-wasm": "^0.0.1",
33+ "react-markdown": "^10.1.0",
34+ "react-syntax-highlighter": "^16.1.1",
35+ "remark-gfm": "^4.0.1",
36+ "three": "^0.183.2"
37+ },
38+ "bin": {
39+ "numbl": "dist-cli/cli.js"
40+ },
41+ "devDependencies": {
42+ "@emotion/react": "^11.14.0",
43+ "@emotion/styled": "^11.14.1",
44+ "@eslint/js": "^9.39.1",
45+ "@monaco-editor/react": "^4.7.0",
46+ "@mui/icons-material": "^7.3.7",
47+ "@mui/material": "^7.3.7",
48+ "@playwright/test": "^1.59.1",
49+ "@types/node": "^24.10.1",
50+ "@types/pako": "^2.0.4",
51+ "@types/react": "^19.2.5",
52+ "@types/react-dom": "^19.2.3",
53+ "@types/react-syntax-highlighter": "^15.5.13",
54+ "@types/three": "^0.183.1",
55+ "@vitejs/plugin-react": "^5.1.1",
56+ "@vitest/coverage-v8": "^4.0.18",
57+ "@xterm/addon-fit": "^0.11.0",
58+ "@xterm/xterm": "^6.0.0",
59+ "dexie": "^4.3.0",
60+ "esbuild": "^0.27.3",
61+ "eslint": "^9.39.1",
62+ "eslint-config-prettier": "^10.1.8",
63+ "eslint-plugin-react-hooks": "^7.0.1",
64+ "eslint-plugin-react-refresh": "^0.4.24",
65+ "globals": "^16.5.0",
66+ "husky": "^9.1.7",
67+ "lint-staged": "^16.2.7",
68+ "node-gyp": "^11.2.0",
69+ "prettier": "^3.8.1",
70+ "react": "^19.2.0",
71+ "react-dom": "^19.2.0",
72+ "react-router-dom": "^7.13.0",
73+ "tsx": "^4.21.0",
74+ "typescript": "~5.9.3",
75+ "typescript-eslint": "^8.46.4",
76+ "vite": "^7.2.4",
77+ "vite-plugin-wasm": "^3.5.0",
78+ "vitest": "^4.0.18"
79+ },
80+ "engines": {
81+ "node": ">=18"
82+ },
83+ "optionalDependencies": {
84+ "koffi": "^2.15.2"
85+ },
86+ "peerDependencies": {
87+ "react": ">=18",
88+ "react-dom": ">=18"
89+ },
90+ "peerDependenciesMeta": {
91+ "react": {
92+ "optional": true
93+ },
94+ "react-dom": {
95+ "optional": true
96+ }
97+ }
98+ },
99+ "node_modules/@babel/code-frame": {
100+ "version": "7.29.7",
101+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
102+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
103+ "dev": true,
104+ "license": "MIT",
105+ "dependencies": {
106+ "@babel/helper-validator-identifier": "^7.29.7",
107+ "js-tokens": "^4.0.0",
108+ "picocolors": "^1.1.1"
109+ },
110+ "engines": {
111+ "node": ">=6.9.0"
112+ }
113+ },
114+ "node_modules/@babel/compat-data": {
115+ "version": "7.29.7",
116+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
117+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
118+ "dev": true,
119+ "license": "MIT",
120+ "engines": {
121+ "node": ">=6.9.0"
122+ }
123+ },
124+ "node_modules/@babel/core": {
125+ "version": "7.29.7",
126+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
127+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
128+ "dev": true,
129+ "license": "MIT",
130+ "dependencies": {
131+ "@babel/code-frame": "^7.29.7",
132+ "@babel/generator": "^7.29.7",
133+ "@babel/helper-compilation-targets": "^7.29.7",
134+ "@babel/helper-module-transforms": "^7.29.7",
135+ "@babel/helpers": "^7.29.7",
136+ "@babel/parser": "^7.29.7",
137+ "@babel/template": "^7.29.7",
138+ "@babel/traverse": "^7.29.7",
139+ "@babel/types": "^7.29.7",
140+ "@jridgewell/remapping": "^2.3.5",
141+ "convert-source-map": "^2.0.0",
142+ "debug": "^4.1.0",
143+ "gensync": "^1.0.0-beta.2",
144+ "json5": "^2.2.3",
145+ "semver": "^6.3.1"
146+ },
147+ "engines": {
148+ "node": ">=6.9.0"
149+ },
150+ "funding": {
151+ "type": "opencollective",
152+ "url": "https://opencollective.com/babel"
153+ }
154+ },
155+ "node_modules/@babel/generator": {
156+ "version": "7.29.7",
157+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
158+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
159+ "dev": true,
160+ "license": "MIT",
161+ "dependencies": {
162+ "@babel/parser": "^7.29.7",
163+ "@babel/types": "^7.29.7",
164+ "@jridgewell/gen-mapping": "^0.3.12",
165+ "@jridgewell/trace-mapping": "^0.3.28",
166+ "jsesc": "^3.0.2"
167+ },
168+ "engines": {
169+ "node": ">=6.9.0"
170+ }
171+ },
172+ "node_modules/@babel/helper-compilation-targets": {
173+ "version": "7.29.7",
174+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
175+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
176+ "dev": true,
177+ "license": "MIT",
178+ "dependencies": {
179+ "@babel/compat-data": "^7.29.7",
180+ "@babel/helper-validator-option": "^7.29.7",
181+ "browserslist": "^4.24.0",
182+ "lru-cache": "^5.1.1",
183+ "semver": "^6.3.1"
184+ },
185+ "engines": {
186+ "node": ">=6.9.0"
187+ }
188+ },
189+ "node_modules/@babel/helper-globals": {
190+ "version": "7.29.7",
191+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
192+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
193+ "dev": true,
194+ "license": "MIT",
195+ "engines": {
196+ "node": ">=6.9.0"
197+ }
198+ },
199+ "node_modules/@babel/helper-module-imports": {
200+ "version": "7.29.7",
201+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
202+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
203+ "dev": true,
204+ "license": "MIT",
205+ "dependencies": {
206+ "@babel/traverse": "^7.29.7",
207+ "@babel/types": "^7.29.7"
208+ },
209+ "engines": {
210+ "node": ">=6.9.0"
211+ }
212+ },
213+ "node_modules/@babel/helper-module-transforms": {
214+ "version": "7.29.7",
215+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
216+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
217+ "dev": true,
218+ "license": "MIT",
219+ "dependencies": {
220+ "@babel/helper-module-imports": "^7.29.7",
221+ "@babel/helper-validator-identifier": "^7.29.7",
222+ "@babel/traverse": "^7.29.7"
223+ },
224+ "engines": {
225+ "node": ">=6.9.0"
226+ },
227+ "peerDependencies": {
228+ "@babel/core": "^7.0.0"
229+ }
230+ },
231+ "node_modules/@babel/helper-plugin-utils": {
232+ "version": "7.29.7",
233+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
234+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
235+ "dev": true,
236+ "license": "MIT",
237+ "engines": {
238+ "node": ">=6.9.0"
239+ }
240+ },
241+ "node_modules/@babel/helper-string-parser": {
242+ "version": "7.29.7",
243+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
244+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
245+ "dev": true,
246+ "license": "MIT",
247+ "engines": {
248+ "node": ">=6.9.0"
249+ }
250+ },
251+ "node_modules/@babel/helper-validator-identifier": {
252+ "version": "7.29.7",
253+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
254+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
255+ "dev": true,
256+ "license": "MIT",
257+ "engines": {
258+ "node": ">=6.9.0"
259+ }
260+ },
261+ "node_modules/@babel/helper-validator-option": {
262+ "version": "7.29.7",
263+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
264+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
265+ "dev": true,
266+ "license": "MIT",
267+ "engines": {
268+ "node": ">=6.9.0"
269+ }
270+ },
271+ "node_modules/@babel/helpers": {
272+ "version": "7.29.7",
273+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
274+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
275+ "dev": true,
276+ "license": "MIT",
277+ "dependencies": {
278+ "@babel/template": "^7.29.7",
279+ "@babel/types": "^7.29.7"
280+ },
281+ "engines": {
282+ "node": ">=6.9.0"
283+ }
284+ },
285+ "node_modules/@babel/parser": {
286+ "version": "7.29.7",
287+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
288+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
289+ "dev": true,
290+ "license": "MIT",
291+ "dependencies": {
292+ "@babel/types": "^7.29.7"
293+ },
294+ "bin": {
295+ "parser": "bin/babel-parser.js"
296+ },
297+ "engines": {
298+ "node": ">=6.0.0"
299+ }
300+ },
301+ "node_modules/@babel/plugin-transform-react-jsx-self": {
302+ "version": "7.29.7",
303+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
304+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
305+ "dev": true,
306+ "license": "MIT",
307+ "dependencies": {
308+ "@babel/helper-plugin-utils": "^7.29.7"
309+ },
310+ "engines": {
311+ "node": ">=6.9.0"
312+ },
313+ "peerDependencies": {
314+ "@babel/core": "^7.0.0-0"
315+ }
316+ },
317+ "node_modules/@babel/plugin-transform-react-jsx-source": {
318+ "version": "7.29.7",
319+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
320+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
321+ "dev": true,
322+ "license": "MIT",
323+ "dependencies": {
324+ "@babel/helper-plugin-utils": "^7.29.7"
325+ },
326+ "engines": {
327+ "node": ">=6.9.0"
328+ },
329+ "peerDependencies": {
330+ "@babel/core": "^7.0.0-0"
331+ }
332+ },
333+ "node_modules/@babel/template": {
334+ "version": "7.29.7",
335+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
336+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
337+ "dev": true,
338+ "license": "MIT",
339+ "dependencies": {
340+ "@babel/code-frame": "^7.29.7",
341+ "@babel/parser": "^7.29.7",
342+ "@babel/types": "^7.29.7"
343+ },
344+ "engines": {
345+ "node": ">=6.9.0"
346+ }
347+ },
348+ "node_modules/@babel/traverse": {
349+ "version": "7.29.7",
350+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
351+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
352+ "dev": true,
353+ "license": "MIT",
354+ "dependencies": {
355+ "@babel/code-frame": "^7.29.7",
356+ "@babel/generator": "^7.29.7",
357+ "@babel/helper-globals": "^7.29.7",
358+ "@babel/parser": "^7.29.7",
359+ "@babel/template": "^7.29.7",
360+ "@babel/types": "^7.29.7",
361+ "debug": "^4.3.1"
362+ },
363+ "engines": {
364+ "node": ">=6.9.0"
365+ }
366+ },
367+ "node_modules/@babel/types": {
368+ "version": "7.29.7",
369+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
370+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
371+ "dev": true,
372+ "license": "MIT",
373+ "dependencies": {
374+ "@babel/helper-string-parser": "^7.29.7",
375+ "@babel/helper-validator-identifier": "^7.29.7"
376+ },
377+ "engines": {
378+ "node": ">=6.9.0"
379+ }
380+ },
381+ "node_modules/@esbuild/aix-ppc64": {
382+ "version": "0.27.7",
383+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
384+ "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
385+ "cpu": [
386+ "ppc64"
387+ ],
388+ "dev": true,
389+ "license": "MIT",
390+ "optional": true,
391+ "os": [
392+ "aix"
393+ ],
394+ "engines": {
395+ "node": ">=18"
396+ }
397+ },
398+ "node_modules/@esbuild/android-arm": {
399+ "version": "0.27.7",
400+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
401+ "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
402+ "cpu": [
403+ "arm"
404+ ],
405+ "dev": true,
406+ "license": "MIT",
407+ "optional": true,
408+ "os": [
409+ "android"
410+ ],
411+ "engines": {
412+ "node": ">=18"
413+ }
414+ },
415+ "node_modules/@esbuild/android-arm64": {
416+ "version": "0.27.7",
417+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
418+ "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
419+ "cpu": [
420+ "arm64"
421+ ],
422+ "dev": true,
423+ "license": "MIT",
424+ "optional": true,
425+ "os": [
426+ "android"
427+ ],
428+ "engines": {
429+ "node": ">=18"
430+ }
431+ },
432+ "node_modules/@esbuild/android-x64": {
433+ "version": "0.27.7",
434+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
435+ "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
436+ "cpu": [
437+ "x64"
438+ ],
439+ "dev": true,
440+ "license": "MIT",
441+ "optional": true,
442+ "os": [
443+ "android"
444+ ],
445+ "engines": {
446+ "node": ">=18"
447+ }
448+ },
449+ "node_modules/@esbuild/darwin-arm64": {
450+ "version": "0.27.7",
451+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
452+ "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
453+ "cpu": [
454+ "arm64"
455+ ],
456+ "dev": true,
457+ "license": "MIT",
458+ "optional": true,
459+ "os": [
460+ "darwin"
461+ ],
462+ "engines": {
463+ "node": ">=18"
464+ }
465+ },
466+ "node_modules/@esbuild/darwin-x64": {
467+ "version": "0.27.7",
468+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
469+ "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
470+ "cpu": [
471+ "x64"
472+ ],
473+ "dev": true,
474+ "license": "MIT",
475+ "optional": true,
476+ "os": [
477+ "darwin"
478+ ],
479+ "engines": {
480+ "node": ">=18"
481+ }
482+ },
483+ "node_modules/@esbuild/freebsd-arm64": {
484+ "version": "0.27.7",
485+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
486+ "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
487+ "cpu": [
488+ "arm64"
489+ ],
490+ "dev": true,
491+ "license": "MIT",
492+ "optional": true,
493+ "os": [
494+ "freebsd"
495+ ],
496+ "engines": {
497+ "node": ">=18"
498+ }
499+ },
500+ "node_modules/@esbuild/freebsd-x64": {
501+ "version": "0.27.7",
502+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
503+ "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
504+ "cpu": [
505+ "x64"
506+ ],
507+ "dev": true,
508+ "license": "MIT",
509+ "optional": true,
510+ "os": [
511+ "freebsd"
512+ ],
513+ "engines": {
514+ "node": ">=18"
515+ }
516+ },
517+ "node_modules/@esbuild/linux-arm": {
518+ "version": "0.27.7",
519+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
520+ "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
521+ "cpu": [
522+ "arm"
523+ ],
524+ "dev": true,
525+ "license": "MIT",
526+ "optional": true,
527+ "os": [
528+ "linux"
529+ ],
530+ "engines": {
531+ "node": ">=18"
532+ }
533+ },
534+ "node_modules/@esbuild/linux-arm64": {
535+ "version": "0.27.7",
536+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
537+ "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
538+ "cpu": [
539+ "arm64"
540+ ],
541+ "dev": true,
542+ "license": "MIT",
543+ "optional": true,
544+ "os": [
545+ "linux"
546+ ],
547+ "engines": {
548+ "node": ">=18"
549+ }
550+ },
551+ "node_modules/@esbuild/linux-ia32": {
552+ "version": "0.27.7",
553+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
554+ "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
555+ "cpu": [
556+ "ia32"
557+ ],
558+ "dev": true,
559+ "license": "MIT",
560+ "optional": true,
561+ "os": [
562+ "linux"
563+ ],
564+ "engines": {
565+ "node": ">=18"
566+ }
567+ },
568+ "node_modules/@esbuild/linux-loong64": {
569+ "version": "0.27.7",
570+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
571+ "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
572+ "cpu": [
573+ "loong64"
574+ ],
575+ "dev": true,
576+ "license": "MIT",
577+ "optional": true,
578+ "os": [
579+ "linux"
580+ ],
581+ "engines": {
582+ "node": ">=18"
583+ }
584+ },
585+ "node_modules/@esbuild/linux-mips64el": {
586+ "version": "0.27.7",
587+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
588+ "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
589+ "cpu": [
590+ "mips64el"
591+ ],
592+ "dev": true,
593+ "license": "MIT",
594+ "optional": true,
595+ "os": [
596+ "linux"
597+ ],
598+ "engines": {
599+ "node": ">=18"
600+ }
601+ },
602+ "node_modules/@esbuild/linux-ppc64": {
603+ "version": "0.27.7",
604+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
605+ "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
606+ "cpu": [
607+ "ppc64"
608+ ],
609+ "dev": true,
610+ "license": "MIT",
611+ "optional": true,
612+ "os": [
613+ "linux"
614+ ],
615+ "engines": {
616+ "node": ">=18"
617+ }
618+ },
619+ "node_modules/@esbuild/linux-riscv64": {
620+ "version": "0.27.7",
621+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
622+ "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
623+ "cpu": [
624+ "riscv64"
625+ ],
626+ "dev": true,
627+ "license": "MIT",
628+ "optional": true,
629+ "os": [
630+ "linux"
631+ ],
632+ "engines": {
633+ "node": ">=18"
634+ }
635+ },
636+ "node_modules/@esbuild/linux-s390x": {
637+ "version": "0.27.7",
638+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
639+ "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
640+ "cpu": [
641+ "s390x"
642+ ],
643+ "dev": true,
644+ "license": "MIT",
645+ "optional": true,
646+ "os": [
647+ "linux"
648+ ],
649+ "engines": {
650+ "node": ">=18"
651+ }
652+ },
653+ "node_modules/@esbuild/linux-x64": {
654+ "version": "0.27.7",
655+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
656+ "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
657+ "cpu": [
658+ "x64"
659+ ],
660+ "dev": true,
661+ "license": "MIT",
662+ "optional": true,
663+ "os": [
664+ "linux"
665+ ],
666+ "engines": {
667+ "node": ">=18"
668+ }
669+ },
670+ "node_modules/@esbuild/netbsd-arm64": {
671+ "version": "0.27.7",
672+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
673+ "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
674+ "cpu": [
675+ "arm64"
676+ ],
677+ "dev": true,
678+ "license": "MIT",
679+ "optional": true,
680+ "os": [
681+ "netbsd"
682+ ],
683+ "engines": {
684+ "node": ">=18"
685+ }
686+ },
687+ "node_modules/@esbuild/netbsd-x64": {
688+ "version": "0.27.7",
689+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
690+ "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
691+ "cpu": [
692+ "x64"
693+ ],
694+ "dev": true,
695+ "license": "MIT",
696+ "optional": true,
697+ "os": [
698+ "netbsd"
699+ ],
700+ "engines": {
701+ "node": ">=18"
702+ }
703+ },
704+ "node_modules/@esbuild/openbsd-arm64": {
705+ "version": "0.27.7",
706+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
707+ "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
708+ "cpu": [
709+ "arm64"
710+ ],
711+ "dev": true,
712+ "license": "MIT",
713+ "optional": true,
714+ "os": [
715+ "openbsd"
716+ ],
717+ "engines": {
718+ "node": ">=18"
719+ }
720+ },
721+ "node_modules/@esbuild/openbsd-x64": {
722+ "version": "0.27.7",
723+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
724+ "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
725+ "cpu": [
726+ "x64"
727+ ],
728+ "dev": true,
729+ "license": "MIT",
730+ "optional": true,
731+ "os": [
732+ "openbsd"
733+ ],
734+ "engines": {
735+ "node": ">=18"
736+ }
737+ },
738+ "node_modules/@esbuild/openharmony-arm64": {
739+ "version": "0.27.7",
740+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
741+ "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
742+ "cpu": [
743+ "arm64"
744+ ],
745+ "dev": true,
746+ "license": "MIT",
747+ "optional": true,
748+ "os": [
749+ "openharmony"
750+ ],
751+ "engines": {
752+ "node": ">=18"
753+ }
754+ },
755+ "node_modules/@esbuild/sunos-x64": {
756+ "version": "0.27.7",
757+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
758+ "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
759+ "cpu": [
760+ "x64"
761+ ],
762+ "dev": true,
763+ "license": "MIT",
764+ "optional": true,
765+ "os": [
766+ "sunos"
767+ ],
768+ "engines": {
769+ "node": ">=18"
770+ }
771+ },
772+ "node_modules/@esbuild/win32-arm64": {
773+ "version": "0.27.7",
774+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
775+ "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
776+ "cpu": [
777+ "arm64"
778+ ],
779+ "dev": true,
780+ "license": "MIT",
781+ "optional": true,
782+ "os": [
783+ "win32"
784+ ],
785+ "engines": {
786+ "node": ">=18"
787+ }
788+ },
789+ "node_modules/@esbuild/win32-ia32": {
790+ "version": "0.27.7",
791+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
792+ "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
793+ "cpu": [
794+ "ia32"
795+ ],
796+ "dev": true,
797+ "license": "MIT",
798+ "optional": true,
799+ "os": [
800+ "win32"
801+ ],
802+ "engines": {
803+ "node": ">=18"
804+ }
805+ },
806+ "node_modules/@esbuild/win32-x64": {
807+ "version": "0.27.7",
808+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
809+ "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
810+ "cpu": [
811+ "x64"
812+ ],
813+ "dev": true,
814+ "license": "MIT",
815+ "optional": true,
816+ "os": [
817+ "win32"
818+ ],
819+ "engines": {
820+ "node": ">=18"
821+ }
822+ },
823+ "node_modules/@jridgewell/gen-mapping": {
824+ "version": "0.3.13",
825+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
826+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
827+ "dev": true,
828+ "license": "MIT",
829+ "dependencies": {
830+ "@jridgewell/sourcemap-codec": "^1.5.0",
831+ "@jridgewell/trace-mapping": "^0.3.24"
832+ }
833+ },
834+ "node_modules/@jridgewell/remapping": {
835+ "version": "2.3.5",
836+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
837+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
838+ "dev": true,
839+ "license": "MIT",
840+ "dependencies": {
841+ "@jridgewell/gen-mapping": "^0.3.5",
842+ "@jridgewell/trace-mapping": "^0.3.24"
843+ }
844+ },
845+ "node_modules/@jridgewell/resolve-uri": {
846+ "version": "3.1.2",
847+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
848+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
849+ "dev": true,
850+ "license": "MIT",
851+ "engines": {
852+ "node": ">=6.0.0"
853+ }
854+ },
855+ "node_modules/@jridgewell/sourcemap-codec": {
856+ "version": "1.5.5",
857+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
858+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
859+ "dev": true,
860+ "license": "MIT"
861+ },
862+ "node_modules/@jridgewell/trace-mapping": {
863+ "version": "0.3.31",
864+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
865+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
866+ "dev": true,
867+ "license": "MIT",
868+ "dependencies": {
869+ "@jridgewell/resolve-uri": "^3.1.0",
870+ "@jridgewell/sourcemap-codec": "^1.4.14"
871+ }
872+ },
873+ "node_modules/@rolldown/pluginutils": {
874+ "version": "1.0.0-rc.3",
875+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
876+ "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==",
877+ "dev": true,
878+ "license": "MIT"
879+ },
880+ "node_modules/@rollup/rollup-android-arm-eabi": {
881+ "version": "4.62.0",
882+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz",
883+ "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==",
884+ "cpu": [
885+ "arm"
886+ ],
887+ "dev": true,
888+ "license": "MIT",
889+ "optional": true,
890+ "os": [
891+ "android"
892+ ]
893+ },
894+ "node_modules/@rollup/rollup-android-arm64": {
895+ "version": "4.62.0",
896+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz",
897+ "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==",
898+ "cpu": [
899+ "arm64"
900+ ],
901+ "dev": true,
902+ "license": "MIT",
903+ "optional": true,
904+ "os": [
905+ "android"
906+ ]
907+ },
908+ "node_modules/@rollup/rollup-darwin-arm64": {
909+ "version": "4.62.0",
910+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz",
911+ "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==",
912+ "cpu": [
913+ "arm64"
914+ ],
915+ "dev": true,
916+ "license": "MIT",
917+ "optional": true,
918+ "os": [
919+ "darwin"
920+ ]
921+ },
922+ "node_modules/@rollup/rollup-darwin-x64": {
923+ "version": "4.62.0",
924+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz",
925+ "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==",
926+ "cpu": [
927+ "x64"
928+ ],
929+ "dev": true,
930+ "license": "MIT",
931+ "optional": true,
932+ "os": [
933+ "darwin"
934+ ]
935+ },
936+ "node_modules/@rollup/rollup-freebsd-arm64": {
937+ "version": "4.62.0",
938+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz",
939+ "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==",
940+ "cpu": [
941+ "arm64"
942+ ],
943+ "dev": true,
944+ "license": "MIT",
945+ "optional": true,
946+ "os": [
947+ "freebsd"
948+ ]
949+ },
950+ "node_modules/@rollup/rollup-freebsd-x64": {
951+ "version": "4.62.0",
952+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz",
953+ "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==",
954+ "cpu": [
955+ "x64"
956+ ],
957+ "dev": true,
958+ "license": "MIT",
959+ "optional": true,
960+ "os": [
961+ "freebsd"
962+ ]
963+ },
964+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
965+ "version": "4.62.0",
966+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz",
967+ "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==",
968+ "cpu": [
969+ "arm"
970+ ],
971+ "dev": true,
972+ "libc": [
973+ "glibc"
974+ ],
975+ "license": "MIT",
976+ "optional": true,
977+ "os": [
978+ "linux"
979+ ]
980+ },
981+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
982+ "version": "4.62.0",
983+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz",
984+ "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==",
985+ "cpu": [
986+ "arm"
987+ ],
988+ "dev": true,
989+ "libc": [
990+ "musl"
991+ ],
992+ "license": "MIT",
993+ "optional": true,
994+ "os": [
995+ "linux"
996+ ]
997+ },
998+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
999+ "version": "4.62.0",
1000+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz",
1001+ "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==",
1002+ "cpu": [
1003+ "arm64"
1004+ ],
1005+ "dev": true,
1006+ "libc": [
1007+ "glibc"
1008+ ],
1009+ "license": "MIT",
1010+ "optional": true,
1011+ "os": [
1012+ "linux"
1013+ ]
1014+ },
1015+ "node_modules/@rollup/rollup-linux-arm64-musl": {
1016+ "version": "4.62.0",
1017+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz",
1018+ "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==",
1019+ "cpu": [
1020+ "arm64"
1021+ ],
1022+ "dev": true,
1023+ "libc": [
1024+ "musl"
1025+ ],
1026+ "license": "MIT",
1027+ "optional": true,
1028+ "os": [
1029+ "linux"
1030+ ]
1031+ },
1032+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
1033+ "version": "4.62.0",
1034+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz",
1035+ "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==",
1036+ "cpu": [
1037+ "loong64"
1038+ ],
1039+ "dev": true,
1040+ "libc": [
1041+ "glibc"
1042+ ],
1043+ "license": "MIT",
1044+ "optional": true,
1045+ "os": [
1046+ "linux"
1047+ ]
1048+ },
1049+ "node_modules/@rollup/rollup-linux-loong64-musl": {
1050+ "version": "4.62.0",
1051+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz",
1052+ "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==",
1053+ "cpu": [
1054+ "loong64"
1055+ ],
1056+ "dev": true,
1057+ "libc": [
1058+ "musl"
1059+ ],
1060+ "license": "MIT",
1061+ "optional": true,
1062+ "os": [
1063+ "linux"
1064+ ]
1065+ },
1066+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1067+ "version": "4.62.0",
1068+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz",
1069+ "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==",
1070+ "cpu": [
1071+ "ppc64"
1072+ ],
1073+ "dev": true,
1074+ "libc": [
1075+ "glibc"
1076+ ],
1077+ "license": "MIT",
1078+ "optional": true,
1079+ "os": [
1080+ "linux"
1081+ ]
1082+ },
1083+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
1084+ "version": "4.62.0",
1085+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz",
1086+ "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==",
1087+ "cpu": [
1088+ "ppc64"
1089+ ],
1090+ "dev": true,
1091+ "libc": [
1092+ "musl"
1093+ ],
1094+ "license": "MIT",
1095+ "optional": true,
1096+ "os": [
1097+ "linux"
1098+ ]
1099+ },
1100+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1101+ "version": "4.62.0",
1102+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz",
1103+ "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==",
1104+ "cpu": [
1105+ "riscv64"
1106+ ],
1107+ "dev": true,
1108+ "libc": [
1109+ "glibc"
1110+ ],
1111+ "license": "MIT",
1112+ "optional": true,
1113+ "os": [
1114+ "linux"
1115+ ]
1116+ },
1117+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1118+ "version": "4.62.0",
1119+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz",
1120+ "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==",
1121+ "cpu": [
1122+ "riscv64"
1123+ ],
1124+ "dev": true,
1125+ "libc": [
1126+ "musl"
1127+ ],
1128+ "license": "MIT",
1129+ "optional": true,
1130+ "os": [
1131+ "linux"
1132+ ]
1133+ },
1134+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1135+ "version": "4.62.0",
1136+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz",
1137+ "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==",
1138+ "cpu": [
1139+ "s390x"
1140+ ],
1141+ "dev": true,
1142+ "libc": [
1143+ "glibc"
1144+ ],
1145+ "license": "MIT",
1146+ "optional": true,
1147+ "os": [
1148+ "linux"
1149+ ]
1150+ },
1151+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1152+ "version": "4.62.0",
1153+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz",
1154+ "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==",
1155+ "cpu": [
1156+ "x64"
1157+ ],
1158+ "dev": true,
1159+ "libc": [
1160+ "glibc"
1161+ ],
1162+ "license": "MIT",
1163+ "optional": true,
1164+ "os": [
1165+ "linux"
1166+ ]
1167+ },
1168+ "node_modules/@rollup/rollup-linux-x64-musl": {
1169+ "version": "4.62.0",
1170+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz",
1171+ "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==",
1172+ "cpu": [
1173+ "x64"
1174+ ],
1175+ "dev": true,
1176+ "libc": [
1177+ "musl"
1178+ ],
1179+ "license": "MIT",
1180+ "optional": true,
1181+ "os": [
1182+ "linux"
1183+ ]
1184+ },
1185+ "node_modules/@rollup/rollup-openbsd-x64": {
1186+ "version": "4.62.0",
1187+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz",
1188+ "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==",
1189+ "cpu": [
1190+ "x64"
1191+ ],
1192+ "dev": true,
1193+ "license": "MIT",
1194+ "optional": true,
1195+ "os": [
1196+ "openbsd"
1197+ ]
1198+ },
1199+ "node_modules/@rollup/rollup-openharmony-arm64": {
1200+ "version": "4.62.0",
1201+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz",
1202+ "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==",
1203+ "cpu": [
1204+ "arm64"
1205+ ],
1206+ "dev": true,
1207+ "license": "MIT",
1208+ "optional": true,
1209+ "os": [
1210+ "openharmony"
1211+ ]
1212+ },
1213+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1214+ "version": "4.62.0",
1215+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz",
1216+ "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==",
1217+ "cpu": [
1218+ "arm64"
1219+ ],
1220+ "dev": true,
1221+ "license": "MIT",
1222+ "optional": true,
1223+ "os": [
1224+ "win32"
1225+ ]
1226+ },
1227+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1228+ "version": "4.62.0",
1229+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz",
1230+ "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==",
1231+ "cpu": [
1232+ "ia32"
1233+ ],
1234+ "dev": true,
1235+ "license": "MIT",
1236+ "optional": true,
1237+ "os": [
1238+ "win32"
1239+ ]
1240+ },
1241+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1242+ "version": "4.62.0",
1243+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz",
1244+ "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==",
1245+ "cpu": [
1246+ "x64"
1247+ ],
1248+ "dev": true,
1249+ "license": "MIT",
1250+ "optional": true,
1251+ "os": [
1252+ "win32"
1253+ ]
1254+ },
1255+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1256+ "version": "4.62.0",
1257+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz",
1258+ "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==",
1259+ "cpu": [
1260+ "x64"
1261+ ],
1262+ "dev": true,
1263+ "license": "MIT",
1264+ "optional": true,
1265+ "os": [
1266+ "win32"
1267+ ]
1268+ },
1269+ "node_modules/@types/babel__core": {
1270+ "version": "7.20.5",
1271+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
1272+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
1273+ "dev": true,
1274+ "license": "MIT",
1275+ "dependencies": {
1276+ "@babel/parser": "^7.20.7",
1277+ "@babel/types": "^7.20.7",
1278+ "@types/babel__generator": "*",
1279+ "@types/babel__template": "*",
1280+ "@types/babel__traverse": "*"
1281+ }
1282+ },
1283+ "node_modules/@types/babel__generator": {
1284+ "version": "7.27.0",
1285+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
1286+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
1287+ "dev": true,
1288+ "license": "MIT",
1289+ "dependencies": {
1290+ "@babel/types": "^7.0.0"
1291+ }
1292+ },
1293+ "node_modules/@types/babel__template": {
1294+ "version": "7.4.4",
1295+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
1296+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
1297+ "dev": true,
1298+ "license": "MIT",
1299+ "dependencies": {
1300+ "@babel/parser": "^7.1.0",
1301+ "@babel/types": "^7.0.0"
1302+ }
1303+ },
1304+ "node_modules/@types/babel__traverse": {
1305+ "version": "7.28.0",
1306+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
1307+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
1308+ "dev": true,
1309+ "license": "MIT",
1310+ "dependencies": {
1311+ "@babel/types": "^7.28.2"
1312+ }
1313+ },
1314+ "node_modules/@types/estree": {
1315+ "version": "1.0.9",
1316+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
1317+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
1318+ "dev": true,
1319+ "license": "MIT"
1320+ },
1321+ "node_modules/@types/react": {
1322+ "version": "19.2.17",
1323+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
1324+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
1325+ "dev": true,
1326+ "license": "MIT",
1327+ "dependencies": {
1328+ "csstype": "^3.2.2"
1329+ }
1330+ },
1331+ "node_modules/@types/react-dom": {
1332+ "version": "19.2.3",
1333+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
1334+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
1335+ "dev": true,
1336+ "license": "MIT",
1337+ "peerDependencies": {
1338+ "@types/react": "^19.2.0"
1339+ }
1340+ },
1341+ "node_modules/@vitejs/plugin-react": {
1342+ "version": "5.2.0",
1343+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz",
1344+ "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==",
1345+ "dev": true,
1346+ "license": "MIT",
1347+ "dependencies": {
1348+ "@babel/core": "^7.29.0",
1349+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
1350+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
1351+ "@rolldown/pluginutils": "1.0.0-rc.3",
1352+ "@types/babel__core": "^7.20.5",
1353+ "react-refresh": "^0.18.0"
1354+ },
1355+ "engines": {
1356+ "node": "^20.19.0 || >=22.12.0"
1357+ },
1358+ "peerDependencies": {
1359+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
1360+ }
1361+ },
1362+ "node_modules/baseline-browser-mapping": {
1363+ "version": "2.10.38",
1364+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz",
1365+ "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==",
1366+ "dev": true,
1367+ "license": "Apache-2.0",
1368+ "bin": {
1369+ "baseline-browser-mapping": "dist/cli.cjs"
1370+ },
1371+ "engines": {
1372+ "node": ">=6.0.0"
1373+ }
1374+ },
1375+ "node_modules/browserslist": {
1376+ "version": "4.28.2",
1377+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
1378+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
1379+ "dev": true,
1380+ "funding": [
1381+ {
1382+ "type": "opencollective",
1383+ "url": "https://opencollective.com/browserslist"
1384+ },
1385+ {
1386+ "type": "tidelift",
1387+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1388+ },
1389+ {
1390+ "type": "github",
1391+ "url": "https://github.com/sponsors/ai"
1392+ }
1393+ ],
1394+ "license": "MIT",
1395+ "dependencies": {
1396+ "baseline-browser-mapping": "^2.10.12",
1397+ "caniuse-lite": "^1.0.30001782",
1398+ "electron-to-chromium": "^1.5.328",
1399+ "node-releases": "^2.0.36",
1400+ "update-browserslist-db": "^1.2.3"
1401+ },
1402+ "bin": {
1403+ "browserslist": "cli.js"
1404+ },
1405+ "engines": {
1406+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1407+ }
1408+ },
1409+ "node_modules/caniuse-lite": {
1410+ "version": "1.0.30001799",
1411+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
1412+ "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
1413+ "dev": true,
1414+ "funding": [
1415+ {
1416+ "type": "opencollective",
1417+ "url": "https://opencollective.com/browserslist"
1418+ },
1419+ {
1420+ "type": "tidelift",
1421+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1422+ },
1423+ {
1424+ "type": "github",
1425+ "url": "https://github.com/sponsors/ai"
1426+ }
1427+ ],
1428+ "license": "CC-BY-4.0"
1429+ },
1430+ "node_modules/convert-source-map": {
1431+ "version": "2.0.0",
1432+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
1433+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
1434+ "dev": true,
1435+ "license": "MIT"
1436+ },
1437+ "node_modules/csstype": {
1438+ "version": "3.2.3",
1439+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
1440+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
1441+ "dev": true,
1442+ "license": "MIT"
1443+ },
1444+ "node_modules/debug": {
1445+ "version": "4.4.3",
1446+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1447+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1448+ "dev": true,
1449+ "license": "MIT",
1450+ "dependencies": {
1451+ "ms": "^2.1.3"
1452+ },
1453+ "engines": {
1454+ "node": ">=6.0"
1455+ },
1456+ "peerDependenciesMeta": {
1457+ "supports-color": {
1458+ "optional": true
1459+ }
1460+ }
1461+ },
1462+ "node_modules/electron-to-chromium": {
1463+ "version": "1.5.375",
1464+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz",
1465+ "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==",
1466+ "dev": true,
1467+ "license": "ISC"
1468+ },
1469+ "node_modules/esbuild": {
1470+ "version": "0.27.7",
1471+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
1472+ "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
1473+ "dev": true,
1474+ "hasInstallScript": true,
1475+ "license": "MIT",
1476+ "bin": {
1477+ "esbuild": "bin/esbuild"
1478+ },
1479+ "engines": {
1480+ "node": ">=18"
1481+ },
1482+ "optionalDependencies": {
1483+ "@esbuild/aix-ppc64": "0.27.7",
1484+ "@esbuild/android-arm": "0.27.7",
1485+ "@esbuild/android-arm64": "0.27.7",
1486+ "@esbuild/android-x64": "0.27.7",
1487+ "@esbuild/darwin-arm64": "0.27.7",
1488+ "@esbuild/darwin-x64": "0.27.7",
1489+ "@esbuild/freebsd-arm64": "0.27.7",
1490+ "@esbuild/freebsd-x64": "0.27.7",
1491+ "@esbuild/linux-arm": "0.27.7",
1492+ "@esbuild/linux-arm64": "0.27.7",
1493+ "@esbuild/linux-ia32": "0.27.7",
1494+ "@esbuild/linux-loong64": "0.27.7",
1495+ "@esbuild/linux-mips64el": "0.27.7",
1496+ "@esbuild/linux-ppc64": "0.27.7",
1497+ "@esbuild/linux-riscv64": "0.27.7",
1498+ "@esbuild/linux-s390x": "0.27.7",
1499+ "@esbuild/linux-x64": "0.27.7",
1500+ "@esbuild/netbsd-arm64": "0.27.7",
1501+ "@esbuild/netbsd-x64": "0.27.7",
1502+ "@esbuild/openbsd-arm64": "0.27.7",
1503+ "@esbuild/openbsd-x64": "0.27.7",
1504+ "@esbuild/openharmony-arm64": "0.27.7",
1505+ "@esbuild/sunos-x64": "0.27.7",
1506+ "@esbuild/win32-arm64": "0.27.7",
1507+ "@esbuild/win32-ia32": "0.27.7",
1508+ "@esbuild/win32-x64": "0.27.7"
1509+ }
1510+ },
1511+ "node_modules/escalade": {
1512+ "version": "3.2.0",
1513+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
1514+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
1515+ "dev": true,
1516+ "license": "MIT",
1517+ "engines": {
1518+ "node": ">=6"
1519+ }
1520+ },
1521+ "node_modules/fdir": {
1522+ "version": "6.5.0",
1523+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
1524+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
1525+ "dev": true,
1526+ "license": "MIT",
1527+ "engines": {
1528+ "node": ">=12.0.0"
1529+ },
1530+ "peerDependencies": {
1531+ "picomatch": "^3 || ^4"
1532+ },
1533+ "peerDependenciesMeta": {
1534+ "picomatch": {
1535+ "optional": true
1536+ }
1537+ }
1538+ },
1539+ "node_modules/fsevents": {
1540+ "version": "2.3.3",
1541+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1542+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1543+ "dev": true,
1544+ "hasInstallScript": true,
1545+ "license": "MIT",
1546+ "optional": true,
1547+ "os": [
1548+ "darwin"
1549+ ],
1550+ "engines": {
1551+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1552+ }
1553+ },
1554+ "node_modules/gensync": {
1555+ "version": "1.0.0-beta.2",
1556+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
1557+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
1558+ "dev": true,
1559+ "license": "MIT",
1560+ "engines": {
1561+ "node": ">=6.9.0"
1562+ }
1563+ },
1564+ "node_modules/js-tokens": {
1565+ "version": "4.0.0",
1566+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1567+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1568+ "dev": true,
1569+ "license": "MIT"
1570+ },
1571+ "node_modules/jsesc": {
1572+ "version": "3.1.0",
1573+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
1574+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
1575+ "dev": true,
1576+ "license": "MIT",
1577+ "bin": {
1578+ "jsesc": "bin/jsesc"
1579+ },
1580+ "engines": {
1581+ "node": ">=6"
1582+ }
1583+ },
1584+ "node_modules/json5": {
1585+ "version": "2.2.3",
1586+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
1587+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
1588+ "dev": true,
1589+ "license": "MIT",
1590+ "bin": {
1591+ "json5": "lib/cli.js"
1592+ },
1593+ "engines": {
1594+ "node": ">=6"
1595+ }
1596+ },
1597+ "node_modules/lru-cache": {
1598+ "version": "5.1.1",
1599+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
1600+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
1601+ "dev": true,
1602+ "license": "ISC",
1603+ "dependencies": {
1604+ "yallist": "^3.0.2"
1605+ }
1606+ },
1607+ "node_modules/ms": {
1608+ "version": "2.1.3",
1609+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1610+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1611+ "dev": true,
1612+ "license": "MIT"
1613+ },
1614+ "node_modules/nanoid": {
1615+ "version": "3.3.13",
1616+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.13.tgz",
1617+ "integrity": "sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==",
1618+ "dev": true,
1619+ "funding": [
1620+ {
1621+ "type": "github",
1622+ "url": "https://github.com/sponsors/ai"
1623+ }
1624+ ],
1625+ "license": "MIT",
1626+ "bin": {
1627+ "nanoid": "bin/nanoid.cjs"
1628+ },
1629+ "engines": {
1630+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1631+ }
1632+ },
1633+ "node_modules/node-releases": {
1634+ "version": "2.0.48",
1635+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz",
1636+ "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==",
1637+ "dev": true,
1638+ "license": "MIT",
1639+ "engines": {
1640+ "node": ">=18"
1641+ }
1642+ },
1643+ "node_modules/numbl": {
1644+ "resolved": "../../numbl",
1645+ "link": true
1646+ },
1647+ "node_modules/picocolors": {
1648+ "version": "1.1.1",
1649+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1650+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1651+ "dev": true,
1652+ "license": "ISC"
1653+ },
1654+ "node_modules/picomatch": {
1655+ "version": "4.0.4",
1656+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
1657+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
1658+ "dev": true,
1659+ "license": "MIT",
1660+ "engines": {
1661+ "node": ">=12"
1662+ },
1663+ "funding": {
1664+ "url": "https://github.com/sponsors/jonschlinkert"
1665+ }
1666+ },
1667+ "node_modules/postcss": {
1668+ "version": "8.5.15",
1669+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
1670+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
1671+ "dev": true,
1672+ "funding": [
1673+ {
1674+ "type": "opencollective",
1675+ "url": "https://opencollective.com/postcss/"
1676+ },
1677+ {
1678+ "type": "tidelift",
1679+ "url": "https://tidelift.com/funding/github/npm/postcss"
1680+ },
1681+ {
1682+ "type": "github",
1683+ "url": "https://github.com/sponsors/ai"
1684+ }
1685+ ],
1686+ "license": "MIT",
1687+ "dependencies": {
1688+ "nanoid": "^3.3.12",
1689+ "picocolors": "^1.1.1",
1690+ "source-map-js": "^1.2.1"
1691+ },
1692+ "engines": {
1693+ "node": "^10 || ^12 || >=14"
1694+ }
1695+ },
1696+ "node_modules/react": {
1697+ "version": "19.2.7",
1698+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
1699+ "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
1700+ "license": "MIT",
1701+ "engines": {
1702+ "node": ">=0.10.0"
1703+ }
1704+ },
1705+ "node_modules/react-dom": {
1706+ "version": "19.2.7",
1707+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
1708+ "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
1709+ "license": "MIT",
1710+ "dependencies": {
1711+ "scheduler": "^0.27.0"
1712+ },
1713+ "peerDependencies": {
1714+ "react": "^19.2.7"
1715+ }
1716+ },
1717+ "node_modules/react-refresh": {
1718+ "version": "0.18.0",
1719+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
1720+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
1721+ "dev": true,
1722+ "license": "MIT",
1723+ "engines": {
1724+ "node": ">=0.10.0"
1725+ }
1726+ },
1727+ "node_modules/rollup": {
1728+ "version": "4.62.0",
1729+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz",
1730+ "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==",
1731+ "dev": true,
1732+ "license": "MIT",
1733+ "dependencies": {
1734+ "@types/estree": "1.0.9"
1735+ },
1736+ "bin": {
1737+ "rollup": "dist/bin/rollup"
1738+ },
1739+ "engines": {
1740+ "node": ">=18.0.0",
1741+ "npm": ">=8.0.0"
1742+ },
1743+ "optionalDependencies": {
1744+ "@rollup/rollup-android-arm-eabi": "4.62.0",
1745+ "@rollup/rollup-android-arm64": "4.62.0",
1746+ "@rollup/rollup-darwin-arm64": "4.62.0",
1747+ "@rollup/rollup-darwin-x64": "4.62.0",
1748+ "@rollup/rollup-freebsd-arm64": "4.62.0",
1749+ "@rollup/rollup-freebsd-x64": "4.62.0",
1750+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.0",
1751+ "@rollup/rollup-linux-arm-musleabihf": "4.62.0",
1752+ "@rollup/rollup-linux-arm64-gnu": "4.62.0",
1753+ "@rollup/rollup-linux-arm64-musl": "4.62.0",
1754+ "@rollup/rollup-linux-loong64-gnu": "4.62.0",
1755+ "@rollup/rollup-linux-loong64-musl": "4.62.0",
1756+ "@rollup/rollup-linux-ppc64-gnu": "4.62.0",
1757+ "@rollup/rollup-linux-ppc64-musl": "4.62.0",
1758+ "@rollup/rollup-linux-riscv64-gnu": "4.62.0",
1759+ "@rollup/rollup-linux-riscv64-musl": "4.62.0",
1760+ "@rollup/rollup-linux-s390x-gnu": "4.62.0",
1761+ "@rollup/rollup-linux-x64-gnu": "4.62.0",
1762+ "@rollup/rollup-linux-x64-musl": "4.62.0",
1763+ "@rollup/rollup-openbsd-x64": "4.62.0",
1764+ "@rollup/rollup-openharmony-arm64": "4.62.0",
1765+ "@rollup/rollup-win32-arm64-msvc": "4.62.0",
1766+ "@rollup/rollup-win32-ia32-msvc": "4.62.0",
1767+ "@rollup/rollup-win32-x64-gnu": "4.62.0",
1768+ "@rollup/rollup-win32-x64-msvc": "4.62.0",
1769+ "fsevents": "~2.3.2"
1770+ }
1771+ },
1772+ "node_modules/scheduler": {
1773+ "version": "0.27.0",
1774+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
1775+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
1776+ "license": "MIT"
1777+ },
1778+ "node_modules/semver": {
1779+ "version": "6.3.1",
1780+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
1781+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
1782+ "dev": true,
1783+ "license": "ISC",
1784+ "bin": {
1785+ "semver": "bin/semver.js"
1786+ }
1787+ },
1788+ "node_modules/source-map-js": {
1789+ "version": "1.2.1",
1790+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1791+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1792+ "dev": true,
1793+ "license": "BSD-3-Clause",
1794+ "engines": {
1795+ "node": ">=0.10.0"
1796+ }
1797+ },
1798+ "node_modules/tinyglobby": {
1799+ "version": "0.2.17",
1800+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
1801+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
1802+ "dev": true,
1803+ "license": "MIT",
1804+ "dependencies": {
1805+ "fdir": "^6.5.0",
1806+ "picomatch": "^4.0.4"
1807+ },
1808+ "engines": {
1809+ "node": ">=12.0.0"
1810+ },
1811+ "funding": {
1812+ "url": "https://github.com/sponsors/SuperchupuDev"
1813+ }
1814+ },
1815+ "node_modules/typescript": {
1816+ "version": "5.9.3",
1817+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
1818+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
1819+ "dev": true,
1820+ "license": "Apache-2.0",
1821+ "bin": {
1822+ "tsc": "bin/tsc",
1823+ "tsserver": "bin/tsserver"
1824+ },
1825+ "engines": {
1826+ "node": ">=14.17"
1827+ }
1828+ },
1829+ "node_modules/update-browserslist-db": {
1830+ "version": "1.2.3",
1831+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
1832+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
1833+ "dev": true,
1834+ "funding": [
1835+ {
1836+ "type": "opencollective",
1837+ "url": "https://opencollective.com/browserslist"
1838+ },
1839+ {
1840+ "type": "tidelift",
1841+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1842+ },
1843+ {
1844+ "type": "github",
1845+ "url": "https://github.com/sponsors/ai"
1846+ }
1847+ ],
1848+ "license": "MIT",
1849+ "dependencies": {
1850+ "escalade": "^3.2.0",
1851+ "picocolors": "^1.1.1"
1852+ },
1853+ "bin": {
1854+ "update-browserslist-db": "cli.js"
1855+ },
1856+ "peerDependencies": {
1857+ "browserslist": ">= 4.21.0"
1858+ }
1859+ },
1860+ "node_modules/vite": {
1861+ "version": "7.3.5",
1862+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz",
1863+ "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==",
1864+ "dev": true,
1865+ "license": "MIT",
1866+ "dependencies": {
1867+ "esbuild": "^0.27.0",
1868+ "fdir": "^6.5.0",
1869+ "picomatch": "^4.0.3",
1870+ "postcss": "^8.5.6",
1871+ "rollup": "^4.43.0",
1872+ "tinyglobby": "^0.2.15"
1873+ },
1874+ "bin": {
1875+ "vite": "bin/vite.js"
1876+ },
1877+ "engines": {
1878+ "node": "^20.19.0 || >=22.12.0"
1879+ },
1880+ "funding": {
1881+ "url": "https://github.com/vitejs/vite?sponsor=1"
1882+ },
1883+ "optionalDependencies": {
1884+ "fsevents": "~2.3.3"
1885+ },
1886+ "peerDependencies": {
1887+ "@types/node": "^20.19.0 || >=22.12.0",
1888+ "jiti": ">=1.21.0",
1889+ "less": "^4.0.0",
1890+ "lightningcss": "^1.21.0",
1891+ "sass": "^1.70.0",
1892+ "sass-embedded": "^1.70.0",
1893+ "stylus": ">=0.54.8",
1894+ "sugarss": "^5.0.0",
1895+ "terser": "^5.16.0",
1896+ "tsx": "^4.8.1",
1897+ "yaml": "^2.4.2"
1898+ },
1899+ "peerDependenciesMeta": {
1900+ "@types/node": {
1901+ "optional": true
1902+ },
1903+ "jiti": {
1904+ "optional": true
1905+ },
1906+ "less": {
1907+ "optional": true
1908+ },
1909+ "lightningcss": {
1910+ "optional": true
1911+ },
1912+ "sass": {
1913+ "optional": true
1914+ },
1915+ "sass-embedded": {
1916+ "optional": true
1917+ },
1918+ "stylus": {
1919+ "optional": true
1920+ },
1921+ "sugarss": {
1922+ "optional": true
1923+ },
1924+ "terser": {
1925+ "optional": true
1926+ },
1927+ "tsx": {
1928+ "optional": true
1929+ },
1930+ "yaml": {
1931+ "optional": true
1932+ }
1933+ }
1934+ },
1935+ "node_modules/yallist": {
1936+ "version": "3.1.1",
1937+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1938+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
1939+ "dev": true,
1940+ "license": "ISC"
1941+ }
1942+ }
1943+}
package.jsonadded+25−0View file
@@ -0,0 +1,25 @@
1+{
2+ "name": "numbl-figure-viewer",
3+ "private": true,
4+ "version": "0.0.0",
5+ "type": "module",
6+ "scripts": {
7+ "dev": "vite",
8+ "build": "tsc -b && vite build",
9+ "build:pages": "tsc -b && vite build --mode pages",
10+ "preview": "vite preview",
11+ "typecheck": "tsc -b"
12+ },
13+ "dependencies": {
14+ "numbl": "file:../../numbl",
15+ "react": "^19.2.0",
16+ "react-dom": "^19.2.0"
17+ },
18+ "devDependencies": {
19+ "@types/react": "^19.2.5",
20+ "@types/react-dom": "^19.2.3",
21+ "@vitejs/plugin-react": "^5.1.1",
22+ "typescript": "~5.9.3",
23+ "vite": "^7.2.4"
24+ }
25+}
public/sample.h5added+0−0View file
Binary file not shown.
src/App.tsxadded+105−0View file
@@ -0,0 +1,105 @@
1+import { useCallback, useRef, useState } from "react";
2+import { importFigureHdf5, FigureView, type FigureState } from "numbl/graphics";
3+
4+export function App() {
5+ const [figure, setFigure] = useState<FigureState | null>(null);
6+ const [fileName, setFileName] = useState<string | null>(null);
7+ const [error, setError] = useState<string | null>(null);
8+ const [loading, setLoading] = useState(false);
9+ const [dragOver, setDragOver] = useState(false);
10+ const inputRef = useRef<HTMLInputElement>(null);
11+
12+ const loadBytes = useCallback(async (bytes: Uint8Array, name: string) => {
13+ setLoading(true);
14+ setError(null);
15+ try {
16+ const fig = await importFigureHdf5(bytes);
17+ setFigure(fig);
18+ setFileName(name);
19+ } catch (e) {
20+ setError(e instanceof Error ? e.message : String(e));
21+ setFigure(null);
22+ setFileName(null);
23+ } finally {
24+ setLoading(false);
25+ }
26+ }, []);
27+
28+ const loadFile = useCallback(
29+ async (file: File) => loadBytes(new Uint8Array(await file.arrayBuffer()), file.name),
30+ [loadBytes]
31+ );
32+
33+ const loadSample = useCallback(async () => {
34+ setLoading(true);
35+ setError(null);
36+ try {
37+ const resp = await fetch(`${import.meta.env.BASE_URL}sample.h5`);
38+ await loadBytes(new Uint8Array(await resp.arrayBuffer()), "sample.h5");
39+ } catch (e) {
40+ setError(e instanceof Error ? e.message : String(e));
41+ setLoading(false);
42+ }
43+ }, [loadBytes]);
44+
45+ return (
46+ <div className="app">
47+ <header>
48+ <h1>numbl figure viewer</h1>
49+ <p className="sub">
50+ Open a <code>.h5</code> figure file exported from{" "}
51+ <a href="https://numbl.org">numbl</a> and view it here. Rendering uses
52+ numbl&rsquo;s own figure components.
53+ </p>
54+ </header>
55+
56+ <div
57+ className={"dropzone" + (dragOver ? " over" : "")}
58+ onClick={() => inputRef.current?.click()}
59+ onDragOver={e => {
60+ e.preventDefault();
61+ setDragOver(true);
62+ }}
63+ onDragLeave={() => setDragOver(false)}
64+ onDrop={e => {
65+ e.preventDefault();
66+ setDragOver(false);
67+ const f = e.dataTransfer.files[0];
68+ if (f) loadFile(f);
69+ }}
70+ >
71+ <input
72+ ref={inputRef}
73+ type="file"
74+ accept=".h5,.hdf5"
75+ style={{ display: "none" }}
76+ onChange={e => {
77+ const f = e.target.files?.[0];
78+ if (f) loadFile(f);
79+ }}
80+ />
81+ {loading
82+ ? "Loading…"
83+ : fileName
84+ ? `Loaded: ${fileName} — click or drop to open another`
85+ : "Click to choose, or drag a .h5 figure file here"}
86+ </div>
87+
88+ <div className="actions">
89+ <button onClick={loadSample} disabled={loading}>
90+ Try a sample figure
91+ </button>
92+ </div>
93+
94+ {error && <div className="error">Failed to open file: {error}</div>}
95+
96+ {figure && (
97+ <div className="figure-wrap">
98+ <div className="figure-inner">
99+ <FigureView figure={figure} />
100+ </div>
101+ </div>
102+ )}
103+ </div>
104+ );
105+}
src/index.cssadded+98−0View file
@@ -0,0 +1,98 @@
1+:root {
2+ font-family: system-ui, -apple-system, sans-serif;
3+ color: #1a1a1a;
4+ background: #fafafa;
5+}
6+
7+* {
8+ box-sizing: border-box;
9+}
10+
11+body {
12+ margin: 0;
13+}
14+
15+.app {
16+ max-width: 960px;
17+ margin: 0 auto;
18+ padding: 24px 16px 48px;
19+}
20+
21+header h1 {
22+ margin: 0 0 4px;
23+ font-size: 1.5rem;
24+}
25+
26+.sub {
27+ margin: 0 0 20px;
28+ color: #555;
29+ font-size: 0.9rem;
30+}
31+
32+.dropzone {
33+ border: 2px dashed #bbb;
34+ border-radius: 8px;
35+ padding: 36px 16px;
36+ text-align: center;
37+ color: #666;
38+ cursor: pointer;
39+ background: #fff;
40+ transition:
41+ border-color 0.15s,
42+ background 0.15s;
43+}
44+
45+.dropzone:hover,
46+.dropzone.over {
47+ border-color: #4a90d9;
48+ background: #f0f7ff;
49+}
50+
51+.actions {
52+ margin-top: 12px;
53+}
54+
55+.actions button {
56+ font: inherit;
57+ font-size: 0.85rem;
58+ padding: 6px 14px;
59+ border: 1px solid #c8c8c8;
60+ border-radius: 6px;
61+ background: #fff;
62+ cursor: pointer;
63+}
64+
65+.actions button:hover:not(:disabled) {
66+ border-color: #4a90d9;
67+ color: #1a5fa8;
68+}
69+
70+.actions button:disabled {
71+ opacity: 0.5;
72+ cursor: default;
73+}
74+
75+.error {
76+ margin-top: 16px;
77+ padding: 10px 14px;
78+ border-radius: 6px;
79+ background: #fdecea;
80+ color: #a12;
81+ font-size: 0.9rem;
82+}
83+
84+.figure-wrap {
85+ margin-top: 20px;
86+ background: #fff;
87+ border: 1px solid #e2e2e2;
88+ border-radius: 8px;
89+ padding: 8px;
90+}
91+
92+/* FigureView fills its positioned parent, mirroring the numbl plot viewer. */
93+.figure-inner {
94+ position: relative;
95+ width: 100%;
96+ height: 70vh;
97+ min-height: 420px;
98+}
src/main.tsxadded+10−0View file
@@ -0,0 +1,10 @@
1+import { StrictMode } from "react";
2+import { createRoot } from "react-dom/client";
3+import { App } from "./App";
4+import "./index.css";
5+
6+createRoot(document.getElementById("root")!).render(
7+ <StrictMode>
8+ <App />
9+ </StrictMode>
10+);
src/vite-env.d.tsadded+1−0View file
@@ -0,0 +1 @@
1+/// <reference types="vite/client" />
tsconfig.app.jsonadded+21−0View file
@@ -0,0 +1,21 @@
1+{
2+ "compilerOptions": {
3+ "target": "ES2022",
4+ "useDefineForClassFields": true,
5+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
6+ "module": "ESNext",
7+ "skipLibCheck": true,
8+ "moduleResolution": "bundler",
9+ "allowImportingTsExtensions": true,
10+ "resolveJsonModule": true,
11+ "isolatedModules": true,
12+ "moduleDetection": "force",
13+ "noEmit": true,
14+ "jsx": "react-jsx",
15+ "strict": true,
16+ "noUnusedLocals": true,
17+ "noUnusedParameters": true,
18+ "noFallthroughCasesInSwitch": true
19+ },
20+ "include": ["src"]
21+}
tsconfig.jsonadded+7−0View file
@@ -0,0 +1,7 @@
1+{
2+ "files": [],
3+ "references": [
4+ { "path": "./tsconfig.app.json" },
5+ { "path": "./tsconfig.node.json" }
6+ ]
7+}
tsconfig.node.jsonadded+15−0View file
@@ -0,0 +1,15 @@
1+{
2+ "compilerOptions": {
3+ "target": "ES2023",
4+ "lib": ["ES2023"],
5+ "module": "ESNext",
6+ "skipLibCheck": true,
7+ "moduleResolution": "bundler",
8+ "allowImportingTsExtensions": true,
9+ "isolatedModules": true,
10+ "moduleDetection": "force",
11+ "noEmit": true,
12+ "strict": true
13+ },
14+ "include": ["vite.config.ts"]
15+}
vite.config.tsadded+14−0View file
@@ -0,0 +1,14 @@
1+import { defineConfig } from "vite";
2+import react from "@vitejs/plugin-react";
3+
4+// https://vite.dev/config/
5+// Served from a project subpath on GitHub Pages when built with `--mode pages`
6+// (https://magland.github.io/numbl-figure-viewer/); local dev/build stays root.
7+export default defineConfig(({ mode }) => ({
8+ base: mode === "pages" ? "/numbl-figure-viewer/" : "/",
9+ plugins: [react()],
10+ // numbl is a linked (file:) dependency, so force a single React instance and
11+ // let Vite descend into the linked package to resolve its imports.
12+ resolve: { dedupe: ["react", "react-dom"] },
13+ optimizeDeps: { exclude: ["numbl"] },
14+}));