diff --git a/apps/web/package.json b/apps/web/package.json
index 31e25ed..09252e3 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -8,6 +8,7 @@
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
+ "test": "vitest",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui"
},
@@ -29,6 +30,8 @@
"@eslint/js": "^9.39.4",
"@playwright/test": "^1.52.0",
"@tailwindcss/vite": "^4.2.2",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
"@types/node": "^24.12.2",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
@@ -37,9 +40,11 @@
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
+ "jsdom": "^29.0.2",
"tailwindcss": "^4.2.2",
"typescript": "~6.0.2",
"typescript-eslint": "^8.58.0",
- "vite": "^8.0.4"
+ "vite": "^8.0.4",
+ "vitest": "^4.1.5"
}
}
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
index b7fb474..e1a0c1c 100644
--- a/apps/web/pnpm-lock.yaml
+++ b/apps/web/pnpm-lock.yaml
@@ -32,18 +32,12 @@ importers:
dayjs:
specifier: ^1.11.20
version: 1.11.20
- i18next:
- specifier: ^26.0.5
- version: 26.0.5(typescript@6.0.2)
react:
specifier: ^19.2.4
version: 19.2.5
react-dom:
specifier: ^19.2.4
version: 19.2.5(react@19.2.5)
- react-i18next:
- specifier: ^17.0.4
- version: 17.0.4(i18next@26.0.5(typescript@6.0.2))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.2)
react-router-dom:
specifier: ^7.14.0
version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
@@ -60,6 +54,12 @@ importers:
'@tailwindcss/vite':
specifier: ^4.2.2
version: 4.2.2(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+ '@testing-library/jest-dom':
+ specifier: ^6.9.1
+ version: 6.9.1
+ '@testing-library/react':
+ specifier: ^16.3.2
+ version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
'@types/node':
specifier: ^24.12.2
version: 24.12.2
@@ -84,6 +84,9 @@ importers:
globals:
specifier: ^17.4.0
version: 17.4.0
+ jsdom:
+ specifier: ^29.0.2
+ version: 29.0.2
tailwindcss:
specifier: ^4.2.2
version: 4.2.2
@@ -96,9 +99,15 @@ importers:
vite:
specifier: ^8.0.4
version: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ vitest:
+ specifier: ^4.1.5
+ version: 4.1.5(@types/node@24.12.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
packages:
+ '@adobe/css-tools@4.4.4':
+ resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
+
'@ant-design/charts-util@0.0.1-alpha.7':
resolution: {integrity: sha512-Yh0o6EdO6SvdSnStFZMbnUzjyymkVzV+TQ9ymVW9hlVgO/fUkUII3JYSdV+UVcFnYwUF0YiDKuSTLCZNAzg2bQ==}
peerDependencies:
@@ -243,6 +252,21 @@ packages:
'@antv/vendor@1.0.11':
resolution: {integrity: sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==}
+ '@asamuzakjp/css-color@5.1.11':
+ resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/dom-selector@7.1.1':
+ resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/generational-cache@1.0.1':
+ resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -314,6 +338,46 @@ packages:
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
engines: {node: '>=6.9.0'}
+ '@bramus/specificity@2.4.2':
+ resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==}
+ hasBin: true
+
+ '@csstools/color-helpers@6.0.2':
+ resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==}
+ engines: {node: '>=20.19.0'}
+
+ '@csstools/css-calc@3.2.0':
+ resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-color-parser@4.1.0':
+ resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0':
+ resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.3':
+ resolution: {integrity: sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==}
+ peerDependencies:
+ css-tree: ^3.2.1
+ peerDependenciesMeta:
+ css-tree:
+ optional: true
+
+ '@csstools/css-tokenizer@4.0.0':
+ resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
+ engines: {node: '>=20.19.0'}
+
'@dnd-kit/accessibility@3.1.1':
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
peerDependencies:
@@ -395,6 +459,15 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@exodus/bytes@1.15.0':
+ resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@noble/hashes': ^1.8.0 || ^2.0.0
+ peerDependenciesMeta:
+ '@noble/hashes':
+ optional: true
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -825,6 +898,9 @@ packages:
'@rolldown/pluginutils@1.0.0-rc.7':
resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
'@tailwindcss/node@4.2.2':
resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==}
@@ -919,9 +995,38 @@ packages:
peerDependencies:
vite: ^5.2.0 || ^6 || ^7 || ^8
+ '@testing-library/dom@10.4.1':
+ resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
+ engines: {node: '>=18'}
+
+ '@testing-library/jest-dom@6.9.1':
+ resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
+ engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+
+ '@testing-library/react@16.3.2':
+ resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@testing-library/dom': ^10.0.0
+ '@types/react': ^18.0.0 || ^19.0.0
+ '@types/react-dom': ^18.0.0 || ^19.0.0
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
+ '@types/chai@5.2.3':
+ resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+
'@types/d3-array@3.2.2':
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
@@ -991,6 +1096,9 @@ packages:
'@types/d3-zoom@3.0.8':
resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==}
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1083,6 +1191,35 @@ packages:
babel-plugin-react-compiler:
optional: true
+ '@vitest/expect@4.1.5':
+ resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==}
+
+ '@vitest/mocker@4.1.5':
+ resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@4.1.5':
+ resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==}
+
+ '@vitest/runner@4.1.5':
+ resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==}
+
+ '@vitest/snapshot@4.1.5':
+ resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==}
+
+ '@vitest/spy@4.1.5':
+ resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==}
+
+ '@vitest/utils@4.1.5':
+ resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==}
+
'@xyflow/react@12.10.2':
resolution: {integrity: sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ==}
peerDependencies:
@@ -1105,10 +1242,18 @@ packages:
ajv@6.14.0:
resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
antd@6.3.5:
resolution: {integrity: sha512-8BPz9lpZWQm42PTx7yL4KxWAotVuqINiKcoYRcLtdd5BFmAcAZicVyFTnBJyRDlzGZFZeRW3foGu6jXYFnej6Q==}
peerDependencies:
@@ -1118,6 +1263,17 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -1140,6 +1296,9 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ bidi-js@1.0.3:
+ resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
+
brace-expansion@1.1.13:
resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
@@ -1166,6 +1325,10 @@ packages:
caniuse-lite@1.0.30001787:
resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==}
+ chai@6.2.2:
+ resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
+ engines: {node: '>=18'}
+
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@@ -1218,6 +1381,13 @@ packages:
css-line-break@2.1.0:
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -1341,6 +1511,10 @@ packages:
dagre@0.8.5:
resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
+ data-urls@7.0.0:
+ resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
dayjs@1.11.20:
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
@@ -1353,6 +1527,9 @@ packages:
supports-color:
optional: true
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -1360,10 +1537,20 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
+ dom-accessibility-api@0.6.3:
+ resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -1375,6 +1562,10 @@ packages:
resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
engines: {node: '>=10.13.0'}
+ entities@8.0.0:
+ resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
+ engines: {node: '>=20.19.0'}
+
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
@@ -1383,6 +1574,9 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
+ es-module-lexer@2.0.0:
+ resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
+
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
@@ -1452,6 +1646,9 @@ packages:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@@ -1459,6 +1656,10 @@ packages:
eventemitter3@5.0.4:
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
+ expect-type@1.3.0:
+ resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
+ engines: {node: '>=12.0.0'}
+
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@@ -1584,21 +1785,14 @@ packages:
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
- html-parse-stringify@3.0.1:
- resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
html2canvas@1.4.1:
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
engines: {node: '>=8.0.0'}
- i18next@26.0.5:
- resolution: {integrity: sha512-9uHb4T27TdV36phJXcbpnRPt5yzAfqHXVrdASvmHZyPuZJtrLythd+GyXhiaHV5LlpuuskbAqhwPjmfTbKbi8w==}
- peerDependencies:
- typescript: ^5 || ^6
- peerDependenciesMeta:
- typescript:
- optional: true
-
iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
@@ -1619,6 +1813,10 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+
internmap@2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
@@ -1640,6 +1838,9 @@ packages:
is-mobile@5.0.0:
resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -1654,6 +1855,15 @@ packages:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
+ jsdom@29.0.2:
+ resolution: {integrity: sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -1767,9 +1977,17 @@ packages:
lodash@4.18.1:
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
+ lru-cache@11.3.5:
+ resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==}
+ engines: {node: 20 || >=22}
+
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1777,6 +1995,9 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
@@ -1785,6 +2006,10 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
+ min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+
minimatch@10.2.5:
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
engines: {node: 18 || 20 || >=22}
@@ -1818,6 +2043,9 @@ packages:
node-releases@2.0.37:
resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==}
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -1834,6 +2062,9 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parse5@8.0.1:
+ resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -1842,6 +2073,9 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
pdfast@0.2.0:
resolution: {integrity: sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==}
@@ -1870,6 +2104,10 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
proxy-from-env@2.1.0:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
@@ -1883,21 +2121,8 @@ packages:
peerDependencies:
react: ^19.2.5
- react-i18next@17.0.4:
- resolution: {integrity: sha512-hQipmK4EF0y6RO6tt6WuqnmWpWYEXmQUUzecmMBuNsIgYd3smXcG4GtYPWhvgxn0pqMOItKlEO8H24HCs5hc3g==}
- peerDependencies:
- i18next: '>= 26.0.1'
- react: '>= 16.8.0'
- react-dom: '*'
- react-native: '*'
- typescript: ^5 || ^6
- peerDependenciesMeta:
- react-dom:
- optional: true
- react-native:
- optional: true
- typescript:
- optional: true
+ react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
@@ -1923,6 +2148,14 @@ packages:
resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==}
engines: {node: '>=0.10.0'}
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -1938,6 +2171,10 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
@@ -1964,6 +2201,9 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
simple-swizzle@0.2.4:
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
@@ -1971,9 +2211,19 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ std-env@4.1.0:
+ resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==}
+
string-convert@0.2.1:
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -2004,6 +2254,9 @@ packages:
svg-path-parser@1.1.0:
resolution: {integrity: sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==}
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
tailwindcss@4.2.2:
resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==}
@@ -2018,10 +2271,36 @@ packages:
resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
engines: {node: '>=12.22'}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@1.1.1:
+ resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==}
+ engines: {node: '>=18'}
+
tinyglobby@0.2.16:
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
engines: {node: '>=12.0.0'}
+ tinyrainbow@3.1.0:
+ resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
+ engines: {node: '>=14.0.0'}
+
+ tldts-core@7.0.28:
+ resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==}
+
+ tldts@7.0.28:
+ resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==}
+ hasBin: true
+
+ tough-cookie@6.0.1:
+ resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
+ engines: {node: '>=16'}
+
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
ts-api-utils@2.5.0:
resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==}
engines: {node: '>=18.12'}
@@ -2050,6 +2329,10 @@ packages:
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+ undici@7.25.0:
+ resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==}
+ engines: {node: '>=20.18.1'}
+
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
@@ -2110,19 +2393,84 @@ packages:
yaml:
optional: true
- void-elements@3.1.0:
- resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
- engines: {node: '>=0.10.0'}
+ vitest@4.1.5:
+ resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==}
+ engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@opentelemetry/api': ^1.9.0
+ '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
+ '@vitest/browser-playwright': 4.1.5
+ '@vitest/browser-preview': 4.1.5
+ '@vitest/browser-webdriverio': 4.1.5
+ '@vitest/coverage-istanbul': 4.1.5
+ '@vitest/coverage-v8': 4.1.5
+ '@vitest/ui': 4.1.5
+ happy-dom: '*'
+ jsdom: '*'
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@opentelemetry/api':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser-playwright':
+ optional: true
+ '@vitest/browser-preview':
+ optional: true
+ '@vitest/browser-webdriverio':
+ optional: true
+ '@vitest/coverage-istanbul':
+ optional: true
+ '@vitest/coverage-v8':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
+ whatwg-mimetype@5.0.0:
+ resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
+ engines: {node: '>=20'}
+
+ whatwg-url@16.0.1:
+ resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@@ -2174,6 +2522,8 @@ packages:
snapshots:
+ '@adobe/css-tools@4.4.4': {}
+
'@ant-design/charts-util@0.0.1-alpha.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
dependencies:
lodash: 4.18.1
@@ -2476,6 +2826,26 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
+ '@asamuzakjp/css-color@5.1.11':
+ dependencies:
+ '@asamuzakjp/generational-cache': 1.0.1
+ '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@asamuzakjp/dom-selector@7.1.1':
+ dependencies:
+ '@asamuzakjp/generational-cache': 1.0.1
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.0.3
+ css-tree: 3.2.1
+ is-potential-custom-element-name: 1.0.1
+
+ '@asamuzakjp/generational-cache@1.0.1': {}
+
+ '@asamuzakjp/nwsapi@2.3.9': {}
+
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -2578,6 +2948,34 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
+ '@bramus/specificity@2.4.2':
+ dependencies:
+ css-tree: 3.2.1
+
+ '@csstools/color-helpers@6.0.2': {}
+
+ '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/color-helpers': 6.0.2
+ '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.3(css-tree@3.2.1)':
+ optionalDependencies:
+ css-tree: 3.2.1
+
+ '@csstools/css-tokenizer@4.0.0': {}
+
'@dnd-kit/accessibility@3.1.1(react@19.2.5)':
dependencies:
react: 19.2.5
@@ -2675,6 +3073,8 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@exodus/bytes@1.15.0': {}
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -3117,6 +3517,8 @@ snapshots:
'@rolldown/pluginutils@1.0.0-rc.7': {}
+ '@standard-schema/spec@1.1.0': {}
+
'@tailwindcss/node@4.2.2':
dependencies:
'@jridgewell/remapping': 2.3.5
@@ -3185,11 +3587,48 @@ snapshots:
tailwindcss: 4.2.2
vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ '@testing-library/dom@10.4.1':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/runtime': 7.29.2
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ picocolors: 1.1.1
+ pretty-format: 27.5.1
+
+ '@testing-library/jest-dom@6.9.1':
+ dependencies:
+ '@adobe/css-tools': 4.4.4
+ aria-query: 5.3.2
+ css.escape: 1.5.1
+ dom-accessibility-api: 0.6.3
+ picocolors: 1.1.1
+ redent: 3.0.0
+
+ '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@testing-library/dom': 10.4.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ optionalDependencies:
+ '@types/react': 19.2.14
+ '@types/react-dom': 19.2.3(@types/react@19.2.14)
+
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
optional: true
+ '@types/aria-query@5.0.4': {}
+
+ '@types/chai@5.2.3':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
+
'@types/d3-array@3.2.2': {}
'@types/d3-color@3.1.3': {}
@@ -3253,6 +3692,8 @@ snapshots:
'@types/d3-interpolate': 3.0.4
'@types/d3-selection': 3.0.11
+ '@types/deep-eql@4.0.2': {}
+
'@types/estree@1.0.8': {}
'@types/geojson@7946.0.16': {}
@@ -3367,6 +3808,47 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.7
vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ '@vitest/expect@4.1.5':
+ dependencies:
+ '@standard-schema/spec': 1.1.0
+ '@types/chai': 5.2.3
+ '@vitest/spy': 4.1.5
+ '@vitest/utils': 4.1.5
+ chai: 6.2.2
+ tinyrainbow: 3.1.0
+
+ '@vitest/mocker@4.1.5(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))':
+ dependencies:
+ '@vitest/spy': 4.1.5
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+
+ '@vitest/pretty-format@4.1.5':
+ dependencies:
+ tinyrainbow: 3.1.0
+
+ '@vitest/runner@4.1.5':
+ dependencies:
+ '@vitest/utils': 4.1.5
+ pathe: 2.0.3
+
+ '@vitest/snapshot@4.1.5':
+ dependencies:
+ '@vitest/pretty-format': 4.1.5
+ '@vitest/utils': 4.1.5
+ magic-string: 0.30.21
+ pathe: 2.0.3
+
+ '@vitest/spy@4.1.5': {}
+
+ '@vitest/utils@4.1.5':
+ dependencies:
+ '@vitest/pretty-format': 4.1.5
+ convert-source-map: 2.0.0
+ tinyrainbow: 3.1.0
+
'@xyflow/react@12.10.2(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
dependencies:
'@xyflow/system': 0.0.76
@@ -3403,10 +3885,14 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ ansi-regex@5.0.1: {}
+
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
+ ansi-styles@5.2.0: {}
+
antd@6.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
dependencies:
'@ant-design/colors': 8.0.1
@@ -3466,6 +3952,14 @@ snapshots:
argparse@2.0.1: {}
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
+ aria-query@5.3.2: {}
+
+ assertion-error@2.0.1: {}
+
asynckit@0.4.0: {}
axios@1.15.0:
@@ -3484,6 +3978,10 @@ snapshots:
baseline-browser-mapping@2.10.17: {}
+ bidi-js@1.0.3:
+ dependencies:
+ require-from-string: 2.0.2
+
brace-expansion@1.1.13:
dependencies:
balanced-match: 1.0.2
@@ -3512,6 +4010,8 @@ snapshots:
caniuse-lite@1.0.30001787: {}
+ chai@6.2.2: {}
+
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
@@ -3558,6 +4058,13 @@ snapshots:
dependencies:
utrie: 1.0.2
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
+ css.escape@1.5.1: {}
+
csstype@3.2.3: {}
d3-array@3.2.4:
@@ -3680,18 +4187,33 @@ snapshots:
graphlib: 2.1.8
lodash: 4.18.1
+ data-urls@7.0.0:
+ dependencies:
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
dayjs@1.11.20: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
+ decimal.js@10.6.0: {}
+
deep-is@0.1.4: {}
delayed-stream@1.0.0: {}
+ dequal@2.0.3: {}
+
detect-libc@2.1.2: {}
+ dom-accessibility-api@0.5.16: {}
+
+ dom-accessibility-api@0.6.3: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -3705,10 +4227,14 @@ snapshots:
graceful-fs: 4.2.11
tapable: 2.3.2
+ entities@8.0.0: {}
+
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
+ es-module-lexer@2.0.0: {}
+
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
@@ -3807,10 +4333,16 @@ snapshots:
estraverse@5.3.0: {}
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
esutils@2.0.3: {}
eventemitter3@5.0.4: {}
+ expect-type@1.3.0: {}
+
fast-deep-equal@3.1.3: {}
fast-json-stable-stringify@2.1.0: {}
@@ -3915,21 +4447,17 @@ snapshots:
dependencies:
hermes-estree: 0.25.1
- html-parse-stringify@3.0.1:
+ html-encoding-sniffer@6.0.0:
dependencies:
- void-elements: 3.1.0
+ '@exodus/bytes': 1.15.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
html2canvas@1.4.1:
dependencies:
css-line-break: 2.1.0
text-segmentation: 1.0.3
- i18next@26.0.5(typescript@6.0.2):
- dependencies:
- '@babel/runtime': 7.29.2
- optionalDependencies:
- typescript: 6.0.2
-
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
@@ -3945,6 +4473,8 @@ snapshots:
imurmurhash@0.1.4: {}
+ indent-string@4.0.0: {}
+
internmap@2.0.3: {}
is-any-array@3.0.0: {}
@@ -3959,6 +4489,8 @@ snapshots:
is-mobile@5.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
isexe@2.0.0: {}
jiti@2.6.1: {}
@@ -3969,6 +4501,32 @@ snapshots:
dependencies:
argparse: 2.0.1
+ jsdom@29.0.2:
+ dependencies:
+ '@asamuzakjp/css-color': 5.1.11
+ '@asamuzakjp/dom-selector': 7.1.1
+ '@bramus/specificity': 2.4.2
+ '@csstools/css-syntax-patches-for-csstree': 1.1.3(css-tree@3.2.1)
+ '@exodus/bytes': 1.15.0
+ css-tree: 3.2.1
+ data-urls: 7.0.0
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.3.5
+ parse5: 8.0.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.1
+ undici: 7.25.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -4049,22 +4607,30 @@ snapshots:
lodash@4.18.1: {}
+ lru-cache@11.3.5: {}
+
lru-cache@5.1.1:
dependencies:
yallist: 3.1.1
+ lz-string@1.5.0: {}
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
math-intrinsics@1.1.0: {}
+ mdn-data@2.27.1: {}
+
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
+ min-indent@1.0.1: {}
+
minimatch@10.2.5:
dependencies:
brace-expansion: 5.0.5
@@ -4100,6 +4666,8 @@ snapshots:
node-releases@2.0.37: {}
+ obug@2.1.1: {}
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -4121,10 +4689,16 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parse5@8.0.1:
+ dependencies:
+ entities: 8.0.0
+
path-exists@4.0.0: {}
path-key@3.1.1: {}
+ pathe@2.0.3: {}
+
pdfast@0.2.0: {}
picocolors@1.1.1: {}
@@ -4147,6 +4721,12 @@ snapshots:
prelude-ls@1.2.1: {}
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+
proxy-from-env@2.1.0: {}
punycode@2.3.1: {}
@@ -4156,16 +4736,7 @@ snapshots:
react: 19.2.5
scheduler: 0.27.0
- react-i18next@17.0.4(i18next@26.0.5(typescript@6.0.2))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@6.0.2):
- dependencies:
- '@babel/runtime': 7.29.2
- html-parse-stringify: 3.0.1
- i18next: 26.0.5(typescript@6.0.2)
- react: 19.2.5
- use-sync-external-store: 1.6.0(react@19.2.5)
- optionalDependencies:
- react-dom: 19.2.5(react@19.2.5)
- typescript: 6.0.2
+ react-is@17.0.2: {}
react-is@18.3.1: {}
@@ -4185,6 +4756,13 @@ snapshots:
react@19.2.5: {}
+ redent@3.0.0:
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+
+ require-from-string@2.0.2: {}
+
resolve-from@4.0.0: {}
rolldown@1.0.0-rc.15:
@@ -4212,6 +4790,10 @@ snapshots:
safer-buffer@2.1.2: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
scheduler@0.27.0: {}
scroll-into-view-if-needed@3.1.0:
@@ -4230,14 +4812,24 @@ snapshots:
shebang-regex@3.0.0: {}
+ siginfo@2.0.0: {}
+
simple-swizzle@0.2.4:
dependencies:
is-arrayish: 0.3.4
source-map-js@1.2.1: {}
+ stackback@0.0.2: {}
+
+ std-env@4.1.0: {}
+
string-convert@0.2.1: {}
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
strip-json-comments@3.1.1: {}
styled-components@6.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
@@ -4257,6 +4849,8 @@ snapshots:
svg-path-parser@1.1.0: {}
+ symbol-tree@3.2.4: {}
+
tailwindcss@4.2.2: {}
tapable@2.3.2: {}
@@ -4267,11 +4861,31 @@ snapshots:
throttle-debounce@5.0.2: {}
+ tinybench@2.9.0: {}
+
+ tinyexec@1.1.1: {}
+
tinyglobby@0.2.16:
dependencies:
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
+ tinyrainbow@3.1.0: {}
+
+ tldts-core@7.0.28: {}
+
+ tldts@7.0.28:
+ dependencies:
+ tldts-core: 7.0.28
+
+ tough-cookie@6.0.1:
+ dependencies:
+ tldts: 7.0.28
+
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+
ts-api-utils@2.5.0(typescript@6.0.2):
dependencies:
typescript: 6.0.2
@@ -4297,6 +4911,8 @@ snapshots:
undici-types@7.16.0: {}
+ undici@7.25.0: {}
+
update-browserslist-db@1.2.3(browserslist@4.28.2):
dependencies:
browserslist: 4.28.2
@@ -4327,14 +4943,65 @@ snapshots:
fsevents: 2.3.3
jiti: 2.6.1
- void-elements@3.1.0: {}
+ vitest@4.1.5(@types/node@24.12.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)):
+ dependencies:
+ '@vitest/expect': 4.1.5
+ '@vitest/mocker': 4.1.5(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+ '@vitest/pretty-format': 4.1.5
+ '@vitest/runner': 4.1.5
+ '@vitest/snapshot': 4.1.5
+ '@vitest/spy': 4.1.5
+ '@vitest/utils': 4.1.5
+ es-module-lexer: 2.0.0
+ expect-type: 1.3.0
+ magic-string: 0.30.21
+ obug: 2.1.1
+ pathe: 2.0.3
+ picomatch: 4.0.4
+ std-env: 4.1.0
+ tinybench: 2.9.0
+ tinyexec: 1.1.1
+ tinyglobby: 0.2.16
+ tinyrainbow: 3.1.0
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 24.12.2
+ jsdom: 29.0.2
+ transitivePeerDependencies:
+ - msw
+
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
+ webidl-conversions@8.0.1: {}
+
+ whatwg-mimetype@5.0.0: {}
+
+ whatwg-url@16.0.1:
+ dependencies:
+ '@exodus/bytes': 1.15.0
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
which@2.0.2:
dependencies:
isexe: 2.0.0
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
word-wrap@1.2.5: {}
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
yallist@3.1.1: {}
yocto-queue@0.1.0: {}
diff --git a/apps/web/src/constants/health.test.ts b/apps/web/src/constants/health.test.ts
new file mode 100644
index 0000000..3753dbc
--- /dev/null
+++ b/apps/web/src/constants/health.test.ts
@@ -0,0 +1,85 @@
+import { describe, it, expect } from 'vitest'
+import {
+ GENDER_OPTIONS,
+ BLOOD_TYPE_OPTIONS,
+ STATUS_OPTIONS,
+} from './health'
+
+describe('GENDER_OPTIONS', () => {
+ it('should be an array with 3 items', () => {
+ expect(GENDER_OPTIONS).toBeInstanceOf(Array)
+ expect(GENDER_OPTIONS).toHaveLength(3)
+ })
+
+ it('each item should have value and label string properties', () => {
+ for (const opt of GENDER_OPTIONS) {
+ expect(opt).toHaveProperty('value')
+ expect(opt).toHaveProperty('label')
+ expect(typeof opt.value).toBe('string')
+ expect(typeof opt.label).toBe('string')
+ }
+ })
+
+ it('should contain expected gender values', () => {
+ const values = GENDER_OPTIONS.map((o) => o.value)
+ expect(values).toEqual(['male', 'female', 'other'])
+ })
+
+ it('should contain expected Chinese labels', () => {
+ const labels = GENDER_OPTIONS.map((o) => o.label)
+ expect(labels).toEqual(['男', '女', '其他'])
+ })
+})
+
+describe('BLOOD_TYPE_OPTIONS', () => {
+ it('should be an array with 4 items', () => {
+ expect(BLOOD_TYPE_OPTIONS).toBeInstanceOf(Array)
+ expect(BLOOD_TYPE_OPTIONS).toHaveLength(4)
+ })
+
+ it('each item should have value and label string properties', () => {
+ for (const opt of BLOOD_TYPE_OPTIONS) {
+ expect(opt).toHaveProperty('value')
+ expect(opt).toHaveProperty('label')
+ expect(typeof opt.value).toBe('string')
+ expect(typeof opt.label).toBe('string')
+ }
+ })
+
+ it('should contain expected blood type values', () => {
+ const values = BLOOD_TYPE_OPTIONS.map((o) => o.value)
+ expect(values).toEqual(['A', 'B', 'AB', 'O'])
+ })
+
+ it('should contain expected Chinese labels', () => {
+ const labels = BLOOD_TYPE_OPTIONS.map((o) => o.label)
+ expect(labels).toEqual(['A 型', 'B 型', 'AB 型', 'O 型'])
+ })
+})
+
+describe('STATUS_OPTIONS', () => {
+ it('should be an array with 4 items', () => {
+ expect(STATUS_OPTIONS).toBeInstanceOf(Array)
+ expect(STATUS_OPTIONS).toHaveLength(4)
+ })
+
+ it('each item should have value and label string properties', () => {
+ for (const opt of STATUS_OPTIONS) {
+ expect(opt).toHaveProperty('value')
+ expect(opt).toHaveProperty('label')
+ expect(typeof opt.value).toBe('string')
+ expect(typeof opt.label).toBe('string')
+ }
+ })
+
+ it('should include an empty-string value for "all statuses" filter', () => {
+ const allOption = STATUS_OPTIONS.find((o) => o.value === '')
+ expect(allOption).toBeDefined()
+ expect(allOption!.label).toBe('全部状态')
+ })
+
+ it('should contain expected status values', () => {
+ const values = STATUS_OPTIONS.map((o) => o.value)
+ expect(values).toEqual(['', 'active', 'inactive', 'deceased'])
+ })
+})
diff --git a/apps/web/src/hooks/useThemeMode.test.ts b/apps/web/src/hooks/useThemeMode.test.ts
new file mode 100644
index 0000000..4dfee01
--- /dev/null
+++ b/apps/web/src/hooks/useThemeMode.test.ts
@@ -0,0 +1,15 @@
+import { describe, it, expect } from 'vitest'
+import { renderHook } from '@testing-library/react'
+import { useThemeMode } from './useThemeMode'
+
+describe('useThemeMode', () => {
+ it('should return false when no ConfigProvider is present (light default)', () => {
+ const { result } = renderHook(() => useThemeMode())
+ expect(result.current).toBe(false)
+ })
+
+ it('should return a boolean value', () => {
+ const { result } = renderHook(() => useThemeMode())
+ expect(typeof result.current).toBe('boolean')
+ })
+})
diff --git a/apps/web/src/pages/health/components/StatusTag.test.tsx b/apps/web/src/pages/health/components/StatusTag.test.tsx
new file mode 100644
index 0000000..a02ded5
--- /dev/null
+++ b/apps/web/src/pages/health/components/StatusTag.test.tsx
@@ -0,0 +1,120 @@
+import { describe, it, expect } from 'vitest'
+import { render, screen } from '@testing-library/react'
+import { StatusTag } from './StatusTag'
+
+describe('StatusTag', () => {
+ describe('appointment statuses', () => {
+ it('renders pending status with gold color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(tag).toHaveClass('ant-tag-gold')
+ expect(screen.getByText('待确认')).toBeInTheDocument()
+ })
+
+ it('renders confirmed status with blue color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-blue')
+ expect(screen.getByText('已确认')).toBeInTheDocument()
+ })
+
+ it('renders completed status with green color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-green')
+ expect(screen.getByText('已完成')).toBeInTheDocument()
+ })
+
+ it('renders cancelled status with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(screen.getByText('已取消')).toBeInTheDocument()
+ })
+
+ it('renders no_show status with red color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-red')
+ expect(screen.getByText('未到诊')).toBeInTheDocument()
+ })
+ })
+
+ describe('follow-up statuses', () => {
+ it('renders overdue status with red color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-red')
+ expect(screen.getByText('逾期')).toBeInTheDocument()
+ })
+
+ it('renders in_progress status with processing color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-processing')
+ expect(screen.getByText('进行中')).toBeInTheDocument()
+ })
+ })
+
+ describe('consultation statuses', () => {
+ it('renders waiting status with gold color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-gold')
+ expect(screen.getByText('等待中')).toBeInTheDocument()
+ })
+
+ it('renders active consultation status with green color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-green')
+ expect(screen.getByText('进行中')).toBeInTheDocument()
+ })
+
+ it('renders closed status with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(screen.getByText('已关闭')).toBeInTheDocument()
+ })
+ })
+
+ describe('patient statuses', () => {
+ it('renders inactive status with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(screen.getByText('停用')).toBeInTheDocument()
+ })
+
+ it('renders deceased status with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(screen.getByText('已故')).toBeInTheDocument()
+ })
+
+ it('renders verified status with green color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toHaveClass('ant-tag-green')
+ expect(screen.getByText('已认证')).toBeInTheDocument()
+ })
+ })
+
+ describe('unknown status fallback', () => {
+ it('renders unknown status text with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ expect(screen.getByText('unknown_status')).toBeInTheDocument()
+ })
+
+ it('renders empty string status with default color', () => {
+ const { container } = render()
+ const tag = container.querySelector('.ant-tag')
+ expect(tag).toBeInTheDocument()
+ })
+ })
+})
diff --git a/apps/web/src/test/setup.ts b/apps/web/src/test/setup.ts
new file mode 100644
index 0000000..c44951a
--- /dev/null
+++ b/apps/web/src/test/setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom'
diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts
new file mode 100644
index 0000000..4935b08
--- /dev/null
+++ b/apps/web/vitest.config.ts
@@ -0,0 +1,18 @@
+import { defineConfig } from 'vitest/config'
+import react from '@vitejs/plugin-react'
+import path from 'path'
+
+export default defineConfig({
+ plugins: [react()],
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ setupFiles: ['./src/test/setup.ts'],
+ exclude: ['e2e/**', 'node_modules/**'],
+ },
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+})