diff --git a/.changeset/brown-bears-cheat.md b/.changeset/brown-bears-cheat.md
new file mode 100644
index 0000000..70be95e
--- /dev/null
+++ b/.changeset/brown-bears-cheat.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+build: upgrade from tsup to tsdown bundler
diff --git a/.changeset/brown-wolves-play.md b/.changeset/brown-wolves-play.md
new file mode 100644
index 0000000..26b3930
--- /dev/null
+++ b/.changeset/brown-wolves-play.md
@@ -0,0 +1,21 @@
+---
+'classic-react-hooks': minor
+---
+
+## Major Rewrite for the Documentation
+- home page and overview
+- use-can-reach-to-internet
+- use-copy-to-clipboard
+- use-counter
+- use-debounced-fn
+- use-event-listener
+- use-intersection-observer
+- use-multi-intersection-observer
+- use-interval-effect
+- use-on-mount-effect
+- use-outside-effect
+- use-synced-effect
+- use-synced-ref
+- use-throttled-fn
+- use-timeout-effect
+- use-window-resize
diff --git a/.changeset/clean-coats-occur.md b/.changeset/clean-coats-occur.md
new file mode 100644
index 0000000..321d05b
--- /dev/null
+++ b/.changeset/clean-coats-occur.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+Doc update
diff --git a/.changeset/cool-emus-lie.md b/.changeset/cool-emus-lie.md
new file mode 100644
index 0000000..21fb956
--- /dev/null
+++ b/.changeset/cool-emus-lie.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+Docs: Update features and overview section
diff --git a/.changeset/cool-spoons-fold.md b/.changeset/cool-spoons-fold.md
new file mode 100644
index 0000000..818efa7
--- /dev/null
+++ b/.changeset/cool-spoons-fold.md
@@ -0,0 +1,6 @@
+---
+'classic-react-hooks': minor
+---
+
+Feature:
+- Add cross-tab sync and ssr support and function based initial value support for `useLocalStorage` hook.
diff --git a/.changeset/cuddly-melons-turn.md b/.changeset/cuddly-melons-turn.md
new file mode 100644
index 0000000..fbb3420
--- /dev/null
+++ b/.changeset/cuddly-melons-turn.md
@@ -0,0 +1,10 @@
+---
+'classic-react-hooks': minor
+---
+
+
+- Doc: Add `what problem it solves` doc for useCanReachToInternet
+- Doc: Refactor the docs for hooks
+
+
+
diff --git a/.changeset/early-apes-march.md b/.changeset/early-apes-march.md
new file mode 100644
index 0000000..bcc640e
--- /dev/null
+++ b/.changeset/early-apes-march.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+- Update dependencies, pnpm and node version for better security and performance
diff --git a/.changeset/eight-webs-look.md b/.changeset/eight-webs-look.md
new file mode 100644
index 0000000..59c11c1
--- /dev/null
+++ b/.changeset/eight-webs-look.md
@@ -0,0 +1,7 @@
+---
+'classic-react-hooks': minor
+---
+
+New api and props for use-debounced-fn
+- Introduce cleanup and debouncedFn return value
+- Introduce immediateCallback, onSuccess, onError and onFinally callback as lifecycle functions
diff --git a/.changeset/fresh-hounds-move.md b/.changeset/fresh-hounds-move.md
new file mode 100644
index 0000000..385ac7b
--- /dev/null
+++ b/.changeset/fresh-hounds-move.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+Include src folder in npm publish
diff --git a/.changeset/good-vans-impress.md b/.changeset/good-vans-impress.md
new file mode 100644
index 0000000..f77dbf2
--- /dev/null
+++ b/.changeset/good-vans-impress.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+Add CanReachToInterernetCtxProvder and useCanReachToInternetCtx component's documentation
diff --git a/.changeset/hungry-moons-serve.md b/.changeset/hungry-moons-serve.md
new file mode 100644
index 0000000..50d848a
--- /dev/null
+++ b/.changeset/hungry-moons-serve.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+Feat: Introduce `layoutEffect` boolean prop in use-event-listener hook to pickup `useEffect` between `useLayoutEffect`. By default `useEffect` hook will be used.
+Feat: Using layoutEffect for use-window-resize hook.
diff --git a/.changeset/icy-boats-make.md b/.changeset/icy-boats-make.md
new file mode 100644
index 0000000..283b98e
--- /dev/null
+++ b/.changeset/icy-boats-make.md
@@ -0,0 +1,7 @@
+---
+'classic-react-hooks': major
+---
+
+Breaking
+- v2 release prepare
+- Rewrite all of the hooks and their documenation
diff --git a/.changeset/mighty-donkeys-roll.md b/.changeset/mighty-donkeys-roll.md
new file mode 100644
index 0000000..d2065d6
--- /dev/null
+++ b/.changeset/mighty-donkeys-roll.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+ref: Initialize context lazily within ContextProvider component for can-reach-to-internet-context
diff --git a/.changeset/modern-ants-add.md b/.changeset/modern-ants-add.md
new file mode 100644
index 0000000..0ae5fd6
--- /dev/null
+++ b/.changeset/modern-ants-add.md
@@ -0,0 +1,7 @@
+---
+'classic-react-hooks': minor
+---
+
+
+- breaking: use the implementation and working for `useIntersection` observer hook.
+- feat: introduce new hook `useMultiIntersectionObserver` hook.
\ No newline at end of file
diff --git a/.changeset/moody-pens-poke.md b/.changeset/moody-pens-poke.md
new file mode 100644
index 0000000..662995a
--- /dev/null
+++ b/.changeset/moody-pens-poke.md
@@ -0,0 +1,12 @@
+---
+'classic-react-hooks': minor
+---
+
+
+## Fixes following issues
+- Fix: use-can-reach-to-internet `subscribe` handler for `useSyncExternalStore`. It was adding events instead of removing.
+- Fix: Prevent from re-triggering the call of `checkIfCanReachToInternet` function in useEffect when `isNetworkPollingEnabled` is disabled.
+
+## Test cases
+- Wrote test cases for use-can-reach-to-internet and use-copy-to-clipboard hook. Previously not written.
+
diff --git a/.changeset/pink-pugs-eat.md b/.changeset/pink-pugs-eat.md
new file mode 100644
index 0000000..1f06d8e
--- /dev/null
+++ b/.changeset/pink-pugs-eat.md
@@ -0,0 +1,7 @@
+---
+'classic-react-hooks': minor
+---
+
+- breaking: remove useIsOnline hook
+- Feat: add useCanReachToInternet for getting network connection
+- Feat: add useCanReachToInternetCtx and CanReachToInternetCtxProvider for subscribing the application to get network reachability with context
\ No newline at end of file
diff --git a/.changeset/popular-students-happen.md b/.changeset/popular-students-happen.md
new file mode 100644
index 0000000..d63ba9f
--- /dev/null
+++ b/.changeset/popular-students-happen.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+Add canary branch in CI release
diff --git a/.changeset/pre.json b/.changeset/pre.json
new file mode 100644
index 0000000..cb9634f
--- /dev/null
+++ b/.changeset/pre.json
@@ -0,0 +1,37 @@
+{
+ "mode": "pre",
+ "tag": "canary",
+ "initialVersions": {
+ "classic-react-hooks": "1.4.0"
+ },
+ "changesets": [
+ "brown-bears-cheat",
+ "brown-wolves-play",
+ "clean-coats-occur",
+ "cool-emus-lie",
+ "cool-spoons-fold",
+ "cuddly-melons-turn",
+ "early-apes-march",
+ "eight-webs-look",
+ "fresh-hounds-move",
+ "good-vans-impress",
+ "hungry-moons-serve",
+ "icy-boats-make",
+ "mighty-donkeys-roll",
+ "modern-ants-add",
+ "moody-pens-poke",
+ "pink-pugs-eat",
+ "popular-students-happen",
+ "silver-radios-tickle",
+ "slick-carrots-stick",
+ "spotty-jeans-carry",
+ "stale-radios-rule",
+ "tender-sites-occur",
+ "thirty-foxes-wink",
+ "twenty-pans-search",
+ "violet-cherries-applaud",
+ "warm-olives-punch",
+ "wet-states-wink",
+ "yellow-nails-worry"
+ ]
+}
diff --git a/.changeset/silver-radios-tickle.md b/.changeset/silver-radios-tickle.md
new file mode 100644
index 0000000..a9ac39e
--- /dev/null
+++ b/.changeset/silver-radios-tickle.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+- Fix timeout and interval effect cleanup when interval changes
diff --git a/.changeset/slick-carrots-stick.md b/.changeset/slick-carrots-stick.md
new file mode 100644
index 0000000..506615f
--- /dev/null
+++ b/.changeset/slick-carrots-stick.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+Update target build to esnext in builder
diff --git a/.changeset/spotty-jeans-carry.md b/.changeset/spotty-jeans-carry.md
new file mode 100644
index 0000000..7ed304b
--- /dev/null
+++ b/.changeset/spotty-jeans-carry.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+- Fix missing export for `useMultipleIntersectionObserver` hook
diff --git a/.changeset/stale-radios-rule.md b/.changeset/stale-radios-rule.md
new file mode 100644
index 0000000..a34b42d
--- /dev/null
+++ b/.changeset/stale-radios-rule.md
@@ -0,0 +1,6 @@
+---
+'classic-react-hooks': patch
+---
+
+Docs: Start overhauling to new documentation
+- Create new docs for `use-event-listener` and `use-intersection-observer` hooks
diff --git a/.changeset/tender-sites-occur.md b/.changeset/tender-sites-occur.md
new file mode 100644
index 0000000..b42eec7
--- /dev/null
+++ b/.changeset/tender-sites-occur.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+Docs - add usage example in js-doc for all of the hooks
diff --git a/.changeset/thirty-foxes-wink.md b/.changeset/thirty-foxes-wink.md
new file mode 100644
index 0000000..7fef3ed
--- /dev/null
+++ b/.changeset/thirty-foxes-wink.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+- Introduce second method `setElementRef` function for observing target with `ref` attribute (i.e. ref={setElementRef})
diff --git a/.changeset/twenty-pans-search.md b/.changeset/twenty-pans-search.md
new file mode 100644
index 0000000..e6cde0f
--- /dev/null
+++ b/.changeset/twenty-pans-search.md
@@ -0,0 +1,17 @@
+---
+'classic-react-hooks': minor
+---
+
+## Doc Fixes
+- docs: fix imports in js-doc examples
+- types: Update type definitions to common types folder
+- docs: update docs for hooks
+
+## Test Updates
+- test: refactor and add new the test cases
+
+## Bug Fixes
+- fix: network state update on online/offline event when polling is off(7c765e984556b8496667dd057ca20bc6586e82b6)
+- fix: create seperate setElementRef for target setting in use-outside-click(ff812ca88e527c12b3604fb559c1b3d6b87ca7d9)
+- fix: making capture flag to false for use-outside-click(fd31ba46b569ed298de6c7a445204beea2c57284)
+- fix: lazily set target for outside and use-event-listener(1a387a1fe05dc8a736a629d8a66d067a3162340e)
diff --git a/.changeset/violet-cherries-applaud.md b/.changeset/violet-cherries-applaud.md
new file mode 100644
index 0000000..4dc67d5
--- /dev/null
+++ b/.changeset/violet-cherries-applaud.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': patch
+---
+
+Update docs for copy-to-clipboard and deboucned-fn hook
diff --git a/.changeset/warm-olives-punch.md b/.changeset/warm-olives-punch.md
new file mode 100644
index 0000000..4cd50cb
--- /dev/null
+++ b/.changeset/warm-olives-punch.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+docs: revamp to new doc version for `use-multi-intersection-observer`
diff --git a/.changeset/wet-states-wink.md b/.changeset/wet-states-wink.md
new file mode 100644
index 0000000..1ec1aa7
--- /dev/null
+++ b/.changeset/wet-states-wink.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+Feature: Add AbortSignal api support for use-debounced-fn hook for cancelling the async work
diff --git a/.changeset/yellow-nails-worry.md b/.changeset/yellow-nails-worry.md
new file mode 100644
index 0000000..e966bef
--- /dev/null
+++ b/.changeset/yellow-nails-worry.md
@@ -0,0 +1,5 @@
+---
+'classic-react-hooks': minor
+---
+
+feat: add `encoder` and `decoder` props in useLocalStorage for encoding/decoding value in localStorage
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..4ad820f
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 3
+tab_width = 3
+max_line_length = 120
+trim_trailing_whitespace = true
+insert_final_newline = true
\ No newline at end of file
diff --git a/.github/workflows/canary-publish.yml b/.github/workflows/canary-publish.yml
new file mode 100644
index 0000000..232da07
--- /dev/null
+++ b/.github/workflows/canary-publish.yml
@@ -0,0 +1,32 @@
+name: Publish
+on:
+ push:
+ branches:
+ - canary
+
+concurrency: ${{ github.workflow }}-${{ github.ref }}
+
+jobs:
+ canary:
+ runs-on: 'ubuntu-latest'
+ permissions: write-all
+ steps:
+ - uses: actions/checkout@v3
+ - uses: pnpm/action-setup@v4
+ # with:
+ # version: 8
+ - uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node }}
+ cache: 'pnpm'
+
+ - run: pnpm install --no-frozen-lockfile
+
+ - name: Create Canary Release Pull Request or Canary Publish
+ id: changesets
+ uses: changesets/action@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+ with:
+ publish: pnpm release
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 5730f80..81a61de 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -3,6 +3,7 @@ on:
pull_request:
branches:
- 'main'
+ - 'canary'
jobs:
build:
diff --git a/.gitignore b/.gitignore
index f8c4d87..0d893a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,8 @@ apps/*
apps/doc/.vitepress/cache
-src/**/*.dev.tsx
\ No newline at end of file
+/**/*.dev.tsx
+/**/*.dev.ts
+/**/*.dev.jsx
+/**/*.dev.js
+/**/*.dev.md
diff --git a/.nvmrc b/.nvmrc
index e06fc80..fc37597 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-18.14.2
\ No newline at end of file
+22.17.0
diff --git a/.prettierignore b/.prettierignore
index 71c4766..306851e 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,4 +4,6 @@ node_modules
public
apps/doc/.vitepress/cache
apps/example
-.changeset
\ No newline at end of file
+.changeset
+
+pnpm-lock.yaml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d89d03..5f3329f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,223 @@
# classic-react-hooks
+## 2.0.0-canary.27
+
+### Minor Changes
+
+- 8a2a4b7: Feature: Add AbortSignal api support for use-debounced-fn hook for cancelling the async work
+
+## 2.0.0-canary.26
+
+### Minor Changes
+
+- 4fc9b6c: feat: add `encoder` and `decoder` props in useLocalStorage for encoding/decoding value in localStorage
+
+## 2.0.0-canary.25
+
+### Minor Changes
+
+- 2358a55: New api and props for use-debounced-fn
+ - Introduce cleanup and debouncedFn return value
+ - Introduce immediateCallback, onSuccess, onError and onFinally callback as lifecycle functions
+
+## 2.0.0-canary.24
+
+### Patch Changes
+
+- ab12cc5: build: upgrade from tsup to tsdown bundler
+
+## 2.0.0-canary.23
+
+### Minor Changes
+
+- a0c4e96: ref: Initialize context lazily within ContextProvider component for can-reach-to-internet-context
+
+## 2.0.0-canary.22
+
+### Minor Changes
+
+- 5e43e42: Update target build to esnext in builder
+
+## 2.0.0-canary.21
+
+### Minor Changes
+
+- f5197b4: ## Doc Fixes
+
+ - docs: fix imports in js-doc examples
+ - types: Update type definitions to common types folder
+ - docs: update docs for hooks
+
+ ## Test Updates
+
+ - test: refactor and add new the test cases
+
+ ## Bug Fixes
+
+ - fix: network state update on online/offline event when polling is off(7c765e984556b8496667dd057ca20bc6586e82b6)
+ - fix: create seperate setElementRef for target setting in use-outside-click(ff812ca88e527c12b3604fb559c1b3d6b87ca7d9)
+ - fix: making capture flag to false for use-outside-click(fd31ba46b569ed298de6c7a445204beea2c57284)
+ - fix: lazily set target for outside and use-event-listener(1a387a1fe05dc8a736a629d8a66d067a3162340e)
+
+## 2.0.0-canary.20
+
+### Patch Changes
+
+- f8af3e3: - Update dependencies, pnpm and node version for better security and performance
+
+## 2.0.0-canary.19
+
+### Minor Changes
+
+- c534ff5: - Introduce second method `setElementRef` function for observing target with `ref` attribute (i.e. ref={setElementRef})
+
+## 2.0.0-canary.18
+
+### Minor Changes
+
+- 8305b6d: - Fix missing export for `useMultipleIntersectionObserver` hook
+
+## 2.0.0-canary.17
+
+### Minor Changes
+
+- 0d1ac96: - Fix timeout and interval effect cleanup when interval changes
+
+## 2.0.0-canary.16
+
+### Minor Changes
+
+- 87b8bbb: Feature:
+ - Add cross-tab sync and ssr support and function based initial value support for `useLocalStorage` hook.
+
+## 2.0.0-canary.15
+
+### Minor Changes
+
+- fb26e91: ## Fixes following issues
+
+ - Fix: use-can-reach-to-internet `subscribe` handler for `useSyncExternalStore`. It was adding events instead of removing.
+ - Fix: Prevent from re-triggering the call of `checkIfCanReachToInternet` function in useEffect when `isNetworkPollingEnabled` is disabled.
+
+ ## Test cases
+
+ - Wrote test cases for use-can-reach-to-internet and use-copy-to-clipboard hook. Previously not written.
+
+## 2.0.0-canary.14
+
+### Minor Changes
+
+- a2f9744: ## Major Rewrite for the Documentation
+ - home page and overview
+ - use-can-reach-to-internet
+ - use-copy-to-clipboard
+ - use-counter
+ - use-debounced-fn
+ - use-event-listener
+ - use-intersection-observer
+ - use-multi-intersection-observer
+ - use-interval-effect
+ - use-on-mount-effect
+ - use-outside-effect
+ - use-synced-effect
+ - use-synced-ref
+ - use-throttled-fn
+ - use-timeout-effect
+ - use-window-resize
+
+## 2.0.0-canary.13
+
+### Minor Changes
+
+- ff4615c: docs: revamp to new doc version for `use-multi-intersection-observer`
+
+## 2.0.0-canary.12
+
+### Patch Changes
+
+- 5877980: Docs: Start overhauling to new documentation
+ - Create new docs for `use-event-listener` and `use-intersection-observer` hooks
+
+## 2.0.0-canary.11
+
+### Minor Changes
+
+- 4f5bb6c: - breaking: use the implementation and working for `useIntersection` observer hook.
+ - feat: introduce new hook `useMultiIntersectionObserver` hook.
+
+## 2.0.0-canary.10
+
+### Patch Changes
+
+- 5807a38: Add canary branch in CI release
+
+## 2.0.0-canary.9
+
+### Minor Changes
+
+- e73af53: Feat: Introduce `layoutEffect` boolean prop in use-event-listener hook to pickup `useEffect` between `useLayoutEffect`. By default `useEffect` hook will be used.
+ Feat: Using layoutEffect for use-window-resize hook.
+
+## 2.0.0-canary.8
+
+### Patch Changes
+
+- 56478c2: Docs: Update features and overview section
+
+## 2.0.0-canary.7
+
+### Patch Changes
+
+- cc71e9c: Update docs for copy-to-clipboard and deboucned-fn hook
+
+## 2.0.0-canary.6
+
+### Patch Changes
+
+- c20ae22: Include src folder in npm publish
+
+## 2.0.0-canary.5
+
+### Minor Changes
+
+- 51e96f8: Doc update
+
+## 2.0.0-canary.4
+
+### Minor Changes
+
+- c52bb9f: Add CanReachToInterernetCtxProvder and useCanReachToInternetCtx component's documentation
+
+## 2.0.0-canary.3
+
+### Minor Changes
+
+- 3e110b2: - Doc: Add `what problem it solves` doc for useCanReachToInternet
+ - Doc: Refactor the docs for hooks
+
+## 2.0.0-canary.2
+
+### Minor Changes
+
+- 703c876: - breaking: remove useIsOnline hook
+ - Feat: add useCanReachToInternet for getting network connection
+ - Feat: add useCanReachToInternetCtx and CanReachToInternetCtxProvider for subscribing the application to get network reachability with context
+
+## 2.0.0-canary.1
+
+### Minor Changes
+
+- 44ce4b9: Docs - add usage example in js-doc for all of the hooks
+
+## 2.0.0-canary.0
+
+### Major Changes
+
+Breaking
+
+- v2 release prepare
+- Rewrite all of the hooks and their documenation
+
## 1.4.0
### Minor Changes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7580c6e..689aa42 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,28 +2,52 @@
Hi! We are really excited that you are interested in contributing to classic-react-hooks. Before submitting your contribution, please make sure to take a moment and read through the following guide:
-## Repo Setup
-The package manager used to install and link dependencies should be [pnpm](https://pnpm.io/) v8.12.0 or higher. NodeJS version should be v18.14.2 or higher
+## 🔧 System Requirements
+- [Node.js](https://nodejs.org/en) v16 or higher
+- [Pnpm](https://pnpm.io/) v8 or higher
-1. Run `pnpm install` in root folder
-2. Run `pnpm run build` to build the package
+----
+## 🏗️ Repo Setup
-3. Run `pnpm run test` to run the test cases
+```bash
+git clone https://github.com/Ashish-simpleCoder/classic-react-hooks.git
-4. Run `pnpm run format` to format all of the coding with prettier
+cd classic-react-hooks
+```
-## Pull Request Guidelines
+
+### Install dependencies
+```sh
+pnpm install
+```
+
+### Build project
+```sh
+pnpm build
+```
+### Run tests
+```sh
+pnpm test
+```
+### Format code
+```sh
+pnpm format
+```
+
+
+----
+## 🔃 Pull Request Guidelines
- Checkout a topic branch from a base branch, e.g. `main`, and merge back against that branch.
- If adding a new feature:
- - Add accompanying test case.
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
+ - Add accompanying test case.
-- If fixing bug:
+- If fixing a bug:
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update fetch logic (fix #3899)`.
- Provide a detailed description of the bug in the PR. Live demo preferred.
@@ -35,9 +59,13 @@ The package manager used to install and link dependencies should be [pnpm](https
- Use `pnpm format` to format files according to the project guidelines.
-## Documenation Guidelines
-- To contribute in the documentation, go to apps/doc directory
+---
+## 📄 Documenation Guidelines
+
+To contribute in the documentation, go to `apps/doc` directory
+
+### Steps to contribute
1. Run `pnpm install` to install all of the dependencies
diff --git a/LICENSE b/LICENSE
index e01b318..50d96b4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2022 Ashish Prajapati
+Copyright (c) 2022-Present Ashish Prajapati
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/README.md b/README.md
index 537715b..d1e0e09 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# 🚀 classic-react-hooks
-#### An awesome collection of `feature packed custom hooks`.
-
+Performant · Minimal · Lightweight collection of everyday hooks
+
@@ -18,59 +18,64 @@
+
+
## Read the Documentation
https://classic-react-hooks.vercel.app/
-## Features
+## ✨ Features
-- Comes with treeshaking
-- Typescript support
-- Small bundle size
-- Minimal and Easy to use
+- A carefully curated set of feature-rich, general-purpose hooks
+- High performance with a minimal and lightweight footprint
+- Predictable, intuitive APIs designed for natural usage
+- Strong TypeScript support with an emphasis on type safety
+- Zero third-party dependencies
+- Modular and declarative design principles
+- Fully tree-shakable for optimal bundling
+- Comprehensive, well-structured documentation
-## Installation
+## 🛠️ Tech Stack
+- React 18 with TypeScript
+- Vitepress for documentation
+- Changeset for sementic version releases
+- Vitest & React-Testing-Library for testing
+- tsdown for build tooling
-For npm users
-```bash
+## 🚀 Install in your project
+
+For npm users
+```bash [npm]
$ npm install classic-react-hooks
```
For pnpm users
+```bash [pnpm]
+$ pnpm add classic-react-hooks
+```
-```bash
-$ pnpm install classic-react-hooks
+For deno users
+```bash [deno]
+$ deno install classic-react-hooks
```
For yarn users
-
-```bash
+```bash [yarn]
$ yarn add classic-react-hooks
```
For bun users
-
-```bash
+```bash [bun]
$ bun add classic-react-hooks
```
-## Hooks
-- use-event-listener
-- use-copy-to-clipboard
-- use-local-storage
-- use-outside-click
-- use-debounced-fn
-- use-throttled-hook
-- use-is-online
-- use-timeout-effect
-- use-interval-effect
-- use-synced-ref
-- use-synced-effect
-- use-on-mount-effect
-- use-counter
-
-## Contribution
+## 📝 Contribution
See [Contributing Guide](https://github.com/Ashish-simpleCoder/classic-react-hooks/blob/main/CONTRIBUTING.md).
+
+
+## 📄 License
+- This project is licensed under the MIT License - see the LICENSE file for details.
+Copyright (c) 2022-present, Ashish Prajapati
diff --git a/apps/doc/.vitepress/config.mts b/apps/doc/.vitepress/config.mts
index ae0a2f4..53c085b 100644
--- a/apps/doc/.vitepress/config.mts
+++ b/apps/doc/.vitepress/config.mts
@@ -1,5 +1,6 @@
import { defineConfig, type DefaultTheme } from 'vitepress'
import { version } from '../../../package.json'
+import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons'
// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -10,6 +11,17 @@ export default defineConfig({
lastUpdated: true,
cleanUrls: false,
+ markdown: {
+ lineNumbers: true,
+ config(md) {
+ md.use(groupIconMdPlugin)
+ },
+ },
+
+ vite: {
+ plugins: [groupIconVitePlugin()],
+ },
+
sitemap: {
hostname: 'https://classic-react-hooks.vercel.app',
transformItems(items) {
@@ -32,7 +44,28 @@ export default defineConfig({
},
{
text: `v${version}`,
- link: `https://github.com/Ashish-simpleCoder/classic-react-hooks/releases/tag/v${version}`,
+ items: [
+ {
+ items: [
+ {
+ text: `v${version}`,
+ link: `https://github.com/Ashish-simpleCoder/classic-react-hooks/releases/tag/v${version}`,
+ },
+ ],
+ },
+ {
+ items: [
+ {
+ text: 'Unreleased',
+ link: `https://canary-classic-react-hooks.vercel.app/`,
+ },
+ {
+ text: 'v1.x',
+ link: `https://v1-classic-react-hooks.vercel.app`,
+ },
+ ],
+ },
+ ],
},
],
@@ -52,9 +85,10 @@ export default defineConfig({
icon: 'github',
link: 'https://github.com/Ashish-simpleCoder/classic-react-hooks',
},
- { icon: 'x', link: 'https://twitter.com/ashish_devloper' },
{ icon: 'linkedin', link: 'https://linkedin.com/in/ashish-prajapati-002154193' },
+ { icon: 'bluesky', link: 'https://bsky.app/profile/ashish-simplecoder.bsky.social' },
{ icon: 'npm', link: 'https://www.npmjs.com/package/classic-react-hooks' },
+ { icon: 'x', link: 'https://twitter.com/ashish_devloper' },
],
editLink: {
pattern: 'https://github.com/Ashish-simpleCoder/classic-react-hooks/edit/main/apps/doc/:path',
@@ -86,13 +120,14 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
items: [
{ text: 'use-event-listener', link: 'use-event-listener' },
{ text: 'use-intersection-observer', link: 'use-intersection-observer' },
+ { text: 'use-multi-intersection-observer', link: 'use-multi-intersection-observer' },
{ text: 'use-window-resize', link: 'use-window-resize' },
{ text: 'use-copy-to-clipboard', link: 'use-copy-to-clipboard' },
{ text: 'use-local-storage', link: 'use-local-storage' },
{ text: 'use-outside-click', link: 'use-outside-click' },
{ text: 'use-debounced-fn', link: 'use-debounced-fn' },
{ text: 'use-throttled-fn', link: 'use-throttled-fn' },
- { text: 'use-is-online', link: 'use-is-online' },
+ { text: 'use-can-reach-to-internet', link: 'use-can-reach-to-internet' ,collapsed: true},
{ text: 'use-timeout-effect', link: 'use-timeout-effect' },
{ text: 'use-interval-effect', link: 'use-interval-effect' },
{ text: 'use-synced-ref', link: 'use-synced-ref' },
@@ -101,5 +136,13 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
{ text: 'use-counter', link: 'use-counter' },
]
},
+ {
+ text: 'Components',
+ collapsed: false,
+ base: "/components/",
+ items: [
+ { text: 'Internet Connectivity Context', link: 'CanReachToInternetCtxProvider' },
+ ]
+ },
]
}
diff --git a/apps/doc/.vitepress/theme/index.ts b/apps/doc/.vitepress/theme/index.ts
index 2323d71..cac02b2 100644
--- a/apps/doc/.vitepress/theme/index.ts
+++ b/apps/doc/.vitepress/theme/index.ts
@@ -2,6 +2,8 @@
import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
+
+import 'virtual:group-icons.css'
import './style.css'
export default {
diff --git a/apps/doc/.vitepress/theme/style.css b/apps/doc/.vitepress/theme/style.css
index 377620f..9f98b07 100644
--- a/apps/doc/.vitepress/theme/style.css
+++ b/apps/doc/.vitepress/theme/style.css
@@ -8,7 +8,7 @@
*
* Each colors have exact same color scale system with 3 levels of solid
* colors with different brightness, and 1 soft color.
- *
+ *
* - `XXX-1`: The most solid color used mainly for colored text. It must
* satisfy the contrast ratio against when used on top of `XXX-soft`.
*
@@ -128,3 +128,11 @@
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}
+
+/* Dynamic color for icons in index.md */
+html.dark .icon-color-theme {
+ fill: #e7e7e7;
+}
+.icon-color-theme {
+ fill: currentColor;
+}
diff --git a/apps/doc/components/CanReachToInternetCtxProvider.md b/apps/doc/components/CanReachToInternetCtxProvider.md
new file mode 100644
index 0000000..3eade04
--- /dev/null
+++ b/apps/doc/components/CanReachToInternetCtxProvider.md
@@ -0,0 +1,90 @@
+---
+outline: deep
+---
+
+# Internet Connectivity Context
+
+A React Context provider and hook for sharing internet connectivity status across your component tree without prop drilling.
+
+Built on top of the [useCanReachToInternet](/hooks/use-can-reach-to-internet.html) hook to provide centralized connectivity monitoring.
+
+## Features
+
+- **Centralized connectivity state:** Share connectivity status across your entire app
+- **No prop drilling:** Access connectivity data from any component in the tree
+- **Same configuration options:** All `useCanReachToInternet` options available at provider level
+
+## Components & Hooks
+
+### CanReachToInternetCtxProvider
+
+A context provider component that wraps your application to provide connectivity status to all child components.
+
+It takes following props
+
+| Parameter | Type | Required | Default Value | Description |
+| ---------------------- | :-------: | :------: | :----------------: | --------------------------------------------------------------------------- |
+| children | ReactNode | ✅ | - | React children components that will have access to the connectivity context |
+| enableNetworkPolling | boolean | ❌ | true | Enable automatic network polling to continuously check connectivity |
+| networkPollingInterval | number | ❌ | 3000 | Interval in milliseconds between network polls |
+| testUrl | string | ❌ | https://dns.google | URL to test internet connectivity against |
+
+### useCanReachToInternetCtx
+
+A custom hook to consume the internet connectivity context values.
+
+Return value(s):
+
+| Property | Type | Description |
+| --------------------------- | ------------- | -------------------------------------------------------------------------------- |
+| isOnline | boolean | Browser's native online/offline status from `navigator.onLine` |
+| canReachToInternet | boolean | Whether the device can actually reach the internet (verified via HTTP request) |
+| isFullyConnected | boolean | Combined status: `true` when both `isOnline` and `canReachToInternet` are `true` |
+| isNetworkPollingEnabled | boolean | Current state of automatic network polling |
+| isCheckingConnection | boolean | Whether a connectivity check is currently in progress |
+| startNetworkPolling | () => void | Function to start automatic network polling |
+| stopNetworkPolling | () => void | Function to stop automatic network polling |
+| forceCheckNetwork | () => void | Function to manually trigger a connectivity check |
+| getCanReachToInternetStatus | () => boolean | Function to get current internet reachability status |
+
+## Usage Examples
+
+### Basic App Setup
+
+```tsx
+import { CanReachToInternetCtxProvider } from 'classic-react-hooks'
+
+function App() {
+ return (
+
+
+
+
+
+ )
+}
+```
+
+### Custom Configuration
+
+::: details Example
+
+```tsx
+import { CanReachToInternetCtxProvider } from 'classic-react-hooks'
+
+function App() {
+ return (
+
+
+
+
+
+ )
+}
+```
+
+:::
diff --git a/apps/doc/getting-started/overview.md b/apps/doc/getting-started/overview.md
index 7904c90..0b9708a 100644
--- a/apps/doc/getting-started/overview.md
+++ b/apps/doc/getting-started/overview.md
@@ -1,35 +1,58 @@
# Overview
-## What is **classic-react-hooks**?
+**_`classic-react-hooks`_** is a lightweight yet robust collection of custom React hooks and components designed to simplify common development tasks without sacrificing clarity or control.
-- **`classic-react-hooks`** is collection of feature packed custom react hooks
-- It helps you to write day-to-day code in a manner which is easy to write, declarative and maintainable.
+The library encourages _clean_, _declarative_, _modular_, and _predictable_ code, helping teams build applications that remain maintainable and scalable as complexity grows.
+
+Built entirely with **TypeScript**, **`classic-react-hooks`** prioritizes strong type safety while remaining _minimal_, _tree-shakable_, and optimized for modern React environments. All hooks are fully compatible with server-side rendering _(SSR)_, ensuring consistent behavior and preventing hydration mismatches.
+
+The library is thoroughly tested using **Vitest** and **React Testing Library**, covering a broad range of real-world use cases. Contributions—especially additional test cases—are always welcome.
+
+## Motivation
+
+**_`classic-react-hooks`_** exists to provide a _focused_, _predictable_, and _developer-friendly_ set of React hooks that emphasize clarity, consistency, and long-term maintainability.
+
+Rather than offering a sprawling collection of narrowly scoped utilities, the library concentrates on stable, reusable primitives with minimal abstraction. APIs are designed to be easy to reason about, enabling developers to understand behavior intuitively and build scalable systems with confidence.
+
+Many existing hook libraries prioritize syntactic brevity or highly specialized use cases. While this can reduce boilerplate, it often leads to fragmented APIs, inconsistent behavior, and abstractions that are difficult to internalize or adapt to real-world requirements. In some cases, these libraries merely wrap smaller utilities, adding layers of indirection without meaningful architectural benefit.
+
+Another common pattern is a heavy reliance on **`useEffect`**, **`useCallback`**, and **`useMemo`** for state tracking and lifecycle control. This frequently shifts the burden of dependency management and stale-closure prevention onto developers, increasing cognitive load, introducing subtle bugs, and requiring unnecessary performance tuning.
+
+**_`classic-react-hooks`_** aims to reverse this trend—reducing mental overhead and allowing developers to focus on building features instead of managing complex or inconsistent abstractions.
+
+## What `classic-react-hooks` Offers
+
+- A carefully curated set of feature-rich, general-purpose hooks
+- High performance with a minimal and lightweight footprint
+- Predictable, intuitive APIs designed for natural usage
+- Strong TypeScript support with an emphasis on type safety
+- Zero third-party dependencies
+- Modular and declarative design principles
+- Fully tree-shakable for optimal bundling
+- Comprehensive, well-structured documentation
## Installation
::: code-group
-```bash [npm]
-npm install classic-react-hooks
+```sh [npm]
+$ npm install classic-react-hooks
```
-```bash [yarn]
-yarn add classic-react-hooks
+```sh [pnpm]
+$ pnpm add classic-react-hooks
```
-```bash [pnpm]
-pnpm add classic-react-hooks
+```sh [deno]
+$ deno install classic-react-hooks
```
-```bash [bun]
-bun add classic-react-hooks
+```sh [yarn]
+$ yarn add classic-react-hooks
```
-:::
-
-## Features
+```sh [bun]
+$ bun add classic-react-hooks
+```
-- Comprehensive hooks collection
-- Typesafe (Built in Typescript)
-- Comes with treeshaking
-- Small, Minimal and Easy to use
+:::
diff --git a/apps/doc/hooks/use-can-reach-to-internet.md b/apps/doc/hooks/use-can-reach-to-internet.md
new file mode 100644
index 0000000..df7c7f1
--- /dev/null
+++ b/apps/doc/hooks/use-can-reach-to-internet.md
@@ -0,0 +1,159 @@
+---
+outline: deep
+---
+
+# use-can-reach-to-internet
+
+_`use-can-reach-to-internet`_ is a comprehensive React hook for accurately detecting real internet connectivity, not just network presence.
+
+It combines the browser’s native navigator.onLine signal with active HTTP reachability checks to determine whether external internet access is actually available. The hook supports automatic polling as well as manual, on-demand connectivity checks, giving you full control over monitoring behavior.
+
+Its ref-safe, cleanup-aware design prevents memory leaks by properly managing timers and in-flight requests. This makes it well-suited for connectivity-aware UIs, retry logic, and robust offline/online handling.
+
+## Features
+
+- **Real connectivity testing:** Verifies internet access using actual HTTP requests
+- **Dual-layer detection:** Combines `navigator.onLine` with reachability checks for accurate results
+- **Comprehensive status flags:** Exposes `isOnline`, `canReachToInternet`, and `isFullyConnected`
+- **Automatic monitoring:** Configurable polling interval for continuous connectivity tracking
+- **Manual control:** Start, stop, or force connectivity checks programmatically
+- **Cleanup-safe design:** Automatically cleans up timers and network requests to prevent leaks
+
+## Problem It Solves
+
+::: details The Problem with `navigator.onLine`
+
+---
+
+**Problem:-** `navigator.onLine` only tells you if the browser thinks it's connected to a network, not if it can actually reach the internet.
+
+Common Scenarios Where `navigator.onLine` Fails
+
+- **Limited Connectivity:** Your device is connected to a router, but the router has no internet connection. The browser sees the local network connection and reports online status as true.
+- **Network Issues:** DNS problems or ISP outages where you have network connection but can't reach to external servers.
+- **Captive Portals:** You're connected to WiFi at a hotel, airport but haven't authenticated yet. `navigator.onLine` returns true, but you can't access any websites.
+
+---
+
+**Solution:-** How `useCanReachToInternet` solve these problems
+
+It provides two layers of connectivity detection
+
+- **`isOnline`:** Browser's basic network status (via `navigator.onLine`)
+- **`canReachToInternet`:** Actual internet reachability (via real HTTP requests to a test server)
+- **`isFullyConnected`:** Both conditions must be true for genuine internet access
+ :::
+
+## Important Notes
+
+::: danger Important
+
+- Performance Considerations:
+ - Network polling makes regular HTTP requests - use appropriate intervals
+ - Consider battery usage on mobile devices with frequent polling
+ - The hook automatically cleans up requests to prevent memory leaks
+- CORS Limitations:
+ - Uses `mode: 'no-cors'` for broader compatibility
+ - Default test URL `(https://dns.google)` is chosen for reliability
+
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :--------------------------------------------: | :------: | :-----------: | -------------------------------------------------- |
+| options | [CanReachToInternetOptions](#type-definitions) | ❌ | {} | Configuration object for customizing hook behavior |
+
+### Options Parameter
+
+| Property | Type | Default | Description |
+| ---------------------- | ------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- |
+| enableNetworkPolling | boolean | true | Controls whether the hook should automatically and continuously check internet connectivity at regular intervals. |
+| networkPollingInterval | number | 3000 | Specifies the interval in milliseconds for polling. |
+| testUrl | string | https://dns.google' | The URL endpoint used to test actual internet connectivity with HEAD method. |
+
+### Type Definitions
+
+```ts
+type CanReachToInternetOptions = {
+ /** Enable automatic network polling to continuously check connectivity */
+ enableNetworkPolling?: boolean
+ /** Interval in milliseconds between network polls */
+ networkPollingInterval?: number
+ /** URL to test internet connectivity against */
+ testUrl?: string
+}
+
+type CanReachToInternetBoolean = boolean
+```
+
+## Return value(s)
+
+This hook provides full list of status flags and callbacks for internet reachability tracking
+
+| Property | Type | Description |
+| --------------------------- | ------------- | -------------------------------------------------------------------------------- |
+| isOnline | boolean | Browser's native online/offline status from `navigator.onLine` |
+| canReachToInternet | boolean | Whether the device can actually reach the internet (verified via HTTP request) |
+| isFullyConnected | boolean | Combined status: `true` when both `isOnline` and `canReachToInternet` are `true` |
+| isNetworkPollingEnabled | boolean | Current state of automatic network polling |
+| isCheckingConnection | boolean | Whether a connectivity check is currently in progress |
+| startNetworkPolling | () => void | Function to start automatic network polling |
+| stopNetworkPolling | () => void | Function to stop automatic network polling |
+| forceCheckNetwork | () => void | Function to manually trigger a connectivity check |
+| getCanReachToInternetStatus | () => boolean | Function to get current internet reachability status |
+
+## Common Use Cases
+
+- **Real Internet stats:** Show connection status, disable features when offline
+- **Error handling:** Distinguish between network errors and server errors
+- **Auto-retry logic:** Retry failed requests when connectivity is restored
+
+## Usage Examples
+
+### Basic Network query
+
+```ts
+import { useCanReachToInternet } from 'classic-react-hooks'
+
+function NetworkStatus() {
+ const { isOnline, canReachToInternet, isFullyConnected } = useCanReachToInternet()
+
+ return (
+
+
Browser Online: {isOnline ? '✅' : '❌'}
+
Internet Reachable: {canReachToInternet ? '✅' : '❌'}
+
Fully Connected: {isFullyConnected ? '🟢 Connected' : '🔴 Disconnected'}
+
+ )
+}
+```
+
+### Conditional Rendering Based on Connectivity
+
+::: details Example
+
+```ts
+import { useCanReachToInternet } from 'classic-react-hooks'
+
+function DataFetchingComponent() {
+ const { isFullyConnected, isCheckingConnection } = useCanReachToInternet()
+
+ if (isCheckingConnection) {
+ return Checking connection...
+ }
+
+ if (!isFullyConnected) {
+ return (
+
+
No Internet Connection
+
Please check your connection and try again.
+
+ )
+ }
+
+ return
+}
+```
+
+:::
diff --git a/apps/doc/hooks/use-copy-to-clipboard.md b/apps/doc/hooks/use-copy-to-clipboard.md
index 1945c40..5f5e8e5 100644
--- a/apps/doc/hooks/use-copy-to-clipboard.md
+++ b/apps/doc/hooks/use-copy-to-clipboard.md
@@ -4,65 +4,107 @@ outline: deep
# use-copy-to-clipboard
-- A hook for copying the data in the clipboard with success and error callbacks.
+_`use-copy-to-clipboard`_ is a lightweight React hook that provides a simple and reliable way to copy text to the clipboard with built-in success and error handling.
-### Parameters
+It leverages the modern Clipboard API while gracefully handling unsupported environments. The hook avoids unnecessary state updates by using a ref-based implementation, ensuring zero re-renders. It also allows flexible configuration through global and per-call callbacks.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :---------------------: | :------: | :-----------: | ----------- |
-| Object | [Props](#parametertype) | ❌ | - | Object |
+## Features
-### Returns
+- **Modern Clipboard API:** Uses [navigator.clipboard](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) for secure, async clipboard access
+- **Graceful fallback handling:** Safely handles environments without clipboard support
+- **Success & error callbacks:** Built-in hooks for handling copy outcomes
+- **Flexible callback configuration:** Define global callbacks or override them per copy call
+- **Zero re-renders:** Ref-based implementation ensures optimal performance
+- **Promise-based API:** Enables async handling and easy error chaining
-[`CopyToClipboardFn`](#returntype) : A function for copying the data into clipboard
+## Problems It Solves
-### Types
+- Removes repetitive clipboard access logic from components
+- Handles browser support differences for clipboard operations
+- Simplifies success and error handling for copy actions
+- Prevents unnecessary re-renders when copying data
+- Centralizes clipboard logic for reuse across the application
+- Reduces error-prone imperative clipboard code
----
+## Parameters
-#### ParameterType
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :----------------------------: | :------: | :-----------: | --------------------------------- |
+| onSuccess | [OnSuccess](#type-definitions) | ❌ | - | Default success callback function |
+| onError | [OnError](#type-definitions) | ❌ | - | Default error callback function |
-```ts
-type Props = {
- onSuccess?: OnSuccess
- onError?: onError
-}
+::: warning
+Any occured errors during operation are passed to the `onError` callback with descriptive error messages.
+:::
+### Type Definitions
+
+```ts
type OnSuccess = () => void
type OnError = (err: Error) => void
```
-#### ReturnType
+## Return Value(s)
+
+The hook returns a function which will copy the provided data into the clipboard
+
+| Return Value | Type | Description |
+| -------------------------- | ------------------- | ---------------------------------- |
+| `copyToClipboard` function | `CopyToClipboardFn` | Handler function to copy text data |
+
+### Type Definitions
```ts
type CopyToClipboardFn = (data: string, onSuccess?: OnSuccess, onError?: OnError) => Promise
```
-### Usage
+## Common Use Cases
-```ts
+- Copy text data programatically
+
+## Usage Examples
+
+### Basic usage
+
+```ts {7-15}
import { useState } from 'react'
import { useCopyToClipboard } from 'classic-react-hooks'
-export default function YourComponent() {
- const [data, setData] = useState('')
- const copyToClipboard = useCopyToClipboard()
-
- return (
-
- setData(e.target.value)} />
-
- copyToClipboard(
- data,
- () => console.log('success'),
- (err) => console.log(err)
- )
- }
- >
- copy
-
-
- )
+export default function CopyButton() {
+ const [copied, setCopied] = useState(false)
+
+ const copyToClipboard = useCopyToClipboard({
+ onSuccess: () => {
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ },
+ onError: (error) => {
+ console.error('Failed to copy:', error)
+ },
+ })
+
+ const handleCopy = () => {
+ copyToClipboard('Hello, World!')
+ }
+
+ return {copied ? 'Copied!' : 'Copy Text'}
}
```
+
+## Alternative: Non-React Usage
+
+For use outside of React components, use the standalone function:
+
+```ts
+import { copyToClipboardFn } from 'classic-react-hooks'
+
+// Simple copy
+copyToClipboardFn('Text to copy')
+
+// With callbacks
+copyToClipboardFn(
+ 'Text to copy',
+ () => console.log('Copied successfully!'),
+ (error) => console.error('Copy failed:', error)
+)
+```
diff --git a/apps/doc/hooks/use-counter.md b/apps/doc/hooks/use-counter.md
index 409d779..05666ce 100644
--- a/apps/doc/hooks/use-counter.md
+++ b/apps/doc/hooks/use-counter.md
@@ -4,23 +4,46 @@ outline: deep
# use-counter
-- A simple hook for managing counter.
+A Hook for Fun
-### Parameters
+_`use-counter`_ is a playful yet type-safe React hook for managing counter state with minimal setup and maximum flexibility.
-| Parameter | Type | Required | Default Value | Description |
-| ------------ | :----: | :------: | :-----------: | --------------------------------------------------------------------------- |
-| key | string | ❌ | "" | Based on the key, it generates `type-safe` object with `prefixed` proprety. |
-| initialValue | number | ❌ | 0 | Initial value of the counter. |
+It supports configurable initial values and step sizes while generating strongly typed, ergonomically named properties. By optionally accepting a key, the hook dynamically prefixes returned state and handlers, improving readability and avoiding naming collisions.
-### Returns
+Its simple API makes it ideal for demos, UI controls, scores, and quick stateful interactions. Despite its fun nature, it remains fully predictable and TypeScript-friendly.
-- It returns an object.
-- `counter` : number
-- `incrementCounter` : () => void
-- `decrementCounter` : () => void
+## Features
-### Usage
+- Find out yourself buddy
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| ------------ | ------ | :------: | :-----------: | ------------------------------------------------------------------------- |
+| key | string | ❌ | "" | Prefix for generated property names. Creates type-safe object properties. |
+| props | object | ❌ | undefined | Configuration object containing `initialValue` and `stepper`. |
+| initialValue | number | ❌ | 0 | Initial value for the counter. |
+| stepper | number | ❌ | 1 | Amount to increment/decrement by on each operation. |
+
+## Return value(s)
+
+Returns a type-safe object with dynamically named properties:
+
+### Without key (default):
+
+- `counter:` number - Current counter value
+- `incrementCounter:` () => void - Function to increment counter
+- `decrementCounter:` () => void - Function to decrement counter
+
+### With key (e.g., "user"):
+
+- `userCounter:` number - Current counter value
+- `incrementUserCounter:` () => void - Function to increment counter
+- `decrementUserCounter:` () => void - Function to decrement counter
+
+## Usage Examples
+
+### Basic Counter
```ts
import { useCounter } from 'classic-react-hooks'
@@ -42,3 +65,24 @@ export default function YourComponent() {
)
}
```
+
+### Named Counter with Custom Step
+
+```ts
+import { useCounter } from 'classic-react-hooks'
+
+export default function UserScoreCounter() {
+ const { userCounter, incrementUserCounter, decrementUserCounter } = useCounter('user', {
+ initialValue: 10,
+ stepper: 5,
+ })
+
+ return (
+
+
User Score: {userCounter}
+ -5
+ +5
+
+ )
+}
+```
diff --git a/apps/doc/hooks/use-debounced-fn.md b/apps/doc/hooks/use-debounced-fn.md
index d225959..83f32be 100644
--- a/apps/doc/hooks/use-debounced-fn.md
+++ b/apps/doc/hooks/use-debounced-fn.md
@@ -2,40 +2,670 @@
outline: deep
---
-# use-debouced-fn
+# use-debounced-fn
-- A hook which returns a debounced function.
+_`use-debounced-fn`_ is an async-aware React hook that provides a powerful, declarative way to implement debouncing with full lifecycle control.
-### Parameters
+It automatically manages timeouts and `AbortController`, ensuring stale async operations are safely cancelled when new calls occur or components unmount.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | ----------------------------------------------------------- |
-| cb | Function | ✅ | - | A callback which is to be debounced. |
-| delay | number | ❌ | 300 | A delay in milliseconds after that the callback gets fired. |
+The hook supports immediate execution for synchronous UI updates, along with structured `onSuccess`, `onError`, and `onFinally` callbacks for robust async workflows. Its ref-based implementation guarantees a stable function reference across re-renders, eliminating stale closures and unnecessary rebindings. This makes it ideal for complex scenarios like search, validation, auto-save, and any debounced async side effects.
-### Returns
+## Features
-- It returns a function which is debouced version of passed callback.
+- **Automatic cleanup:** Timeouts are cleared on unmount or dependency changes
+- **AbortSignal support:** Cancels pending async operations when a new call starts
+- **Configurable delay:** Flexible timing with sensible defaults
+- **Immediate execution:** Run synchronous logic before debouncing
+- **Success handler:** Invoke a callback on successful completion (async supported)
+- **Error handler:** Gracefully handle execution errors
+- **Finally handler:** Run cleanup logic regardless of outcome
+- **Manual cleanup:** Exposed cleanup function for advanced use cases
+- **Type-safe overloads:** Full TypeScript support for events and multiple arguments
-### Usage
+## Problem It Solves
+
+::: details **Boilerplate Reduction and More control on behaviors**
+
+---
+
+**Problem:-** Manually implementing debouncing in React components leads to less control on behaviors, lengthy, error-prone code with potential memory leaks and stale closures. Additionally, handling request cancellation requires manual AbortController management.
+
+```tsx
+// ❌ Problematic approach which is redundant and lengthy
+function SearchInput() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+ const timeoutRef = useRef()
+ const controllerRef = useRef()
+
+ const handleSearch = useCallback(async (searchTerm: string) => {
+ // Cancel previous request
+ if (controllerRef.current) {
+ controllerRef.current.abort()
+ }
+
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current)
+ }
+
+ controllerRef.current = new AbortController()
+ const controller = controllerRef.current
+
+ timeoutRef.current = setTimeout(async () => {
+ try {
+ if (searchTerm.trim()) {
+ const response = await fetch(`/api/search?q=${searchTerm}`, {
+ signal: controller.signal,
+ })
+ const data = await response.json()
+ setResults(data.results)
+ }
+ } catch (error) {
+ if (error.name !== 'AbortError') {
+ console.error('Search failed:', error)
+ }
+ }
+ }, 500)
+ }, [])
+
+ useEffect(() => {
+ return () => {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current)
+ }
+ if (controllerRef.current) {
+ controllerRef.current.abort()
+ }
+ }
+ }, [])
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ const value = e.target.value
+ setQuery(value)
+ handleSearch(value)
+ }
+
+ return
+}
+```
+
+---
+
+**Solution:-**
+
+- Eliminates repetitive debounce timing logic
+- Automatic AbortController management - previous requests are automatically cancelled
+- Eliminates manual management of custom callback for updating the UI state
+- Providing full flexibility on debouncing life cycle behavior with `immediateCallback`, `onSuccess`, `onError`, `onFinally` and `callbackToBounce` functions.
+- Automatic cleanup ensures timeouts and requests are cancelled when:
+ - Component unmounts
+ - Delay value changes
+ - New debounced call is triggered
+
+```tsx {8,11,14,18,21,24}
+// ✅ Clean, declarative approach with automatic abort handling
+function SearchInput() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const { debouncedFn } = useDebouncedFn({
+ /* searchTerm is type-safe for all of the callbacks. */
+ immediateCallback: (searchTerm) => {
+ setQuery(searchTerm) // Update UI immediately
+ },
+ callbackToBounce: async (signal, searchTerm) => {
+ // signal is automatically provided - use it in fetch!
+ if (searchTerm.trim()) {
+ const response = await fetch(`/api/search?q=${searchTerm}`, { signal })
+ const data = await response.json()
+ setResults(data.results)
+ }
+ },
+ onSuccess: (searchTerm) => {
+ console.log('runs after successful completion of callbackToBounce')
+ },
+ onError: (error, searchTerm) => {
+ // AbortError is automatically filtered out - only real errors trigger this
+ console.error('Search failed:', error)
+ },
+ delay: 500,
+ })
+
+ /* debouncedFn is aware of its type. String argument must be provided. */
+ return debouncedFn(e.target.value)} placeholder='Search...' />
+}
+```
+
+:::
+
+::: details **Performance Benefits**
+
+- **Reduces execution frequency:** Limits function calls during rapid user input
+- **Automatic request cancellation:** Prevents race conditions by aborting stale requests
+- **Memory efficient:** Proper cleanup prevents memory leaks from pending timeouts and requests
+- **Stable references:** Function reference remains stable across re-renders
+- **Immediate UI updates:** `immediateCallback` ensures responsive user experience
+- **Async-aware:** `onSuccess` waits for async operations to complete
+- **Error resilience:** `onError` handles failures gracefully (AbortError is automatically filtered out)
+
+:::
+
+## AbortSignal Support
+
+The hook automatically manages AbortController for you. The `callbackToBounce` function receives an AbortSignal as its first parameter, which you can pass to `fetch()` or other abortable operations.
+
+**Key behaviors:**
+
+- When a new debounced call is triggered, the previous async operation is automatically aborted
+- `AbortError` exceptions are automatically filtered out and won't trigger `onError`
+- Only real errors (network failures, API errors, etc.) will trigger the `onError` callback
+- On component unmount, all pending operations are aborted
+
+```tsx
+const { debouncedFn } = useDebouncedFn({
+ callbackToBounce: async (signal, searchTerm) => {
+ // ✅ Pass signal to fetch
+ const response = await fetch(`/api/search?q=${searchTerm}`, { signal })
+ const data = await response.json()
+ return data
+ },
+ onError: (error, searchTerm) => {
+ // ✅ This will NOT be called for AbortError
+ // Only called for real errors (network issues, 500 errors, etc.)
+ console.error('Real error occurred:', error)
+ },
+})
+```
+
+## Execution Flow for the callbacks
+
+```tsx
+function SearchInput() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const { debouncedFn } = useDebouncedFn({
+ /* searchTerm is type-safe for all of the callbacks. */
+ immediateCallback: (searchTerm) => {
+ setQuery(searchTerm) /* Update UI immediately */
+ },
+ callbackToBounce: async (signal, searchTerm) => {
+ // No try-catch needed for AbortError
+ // Error is handled within `onError` callback (except AbortError)
+ const response = await fetch(`/api/search?q=${searchTerm}`, { signal })
+ const data = await response.json()
+ setResults(data.results)
+ },
+ onSuccess: (searchTerm) => {
+ console.log('runs after successful completion of callbackToBounce')
+ },
+ onError: (error, searchTerm) => {
+ console.log('runs if error occurs (AbortError filtered out)', error)
+ },
+ onFinally: (searchTerm) => {
+ console.log('runs after all of the callbacks (even on abort)')
+ },
+ })
+
+ /* debouncedFn is aware of its type. String argument must be provided. */
+ return debouncedFn(e.target.value)} placeholder='Search...' />
+}
+```
+
+## Callback Execution Order
+
+The callbacks execute in the following order:
+
+### Success Flow
+
+1. **immediateCallback** - Executes synchronously when `debouncedFn` is called
+2. **callbackToBounce** - Executes after the delay period (receives AbortSignal as first parameter)
+3. **onSuccess** - Executes after `callbackToBounce` completes successfully
+4. **onFinally** - Executes after `onSuccess`
+
+### Error Flow
+
+1. **immediateCallback** - Executes synchronously when `debouncedFn` is called
+2. **callbackToBounce** - Executes after the delay period and throws an error
+3. **onError** - Executes when error is caught (receives the error and all arguments) - **AbortError is automatically filtered out**
+4. **onFinally** - Executes after `onError`
+
+### Abort Flow
+
+1. **immediateCallback** - Executes synchronously when `debouncedFn` is called
+2. **callbackToBounce** - Starts executing after delay, but gets aborted
+3. **onError** - Does NOT execute (AbortError is filtered)
+4. **onFinally** - Still executes
+
+::: tip
+
+- `onSuccess` and `onError` are mutually exclusive - only one will run per execution
+- `onFinally` always runs, regardless of success, error, or abort
+- All callbacks except `onError` receive the same arguments passed to `debouncedFn`
+- `onError` receives the error as the first argument, followed by the original arguments
+- **`callbackToBounce` receives AbortSignal as the first parameter, followed by the arguments**
+- AbortError is automatically filtered and won't trigger `onError`
+ :::
+
+::: tip
+The `debounced function` is purely ref based and does not change across re-renders.
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| ----------------- | :------------------------------: | :------: | :-----------: | ------------------------------------------------------------------------------- |
+| callbackToBounce | [DebouncedFn](#type-definitions) | ✅ | - | The function to debounce (receives AbortSignal as first parameter) |
+| immediateCallback | [DebouncedFn](#type-definitions) | ❌ | - | Function to execute immediately before debouncing starts |
+| onSuccess | [DebouncedFn](#type-definitions) | ❌ | - | Function to execute after debounced callback completes successfully |
+| onError | [ErrorFn](#type-definitions) | ❌ | - | Function to execute when debounced callback throws an error (except AbortError) |
+| onFinally | [DebouncedFn](#type-definitions) | ❌ | - | Function to execute after completion (success, error, or abort) |
+| delay | number | ❌ | 300ms | Delay in milliseconds before function execution |
+
+### Type Definitions
+
+::: details
```ts
+export type DebouncedFn any> = (signal: AbortSignal, ...args: Parameters) => void
+export type ErrorFn any> = (error: Error, ...args: Parameters) => void
+
+// Function overloads for type safety
+export function useDebouncedFn({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ onError,
+ onFinally,
+ delay,
+}: {
+ immediateCallback?: (...args: any[]) => void
+ callbackToBounce: (signal: AbortSignal, ...args: any[]) => void
+ onSuccess?: (...args: any[]) => void
+ onError?: (error: Error, ...args: any[]) => void
+ onFinally?: (...args: any[]) => void
+ delay?: number
+}): {
+ debouncedFn: (...args: any[]) => void
+ cleanup: () => void
+}
+
+// Overload with event and additional arguments
+export function useDebouncedFn({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ onError,
+ onFinally,
+ delay,
+}: {
+ immediateCallback?: (ev: Ev, ...args: Args) => void
+ callbackToBounce: (signal: AbortSignal, ev: Ev, ...args: Args) => void
+ onSuccess?: (ev: Ev, ...args: Args) => void
+ onError?: (error: Error, ev: Ev, ...args: Args) => void
+ onFinally?: (ev: Ev, ...args: Args) => void
+ delay?: number
+}): {
+ debouncedFn: (ev: Ev, ...args: Args) => void
+ cleanup: () => void
+}
+```
+
+:::
+
+## Return Value(s)
+
+The hook returns an object with the debounced function and a cleanup function.
+
+| Return Value | Type | Description |
+| ------------- | ---------------------------------- | --------------------------------------------------------------------------------------- |
+| `debouncedFn` | `(...args: Parameters) => void` | Debounced version of the original function that delays execution by the specified delay |
+| `cleanup` | `() => void` | Manual cleanup function to clear pending timeouts and abort pending requests |
+
+## Common Use Cases
+
+- **Search functionality:** Debouncing search queries to reduce API calls with automatic request cancellation, immediate UI updates, and error handling
+- **API rate limiting:** Preventing excessive API requests with proper error handling and request cancellation
+- **Form validation:** Debouncing validation with loading states, error feedback, and automatic abort of stale validations
+- **Auto-save:** Debouncing save operations with completion callbacks, error recovery, and request cancellation
+- **Resize/scroll handlers:** Optimizing expensive DOM operations with error boundaries
+
+## Usage Examples
+
+### Basic Search with AbortSignal
+
+```tsx {8-24}
+import { useState } from 'react'
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function SearchExample() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const { debouncedFn } = useDebouncedFn({
+ immediateCallback: (searchTerm: string) => {
+ setQuery(searchTerm) // Update input immediately
+ },
+ callbackToBounce: async (signal, searchTerm: string) => {
+ if (searchTerm.trim()) {
+ // Pass signal to fetch - request will be automatically cancelled
+ // if user types again before this completes
+ const response = await fetch(`https://api.example.com/search?q=${searchTerm}`, {
+ signal,
+ })
+ const data = await response.json()
+ setResults(data.results)
+ } else {
+ setResults([])
+ }
+ },
+ delay: 500,
+ })
+
+ return (
+
+
debouncedFn(e.target.value)} placeholder='Search products...' />
+
+ {results.map((result) => (
+
{result.name}
+ ))}
+
+
+ )
+}
+```
+
+### Auto-save with Loading State and Request Cancellation
+
+```tsx {7-37}
+import { useState } from 'react'
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function AutoSaveEditor() {
+ const [content, setContent] = useState('')
+ const [isSaving, setIsSaving] = useState(false)
+ const [lastSaved, setLastSaved] = useState(null)
+ const [error, setError] = useState(null)
+
+ const { debouncedFn } = useDebouncedFn({
+ immediateCallback: (text: string) => {
+ setContent(text) // Update editor immediately
+ setError(null) // Clear previous errors
+ },
+ callbackToBounce: async (signal, text: string) => {
+ setIsSaving(true)
+ // Previous save request will be automatically cancelled
+ const response = await fetch('/api/save', {
+ method: 'POST',
+ body: JSON.stringify({ content: text }),
+ signal, // Pass the signal
+ })
+ if (!response.ok) throw new Error('Save failed')
+ },
+ onSuccess: () => {
+ setLastSaved(new Date())
+ },
+ onError: (err) => {
+ // AbortError won't trigger this - only real errors
+ setError(err.message)
+ },
+ onFinally: () => {
+ setIsSaving(false)
+ },
+ delay: 1000,
+ })
+
+ return (
+
+ )
+}
+```
+
+### Form Validation with Status Tracking and Abort
+
+```tsx {7-41}
+import { useState } from 'react'
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function UsernameValidator() {
+ const [username, setUsername] = useState('')
+ const [isValidating, setIsValidating] = useState(false)
+ const [isAvailable, setIsAvailable] = useState(null)
+ const [error, setError] = useState(null)
+
+ const { debouncedFn } = useDebouncedFn({
+ immediateCallback: (value: string) => {
+ setUsername(value)
+ setIsAvailable(null) // Reset validation state
+ setError(null)
+ },
+ callbackToBounce: async (signal, value: string) => {
+ if (value.length < 3) return
+
+ setIsValidating(true)
+ // Previous validation will be automatically cancelled
+ const response = await fetch(`/api/check-username?name=${value}`, {
+ signal,
+ })
+ if (!response.ok) throw new Error('Validation failed')
+ const data = await response.json()
+ setIsAvailable(data.available)
+ },
+ onError: (err) => {
+ // Only real errors trigger this (not AbortError)
+ setError(err.message)
+ setIsAvailable(null)
+ },
+ onFinally: () => {
+ setIsValidating(false)
+ },
+ delay: 600,
+ })
+
+ return (
+
+ debouncedFn(e.target.value)} placeholder='Enter username' />
+ {isValidating && Checking... }
+ {error && {error} }
+ {isAvailable !== null && {isAvailable ? '✓ Available' : '✗ Taken'} }
+
+ )
+}
+```
+
+### Manual Cleanup Example
+
+```tsx {8-21,27}
+import { useState } from 'react'
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function SearchWithCancel() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const { debouncedFn, cleanup } = useDebouncedFn({
+ callbackToBounce: async (signal, searchTerm: string) => {
+ const response = await fetch(`/api/search?q=${searchTerm}`, {
+ signal,
+ })
+ const data = await response.json()
+ setResults(data.results)
+ },
+ delay: 500,
+ })
+
+ const handleClear = () => {
+ setQuery('')
+ setResults([])
+ cleanup() // Cancel pending timeout AND abort any in-flight request
+ }
+
+ return (
+
+
debouncedFn(e.target.value)} />
+
Clear
+
+ {results.map((result) => (
+
{result.name}
+ ))}
+
+
+ )
+}
+```
+
+### Type-safe Event Handling with AbortSignal
+
+```tsx {8-26}
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function TypeSafeExample() {
+ const { debouncedFn } = useDebouncedFn>({
+ immediateCallback: (event) => {
+ console.log('Immediate:', event.target.value)
+ },
+ callbackToBounce: async (signal, event) => {
+ // Full type safety for signal and event object
+ const response = await fetch(`/api/process?value=${event.target.value}`, {
+ signal,
+ })
+ const data = await response.json()
+ console.log('Debounced:', data)
+ },
+ onSuccess: (event) => {
+ console.log('Completed for:', event.target.value)
+ },
+ onError: (error, event) => {
+ console.error('Error processing:', event.target.value, error)
+ },
+ delay: 400,
+ })
+
+ return
+}
+```
+
+### Complex Workflow with All Callbacks
+
+```tsx {7-47}
import { useState } from 'react'
import { useDebouncedFn } from 'classic-react-hooks'
-export default function YourComponent() {
- const [debouncedInput, setDebouncedInput] = useState('')
- const updateInput = useDebouncedFn((e) => {
- setDebouncedInput(e.target.value)
- }, 300)
+export default function CompleteExample() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+ const [isLoading, setIsLoading] = useState(false)
+ const [error, setError] = useState(null)
+
+ const { debouncedFn } = useDebouncedFn({
+ immediateCallback: (searchTerm) => {
+ // 1. Runs immediately on every keystroke
+ setQuery(searchTerm)
+ setError(null)
+ console.log('User typed:', searchTerm)
+ },
+ callbackToBounce: async (signal, searchTerm) => {
+ // 2. Runs after delay (debounced)
+ setIsLoading(true)
+ console.log('Searching for:', searchTerm)
+
+ // Previous request is automatically aborted when new one starts
+ const response = await fetch(`/api/search?q=${searchTerm}`, {
+ signal,
+ })
+ if (!response.ok) throw new Error('Search failed')
+
+ const data = await response.json()
+ setResults(data.results)
+ },
+ onSuccess: (searchTerm) => {
+ // 3. Runs after successful completion
+ console.log('Search completed for:', searchTerm)
+ },
+ onError: (err, searchTerm) => {
+ // 3. Runs if error occurs (instead of onSuccess)
+ // Note: AbortError is filtered out automatically
+ console.error('Search failed for:', searchTerm, err)
+ setError(err.message)
+ setResults([])
+ },
+ onFinally: (searchTerm) => {
+ // 4. Always runs at the end (even after abort)
+ setIsLoading(false)
+ console.log('Finished processing:', searchTerm)
+ },
+ delay: 500,
+ })
+
+ return (
+
+
debouncedFn(e.target.value)} placeholder='Search...' />
+ {isLoading &&
Loading...
}
+ {error &&
{error}
}
+
+ {results.map((result) => (
+
{result.name}
+ ))}
+
+
+ )
+}
+```
+
+### Custom Abortable Operation
+
+```tsx {7-30}
+import { useState } from 'react'
+import { useDebouncedFn } from 'classic-react-hooks'
+
+export default function CustomAbortExample() {
+ const [result, setResult] = useState('')
+
+ const { debouncedFn } = useDebouncedFn({
+ callbackToBounce: async (signal, value: string) => {
+ // You can use the signal for custom abort logic
+ return new Promise((resolve, reject) => {
+ const timeoutId = setTimeout(() => {
+ resolve(`Processed: ${value}`)
+ }, 2000)
+
+ // Listen to abort signal
+ signal.addEventListener('abort', () => {
+ clearTimeout(timeoutId)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ },
+ onSuccess: (value) => {
+ setResult(`Success: ${value}`)
+ },
+ delay: 500,
+ })
return (
-
-
- value - {debouncedInput}
-
+
debouncedFn(e.target.value)} placeholder='Type to trigger...' />
+
{result}
)
}
```
+
+## Things to keep in mind
+
+- Always use the `signal` parameter in `callbackToBounce` for fetches and other abortable operations to avoid race conditions
+- Use `immediateCallback` for synchronous UI updates to keep interactions responsive
+- Use `onSuccess` to track successful async completion (e.g., loading states, success messages)
+- Use `onError` for graceful failure handling and user-facing errors — `AbortError` is filtered automatically
+- Use `onFinally` for cleanup logic that must run on success, failure, or abort (e.g., hiding spinners)
+- Use `cleanup` to cancel pending work and abort in-flight requests (navigation, unmounting)
+- No callback memoization required — no stale-closure issues
+- Built-in error handling removes the need for `try/catch` in `callbackToBounce`
+- Abort signals are managed automatically — previous operations are cancelled on new calls or unmount
diff --git a/apps/doc/hooks/use-event-listener.md b/apps/doc/hooks/use-event-listener.md
index d52c965..659b4ff 100644
--- a/apps/doc/hooks/use-event-listener.md
+++ b/apps/doc/hooks/use-event-listener.md
@@ -4,45 +4,271 @@ outline: deep
# use-event-listener
-- A hook which handles dom events in efficient and declarative manner.
+_`use-event-listener`_ is a declarative React hook that simplifies DOM event handling with automatic lifecycle management.
-### Parameters
+It eliminates repetitive add/removeEventListener boilerplate while preventing memory leaks through intelligent cleanup on unmount or dependency changes.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :-----------------------: | :------: | :-----------: | ------------------------------ |
-| target | [Target](#parametertype) | ✅ | - | Reference of the html element |
-| event | string | ✅ | - | Event name |
-| handler | [Handler](#parametertype) | ❌ | undefined | Callback for the event |
-| options | [Options](#parametertype) | ❌ | undefined | For managing Event Propagation |
+This hook supports flexible targeting via either a target prop or setElementRef callback, and features built-in conditional binding. It fully supports all standard AddEventListenerOptions including capture, once, passive, and signal.
-### Types
+## Features
+
+- **Declarative event handling:** Attach DOM events via a clean, hook-based API
+- **Flexible targeting:** Bind listeners using a `target` function or `setElementRef` callback
+- **Automatic cleanup:** Listeners are removed on unmount or dependency changes
+- **Reactive rebinding:** Reattaches automatically when target, event, or options change
+- **Conditional binding:** Toggle listener attachment with `shouldInjectEvent`
+- **Full options support:** Supports all `AddEventListenerOptions` (`capture`, `once`, `passive`, `signal`)
+- **Stable references:** Avoids unnecessary add/remove cycles across re-renders
+- **Ref-free usage:** No manual refs needed when using `setElementRef`
+
+::: warning Usage Note
+
+- Do not pass _`target`_ prop if using _`setElementRef`_ and vise-versa.
+
+:::
+
+## Problem It Solves
+
+::: details **Boilerplate Reduction**
+
+Manually managing event listeners in React components leads to verbose, repetitive and error-prone code with potential memory leaks.
+See the below implementation:
+
+```tsx
+// ❌ Problematic approach which is redundant and verbose
+function Component() {
+ const [scrollY, setScrollY] = useState(0)
+
+ useEffect(() => {
+ const handleScroll = () => {
+ setScrollY(window.scrollY)
+ }
+
+ window.addEventListener('scroll', handleScroll)
+ return () => window.removeEventListener('scroll', handleScroll) // Doing proper cleanup on unmount
+ }, [])
+
+ return Current: {scrollY}
+}
+```
---
-#### ParameterType
+How _`use-event-listener`_ solves it:
+
+- Eliminates repetitive `addEventListener/removeEventListener` code
+- Reduces component complexity by abstracting event handling logic
+- Makes conditional event attachment predictable and declarative
+- Simplifies dynamic event binding when below things happens:-
+ - Component unmounts
+ - `target` element changes
+ - `event` type changes
+ - Any of `options` params:- (_shouldInjectEvent_, _capture_, _once_, _passive_, _signal_) gets changed
+
+```tsx
+// ✅ Clean, declarative approach
+function Component() {
+ const [scrollY, setScrollY] = useState(0)
+ const breakpoint = useEventListener({
+ target: () => window,
+ event: 'scroll',
+ handler: () => {
+ setScrollY(window.scrollY)
+ },
+ })
+
+ return Current: {scrollY}
+}
+```
+
+:::
+
+::: details **Performance Benefits**
+
+- Stable references accross re-renders which prevents listeners from being repeatedly added/removed
+- Efficient dependency tracking
+- Prevents memory leaks caused by missed or incorrect cleanup
+- Eliminates manual lifecycle management for DOM event listeners
+- Avoids unnecessary listener re-creation across component re-renders
+ :::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :----------------------------: | :------: | :-----------: | ------------------------------------------------- |
+| target | [EvTarget](#type-definitions) | ✅ | - | Target element on which the event is listened to. |
+| event | string | ✅ | - | Event name (e.g. 'click', 'keydown') |
+| handler | [EvHandler](#type-definitions) | ❌ | undefined | Event listener callback function |
+| options | [EvOptions](#type-definitions) | ❌ | undefined | Standard Options and Feature flags |
+| |
+
+### Options Parameter
+
+The _`options`_ parameter supports all standard _`AddEventListenerOptions`_ and introduces extra custom properties to control conditional event binding.
+
+#### Standard _`AddEventListenerOptions`_
+
+| Property | Type | Default | Description |
+| -------- | ----------- | --------- | -------------------------------------------------------------------------------- |
+| capture | boolean | false | If `true`, the listener will be triggered during the capture phase |
+| once | boolean | false | If `true`, the listener will be automatically removed after being triggered once |
+| passive | boolean | false | If `true`, indicates that the function will never call `preventDefault()` |
+| signal | AbortSignal | undefined | An AbortSignal that can be used to remove the event listener |
+
+#### Custom _`Options`_
+
+| Property | Type | Default | Description |
+| ----------------- | -------------- | ------- | --------------------------------------------------------------------------------------------------- |
+| shouldInjectEvent | boolean \| any | true | Controls whether the event listener should be attached. When false, the event listener is not added |
+
+### Type Definitions
+
+::: details
```ts
-type Target = null | EventTarget | (() => EventTarget | null)
-type Options = boolean | (AddEventListenerOptions & { shouldInjectEvent?: boolean | any })
-type Handler = (event: Event) => void
+export type EvTarget = () => EventTarget | null
+export type EvHandler = (event: Event) => void
+
+export interface EvOptions extends AddEventListenerOptions {
+ // Standard AddEventListenerOptions:
+ capture?: boolean
+ once?: boolean
+ passive?: boolean
+ signal?: AbortSignal
+
+ // Custom option:
+ shouldInjectEvent?: boolean | any // Controls whether the event should be attached
+}
```
-### Usage
+:::
+
+## Return Value(s)
+
+This hook returns an object that includes a setter function, allowing you to observe and manage the target element through its ref attribute.
+
+| Property | Type | Description |
+| ------------- | ------------------------- | ------------------------------------------------------------------- |
+| setElementRef | [Function](#return-types) | A ref callback that observes the target element for event listening |
+
+### Return Types
+
+::: details
```ts
+export type UseEventListenerReturnValues = {
+ setElementRef: (elementNode: HTMLElement | null) => void
+}
+```
+
+:::
+
+## Common Use Cases
+
+- Adding dom events (e.g 'click', 'keydown', 'resize', 'scroll')
+
+## Usage Examples
+
+### Usage with `setElementRef`(no manual creation of ref)
+
+```ts {6,16}
+import { useState } from 'react'
+import { useEventListener } from 'classic-react-hooks'
+
+export default function ConditionalExample() {
+ const [counter, setCounter] = useState(0)
+ const { setElementRef } = useEventListener({
+ event: 'click',
+ handler: () => {
+ console.log(counter)
+ },
+ })
+
+ return (
+
+
setCounter((c) => c + 1)}>update counter {counter}
+
log value
+
+ )
+}
+```
+
+### Basic Click Handler
+
+::: details Exampls
+
+```ts {7-13}
import { useRef } from 'react'
import { useEventListener } from 'classic-react-hooks'
-export default function YourComponent() {
- const ref = useRef()
- useEventListener(ref, 'click', (e) => {
- console.log(e)
+export default function ClickExample() {
+ const buttonRef = useRef(null)
+
+ useEventListener({
+ target: () => buttonRef.current,
+ event: 'click',
+ handler: (e) => {
+ console.log('Button clicked!', e)
+ },
+ })
+
+ return Click me
+}
+```
+
+:::
+
+### Listening Window Event
+
+::: details Example
+
+```ts {6-9}
+import { useEventListener } from 'classic-react-hooks'
+
+export default function WindowExample() {
+ useEventListener({
+ target: () => window,
+ event: 'resize',
+ handler: (e) => {
+ console.log('Window resized:', window.innerWidth, window.innerHeight)
+ },
+ })
+
+ return Resize the window and check console
+}
+```
+
+:::
+
+### Conditional Event Listening
+
+::: details Example
+
+```ts
+import { useState } from 'react'
+import { useEventListener } from 'classic-react-hooks'
+
+export default function ConditionalExample() {
+ const [isListening, setIsListening] = useState(true) // [!code ++]
+
+ useEventListener({
+ target: () => document,
+ event: 'keydown',
+ handler: (e) => {
+ console.log('Key pressed:', e.key)
+ },
+ options: {
+ shouldInjectEvent: isListening, // Only listen when enabled // [!code ++]
+ },
})
return (
-
button
+
setIsListening(!isListening)}>{isListening ? 'Stop' : 'Start'} Listening
+
Press any key (when listening is enabled)
)
}
```
+
+:::
diff --git a/apps/doc/hooks/use-intersection-observer.md b/apps/doc/hooks/use-intersection-observer.md
index 5636ece..82828f7 100644
--- a/apps/doc/hooks/use-intersection-observer.md
+++ b/apps/doc/hooks/use-intersection-observer.md
@@ -4,77 +4,265 @@ outline: deep
# use-intersection-observer
-- A hook which provides a way for listening to the Intersection Observer event for given target.
-- It returns an array of boolean values which represents whether the targets are intersecting the screen or not.
+_`use-intersection-observer`_ is a declarative React hook that simplifies observing element visibility using the native Intersection Observer API.
-### Parameters
+It abstracts observer creation, lifecycle management, and cleanup while remaining fully type-safe. The hook supports dynamic property naming, one-time observation, and all standard observer options. It also gracefully handles unsupported environments by avoiding observer creation and warning in development.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------------------------: | :------: | :-----------: | ------------------------------------------------------------- |
-| targets | [Target[]](#parametertype) | ✅ | - | Array of targets which contains reference of the html element |
-| options | [Options](#parametertype) | ❌ | {} | Options to pass as feature flag |
+::: danger Important
-### Types
+This hook automatically checks for `IntersectionObserver` support and logs a warning in development if it's not available. The hook will gracefully handle unsupported browsers by not creating observers.
+:::
----
+## Features
-#### ParameterType
+- **Declarative API:** Observe element visibility without manual observer management
+- **Automatic cleanup:** Observers disconnect on unmount or dependency changes
+- **Reactive re-attachment:** Updates automatically when the element or options change
+- **One-time observation:** `onlyTriggerOnce` support for single-intersection cases
+- **Dynamic property keys:** Custom `key` for type-safe, IntelliSense-friendly state
+- **Full options support:** Supports all `IntersectionObserverInit` options ([root](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/root), [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin), [threshold](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/thresholds))
+- **Intersection callbacks:** Optional `onIntersection` for fine-grained control
+- **Optimized reactivity:** Avoids unnecessary re-renders via [use-synced-ref](use-synced-ref.html)
+- **Graceful degradation:** Safely handles environments without `IntersectionObserver`
-```ts
-type Target = HTMLElement | RefObject | (() => HTMLElement | null) | null
-type Options = {
- mode?: 'lazy' | 'virtualized'
-} & IntersectionObserverInit
-```
+::: tip
+This hook internally uses [useSyncedRef](/hooks/use-synced-ref) to avoid unnecessary re-renders when callback functions change
+:::
+
+## Problem It Solves
+
+::: details Eliminate manual setup
+
+- Eliminates manual setup and cleanup of `IntersectionObserver` instances
+- Prevents memory leaks caused by orphaned observers
+- Removes complexity when observing elements only once
+- Avoids brittle state handling for intersection status
+
+:::
+
+::: details Type-Safe and Collision free Instance Management
+
+- **Dynamic & Type-Safe Properties:** Generates uniquely named properties for each observer with full TypeScript and IntelliSense support.
+- **Scalable:** Efficiently observe any number of elements without property naming conflicts.
+
+````tsx
+// Example: Dynamically named properties based on the 'key'
+const { element, setElementRef, isElementIntersecting } = useIntersectionObserver() // Without key
+const { sidebarElement, setSidebarElementRef, isSidebarElementIntersecting } = useIntersectionObserver({
+ key: 'sidebar', // With key 'sidebar'
+})
+
+
+:::
+
+::: details One-Time Observation Complexity
+
+- _`onlyTriggerOnce`_ option for automatically cleaning up observer after first intersection
+
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :----------------------------------------------: | :------: | :-----------: | -------------------------------------------------- |
+| options | [IntersectionObserverOptions](#type-definitions) | ❌ | undefined | Configuration object for the intersection observer |
+
+### Options Parameter
+
+The `options` parameter accepts an object that extends the standard `IntersectionObserverInit` with an additional custom property for conditional event handling and post callback.
+
+#### Standard _`IntersectionObserverInit`_ Options
-### Usage
+| Property | Type | Default | Description |
+| ---------- | :-------------------------: | :-----: | ------------------------------- |
+| key | string | '' | Custom key for property naming |
+| root | Element \| Document \| null | null | Root element for intersection |
+| rootMargin | string | 0px | Margin around root element |
+| threshold | number \| number[] | 0 | Intersection ratio threshold(s) |
+
+#### Custom _`Options`_
+
+| Property | Type | Default | Description |
+| --------------- | :----------------------------------------: | :-------: | --------------------------------------------------------- |
+| onlyTriggerOnce | boolean | false | Controls whether to observe only the initial intersection |
+| onIntersection | (entry: IntersectionObserverEntry) => void | undefined | Callback fired on every intersection of the element |
+
+### Type Definitions
+
+::: details
```ts
-import { ElementRef, useRef } from 'react'
-import { useInterSectionObserver } from 'classic-react-hooks'
-
-export default function Intersection() {
- const purpleBoxRef = useRef>(null)
- const greenBoxRef = useRef>(null)
- const [isPurpleVisible, isGreenVisible] = useInterSectionObserver([purpleBoxRef, greenBoxRef], {
- threshold: 0,
- root: null,
- rootMargin: '-150px',
- mode: 'virtualized',
+export interface BaseIntersectionObserverOptions {
+ onIntersection?: (entry: IntersectionObserverEntry) => void
+ onlyTriggerOnce?: boolean
+}
+
+export interface IntersectionObserverOptions
+ extends IntersectionObserverInit,
+ BaseIntersectionObserverOptions {
+ key?: Key
+}
+
+export type IntersectionObserverResult = {
+ // Dynamic property names based on key
+ [K in Key as Key extends '' ? 'element' : `${Key}Element`]: HTMLElement | null
+} & {
+ [K in Key as Key extends '' ? 'setElementRef' : `set${Capitalize}ElementRef`]: (
+ elementNode: HTMLElement | null
+ ) => void
+} & {
+ [K in Key as Key extends '' ? 'isElementIntersecting' : `is${Capitalize}ElementIntersecting`]: boolean
+}
+````
+
+:::
+
+## Return Value(s)
+
+The hook returns an object with dynamically named properties based on the `key` parameter:
+
+- **Without key:** `element`, `setElementRef`, `isElementIntersecting`
+- **With key:** `{key}Element`, `set{Key}ElementRef`, `is{Key}ElementIntersecting`
+
+::: info
+**`element`:** Holds the reference of element which is being observed, initial value is undefined.
+
+**`setElementRef`:** A Setter function to store the element reference within `element`, which will be observed.
+
+**`isElementIntersecting`:** Holds the boolean intersection status of the `element` weather it is intersecting the screen or not.
+:::
+
+## Common Use Cases
+
+- **Lazy loading:** Load images or content when they come into view
+- **Infinite scrolling:** Load more content when reaching the end
+- **Performance optimization:** Pause expensive operations when elements are not visible
+
+## Usage Examples
+
+### Basic Intersection Observer
+
+```tsx {4-9,14}
+import { useIntersectionObserver } from 'classic-react-hooks'
+
+export default function BasicExample() {
+ const { element, setElementRef, isElementIntersecting } = useIntersectionObserver({
+ threshold: 0.5,
+ onIntersection: (entry) => {
+ console.log('Intersection changed:', entry.isIntersecting)
+ },
})
return (
- <>
-
- Scroll to the very bottom of the page
-
-
-
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Modi quae illum rem quod recusandae a tempora
- officia natus quos dignissimos, eum beatae ea! Consectetur nemo assumenda eligendi optio voluptatum fuga.
-
-
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Modi quae illum rem quod recusandae a tempora
- officia natus quos dignissimos, eum beatae ea! Consectetur nemo assumenda eligendi optio voluptatum fuga.
-
+
+
+
+ {isElementIntersecting ? 'Visible!' : 'Not visible'}
+
+
+
+ )
+}
+```
-
+
- purple
+ Hero Section {isHeroElementIntersecting ? '(Visible)' : '(Hidden)'}
+
+
+
Scroll to see the hero section intersection status change
+
+ )
+}
+```
+
+:::
+
+### One-Time Trigger
+
+::: details Example
+
+```tsx {7-16}
+import { useState } from 'react'
+import { useIntersectionObserver } from 'classic-react-hooks'
+
+export default function OneTimeExample() {
+ const [hasBeenSeen, setHasBeenSeen] = useState(false)
+
+ const { setElementRef, isElementIntersecting } = useIntersectionObserver({
+ onlyTriggerOnce: true, // [!code ++]
+ threshold: 0.8,
+ onIntersection: (entry) => {
+ if (entry.isIntersecting) {
+ setHasBeenSeen(true)
+ console.log('Element seen for the first time!')
+ }
+ },
+ })
+
+ return (
+
+
+
+ {hasBeenSeen ? 'I was seen!' : 'Scroll down to see me'}
+
+
+
+ )
+}
+```
+
+:::
+
+### Multiple Thresholds
+
+::: details Example
+
+```tsx {4-10}
+import { useIntersectionObserver } from 'classic-react-hooks'
+
+export default function MultipleThresholdsExample() {
+ const { setElementRef, isElementIntersecting } = useIntersectionObserver({
+ threshold: [0, 0.25, 0.5, 0.75, 1.0], // [!code ++]
+ onIntersection: (entry) => {
+ const percentage = Math.round(entry.intersectionRatio * 100)
+ console.log(`Element is ${percentage}% visible`)
+ },
+ })
+
+ return (
+
+
- green
+
Check console for intersection percentage
- >
+
)
}
```
+
+:::
diff --git a/apps/doc/hooks/use-interval-effect.md b/apps/doc/hooks/use-interval-effect.md
index d572d7a..3aa7548 100644
--- a/apps/doc/hooks/use-interval-effect.md
+++ b/apps/doc/hooks/use-interval-effect.md
@@ -4,38 +4,59 @@ outline: deep
# use-interval-effect
-- A hooks which fires the provided callback every time when the given delay is passed, just like the `setInterval`.
+_`use-interval-effect`_ is a declarative React hook that provides a safe and flexible abstraction over `setInterval`.
-### Parameters
+It repeatedly executes a callback at a specified interval while automatically handling setup and cleanup during the component lifecycle. The hook exposes simple control methods to pause or restart the interval, optionally with a new duration, without reimplementing timer logic. Its stable, cleanup-aware design prevents orphaned intervals and unexpected side effects.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | -------------------------------------------------------------------- |
-| cb | Function | ✅ | - | Callback gets fired after every given amount of interval is passed . |
-| interval | number | ❌ | 100 | Interval value after which the callback is fired. |
+::: tip
+This hook is ideal for counters, polling, animations, and periodic background tasks.
+:::
-### Returns
+## Features
-- It returns an object.
-- `clearTimer` : () => void
-- `restartTimer` : () => void
+- **Recurring execution:** Executes a callback at regular intervals
+- **Flexible control:** Provides methods to clear or restart the timer with different intervals
+- **Auto cleanup:** Automatically clears up interval on component unmount
-### Usage
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :------: | :------: | :-----------: | --------------------------------------------------------------- |
+| handler | Function | ✅ | - | The callback function to execute at each interval |
+| interval | number | ❌ | 100 | The delay in milliseconds between each execution of the handler |
+
+## Return value(s)
+
+This hooks returns an object having several utility functions for controlling the interval-effect:
+
+| Property | Type | Description |
+| ------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| clearTimer | () => void | Clears the current interval timer, stopping the recurring execution of the handler. Similar to calling `clearInterval()` on a standard interval. |
+| restartTimer | (new_interval?: number) => void | Clears the current timer and starts a new one. Optionally accepts a `new_interval` parameter to use a different interval duration. If no interval is provided, uses the original interval value. |
+
+## Usage Examples
+
+### Basic example
```ts
import { useState } from 'react'
import { useIntervalEffect } from 'classic-react-hooks'
-export default function YourComponent() {
- const [counter, setCounter] = useState(0)
- const { clearTimer, restartTimer } = useIntervalEffect(() => {
- setCounter((c) => c + 1)
- }, 1000)
+export default function Counter() {
+ const [count, setCount] = useState(0)
+
+ const { clearTimer, restartTimer } = useIntervalEffect({
+ handler: () => setCount((prev) => prev + 1),
+ interval: 1000, // 1 second
+ })
return (
-
{counter}
-
Pause timer
-
Restart timer
+
Count: {count}
+
Pause
+
restartTimer()}>Resume
+
restartTimer(500)}>Speed Up (500ms)
+
restartTimer(2000)}>Slow Down (2s)
)
}
diff --git a/apps/doc/hooks/use-is-online.md b/apps/doc/hooks/use-is-online.md
deleted file mode 100644
index b42297c..0000000
--- a/apps/doc/hooks/use-is-online.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-outline: deep
----
-
-# use-is-online
-
-- A simple hook for getting the network connection state.
-
-### Returns
-
-- `connectionState` : boolean
-
-### Usage
-
-```ts
-import { useIsOnline } from 'classic-react-hooks'
-
-export default function YourComponent() {
- const isOnline = useIsOnline()
-
- return {isOnline ? 'online' : 'offline'}
-}
-```
diff --git a/apps/doc/hooks/use-local-storage.md b/apps/doc/hooks/use-local-storage.md
index 4af8e56..029c19e 100644
--- a/apps/doc/hooks/use-local-storage.md
+++ b/apps/doc/hooks/use-local-storage.md
@@ -4,49 +4,469 @@ outline: deep
# use-local-storage
-- A hook for managing the states with `local-storage`
-- It automatically updates the state in `local-storage`
-- It is `useState` with local storage power.
+_`use-local-storage`_ is a React hook that provides a `useState`-compatible API for persisting state in `localStorage` with built-in synchronization and type safety.
-### Parameters
+It automatically keeps React state, `localStorage`, and multiple browser tabs in sync while remaining SSR-friendly. The hook supports custom data encoding and decoding for advanced use cases like encryption or compression. It also handles key migration seamlessly without data loss.
-| Parameter | Type | Required | Default Value | Description |
-| ------------ | :----: | :------: | :-----------: | ---------------------------------------------------- |
-| key | string | ✅ | - | key for getting an item from local-storage |
-| defaultValue | any | ❌ | - | A initial value when item is not found local-storage |
+## Features
-### Returns
+- **useState-compatible API:** Drop-in replacement with full support for functional updates
+- **SSR safe:** Predictable initial values prevent hydration mismatches
+- **Automatic synchronization:** Bidirectional sync between React state, `localStorage`, and browser tabs
+- **Error resilience:** Graceful fallbacks when storage operations fail
+- **Type-safe by design:** Strong TypeScript inference with generic support
+- **Custom encoding/decoding:** Transform data via encryption, compression, or serialization strategies
+- **Dynamic key migration:** Automatically migrates stored data when the key changes
+- **Synchronous persistence:** State updates are synchronous and immediately written to `localStorage`
-- It returns an array of `state` and setter function `setState`.
-- `state` : It's type get inferred by `defaultValue` parameter.
-- `setState` : A function just like the setter function from `useState`.
+::: danger Important Notes
-### Usage
+- **Automatic Serialization:** Data is automatically serialized to JSON when storing.
+- **Fallback value:** Always provide default values for SSR fallback.
+- **Encoder/Decoder:** Applied after JSON serialization and before JSON parsing respectively.
-```ts
+:::
+
+## Problem It Solves
+
+::: details Manual LocalStorage Synchronization
+
+---
+
+**Problem:-** Manually keeping React state synchronized with `localStorage` requires complex boilerplate code and is prone to sync issues.
+
+```tsx
+// ❌ Manual synchronization nightmare
+function UserSettings() {
+ const [theme, setTheme] = useState('light')
+
+ // Load from localStorage on mount
+ useEffect(() => {
+ const saved = localStorage.getItem('theme')
+ if (saved) {
+ try {
+ setTheme(JSON.parse(saved))
+ } catch (error) {
+ console.error('Failed to parse theme from localStorage')
+ }
+ }
+ }, [])
+
+ // Save to localStorage on every change
+ useEffect(() => {
+ localStorage.setItem('theme', JSON.stringify(theme))
+ }, [theme])
+
+ return (
+ {
+ setTheme(e.target.value)
+
+ // Or do this manually to sync with localStorage
+ // localStorage.setItem('theme', JSON.stringify(theme))
+ }}
+ >
+ Light
+ Dark
+
+ )
+}
+```
+
+---
+
+**Solution:-** This hook provides automatic bidirectional synchronization between React state and localStorage with a single line of code.
+
+It's designed to be a drop-in replacement for `useState`, maintaining the familiar API.
+
+```tsx
+// ✅ Automatic synchronization
+function UserSettings() {
+ const [theme, setTheme] = useLocalStorage({ key: 'theme', initialValue: 'light' })
+
+ return (
+ setTheme(e.target.value)}>
+ Light
+ Dark
+
+ )
+}
+```
+
+:::
+::: details Inconsistent useState API Compatibility
+
+---
+
+**Problem:-** Custom localStorage solutions often don't maintain the familiar `useState` API, breaking developer expectations and existing code patterns.
+
+```tsx
+// ❌ Non-standard API breaks familiar patterns
+function BrokenComponent() {
+ const [count, updateCount] = someLocalStorageHook('count', 0)
+
+ // This doesn't work because updateCount doesn't support function updates
+ updateCount((prev) => prev + 1) // ❌ TypeError
+
+ // Forced to use unfamiliar patterns
+ updateCount(count + 1) // ❌ Race condition risk
+}
+```
+
+---
+
+**Solution:-** This hook maintains 100% API compatibility with useState, including support for functional updates and previous value callbacks.
+
+```tsx
+// ✅ Perfect useState compatibility
+function Component() {
+ const [count, setCount] = useLocalStorage({ key: 'count', initialValue: 0 })
+
+ // All familiar useState patterns work perfectly
+ setCount(5) // Direct value
+ setCount((prev) => prev + 1) // Functional update
+ setCount((c) => c * 2) // Previous value callback
+}
+```
+
+:::
+
+::: details Server-Side Rendering Compatibility Issues
+
+---
+
+**Problem:-** Direct localStorage access during SSR causes `hydration mismatches` and crashes because localStorage isn't available on the server.
+
+```tsx
+// ❌ SSR/hydration nightmare
+function ProblematicComponent() {
+ const [theme, setTheme] = useState(() => {
+ return localStorage.getItem('theme') || 'light' // ❌ Crashes during SSR
+ })
+
+ // Hydration mismatch: server renders 'light', client might render 'dark'
+}
+```
+
+---
+
+**Solution:-** The hook's `initialValue` prop ensures consistent initial renders and smooth hydration by providing predictable fallback values.
+
+```tsx
+// ✅ SSR-compatible with smooth hydration
+function SSRFriendlyComponent() {
+ const [theme, setTheme] = useLocalStorage({
+ key: 'theme',
+ initialValue: 'light', // Used during SSR and as fallback
+ })
+
+ // Server and client both start with 'light'
+ // Client hydrates smoothly, then updates from localStorage
+}
+```
+
+:::
+
+::: details Lack of Type Safety
+
+---
+
+**Problem:-** localStorage operations are inherently `untyped`, leading to runtime errors and `unpredictable` behavior when data types don't match expectations.
+
+```tsx
+// ❌ No type safety leads to runtime errors
+function UnsafeComponent() {
+ const [settings, setSettings] = useState()
+
+ useEffect(() => {
+ const saved = localStorage.getItem('settings')
+ setSettings(JSON.parse(saved)) // Could be anything!
+ }, [])
+
+ // Runtime error if settings isn't the expected shape
+ return {settings.theme.mode}
// ❌ Potential crash
+}
+```
+
+---
+
+**Solution:-** The hook provides full TypeScript support with generic type parameters that ensure type safety throughout the application.
+
+```tsx
+// ✅ Full type safety with TypeScript generics
+interface UserSettings {
+ theme: 'light' | 'dark'
+ language: 'en' | 'es' | 'fr'
+ notifications: boolean
+}
+
+function SafeComponent() {
+ const [settings, setSettings] = useLocalStorage({
+ key: 'user-settings',
+ initialValue: { theme: 'light', language: 'en', notifications: true },
+ })
+
+ // TypeScript ensures settings has the correct shape
+ return {settings.theme}
// ✅ Type-safe access
+
+ // TypeScript prevents invalid updates
+ setSettings({ theme: 'blue' }) // ❌ TypeScript error: 'blue' not assignable
+}
+```
+
+:::
+
+::: details Lack of Data Security and Transformation
+
+---
+
+**Problem:-** Sensitive data stored in localStorage is visible in plain text, and there's no built-in way to transform or compress data before storage.
+
+```tsx
+// ❌ Sensitive data exposed in plain text
+function InsecureComponent() {
+ const [apiKey, setApiKey] = useLocalStorage({ key: 'api-key', initialValue: '' })
+
+ // API key stored as plain text in localStorage - anyone can read it!
+ // No way to compress large data structures
+}
+```
+
+---
+
+**Solution:-** The hook supports optional `encoder` and `decoder` functions for custom data transformation like encryption, compression, or Base64 encoding.
+
+```tsx
+// ✅ Encrypted storage with custom encoder/decoder
+function SecureComponent() {
+ const [apiKey, setApiKey] = useLocalStorage({
+ key: 'api-key',
+ initialValue: '',
+ encoder: (value) => btoa(value), // Base64 encode
+ decoder: (value) => atob(value), // Base64 decode
+ })
+
+ // Or use real encryption
+ const [sensitiveData, setSensitiveData] = useLocalStorage({
+ key: 'sensitive',
+ initialValue: {},
+ encoder: (value) => encryptData(value), // Your encryption function
+ decoder: (value) => decryptData(value), // Your decryption function
+ })
+}
+```
+
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| ------------ | :-----------------------: | :------: | :-----------: | ------------------------------------------------------------ |
+| key | string | ✅ | - | Unique key for localStorage item |
+| initialValue | State \| (() => State) | ❌ | undefined | Initial value when no stored value exists |
+| encoder | (value: string) => string | ❌ | undefined | Optional function to encode stringified value before storing |
+| decoder | (value: string) => string | ❌ | undefined | Optional function to decode stored value before parsing |
+
+## Return Value(s)
+
+Returns a tuple `[state, setState]` similar to `useState`:
+
+| Index | Type | Description |
+| ----- | ----------------------------------- | ---------------------------------------------------------------------------- |
+| 0 | State | Current state value from localStorage |
+| 1 | Dispatch\\> | Function to update state (supports both direct values and updater functions) |
+
+## Common Use Cases
+
+- Theme preferences (dark/light mode)
+- Form draft saving (auto-save functionality)
+- Shopping cart persistence
+- User settings and preferences
+- Feature flags for application
+- Encrypted/encoded sensitive data storage
+- Compressed data for large objects
+
+## Usage Examples
+
+### Basic User Preferences
+
+```ts {4,5,9,14}
import { useLocalStorage } from 'classic-react-hooks'
-export default function YourComponent() {
- const [user_details, setUserDetails] = useLocalStorage('user_details', {
- name: '',
+function UserPreferences() {
+ const [theme, setTheme] = useLocalStorage({ key: 'theme', initialValue: 'light' })
+ const [language, setLanguage] = useLocalStorage({ key: 'language', initialValue: 'en' })
+
+ return (
+
+ setTheme(e.target.value)}>
+ Light
+ Dark
+
+
+ setLanguage(e.target.value)}>
+ English
+ Spanish
+ French
+
+
+ )
+}
+```
+
+### Complex Object State
+
+::: details
+
+```ts
+interface UserProfile {
+ name: string
+ email: string
+ preferences: {
+ notifications: boolean
+ newsletter: boolean
+ }
+}
+
+function ProfileForm() {
+ const [profile, setProfile] = useLocalStorage({
+ key: 'user-profile',
+ initialValue: {
+ name: '',
+ email: '',
+ preferences: {
+ notifications: true,
+ newsletter: false,
+ },
+ },
+ })
+
+ const updateName = (name: string) => {
+ setProfile((prev) => ({
+ ...prev,
+ name,
+ }))
+ }
+
+ const toggleNotifications = () => {
+ setProfile((prev) => ({
+ ...prev,
+ preferences: {
+ ...prev.preferences,
+ notifications: !prev.preferences.notifications,
+ },
+ }))
+ }
+
+ return (
+
+ )
+}
+```
+
+:::
+
+### Encoded/Encrypted Storage
+
+::: details
+
+```ts
+// Base64 encoding example
+function Base64Example() {
+ const [token, setToken] = useLocalStorage({
+ key: 'auth-token',
+ initialValue: '',
+ encoder: (value) => btoa(value), // Encode to Base64
+ decoder: (value) => atob(value), // Decode from Base64
+ })
+
+ return setToken(e.target.value)} placeholder='Enter token' />
+}
+
+// Custom encryption example (pseudo-code)
+function EncryptedStorage() {
+ const encrypt = (value: string) => {
+ // Your encryption logic (e.g., AES)
+ return CryptoJS.AES.encrypt(value, 'secret-key').toString()
+ }
+
+ const decrypt = (value: string) => {
+ // Your decryption logic
+ const bytes = CryptoJS.AES.decrypt(value, 'secret-key')
+ return bytes.toString(CryptoJS.enc.Utf8)
+ }
+
+ const [sensitiveData, setSensitiveData] = useLocalStorage({
+ key: 'sensitive-info',
+ initialValue: { apiKey: '', secret: '' },
+ encoder: encrypt,
+ decoder: decrypt,
})
return (
- setUserDetails((user) => {
- user.name = e.target.value
- return {
- ...user,
- }
- })
- }
- className='py-1 px-3 rounded-md bg-white dark:bg-gray-900'
- placeholder='update name...'
+ type='password'
+ value={sensitiveData.apiKey}
+ onChange={(e) => setSensitiveData((prev) => ({ ...prev, apiKey: e.target.value }))}
+ placeholder='API Key'
/>
)
}
+
+// Compression example using pako library
+function CompressedStorage() {
+ const compress = (value: string) => {
+ return pako.deflate(value, { to: 'string' })
+ }
+
+ const decompress = (value: string) => {
+ return pako.inflate(value, { to: 'string' })
+ }
+
+ const [largeData, setLargeData] = useLocalStorage({
+ key: 'large-dataset',
+ initialValue: [],
+ encoder: compress,
+ decoder: decompress,
+ })
+
+ // Useful for storing large arrays or objects
+}
+```
+
+:::
+
+## Data Flow
+
+The encoding and decoding process follows this flow:
+
+**Storing data:**
+
+```
+State → JSON.stringify() → encoder() → localStorage
```
+
+**Retrieving data:**
+
+```
+localStorage → decoder() → JSON.parse() → State
+```
+
+Note: The encoder operates on the JSON-stringified value, and the decoder operates before JSON parsing.
diff --git a/apps/doc/hooks/use-multi-intersection-observer.md b/apps/doc/hooks/use-multi-intersection-observer.md
new file mode 100644
index 0000000..d40f661
--- /dev/null
+++ b/apps/doc/hooks/use-multi-intersection-observer.md
@@ -0,0 +1,211 @@
+---
+outline: deep
+---
+
+# use-multi-intersection-observer
+
+_`use-multi-intersection-observer`_ is a React hook that enables observing multiple elements simultaneously using a single, unified API.
+
+Built on top of [use-intersection-observer](use-intersection-observer.html), it preserves full type safety, predictable behavior, and consistent return shapes. The hook reduces boilerplate by allowing shared configuration while generating uniquely typed observers for each key. It scales intersection tracking cleanly across complex layouts and multi-section UIs.
+
+## Features
+
+- **Multiple observers, one hook:** Create many intersection observers with a single call
+- **Unified API:** Each observer mirrors the [use-intersection-observer](use-intersection-observer.html) API
+- **Full type safety:** Strong TypeScript inference with IntelliSense for all properties
+- **Key-based access:** Access each observer via a unique key
+- **Shared configuration:** Apply common `IntersectionObserver` options across observers
+- **Independent state:** Each observer manages its own element ref and intersection state
+- **Proven core:** Built on `use-intersection-observer` for consistency and reliability
+
+## Problem It Solves
+
+::: details Eliminates repetitive `use-intersection-observer` calls for multiple elements
+**Problem:** Managing many intersection observers requires repetitive hook calls
+
+```ts
+// ❌ Without multi-observer hook - repetitive
+const hero = useIntersectionObserver({ key: 'hero', threshold: 0.5 })
+const about = useIntersectionObserver({ key: 'about', threshold: 0.5 })
+const services = useIntersectionObserver({ key: 'services', threshold: 0.5 })
+const contact = useIntersectionObserver({ key: 'contact', threshold: 0.5 })
+```
+
+**Solution:** Single hook call for multiple observers
+
+```ts
+// ✅ With multi-observer hook
+const sections = useMultiIntersectionObserver(['hero', 'about', 'services', 'contact'], { threshold: 0.5 })
+```
+
+:::
+
+::: details Type Safety at Scale
+**Problem:** Maintaining type safety with multiple dynamically named properties
+
+- Loses type inference while managing multiple observers manually
+- No IntelliSense for dynamically generated property names
+- Runtime errors due to typos in property access
+
+**Solution:** This hook provides full type safety and comprehensive IntelliSense for all generated observer properties
+
+```ts
+// ✅ Full type safety and IntelliSense
+const observers = useMultiIntersectionObserver(['hero', 'footer'] as const)
+// TypeScript knows: observers.hero.setHeroElementRef, observers.hero.isHeroElementIntersecting
+// TypeScript knows: observers.footer.setFooterElementRef, observers.footer.isFooterElementIntersecting
+```
+
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :------------------------------------------: | :------: | :-----------: | ------------------------------------------------- |
+| keys | readonly Key[] | ✅ | - | Array of unique keys for creating named observers |
+| options | [MultipleObserverOptions](#type-definitions) | ❌ | undefined | Shared configuration for all observers |
+
+### Options Parameter
+
+All options from [useIntersectionObserver](use-intersection-observer.html) except `key` (which is provided via the `keys` array):
+
+### Type Definitions
+
+::: details
+
+```ts
+export type MultipleObserverOptions = Omit
+
+// Return type is a record where each key maps to its observer result
+type MultipleIntersectionObserverResult = Record<
+ Key,
+ ReturnType>
+>
+```
+
+:::
+
+## Return Value(s)
+
+The hook returns a record object where each key from the input array maps to its corresponding intersection observer result:
+
+- **Without key:** `element`, `setElementRef`, `isElementIntersecting`
+- **With key:** `{key}Element`, `set{Key}ElementRef`, `is{Key}ElementIntersecting`
+
+```ts
+// Object contains all of the obervers
+{ // [!code ++]
+ [key]: {
+ [`${key}Element`]: HTMLElement | null,
+ [`set${Capitalize}ElementRef`]: (element: HTMLElement | null) => void,
+ [`is${Capitalize}ElementIntersecting`]: boolean
+ }
+} // [!code ++]
+```
+
+::: info
+**`{key}Element`:** Holds the element reference which is being observed, it's initially undefined.
+
+**`set{Capitalize}ElementRef`:** Setter function to store the element reference within `element`, which is going tobe observed.
+
+**`is{Capitalize}ElementIntersecting`:** Holds the boolean intersection status of the `element` weather it is intersecting the screen or not.
+:::
+
+## Common Use Cases
+
+- **Multi-section navigation:** Track visibility of multiple page sections for active navigation states
+- **Lazy loading galleries:** Load multiple images or content blocks as they come into view
+
+## Usage Examples
+
+### Basic Multiple Observers
+
+```tsx {4-9}
+import { useMultiIntersectionObserver } from 'classic-react-hooks'
+
+export default function MultipleObserversExample() {
+ const observers = useMultiIntersectionObserver(['header', 'main', 'footer'] as const, {
+ threshold: 0.3,
+ onIntersection: (entry) => {
+ console.log('Element intersection changed:', entry.target.id)
+ },
+ })
+
+ return (
+
+
+
+ Header {observers.header.isHeaderElementIntersecting ? '(Visible)' : '(Hidden)'}
+
+
+
+
+
+ Main Content {observers.main.isMainElementIntersecting ? '(Visible)' : '(Hidden)'}
+
+
+
+
+
+ Footer {observers.footer.isFooterElementIntersecting ? '(Visible)' : '(Hidden)'}
+
+
+
+ )
+}
+```
+
+::: danger Important
+Each key in the array creates a separate `useIntersectionObserver` instance. While this provides maximum flexibility, consider the performance impact when observing many elements simultaneously.
+:::
+
+### One-Time Trigger
+
+::: details Example
+
+```tsx {7-16}
+import { useState } from 'react'
+import { useMultiIntersectionObserver } from 'classic-react-hooks'
+
+export default function OneTimeExample() {
+ const [hasBeenSeen, setHasBeenSeen] = useState(false)
+
+ const { setElementRef, isElementIntersecting } = useMultiIntersectionObserver({
+ onlyTriggerOnce: true, // [!code ++]
+ threshold: 0.8,
+ onIntersection: (entry) => {
+ if (entry.isIntersecting) {
+ setHasBeenSeen(true)
+ console.log('Element seen for the first time!')
+ }
+ },
+ })
+
+ return (
+
+
+
+ {hasBeenSeen ? 'I was seen!' : 'Scroll down to see me'}
+
+
+
+ )
+}
+```
+
+:::
diff --git a/apps/doc/hooks/use-on-mount-effect.md b/apps/doc/hooks/use-on-mount-effect.md
index c96d4ea..cebfc54 100644
--- a/apps/doc/hooks/use-on-mount-effect.md
+++ b/apps/doc/hooks/use-on-mount-effect.md
@@ -4,16 +4,34 @@ outline: deep
# use-on-mount-effect
-- A hooks that fires the given callback only once after the mount.
-- It doesn't take any dependencies.
+_`use-on-mount-effect`_ is a small, intention-revealing React hook that runs a side effect exactly once after a component mounts. It provides a clear, declarative alternative to `useEffect` with an empty dependency array, eliminating ambiguity and dependency mistakes.
-### Parameters
+The hook supports cleanup functions just like `useEffect`, making it safe for subscriptions and external integrations. By explicitly modeling mount-only behavior, it improves code readability and communicates intent more clearly. This makes it ideal for initialization logic and third-party setup code.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | ------------------------------------- |
-| cb | Function | ✅ | - | Callback to fire after initial mount. |
+::: tip
+This hook is perfect for initialization logic that should run exactly once when a component first renders.
+:::
-### Usage
+## Features
+
+- **One-time execution:** Runs callback only once after component mounts
+- **Mount-only focus:** Explicitly designed for mount-time operations
+- **Compatible API:** Wrapper around `useEffect` hook
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :------------------: | :------: | :-----------: | ------------------------------------------------------------------------------------------------------- |
+| cb | React.EffectCallback | ✅ | - | The callback function to execute once after component mounts. Can optionally return a cleanup function. |
+
+## Common Use Cases
+
+- **Setup Initialization:** Running one-time setup code
+- **Third-party libraries:** Initializing external libraries or plugins
+
+## Usage Examples
+
+### Basic Usage - Initialization Logic
```ts
import { useOnMountEffect } from 'classic-react-hooks'
@@ -26,3 +44,13 @@ export default function YourComponent() {
return
}
```
+
+## Comparison with useEffect
+
+| Scenario | useEffect(cb, []) | useOnMountEffect(cb) |
+| ------------------- | -------------------- | ------------------------- |
+| Intent clarity | ❌ Less obvious | ✅ Crystal clear |
+| Code brevity | ❌ More verbose | ✅ Cleaner |
+| Dependency mistakes | ⚠️ Easy to forget [] | ✅ No dependencies needed |
+| TypeScript support | ✅ Yes | ✅ Yes |
+| Cleanup support | ✅ Yes | ✅ Yes |
diff --git a/apps/doc/hooks/use-outside-click.md b/apps/doc/hooks/use-outside-click.md
index 919e75c..f0abb44 100644
--- a/apps/doc/hooks/use-outside-click.md
+++ b/apps/doc/hooks/use-outside-click.md
@@ -4,54 +4,131 @@ outline: deep
# use-outside-click
-- A hook that fires the given callback when clicked outside anywhere of the given html element.
+_`use-outside-click`_ is a React hook that detects clicks occurring outside a specified element and triggers a callback in response.
-### Parameters
+It provides a reliable, declarative solution for dismissible UI components such as modals, dropdowns, and context menus. Built on top of [use-event-listener](use-event-listener.html), it ensures proper event lifecycle management while remaining bubble-phase friendly. The hook integrates seamlessly with React refs and supports conditional event binding.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :-----------------------: | :------: | :-----------: | ----------------------------- |
-| target | [Target](#parametertype) | ✅ | - | Reference of the html element |
-| handler | [Handler](#parametertype) | ❌ | undefined | Callback for the event |
-| options | [Options](#parametertype) | ❌ | undefined | Extra params |
+::: tip
+Perfect for implementing modals, dropdowns and other UI components that need to be closed when users click outside of them.
+:::
-### Types
+## Features
----
+- **Accurate outside click detection:** Triggers callbacks only when clicks occur outside the target element
+- **Bubble-phase handling:** Always listens in the bubbling phase for predictable interaction control
+- **Declarative API:** Attach outside click behavior without imperative DOM logic
+- **Automatic cleanup:** Event listeners are safely removed on unmount or option changes
+- **Conditional binding:** Control listener attachment via `shouldInjectEvent`
+- **Ref-based targeting:** Use `setElementRef` to track the target element without manual refs
-#### ParameterType
+* **Underlying hook:** Built on top of the [use-event-listener](use-event-listener.html) hook
-```ts
-type Target = null | EventTarget | (() => EventTarget | null)
-type Options = { shouldInjectEvent?: boolean | any }
-type Handler = (event: Event) => void
+## Problems It Solves
+
+- Eliminates manual document click listener setup and cleanup
+- Prevents common bugs in outside click detection logic
+- Avoids memory leaks caused by forgotten event listener removal
+- Simplifies dismissible UI behavior across components
+- Preserves control over event bubbling using `stopPropagation`
+- Reduces duplicated outside-click handling logic throughout the app
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :----------------------------: | :------: | :-----------: | ------------------------------------------------ |
+| target | [EvTarget](#type-definitions) | ❌ | - | Function that returns the target element or null |
+| handler | [EvHandler](#type-definitions) | ❌ | undefined | Callback executed on outside click |
+| options | [EvOptions](#type-definitions) | ❌ | undefined | Event listener options and feature flags |
+
+### Standard AddEventListenerOptions
+
+| Property | Type | Default | Description |
+| -------- | ----------- | --------- | -------------------------------------------------------------------------------- |
+| capture | boolean | false | Always `false`. Events are handled during the bubbling phase |
+| once | boolean | false | If `true`, the listener will be automatically removed after being triggered once |
+| passive | boolean | false | If `true`, indicates that the function will never call `preventDefault()` |
+| signal | AbortSignal | undefined | An AbortSignal that can be used to remove the event listener |
+
+### Custom Options
+
+| Property | Type | Default | Description |
+| ----------------- | -------------- | ------- | --------------------------------------------------------------------------------------------------- |
+| shouldInjectEvent | boolean \| any | true | Controls whether the event listener should be attached. When false, the event listener is not added |
+
+### Type Definitions
+
+::: details
+
+```tsx
+type EvTarget = () => EventTarget | null
+type EvHandler = (event: DocumentEventMap['click']) => void
+
+interface EvOptions extends AddEventListenerOptions {
+ // Standard AddEventListenerOptions:
+ capture?: boolean // Always overridden to false internally
+ once?: boolean
+ passive?: boolean
+ signal?: AbortSignal
+
+ // Custom option:
+ shouldInjectEvent?: boolean | any // Controls whether the event should be attached
+}
```
-### Usage
+:::
+
+## Return Value(s)
+
+This hook returns an object that includes a setter function, allowing you to observe and manage the target element through its ref attribute.
+
+| Property | Type | Description |
+| ------------- | ------------------------- | ------------------------------------------------------------------ |
+| setElementRef | [Function](#return-types) | A ref callback that observes the target element for outside clicks |
+
+## Common Use Cases
+
+- Modal dialogs — close when clicking the backdrop
+- Dropdown menus — hide when clicking elsewhere
+- Context menus — dismiss on outside click
+
+## Usage Examples
+
+::: info Note
+Refer to [use-event-listener](/hooks/use-event-listener.html#basic-click-handler) hook for more examples.
+:::
+
+### Modal Component
```ts
-import { useRef } from 'react'
+import { useState } from 'react'
import { useOutsideClick } from 'classic-react-hooks'
-export default function YourComponent() {
- const modalRef = useRef(null)
- useOutsideClick(
- modalRef,
- (e) => {
- console.log('clicked outside on modal. Target = ', e.target)
- },
- { shouldInjectEvent: true }
- )
+function Modal() {
+ const [isOpen, setIsOpen] = useState(false)
- return (
-
-
setIsOpen(false),
+ })
+
+ if (!isOpen) {
+ return (
+
{
+ e.stopPropagation()
+ setIsOpen(true)
}}
- ref={modalRef}
>
- This is modal
+ Open Modal
+
+ )
+ }
+
+ return (
+
+
+
Modal Title
+
Click outside this modal to close it.
+
setIsOpen(false)}>Close
)
diff --git a/apps/doc/hooks/use-synced-effect.md b/apps/doc/hooks/use-synced-effect.md
index 9d2402c..e70206c 100644
--- a/apps/doc/hooks/use-synced-effect.md
+++ b/apps/doc/hooks/use-synced-effect.md
@@ -4,17 +4,35 @@ outline: deep
# use-synced-effect
-- A hooks that fires the given callback for given dependencies when they get change.
-- It works exacatly like `useEffect`. But callback doesn't get fired on initial mount.
+_`use-synced-effect`_ is a React hook that behaves like `useEffect` but intentionally skips execution on the initial render.
-### Parameters
+It allows you to respond to dependency changes without triggering side effects during the first mount, which is a common requirement in real-world applications. The hook correctly handles React StrictMode’s double-invocation behavior while preserving standard cleanup semantics.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | ----------------------------------------------- |
-| cb | Function | ✅ | - | Callback to fire when dependencies get changed. |
-| deps | Array | ❌ | [] | Dependencies. |
+::: tip
+This makes it ideal for side effects that should only run in response to state updates, not initial state setup. It provides a clean, predictable alternative to manual “isMounted” or ref-based guards.
+:::
-### Usage
+## Features
+
+- **Skip initial mount:** Skipping the callback on initial mount
+- **Reactive:** Running the callback only when dependencies actually change
+- **React StrictMode:** Handling React StrictMode double execution correctly
+- **Flexible control:** Supporting cleanup functions just like useEffect
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :------------------: | :------: | :-----------: | --------------------------------------------------------------------------------------------------- |
+| cb | React.EffectCallback | ✅ | - | The callback function to execute when dependencies change. Can optionally return a cleanup function |
+| deps | React.DependencyList | ❌ | [] | An array of dependencies that the effect depends on. |
+
+## Common Use Cases
+
+- Use everywhere just like `useEffect`
+
+## Usage Examples
+
+### Basic Usage - Responding to State Changes
```ts
import { useState } from 'react'
@@ -34,3 +52,49 @@ export default function YourComponent() {
)
}
```
+
+### Same cleanup behaviour just like `useEffect`
+
+::: details Example
+
+```ts {21-23}
+import { useState } from 'react'
+import { useSyncedEffect } from 'classic-react-hooks'
+
+function SearchComponent() {
+ const [query, setQuery] = useState('')
+
+ useSyncedEffect(() => {
+ // Only search when query actually changes, not on initial empty string
+ if (query) {
+ const controller = new AbortController()
+
+ fetch(`/api/search?q=${query}`, {
+ signal: controller.signal,
+ })
+ .then((response) => response.json())
+ .then((data) => {
+ // Handle search results
+ })
+
+ // Cleanup function to cancel the request
+ return () => {
+ controller.abort()
+ }
+ }
+ }, [query])
+
+ return
setQuery(e.target.value)} placeholder='Search...' />
+}
+```
+
+:::
+
+## Comparison with useEffect
+
+| Scenario | useEffect | useSyncedEffect |
+| ------------------- | ---------------- | -------------------- |
+| Initial mount | ✅ Runs | ❌ Skips |
+| Dependency changes | ✅ Runs | ✅ Runs |
+| Cleanup support | ✅ Yes | ✅ Yes |
+| StrictMode handling | ⚠️ May run twice | ✅ Handles correctly |
diff --git a/apps/doc/hooks/use-synced-ref.md b/apps/doc/hooks/use-synced-ref.md
index 6dd2059..ff8ffab 100644
--- a/apps/doc/hooks/use-synced-ref.md
+++ b/apps/doc/hooks/use-synced-ref.md
@@ -4,34 +4,175 @@ outline: deep
# use-synced-ref
-- A replacement for `useRef` hook, which automatically syncs-up with the given state.
-- No need to manually update the ref.
+_`use-synced-ref`_ is a hook that creates a ref that automatically stays in sync with the provided value, ensuring you always have access to the latest state in synchronous/asynchronous operations.
-### Parameters
+## Features
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :--: | :------: | :-----------: | --------------------------- |
-| value | any | ✅ | - | Value to be tracked in ref. |
+- **Always current:** Ref automatically updates to reflect the latest value
+- **Stale closure prevention:** Prevents accessing stale values in async operations
+- **Simple API:** Minimal interface with automatic synchronization
+- **Type safe:** Full TypeScript support with generic typing
-### Returns
+## Problem It Solves
-- It returns the ref of given state.
+::: details **Stale Closure Problem**
-### Usage
+---
+
+**Problem:-** In React, when you capture state values in closures (like in `setTimeout`, event handlers, or async operations), you might get stale values due to how JavaScript closures work.
+
+```tsx
+// ❌ Problematic approach - stale closure issue
+function Component() {
+ const [count, setCount] = useState(0)
+
+ const handleAsyncOperation = () => {
+ setTimeout(() => {
+ // This will always log the value of count when handleAsyncOperation was called
+ // Not the current value after 2 seconds
+ console.log('Stale count:', count) // Might be outdated!
+ }, 2000)
+ }
+
+ return (
+
+
Count: {count}
+
setCount((c) => c + 1)}>Increment
+
Log count after 2s
+
+ )
+}
+```
+
+---
+
+**Solution:-**
+
+- Provides a ref that always contains the current value
+- Eliminates stale closure issues in async operations
+- Ensures you can access the latest state regardless of when the closure was created
+
+```tsx
+// ✅ Clean approach with useSyncedRef
+function Component() {
+ const [count, setCount] = useState(0)
+ const countRef = useSyncedRef(count)
+
+ const handleAsyncOperation = () => {
+ setTimeout(() => {
+ // countRef.current always has the latest value
+ console.log('Current count:', countRef.current) // Always up-to-date!
+ }, 2000)
+ }
+
+ return (
+
+
Count: {count}
+
setCount((c) => c + 1)}>Increment
+
Log count after 2s
+
+ )
+}
+```
+
+:::
+
+::: details **Performance Benefits**
+
+- Lightweight solution with minimal overhead
+- No unnecessary re-renders or effect dependencies
+- Simple ref assignment on every render ensures synchronization
+
+:::
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :--: | :------: | :-----------: | ------------------------------------------- |
+| state | T | ✅ | - | The value to keep synchronized with the ref |
+
+## Return Value(s)
+
+This hook returns the ref version of the provided state, which auto syncs up
+
+| Return Value | Type | Description |
+| ------------ | ------------- | ------------------------------------------------------------------------------------- |
+| syncedRef | RefObject
| A mutable ref object whose `.current` property always contains the latest state value |
+
+## Common Use Cases
+
+- **Async operations:** Accessing latest state in `setTimeout`, `setInterval`, or API calls
+- **Event handlers:** Ensuring event callbacks have access to current state without stale closures
+- **WebSocket handlers:** Accessing current state in WebSocket message handlers
+
+## Usage Examples
+
+### Basic State Synchronization
```ts
import { useState } from 'react'
import { useSyncedRef } from 'classic-react-hooks'
-export default function YourComponent() {
- const [counter, setCounter] = useState(0)
+export default function Counter() {
+ const [count, setCount] = useState(0)
+ const countRef = useSyncedRef(count)
+
+ const handleAsyncOperation = () => {
+ setTimeout(() => {
+ // countRef.current always has the latest value
+ console.log('Current count:', countRef.current)
+ alert(`Count is now: ${countRef.current}`)
+ }, 2000)
+ }
+
+ return (
+
+
Count: {count}
+
setCount((c) => c + 1)}>Increment
+
Show count after 2 seconds
+
+ )
+}
+```
+
+### Event Handlers with Latest State
+
+::: details Example
+
+```ts {6,11}
+import { useState, useCallback } from 'react'
+import { useSyncedRef } from 'classic-react-hooks'
+
+export default function EventExample() {
+ const [messages, setMessages] = useState([])
+ const messagesRef = useSyncedRef(messages)
- const counterRef = useSyncedRef(counter)
+ const handleKeyPress = useCallback((event: KeyboardEvent) => {
+ if (event.key === 'Enter') {
+ // Always access the latest messages array
+ const currentMessages = messagesRef.current
+ console.log('Current messages count:', currentMessages.length)
+
+ setMessages((prev) => [...prev, `Message ${prev.length + 1}`])
+ }
+ }, []) // No need to include messages in dependencies
+
+ useEffect(() => {
+ document.addEventListener('keydown', handleKeyPress)
+ return () => document.removeEventListener('keydown', handleKeyPress)
+ }, [handleKeyPress])
return (
-
setCounter((c) => c + 1)}>increment
+
Press Enter to add messages
+
+ {messages.map((msg, index) => (
+ {msg}
+ ))}
+
)
}
```
+
+:::
diff --git a/apps/doc/hooks/use-throttled-fn.md b/apps/doc/hooks/use-throttled-fn.md
index acca427..8a01c26 100644
--- a/apps/doc/hooks/use-throttled-fn.md
+++ b/apps/doc/hooks/use-throttled-fn.md
@@ -4,38 +4,245 @@ outline: deep
# use-throttled-fn
-- A hook which returns a throttled function.
+A React hook that returns a throttled version of provided function, ensuring it executes at most once per specified time interval, regardless of how frequently it's called.
-### Parameters
+## Features
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | ----------------------------------------------------------- |
-| cb | Function | ✅ | - | A callback which is to be throttled. |
-| delay | number | ❌ | 300 | A delay in milliseconds after that the callback gets fired. |
+- **Rate limiting:** Ensures function executes at most once per specified interval
+- **Immediate Execution:** First call executes immediately, subsequent calls are throttled
+- **Performance Optimized:** Prevents excessive function calls during rapid user interactions
+- **Context preservation:** Maintains original function's `this` context and error behavior
+- **Error handling:** Preserves original function's error behavior
-### Returns
+::: tip
+The `throttled function` is purely ref based and does not change across re-renders.
+:::
-- It returns a function which is throttled version of passed callback.
+## Problem It Solves
-### Usage
+::: details **Boilerplate Reduction**
+
+---
+
+**Problem:-** Manually implementing throttling in React components becomes lengthy, little bit complex code with potential performance issues and inconsistent behavior.
+
+```tsx
+// ❌ Problematic approach which is redundant and verbose
+function ScrollTracker() {
+ const [scrollPosition, setScrollPosition] = useState(0)
+ const lastExecutionTimeRef = useRef(0)
+ const THROTTLE_DELAY = 100
+
+ const handleScroll = useCallback(() => {
+ const currentTime = Date.now()
+
+ if (currentTime - lastExecutionTimeRef.current >= THROTTLE_DELAY) {
+ setScrollPosition(window.scrollY)
+ lastExecutionTimeRef.current = currentTime
+
+ // Additional complex logic for tracking scroll performance
+ console.log('Scroll position updated:', window.scrollY)
+ }
+ }, [])
+
+ useEffect(() => {
+ const throttledScrollHandler = (event: Event) => {
+ handleScroll()
+ }
+
+ window.addEventListener('scroll', throttledScrollHandler, { passive: true })
+
+ return () => {
+ window.removeEventListener('scroll', throttledScrollHandler)
+ }
+ }, [handleScroll])
+
+ return Current scroll: {scrollPosition}px
+}
+```
+
+---
+
+**Solution:-**
+
+- Eliminates repetitive throttling logic
+- Automatic handling of:
+ - First call immediate execution
+ - Context preservation
+ - Error handling
+
+```tsx
+// ✅ Clean, declarative approach
+function ScrollTracker() {
+ const [scrollPosition, setScrollPosition] = useState(0)
+
+ const throttledScrollHandler = useThrottledFn({
+ callbackToThrottle: () => {
+ setScrollPosition(window.scrollY)
+ console.log('Scroll position updated:', window.scrollY)
+ },
+ delay: 100,
+ })
+
+ useEffect(() => {
+ window.addEventListener('scroll', throttledScrollHandler, { passive: true })
+ return () => window.removeEventListener('scroll', throttledScrollHandler)
+ }, [throttledScrollHandler])
+
+ return Current scroll: {scrollPosition}px
+}
+```
+
+:::
+
+::: details **Performance Benefits**
+
+- **Reduces execution frequency:** Limits function calls to specified intervals, preventing performance bottlenecks
+- **Memory efficient:** Minimal overhead with simple timestamp tracking
+
+:::
+
+## Throttling vs Debouncing
+
+| Aspect | Throttling | Debouncing |
+| -------------------- | ---------------------------------- | ------------------------------------------ |
+| **Execution timing** | Executes at regular intervals | Executes after inactivity period |
+| **First call** | Executes immediately | May delay first execution |
+| **Use case** | Continuous events (scroll, resize) | User input completion (search, validation) |
+| **Frequency** | Limited to X times per interval | Executes only after pause |
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| ------------------ | :------------------------------: | :------: | :-----------: | ----------------------------------------------------------------- |
+| callbackToThrottle | [ThrottledFn](#type-definitions) | ✅ | - | The function to throttle |
+| delay | number | ❌ | 300ms | Minimum time interval between function executions in milliseconds |
+
+### Type Definitions
+
+::: details
```ts
+export type ThrottledFn any> = (...args: Parameters) => void
+```
+
+:::
+
+## Return Value(s)
+
+This hook returns the throttled version of provided callback.
+
+| Return Value | Type | Description |
+| ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------ |
+| `throttledFn` | `(...args: Parameters) => void` | Throttled version of the original function that limits execution to the specified interval |
+
+## Common Use Cases
+
+- **API Rate Limiting:** Limiting search API calls while typing
+- **Mouse Movement Tracking:** Tracking mouse coordinate and update on screen
+- **Real-time data updates:** Managing WebSocket or polling frequency
+
+## Usage Examples
+
+### API Rate Limiting
+
+```tsx {9-25}
import { useState } from 'react'
import { useThrottledFn } from 'classic-react-hooks'
-export default function YourComponent() {
- const [throttledInput, setThrottledInput] = useState('')
- const updateInput = useThrottledFn((e) => {
- setThrottledInput(e.target.value)
- }, 300)
+export default function ApiExample() {
+ const [data, setData] = useState([])
+ const [requestCount, setRequestCount] = useState(0)
+ const [isLoading, setIsLoading] = useState(false)
+
+ const throttledFetch = useThrottledFn({
+ callbackToThrottle: async () => {
+ setIsLoading(true)
+ setRequestCount((prev) => prev + 1)
+
+ try {
+ const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
+ const result = await response.json()
+ setData(result)
+ } catch (error) {
+ console.error('Fetch failed:', error)
+ } finally {
+ setIsLoading(false)
+ }
+ },
+ delay: 2000, // Max 1 request per 2 seconds
+ })
return (
-
-
+
+
+ {isLoading ? 'Loading...' : 'Fetch Data (max 1/2sec)'}
+
+
API calls made: {requestCount}
+
+ {data.map((item) => (
+
+ {item.title}
+
+ ))}
+
+
+ Click rapidly - API calls are throttled to 1 per 2 seconds
+
+
+ )
+}
+```
+
+### Mouse Movement Tracking
+
+::: details Example
+
+```tsx {8-17}
+import { useState, useEffect } from 'react'
+import { useThrottledFn } from 'classic-react-hooks'
+
+export default function MouseTracker() {
+ const [mousePos, setMousePos] = useState({ x: 0, y: 0 })
+ const [updateCount, setUpdateCount] = useState(0)
+
+ const throttledMouseMove = useThrottledFn({
+ callbackToThrottle: (event: MouseEvent) => {
+ setMousePos({
+ x: event.clientX,
+ y: event.clientY,
+ })
+ setUpdateCount((prev) => prev + 1)
+ },
+ delay: 50, // 20 updates per second max
+ })
+
+ useEffect(() => {
+ const handleMouseMove = (event: MouseEvent) => {
+ throttledMouseMove(event)
+ }
+
+ document.addEventListener('mousemove', handleMouseMove)
+ return () => document.removeEventListener('mousemove', handleMouseMove)
+ }, [throttledMouseMove])
+
+ return (
+
+
Mouse Position Tracker
+
+ Position: ({mousePos.x}, {mousePos.y})
+
+
Updates: {updateCount}
- value - {throttledInput}
+ Move your mouse around this area
)
}
```
+
+:::
diff --git a/apps/doc/hooks/use-timeout-effect.md b/apps/doc/hooks/use-timeout-effect.md
index 2e19336..d59ac24 100644
--- a/apps/doc/hooks/use-timeout-effect.md
+++ b/apps/doc/hooks/use-timeout-effect.md
@@ -4,35 +4,54 @@ outline: deep
# use-timeout-effect
-- A hooks which fires the provided callback only once when the given delay is passed, just like the `setTimeout`.
+_`use-timeout-effect`_ is a small utility React hook that provides a declarative wrapper around `setTimeout` with built-in lifecycle safety.
-### Parameters
+It schedules a callback to run after a specified delay while automatically cleaning up the timer when the component unmounts. The hook exposes simple control methods to clear or restart the timeout without reimplementing timer logic. This ensures predictable behavior across renders and avoids common pitfalls like orphaned timers.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------: | :------: | :-----------: | --------------------------------------------------------- |
-| cb | Function | ✅ | - | Callback to fire after given amount of timeout is passed. |
-| timeout | number | ❌ | 100 | Timeout value after which the callback is fired. |
+::: tip
+It is well suited for delayed UI updates, notifications, and one-off side effects.
+:::
-### Returns
+## Features
-- It returns an object.
-- `clearTimer` : () => void
-- `restartTimer` : () => void
+- **Scheduled execution:** Executes a callback after a specified delay
+- **Flexible control:** Provides methods to clear or restart the timer
+- **Auto cleanup:** Automatically clears up timer on component unmount
-### Usage
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :------: | :------: | :-----------: | ------------------------------------------------------ |
+| handler | Function | ✅ | - | The callback function to execute after the timeout |
+| timeout | number | ❌ | 100 | The delay in milliseconds before executing the handler |
+
+## Return value(s)
+
+This hooks returns an object having several utility functions for controlling the timeout-effect:
+
+| Property | Type | Description |
+| ------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| clearTimer | () => void | Clears the current timeout timer, preventing the handler from executing if it hasn't already run. Similar to calling `clearTimeout()` on a standard timeout. |
+| restartTimer | (new_interval?: number) => void | Clears the current timer and starts a new one. Optionally accepts a `new_interval` parameter to use a different timeout duration. If no interval is provided, uses the original timeout value. |
+
+## Usage Examples
+
+### Basic use
```ts
import { useState } from 'react'
-import { useTimeoutEffect } from 'classic-react-hooks'
+import useTimeoutEffect from './useTimeoutEffect'
-export default function YourComponent() {
- const [show, setShow] = useState(false)
+export default function BasicExample() {
+ const [message, setMessage] = useState('')
- useTimeoutEffect(() => {
- console.log('use-timeout-callback')
- setShow(true)
- }, 2000)
+ useTimeoutEffect({
+ handler: () => {
+ setMessage('Timer executed!')
+ },
+ timeout: 2000,
+ })
- return
+ return
{message}
}
```
diff --git a/apps/doc/hooks/use-window-resize.md b/apps/doc/hooks/use-window-resize.md
index 522c6cd..02ee7c5 100644
--- a/apps/doc/hooks/use-window-resize.md
+++ b/apps/doc/hooks/use-window-resize.md
@@ -4,48 +4,138 @@ outline: deep
# use-window-resize
-- A hook which evaluates the passed callback on window resize event and returns the result of that callback.
+_`use-window-resize`_ is a React hook that runs a user-defined callback whenever the window is resized and returns its evaluated result.
-### Parameters
+It enables responsive logic by recalculating values such as breakpoints, layout states, or visibility flags in real time.
-| Parameter | Type | Required | Default Value | Description |
-| --------- | :------------------------: | :------: | :-----------: | ------------------------------------------------------------------- |
-| cb | [Callback](#parametertype) | ✅ | - | A callback which gets fired whenever the window resize event occurs |
-| options | [Options](#parametertype) | ❌ | undefined | Options to pass as feature flag |
+Built on top of an internal [use-event-listener](use-event-listener.html), it ensures clean event handling and reactive updates. The hook supports configurable defaults and conditional event injection, while leveraging `useLayoutEffect` to avoid layout reflow and ensure performant measurements.
-#### ParameterType
+## Features
+
+- **Custom resize handler:** Execute any calculation or logic on window resize
+- **Reactive updates:** Automatically recalculates and updates state on resize
+- **Configurable defaults:** Supports initial fallback values before first resize
+- **Conditional event injection:** Optionally disable attaching the resize listener
+- **Performance-optimized:** Uses `useLayoutEffect` for accurate, reflow-safe measurements
+
+## Problems It Solves
+
+- Eliminates repetitive and error-prone window resize event handling
+- Prevents unnecessary layout reflows during resize calculations
+- Simplifies responsive logic without manual state management
+- Avoids boilerplate for adding and cleaning up resize listeners
+- Enables consistent, reusable resize-based behavior across components
+
+## Parameters
+
+| Parameter | Type | Required | Default Value | Description |
+| --------- | :--------------------------: | :------: | :-----------: | ------------------------------------------- |
+| handler | [Handler](#type-definitions) | ✅ | - | Callback function executed on window resize |
+| options | [Options](#type-definitions) | ❌ | undefined | Configuration options |
+| |
+
+### Options Parameter
+
+| Property | Type | Default | Description |
+| ----------------- | ----------- | --------- | ----------------------------------------------------------------------------------------------------------------------- |
+| defaultValue | Generic `T` | undefined | The initial value returned before the first resize event. If not provided, the `handler` is called immediately on mount |
+| shouldInjectEvent | boolean | true | Controls whether the resize event listener should be attached. When `false`, the listener is not added |
+
+### Type Definitions
+
+::: details
```ts
-type Callback = () => T
-type Options = { shouldInjectEvent?: boolean; defaultValue?: T }
+type Handler
= () => T
+type Options = { shouldInjectEvent?: boolean; defaultValue?: T }
```
-### Returns
+:::
-- It returns the value, which is the result of the passed callback.
+## Return value(s)
-### Usage
+Returns the evaluated result of the `handler` function call on resize event.
-```ts
+| Return Value | Type | Description |
+| --------------------------------- | ----------- | -------------------------- |
+| Result of `handler` function call | Generic `T` | Result to use in component |
+
+## Common Use Cases
+
+- Creating dynamic layouts
+- Toggling element visibility based on window dimension
+- Dynamically lazy loading components for mobile and desktop screens
+
+## Usage Examples
+
+### Basic Responsive Breakpoints
+
+```ts {4-10,15-17}
import { useWindowResize } from 'classic-react-hooks'
-export default function YourComponent() {
- const result = useWindowResize(() => {
- if (window.innerWidth < 500) {
- return 'md'
- }
- if (window.innerWidth > 500 && window.innerWidth < 800) {
- return 'lg'
- }
+function ResponsiveComponent() {
+ const breakpoint = useWindowResize(() => {
+ const width = window.innerWidth
+ if (width < 640) return 'sm'
+ if (width < 768) return 'md'
+ if (width < 1024) return 'lg'
return 'xl'
})
return (
- <>
- {result == 'md' && md }
- {result == 'lg' && lg }
- {result == 'xl' && xl }
- >
+
+
Current breakpoint: {breakpoint}
+ {breakpoint === 'sm' &&
}
+ {breakpoint === 'md' &&
}
+ {['lg', 'xl'].includes(breakpoint) &&
}
+
)
}
```
+
+### With Default Value
+
+:::details Example
+
+```ts
+import { useWindowResize } from 'classic-react-hooks'
+
+function ComponentWithDefault() {
+ const isMobile = useWindowResize(() => window.innerWidth < 768, {
+ defaultValue: false, // Assume desktop by default // [!code ++]
+ shouldInjectEvent: false,
+ })
+
+ return {/* Navigation content */}
+}
+```
+
+:::
+
+## Advanced Usage
+
+### Debounced Resize Handler
+
+::: details Example
+
+```ts {7-10}
+import { useMemo } from 'react'
+import { useWindowResize, useDebouncedFn } from 'classic-react-hooks'
+
+function ExpensiveCalculation() {
+ const expensiveHandler = useDebouncedFn(
+ () =>
+ debounce(() => {
+ // Expensive calculation here
+ return performComplexCalculation()
+ }),
+ 250
+ )
+
+ const result = useWindowResize(expensiveHandler)
+
+ return {result}
+}
+```
+
+:::
diff --git a/apps/doc/index.md b/apps/doc/index.md
index c10b436..c55c7d8 100644
--- a/apps/doc/index.md
+++ b/apps/doc/index.md
@@ -3,26 +3,58 @@
layout: home
name: 'classic-react-hooks'
-tagline: An awesome collection of feature packed custom hooks
+tagline: Essential Custom Hooks for React Developers
hero:
name: 'classic-react-hooks'
- tagline: Collection of feature packed custom hooks
+ tagline: Performant · Minimal · Lightweight
actions:
- theme: brand
text: Get Started
link: /getting-started/overview
features:
- - icon: 🚀
- title: Awesome Collection of Hooks
- details: Feature packed custom hooks to make your feature building easy.
+ - icon:
+
+
+ title: Essential React Hooks
+ details: Comprehensive and Feature packed collection of everyday hooks
- - icon:
- title: Type safe
- details: Built in Typescript.
+ - icon:
+
+
+
+ title: Performant, Minimal and Lightweight
+ details: Less effects, Less re-renders, Less memory consumption
- - icon: 🌏
- title: Open-Source
- details: 100% open-source & Happy to recieve contributions.
+ - icon:
+
+
+
+
+
+
+
+
+
+ title: Tree-Shakable
+ details: Zero dependency, Tree-Shakable and Tiny bundles
+
+ - icon:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ title: Type-safe
+ details: Built with TypeScript, with a strong emphasis on type safety
---
diff --git a/apps/doc/package.json b/apps/doc/package.json
index 1db545c..8e1d1f4 100644
--- a/apps/doc/package.json
+++ b/apps/doc/package.json
@@ -1,6 +1,6 @@
{
"name": "docs",
- "version": "0.0.0",
+ "version": "2.0.0",
"description": "Documentation for classic-react-hooks package",
"main": "index.js",
"scripts": {
@@ -10,13 +10,16 @@
},
"keywords": [
"classic-react-hooks",
- "hooks",
- "react hooks"
+ "React hooks",
+ "Custom react hooks",
+ "Essential react hooks",
+ "Functional hook",
+ "hooks"
],
"author": "Ashish-simpleCoder",
"license": "MIT",
- "dependencies": {},
"devDependencies": {
- "vitepress": "^1.0.1"
+ "vitepress": "^1.0.1",
+ "vitepress-plugin-group-icons": "^1.6.5"
}
}
diff --git a/apps/doc/pnpm-lock.yaml b/apps/doc/pnpm-lock.yaml
index db7504e..7c4257a 100644
--- a/apps/doc/pnpm-lock.yaml
+++ b/apps/doc/pnpm-lock.yaml
@@ -1,1205 +1,1729 @@
-lockfileVersion: '6.0'
+lockfileVersion: '9.0'
settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
-devDependencies:
- vitepress:
- specifier: ^1.0.1
- version: 1.0.1(@algolia/client-search@4.23.2)(search-insights@2.13.0)
+importers:
+
+ .:
+ devDependencies:
+ vitepress:
+ specifier: ^1.0.1
+ version: 1.6.3(@algolia/client-search@5.25.0)(postcss@8.5.3)(search-insights@2.17.3)
+ vitepress-plugin-group-icons:
+ specifier: ^1.6.5
+ version: 1.6.5(vite@5.4.19)
packages:
- /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)(search-insights@2.13.0):
- resolution:
- { integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw== }
- dependencies:
- '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)(search-insights@2.13.0)
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)
- transitivePeerDependencies:
- - '@algolia/client-search'
- - algoliasearch
- - search-insights
- dev: true
-
- /@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)(search-insights@2.13.0):
- resolution:
- { integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg== }
- peerDependencies:
- search-insights: '>= 1 < 3'
- dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)
- search-insights: 2.13.0
- transitivePeerDependencies:
- - '@algolia/client-search'
- - algoliasearch
- dev: true
-
- /@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2):
- resolution:
- { integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA== }
- peerDependencies:
- '@algolia/client-search': '>= 4.9.1 < 6'
- algoliasearch: '>= 4.9.1 < 6'
- dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)
- '@algolia/client-search': 4.23.2
- algoliasearch: 4.23.2
- dev: true
-
- /@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2):
- resolution:
- { integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ== }
- peerDependencies:
- '@algolia/client-search': '>= 4.9.1 < 6'
- algoliasearch: '>= 4.9.1 < 6'
- dependencies:
- '@algolia/client-search': 4.23.2
- algoliasearch: 4.23.2
- dev: true
-
- /@algolia/cache-browser-local-storage@4.23.2:
- resolution:
- { integrity: sha512-PvRQdCmtiU22dw9ZcTJkrVKgNBVAxKgD0/cfiqyxhA5+PHzA2WDt6jOmZ9QASkeM2BpyzClJb/Wr1yt2/t78Kw== }
- dependencies:
- '@algolia/cache-common': 4.23.2
- dev: true
-
- /@algolia/cache-common@4.23.2:
- resolution:
- { integrity: sha512-OUK/6mqr6CQWxzl/QY0/mwhlGvS6fMtvEPyn/7AHUx96NjqDA4X4+Ju7aXFQKh+m3jW9VPB0B9xvEQgyAnRPNw== }
- dev: true
-
- /@algolia/cache-in-memory@4.23.2:
- resolution:
- { integrity: sha512-rfbi/SnhEa3MmlqQvgYz/9NNJ156NkU6xFxjbxBtLWnHbpj+qnlMoKd+amoiacHRITpajg6zYbLM9dnaD3Bczw== }
- dependencies:
- '@algolia/cache-common': 4.23.2
- dev: true
-
- /@algolia/client-account@4.23.2:
- resolution:
- { integrity: sha512-VbrOCLIN/5I7iIdskSoSw3uOUPF516k4SjDD4Qz3BFwa3of7D9A0lzBMAvQEJJEPHWdVraBJlGgdJq/ttmquJQ== }
- dependencies:
- '@algolia/client-common': 4.23.2
- '@algolia/client-search': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/client-analytics@4.23.2:
- resolution:
- { integrity: sha512-lLj7irsAztGhMoEx/SwKd1cwLY6Daf1Q5f2AOsZacpppSvuFvuBrmkzT7pap1OD/OePjLKxicJS8wNA0+zKtuw== }
- dependencies:
- '@algolia/client-common': 4.23.2
- '@algolia/client-search': 4.23.2
- '@algolia/requester-common': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/client-common@4.23.2:
- resolution:
- { integrity: sha512-Q2K1FRJBern8kIfZ0EqPvUr3V29ICxCm/q42zInV+VJRjldAD9oTsMGwqUQ26GFMdFYmqkEfCbY4VGAiQhh22g== }
- dependencies:
- '@algolia/requester-common': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/client-personalization@4.23.2:
- resolution:
- { integrity: sha512-vwPsgnCGhUcHhhQG5IM27z8q7dWrN9itjdvgA6uKf2e9r7vB+WXt4OocK0CeoYQt3OGEAExryzsB8DWqdMK5wg== }
- dependencies:
- '@algolia/client-common': 4.23.2
- '@algolia/requester-common': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/client-search@4.23.2:
- resolution:
- { integrity: sha512-CxSB29OVGSE7l/iyoHvamMonzq7Ev8lnk/OkzleODZ1iBcCs3JC/XgTIKzN/4RSTrJ9QybsnlrN/bYCGufo7qw== }
- dependencies:
- '@algolia/client-common': 4.23.2
- '@algolia/requester-common': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/logger-common@4.23.2:
- resolution:
- { integrity: sha512-jGM49Q7626cXZ7qRAWXn0jDlzvoA1FvN4rKTi1g0hxKsTTSReyYk0i1ADWjChDPl3Q+nSDhJuosM2bBUAay7xw== }
- dev: true
-
- /@algolia/logger-console@4.23.2:
- resolution:
- { integrity: sha512-oo+lnxxEmlhTBTFZ3fGz1O8PJ+G+8FiAoMY2Qo3Q4w23xocQev6KqDTA1JQAGPDxAewNA2VBwWOsVXeXFjrI/Q== }
- dependencies:
- '@algolia/logger-common': 4.23.2
- dev: true
-
- /@algolia/recommend@4.23.2:
- resolution:
- { integrity: sha512-Q75CjnzRCDzgIlgWfPnkLtrfF4t82JCirhalXkSSwe/c1GH5pWh4xUyDOR3KTMo+YxxX3zTlrL/FjHmUJEWEcg== }
- dependencies:
- '@algolia/cache-browser-local-storage': 4.23.2
- '@algolia/cache-common': 4.23.2
- '@algolia/cache-in-memory': 4.23.2
- '@algolia/client-common': 4.23.2
- '@algolia/client-search': 4.23.2
- '@algolia/logger-common': 4.23.2
- '@algolia/logger-console': 4.23.2
- '@algolia/requester-browser-xhr': 4.23.2
- '@algolia/requester-common': 4.23.2
- '@algolia/requester-node-http': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /@algolia/requester-browser-xhr@4.23.2:
- resolution:
- { integrity: sha512-TO9wLlp8+rvW9LnIfyHsu8mNAMYrqNdQ0oLF6eTWFxXfxG3k8F/Bh7nFYGk2rFAYty4Fw4XUtrv/YjeNDtM5og== }
- dependencies:
- '@algolia/requester-common': 4.23.2
- dev: true
-
- /@algolia/requester-common@4.23.2:
- resolution:
- { integrity: sha512-3EfpBS0Hri0lGDB5H/BocLt7Vkop0bTTLVUBB844HH6tVycwShmsV6bDR7yXbQvFP1uNpgePRD3cdBCjeHmk6Q== }
- dev: true
-
- /@algolia/requester-node-http@4.23.2:
- resolution:
- { integrity: sha512-SVzgkZM/malo+2SB0NWDXpnT7nO5IZwuDTaaH6SjLeOHcya1o56LSWXk+3F3rNLz2GVH+I/rpYKiqmHhSOjerw== }
- dependencies:
- '@algolia/requester-common': 4.23.2
- dev: true
-
- /@algolia/transporter@4.23.2:
- resolution:
- { integrity: sha512-GY3aGKBy+8AK4vZh8sfkatDciDVKad5rTY2S10Aefyjh7e7UGBP4zigf42qVXwU8VOPwi7l/L7OACGMOFcjB0Q== }
- dependencies:
- '@algolia/cache-common': 4.23.2
- '@algolia/logger-common': 4.23.2
- '@algolia/requester-common': 4.23.2
- dev: true
-
- /@babel/helper-string-parser@7.24.1:
- resolution:
- { integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== }
- engines: { node: '>=6.9.0' }
- dev: true
-
- /@babel/helper-validator-identifier@7.22.20:
- resolution:
- { integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== }
- engines: { node: '>=6.9.0' }
- dev: true
-
- /@babel/parser@7.24.1:
- resolution:
- { integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== }
- engines: { node: '>=6.0.0' }
- hasBin: true
- dependencies:
- '@babel/types': 7.24.0
- dev: true
-
- /@babel/types@7.24.0:
- resolution:
- { integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== }
- engines: { node: '>=6.9.0' }
- dependencies:
- '@babel/helper-string-parser': 7.24.1
- '@babel/helper-validator-identifier': 7.22.20
- to-fast-properties: 2.0.0
- dev: true
-
- /@docsearch/css@3.6.0:
- resolution:
- { integrity: sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ== }
- dev: true
-
- /@docsearch/js@3.6.0(@algolia/client-search@4.23.2)(search-insights@2.13.0):
- resolution:
- { integrity: sha512-QujhqINEElrkIfKwyyyTfbsfMAYCkylInLYMRqHy7PHc8xTBQCow73tlo/Kc7oIwBrCLf0P3YhjlOeV4v8hevQ== }
- dependencies:
- '@docsearch/react': 3.6.0(@algolia/client-search@4.23.2)(search-insights@2.13.0)
- preact: 10.20.1
- transitivePeerDependencies:
- - '@algolia/client-search'
- - '@types/react'
- - react
- - react-dom
- - search-insights
- dev: true
-
- /@docsearch/react@3.6.0(@algolia/client-search@4.23.2)(search-insights@2.13.0):
- resolution:
- { integrity: sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w== }
- peerDependencies:
- '@types/react': '>= 16.8.0 < 19.0.0'
- react: '>= 16.8.0 < 19.0.0'
- react-dom: '>= 16.8.0 < 19.0.0'
- search-insights: '>= 1 < 3'
- peerDependenciesMeta:
- '@types/react':
- optional: true
- react:
- optional: true
- react-dom:
- optional: true
- search-insights:
- optional: true
- dependencies:
- '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)(search-insights@2.13.0)
- '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.23.2)(algoliasearch@4.23.2)
- '@docsearch/css': 3.6.0
- algoliasearch: 4.23.2
- search-insights: 2.13.0
- transitivePeerDependencies:
- - '@algolia/client-search'
- dev: true
-
- /@esbuild/aix-ppc64@0.20.2:
- resolution:
- { integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== }
- engines: { node: '>=12' }
- cpu: [ppc64]
- os: [aix]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm64@0.20.2:
- resolution:
- { integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== }
- engines: { node: '>=12' }
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm@0.20.2:
- resolution:
- { integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== }
- engines: { node: '>=12' }
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-x64@0.20.2:
- resolution:
- { integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-arm64@0.20.2:
- resolution:
- { integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== }
- engines: { node: '>=12' }
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-x64@0.20.2:
- resolution:
- { integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-arm64@0.20.2:
- resolution:
- { integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== }
- engines: { node: '>=12' }
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-x64@0.20.2:
- resolution:
- { integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm64@0.20.2:
- resolution:
- { integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== }
- engines: { node: '>=12' }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm@0.20.2:
- resolution:
- { integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== }
- engines: { node: '>=12' }
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ia32@0.20.2:
- resolution:
- { integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== }
- engines: { node: '>=12' }
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-loong64@0.20.2:
- resolution:
- { integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== }
- engines: { node: '>=12' }
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-mips64el@0.20.2:
- resolution:
- { integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== }
- engines: { node: '>=12' }
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ppc64@0.20.2:
- resolution:
- { integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== }
- engines: { node: '>=12' }
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-riscv64@0.20.2:
- resolution:
- { integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== }
- engines: { node: '>=12' }
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-s390x@0.20.2:
- resolution:
- { integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== }
- engines: { node: '>=12' }
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-x64@0.20.2:
- resolution:
- { integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/netbsd-x64@0.20.2:
- resolution:
- { integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/openbsd-x64@0.20.2:
- resolution:
- { integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/sunos-x64@0.20.2:
- resolution:
- { integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-arm64@0.20.2:
- resolution:
- { integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== }
- engines: { node: '>=12' }
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-ia32@0.20.2:
- resolution:
- { integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== }
- engines: { node: '>=12' }
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-x64@0.20.2:
- resolution:
- { integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== }
- engines: { node: '>=12' }
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@jridgewell/sourcemap-codec@1.4.15:
- resolution:
- { integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== }
- dev: true
-
- /@rollup/rollup-android-arm-eabi@4.13.2:
- resolution:
- { integrity: sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g== }
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-android-arm64@4.13.2:
- resolution:
- { integrity: sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ== }
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-arm64@4.13.2:
- resolution:
- { integrity: sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA== }
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-x64@4.13.2:
- resolution:
- { integrity: sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A== }
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm-gnueabihf@4.13.2:
- resolution:
- { integrity: sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ== }
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-gnu@4.13.2:
- resolution:
- { integrity: sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ== }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-musl@4.13.2:
- resolution:
- { integrity: sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA== }
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-powerpc64le-gnu@4.13.2:
- resolution:
- { integrity: sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ== }
- cpu: [ppc64le]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-riscv64-gnu@4.13.2:
- resolution:
- { integrity: sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw== }
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-s390x-gnu@4.13.2:
- resolution:
- { integrity: sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg== }
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-gnu@4.13.2:
- resolution:
- { integrity: sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A== }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-musl@4.13.2:
- resolution:
- { integrity: sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA== }
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-arm64-msvc@4.13.2:
- resolution:
- { integrity: sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA== }
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-ia32-msvc@4.13.2:
- resolution:
- { integrity: sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw== }
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-x64-msvc@4.13.2:
- resolution:
- { integrity: sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ== }
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@shikijs/core@1.2.1:
- resolution:
- { integrity: sha512-KaIS0H4EQ3KI2d++TjYqRNgwp8E3M/68e9veR4QtInzA7kKFgcjeiJqb80fuXW+blDy5fmd11PN9g9soz/3ANQ== }
- dev: true
-
- /@shikijs/transformers@1.2.1:
- resolution:
- { integrity: sha512-H7cVtrdv6BW2kx83t2IQgP5ri1IA50mE3QnzgJ0AvOKCGtCEieXu0JIP3245cgjNLrL+LBwb8DtTXdky1iQL9Q== }
- dependencies:
- shiki: 1.2.1
- dev: true
-
- /@types/estree@1.0.5:
- resolution:
- { integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== }
- dev: true
-
- /@types/linkify-it@3.0.5:
- resolution:
- { integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw== }
- dev: true
-
- /@types/markdown-it@13.0.7:
- resolution:
- { integrity: sha512-U/CBi2YUUcTHBt5tjO2r5QV/x0Po6nsYwQU4Y04fBS6vfoImaiZ6f8bi3CjTCxBPQSO1LMyUqkByzi8AidyxfA== }
- dependencies:
- '@types/linkify-it': 3.0.5
- '@types/mdurl': 1.0.5
- dev: true
-
- /@types/mdurl@1.0.5:
- resolution:
- { integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA== }
- dev: true
-
- /@types/web-bluetooth@0.0.20:
- resolution:
- { integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow== }
- dev: true
-
- /@vitejs/plugin-vue@5.0.4(vite@5.2.7)(vue@3.4.21):
- resolution:
- { integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ== }
- engines: { node: ^18.0.0 || >=20.0.0 }
- peerDependencies:
- vite: ^5.0.0
- vue: ^3.2.25
- dependencies:
- vite: 5.2.7
- vue: 3.4.21
- dev: true
-
- /@vue/compiler-core@3.4.21:
- resolution:
- { integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og== }
- dependencies:
- '@babel/parser': 7.24.1
- '@vue/shared': 3.4.21
- entities: 4.5.0
- estree-walker: 2.0.2
- source-map-js: 1.2.0
- dev: true
-
- /@vue/compiler-dom@3.4.21:
- resolution:
- { integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA== }
- dependencies:
- '@vue/compiler-core': 3.4.21
- '@vue/shared': 3.4.21
- dev: true
-
- /@vue/compiler-sfc@3.4.21:
- resolution:
- { integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ== }
- dependencies:
- '@babel/parser': 7.24.1
- '@vue/compiler-core': 3.4.21
- '@vue/compiler-dom': 3.4.21
- '@vue/compiler-ssr': 3.4.21
- '@vue/shared': 3.4.21
- estree-walker: 2.0.2
- magic-string: 0.30.8
- postcss: 8.4.38
- source-map-js: 1.2.0
- dev: true
-
- /@vue/compiler-ssr@3.4.21:
- resolution:
- { integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q== }
- dependencies:
- '@vue/compiler-dom': 3.4.21
- '@vue/shared': 3.4.21
- dev: true
-
- /@vue/devtools-api@7.0.25(vue@3.4.21):
- resolution:
- { integrity: sha512-fL6DlRp4MSXCLYcqYvKU7QhQZWE3Hfu7X8pC25BS74coJi7uJeSWs4tmrITcwFihNmC9S5GPiffkMdckkeWjzg== }
- dependencies:
- '@vue/devtools-kit': 7.0.25(vue@3.4.21)
- transitivePeerDependencies:
- - vue
- dev: true
-
- /@vue/devtools-kit@7.0.25(vue@3.4.21):
- resolution:
- { integrity: sha512-wbLkSnOTsKHPb1mB9koFHUoSAF8Dp6Ii/ocR2+DeXFY4oKqIjCeJb/4Lihk4rgqEhCy1WwxLfTgNDo83VvDYkQ== }
- peerDependencies:
- vue: ^3.0.0
- dependencies:
- '@vue/devtools-shared': 7.0.25
- hookable: 5.5.3
- mitt: 3.0.1
- perfect-debounce: 1.0.0
- speakingurl: 14.0.1
- vue: 3.4.21
- dev: true
-
- /@vue/devtools-shared@7.0.25:
- resolution:
- { integrity: sha512-5+XYhcHSXuJSguYnNwL6/e6VTmXwCfryWQOkffh9ZU2zMByybqqqBrMWqvBkqTmMFCjPdzulo66xXbVbwLaElQ== }
- dependencies:
- rfdc: 1.3.1
- dev: true
-
- /@vue/reactivity@3.4.21:
- resolution:
- { integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw== }
- dependencies:
- '@vue/shared': 3.4.21
- dev: true
-
- /@vue/runtime-core@3.4.21:
- resolution:
- { integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA== }
- dependencies:
- '@vue/reactivity': 3.4.21
- '@vue/shared': 3.4.21
- dev: true
-
- /@vue/runtime-dom@3.4.21:
- resolution:
- { integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw== }
- dependencies:
- '@vue/runtime-core': 3.4.21
- '@vue/shared': 3.4.21
- csstype: 3.1.3
- dev: true
-
- /@vue/server-renderer@3.4.21(vue@3.4.21):
- resolution:
- { integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg== }
- peerDependencies:
- vue: 3.4.21
- dependencies:
- '@vue/compiler-ssr': 3.4.21
- '@vue/shared': 3.4.21
- vue: 3.4.21
- dev: true
-
- /@vue/shared@3.4.21:
- resolution:
- { integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g== }
- dev: true
-
- /@vueuse/core@10.9.0(vue@3.4.21):
- resolution:
- { integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg== }
- dependencies:
- '@types/web-bluetooth': 0.0.20
- '@vueuse/metadata': 10.9.0
- '@vueuse/shared': 10.9.0(vue@3.4.21)
- vue-demi: 0.14.7(vue@3.4.21)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(vue@3.4.21):
- resolution:
- { integrity: sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q== }
- peerDependencies:
- async-validator: '*'
- axios: '*'
- change-case: '*'
- drauu: '*'
- focus-trap: '*'
- fuse.js: '*'
- idb-keyval: '*'
- jwt-decode: '*'
- nprogress: '*'
- qrcode: '*'
- sortablejs: '*'
- universal-cookie: '*'
- peerDependenciesMeta:
- async-validator:
- optional: true
- axios:
- optional: true
- change-case:
- optional: true
- drauu:
- optional: true
- focus-trap:
- optional: true
- fuse.js:
- optional: true
- idb-keyval:
- optional: true
- jwt-decode:
- optional: true
- nprogress:
- optional: true
- qrcode:
- optional: true
- sortablejs:
- optional: true
- universal-cookie:
- optional: true
- dependencies:
- '@vueuse/core': 10.9.0(vue@3.4.21)
- '@vueuse/shared': 10.9.0(vue@3.4.21)
- focus-trap: 7.5.4
- vue-demi: 0.14.7(vue@3.4.21)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /@vueuse/metadata@10.9.0:
- resolution:
- { integrity: sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA== }
- dev: true
-
- /@vueuse/shared@10.9.0(vue@3.4.21):
- resolution:
- { integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw== }
- dependencies:
- vue-demi: 0.14.7(vue@3.4.21)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /algoliasearch@4.23.2:
- resolution:
- { integrity: sha512-8aCl055IsokLuPU8BzLjwzXjb7ty9TPcUFFOk0pYOwsE5DMVhE3kwCMFtsCFKcnoPZK7oObm+H5mbnSO/9ioxQ== }
- dependencies:
- '@algolia/cache-browser-local-storage': 4.23.2
- '@algolia/cache-common': 4.23.2
- '@algolia/cache-in-memory': 4.23.2
- '@algolia/client-account': 4.23.2
- '@algolia/client-analytics': 4.23.2
- '@algolia/client-common': 4.23.2
- '@algolia/client-personalization': 4.23.2
- '@algolia/client-search': 4.23.2
- '@algolia/logger-common': 4.23.2
- '@algolia/logger-console': 4.23.2
- '@algolia/recommend': 4.23.2
- '@algolia/requester-browser-xhr': 4.23.2
- '@algolia/requester-common': 4.23.2
- '@algolia/requester-node-http': 4.23.2
- '@algolia/transporter': 4.23.2
- dev: true
-
- /csstype@3.1.3:
- resolution:
- { integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== }
- dev: true
-
- /entities@4.5.0:
- resolution:
- { integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== }
- engines: { node: '>=0.12' }
- dev: true
-
- /esbuild@0.20.2:
- resolution:
- { integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g== }
- engines: { node: '>=12' }
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.20.2
- '@esbuild/android-arm': 0.20.2
- '@esbuild/android-arm64': 0.20.2
- '@esbuild/android-x64': 0.20.2
- '@esbuild/darwin-arm64': 0.20.2
- '@esbuild/darwin-x64': 0.20.2
- '@esbuild/freebsd-arm64': 0.20.2
- '@esbuild/freebsd-x64': 0.20.2
- '@esbuild/linux-arm': 0.20.2
- '@esbuild/linux-arm64': 0.20.2
- '@esbuild/linux-ia32': 0.20.2
- '@esbuild/linux-loong64': 0.20.2
- '@esbuild/linux-mips64el': 0.20.2
- '@esbuild/linux-ppc64': 0.20.2
- '@esbuild/linux-riscv64': 0.20.2
- '@esbuild/linux-s390x': 0.20.2
- '@esbuild/linux-x64': 0.20.2
- '@esbuild/netbsd-x64': 0.20.2
- '@esbuild/openbsd-x64': 0.20.2
- '@esbuild/sunos-x64': 0.20.2
- '@esbuild/win32-arm64': 0.20.2
- '@esbuild/win32-ia32': 0.20.2
- '@esbuild/win32-x64': 0.20.2
- dev: true
-
- /estree-walker@2.0.2:
- resolution:
- { integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== }
- dev: true
-
- /focus-trap@7.5.4:
- resolution:
- { integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w== }
- dependencies:
- tabbable: 6.2.0
- dev: true
-
- /fsevents@2.3.3:
- resolution:
- { integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== }
- engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 }
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /hookable@5.5.3:
- resolution:
- { integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ== }
- dev: true
-
- /magic-string@0.30.8:
- resolution:
- { integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== }
- engines: { node: '>=12' }
- dependencies:
- '@jridgewell/sourcemap-codec': 1.4.15
- dev: true
-
- /mark.js@8.11.1:
- resolution:
- { integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ== }
- dev: true
-
- /minisearch@6.3.0:
- resolution:
- { integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ== }
- dev: true
-
- /mitt@3.0.1:
- resolution:
- { integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== }
- dev: true
-
- /nanoid@3.3.7:
- resolution:
- { integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== }
- engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 }
- hasBin: true
- dev: true
-
- /perfect-debounce@1.0.0:
- resolution:
- { integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== }
- dev: true
-
- /picocolors@1.0.0:
- resolution:
- { integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== }
- dev: true
-
- /postcss@8.4.38:
- resolution:
- { integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== }
- engines: { node: ^10 || ^12 || >=14 }
- dependencies:
- nanoid: 3.3.7
- picocolors: 1.0.0
- source-map-js: 1.2.0
- dev: true
-
- /preact@10.20.1:
- resolution:
- { integrity: sha512-JIFjgFg9B2qnOoGiYMVBtrcFxHqn+dNXbq76bVmcaHYJFYR4lW67AOcXgAYQQTDYXDOg/kTZrKPNCdRgJ2UJmw== }
- dev: true
-
- /rfdc@1.3.1:
- resolution:
- { integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== }
- dev: true
-
- /rollup@4.13.2:
- resolution:
- { integrity: sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g== }
- engines: { node: '>=18.0.0', npm: '>=8.0.0' }
- hasBin: true
- dependencies:
- '@types/estree': 1.0.5
- optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.13.2
- '@rollup/rollup-android-arm64': 4.13.2
- '@rollup/rollup-darwin-arm64': 4.13.2
- '@rollup/rollup-darwin-x64': 4.13.2
- '@rollup/rollup-linux-arm-gnueabihf': 4.13.2
- '@rollup/rollup-linux-arm64-gnu': 4.13.2
- '@rollup/rollup-linux-arm64-musl': 4.13.2
- '@rollup/rollup-linux-powerpc64le-gnu': 4.13.2
- '@rollup/rollup-linux-riscv64-gnu': 4.13.2
- '@rollup/rollup-linux-s390x-gnu': 4.13.2
- '@rollup/rollup-linux-x64-gnu': 4.13.2
- '@rollup/rollup-linux-x64-musl': 4.13.2
- '@rollup/rollup-win32-arm64-msvc': 4.13.2
- '@rollup/rollup-win32-ia32-msvc': 4.13.2
- '@rollup/rollup-win32-x64-msvc': 4.13.2
- fsevents: 2.3.3
- dev: true
-
- /search-insights@2.13.0:
- resolution:
- { integrity: sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw== }
- dev: true
-
- /shiki@1.2.1:
- resolution:
- { integrity: sha512-u+XW6o0vCkUNlneZb914dLO+AayEIwK5tI62WeS//R5HIXBFiYaj/Hc5xcq27Yh83Grr4JbNtUBV8W6zyK4hWg== }
- dependencies:
- '@shikijs/core': 1.2.1
- dev: true
-
- /source-map-js@1.2.0:
- resolution:
- { integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== }
- engines: { node: '>=0.10.0' }
- dev: true
-
- /speakingurl@14.0.1:
- resolution:
- { integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ== }
- engines: { node: '>=0.10.0' }
- dev: true
-
- /tabbable@6.2.0:
- resolution:
- { integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== }
- dev: true
-
- /to-fast-properties@2.0.0:
- resolution:
- { integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== }
- engines: { node: '>=4' }
- dev: true
-
- /vite@5.2.7:
- resolution:
- { integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA== }
- engines: { node: ^18.0.0 || >=20.0.0 }
- hasBin: true
- peerDependencies:
- '@types/node': ^18.0.0 || >=20.0.0
- less: '*'
- lightningcss: ^1.21.0
- sass: '*'
- stylus: '*'
- sugarss: '*'
- terser: ^5.4.0
- peerDependenciesMeta:
- '@types/node':
- optional: true
- less:
- optional: true
- lightningcss:
- optional: true
- sass:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- dependencies:
- esbuild: 0.20.2
- postcss: 8.4.38
- rollup: 4.13.2
- optionalDependencies:
- fsevents: 2.3.3
- dev: true
-
- /vitepress@1.0.1(@algolia/client-search@4.23.2)(search-insights@2.13.0):
- resolution:
- { integrity: sha512-eNr5pOBppYUUjEhv8S0S2t9Tv95LQ6mMeHj6ivaGwfHxpov70Vduuwl/QQMDRznKDSaP0WKV7a82Pb4JVOaqEw== }
- hasBin: true
- peerDependencies:
- markdown-it-mathjax3: ^4
- postcss: ^8
- peerDependenciesMeta:
- markdown-it-mathjax3:
- optional: true
- postcss:
- optional: true
- dependencies:
- '@docsearch/css': 3.6.0
- '@docsearch/js': 3.6.0(@algolia/client-search@4.23.2)(search-insights@2.13.0)
- '@shikijs/core': 1.2.1
- '@shikijs/transformers': 1.2.1
- '@types/markdown-it': 13.0.7
- '@vitejs/plugin-vue': 5.0.4(vite@5.2.7)(vue@3.4.21)
- '@vue/devtools-api': 7.0.25(vue@3.4.21)
- '@vueuse/core': 10.9.0(vue@3.4.21)
- '@vueuse/integrations': 10.9.0(focus-trap@7.5.4)(vue@3.4.21)
- focus-trap: 7.5.4
- mark.js: 8.11.1
- minisearch: 6.3.0
- shiki: 1.2.1
- vite: 5.2.7
- vue: 3.4.21
- transitivePeerDependencies:
- - '@algolia/client-search'
- - '@types/node'
- - '@types/react'
- - '@vue/composition-api'
- - async-validator
- - axios
- - change-case
- - drauu
- - fuse.js
- - idb-keyval
- - jwt-decode
- - less
- - lightningcss
- - nprogress
- - qrcode
- - react
- - react-dom
- - sass
- - search-insights
- - sortablejs
- - stylus
- - sugarss
- - terser
- - typescript
- - universal-cookie
- dev: true
-
- /vue-demi@0.14.7(vue@3.4.21):
- resolution:
- { integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA== }
- engines: { node: '>=12' }
- hasBin: true
- requiresBuild: true
- peerDependencies:
- '@vue/composition-api': ^1.0.0-rc.1
- vue: ^3.0.0-0 || ^2.6.0
- peerDependenciesMeta:
- '@vue/composition-api':
- optional: true
- dependencies:
- vue: 3.4.21
- dev: true
-
- /vue@3.4.21:
- resolution:
- { integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA== }
- peerDependencies:
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
- dependencies:
- '@vue/compiler-dom': 3.4.21
- '@vue/compiler-sfc': 3.4.21
- '@vue/runtime-dom': 3.4.21
- '@vue/server-renderer': 3.4.21(vue@3.4.21)
- '@vue/shared': 3.4.21
- dev: true
+
+ '@algolia/autocomplete-core@1.17.7':
+ resolution: {integrity: sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==}
+
+ '@algolia/autocomplete-plugin-algolia-insights@1.17.7':
+ resolution: {integrity: sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==}
+ peerDependencies:
+ search-insights: '>= 1 < 3'
+
+ '@algolia/autocomplete-preset-algolia@1.17.7':
+ resolution: {integrity: sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==}
+ peerDependencies:
+ '@algolia/client-search': '>= 4.9.1 < 6'
+ algoliasearch: '>= 4.9.1 < 6'
+
+ '@algolia/autocomplete-shared@1.17.7':
+ resolution: {integrity: sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==}
+ peerDependencies:
+ '@algolia/client-search': '>= 4.9.1 < 6'
+ algoliasearch: '>= 4.9.1 < 6'
+
+ '@algolia/client-abtesting@5.25.0':
+ resolution: {integrity: sha512-1pfQulNUYNf1Tk/svbfjfkLBS36zsuph6m+B6gDkPEivFmso/XnRgwDvjAx80WNtiHnmeNjIXdF7Gos8+OLHqQ==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-analytics@5.25.0':
+ resolution: {integrity: sha512-AFbG6VDJX/o2vDd9hqncj1B6B4Tulk61mY0pzTtzKClyTDlNP0xaUiEKhl6E7KO9I/x0FJF5tDCm0Hn6v5x18A==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-common@5.25.0':
+ resolution: {integrity: sha512-il1zS/+Rc6la6RaCdSZ2YbJnkQC6W1wiBO8+SH+DE6CPMWBU6iDVzH0sCKSAtMWl9WBxoN6MhNjGBnCv9Yy2bA==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-insights@5.25.0':
+ resolution: {integrity: sha512-blbjrUH1siZNfyCGeq0iLQu00w3a4fBXm0WRIM0V8alcAPo7rWjLbMJMrfBtzL9X5ic6wgxVpDADXduGtdrnkw==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-personalization@5.25.0':
+ resolution: {integrity: sha512-aywoEuu1NxChBcHZ1pWaat0Plw7A8jDMwjgRJ00Mcl7wGlwuPt5dJ/LTNcg3McsEUbs2MBNmw0ignXBw9Tbgow==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-query-suggestions@5.25.0':
+ resolution: {integrity: sha512-a/W2z6XWKjKjIW1QQQV8PTTj1TXtaKx79uR3NGBdBdGvVdt24KzGAaN7sCr5oP8DW4D3cJt44wp2OY/fZcPAVA==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/client-search@5.25.0':
+ resolution: {integrity: sha512-9rUYcMIBOrCtYiLX49djyzxqdK9Dya/6Z/8sebPn94BekT+KLOpaZCuc6s0Fpfq7nx5J6YY5LIVFQrtioK9u0g==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/ingestion@1.25.0':
+ resolution: {integrity: sha512-jJeH/Hk+k17Vkokf02lkfYE4A+EJX+UgnMhTLR/Mb+d1ya5WhE+po8p5a/Nxb6lo9OLCRl6w3Hmk1TX1e9gVbQ==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/monitoring@1.25.0':
+ resolution: {integrity: sha512-Ls3i1AehJ0C6xaHe7kK9vPmzImOn5zBg7Kzj8tRYIcmCWVyuuFwCIsbuIIz/qzUf1FPSWmw0TZrGeTumk2fqXg==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/recommend@5.25.0':
+ resolution: {integrity: sha512-79sMdHpiRLXVxSjgw7Pt4R1aNUHxFLHiaTDnN2MQjHwJ1+o3wSseb55T9VXU4kqy3m7TUme3pyRhLk5ip/S4Mw==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/requester-browser-xhr@5.25.0':
+ resolution: {integrity: sha512-JLaF23p1SOPBmfEqozUAgKHQrGl3z/Z5RHbggBu6s07QqXXcazEsub5VLonCxGVqTv6a61AAPr8J1G5HgGGjEw==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/requester-fetch@5.25.0':
+ resolution: {integrity: sha512-rtzXwqzFi1edkOF6sXxq+HhmRKDy7tz84u0o5t1fXwz0cwx+cjpmxu/6OQKTdOJFS92JUYHsG51Iunie7xbqfQ==}
+ engines: {node: '>= 14.0.0'}
+
+ '@algolia/requester-node-http@5.25.0':
+ resolution: {integrity: sha512-ZO0UKvDyEFvyeJQX0gmZDQEvhLZ2X10K+ps6hViMo1HgE2V8em00SwNsQ+7E/52a+YiBkVWX61pJJJE44juDMQ==}
+ engines: {node: '>= 14.0.0'}
+
+ '@antfu/install-pkg@1.1.0':
+ resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
+
+ '@antfu/utils@9.3.0':
+ resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.27.2':
+ resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/types@7.27.1':
+ resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@docsearch/css@3.8.2':
+ resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==}
+
+ '@docsearch/js@3.8.2':
+ resolution: {integrity: sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==}
+
+ '@docsearch/react@3.8.2':
+ resolution: {integrity: sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==}
+ peerDependencies:
+ '@types/react': '>= 16.8.0 < 19.0.0'
+ react: '>= 16.8.0 < 19.0.0'
+ react-dom: '>= 16.8.0 < 19.0.0'
+ search-insights: '>= 1 < 3'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ search-insights:
+ optional: true
+
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
+ '@iconify-json/logos@1.2.10':
+ resolution: {integrity: sha512-qxaXKJ6fu8jzTMPQdHtNxlfx6tBQ0jXRbHZIYy5Ilh8Lx9US9FsAdzZWUR8MXV8PnWTKGDFO4ZZee9VwerCyMA==}
+
+ '@iconify-json/simple-icons@1.2.34':
+ resolution: {integrity: sha512-1FRWEA94hSl5zmBogRh6lQL36l7bVTfrl0n5+QJ+WmXmw70RccPT5phqeiSynwo3IhUWKoW2LiajyUMeweXW8g==}
+
+ '@iconify-json/vscode-icons@1.2.33':
+ resolution: {integrity: sha512-2lKDybGxXXeLeeqeNT2YVDYXs5va0YMHf06w3GemS22j/0CCTpKwKDK7REaibsCq3bRV8qX0RJDM4AbREE7L+w==}
+
+ '@iconify/types@2.0.0':
+ resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
+
+ '@iconify/utils@3.0.2':
+ resolution: {integrity: sha512-EfJS0rLfVuRuJRn4psJHtK2A9TqVnkxPpHY6lYHiB9+8eSuudsxbwMiavocG45ujOo6FJ+CIRlRnlOGinzkaGQ==}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@shikijs/core@2.5.0':
+ resolution: {integrity: sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==}
+
+ '@shikijs/engine-javascript@2.5.0':
+ resolution: {integrity: sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==}
+
+ '@shikijs/engine-oniguruma@2.5.0':
+ resolution: {integrity: sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==}
+
+ '@shikijs/langs@2.5.0':
+ resolution: {integrity: sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==}
+
+ '@shikijs/themes@2.5.0':
+ resolution: {integrity: sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==}
+
+ '@shikijs/transformers@2.5.0':
+ resolution: {integrity: sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==}
+
+ '@shikijs/types@2.5.0':
+ resolution: {integrity: sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==}
+
+ '@shikijs/vscode-textmate@10.0.2':
+ resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
+
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
+ '@types/hast@3.0.4':
+ resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
+
+ '@types/linkify-it@5.0.0':
+ resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
+
+ '@types/markdown-it@14.1.2':
+ resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
+
+ '@types/mdast@4.0.4':
+ resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
+
+ '@types/mdurl@2.0.0':
+ resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
+
+ '@types/unist@3.0.3':
+ resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
+
+ '@types/web-bluetooth@0.0.21':
+ resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
+
+ '@ungap/structured-clone@1.3.0':
+ resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
+
+ '@vitejs/plugin-vue@5.2.4':
+ resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ vite: ^5.0.0 || ^6.0.0
+ vue: ^3.2.25
+
+ '@vue/compiler-core@3.5.14':
+ resolution: {integrity: sha512-k7qMHMbKvoCXIxPhquKQVw3Twid3Kg4s7+oYURxLGRd56LiuHJVrvFKI4fm2AM3c8apqODPfVJGoh8nePbXMRA==}
+
+ '@vue/compiler-dom@3.5.14':
+ resolution: {integrity: sha512-1aOCSqxGOea5I80U2hQJvXYpPm/aXo95xL/m/mMhgyPUsKe9jhjwWpziNAw7tYRnbz1I61rd9Mld4W9KmmRoug==}
+
+ '@vue/compiler-sfc@3.5.14':
+ resolution: {integrity: sha512-9T6m/9mMr81Lj58JpzsiSIjBgv2LiVoWjIVa7kuXHICUi8LiDSIotMpPRXYJsXKqyARrzjT24NAwttrMnMaCXA==}
+
+ '@vue/compiler-ssr@3.5.14':
+ resolution: {integrity: sha512-Y0G7PcBxr1yllnHuS/NxNCSPWnRGH4Ogrp0tsLA5QemDZuJLs99YjAKQ7KqkHE0vCg4QTKlQzXLKCMF7WPSl7Q==}
+
+ '@vue/devtools-api@7.7.6':
+ resolution: {integrity: sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==}
+
+ '@vue/devtools-kit@7.7.6':
+ resolution: {integrity: sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==}
+
+ '@vue/devtools-shared@7.7.6':
+ resolution: {integrity: sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==}
+
+ '@vue/reactivity@3.5.14':
+ resolution: {integrity: sha512-7cK1Hp343Fu/SUCCO52vCabjvsYu7ZkOqyYu7bXV9P2yyfjUMUXHZafEbq244sP7gf+EZEz+77QixBTuEqkQQw==}
+
+ '@vue/runtime-core@3.5.14':
+ resolution: {integrity: sha512-w9JWEANwHXNgieAhxPpEpJa+0V5G0hz3NmjAZwlOebtfKyp2hKxKF0+qSh0Xs6/PhfGihuSdqMprMVcQU/E6ag==}
+
+ '@vue/runtime-dom@3.5.14':
+ resolution: {integrity: sha512-lCfR++IakeI35TVR80QgOelsUIdcKjd65rWAMfdSlCYnaEY5t3hYwru7vvcWaqmrK+LpI7ZDDYiGU5V3xjMacw==}
+
+ '@vue/server-renderer@3.5.14':
+ resolution: {integrity: sha512-Rf/ISLqokIvcySIYnv3tNWq40PLpNLDLSJwwVWzG6MNtyIhfbcrAxo5ZL9nARJhqjZyWWa40oRb2IDuejeuv6w==}
+ peerDependencies:
+ vue: 3.5.14
+
+ '@vue/shared@3.5.14':
+ resolution: {integrity: sha512-oXTwNxVfc9EtP1zzXAlSlgARLXNC84frFYkS0HHz0h3E4WZSP9sywqjqzGCP9Y34M8ipNmd380pVgmMuwELDyQ==}
+
+ '@vueuse/core@12.8.2':
+ resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==}
+
+ '@vueuse/integrations@12.8.2':
+ resolution: {integrity: sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==}
+ peerDependencies:
+ async-validator: ^4
+ axios: ^1
+ change-case: ^5
+ drauu: ^0.4
+ focus-trap: ^7
+ fuse.js: ^7
+ idb-keyval: ^6
+ jwt-decode: ^4
+ nprogress: ^0.2
+ qrcode: ^1.5
+ sortablejs: ^1
+ universal-cookie: ^7
+ peerDependenciesMeta:
+ async-validator:
+ optional: true
+ axios:
+ optional: true
+ change-case:
+ optional: true
+ drauu:
+ optional: true
+ focus-trap:
+ optional: true
+ fuse.js:
+ optional: true
+ idb-keyval:
+ optional: true
+ jwt-decode:
+ optional: true
+ nprogress:
+ optional: true
+ qrcode:
+ optional: true
+ sortablejs:
+ optional: true
+ universal-cookie:
+ optional: true
+
+ '@vueuse/metadata@12.8.2':
+ resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==}
+
+ '@vueuse/shared@12.8.2':
+ resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==}
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ algoliasearch@5.25.0:
+ resolution: {integrity: sha512-n73BVorL4HIwKlfJKb4SEzAYkR3Buwfwbh+MYxg2mloFph2fFGV58E90QTzdbfzWrLn4HE5Czx/WTjI8fcHaMg==}
+ engines: {node: '>= 14.0.0'}
+
+ birpc@2.3.0:
+ resolution: {integrity: sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==}
+
+ ccount@2.0.1:
+ resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+
+ character-entities-html4@2.1.0:
+ resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
+
+ character-entities-legacy@3.0.0:
+ resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+
+ comma-separated-tokens@2.0.3:
+ resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
+
+ confbox@0.1.8:
+ resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
+
+ confbox@0.2.2:
+ resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
+
+ copy-anything@3.0.5:
+ resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
+ engines: {node: '>=12.13'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ devlop@1.1.0:
+ resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
+
+ emoji-regex-xs@1.0.0:
+ resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ exsolve@1.0.7:
+ resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
+
+ focus-trap@7.6.4:
+ resolution: {integrity: sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ globals@15.15.0:
+ resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
+ engines: {node: '>=18'}
+
+ hast-util-to-html@9.0.5:
+ resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==}
+
+ hast-util-whitespace@3.0.0:
+ resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
+
+ hookable@5.5.3:
+ resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
+
+ html-void-elements@3.0.0:
+ resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
+
+ is-what@4.1.16:
+ resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
+ engines: {node: '>=12.13'}
+
+ kolorist@1.8.0:
+ resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+
+ local-pkg@1.1.2:
+ resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==}
+ engines: {node: '>=14'}
+
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+ mark.js@8.11.1:
+ resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
+
+ mdast-util-to-hast@13.2.0:
+ resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
+
+ micromark-util-character@2.1.1:
+ resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==}
+
+ micromark-util-encode@2.0.1:
+ resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==}
+
+ micromark-util-sanitize-uri@2.0.1:
+ resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==}
+
+ micromark-util-symbol@2.0.1:
+ resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==}
+
+ micromark-util-types@2.0.2:
+ resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==}
+
+ minisearch@7.1.2:
+ resolution: {integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==}
+
+ mitt@3.0.1:
+ resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
+
+ mlly@1.8.0:
+ resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ oniguruma-to-es@3.1.1:
+ resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==}
+
+ package-manager-detector@1.5.0:
+ resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==}
+
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ perfect-debounce@1.0.0:
+ resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ pkg-types@1.3.1:
+ resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+
+ pkg-types@2.3.0:
+ resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
+
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact@10.26.6:
+ resolution: {integrity: sha512-5SRRBinwpwkaD+OqlBDeITlRgvd8I8QlxHJw9AxSdMNV6O+LodN9nUyYGpSF7sadHjs6RzeFShMexC6DbtWr9g==}
+
+ property-information@7.1.0:
+ resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
+
+ quansync@0.2.11:
+ resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
+
+ regex-recursion@6.0.2:
+ resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==}
+
+ regex-utilities@2.3.0:
+ resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==}
+
+ regex@6.0.1:
+ resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==}
+
+ rfdc@1.4.1:
+ resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+
+ rollup@4.40.2:
+ resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ search-insights@2.17.3:
+ resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==}
+
+ shiki@2.5.0:
+ resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ space-separated-tokens@2.0.2:
+ resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
+
+ speakingurl@14.0.1:
+ resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
+ engines: {node: '>=0.10.0'}
+
+ stringify-entities@4.0.4:
+ resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
+
+ superjson@2.2.2:
+ resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==}
+ engines: {node: '>=16'}
+
+ tabbable@6.2.0:
+ resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
+
+ tinyexec@1.0.2:
+ resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
+ engines: {node: '>=18'}
+
+ trim-lines@3.0.1:
+ resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+
+ ufo@1.6.1:
+ resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
+
+ unist-util-is@6.0.0:
+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+ unist-util-visit-parents@6.0.1:
+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+
+ unist-util-visit@5.0.0:
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+
+ vfile-message@4.0.2:
+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
+
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+
+ vite@5.4.19:
+ resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
+ vitepress-plugin-group-icons@1.6.5:
+ resolution: {integrity: sha512-+pg4+GKDq2fLqKb1Sat5p1p4SuIZ5tEPxu8HjpwoeecZ/VaXKy6Bdf0wyjedjaTAyZQzXbvyavJegqAcQ+B0VA==}
+ peerDependencies:
+ vite: '>=3'
+ peerDependenciesMeta:
+ vite:
+ optional: true
+
+ vitepress@1.6.3:
+ resolution: {integrity: sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw==}
+ hasBin: true
+ peerDependencies:
+ markdown-it-mathjax3: ^4
+ postcss: ^8
+ peerDependenciesMeta:
+ markdown-it-mathjax3:
+ optional: true
+ postcss:
+ optional: true
+
+ vue@3.5.14:
+ resolution: {integrity: sha512-LbOm50/vZFG6Mhy6KscQYXZMQ0LMCC/y40HDJPPvGFQ+i/lUH+PJHR6C3assgOQiXdl6tAfsXHbXYVBZZu65ew==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
+
+snapshots:
+
+ '@algolia/autocomplete-core@1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)(search-insights@2.17.3)':
+ dependencies:
+ '@algolia/autocomplete-plugin-algolia-insights': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)(search-insights@2.17.3)
+ '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - algoliasearch
+ - search-insights
+
+ '@algolia/autocomplete-plugin-algolia-insights@1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)(search-insights@2.17.3)':
+ dependencies:
+ '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)
+ search-insights: 2.17.3
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - algoliasearch
+
+ '@algolia/autocomplete-preset-algolia@1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)':
+ dependencies:
+ '@algolia/autocomplete-shared': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)
+ '@algolia/client-search': 5.25.0
+ algoliasearch: 5.25.0
+
+ '@algolia/autocomplete-shared@1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)':
+ dependencies:
+ '@algolia/client-search': 5.25.0
+ algoliasearch: 5.25.0
+
+ '@algolia/client-abtesting@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/client-analytics@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/client-common@5.25.0': {}
+
+ '@algolia/client-insights@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/client-personalization@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/client-query-suggestions@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/client-search@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/ingestion@1.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/monitoring@1.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/recommend@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ '@algolia/requester-browser-xhr@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+
+ '@algolia/requester-fetch@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+
+ '@algolia/requester-node-http@5.25.0':
+ dependencies:
+ '@algolia/client-common': 5.25.0
+
+ '@antfu/install-pkg@1.1.0':
+ dependencies:
+ package-manager-detector: 1.5.0
+ tinyexec: 1.0.2
+
+ '@antfu/utils@9.3.0': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/parser@7.27.2':
+ dependencies:
+ '@babel/types': 7.27.1
+
+ '@babel/types@7.27.1':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@docsearch/css@3.8.2': {}
+
+ '@docsearch/js@3.8.2(@algolia/client-search@5.25.0)(search-insights@2.17.3)':
+ dependencies:
+ '@docsearch/react': 3.8.2(@algolia/client-search@5.25.0)(search-insights@2.17.3)
+ preact: 10.26.6
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - '@types/react'
+ - react
+ - react-dom
+ - search-insights
+
+ '@docsearch/react@3.8.2(@algolia/client-search@5.25.0)(search-insights@2.17.3)':
+ dependencies:
+ '@algolia/autocomplete-core': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)(search-insights@2.17.3)
+ '@algolia/autocomplete-preset-algolia': 1.17.7(@algolia/client-search@5.25.0)(algoliasearch@5.25.0)
+ '@docsearch/css': 3.8.2
+ algoliasearch: 5.25.0
+ optionalDependencies:
+ search-insights: 2.17.3
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.21.5':
+ optional: true
+
+ '@iconify-json/logos@1.2.10':
+ dependencies:
+ '@iconify/types': 2.0.0
+
+ '@iconify-json/simple-icons@1.2.34':
+ dependencies:
+ '@iconify/types': 2.0.0
+
+ '@iconify-json/vscode-icons@1.2.33':
+ dependencies:
+ '@iconify/types': 2.0.0
+
+ '@iconify/types@2.0.0': {}
+
+ '@iconify/utils@3.0.2':
+ dependencies:
+ '@antfu/install-pkg': 1.1.0
+ '@antfu/utils': 9.3.0
+ '@iconify/types': 2.0.0
+ debug: 4.4.3
+ globals: 15.15.0
+ kolorist: 1.8.0
+ local-pkg: 1.1.2
+ mlly: 1.8.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@rollup/rollup-android-arm-eabi@4.40.2':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.40.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.40.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.40.2':
+ optional: true
+
+ '@shikijs/core@2.5.0':
+ dependencies:
+ '@shikijs/engine-javascript': 2.5.0
+ '@shikijs/engine-oniguruma': 2.5.0
+ '@shikijs/types': 2.5.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+ hast-util-to-html: 9.0.5
+
+ '@shikijs/engine-javascript@2.5.0':
+ dependencies:
+ '@shikijs/types': 2.5.0
+ '@shikijs/vscode-textmate': 10.0.2
+ oniguruma-to-es: 3.1.1
+
+ '@shikijs/engine-oniguruma@2.5.0':
+ dependencies:
+ '@shikijs/types': 2.5.0
+ '@shikijs/vscode-textmate': 10.0.2
+
+ '@shikijs/langs@2.5.0':
+ dependencies:
+ '@shikijs/types': 2.5.0
+
+ '@shikijs/themes@2.5.0':
+ dependencies:
+ '@shikijs/types': 2.5.0
+
+ '@shikijs/transformers@2.5.0':
+ dependencies:
+ '@shikijs/core': 2.5.0
+ '@shikijs/types': 2.5.0
+
+ '@shikijs/types@2.5.0':
+ dependencies:
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ '@shikijs/vscode-textmate@10.0.2': {}
+
+ '@types/estree@1.0.7': {}
+
+ '@types/hast@3.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/linkify-it@5.0.0': {}
+
+ '@types/markdown-it@14.1.2':
+ dependencies:
+ '@types/linkify-it': 5.0.0
+ '@types/mdurl': 2.0.0
+
+ '@types/mdast@4.0.4':
+ dependencies:
+ '@types/unist': 3.0.3
+
+ '@types/mdurl@2.0.0': {}
+
+ '@types/unist@3.0.3': {}
+
+ '@types/web-bluetooth@0.0.21': {}
+
+ '@ungap/structured-clone@1.3.0': {}
+
+ '@vitejs/plugin-vue@5.2.4(vite@5.4.19)(vue@3.5.14)':
+ dependencies:
+ vite: 5.4.19
+ vue: 3.5.14
+
+ '@vue/compiler-core@3.5.14':
+ dependencies:
+ '@babel/parser': 7.27.2
+ '@vue/shared': 3.5.14
+ entities: 4.5.0
+ estree-walker: 2.0.2
+ source-map-js: 1.2.1
+
+ '@vue/compiler-dom@3.5.14':
+ dependencies:
+ '@vue/compiler-core': 3.5.14
+ '@vue/shared': 3.5.14
+
+ '@vue/compiler-sfc@3.5.14':
+ dependencies:
+ '@babel/parser': 7.27.2
+ '@vue/compiler-core': 3.5.14
+ '@vue/compiler-dom': 3.5.14
+ '@vue/compiler-ssr': 3.5.14
+ '@vue/shared': 3.5.14
+ estree-walker: 2.0.2
+ magic-string: 0.30.17
+ postcss: 8.5.3
+ source-map-js: 1.2.1
+
+ '@vue/compiler-ssr@3.5.14':
+ dependencies:
+ '@vue/compiler-dom': 3.5.14
+ '@vue/shared': 3.5.14
+
+ '@vue/devtools-api@7.7.6':
+ dependencies:
+ '@vue/devtools-kit': 7.7.6
+
+ '@vue/devtools-kit@7.7.6':
+ dependencies:
+ '@vue/devtools-shared': 7.7.6
+ birpc: 2.3.0
+ hookable: 5.5.3
+ mitt: 3.0.1
+ perfect-debounce: 1.0.0
+ speakingurl: 14.0.1
+ superjson: 2.2.2
+
+ '@vue/devtools-shared@7.7.6':
+ dependencies:
+ rfdc: 1.4.1
+
+ '@vue/reactivity@3.5.14':
+ dependencies:
+ '@vue/shared': 3.5.14
+
+ '@vue/runtime-core@3.5.14':
+ dependencies:
+ '@vue/reactivity': 3.5.14
+ '@vue/shared': 3.5.14
+
+ '@vue/runtime-dom@3.5.14':
+ dependencies:
+ '@vue/reactivity': 3.5.14
+ '@vue/runtime-core': 3.5.14
+ '@vue/shared': 3.5.14
+ csstype: 3.1.3
+
+ '@vue/server-renderer@3.5.14(vue@3.5.14)':
+ dependencies:
+ '@vue/compiler-ssr': 3.5.14
+ '@vue/shared': 3.5.14
+ vue: 3.5.14
+
+ '@vue/shared@3.5.14': {}
+
+ '@vueuse/core@12.8.2':
+ dependencies:
+ '@types/web-bluetooth': 0.0.21
+ '@vueuse/metadata': 12.8.2
+ '@vueuse/shared': 12.8.2
+ vue: 3.5.14
+ transitivePeerDependencies:
+ - typescript
+
+ '@vueuse/integrations@12.8.2(focus-trap@7.6.4)':
+ dependencies:
+ '@vueuse/core': 12.8.2
+ '@vueuse/shared': 12.8.2
+ vue: 3.5.14
+ optionalDependencies:
+ focus-trap: 7.6.4
+ transitivePeerDependencies:
+ - typescript
+
+ '@vueuse/metadata@12.8.2': {}
+
+ '@vueuse/shared@12.8.2':
+ dependencies:
+ vue: 3.5.14
+ transitivePeerDependencies:
+ - typescript
+
+ acorn@8.15.0: {}
+
+ algoliasearch@5.25.0:
+ dependencies:
+ '@algolia/client-abtesting': 5.25.0
+ '@algolia/client-analytics': 5.25.0
+ '@algolia/client-common': 5.25.0
+ '@algolia/client-insights': 5.25.0
+ '@algolia/client-personalization': 5.25.0
+ '@algolia/client-query-suggestions': 5.25.0
+ '@algolia/client-search': 5.25.0
+ '@algolia/ingestion': 1.25.0
+ '@algolia/monitoring': 1.25.0
+ '@algolia/recommend': 5.25.0
+ '@algolia/requester-browser-xhr': 5.25.0
+ '@algolia/requester-fetch': 5.25.0
+ '@algolia/requester-node-http': 5.25.0
+
+ birpc@2.3.0: {}
+
+ ccount@2.0.1: {}
+
+ character-entities-html4@2.1.0: {}
+
+ character-entities-legacy@3.0.0: {}
+
+ comma-separated-tokens@2.0.3: {}
+
+ confbox@0.1.8: {}
+
+ confbox@0.2.2: {}
+
+ copy-anything@3.0.5:
+ dependencies:
+ is-what: 4.1.16
+
+ csstype@3.1.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ dequal@2.0.3: {}
+
+ devlop@1.1.0:
+ dependencies:
+ dequal: 2.0.3
+
+ emoji-regex-xs@1.0.0: {}
+
+ entities@4.5.0: {}
+
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
+ estree-walker@2.0.2: {}
+
+ exsolve@1.0.7: {}
+
+ focus-trap@7.6.4:
+ dependencies:
+ tabbable: 6.2.0
+
+ fsevents@2.3.3:
+ optional: true
+
+ globals@15.15.0: {}
+
+ hast-util-to-html@9.0.5:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.3
+ ccount: 2.0.1
+ comma-separated-tokens: 2.0.3
+ hast-util-whitespace: 3.0.0
+ html-void-elements: 3.0.0
+ mdast-util-to-hast: 13.2.0
+ property-information: 7.1.0
+ space-separated-tokens: 2.0.2
+ stringify-entities: 4.0.4
+ zwitch: 2.0.4
+
+ hast-util-whitespace@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
+ hookable@5.5.3: {}
+
+ html-void-elements@3.0.0: {}
+
+ is-what@4.1.16: {}
+
+ kolorist@1.8.0: {}
+
+ local-pkg@1.1.2:
+ dependencies:
+ mlly: 1.8.0
+ pkg-types: 2.3.0
+ quansync: 0.2.11
+
+ magic-string@0.30.17:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ mark.js@8.11.1: {}
+
+ mdast-util-to-hast@13.2.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.3.0
+ devlop: 1.1.0
+ micromark-util-sanitize-uri: 2.0.1
+ trim-lines: 3.0.1
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.0.0
+ vfile: 6.0.3
+
+ micromark-util-character@2.1.1:
+ dependencies:
+ micromark-util-symbol: 2.0.1
+ micromark-util-types: 2.0.2
+
+ micromark-util-encode@2.0.1: {}
+
+ micromark-util-sanitize-uri@2.0.1:
+ dependencies:
+ micromark-util-character: 2.1.1
+ micromark-util-encode: 2.0.1
+ micromark-util-symbol: 2.0.1
+
+ micromark-util-symbol@2.0.1: {}
+
+ micromark-util-types@2.0.2: {}
+
+ minisearch@7.1.2: {}
+
+ mitt@3.0.1: {}
+
+ mlly@1.8.0:
+ dependencies:
+ acorn: 8.15.0
+ pathe: 2.0.3
+ pkg-types: 1.3.1
+ ufo: 1.6.1
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ oniguruma-to-es@3.1.1:
+ dependencies:
+ emoji-regex-xs: 1.0.0
+ regex: 6.0.1
+ regex-recursion: 6.0.2
+
+ package-manager-detector@1.5.0: {}
+
+ pathe@2.0.3: {}
+
+ perfect-debounce@1.0.0: {}
+
+ picocolors@1.1.1: {}
+
+ pkg-types@1.3.1:
+ dependencies:
+ confbox: 0.1.8
+ mlly: 1.8.0
+ pathe: 2.0.3
+
+ pkg-types@2.3.0:
+ dependencies:
+ confbox: 0.2.2
+ exsolve: 1.0.7
+ pathe: 2.0.3
+
+ postcss@8.5.3:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact@10.26.6: {}
+
+ property-information@7.1.0: {}
+
+ quansync@0.2.11: {}
+
+ regex-recursion@6.0.2:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ regex-utilities@2.3.0: {}
+
+ regex@6.0.1:
+ dependencies:
+ regex-utilities: 2.3.0
+
+ rfdc@1.4.1: {}
+
+ rollup@4.40.2:
+ dependencies:
+ '@types/estree': 1.0.7
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.40.2
+ '@rollup/rollup-android-arm64': 4.40.2
+ '@rollup/rollup-darwin-arm64': 4.40.2
+ '@rollup/rollup-darwin-x64': 4.40.2
+ '@rollup/rollup-freebsd-arm64': 4.40.2
+ '@rollup/rollup-freebsd-x64': 4.40.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.40.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.40.2
+ '@rollup/rollup-linux-arm64-gnu': 4.40.2
+ '@rollup/rollup-linux-arm64-musl': 4.40.2
+ '@rollup/rollup-linux-loongarch64-gnu': 4.40.2
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.40.2
+ '@rollup/rollup-linux-riscv64-musl': 4.40.2
+ '@rollup/rollup-linux-s390x-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-gnu': 4.40.2
+ '@rollup/rollup-linux-x64-musl': 4.40.2
+ '@rollup/rollup-win32-arm64-msvc': 4.40.2
+ '@rollup/rollup-win32-ia32-msvc': 4.40.2
+ '@rollup/rollup-win32-x64-msvc': 4.40.2
+ fsevents: 2.3.3
+
+ search-insights@2.17.3: {}
+
+ shiki@2.5.0:
+ dependencies:
+ '@shikijs/core': 2.5.0
+ '@shikijs/engine-javascript': 2.5.0
+ '@shikijs/engine-oniguruma': 2.5.0
+ '@shikijs/langs': 2.5.0
+ '@shikijs/themes': 2.5.0
+ '@shikijs/types': 2.5.0
+ '@shikijs/vscode-textmate': 10.0.2
+ '@types/hast': 3.0.4
+
+ source-map-js@1.2.1: {}
+
+ space-separated-tokens@2.0.2: {}
+
+ speakingurl@14.0.1: {}
+
+ stringify-entities@4.0.4:
+ dependencies:
+ character-entities-html4: 2.1.0
+ character-entities-legacy: 3.0.0
+
+ superjson@2.2.2:
+ dependencies:
+ copy-anything: 3.0.5
+
+ tabbable@6.2.0: {}
+
+ tinyexec@1.0.2: {}
+
+ trim-lines@3.0.1: {}
+
+ ufo@1.6.1: {}
+
+ unist-util-is@6.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+
+ unist-util-visit@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
+
+ vfile-message@4.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
+
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.2
+
+ vite@5.4.19:
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.5.3
+ rollup: 4.40.2
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ vitepress-plugin-group-icons@1.6.5(vite@5.4.19):
+ dependencies:
+ '@iconify-json/logos': 1.2.10
+ '@iconify-json/vscode-icons': 1.2.33
+ '@iconify/utils': 3.0.2
+ optionalDependencies:
+ vite: 5.4.19
+ transitivePeerDependencies:
+ - supports-color
+
+ vitepress@1.6.3(@algolia/client-search@5.25.0)(postcss@8.5.3)(search-insights@2.17.3):
+ dependencies:
+ '@docsearch/css': 3.8.2
+ '@docsearch/js': 3.8.2(@algolia/client-search@5.25.0)(search-insights@2.17.3)
+ '@iconify-json/simple-icons': 1.2.34
+ '@shikijs/core': 2.5.0
+ '@shikijs/transformers': 2.5.0
+ '@shikijs/types': 2.5.0
+ '@types/markdown-it': 14.1.2
+ '@vitejs/plugin-vue': 5.2.4(vite@5.4.19)(vue@3.5.14)
+ '@vue/devtools-api': 7.7.6
+ '@vue/shared': 3.5.14
+ '@vueuse/core': 12.8.2
+ '@vueuse/integrations': 12.8.2(focus-trap@7.6.4)
+ focus-trap: 7.6.4
+ mark.js: 8.11.1
+ minisearch: 7.1.2
+ shiki: 2.5.0
+ vite: 5.4.19
+ vue: 3.5.14
+ optionalDependencies:
+ postcss: 8.5.3
+ transitivePeerDependencies:
+ - '@algolia/client-search'
+ - '@types/node'
+ - '@types/react'
+ - async-validator
+ - axios
+ - change-case
+ - drauu
+ - fuse.js
+ - idb-keyval
+ - jwt-decode
+ - less
+ - lightningcss
+ - nprogress
+ - qrcode
+ - react
+ - react-dom
+ - sass
+ - sass-embedded
+ - search-insights
+ - sortablejs
+ - stylus
+ - sugarss
+ - terser
+ - typescript
+ - universal-cookie
+
+ vue@3.5.14:
+ dependencies:
+ '@vue/compiler-dom': 3.5.14
+ '@vue/compiler-sfc': 3.5.14
+ '@vue/runtime-dom': 3.5.14
+ '@vue/server-renderer': 3.5.14(vue@3.5.14)
+ '@vue/shared': 3.5.14
+
+ zwitch@2.0.4: {}
diff --git a/package.json b/package.json
index 6acdcda..772774c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "classic-react-hooks",
- "version": "1.4.0",
+ "version": "2.0.0-canary.27",
"description": "A great collection of React utility hooks",
"keywords": [
"classic-react-hooks",
@@ -25,10 +25,12 @@
"module": "dist/index.mjs",
"typings": "dist/index.d.ts",
"files": [
- "dist"
+ "dist",
+ "src",
+ "tsup.config.ts"
],
"scripts": {
- "build": "pnpm clean && tsup",
+ "build": "tsdown",
"prepare": "pnpm build",
"release": "changeset publish",
"type-check": "tsc",
@@ -49,19 +51,19 @@
"@size-limit/preset-small-lib": "^8.2.4",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
- "@types/node": "^18.15.13",
- "@types/react": "^18.0.38",
- "@types/react-dom": "^18.0.11",
+ "@types/node": "^22.17.0",
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
"@types/testing-library__jest-dom": "^5.14.5",
"@vitejs/plugin-react": "^4.3.1",
- "@vitest/coverage-istanbul": "^2.0.3",
+ "@vitest/coverage-istanbul": "^3.2.4",
"jsdom": "^21.1.1",
"prettier": "^2.8.7",
"react-dom": "^18.2.0",
"size-limit": "^8.2.4",
"terser": "^5.17.1",
"ts-node": "^10.9.1",
- "tsup": "^6.7.0",
+ "tsdown": "^0.17.2",
"typescript": "^5.0.4",
"vite": "5.3.3",
"vitest": "^2.0.3"
@@ -70,7 +72,7 @@
"node": ">=16.14.0",
"pnpm": ">=8.12.0"
},
- "packageManager": "pnpm@8.12.0",
+ "packageManager": "pnpm@10.0.0",
"prettier": {
"arrowParens": "always",
"printWidth": 120,
@@ -100,7 +102,30 @@
"ws@>=8.0.0 <8.17.1": ">=8.17.1",
"word-wrap@<1.2.4": ">=1.2.4",
"tough-cookie@<4.1.3": ">=4.1.3",
- "braces@<3.0.3": ">=3.0.3"
+ "braces@<3.0.3": ">=3.0.3",
+ "micromatch@<4.0.8": ">=4.0.8",
+ "vite@>=5.3.0 <5.3.6": ">=5.3.6",
+ "vite@>=5.3.0 <=5.3.5": ">=5.3.6",
+ "rollup@>=3.0.0 <3.29.5": ">=3.29.5",
+ "rollup@>=4.0.0 <4.22.4": ">=4.22.4",
+ "nanoid@<3.3.8": ">=3.3.8",
+ "esbuild@<=0.24.2": ">=0.25.0",
+ "vitest@>=2.0.0 <2.1.9": ">=2.1.9",
+ "vite@>=5.0.0 <=5.4.11": ">=5.4.12",
+ "vite@>=5.0.0 <5.4.15": ">=5.4.15",
+ "vite@>=5.0.0 <5.4.16": ">=5.4.16",
+ "vite@>=5.0.0 <5.4.18": ">=5.4.18",
+ "@babel/runtime@<7.26.10": ">=7.26.10",
+ "@babel/helpers@<7.26.10": ">=7.26.10",
+ "vite@>=5.0.0 <=5.4.18": ">=5.4.19",
+ "vite@>=5.0.0 <5.4.17": ">=5.4.17",
+ "cross-spawn@<6.0.6": ">=6.0.6",
+ "cross-spawn@>=7.0.0 <7.0.5": ">=7.0.5",
+ "brace-expansion@>=1.0.0 <=1.1.11": ">=1.1.12",
+ "brace-expansion@>=2.0.0 <=2.0.1": ">=2.0.2",
+ "form-data@>=4.0.0 <4.0.4": ">=4.0.4",
+ "tmp@<=0.2.3": ">=0.2.4",
+ "vite@<=5.4.19": ">=5.4.20"
}
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c2edd33..6438df8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,4 +1,4 @@
-lockfileVersion: '6.0'
+lockfileVersion: '9.0'
settings:
autoInstallPeers: true
@@ -13,4871 +13,4655 @@ overrides:
word-wrap@<1.2.4: '>=1.2.4'
tough-cookie@<4.1.3: '>=4.1.3'
braces@<3.0.3: '>=3.0.3'
+ micromatch@<4.0.8: '>=4.0.8'
+ vite@>=5.3.0 <5.3.6: '>=5.3.6'
+ vite@>=5.3.0 <=5.3.5: '>=5.3.6'
+ rollup@>=3.0.0 <3.29.5: '>=3.29.5'
+ rollup@>=4.0.0 <4.22.4: '>=4.22.4'
+ nanoid@<3.3.8: '>=3.3.8'
+ esbuild@<=0.24.2: '>=0.25.0'
+ vitest@>=2.0.0 <2.1.9: '>=2.1.9'
+ vite@>=5.0.0 <=5.4.11: '>=5.4.12'
+ vite@>=5.0.0 <5.4.15: '>=5.4.15'
+ vite@>=5.0.0 <5.4.16: '>=5.4.16'
+ vite@>=5.0.0 <5.4.18: '>=5.4.18'
+ '@babel/runtime@<7.26.10': '>=7.26.10'
+ '@babel/helpers@<7.26.10': '>=7.26.10'
+ vite@>=5.0.0 <=5.4.18: '>=5.4.19'
+ vite@>=5.0.0 <5.4.17: '>=5.4.17'
+ cross-spawn@<6.0.6: '>=6.0.6'
+ cross-spawn@>=7.0.0 <7.0.5: '>=7.0.5'
+ brace-expansion@>=1.0.0 <=1.1.11: '>=1.1.12'
+ brace-expansion@>=2.0.0 <=2.0.1: '>=2.0.2'
+ form-data@>=4.0.0 <4.0.4: '>=4.0.4'
+ tmp@<=0.2.3: '>=0.2.4'
+ vite@<=5.4.19: '>=5.4.20'
+
+importers:
+
+ .:
+ dependencies:
+ react:
+ specifier: ^18.2.0
+ version: 18.3.1
+ devDependencies:
+ '@changesets/cli':
+ specifier: ^2.26.1
+ version: 2.29.7(@types/node@22.18.11)
+ '@size-limit/preset-small-lib':
+ specifier: ^8.2.4
+ version: 8.2.6(size-limit@8.2.6)
+ '@testing-library/jest-dom':
+ specifier: ^5.16.5
+ version: 5.17.0
+ '@testing-library/react':
+ specifier: ^14.0.0
+ version: 14.3.1(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@types/node':
+ specifier: ^22.17.0
+ version: 22.18.11
+ '@types/react':
+ specifier: ^18.2.0
+ version: 18.3.26
+ '@types/react-dom':
+ specifier: ^18.2.0
+ version: 18.3.7(@types/react@18.3.26)
+ '@types/testing-library__jest-dom':
+ specifier: ^5.14.5
+ version: 5.14.9
+ '@vitejs/plugin-react':
+ specifier: ^4.3.1
+ version: 4.7.0(vite@7.1.11(@types/node@22.18.11)(terser@5.44.0))
+ '@vitest/coverage-istanbul':
+ specifier: ^3.2.4
+ version: 3.2.4(vitest@3.2.4(@types/node@22.18.11)(jsdom@21.1.2)(terser@5.44.0))
+ jsdom:
+ specifier: ^21.1.1
+ version: 21.1.2
+ prettier:
+ specifier: ^2.8.7
+ version: 2.8.8
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.3.1(react@18.3.1)
+ size-limit:
+ specifier: ^8.2.4
+ version: 8.2.6
+ terser:
+ specifier: ^5.17.1
+ version: 5.44.0
+ ts-node:
+ specifier: ^10.9.1
+ version: 10.9.2(@types/node@22.18.11)(typescript@5.9.3)
+ tsdown:
+ specifier: ^0.17.2
+ version: 0.17.3(typescript@5.9.3)
+ typescript:
+ specifier: ^5.0.4
+ version: 5.9.3
+ vite:
+ specifier: '>=5.4.20'
+ version: 7.1.11(@types/node@22.18.11)(terser@5.44.0)
+ vitest:
+ specifier: '>=2.1.9'
+ version: 3.2.4(@types/node@22.18.11)(jsdom@21.1.2)(terser@5.44.0)
+
+packages:
+
+ '@adobe/css-tools@4.4.4':
+ resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.28.4':
+ resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.28.4':
+ resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.28.3':
+ resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.28.5':
+ resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.3':
+ resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.28.4':
+ resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.28.4':
+ resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/parser@7.28.5':
+ resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/runtime@7.28.4':
+ resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.28.4':
+ resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.28.4':
+ resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.28.5':
+ resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
+ engines: {node: '>=6.9.0'}
+
+ '@changesets/apply-release-plan@7.0.13':
+ resolution: {integrity: sha512-BIW7bofD2yAWoE8H4V40FikC+1nNFEKBisMECccS16W1rt6qqhNTBDmIw5HaqmMgtLNz9e7oiALiEUuKrQ4oHg==}
+
+ '@changesets/assemble-release-plan@6.0.9':
+ resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==}
+
+ '@changesets/changelog-git@0.2.1':
+ resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==}
+
+ '@changesets/cli@2.29.7':
+ resolution: {integrity: sha512-R7RqWoaksyyKXbKXBTbT4REdy22yH81mcFK6sWtqSanxUCbUi9Uf+6aqxZtDQouIqPdem2W56CdxXgsxdq7FLQ==}
+ hasBin: true
+
+ '@changesets/config@3.1.1':
+ resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==}
+
+ '@changesets/errors@0.2.0':
+ resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==}
+
+ '@changesets/get-dependents-graph@2.1.3':
+ resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==}
+
+ '@changesets/get-release-plan@4.0.13':
+ resolution: {integrity: sha512-DWG1pus72FcNeXkM12tx+xtExyH/c9I1z+2aXlObH3i9YA7+WZEVaiHzHl03thpvAgWTRaH64MpfHxozfF7Dvg==}
+
+ '@changesets/get-version-range-type@0.4.0':
+ resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==}
+
+ '@changesets/git@3.0.4':
+ resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==}
+
+ '@changesets/logger@0.1.1':
+ resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==}
+
+ '@changesets/parse@0.4.1':
+ resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==}
+
+ '@changesets/pre@2.0.2':
+ resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==}
+
+ '@changesets/read@0.6.5':
+ resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==}
+
+ '@changesets/should-skip-package@0.1.2':
+ resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==}
+
+ '@changesets/types@4.1.0':
+ resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==}
+
+ '@changesets/types@6.1.0':
+ resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==}
+
+ '@changesets/write@0.4.0':
+ resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
+
+ '@cspotcode/source-map-support@0.8.1':
+ resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+ engines: {node: '>=12'}
+
+ '@emnapi/core@1.7.1':
+ resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
+
+ '@emnapi/runtime@1.7.1':
+ resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
+
+ '@emnapi/wasi-threads@1.1.0':
+ resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+
+ '@esbuild/aix-ppc64@0.25.11':
+ resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.11':
+ resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.11':
+ resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.11':
+ resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.11':
+ resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.11':
+ resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.11':
+ resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.11':
+ resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.11':
+ resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.11':
+ resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.11':
+ resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.11':
+ resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.11':
+ resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.11':
+ resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.11':
+ resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.11':
+ resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.11':
+ resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.11':
+ resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.11':
+ resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.11':
+ resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.11':
+ resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.25.11':
+ resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.11':
+ resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.11':
+ resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.11':
+ resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.11':
+ resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@inquirer/external-editor@1.0.2':
+ resolution: {integrity: sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
+ '@istanbuljs/schema@0.1.3':
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+
+ '@jest/diff-sequences@30.0.1':
+ resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jest/expect-utils@30.2.0':
+ resolution: {integrity: sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jest/get-type@30.1.0':
+ resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jest/pattern@30.0.1':
+ resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jest/schemas@30.0.5':
+ resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jest/types@30.2.0':
+ resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/source-map@0.3.11':
+ resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@jridgewell/trace-mapping@0.3.9':
+ resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+
+ '@manypkg/find-root@1.1.0':
+ resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
+
+ '@manypkg/get-packages@1.1.3':
+ resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==}
+
+ '@napi-rs/wasm-runtime@1.1.0':
+ resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
+
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+
+ '@oxc-project/types@0.101.0':
+ resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==}
+
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+
+ '@quansync/fs@1.0.0':
+ resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==}
+
+ '@rolldown/binding-android-arm64@1.0.0-beta.53':
+ resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.53':
+ resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.0.0-beta.53':
+ resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.53':
+ resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53':
+ resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53':
+ resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53':
+ resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53':
+ resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.53':
+ resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.53':
+ resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.53':
+ resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53':
+ resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53':
+ resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.0-beta.27':
+ resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+
+ '@rolldown/pluginutils@1.0.0-beta.53':
+ resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==}
+
+ '@rollup/rollup-android-arm-eabi@4.52.5':
+ resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.52.5':
+ resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.52.5':
+ resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.52.5':
+ resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.52.5':
+ resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.52.5':
+ resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
+ resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.52.5':
+ resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.52.5':
+ resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.52.5':
+ resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loong64-gnu@4.52.5':
+ resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.52.5':
+ resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.52.5':
+ resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.52.5':
+ resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.52.5':
+ resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.52.5':
+ resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.52.5':
+ resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-openharmony-arm64@4.52.5':
+ resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.52.5':
+ resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.52.5':
+ resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.52.5':
+ resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.52.5':
+ resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==}
+ cpu: [x64]
+ os: [win32]
+
+ '@sinclair/typebox@0.34.41':
+ resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==}
+
+ '@size-limit/esbuild@8.2.6':
+ resolution: {integrity: sha512-a4c8xVDuDMYw5jF655ADjQDluw3jGPPYer6UJock5rSnUlWnIbmT/Ohud7gJGq5gqyLUQOCrBD7NB3g+mlhj4g==}
+ engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ size-limit: 8.2.6
+
+ '@size-limit/file@8.2.6':
+ resolution: {integrity: sha512-B7ayjxiJsbtXdIIWazJkB5gezi5WBMecdHTFPMDhI3NwEML1RVvUjAkrb1mPAAkIpt2LVHPnhdCUHjqDdjugwg==}
+ engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ size-limit: 8.2.6
+
+ '@size-limit/preset-small-lib@8.2.6':
+ resolution: {integrity: sha512-roanEuscDaaXDsT5Cg9agMbmsQVlMr66eRg3AwT2o4vE7WFLR8Z42p0AHZiwucW1nGpCxAh8E08Qa/yyVuj5nA==}
+ peerDependencies:
+ size-limit: 8.2.6
+
+ '@testing-library/dom@9.3.4':
+ resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
+ engines: {node: '>=14'}
+
+ '@testing-library/jest-dom@5.17.0':
+ resolution: {integrity: sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==}
+ engines: {node: '>=8', npm: '>=6', yarn: '>=1'}
+
+ '@testing-library/react@14.3.1':
+ resolution: {integrity: sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ react: ^18.0.0
+ react-dom: ^18.0.0
+
+ '@tootallnate/once@2.0.0':
+ resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
+ engines: {node: '>= 10'}
+
+ '@tsconfig/node10@1.0.11':
+ resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
+
+ '@tsconfig/node12@1.0.11':
+ resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+
+ '@tsconfig/node14@1.0.3':
+ resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+
+ '@tsconfig/node16@1.0.4':
+ resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+
+ '@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/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/chai@5.2.2':
+ resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
+
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
+
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
+
+ '@types/jest@30.0.0':
+ resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==}
+
+ '@types/node@12.20.55':
+ resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
+
+ '@types/node@22.18.11':
+ resolution: {integrity: sha512-Gd33J2XIrXurb+eT2ktze3rJAfAp9ZNjlBdh4SVgyrKEOADwCbdUDaK7QgJno8Ue4kcajscsKqu6n8OBG3hhCQ==}
+
+ '@types/prop-types@15.7.15':
+ resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
+
+ '@types/react-dom@18.3.7':
+ resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==}
+ peerDependencies:
+ '@types/react': ^18.0.0
+
+ '@types/react@18.3.26':
+ resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==}
+
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+
+ '@types/testing-library__jest-dom@5.14.9':
+ resolution: {integrity: sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==}
+
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
+ '@types/yargs@17.0.33':
+ resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+
+ '@vitejs/plugin-react@4.7.0':
+ resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: '>=5.4.20'
+
+ '@vitest/coverage-istanbul@3.2.4':
+ resolution: {integrity: sha512-IDlpuFJiWU9rhcKLkpzj8mFu/lpe64gVgnV15ZOrYx1iFzxxrxCzbExiUEKtwwXRvEiEMUS6iZeYgnMxgbqbxQ==}
+ peerDependencies:
+ vitest: 3.2.4
+
+ '@vitest/expect@3.2.4':
+ resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
+
+ '@vitest/mocker@3.2.4':
+ resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: '>=5.4.20'
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@3.2.4':
+ resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
+
+ '@vitest/runner@3.2.4':
+ resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
+
+ '@vitest/snapshot@3.2.4':
+ resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
+
+ '@vitest/spy@3.2.4':
+ resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
+
+ '@vitest/utils@3.2.4':
+ resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
+
+ abab@2.0.6:
+ resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
+ deprecated: Use your platform's native atob() and btoa() methods instead
+
+ acorn-globals@7.0.1:
+ resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
+
+ acorn-walk@8.3.4:
+ resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
+ engines: {node: '>=0.4.0'}
+
+ acorn@8.15.0:
+ resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ agent-base@6.0.2:
+ resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+ engines: {node: '>= 6.0.0'}
+
+ ansi-colors@4.1.3:
+ resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+ engines: {node: '>=6'}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-regex@6.2.2:
+ resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==}
+ engines: {node: '>=12'}
+
+ 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'}
+
+ ansi-styles@6.2.3:
+ resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
+ engines: {node: '>=12'}
+
+ ansis@4.2.0:
+ resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==}
+ engines: {node: '>=14'}
+
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+
+ arg@4.1.3:
+ resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+
+ argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
+ aria-query@5.1.3:
+ resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ array-buffer-byte-length@1.0.2:
+ resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}
+ engines: {node: '>= 0.4'}
+
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ ast-kit@2.2.0:
+ resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==}
+ engines: {node: '>=20.19.0'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
+ balanced-match@3.0.1:
+ resolution: {integrity: sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==}
+ engines: {node: '>= 16'}
+
+ baseline-browser-mapping@2.8.18:
+ resolution: {integrity: sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==}
+ hasBin: true
+
+ better-path-resolve@1.0.0:
+ resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
+ engines: {node: '>=4'}
+
+ binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ birpc@3.0.0:
+ resolution: {integrity: sha512-by+04pHuxpCEQcucAXqzopqfhyI8TLK5Qg5MST0cB6MP+JhHna9ollrtK9moVh27aq6Q6MEJgebD0cVm//yBkg==}
+
+ brace-expansion@4.0.1:
+ resolution: {integrity: sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==}
+ engines: {node: '>= 18'}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.26.3:
+ resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ buffer-from@1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+
+ bytes-iec@3.1.1:
+ resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==}
+ engines: {node: '>= 0.8'}
+
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bind@1.0.8:
+ resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
+ caniuse-lite@1.0.30001751:
+ resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==}
+
+ chai@5.3.3:
+ resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ engines: {node: '>=18'}
+
+ chalk@3.0.0:
+ resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+ engines: {node: '>=8'}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ chardet@2.1.0:
+ resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==}
+
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
+
+ chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+
+ ci-info@3.9.0:
+ resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
+ engines: {node: '>=8'}
+
+ ci-info@4.3.1:
+ resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==}
+ engines: {node: '>=8'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ commander@2.20.3:
+ resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ create-require@1.1.1:
+ resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
+ cssstyle@3.0.0:
+ resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
+ engines: {node: '>=14'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ data-urls@4.0.0:
+ resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==}
+ engines: {node: '>=14'}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
+ deep-equal@2.2.3:
+ resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
+ engines: {node: '>= 0.4'}
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+
+ defu@6.1.4:
+ resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ detect-indent@6.1.0:
+ resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
+ engines: {node: '>=8'}
+
+ diff@4.0.2:
+ resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
+ engines: {node: '>=0.3.1'}
+
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
+ domexception@4.0.0:
+ resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
+ engines: {node: '>=12'}
+ deprecated: Use your platform's native DOMException instead
+
+ dts-resolver@2.1.3:
+ resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ oxc-resolver: '>=11.0.0'
+ peerDependenciesMeta:
+ oxc-resolver:
+ optional: true
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ electron-to-chromium@1.5.237:
+ resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ empathic@2.0.0:
+ resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==}
+ engines: {node: '>=14'}
+
+ enquirer@2.4.1:
+ resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
+ engines: {node: '>=8.6'}
+
+ entities@6.0.1:
+ resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
+ engines: {node: '>=0.12'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-get-iterator@1.1.3:
+ resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+
+ es-module-lexer@1.7.0:
+ resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ esbuild@0.25.11:
+ resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
+ escodegen@2.1.0:
+ resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+ engines: {node: '>=6.0'}
+ hasBin: true
+
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ estraverse@5.3.0:
+ 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'}
+
+ expect-type@1.2.2:
+ resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==}
+ engines: {node: '>=12.0.0'}
+
+ expect@30.2.0:
+ resolution: {integrity: sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ extendable-error@0.1.7:
+ resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fastq@1.19.1:
+ resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
+ for-each@0.3.5:
+ resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
+ engines: {node: '>= 0.4'}
+
+ foreground-child@3.3.1:
+ resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ engines: {node: '>=14'}
+
+ form-data@4.0.4:
+ resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==}
+ engines: {node: '>= 6'}
+
+ fs-extra@7.0.1:
+ resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
+ engines: {node: '>=6 <7 || >=8'}
+
+ fs-extra@8.1.0:
+ resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
+ engines: {node: '>=6 <7 || >=8'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-tsconfig@4.13.0:
+ resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ hasBin: true
+
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ has-bigints@1.1.0:
+ resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ hookable@5.5.3:
+ resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
+
+ html-encoding-sniffer@3.0.0:
+ resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
+ engines: {node: '>=12'}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+ http-proxy-agent@5.0.0:
+ resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
+ engines: {node: '>= 6'}
+
+ https-proxy-agent@5.0.1:
+ resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+ engines: {node: '>= 6'}
+
+ human-id@4.1.2:
+ resolution: {integrity: sha512-v/J+4Z/1eIJovEBdlV5TYj1IR+ZiohcYGRY+qN/oC9dAfKzVT023N/Bgw37hrKCoVRBvk3bqyzpr2PP5YeTMSg==}
+ hasBin: true
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ iconv-lite@0.7.0:
+ resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
+ engines: {node: '>=0.10.0'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ import-without-cache@0.2.3:
+ resolution: {integrity: sha512-roCvX171VqJ7+7pQt1kSRfwaJvFAC2zhThJWXal1rN8EqzPS3iapkAoNpHh4lM8Na1BDen+n9rVfo73RN+Y87g==}
+ engines: {node: '>=20.19.0'}
+
+ indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+
+ internal-slot@1.1.0:
+ resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
+ engines: {node: '>= 0.4'}
+
+ is-arguments@1.2.0:
+ resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==}
+ engines: {node: '>= 0.4'}
+
+ is-array-buffer@3.0.5:
+ resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
+ engines: {node: '>= 0.4'}
+
+ is-bigint@1.1.0:
+ resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}
+ engines: {node: '>= 0.4'}
+
+ is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+
+ is-boolean-object@1.2.2:
+ resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}
+ engines: {node: '>= 0.4'}
+
+ is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+
+ is-date-object@1.1.0:
+ resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
+ engines: {node: '>= 0.4'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-map@2.0.3:
+ resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+ engines: {node: '>= 0.4'}
+
+ is-number-object@1.1.1:
+ resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}
+ engines: {node: '>= 0.4'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
+ is-regex@1.2.1:
+ resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+ engines: {node: '>= 0.4'}
+
+ is-set@2.0.3:
+ resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+ engines: {node: '>= 0.4'}
+
+ is-shared-array-buffer@1.0.4:
+ resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
+ engines: {node: '>= 0.4'}
+
+ is-string@1.1.1:
+ resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
+ engines: {node: '>= 0.4'}
+
+ is-subdir@1.2.0:
+ resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==}
+ engines: {node: '>=4'}
+
+ is-symbol@1.1.1:
+ resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}
+ engines: {node: '>= 0.4'}
+
+ is-weakmap@2.0.2:
+ resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+ engines: {node: '>= 0.4'}
+
+ is-weakset@2.0.4:
+ resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
+ engines: {node: '>= 0.4'}
+
+ is-windows@1.0.2:
+ resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
+ engines: {node: '>=0.10.0'}
+
+ isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@6.0.3:
+ resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-source-maps@5.0.6:
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.2.0:
+ resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
+ engines: {node: '>=8'}
+
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
+ jest-diff@30.2.0:
+ resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ jest-matcher-utils@30.2.0:
+ resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ jest-message-util@30.2.0:
+ resolution: {integrity: sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ jest-mock@30.2.0:
+ resolution: {integrity: sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ jest-regex-util@30.0.1:
+ resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ jest-util@30.2.0:
+ resolution: {integrity: sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
+ js-yaml@3.14.1:
+ resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ hasBin: true
+
+ jsdom@21.1.2:
+ resolution: {integrity: sha512-sCpFmK2jv+1sjff4u7fzft+pUh2KSUbUrEHYHyfSIbGTIcmnjyp83qg6qLwdJ/I3LpTXx33ACxeRL7Lsyc6lGQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ canvas: ^2.5.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ jsonfile@4.0.0:
+ resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+
+ lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
+ lodash.startcase@4.4.0:
+ resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
+
+ lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ loupe@3.2.1:
+ resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
+
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
+ magic-string@0.30.19:
+ resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ magicast@0.3.5:
+ resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
+ make-error@1.3.6:
+ resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ 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@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ mri@1.2.0:
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+ engines: {node: '>=4'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ nanoid@5.1.6:
+ resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
+ engines: {node: ^18 || >=20}
+ hasBin: true
+
+ nanospinner@1.2.2:
+ resolution: {integrity: sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA==}
+
+ node-releases@2.0.25:
+ resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ nwsapi@2.2.22:
+ resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==}
+
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
+ object-is@1.1.6:
+ resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
+ engines: {node: '>= 0.4'}
+
+ object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+
+ object.assign@4.1.7:
+ resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
+ engines: {node: '>= 0.4'}
+
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
+ outdent@0.5.0:
+ resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
+
+ p-filter@2.1.0:
+ resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
+ engines: {node: '>=8'}
+
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
+ p-map@2.1.0:
+ resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
+ engines: {node: '>=6'}
+
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
+ package-manager-detector@0.2.11:
+ resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==}
+
+ parse5@7.3.0:
+ resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ picomatch@4.0.3:
+ resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
+ engines: {node: '>=12'}
+
+ pify@4.0.1:
+ resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+ engines: {node: '>=6'}
+
+ possible-typed-array-names@1.1.0:
+ resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
+ engines: {node: '>= 0.4'}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prettier@2.8.8:
+ resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+
+ 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}
+
+ pretty-format@30.2.0:
+ resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ quansync@0.2.11:
+ resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
+
+ quansync@1.0.0:
+ resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ react-dom@18.3.1:
+ resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+ peerDependencies:
+ react: ^18.3.1
+
+ 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==}
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@18.3.1:
+ resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
+ engines: {node: '>=0.10.0'}
+
+ read-yaml-file@1.1.0:
+ resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==}
+ engines: {node: '>=6'}
+
+ readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
+ regexp.prototype.flags@1.5.4:
+ resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
+ engines: {node: '>= 0.4'}
+
+ resolve-from@5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ reusify@1.1.0:
+ resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ rolldown-plugin-dts@0.18.3:
+ resolution: {integrity: sha512-rd1LZ0Awwfyn89UndUF/HoFF4oH9a5j+2ZeuKSJYM80vmeN/p0gslYMnHTQHBEXPhUlvAlqGA3tVgXB/1qFNDg==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@ts-macro/tsc': ^0.3.6
+ '@typescript/native-preview': '>=7.0.0-dev.20250601.1'
+ rolldown: ^1.0.0-beta.51
+ typescript: ^5.0.0
+ vue-tsc: ~3.1.0
+ peerDependenciesMeta:
+ '@ts-macro/tsc':
+ optional: true
+ '@typescript/native-preview':
+ optional: true
+ typescript:
+ optional: true
+ vue-tsc:
+ optional: true
+
+ rolldown@1.0.0-beta.53:
+ resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
+ rollup@4.52.5:
+ resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ rrweb-cssom@0.6.0:
+ resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ safe-regex-test@1.1.0:
+ resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
+ engines: {node: '>= 0.4'}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
+ scheduler@0.23.2:
+ resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.5.3:
+ resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ semver@7.7.3:
+ resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ size-limit@8.2.6:
+ resolution: {integrity: sha512-zpznim/tX/NegjoQuRKgWTF4XiB0cn2qt90uJzxYNTFAqexk4b94DOAkBD3TwhC6c3kw2r0KcnA5upziVMZqDg==}
+ engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
+ hasBin: true
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map-support@0.5.21:
+ resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
+ spawndamnit@3.0.1:
+ resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==}
+
+ sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ std-env@3.10.0:
+ resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+
+ stop-iteration-iterator@1.1.0:
+ resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
+ engines: {node: '>= 0.4'}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-ansi@7.1.2:
+ resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
+ engines: {node: '>=12'}
+
+ strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
+ strip-literal@3.1.0:
+ resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
+ term-size@2.2.1:
+ resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
+ engines: {node: '>=8'}
+
+ terser@5.44.0:
+ resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ test-exclude@7.0.1:
+ resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
+ engines: {node: '>=18'}
+
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
+ tinyexec@1.0.2:
+ resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.15:
+ resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ engines: {node: '>=12.0.0'}
+
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@4.0.4:
+ resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
+ engines: {node: '>=14.0.0'}
+
+ tldts-core@7.0.17:
+ resolution: {integrity: sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==}
+
+ tldts@7.0.17:
+ resolution: {integrity: sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==}
+ hasBin: true
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ tough-cookie@6.0.0:
+ resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
+ engines: {node: '>=16'}
+
+ tr46@4.1.1:
+ resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
+ engines: {node: '>=14'}
+
+ tree-kill@1.2.2:
+ resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+ hasBin: true
+
+ ts-node@10.9.2:
+ resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': '>=1.2.50'
+ '@swc/wasm': '>=1.2.50'
+ '@types/node': '*'
+ typescript: '>=2.7'
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ '@swc/wasm':
+ optional: true
+
+ tsdown@0.17.3:
+ resolution: {integrity: sha512-bgLgTog+oyadDTr9SZ57jZtb+A4aglCjo3xgJrkCDxbzcQl2l2iDDr4b06XHSQHwyDNIhYFDgPRhuu1wL3pNsw==}
+ engines: {node: '>=20.19.0'}
+ hasBin: true
+ peerDependencies:
+ '@arethetypeswrong/core': ^0.18.1
+ '@vitejs/devtools': ^0.0.0-alpha.19
+ publint: ^0.3.0
+ typescript: ^5.0.0
+ unplugin-lightningcss: ^0.4.0
+ unplugin-unused: ^0.5.0
+ peerDependenciesMeta:
+ '@arethetypeswrong/core':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ publint:
+ optional: true
+ typescript:
+ optional: true
+ unplugin-lightningcss:
+ optional: true
+ unplugin-unused:
+ optional: true
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ unconfig-core@7.4.2:
+ resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==}
+
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+
+ universalify@0.1.2:
+ resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
+ engines: {node: '>= 4.0.0'}
+
+ unrun@0.2.19:
+ resolution: {integrity: sha512-DbwbJ9BvPEb3BeZnIpP9S5tGLO/JIgPQ3JrpMRFIfZMZfMG19f26OlLbC2ml8RRdrI2ZA7z2t+at5tsIHbh6Qw==}
+ engines: {node: '>=20.19.0'}
+ hasBin: true
+ peerDependencies:
+ synckit: ^0.11.11
+ peerDependenciesMeta:
+ synckit:
+ optional: true
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ v8-compile-cache-lib@3.0.1:
+ resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+
+ vite@7.1.11:
+ resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ lightningcss: ^1.21.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitest@3.2.4:
+ resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/debug': ^4.1.12
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@vitest/browser': 3.2.4
+ '@vitest/ui': 3.2.4
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/debug':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ w3c-xmlserializer@4.0.0:
+ resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
+ engines: {node: '>=14'}
+
+ webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+
+ whatwg-encoding@2.0.0:
+ resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+ engines: {node: '>=12'}
+
+ whatwg-mimetype@3.0.0:
+ resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
+ engines: {node: '>=12'}
+
+ whatwg-url@12.0.1:
+ resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==}
+ engines: {node: '>=14'}
+
+ which-boxed-primitive@1.1.1:
+ resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
+ engines: {node: '>= 0.4'}
+
+ which-collection@1.0.2:
+ resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+ engines: {node: '>= 0.4'}
+
+ which-typed-array@1.1.19:
+ resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}
+ engines: {node: '>= 0.4'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
-dependencies:
- react:
- specifier: ^18.2.0
- version: 18.2.0
-
-devDependencies:
- '@changesets/cli':
- specifier: ^2.26.1
- version: 2.26.1
- '@size-limit/preset-small-lib':
- specifier: ^8.2.4
- version: 8.2.4(size-limit@8.2.4)
- '@testing-library/jest-dom':
- specifier: ^5.16.5
- version: 5.16.5
- '@testing-library/react':
- specifier: ^14.0.0
- version: 14.0.0(react-dom@18.2.0)(react@18.2.0)
- '@types/node':
- specifier: ^18.15.13
- version: 18.15.13
- '@types/react':
- specifier: ^18.0.38
- version: 18.0.38
- '@types/react-dom':
- specifier: ^18.0.11
- version: 18.0.11
- '@types/testing-library__jest-dom':
- specifier: ^5.14.5
- version: 5.14.5
- '@vitejs/plugin-react':
- specifier: ^4.3.1
- version: 4.3.1(vite@5.3.3)
- '@vitest/coverage-istanbul':
- specifier: ^2.0.3
- version: 2.0.3(vitest@2.0.3)
- jsdom:
- specifier: ^21.1.1
- version: 21.1.1
- prettier:
- specifier: ^2.8.7
- version: 2.8.7
- react-dom:
- specifier: ^18.2.0
- version: 18.2.0(react@18.2.0)
- size-limit:
- specifier: ^8.2.4
- version: 8.2.4
- terser:
- specifier: ^5.17.1
- version: 5.17.1
- ts-node:
- specifier: ^10.9.1
- version: 10.9.1(@types/node@18.15.13)(typescript@5.0.4)
- tsup:
- specifier: ^6.7.0
- version: 6.7.0(ts-node@10.9.1)(typescript@5.0.4)
- typescript:
- specifier: ^5.0.4
- version: 5.0.4
- vite:
- specifier: 5.3.3
- version: 5.3.3(@types/node@18.15.13)(terser@5.17.1)
- vitest:
- specifier: ^2.0.3
- version: 2.0.3(@types/node@18.15.13)(jsdom@21.1.1)(terser@5.17.1)
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
-packages:
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
- /@adobe/css-tools@4.4.0:
- resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
- dev: true
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
- /@ampproject/remapping@2.3.0:
- resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
- engines: {node: '>=6.0.0'}
- dependencies:
- '@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
- dev: true
+ ws@8.18.3:
+ resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
- /@babel/code-frame@7.21.4:
- resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/highlight': 7.18.6
- dev: true
+ xml-name-validator@4.0.0:
+ resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+ engines: {node: '>=12'}
- /@babel/code-frame@7.24.7:
- resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/highlight': 7.24.7
- picocolors: 1.0.1
- dev: true
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
- /@babel/compat-data@7.24.9:
- resolution: {integrity: sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==}
- engines: {node: '>=6.9.0'}
- dev: true
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
- /@babel/core@7.24.9:
- resolution: {integrity: sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==}
- engines: {node: '>=6.9.0'}
+ yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
+ yn@3.1.1:
+ resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+ engines: {node: '>=6'}
+
+snapshots:
+
+ '@adobe/css-tools@4.4.4': {}
+
+ '@babel/code-frame@7.27.1':
dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.9
- '@babel/helper-compilation-targets': 7.24.8
- '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.9)
- '@babel/helpers': 7.24.8
- '@babel/parser': 7.24.8
- '@babel/template': 7.24.7
- '@babel/traverse': 7.24.8
- '@babel/types': 7.24.9
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.28.4': {}
+
+ '@babel/core@7.28.4':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
+ '@babel/helpers': 7.28.4
+ '@babel/parser': 7.28.4
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.4
+ '@babel/types': 7.28.4
+ '@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
- debug: 4.3.5
+ debug: 4.4.3
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
- dev: true
-
- /@babel/generator@7.24.9:
- resolution: {integrity: sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.24.9
- '@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
- jsesc: 2.5.2
- dev: true
-
- /@babel/helper-compilation-targets@7.24.8:
- resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/compat-data': 7.24.9
- '@babel/helper-validator-option': 7.24.8
- browserslist: 4.23.2
- lru-cache: 5.1.1
- semver: 6.3.1
- dev: true
- /@babel/helper-environment-visitor@7.24.7:
- resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==}
- engines: {node: '>=6.9.0'}
+ '@babel/generator@7.28.3':
dependencies:
- '@babel/types': 7.24.9
- dev: true
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
- /@babel/helper-function-name@7.24.7:
- resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==}
- engines: {node: '>=6.9.0'}
+ '@babel/generator@7.28.5':
dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.9
- dev: true
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
- /@babel/helper-hoist-variables@7.24.7:
- resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==}
- engines: {node: '>=6.9.0'}
+ '@babel/helper-compilation-targets@7.27.2':
dependencies:
- '@babel/types': 7.24.9
- dev: true
+ '@babel/compat-data': 7.28.4
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.26.3
+ lru-cache: 5.1.1
+ semver: 6.3.1
- /@babel/helper-module-imports@7.24.7:
- resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/traverse': 7.24.8
- '@babel/types': 7.24.9
- transitivePeerDependencies:
- - supports-color
- dev: true
+ '@babel/helper-globals@7.28.0': {}
- /@babel/helper-module-transforms@7.24.9(@babel/core@7.24.9):
- resolution: {integrity: sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
+ '@babel/helper-module-imports@7.27.1':
dependencies:
- '@babel/core': 7.24.9
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-module-imports': 7.24.7
- '@babel/helper-simple-access': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/helper-validator-identifier': 7.24.7
+ '@babel/traverse': 7.28.4
+ '@babel/types': 7.28.4
transitivePeerDependencies:
- supports-color
- dev: true
-
- /@babel/helper-plugin-utils@7.24.8:
- resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==}
- engines: {node: '>=6.9.0'}
- dev: true
- /@babel/helper-simple-access@7.24.7:
- resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==}
- engines: {node: '>=6.9.0'}
+ '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)':
dependencies:
- '@babel/traverse': 7.24.8
- '@babel/types': 7.24.9
+ '@babel/core': 7.28.4
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.28.4
transitivePeerDependencies:
- supports-color
- dev: true
-
- /@babel/helper-split-export-declaration@7.24.7:
- resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/types': 7.24.9
- dev: true
- /@babel/helper-string-parser@7.19.4:
- resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
- engines: {node: '>=6.9.0'}
- dev: true
-
- /@babel/helper-string-parser@7.24.8:
- resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
- engines: {node: '>=6.9.0'}
- dev: true
+ '@babel/helper-plugin-utils@7.27.1': {}
- /@babel/helper-validator-identifier@7.19.1:
- resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
- engines: {node: '>=6.9.0'}
- dev: true
+ '@babel/helper-string-parser@7.27.1': {}
- /@babel/helper-validator-identifier@7.24.7:
- resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
- engines: {node: '>=6.9.0'}
- dev: true
+ '@babel/helper-validator-identifier@7.27.1': {}
- /@babel/helper-validator-option@7.24.8:
- resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==}
- engines: {node: '>=6.9.0'}
- dev: true
+ '@babel/helper-validator-identifier@7.28.5': {}
- /@babel/helpers@7.24.8:
- resolution: {integrity: sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/template': 7.24.7
- '@babel/types': 7.24.9
- dev: true
+ '@babel/helper-validator-option@7.27.1': {}
- /@babel/highlight@7.18.6:
- resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
- engines: {node: '>=6.9.0'}
+ '@babel/helpers@7.28.4':
dependencies:
- '@babel/helper-validator-identifier': 7.19.1
- chalk: 2.4.2
- js-tokens: 4.0.0
- dev: true
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.4
- /@babel/highlight@7.24.7:
- resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
- engines: {node: '>=6.9.0'}
+ '@babel/parser@7.28.4':
dependencies:
- '@babel/helper-validator-identifier': 7.24.7
- chalk: 2.4.2
- js-tokens: 4.0.0
- picocolors: 1.0.1
- dev: true
+ '@babel/types': 7.28.4
- /@babel/parser@7.24.8:
- resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==}
- engines: {node: '>=6.0.0'}
- hasBin: true
+ '@babel/parser@7.28.5':
dependencies:
- '@babel/types': 7.21.4
- dev: true
+ '@babel/types': 7.28.5
- /@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.24.9):
- resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)':
dependencies:
- '@babel/core': 7.24.9
- '@babel/helper-plugin-utils': 7.24.8
- dev: true
+ '@babel/core': 7.28.4
+ '@babel/helper-plugin-utils': 7.27.1
- /@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.24.9):
- resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)':
dependencies:
- '@babel/core': 7.24.9
- '@babel/helper-plugin-utils': 7.24.8
- dev: true
+ '@babel/core': 7.28.4
+ '@babel/helper-plugin-utils': 7.27.1
- /@babel/runtime@7.21.0:
- resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==}
- engines: {node: '>=6.9.0'}
- dependencies:
- regenerator-runtime: 0.13.11
- dev: true
+ '@babel/runtime@7.28.4': {}
- /@babel/template@7.24.7:
- resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==}
- engines: {node: '>=6.9.0'}
+ '@babel/template@7.27.2':
dependencies:
- '@babel/code-frame': 7.24.7
- '@babel/parser': 7.24.8
- '@babel/types': 7.24.9
- dev: true
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
- /@babel/traverse@7.24.8:
- resolution: {integrity: sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==}
- engines: {node: '>=6.9.0'}
+ '@babel/traverse@7.28.4':
dependencies:
- '@babel/code-frame': 7.24.7
- '@babel/generator': 7.24.9
- '@babel/helper-environment-visitor': 7.24.7
- '@babel/helper-function-name': 7.24.7
- '@babel/helper-hoist-variables': 7.24.7
- '@babel/helper-split-export-declaration': 7.24.7
- '@babel/parser': 7.24.8
- '@babel/types': 7.24.9
- debug: 4.3.5
- globals: 11.12.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.28.4
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
- dev: true
- /@babel/types@7.21.4:
- resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==}
- engines: {node: '>=6.9.0'}
+ '@babel/types@7.28.4':
dependencies:
- '@babel/helper-string-parser': 7.19.4
- '@babel/helper-validator-identifier': 7.19.1
- to-fast-properties: 2.0.0
- dev: true
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
- /@babel/types@7.24.9:
- resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==}
- engines: {node: '>=6.9.0'}
+ '@babel/types@7.28.5':
dependencies:
- '@babel/helper-string-parser': 7.24.8
- '@babel/helper-validator-identifier': 7.24.7
- to-fast-properties: 2.0.0
- dev: true
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
- /@changesets/apply-release-plan@6.1.3:
- resolution: {integrity: sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==}
+ '@changesets/apply-release-plan@7.0.13':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/config': 2.3.0
- '@changesets/get-version-range-type': 0.3.2
- '@changesets/git': 2.0.0
- '@changesets/types': 5.2.1
+ '@changesets/config': 3.1.1
+ '@changesets/get-version-range-type': 0.4.0
+ '@changesets/git': 3.0.4
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
detect-indent: 6.1.0
fs-extra: 7.0.1
lodash.startcase: 4.4.0
outdent: 0.5.0
- prettier: 2.8.7
+ prettier: 2.8.8
resolve-from: 5.0.0
- semver: 7.6.2
- dev: true
+ semver: 7.7.3
- /@changesets/assemble-release-plan@5.2.3:
- resolution: {integrity: sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==}
+ '@changesets/assemble-release-plan@6.0.9':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/errors': 0.1.4
- '@changesets/get-dependents-graph': 1.3.5
- '@changesets/types': 5.2.1
+ '@changesets/errors': 0.2.0
+ '@changesets/get-dependents-graph': 2.1.3
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
- semver: 7.6.2
- dev: true
-
- /@changesets/changelog-git@0.1.14:
- resolution: {integrity: sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==}
- dependencies:
- '@changesets/types': 5.2.1
- dev: true
-
- /@changesets/cli@2.26.1:
- resolution: {integrity: sha512-XnTa+b51vt057fyAudvDKGB0Sh72xutQZNAdXkCqPBKO2zvs2yYZx5hFZj1u9cbtpwM6Sxtcr02/FQJfZOzemQ==}
- hasBin: true
- dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/apply-release-plan': 6.1.3
- '@changesets/assemble-release-plan': 5.2.3
- '@changesets/changelog-git': 0.1.14
- '@changesets/config': 2.3.0
- '@changesets/errors': 0.1.4
- '@changesets/get-dependents-graph': 1.3.5
- '@changesets/get-release-plan': 3.0.16
- '@changesets/git': 2.0.0
- '@changesets/logger': 0.0.5
- '@changesets/pre': 1.0.14
- '@changesets/read': 0.5.9
- '@changesets/types': 5.2.1
- '@changesets/write': 0.2.3
+ semver: 7.7.3
+
+ '@changesets/changelog-git@0.2.1':
+ dependencies:
+ '@changesets/types': 6.1.0
+
+ '@changesets/cli@2.29.7(@types/node@22.18.11)':
+ dependencies:
+ '@changesets/apply-release-plan': 7.0.13
+ '@changesets/assemble-release-plan': 6.0.9
+ '@changesets/changelog-git': 0.2.1
+ '@changesets/config': 3.1.1
+ '@changesets/errors': 0.2.0
+ '@changesets/get-dependents-graph': 2.1.3
+ '@changesets/get-release-plan': 4.0.13
+ '@changesets/git': 3.0.4
+ '@changesets/logger': 0.1.1
+ '@changesets/pre': 2.0.2
+ '@changesets/read': 0.6.5
+ '@changesets/should-skip-package': 0.1.2
+ '@changesets/types': 6.1.0
+ '@changesets/write': 0.4.0
+ '@inquirer/external-editor': 1.0.2(@types/node@22.18.11)
'@manypkg/get-packages': 1.1.3
- '@types/is-ci': 3.0.0
- '@types/semver': 6.2.3
ansi-colors: 4.1.3
- chalk: 2.4.2
- enquirer: 2.3.6
- external-editor: 3.1.0
+ ci-info: 3.9.0
+ enquirer: 2.4.1
fs-extra: 7.0.1
- human-id: 1.0.2
- is-ci: 3.0.1
- meow: 6.1.1
- outdent: 0.5.0
+ mri: 1.2.0
p-limit: 2.3.0
- preferred-pm: 3.0.3
+ package-manager-detector: 0.2.11
+ picocolors: 1.1.1
resolve-from: 5.0.0
- semver: 7.6.2
- spawndamnit: 2.0.0
+ semver: 7.7.3
+ spawndamnit: 3.0.1
term-size: 2.2.1
- tty-table: 4.2.1
- dev: true
+ transitivePeerDependencies:
+ - '@types/node'
- /@changesets/config@2.3.0:
- resolution: {integrity: sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==}
+ '@changesets/config@3.1.1':
dependencies:
- '@changesets/errors': 0.1.4
- '@changesets/get-dependents-graph': 1.3.5
- '@changesets/logger': 0.0.5
- '@changesets/types': 5.2.1
+ '@changesets/errors': 0.2.0
+ '@changesets/get-dependents-graph': 2.1.3
+ '@changesets/logger': 0.1.1
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
fs-extra: 7.0.1
- micromatch: 4.0.5
- dev: true
+ micromatch: 4.0.8
- /@changesets/errors@0.1.4:
- resolution: {integrity: sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==}
+ '@changesets/errors@0.2.0':
dependencies:
extendable-error: 0.1.7
- dev: true
- /@changesets/get-dependents-graph@1.3.5:
- resolution: {integrity: sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==}
+ '@changesets/get-dependents-graph@2.1.3':
dependencies:
- '@changesets/types': 5.2.1
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
- chalk: 2.4.2
- fs-extra: 7.0.1
- semver: 7.6.2
- dev: true
-
- /@changesets/get-release-plan@3.0.16:
- resolution: {integrity: sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==}
- dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/assemble-release-plan': 5.2.3
- '@changesets/config': 2.3.0
- '@changesets/pre': 1.0.14
- '@changesets/read': 0.5.9
- '@changesets/types': 5.2.1
+ picocolors: 1.1.1
+ semver: 7.7.3
+
+ '@changesets/get-release-plan@4.0.13':
+ dependencies:
+ '@changesets/assemble-release-plan': 6.0.9
+ '@changesets/config': 3.1.1
+ '@changesets/pre': 2.0.2
+ '@changesets/read': 0.6.5
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
- dev: true
- /@changesets/get-version-range-type@0.3.2:
- resolution: {integrity: sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==}
- dev: true
+ '@changesets/get-version-range-type@0.4.0': {}
- /@changesets/git@2.0.0:
- resolution: {integrity: sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==}
+ '@changesets/git@3.0.4':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/errors': 0.1.4
- '@changesets/types': 5.2.1
+ '@changesets/errors': 0.2.0
'@manypkg/get-packages': 1.1.3
is-subdir: 1.2.0
- micromatch: 4.0.5
- spawndamnit: 2.0.0
- dev: true
+ micromatch: 4.0.8
+ spawndamnit: 3.0.1
- /@changesets/logger@0.0.5:
- resolution: {integrity: sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==}
+ '@changesets/logger@0.1.1':
dependencies:
- chalk: 2.4.2
- dev: true
+ picocolors: 1.1.1
- /@changesets/parse@0.3.16:
- resolution: {integrity: sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==}
+ '@changesets/parse@0.4.1':
dependencies:
- '@changesets/types': 5.2.1
+ '@changesets/types': 6.1.0
js-yaml: 3.14.1
- dev: true
- /@changesets/pre@1.0.14:
- resolution: {integrity: sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==}
+ '@changesets/pre@2.0.2':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/errors': 0.1.4
- '@changesets/types': 5.2.1
+ '@changesets/errors': 0.2.0
+ '@changesets/types': 6.1.0
'@manypkg/get-packages': 1.1.3
fs-extra: 7.0.1
- dev: true
- /@changesets/read@0.5.9:
- resolution: {integrity: sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==}
+ '@changesets/read@0.6.5':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/git': 2.0.0
- '@changesets/logger': 0.0.5
- '@changesets/parse': 0.3.16
- '@changesets/types': 5.2.1
- chalk: 2.4.2
+ '@changesets/git': 3.0.4
+ '@changesets/logger': 0.1.1
+ '@changesets/parse': 0.4.1
+ '@changesets/types': 6.1.0
fs-extra: 7.0.1
p-filter: 2.1.0
- dev: true
+ picocolors: 1.1.1
- /@changesets/types@4.1.0:
- resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==}
- dev: true
+ '@changesets/should-skip-package@0.1.2':
+ dependencies:
+ '@changesets/types': 6.1.0
+ '@manypkg/get-packages': 1.1.3
- /@changesets/types@5.2.1:
- resolution: {integrity: sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==}
- dev: true
+ '@changesets/types@4.1.0': {}
- /@changesets/write@0.2.3:
- resolution: {integrity: sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==}
+ '@changesets/types@6.1.0': {}
+
+ '@changesets/write@0.4.0':
dependencies:
- '@babel/runtime': 7.21.0
- '@changesets/types': 5.2.1
+ '@changesets/types': 6.1.0
fs-extra: 7.0.1
- human-id: 1.0.2
- prettier: 2.8.7
- dev: true
+ human-id: 4.1.2
+ prettier: 2.8.8
- /@cspotcode/source-map-support@0.8.1:
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
+ '@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
- dev: true
-
- /@esbuild/aix-ppc64@0.21.5:
- resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [aix]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm64@0.17.17:
- resolution: {integrity: sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm64@0.21.5:
- resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm@0.17.17:
- resolution: {integrity: sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm@0.21.5:
- resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-x64@0.17.17:
- resolution: {integrity: sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-x64@0.21.5:
- resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-arm64@0.17.17:
- resolution: {integrity: sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-arm64@0.21.5:
- resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-x64@0.17.17:
- resolution: {integrity: sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-x64@0.21.5:
- resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-arm64@0.17.17:
- resolution: {integrity: sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-arm64@0.21.5:
- resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-x64@0.17.17:
- resolution: {integrity: sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-x64@0.21.5:
- resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm64@0.17.17:
- resolution: {integrity: sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
- /@esbuild/linux-arm64@0.21.5:
- resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@emnapi/core@1.7.1':
+ dependencies:
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
optional: true
- /@esbuild/linux-arm@0.17.17:
- resolution: {integrity: sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@emnapi/runtime@1.7.1':
+ dependencies:
+ tslib: 2.8.1
optional: true
- /@esbuild/linux-arm@0.21.5:
- resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@emnapi/wasi-threads@1.1.0':
+ dependencies:
+ tslib: 2.8.1
optional: true
- /@esbuild/linux-ia32@0.17.17:
- resolution: {integrity: sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/aix-ppc64@0.25.11':
optional: true
- /@esbuild/linux-ia32@0.21.5:
- resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/android-arm64@0.25.11':
optional: true
- /@esbuild/linux-loong64@0.17.17:
- resolution: {integrity: sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/android-arm@0.25.11':
optional: true
- /@esbuild/linux-loong64@0.21.5:
- resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/android-x64@0.25.11':
optional: true
- /@esbuild/linux-mips64el@0.17.17:
- resolution: {integrity: sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/darwin-arm64@0.25.11':
optional: true
- /@esbuild/linux-mips64el@0.21.5:
- resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/darwin-x64@0.25.11':
optional: true
- /@esbuild/linux-ppc64@0.17.17:
- resolution: {integrity: sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/freebsd-arm64@0.25.11':
optional: true
- /@esbuild/linux-ppc64@0.21.5:
- resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/freebsd-x64@0.25.11':
optional: true
- /@esbuild/linux-riscv64@0.17.17:
- resolution: {integrity: sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-arm64@0.25.11':
optional: true
- /@esbuild/linux-riscv64@0.21.5:
- resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-arm@0.25.11':
optional: true
- /@esbuild/linux-s390x@0.17.17:
- resolution: {integrity: sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-ia32@0.25.11':
optional: true
- /@esbuild/linux-s390x@0.21.5:
- resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-loong64@0.25.11':
optional: true
- /@esbuild/linux-x64@0.17.17:
- resolution: {integrity: sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-mips64el@0.25.11':
optional: true
- /@esbuild/linux-x64@0.21.5:
- resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-ppc64@0.25.11':
optional: true
- /@esbuild/netbsd-x64@0.17.17:
- resolution: {integrity: sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-riscv64@0.25.11':
optional: true
- /@esbuild/netbsd-x64@0.21.5:
- resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-s390x@0.25.11':
optional: true
- /@esbuild/openbsd-x64@0.17.17:
- resolution: {integrity: sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/linux-x64@0.25.11':
optional: true
- /@esbuild/openbsd-x64@0.21.5:
- resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
+ '@esbuild/netbsd-arm64@0.25.11':
optional: true
- /@esbuild/sunos-x64@0.17.17:
- resolution: {integrity: sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
+ '@esbuild/netbsd-x64@0.25.11':
optional: true
- /@esbuild/sunos-x64@0.21.5:
- resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
+ '@esbuild/openbsd-arm64@0.25.11':
optional: true
- /@esbuild/win32-arm64@0.17.17:
- resolution: {integrity: sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/openbsd-x64@0.25.11':
optional: true
- /@esbuild/win32-arm64@0.21.5:
- resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/openharmony-arm64@0.25.11':
optional: true
- /@esbuild/win32-ia32@0.17.17:
- resolution: {integrity: sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/sunos-x64@0.25.11':
optional: true
- /@esbuild/win32-ia32@0.21.5:
- resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-arm64@0.25.11':
optional: true
- /@esbuild/win32-x64@0.17.17:
- resolution: {integrity: sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-ia32@0.25.11':
optional: true
- /@esbuild/win32-x64@0.21.5:
- resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@esbuild/win32-x64@0.25.11':
optional: true
- /@isaacs/cliui@8.0.2:
- resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
- engines: {node: '>=12'}
+ '@inquirer/external-editor@1.0.2(@types/node@22.18.11)':
+ dependencies:
+ chardet: 2.1.0
+ iconv-lite: 0.7.0
+ optionalDependencies:
+ '@types/node': 22.18.11
+
+ '@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
- string-width-cjs: /string-width@4.2.3
- strip-ansi: 7.1.0
- strip-ansi-cjs: /strip-ansi@6.0.1
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.2
+ strip-ansi-cjs: strip-ansi@6.0.1
wrap-ansi: 8.1.0
- wrap-ansi-cjs: /wrap-ansi@7.0.0
- dev: true
+ wrap-ansi-cjs: wrap-ansi@7.0.0
- /@istanbuljs/schema@0.1.3:
- resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
- engines: {node: '>=8'}
- dev: true
+ '@istanbuljs/schema@0.1.3': {}
- /@jest/expect-utils@29.5.0:
- resolution: {integrity: sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dependencies:
- jest-get-type: 29.4.3
- dev: true
+ '@jest/diff-sequences@30.0.1': {}
- /@jest/schemas@29.4.3:
- resolution: {integrity: sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jest/expect-utils@30.2.0':
dependencies:
- '@sinclair/typebox': 0.25.24
- dev: true
+ '@jest/get-type': 30.1.0
- /@jest/types@29.5.0:
- resolution: {integrity: sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dependencies:
- '@jest/schemas': 29.4.3
- '@types/istanbul-lib-coverage': 2.0.4
- '@types/istanbul-reports': 3.0.1
- '@types/node': 18.15.13
- '@types/yargs': 17.0.24
- chalk: 4.1.2
- dev: true
+ '@jest/get-type@30.1.0': {}
- /@jridgewell/gen-mapping@0.3.3:
- resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
- engines: {node: '>=6.0.0'}
+ '@jest/pattern@30.0.1':
dependencies:
- '@jridgewell/set-array': 1.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
- '@jridgewell/trace-mapping': 0.3.18
- dev: true
+ '@types/node': 22.18.11
+ jest-regex-util: 30.0.1
- /@jridgewell/gen-mapping@0.3.5:
- resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
- engines: {node: '>=6.0.0'}
+ '@jest/schemas@30.0.5':
dependencies:
- '@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.4.15
- '@jridgewell/trace-mapping': 0.3.25
- dev: true
-
- /@jridgewell/resolve-uri@3.1.0:
- resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
- engines: {node: '>=6.0.0'}
- dev: true
-
- /@jridgewell/set-array@1.1.2:
- resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
- engines: {node: '>=6.0.0'}
- dev: true
+ '@sinclair/typebox': 0.34.41
- /@jridgewell/set-array@1.2.1:
- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
- engines: {node: '>=6.0.0'}
- dev: true
+ '@jest/types@30.2.0':
+ dependencies:
+ '@jest/pattern': 30.0.1
+ '@jest/schemas': 30.0.5
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 22.18.11
+ '@types/yargs': 17.0.33
+ chalk: 4.1.2
- /@jridgewell/source-map@0.3.3:
- resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==}
+ '@jridgewell/gen-mapping@0.3.13':
dependencies:
- '@jridgewell/gen-mapping': 0.3.3
- '@jridgewell/trace-mapping': 0.3.18
- dev: true
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
- /@jridgewell/sourcemap-codec@1.4.14:
- resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
- dev: true
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
- /@jridgewell/sourcemap-codec@1.4.15:
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
- dev: true
+ '@jridgewell/resolve-uri@3.1.2': {}
- /@jridgewell/trace-mapping@0.3.18:
- resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
+ '@jridgewell/source-map@0.3.11':
dependencies:
- '@jridgewell/resolve-uri': 3.1.0
- '@jridgewell/sourcemap-codec': 1.4.14
- dev: true
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
- /@jridgewell/trace-mapping@0.3.25:
- resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ '@jridgewell/trace-mapping@0.3.31':
dependencies:
- '@jridgewell/resolve-uri': 3.1.0
- '@jridgewell/sourcemap-codec': 1.4.15
- dev: true
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
- /@jridgewell/trace-mapping@0.3.9:
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ '@jridgewell/trace-mapping@0.3.9':
dependencies:
- '@jridgewell/resolve-uri': 3.1.0
- '@jridgewell/sourcemap-codec': 1.4.15
- dev: true
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
- /@manypkg/find-root@1.1.0:
- resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
+ '@manypkg/find-root@1.1.0':
dependencies:
- '@babel/runtime': 7.21.0
+ '@babel/runtime': 7.28.4
'@types/node': 12.20.55
find-up: 4.1.0
fs-extra: 8.1.0
- dev: true
- /@manypkg/get-packages@1.1.3:
- resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==}
+ '@manypkg/get-packages@1.1.3':
dependencies:
- '@babel/runtime': 7.21.0
+ '@babel/runtime': 7.28.4
'@changesets/types': 4.1.0
'@manypkg/find-root': 1.1.0
fs-extra: 8.1.0
globby: 11.1.0
read-yaml-file: 1.1.0
- dev: true
- /@nodelib/fs.scandir@2.1.5:
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
+ '@napi-rs/wasm-runtime@1.1.0':
+ dependencies:
+ '@emnapi/core': 1.7.1
+ '@emnapi/runtime': 1.7.1
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
+ '@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
- dev: true
- /@nodelib/fs.stat@2.0.5:
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
- dev: true
+ '@nodelib/fs.stat@2.0.5': {}
- /@nodelib/fs.walk@1.2.8:
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
+ '@nodelib/fs.walk@1.2.8':
dependencies:
'@nodelib/fs.scandir': 2.1.5
- fastq: 1.15.0
- dev: true
+ fastq: 1.19.1
- /@pkgjs/parseargs@0.11.0:
- resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
- engines: {node: '>=14'}
- requiresBuild: true
- dev: true
+ '@oxc-project/types@0.101.0': {}
+
+ '@pkgjs/parseargs@0.11.0':
optional: true
- /@rollup/rollup-android-arm-eabi@4.18.1:
- resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
+ '@quansync/fs@1.0.0':
+ dependencies:
+ quansync: 1.0.0
+
+ '@rolldown/binding-android-arm64@1.0.0-beta.53':
optional: true
- /@rollup/rollup-android-arm64@4.18.1:
- resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.53':
optional: true
- /@rollup/rollup-darwin-arm64@4.18.1:
- resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-darwin-x64@1.0.0-beta.53':
optional: true
- /@rollup/rollup-darwin-x64@4.18.1:
- resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-arm-gnueabihf@4.18.1:
- resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-arm-musleabihf@4.18.1:
- resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-arm64-gnu@4.18.1:
- resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-arm64-musl@4.18.1:
- resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-powerpc64le-gnu@4.18.1:
- resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-riscv64-gnu@4.18.1:
- resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-openharmony-arm64@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-s390x-gnu@4.18.1:
- resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.53':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.0
optional: true
- /@rollup/rollup-linux-x64-gnu@4.18.1:
- resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53':
optional: true
- /@rollup/rollup-linux-x64-musl@4.18.1:
- resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53':
optional: true
- /@rollup/rollup-win32-arm64-msvc@4.18.1:
- resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@rolldown/pluginutils@1.0.0-beta.27': {}
+
+ '@rolldown/pluginutils@1.0.0-beta.53': {}
+
+ '@rollup/rollup-android-arm-eabi@4.52.5':
optional: true
- /@rollup/rollup-win32-ia32-msvc@4.18.1:
- resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@rollup/rollup-android-arm64@4.52.5':
optional: true
- /@rollup/rollup-win32-x64-msvc@4.18.1:
- resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
+ '@rollup/rollup-darwin-arm64@4.52.5':
optional: true
- /@sinclair/typebox@0.25.24:
- resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==}
- dev: true
+ '@rollup/rollup-darwin-x64@4.52.5':
+ optional: true
- /@size-limit/esbuild@8.2.4(size-limit@8.2.4):
- resolution: {integrity: sha512-kPgNfpwUvBD98s5axlf1UciFg4Ki4AYSl/cOmSyyYBuzksHiwW7Myeu0w4mTxtV9nwBFbkrrNXqszE7b+OhFLA==}
- engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
- peerDependencies:
- size-limit: 8.2.4
+ '@rollup/rollup-freebsd-arm64@4.52.5':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.52.5':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.52.5':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.52.5':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.52.5':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.52.5':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.52.5':
+ optional: true
+
+ '@sinclair/typebox@0.34.41': {}
+
+ '@size-limit/esbuild@8.2.6(size-limit@8.2.6)':
dependencies:
- esbuild: 0.17.17
- nanoid: 3.3.6
- size-limit: 8.2.4
- dev: true
+ esbuild: 0.25.11
+ nanoid: 5.1.6
+ size-limit: 8.2.6
- /@size-limit/file@8.2.4(size-limit@8.2.4):
- resolution: {integrity: sha512-xLuF97W7m7lxrRJvqXRlxO/4t7cpXtfxOnjml/t4aRVUCMXLdyvebRr9OM4jjoK8Fmiz8jomCbETUCI3jVhLzA==}
- engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
- peerDependencies:
- size-limit: 8.2.4
+ '@size-limit/file@8.2.6(size-limit@8.2.6)':
dependencies:
- semver: 7.6.2
- size-limit: 8.2.4
- dev: true
+ semver: 7.5.3
+ size-limit: 8.2.6
- /@size-limit/preset-small-lib@8.2.4(size-limit@8.2.4):
- resolution: {integrity: sha512-AL4384oBgMcDPlNblgWHreqFSSOui0J9NbgyHhegB1h8AgRyHbdVGC3yWLpEESYQXHYnKdbNrYeRE/TclsViog==}
- peerDependencies:
- size-limit: 8.2.4
+ '@size-limit/preset-small-lib@8.2.6(size-limit@8.2.6)':
dependencies:
- '@size-limit/esbuild': 8.2.4(size-limit@8.2.4)
- '@size-limit/file': 8.2.4(size-limit@8.2.4)
- size-limit: 8.2.4
- dev: true
+ '@size-limit/esbuild': 8.2.6(size-limit@8.2.6)
+ '@size-limit/file': 8.2.6(size-limit@8.2.6)
+ size-limit: 8.2.6
- /@testing-library/dom@9.2.0:
- resolution: {integrity: sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==}
- engines: {node: '>=14'}
+ '@testing-library/dom@9.3.4':
dependencies:
- '@babel/code-frame': 7.21.4
- '@babel/runtime': 7.21.0
- '@types/aria-query': 5.0.1
+ '@babel/code-frame': 7.27.1
+ '@babel/runtime': 7.28.4
+ '@types/aria-query': 5.0.4
aria-query: 5.1.3
chalk: 4.1.2
dom-accessibility-api: 0.5.16
lz-string: 1.5.0
pretty-format: 27.5.1
- dev: true
- /@testing-library/jest-dom@5.16.5:
- resolution: {integrity: sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==}
- engines: {node: '>=8', npm: '>=6', yarn: '>=1'}
+ '@testing-library/jest-dom@5.17.0':
dependencies:
- '@adobe/css-tools': 4.4.0
- '@babel/runtime': 7.21.0
- '@types/testing-library__jest-dom': 5.14.5
- aria-query: 5.1.3
+ '@adobe/css-tools': 4.4.4
+ '@babel/runtime': 7.28.4
+ '@types/testing-library__jest-dom': 5.14.9
+ aria-query: 5.3.2
chalk: 3.0.0
css.escape: 1.5.1
dom-accessibility-api: 0.5.16
lodash: 4.17.21
redent: 3.0.0
- dev: true
- /@testing-library/react@14.0.0(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==}
- engines: {node: '>=14'}
- peerDependencies:
- react: ^18.0.0
- react-dom: ^18.0.0
+ '@testing-library/react@14.3.1(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
- '@babel/runtime': 7.21.0
- '@testing-library/dom': 9.2.0
- '@types/react-dom': 18.0.11
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
- dev: true
+ '@babel/runtime': 7.28.4
+ '@testing-library/dom': 9.3.4
+ '@types/react-dom': 18.3.7(@types/react@18.3.26)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ transitivePeerDependencies:
+ - '@types/react'
- /@tootallnate/once@2.0.0:
- resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
- engines: {node: '>= 10'}
- dev: true
+ '@tootallnate/once@2.0.0': {}
- /@tsconfig/node10@1.0.9:
- resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
- dev: true
+ '@tsconfig/node10@1.0.11': {}
- /@tsconfig/node12@1.0.11:
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
- dev: true
+ '@tsconfig/node12@1.0.11': {}
- /@tsconfig/node14@1.0.3:
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
- dev: true
+ '@tsconfig/node14@1.0.3': {}
- /@tsconfig/node16@1.0.3:
- resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
- dev: true
+ '@tsconfig/node16@1.0.4': {}
- /@types/aria-query@5.0.1:
- resolution: {integrity: sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==}
- dev: true
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
- /@types/babel__core@7.20.5:
- resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+ '@types/aria-query@5.0.4': {}
+
+ '@types/babel__core@7.20.5':
dependencies:
- '@babel/parser': 7.24.8
- '@babel/types': 7.24.9
- '@types/babel__generator': 7.6.8
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+ '@types/babel__generator': 7.27.0
'@types/babel__template': 7.4.4
- '@types/babel__traverse': 7.20.6
- dev: true
+ '@types/babel__traverse': 7.28.0
- /@types/babel__generator@7.6.8:
- resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
+ '@types/babel__generator@7.27.0':
dependencies:
- '@babel/types': 7.24.9
- dev: true
+ '@babel/types': 7.28.4
- /@types/babel__template@7.4.4:
- resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+ '@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.24.8
- '@babel/types': 7.24.9
- dev: true
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
- /@types/babel__traverse@7.20.6:
- resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
+ '@types/babel__traverse@7.28.0':
dependencies:
- '@babel/types': 7.24.9
- dev: true
+ '@babel/types': 7.28.4
- /@types/estree@1.0.5:
- resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
- dev: true
-
- /@types/is-ci@3.0.0:
- resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==}
+ '@types/chai@5.2.2':
dependencies:
- ci-info: 3.8.0
- dev: true
+ '@types/deep-eql': 4.0.2
- /@types/istanbul-lib-coverage@2.0.4:
- resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
- dev: true
+ '@types/deep-eql@4.0.2': {}
- /@types/istanbul-lib-report@3.0.0:
- resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==}
- dependencies:
- '@types/istanbul-lib-coverage': 2.0.4
- dev: true
+ '@types/estree@1.0.8': {}
- /@types/istanbul-reports@3.0.1:
- resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==}
- dependencies:
- '@types/istanbul-lib-report': 3.0.0
- dev: true
+ '@types/istanbul-lib-coverage@2.0.6': {}
- /@types/jest@29.5.1:
- resolution: {integrity: sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ==}
+ '@types/istanbul-lib-report@3.0.3':
dependencies:
- expect: 29.5.0
- pretty-format: 29.5.0
- dev: true
+ '@types/istanbul-lib-coverage': 2.0.6
- /@types/minimist@1.2.2:
- resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
- dev: true
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
- /@types/node@12.20.55:
- resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
- dev: true
+ '@types/jest@30.0.0':
+ dependencies:
+ expect: 30.2.0
+ pretty-format: 30.2.0
- /@types/node@18.15.13:
- resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==}
- dev: true
+ '@types/node@12.20.55': {}
- /@types/normalize-package-data@2.4.1:
- resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
- dev: true
+ '@types/node@22.18.11':
+ dependencies:
+ undici-types: 6.21.0
- /@types/prop-types@15.7.5:
- resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
- dev: true
+ '@types/prop-types@15.7.15': {}
- /@types/react-dom@18.0.11:
- resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
+ '@types/react-dom@18.3.7(@types/react@18.3.26)':
dependencies:
- '@types/react': 18.0.38
- dev: true
+ '@types/react': 18.3.26
- /@types/react@18.0.38:
- resolution: {integrity: sha512-ExsidLLSzYj4cvaQjGnQCk4HFfVT9+EZ9XZsQ8Hsrcn8QNgXtpZ3m9vSIC2MWtx7jHictK6wYhQgGh6ic58oOw==}
+ '@types/react@18.3.26':
dependencies:
- '@types/prop-types': 15.7.5
- '@types/scheduler': 0.16.3
- csstype: 3.1.2
- dev: true
-
- /@types/scheduler@0.16.3:
- resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
- dev: true
+ '@types/prop-types': 15.7.15
+ csstype: 3.1.3
- /@types/semver@6.2.3:
- resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==}
- dev: true
+ '@types/stack-utils@2.0.3': {}
- /@types/stack-utils@2.0.1:
- resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
- dev: true
-
- /@types/testing-library__jest-dom@5.14.5:
- resolution: {integrity: sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==}
+ '@types/testing-library__jest-dom@5.14.9':
dependencies:
- '@types/jest': 29.5.1
- dev: true
+ '@types/jest': 30.0.0
- /@types/yargs-parser@21.0.0:
- resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
- dev: true
+ '@types/yargs-parser@21.0.3': {}
- /@types/yargs@17.0.24:
- resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==}
+ '@types/yargs@17.0.33':
dependencies:
- '@types/yargs-parser': 21.0.0
- dev: true
+ '@types/yargs-parser': 21.0.3
- /@vitejs/plugin-react@4.3.1(vite@5.3.3):
- resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==}
- engines: {node: ^14.18.0 || >=16.0.0}
- peerDependencies:
- vite: ^4.2.0 || ^5.0.0
+ '@vitejs/plugin-react@4.7.0(vite@7.1.11(@types/node@22.18.11)(terser@5.44.0))':
dependencies:
- '@babel/core': 7.24.9
- '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.9)
- '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.9)
+ '@babel/core': 7.28.4
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4)
+ '@rolldown/pluginutils': 1.0.0-beta.27
'@types/babel__core': 7.20.5
- react-refresh: 0.14.2
- vite: 5.3.3(@types/node@18.15.13)(terser@5.17.1)
+ react-refresh: 0.17.0
+ vite: 7.1.11(@types/node@22.18.11)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
- dev: true
- /@vitest/coverage-istanbul@2.0.3(vitest@2.0.3):
- resolution: {integrity: sha512-ewO7lSXDc/hG7vrVUh3lrpRpNZslivE92b07lW05GE+o7dkmvSheCl6oyMqa3EVU1rjbbM8dlWsfNOY4PAqasQ==}
- peerDependencies:
- vitest: 2.0.3
+ '@vitest/coverage-istanbul@3.2.4(vitest@3.2.4(@types/node@22.18.11)(jsdom@21.1.2)(terser@5.44.0))':
dependencies:
'@istanbuljs/schema': 0.1.3
- debug: 4.3.5
+ debug: 4.4.3
istanbul-lib-coverage: 3.2.2
istanbul-lib-instrument: 6.0.3
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
- istanbul-reports: 3.1.7
- magicast: 0.3.4
+ istanbul-reports: 3.2.0
+ magicast: 0.3.5
test-exclude: 7.0.1
- tinyrainbow: 1.2.0
- vitest: 2.0.3(@types/node@18.15.13)(jsdom@21.1.1)(terser@5.17.1)
+ tinyrainbow: 2.0.0
+ vitest: 3.2.4(@types/node@22.18.11)(jsdom@21.1.2)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
- dev: true
- /@vitest/expect@2.0.3:
- resolution: {integrity: sha512-X6AepoOYePM0lDNUPsGXTxgXZAl3EXd0GYe/MZyVE4HzkUqyUVC6S3PrY5mClDJ6/7/7vALLMV3+xD/Ko60Hqg==}
+ '@vitest/expect@3.2.4':
+ dependencies:
+ '@types/chai': 5.2.2
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.3.3
+ tinyrainbow: 2.0.0
+
+ '@vitest/mocker@3.2.4(vite@7.1.11(@types/node@22.18.11)(terser@5.44.0))':
dependencies:
- '@vitest/spy': 2.0.3
- '@vitest/utils': 2.0.3
- chai: 5.1.1
- tinyrainbow: 1.2.0
- dev: true
+ '@vitest/spy': 3.2.4
+ estree-walker: 3.0.3
+ magic-string: 0.30.19
+ optionalDependencies:
+ vite: 7.1.11(@types/node@22.18.11)(terser@5.44.0)
- /@vitest/pretty-format@2.0.3:
- resolution: {integrity: sha512-URM4GLsB2xD37nnTyvf6kfObFafxmycCL8un3OC9gaCs5cti2u+5rJdIflZ2fUJUen4NbvF6jCufwViAFLvz1g==}
+ '@vitest/pretty-format@3.2.4':
dependencies:
- tinyrainbow: 1.2.0
- dev: true
+ tinyrainbow: 2.0.0
- /@vitest/runner@2.0.3:
- resolution: {integrity: sha512-EmSP4mcjYhAcuBWwqgpjR3FYVeiA4ROzRunqKltWjBfLNs1tnMLtF+qtgd5ClTwkDP6/DGlKJTNa6WxNK0bNYQ==}
+ '@vitest/runner@3.2.4':
dependencies:
- '@vitest/utils': 2.0.3
- pathe: 1.1.2
- dev: true
+ '@vitest/utils': 3.2.4
+ pathe: 2.0.3
+ strip-literal: 3.1.0
- /@vitest/snapshot@2.0.3:
- resolution: {integrity: sha512-6OyA6v65Oe3tTzoSuRPcU6kh9m+mPL1vQ2jDlPdn9IQoUxl8rXhBnfICNOC+vwxWY684Vt5UPgtcA2aPFBb6wg==}
+ '@vitest/snapshot@3.2.4':
dependencies:
- '@vitest/pretty-format': 2.0.3
- magic-string: 0.30.10
- pathe: 1.1.2
- dev: true
+ '@vitest/pretty-format': 3.2.4
+ magic-string: 0.30.19
+ pathe: 2.0.3
- /@vitest/spy@2.0.3:
- resolution: {integrity: sha512-sfqyAw/ypOXlaj4S+w8689qKM1OyPOqnonqOc9T91DsoHbfN5mU7FdifWWv3MtQFf0lEUstEwR9L/q/M390C+A==}
+ '@vitest/spy@3.2.4':
dependencies:
- tinyspy: 3.0.0
- dev: true
+ tinyspy: 4.0.4
- /@vitest/utils@2.0.3:
- resolution: {integrity: sha512-c/UdELMuHitQbbc/EVctlBaxoYAwQPQdSNwv7z/vHyBKy2edYZaFgptE27BRueZB7eW8po+cllotMNTDpL3HWg==}
+ '@vitest/utils@3.2.4':
dependencies:
- '@vitest/pretty-format': 2.0.3
- estree-walker: 3.0.3
- loupe: 3.1.1
- tinyrainbow: 1.2.0
- dev: true
+ '@vitest/pretty-format': 3.2.4
+ loupe: 3.2.1
+ tinyrainbow: 2.0.0
- /abab@2.0.6:
- resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
- dev: true
+ abab@2.0.6: {}
- /acorn-globals@7.0.1:
- resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
+ acorn-globals@7.0.1:
dependencies:
- acorn: 8.8.2
- acorn-walk: 8.2.0
- dev: true
+ acorn: 8.15.0
+ acorn-walk: 8.3.4
- /acorn-walk@8.2.0:
- resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
- engines: {node: '>=0.4.0'}
- dev: true
+ acorn-walk@8.3.4:
+ dependencies:
+ acorn: 8.15.0
- /acorn@8.8.2:
- resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
- engines: {node: '>=0.4.0'}
- hasBin: true
- dev: true
+ acorn@8.15.0: {}
- /agent-base@6.0.2:
- resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
- engines: {node: '>= 6.0.0'}
+ agent-base@6.0.2:
dependencies:
- debug: 4.3.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
- dev: true
-
- /ansi-colors@4.1.3:
- resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
- engines: {node: '>=6'}
- dev: true
- /ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
- dev: true
+ ansi-colors@4.1.3: {}
- /ansi-regex@6.0.1:
- resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
- engines: {node: '>=12'}
- dev: true
+ ansi-regex@5.0.1: {}
- /ansi-styles@3.2.1:
- resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
- engines: {node: '>=4'}
- dependencies:
- color-convert: 1.9.3
- dev: true
+ ansi-regex@6.2.2: {}
- /ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
+ ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
- dev: true
- /ansi-styles@5.2.0:
- resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
- engines: {node: '>=10'}
- dev: true
+ ansi-styles@5.2.0: {}
- /ansi-styles@6.2.1:
- resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
- engines: {node: '>=12'}
- dev: true
+ ansi-styles@6.2.3: {}
- /any-promise@1.3.0:
- resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
- dev: true
+ ansis@4.2.0: {}
- /anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
+ anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
- dev: true
- /arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
- dev: true
+ arg@4.1.3: {}
- /argparse@1.0.10:
- resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
- dev: true
- /aria-query@5.1.3:
- resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+ aria-query@5.1.3:
dependencies:
- deep-equal: 2.2.0
- dev: true
+ deep-equal: 2.2.3
+
+ aria-query@5.3.2: {}
- /array-buffer-byte-length@1.0.0:
- resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+ array-buffer-byte-length@1.0.2:
dependencies:
- call-bind: 1.0.2
- is-array-buffer: 3.0.2
- dev: true
+ call-bound: 1.0.4
+ is-array-buffer: 3.0.5
- /array-union@2.1.0:
- resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
- engines: {node: '>=8'}
- dev: true
+ array-union@2.1.0: {}
- /array.prototype.flat@1.3.1:
- resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.21.2
- es-shim-unscopables: 1.0.0
- dev: true
+ assertion-error@2.0.1: {}
- /arrify@1.0.1:
- resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
- engines: {node: '>=0.10.0'}
- dev: true
+ ast-kit@2.2.0:
+ dependencies:
+ '@babel/parser': 7.28.5
+ pathe: 2.0.3
- /assertion-error@2.0.1:
- resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
- engines: {node: '>=12'}
- dev: true
+ asynckit@0.4.0: {}
- /asynckit@0.4.0:
- resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- dev: true
+ available-typed-arrays@1.0.7:
+ dependencies:
+ possible-typed-array-names: 1.1.0
- /available-typed-arrays@1.0.5:
- resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
- engines: {node: '>= 0.4'}
- dev: true
+ balanced-match@3.0.1: {}
- /balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- dev: true
+ baseline-browser-mapping@2.8.18: {}
- /better-path-resolve@1.0.0:
- resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
- engines: {node: '>=4'}
+ better-path-resolve@1.0.0:
dependencies:
is-windows: 1.0.2
- dev: true
- /binary-extensions@2.2.0:
- resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
- engines: {node: '>=8'}
- dev: true
+ binary-extensions@2.3.0: {}
- /brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
- dev: true
+ birpc@3.0.0: {}
- /brace-expansion@2.0.1:
- resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ brace-expansion@4.0.1:
dependencies:
- balanced-match: 1.0.2
- dev: true
+ balanced-match: 3.0.1
- /braces@3.0.3:
- resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
- engines: {node: '>=8'}
+ braces@3.0.3:
dependencies:
fill-range: 7.1.1
- dev: true
-
- /breakword@1.0.5:
- resolution: {integrity: sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==}
- dependencies:
- wcwidth: 1.0.1
- dev: true
- /browserslist@4.23.2:
- resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
+ browserslist@4.26.3:
dependencies:
- caniuse-lite: 1.0.30001642
- electron-to-chromium: 1.4.828
- node-releases: 2.0.14
- update-browserslist-db: 1.1.0(browserslist@4.23.2)
- dev: true
-
- /buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
- dev: true
+ baseline-browser-mapping: 2.8.18
+ caniuse-lite: 1.0.30001751
+ electron-to-chromium: 1.5.237
+ node-releases: 2.0.25
+ update-browserslist-db: 1.1.3(browserslist@4.26.3)
- /bundle-require@4.0.1(esbuild@0.17.17):
- resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- peerDependencies:
- esbuild: '>=0.17'
- dependencies:
- esbuild: 0.17.17
- load-tsconfig: 0.2.5
- dev: true
+ buffer-from@1.1.2: {}
- /bytes-iec@3.1.1:
- resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==}
- engines: {node: '>= 0.8'}
- dev: true
+ bytes-iec@3.1.1: {}
- /cac@6.7.14:
- resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
- engines: {node: '>=8'}
- dev: true
+ cac@6.7.14: {}
- /call-bind@1.0.2:
- resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ call-bind-apply-helpers@1.0.2:
dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.2.0
- dev: true
+ es-errors: 1.3.0
+ function-bind: 1.1.2
- /camelcase-keys@6.2.2:
- resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
- engines: {node: '>=8'}
+ call-bind@1.0.8:
dependencies:
- camelcase: 5.3.1
- map-obj: 4.3.0
- quick-lru: 4.0.1
- dev: true
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ get-intrinsic: 1.3.0
+ set-function-length: 1.2.2
- /camelcase@5.3.1:
- resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
- engines: {node: '>=6'}
- dev: true
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
- /caniuse-lite@1.0.30001642:
- resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==}
- dev: true
+ caniuse-lite@1.0.30001751: {}
- /chai@5.1.1:
- resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==}
- engines: {node: '>=12'}
+ chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
- loupe: 3.1.1
- pathval: 2.0.0
- dev: true
-
- /chalk@2.4.2:
- resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
- engines: {node: '>=4'}
- dependencies:
- ansi-styles: 3.2.1
- escape-string-regexp: 1.0.5
- supports-color: 5.5.0
- dev: true
+ loupe: 3.2.1
+ pathval: 2.0.1
- /chalk@3.0.0:
- resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
- engines: {node: '>=8'}
+ chalk@3.0.0:
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
- dev: true
- /chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
+ chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
- dev: true
- /chardet@0.7.0:
- resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
- dev: true
+ chardet@2.1.0: {}
- /check-error@2.1.1:
- resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
- engines: {node: '>= 16'}
- dev: true
+ check-error@2.1.1: {}
- /chokidar@3.5.3:
- resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
- engines: {node: '>= 8.10.0'}
+ chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
- normalize-path: 3.0.0
- readdirp: 3.6.0
- optionalDependencies:
- fsevents: 2.3.3
- dev: true
-
- /ci-info@3.8.0:
- resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==}
- engines: {node: '>=8'}
- dev: true
-
- /cliui@6.0.0:
- resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 6.2.0
- dev: true
-
- /cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
- dev: true
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
- /clone@1.0.4:
- resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
- engines: {node: '>=0.8'}
- dev: true
+ ci-info@3.9.0: {}
- /color-convert@1.9.3:
- resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
- dependencies:
- color-name: 1.1.3
- dev: true
+ ci-info@4.3.1: {}
- /color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
+ color-convert@2.0.1:
dependencies:
color-name: 1.1.4
- dev: true
-
- /color-name@1.1.3:
- resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
- dev: true
- /color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- dev: true
+ color-name@1.1.4: {}
- /combined-stream@1.0.8:
- resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
- engines: {node: '>= 0.8'}
+ combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
- dev: true
-
- /commander@2.20.3:
- resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
- dev: true
-
- /commander@4.1.1:
- resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
- engines: {node: '>= 6'}
- dev: true
-
- /concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- dev: true
- /convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
- dev: true
+ commander@2.20.3: {}
- /create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
- dev: true
+ convert-source-map@2.0.0: {}
- /cross-spawn@5.1.0:
- resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
- dependencies:
- lru-cache: 4.1.5
- shebang-command: 1.2.0
- which: 1.3.1
- dev: true
+ create-require@1.1.1: {}
- /cross-spawn@7.0.3:
- resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
- engines: {node: '>= 8'}
+ cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
- dev: true
- /css.escape@1.5.1:
- resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
- dev: true
+ css.escape@1.5.1: {}
- /cssstyle@3.0.0:
- resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
- engines: {node: '>=14'}
+ cssstyle@3.0.0:
dependencies:
rrweb-cssom: 0.6.0
- dev: true
-
- /csstype@3.1.2:
- resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
- dev: true
- /csv-generate@3.4.3:
- resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==}
- dev: true
+ csstype@3.1.3: {}
- /csv-parse@4.16.3:
- resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==}
- dev: true
-
- /csv-stringify@5.6.5:
- resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==}
- dev: true
-
- /csv@5.5.3:
- resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==}
- engines: {node: '>= 0.1.90'}
- dependencies:
- csv-generate: 3.4.3
- csv-parse: 4.16.3
- csv-stringify: 5.6.5
- stream-transform: 2.1.3
- dev: true
-
- /data-urls@4.0.0:
- resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==}
- engines: {node: '>=14'}
+ data-urls@4.0.0:
dependencies:
abab: 2.0.6
whatwg-mimetype: 3.0.0
whatwg-url: 12.0.1
- dev: true
-
- /debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
- dev: true
-
- /debug@4.3.5:
- resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
- dev: true
- /decamelize-keys@1.1.1:
- resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
- engines: {node: '>=0.10.0'}
+ debug@4.4.3:
dependencies:
- decamelize: 1.2.0
- map-obj: 1.0.1
- dev: true
-
- /decamelize@1.2.0:
- resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
- engines: {node: '>=0.10.0'}
- dev: true
+ ms: 2.1.3
- /decimal.js@10.4.3:
- resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
- dev: true
+ decimal.js@10.6.0: {}
- /deep-eql@5.0.2:
- resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
- engines: {node: '>=6'}
- dev: true
+ deep-eql@5.0.2: {}
- /deep-equal@2.2.0:
- resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==}
+ deep-equal@2.2.3:
dependencies:
- call-bind: 1.0.2
+ array-buffer-byte-length: 1.0.2
+ call-bind: 1.0.8
es-get-iterator: 1.1.3
- get-intrinsic: 1.2.0
- is-arguments: 1.1.1
- is-array-buffer: 3.0.2
- is-date-object: 1.0.5
- is-regex: 1.1.4
- is-shared-array-buffer: 1.0.2
+ get-intrinsic: 1.3.0
+ is-arguments: 1.2.0
+ is-array-buffer: 3.0.5
+ is-date-object: 1.1.0
+ is-regex: 1.2.1
+ is-shared-array-buffer: 1.0.4
isarray: 2.0.5
- object-is: 1.1.5
+ object-is: 1.1.6
object-keys: 1.1.1
- object.assign: 4.1.4
- regexp.prototype.flags: 1.5.0
- side-channel: 1.0.4
- which-boxed-primitive: 1.0.2
- which-collection: 1.0.1
- which-typed-array: 1.1.9
- dev: true
-
- /deep-is@0.1.4:
- resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
- dev: true
-
- /defaults@1.0.4:
- resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
- dependencies:
- clone: 1.0.4
- dev: true
-
- /define-properties@1.2.0:
- resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
- engines: {node: '>= 0.4'}
+ object.assign: 4.1.7
+ regexp.prototype.flags: 1.5.4
+ side-channel: 1.1.0
+ which-boxed-primitive: 1.1.1
+ which-collection: 1.0.2
+ which-typed-array: 1.1.19
+
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ define-properties@1.2.1:
dependencies:
- has-property-descriptors: 1.0.0
+ define-data-property: 1.1.4
+ has-property-descriptors: 1.0.2
object-keys: 1.1.1
- dev: true
- /delayed-stream@1.0.0:
- resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
- engines: {node: '>=0.4.0'}
- dev: true
+ defu@6.1.4: {}
- /detect-indent@6.1.0:
- resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
- engines: {node: '>=8'}
- dev: true
+ delayed-stream@1.0.0: {}
- /diff-sequences@29.4.3:
- resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dev: true
+ detect-indent@6.1.0: {}
- /diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
- dev: true
+ diff@4.0.2: {}
- /dir-glob@3.0.1:
- resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
- engines: {node: '>=8'}
+ dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
- dev: true
- /dom-accessibility-api@0.5.16:
- resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
- dev: true
+ dom-accessibility-api@0.5.16: {}
- /domexception@4.0.0:
- resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
- engines: {node: '>=12'}
+ domexception@4.0.0:
dependencies:
webidl-conversions: 7.0.0
- dev: true
- /eastasianwidth@0.2.0:
- resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- dev: true
+ dts-resolver@2.1.3: {}
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
- /electron-to-chromium@1.4.828:
- resolution: {integrity: sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw==}
- dev: true
+ eastasianwidth@0.2.0: {}
- /emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
- dev: true
+ electron-to-chromium@1.5.237: {}
- /emoji-regex@9.2.2:
- resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- dev: true
+ emoji-regex@8.0.0: {}
- /enquirer@2.3.6:
- resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
- engines: {node: '>=8.6'}
+ emoji-regex@9.2.2: {}
+
+ empathic@2.0.0: {}
+
+ enquirer@2.4.1:
dependencies:
ansi-colors: 4.1.3
- dev: true
+ strip-ansi: 6.0.1
- /entities@4.5.0:
- resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
- engines: {node: '>=0.12'}
- dev: true
+ entities@6.0.1: {}
- /error-ex@1.3.2:
- resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
- dependencies:
- is-arrayish: 0.2.1
- dev: true
+ es-define-property@1.0.1: {}
- /es-abstract@1.21.2:
- resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==}
- engines: {node: '>= 0.4'}
- dependencies:
- array-buffer-byte-length: 1.0.0
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- es-set-tostringtag: 2.0.1
- es-to-primitive: 1.2.1
- function.prototype.name: 1.1.5
- get-intrinsic: 1.2.0
- get-symbol-description: 1.0.0
- globalthis: 1.0.3
- gopd: 1.0.1
- has: 1.0.3
- has-property-descriptors: 1.0.0
- has-proto: 1.0.1
- has-symbols: 1.0.3
- internal-slot: 1.0.5
- is-array-buffer: 3.0.2
- is-callable: 1.2.7
- is-negative-zero: 2.0.2
- is-regex: 1.1.4
- is-shared-array-buffer: 1.0.2
- is-string: 1.0.7
- is-typed-array: 1.1.10
- is-weakref: 1.0.2
- object-inspect: 1.12.3
- object-keys: 1.1.1
- object.assign: 4.1.4
- regexp.prototype.flags: 1.5.0
- safe-regex-test: 1.0.0
- string.prototype.trim: 1.2.7
- string.prototype.trimend: 1.0.6
- string.prototype.trimstart: 1.0.6
- typed-array-length: 1.0.4
- unbox-primitive: 1.0.2
- which-typed-array: 1.1.9
- dev: true
-
- /es-get-iterator@1.1.3:
- resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+ es-errors@1.3.0: {}
+
+ es-get-iterator@1.1.3:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- has-symbols: 1.0.3
- is-arguments: 1.1.1
- is-map: 2.0.2
- is-set: 2.0.2
- is-string: 1.0.7
+ call-bind: 1.0.8
+ get-intrinsic: 1.3.0
+ has-symbols: 1.1.0
+ is-arguments: 1.2.0
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-string: 1.1.1
isarray: 2.0.5
- stop-iteration-iterator: 1.0.0
- dev: true
+ stop-iteration-iterator: 1.1.0
- /es-set-tostringtag@2.0.1:
- resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
- engines: {node: '>= 0.4'}
- dependencies:
- get-intrinsic: 1.2.0
- has: 1.0.3
- has-tostringtag: 1.0.0
- dev: true
+ es-module-lexer@1.7.0: {}
- /es-shim-unscopables@1.0.0:
- resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
+ es-object-atoms@1.1.1:
dependencies:
- has: 1.0.3
- dev: true
+ es-errors: 1.3.0
- /es-to-primitive@1.2.1:
- resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
- engines: {node: '>= 0.4'}
+ es-set-tostringtag@2.1.0:
dependencies:
- is-callable: 1.2.7
- is-date-object: 1.0.5
- is-symbol: 1.0.4
- dev: true
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
- /esbuild@0.17.17:
- resolution: {integrity: sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- '@esbuild/android-arm': 0.17.17
- '@esbuild/android-arm64': 0.17.17
- '@esbuild/android-x64': 0.17.17
- '@esbuild/darwin-arm64': 0.17.17
- '@esbuild/darwin-x64': 0.17.17
- '@esbuild/freebsd-arm64': 0.17.17
- '@esbuild/freebsd-x64': 0.17.17
- '@esbuild/linux-arm': 0.17.17
- '@esbuild/linux-arm64': 0.17.17
- '@esbuild/linux-ia32': 0.17.17
- '@esbuild/linux-loong64': 0.17.17
- '@esbuild/linux-mips64el': 0.17.17
- '@esbuild/linux-ppc64': 0.17.17
- '@esbuild/linux-riscv64': 0.17.17
- '@esbuild/linux-s390x': 0.17.17
- '@esbuild/linux-x64': 0.17.17
- '@esbuild/netbsd-x64': 0.17.17
- '@esbuild/openbsd-x64': 0.17.17
- '@esbuild/sunos-x64': 0.17.17
- '@esbuild/win32-arm64': 0.17.17
- '@esbuild/win32-ia32': 0.17.17
- '@esbuild/win32-x64': 0.17.17
- dev: true
-
- /esbuild@0.21.5:
- resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
+ esbuild@0.25.11:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.21.5
- '@esbuild/android-arm': 0.21.5
- '@esbuild/android-arm64': 0.21.5
- '@esbuild/android-x64': 0.21.5
- '@esbuild/darwin-arm64': 0.21.5
- '@esbuild/darwin-x64': 0.21.5
- '@esbuild/freebsd-arm64': 0.21.5
- '@esbuild/freebsd-x64': 0.21.5
- '@esbuild/linux-arm': 0.21.5
- '@esbuild/linux-arm64': 0.21.5
- '@esbuild/linux-ia32': 0.21.5
- '@esbuild/linux-loong64': 0.21.5
- '@esbuild/linux-mips64el': 0.21.5
- '@esbuild/linux-ppc64': 0.21.5
- '@esbuild/linux-riscv64': 0.21.5
- '@esbuild/linux-s390x': 0.21.5
- '@esbuild/linux-x64': 0.21.5
- '@esbuild/netbsd-x64': 0.21.5
- '@esbuild/openbsd-x64': 0.21.5
- '@esbuild/sunos-x64': 0.21.5
- '@esbuild/win32-arm64': 0.21.5
- '@esbuild/win32-ia32': 0.21.5
- '@esbuild/win32-x64': 0.21.5
- dev: true
-
- /escalade@3.1.1:
- resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
- engines: {node: '>=6'}
- dev: true
-
- /escalade@3.1.2:
- resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
- engines: {node: '>=6'}
- dev: true
-
- /escape-string-regexp@1.0.5:
- resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
- engines: {node: '>=0.8.0'}
- dev: true
-
- /escape-string-regexp@2.0.0:
- resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
- engines: {node: '>=8'}
- dev: true
-
- /escodegen@2.0.0:
- resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==}
- engines: {node: '>=6.0'}
- hasBin: true
+ '@esbuild/aix-ppc64': 0.25.11
+ '@esbuild/android-arm': 0.25.11
+ '@esbuild/android-arm64': 0.25.11
+ '@esbuild/android-x64': 0.25.11
+ '@esbuild/darwin-arm64': 0.25.11
+ '@esbuild/darwin-x64': 0.25.11
+ '@esbuild/freebsd-arm64': 0.25.11
+ '@esbuild/freebsd-x64': 0.25.11
+ '@esbuild/linux-arm': 0.25.11
+ '@esbuild/linux-arm64': 0.25.11
+ '@esbuild/linux-ia32': 0.25.11
+ '@esbuild/linux-loong64': 0.25.11
+ '@esbuild/linux-mips64el': 0.25.11
+ '@esbuild/linux-ppc64': 0.25.11
+ '@esbuild/linux-riscv64': 0.25.11
+ '@esbuild/linux-s390x': 0.25.11
+ '@esbuild/linux-x64': 0.25.11
+ '@esbuild/netbsd-arm64': 0.25.11
+ '@esbuild/netbsd-x64': 0.25.11
+ '@esbuild/openbsd-arm64': 0.25.11
+ '@esbuild/openbsd-x64': 0.25.11
+ '@esbuild/openharmony-arm64': 0.25.11
+ '@esbuild/sunos-x64': 0.25.11
+ '@esbuild/win32-arm64': 0.25.11
+ '@esbuild/win32-ia32': 0.25.11
+ '@esbuild/win32-x64': 0.25.11
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@2.0.0: {}
+
+ escodegen@2.1.0:
dependencies:
esprima: 4.0.1
estraverse: 5.3.0
esutils: 2.0.3
- optionator: 0.8.3
optionalDependencies:
source-map: 0.6.1
- dev: true
- /esprima@4.0.1:
- resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
- engines: {node: '>=4'}
- hasBin: true
- dev: true
+ esprima@4.0.1: {}
- /estraverse@5.3.0:
- resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
- engines: {node: '>=4.0'}
- dev: true
+ estraverse@5.3.0: {}
- /estree-walker@3.0.3:
- resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ estree-walker@3.0.3:
dependencies:
- '@types/estree': 1.0.5
- dev: true
+ '@types/estree': 1.0.8
- /esutils@2.0.3:
- resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
- engines: {node: '>=0.10.0'}
- dev: true
+ esutils@2.0.3: {}
- /execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
- dependencies:
- cross-spawn: 7.0.3
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
- dev: true
-
- /execa@8.0.1:
- resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
- engines: {node: '>=16.17'}
- dependencies:
- cross-spawn: 7.0.3
- get-stream: 8.0.1
- human-signals: 5.0.0
- is-stream: 3.0.0
- merge-stream: 2.0.0
- npm-run-path: 5.3.0
- onetime: 6.0.0
- signal-exit: 4.1.0
- strip-final-newline: 3.0.0
- dev: true
+ expect-type@1.2.2: {}
- /expect@29.5.0:
- resolution: {integrity: sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ expect@30.2.0:
dependencies:
- '@jest/expect-utils': 29.5.0
- jest-get-type: 29.4.3
- jest-matcher-utils: 29.5.0
- jest-message-util: 29.5.0
- jest-util: 29.5.0
- dev: true
-
- /extendable-error@0.1.7:
- resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==}
- dev: true
+ '@jest/expect-utils': 30.2.0
+ '@jest/get-type': 30.1.0
+ jest-matcher-utils: 30.2.0
+ jest-message-util: 30.2.0
+ jest-mock: 30.2.0
+ jest-util: 30.2.0
- /external-editor@3.1.0:
- resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
- engines: {node: '>=4'}
- dependencies:
- chardet: 0.7.0
- iconv-lite: 0.4.24
- tmp: 0.0.33
- dev: true
+ extendable-error@0.1.7: {}
- /fast-glob@3.2.12:
- resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
- engines: {node: '>=8.6.0'}
+ fast-glob@3.3.3:
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
- micromatch: 4.0.5
- dev: true
+ micromatch: 4.0.8
- /fast-levenshtein@2.0.6:
- resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
- dev: true
-
- /fastq@1.15.0:
- resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+ fastq@1.19.1:
dependencies:
- reusify: 1.0.4
- dev: true
+ reusify: 1.1.0
- /fill-range@7.1.1:
- resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
- engines: {node: '>=8'}
+ fdir@6.5.0(picomatch@4.0.3):
+ optionalDependencies:
+ picomatch: 4.0.3
+
+ fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
- dev: true
- /find-up@4.1.0:
- resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
- engines: {node: '>=8'}
+ find-up@4.1.0:
dependencies:
locate-path: 5.0.0
path-exists: 4.0.0
- dev: true
-
- /find-up@5.0.0:
- resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
- engines: {node: '>=10'}
- dependencies:
- locate-path: 6.0.0
- path-exists: 4.0.0
- dev: true
-
- /find-yarn-workspace-root2@1.2.16:
- resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==}
- dependencies:
- micromatch: 4.0.5
- pkg-dir: 4.2.0
- dev: true
- /for-each@0.3.3:
- resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+ for-each@0.3.5:
dependencies:
is-callable: 1.2.7
- dev: true
- /foreground-child@3.2.1:
- resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==}
- engines: {node: '>=14'}
+ foreground-child@3.3.1:
dependencies:
- cross-spawn: 7.0.3
+ cross-spawn: 7.0.6
signal-exit: 4.1.0
- dev: true
- /form-data@4.0.0:
- resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
- engines: {node: '>= 6'}
+ form-data@4.0.4:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
mime-types: 2.1.35
- dev: true
- /fs-extra@7.0.1:
- resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
- engines: {node: '>=6 <7 || >=8'}
+ fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
- dev: true
- /fs-extra@8.1.0:
- resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
- engines: {node: '>=6 <7 || >=8'}
+ fs-extra@8.1.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 4.0.0
universalify: 0.1.2
- dev: true
-
- /fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- dev: true
- /fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
- requiresBuild: true
- dev: true
+ fsevents@2.3.3:
optional: true
- /function-bind@1.1.1:
- resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
- dev: true
-
- /function.prototype.name@1.1.5:
- resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.21.2
- functions-have-names: 1.2.3
- dev: true
-
- /functions-have-names@1.2.3:
- resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
- dev: true
-
- /gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
- dev: true
+ function-bind@1.1.2: {}
- /get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
- dev: true
+ functions-have-names@1.2.3: {}
- /get-func-name@2.0.2:
- resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
- dev: true
+ gensync@1.0.0-beta.2: {}
- /get-intrinsic@1.2.0:
- resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
+ get-intrinsic@1.3.0:
dependencies:
- function-bind: 1.1.1
- has: 1.0.3
- has-symbols: 1.0.3
- dev: true
-
- /get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
- dev: true
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
- /get-stream@8.0.1:
- resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
- engines: {node: '>=16'}
- dev: true
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
- /get-symbol-description@1.0.0:
- resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
- engines: {node: '>= 0.4'}
+ get-tsconfig@4.13.0:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- dev: true
+ resolve-pkg-maps: 1.0.0
- /glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
+ glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
- dev: true
- /glob@10.4.5:
- resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
- hasBin: true
+ glob@10.4.5:
dependencies:
- foreground-child: 3.2.1
+ foreground-child: 3.3.1
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
- package-json-from-dist: 1.0.0
+ package-json-from-dist: 1.0.1
path-scurry: 1.11.1
- dev: true
-
- /glob@7.1.6:
- resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
- dev: true
-
- /globals@11.12.0:
- resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
- engines: {node: '>=4'}
- dev: true
-
- /globalthis@1.0.3:
- resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
- engines: {node: '>= 0.4'}
- dependencies:
- define-properties: 1.2.0
- dev: true
- /globby@11.1.0:
- resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
- engines: {node: '>=10'}
+ globby@11.1.0:
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
- fast-glob: 3.2.12
- ignore: 5.2.4
+ fast-glob: 3.3.3
+ ignore: 5.3.2
merge2: 1.4.1
slash: 3.0.0
- dev: true
- /gopd@1.0.1:
- resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
- dependencies:
- get-intrinsic: 1.2.0
- dev: true
-
- /graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
- dev: true
-
- /grapheme-splitter@1.0.4:
- resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
- dev: true
+ gopd@1.2.0: {}
- /hard-rejection@2.1.0:
- resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
- engines: {node: '>=6'}
- dev: true
-
- /has-bigints@1.0.2:
- resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
- dev: true
+ graceful-fs@4.2.11: {}
- /has-flag@3.0.0:
- resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
- engines: {node: '>=4'}
- dev: true
+ has-bigints@1.1.0: {}
- /has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
- dev: true
+ has-flag@4.0.0: {}
- /has-property-descriptors@1.0.0:
- resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+ has-property-descriptors@1.0.2:
dependencies:
- get-intrinsic: 1.2.0
- dev: true
-
- /has-proto@1.0.1:
- resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
- engines: {node: '>= 0.4'}
- dev: true
+ es-define-property: 1.0.1
- /has-symbols@1.0.3:
- resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
- engines: {node: '>= 0.4'}
- dev: true
+ has-symbols@1.1.0: {}
- /has-tostringtag@1.0.0:
- resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
- engines: {node: '>= 0.4'}
+ has-tostringtag@1.0.2:
dependencies:
- has-symbols: 1.0.3
- dev: true
+ has-symbols: 1.1.0
- /has@1.0.3:
- resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
- engines: {node: '>= 0.4.0'}
+ hasown@2.0.2:
dependencies:
- function-bind: 1.1.1
- dev: true
+ function-bind: 1.1.2
- /hosted-git-info@2.8.9:
- resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
- dev: true
+ hookable@5.5.3: {}
- /html-encoding-sniffer@3.0.0:
- resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
- engines: {node: '>=12'}
+ html-encoding-sniffer@3.0.0:
dependencies:
whatwg-encoding: 2.0.0
- dev: true
- /html-escaper@2.0.2:
- resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
- dev: true
+ html-escaper@2.0.2: {}
- /http-proxy-agent@5.0.0:
- resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
- engines: {node: '>= 6'}
+ http-proxy-agent@5.0.0:
dependencies:
'@tootallnate/once': 2.0.0
agent-base: 6.0.2
- debug: 4.3.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
- dev: true
- /https-proxy-agent@5.0.1:
- resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
- engines: {node: '>= 6'}
+ https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
- debug: 4.3.4
+ debug: 4.4.3
transitivePeerDependencies:
- supports-color
- dev: true
- /human-id@1.0.2:
- resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==}
- dev: true
+ human-id@4.1.2: {}
- /human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
- dev: true
-
- /human-signals@5.0.0:
- resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
- engines: {node: '>=16.17.0'}
- dev: true
-
- /iconv-lite@0.4.24:
- resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
- engines: {node: '>=0.10.0'}
+ iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
- dev: true
- /iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
+ iconv-lite@0.7.0:
dependencies:
safer-buffer: 2.1.2
- dev: true
-
- /ignore@5.2.4:
- resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
- engines: {node: '>= 4'}
- dev: true
-
- /indent-string@4.0.0:
- resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
- engines: {node: '>=8'}
- dev: true
- /inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
- dev: true
+ ignore@5.3.2: {}
- /inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- dev: true
+ import-without-cache@0.2.3: {}
- /internal-slot@1.0.5:
- resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
- engines: {node: '>= 0.4'}
- dependencies:
- get-intrinsic: 1.2.0
- has: 1.0.3
- side-channel: 1.0.4
- dev: true
+ indent-string@4.0.0: {}
- /is-arguments@1.1.1:
- resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
- engines: {node: '>= 0.4'}
+ internal-slot@1.1.0:
dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
- dev: true
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.1.0
- /is-array-buffer@3.0.2:
- resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+ is-arguments@1.2.0:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- is-typed-array: 1.1.10
- dev: true
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- /is-arrayish@0.2.1:
- resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
- dev: true
-
- /is-bigint@1.0.4:
- resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+ is-array-buffer@3.0.5:
dependencies:
- has-bigints: 1.0.2
- dev: true
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
- /is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
+ is-bigint@1.1.0:
dependencies:
- binary-extensions: 2.2.0
- dev: true
+ has-bigints: 1.1.0
- /is-boolean-object@1.1.2:
- resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
- engines: {node: '>= 0.4'}
+ is-binary-path@2.1.0:
dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
- dev: true
-
- /is-callable@1.2.7:
- resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
- engines: {node: '>= 0.4'}
- dev: true
+ binary-extensions: 2.3.0
- /is-ci@3.0.1:
- resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
- hasBin: true
+ is-boolean-object@1.2.2:
dependencies:
- ci-info: 3.8.0
- dev: true
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- /is-core-module@2.12.0:
- resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==}
- dependencies:
- has: 1.0.3
- dev: true
+ is-callable@1.2.7: {}
- /is-date-object@1.0.5:
- resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
- engines: {node: '>= 0.4'}
+ is-date-object@1.1.0:
dependencies:
- has-tostringtag: 1.0.0
- dev: true
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- /is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
- dev: true
+ is-extglob@2.1.1: {}
- /is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
- dev: true
+ is-fullwidth-code-point@3.0.0: {}
- /is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
+ is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
- dev: true
- /is-map@2.0.2:
- resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
- dev: true
-
- /is-negative-zero@2.0.2:
- resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
- engines: {node: '>= 0.4'}
- dev: true
+ is-map@2.0.3: {}
- /is-number-object@1.0.7:
- resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
- engines: {node: '>= 0.4'}
+ is-number-object@1.1.1:
dependencies:
- has-tostringtag: 1.0.0
- dev: true
-
- /is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
- dev: true
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- /is-plain-obj@1.1.0:
- resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
- engines: {node: '>=0.10.0'}
- dev: true
+ is-number@7.0.0: {}
- /is-potential-custom-element-name@1.0.1:
- resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
- dev: true
+ is-potential-custom-element-name@1.0.1: {}
- /is-regex@1.1.4:
- resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
- engines: {node: '>= 0.4'}
+ is-regex@1.2.1:
dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
- dev: true
+ call-bound: 1.0.4
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
- /is-set@2.0.2:
- resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
- dev: true
+ is-set@2.0.3: {}
- /is-shared-array-buffer@1.0.2:
- resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+ is-shared-array-buffer@1.0.4:
dependencies:
- call-bind: 1.0.2
- dev: true
-
- /is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
- dev: true
-
- /is-stream@3.0.0:
- resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dev: true
+ call-bound: 1.0.4
- /is-string@1.0.7:
- resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
- engines: {node: '>= 0.4'}
+ is-string@1.1.1:
dependencies:
- has-tostringtag: 1.0.0
- dev: true
+ call-bound: 1.0.4
+ has-tostringtag: 1.0.2
- /is-subdir@1.2.0:
- resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==}
- engines: {node: '>=4'}
+ is-subdir@1.2.0:
dependencies:
better-path-resolve: 1.0.0
- dev: true
-
- /is-symbol@1.0.4:
- resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
- engines: {node: '>= 0.4'}
- dependencies:
- has-symbols: 1.0.3
- dev: true
- /is-typed-array@1.1.10:
- resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
- engines: {node: '>= 0.4'}
+ is-symbol@1.1.1:
dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- for-each: 0.3.3
- gopd: 1.0.1
- has-tostringtag: 1.0.0
- dev: true
-
- /is-weakmap@2.0.1:
- resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==}
- dev: true
+ call-bound: 1.0.4
+ has-symbols: 1.1.0
+ safe-regex-test: 1.1.0
- /is-weakref@1.0.2:
- resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
- dependencies:
- call-bind: 1.0.2
- dev: true
+ is-weakmap@2.0.2: {}
- /is-weakset@2.0.2:
- resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==}
+ is-weakset@2.0.4:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- dev: true
+ call-bound: 1.0.4
+ get-intrinsic: 1.3.0
- /is-windows@1.0.2:
- resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
- engines: {node: '>=0.10.0'}
- dev: true
+ is-windows@1.0.2: {}
- /isarray@2.0.5:
- resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
- dev: true
+ isarray@2.0.5: {}
- /isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- dev: true
+ isexe@2.0.0: {}
- /istanbul-lib-coverage@3.2.2:
- resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
- engines: {node: '>=8'}
- dev: true
+ istanbul-lib-coverage@3.2.2: {}
- /istanbul-lib-instrument@6.0.3:
- resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
- engines: {node: '>=10'}
+ istanbul-lib-instrument@6.0.3:
dependencies:
- '@babel/core': 7.24.9
- '@babel/parser': 7.24.8
+ '@babel/core': 7.28.4
+ '@babel/parser': 7.28.4
'@istanbuljs/schema': 0.1.3
istanbul-lib-coverage: 3.2.2
- semver: 7.6.2
+ semver: 7.7.3
transitivePeerDependencies:
- supports-color
- dev: true
- /istanbul-lib-report@3.0.1:
- resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
- engines: {node: '>=10'}
+ istanbul-lib-report@3.0.1:
dependencies:
istanbul-lib-coverage: 3.2.2
make-dir: 4.0.0
supports-color: 7.2.0
- dev: true
- /istanbul-lib-source-maps@5.0.6:
- resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
- engines: {node: '>=10'}
+ istanbul-lib-source-maps@5.0.6:
dependencies:
- '@jridgewell/trace-mapping': 0.3.25
- debug: 4.3.5
+ '@jridgewell/trace-mapping': 0.3.31
+ debug: 4.4.3
istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
- supports-color
- dev: true
- /istanbul-reports@3.1.7:
- resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
- engines: {node: '>=8'}
+ istanbul-reports@3.2.0:
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.1
- dev: true
- /jackspeak@3.4.3:
- resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+ jackspeak@3.4.3:
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- dev: true
- /jest-diff@29.5.0:
- resolution: {integrity: sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-diff@30.2.0:
dependencies:
+ '@jest/diff-sequences': 30.0.1
+ '@jest/get-type': 30.1.0
chalk: 4.1.2
- diff-sequences: 29.4.3
- jest-get-type: 29.4.3
- pretty-format: 29.5.0
- dev: true
-
- /jest-get-type@29.4.3:
- resolution: {integrity: sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dev: true
+ pretty-format: 30.2.0
- /jest-matcher-utils@29.5.0:
- resolution: {integrity: sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-matcher-utils@30.2.0:
dependencies:
+ '@jest/get-type': 30.1.0
chalk: 4.1.2
- jest-diff: 29.5.0
- jest-get-type: 29.4.3
- pretty-format: 29.5.0
- dev: true
-
- /jest-message-util@29.5.0:
- resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- dependencies:
- '@babel/code-frame': 7.21.4
- '@jest/types': 29.5.0
- '@types/stack-utils': 2.0.1
+ jest-diff: 30.2.0
+ pretty-format: 30.2.0
+
+ jest-message-util@30.2.0:
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@jest/types': 30.2.0
+ '@types/stack-utils': 2.0.3
chalk: 4.1.2
graceful-fs: 4.2.11
- micromatch: 4.0.5
- pretty-format: 29.5.0
+ micromatch: 4.0.8
+ pretty-format: 30.2.0
slash: 3.0.0
stack-utils: 2.0.6
- dev: true
- /jest-util@29.5.0:
- resolution: {integrity: sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-mock@30.2.0:
dependencies:
- '@jest/types': 29.5.0
- '@types/node': 18.15.13
+ '@jest/types': 30.2.0
+ '@types/node': 22.18.11
+ jest-util: 30.2.0
+
+ jest-regex-util@30.0.1: {}
+
+ jest-util@30.2.0:
+ dependencies:
+ '@jest/types': 30.2.0
+ '@types/node': 22.18.11
chalk: 4.1.2
- ci-info: 3.8.0
+ ci-info: 4.3.1
graceful-fs: 4.2.11
- picomatch: 2.3.1
- dev: true
+ picomatch: 4.0.3
- /joycon@3.1.1:
- resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
- engines: {node: '>=10'}
- dev: true
+ js-tokens@4.0.0: {}
- /js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-tokens@9.0.1: {}
- /js-yaml@3.14.1:
- resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
- hasBin: true
+ js-yaml@3.14.1:
dependencies:
argparse: 1.0.10
esprima: 4.0.1
- dev: true
- /jsdom@21.1.1:
- resolution: {integrity: sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==}
- engines: {node: '>=14'}
- peerDependencies:
- canvas: ^2.5.0
- peerDependenciesMeta:
- canvas:
- optional: true
+ jsdom@21.1.2:
dependencies:
abab: 2.0.6
- acorn: 8.8.2
+ acorn: 8.15.0
acorn-globals: 7.0.1
cssstyle: 3.0.0
data-urls: 4.0.0
- decimal.js: 10.4.3
+ decimal.js: 10.6.0
domexception: 4.0.0
- escodegen: 2.0.0
- form-data: 4.0.0
+ escodegen: 2.1.0
+ form-data: 4.0.4
html-encoding-sniffer: 3.0.0
http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.1
is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.4
- parse5: 7.1.2
+ nwsapi: 2.2.22
+ parse5: 7.3.0
rrweb-cssom: 0.6.0
saxes: 6.0.0
symbol-tree: 3.2.4
- tough-cookie: 4.1.4
+ tough-cookie: 6.0.0
w3c-xmlserializer: 4.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 2.0.0
whatwg-mimetype: 3.0.0
whatwg-url: 12.0.1
- ws: 8.18.0
+ ws: 8.18.3
xml-name-validator: 4.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
- dev: true
-
- /jsesc@2.5.2:
- resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
- engines: {node: '>=4'}
- hasBin: true
- dev: true
- /json-parse-even-better-errors@2.3.1:
- resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
- dev: true
+ jsesc@3.1.0: {}
- /json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
- dev: true
+ json5@2.2.3: {}
- /jsonfile@4.0.0:
- resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+ jsonfile@4.0.0:
optionalDependencies:
graceful-fs: 4.2.11
- dev: true
-
- /kind-of@6.0.3:
- resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /kleur@4.1.5:
- resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
- engines: {node: '>=6'}
- dev: true
-
- /levn@0.3.0:
- resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}
- engines: {node: '>= 0.8.0'}
- dependencies:
- prelude-ls: 1.1.2
- type-check: 0.3.2
- dev: true
-
- /lilconfig@2.1.0:
- resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
- engines: {node: '>=10'}
- dev: true
-
- /lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- dev: true
-
- /load-tsconfig@0.2.5:
- resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dev: true
- /load-yaml-file@0.2.0:
- resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==}
- engines: {node: '>=6'}
- dependencies:
- graceful-fs: 4.2.11
- js-yaml: 3.14.1
- pify: 4.0.1
- strip-bom: 3.0.0
- dev: true
+ lilconfig@2.1.0: {}
- /locate-path@5.0.0:
- resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
- engines: {node: '>=8'}
+ locate-path@5.0.0:
dependencies:
p-locate: 4.1.0
- dev: true
- /locate-path@6.0.0:
- resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
- engines: {node: '>=10'}
- dependencies:
- p-locate: 5.0.0
- dev: true
-
- /lodash.sortby@4.7.0:
- resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
- dev: true
-
- /lodash.startcase@4.4.0:
- resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
- dev: true
+ lodash.startcase@4.4.0: {}
- /lodash@4.17.21:
- resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- dev: true
+ lodash@4.17.21: {}
- /loose-envify@1.4.0:
- resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
- hasBin: true
+ loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
- /loupe@3.1.1:
- resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
- dependencies:
- get-func-name: 2.0.2
- dev: true
+ loupe@3.2.1: {}
- /lru-cache@10.4.3:
- resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- dev: true
+ lru-cache@10.4.3: {}
- /lru-cache@4.1.5:
- resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
+ lru-cache@5.1.1:
dependencies:
- pseudomap: 1.0.2
- yallist: 2.1.2
- dev: true
+ yallist: 3.1.1
- /lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lru-cache@6.0.0:
dependencies:
- yallist: 3.1.1
- dev: true
+ yallist: 4.0.0
- /lz-string@1.5.0:
- resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
- hasBin: true
- dev: true
+ lz-string@1.5.0: {}
- /magic-string@0.30.10:
- resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+ magic-string@0.30.19:
dependencies:
- '@jridgewell/sourcemap-codec': 1.4.15
- dev: true
+ '@jridgewell/sourcemap-codec': 1.5.5
- /magicast@0.3.4:
- resolution: {integrity: sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==}
+ magic-string@0.30.21:
dependencies:
- '@babel/parser': 7.24.8
- '@babel/types': 7.24.9
- source-map-js: 1.2.0
- dev: true
+ '@jridgewell/sourcemap-codec': 1.5.5
- /make-dir@4.0.0:
- resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
- engines: {node: '>=10'}
+ magicast@0.3.5:
dependencies:
- semver: 7.6.2
- dev: true
-
- /make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
- dev: true
-
- /map-obj@1.0.1:
- resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /map-obj@4.3.0:
- resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
- engines: {node: '>=8'}
- dev: true
+ '@babel/parser': 7.28.4
+ '@babel/types': 7.28.4
+ source-map-js: 1.2.1
- /meow@6.1.1:
- resolution: {integrity: sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==}
- engines: {node: '>=8'}
+ make-dir@4.0.0:
dependencies:
- '@types/minimist': 1.2.2
- camelcase-keys: 6.2.2
- decamelize-keys: 1.1.1
- hard-rejection: 2.1.0
- minimist-options: 4.1.0
- normalize-package-data: 2.5.0
- read-pkg-up: 7.0.1
- redent: 3.0.0
- trim-newlines: 3.0.1
- type-fest: 0.13.1
- yargs-parser: 18.1.3
- dev: true
+ semver: 7.7.3
- /merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
- dev: true
+ make-error@1.3.6: {}
- /merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
- dev: true
+ math-intrinsics@1.1.0: {}
- /micromatch@4.0.5:
- resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
- engines: {node: '>=8.6'}
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
dependencies:
braces: 3.0.3
picomatch: 2.3.1
- dev: true
- /mime-db@1.52.0:
- resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
- engines: {node: '>= 0.6'}
- dev: true
+ mime-db@1.52.0: {}
- /mime-types@2.1.35:
- resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
- engines: {node: '>= 0.6'}
+ mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
- dev: true
-
- /mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
- dev: true
-
- /mimic-fn@4.0.0:
- resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
- engines: {node: '>=12'}
- dev: true
-
- /min-indent@1.0.1:
- resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
- engines: {node: '>=4'}
- dev: true
- /minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
- dependencies:
- brace-expansion: 1.1.11
- dev: true
-
- /minimatch@9.0.5:
- resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
- engines: {node: '>=16 || 14 >=14.17'}
- dependencies:
- brace-expansion: 2.0.1
- dev: true
-
- /minimist-options@4.1.0:
- resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
- engines: {node: '>= 6'}
- dependencies:
- arrify: 1.0.1
- is-plain-obj: 1.1.0
- kind-of: 6.0.3
- dev: true
+ min-indent@1.0.1: {}
- /minipass@7.1.2:
- resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
- engines: {node: '>=16 || 14 >=14.17'}
- dev: true
-
- /mixme@0.5.9:
- resolution: {integrity: sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==}
- engines: {node: '>= 8.0.0'}
- dev: true
-
- /ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
- dev: true
-
- /mz@2.7.0:
- resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ minimatch@9.0.5:
dependencies:
- any-promise: 1.3.0
- object-assign: 4.1.1
- thenify-all: 1.6.0
- dev: true
-
- /nanoid@3.3.6:
- resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
- dev: true
+ brace-expansion: 4.0.1
- /nanoid@3.3.7:
- resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
- dev: true
+ minipass@7.1.2: {}
- /nanospinner@1.1.0:
- resolution: {integrity: sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==}
- dependencies:
- picocolors: 1.0.0
- dev: true
+ mri@1.2.0: {}
- /node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
- dev: true
+ ms@2.1.3: {}
- /normalize-package-data@2.5.0:
- resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
- dependencies:
- hosted-git-info: 2.8.9
- resolve: 1.22.2
- semver: 7.6.2
- validate-npm-package-license: 3.0.4
- dev: true
+ nanoid@3.3.11: {}
- /normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
- dev: true
+ nanoid@5.1.6: {}
- /npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
+ nanospinner@1.2.2:
dependencies:
- path-key: 3.1.1
- dev: true
+ picocolors: 1.1.1
- /npm-run-path@5.3.0:
- resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dependencies:
- path-key: 4.0.0
- dev: true
+ node-releases@2.0.25: {}
- /nwsapi@2.2.4:
- resolution: {integrity: sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==}
- dev: true
+ normalize-path@3.0.0: {}
- /object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
- dev: true
+ nwsapi@2.2.22: {}
- /object-inspect@1.12.3:
- resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
- dev: true
+ object-inspect@1.13.4: {}
- /object-is@1.1.5:
- resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
- engines: {node: '>= 0.4'}
+ object-is@1.1.6:
dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- dev: true
+ call-bind: 1.0.8
+ define-properties: 1.2.1
- /object-keys@1.1.1:
- resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
- engines: {node: '>= 0.4'}
- dev: true
+ object-keys@1.1.1: {}
- /object.assign@4.1.4:
- resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
- engines: {node: '>= 0.4'}
+ object.assign@4.1.7:
dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- has-symbols: 1.0.3
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ define-properties: 1.2.1
+ es-object-atoms: 1.1.1
+ has-symbols: 1.1.0
object-keys: 1.1.1
- dev: true
-
- /once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
- dependencies:
- wrappy: 1.0.2
- dev: true
- /onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
- dependencies:
- mimic-fn: 2.1.0
- dev: true
-
- /onetime@6.0.0:
- resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
- engines: {node: '>=12'}
- dependencies:
- mimic-fn: 4.0.0
- dev: true
-
- /optionator@0.8.3:
- resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}
- engines: {node: '>= 0.8.0'}
- dependencies:
- deep-is: 0.1.4
- fast-levenshtein: 2.0.6
- levn: 0.3.0
- prelude-ls: 1.1.2
- type-check: 0.3.2
- word-wrap: 1.2.5
- dev: true
-
- /os-tmpdir@1.0.2:
- resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
- engines: {node: '>=0.10.0'}
- dev: true
+ obug@2.1.1: {}
- /outdent@0.5.0:
- resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==}
- dev: true
+ outdent@0.5.0: {}
- /p-filter@2.1.0:
- resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
- engines: {node: '>=8'}
+ p-filter@2.1.0:
dependencies:
p-map: 2.1.0
- dev: true
- /p-limit@2.3.0:
- resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
- engines: {node: '>=6'}
+ p-limit@2.3.0:
dependencies:
p-try: 2.2.0
- dev: true
-
- /p-limit@3.1.0:
- resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
- engines: {node: '>=10'}
- dependencies:
- yocto-queue: 0.1.0
- dev: true
- /p-locate@4.1.0:
- resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
- engines: {node: '>=8'}
+ p-locate@4.1.0:
dependencies:
p-limit: 2.3.0
- dev: true
-
- /p-locate@5.0.0:
- resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
- engines: {node: '>=10'}
- dependencies:
- p-limit: 3.1.0
- dev: true
- /p-map@2.1.0:
- resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
- engines: {node: '>=6'}
- dev: true
+ p-map@2.1.0: {}
- /p-try@2.2.0:
- resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
- engines: {node: '>=6'}
- dev: true
+ p-try@2.2.0: {}
- /package-json-from-dist@1.0.0:
- resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
- dev: true
+ package-json-from-dist@1.0.1: {}
- /parse-json@5.2.0:
- resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
- engines: {node: '>=8'}
+ package-manager-detector@0.2.11:
dependencies:
- '@babel/code-frame': 7.21.4
- error-ex: 1.3.2
- json-parse-even-better-errors: 2.3.1
- lines-and-columns: 1.2.4
- dev: true
+ quansync: 0.2.11
- /parse5@7.1.2:
- resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+ parse5@7.3.0:
dependencies:
- entities: 4.5.0
- dev: true
-
- /path-exists@4.0.0:
- resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
- engines: {node: '>=8'}
- dev: true
-
- /path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
- dev: true
+ entities: 6.0.1
- /path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
- dev: true
-
- /path-key@4.0.0:
- resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
- engines: {node: '>=12'}
- dev: true
+ path-exists@4.0.0: {}
- /path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
- dev: true
+ path-key@3.1.1: {}
- /path-scurry@1.11.1:
- resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
- engines: {node: '>=16 || 14 >=14.18'}
+ path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
minipass: 7.1.2
- dev: true
-
- /path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
- dev: true
-
- /pathe@1.1.2:
- resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
- dev: true
-
- /pathval@2.0.0:
- resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
- engines: {node: '>= 14.16'}
- dev: true
- /picocolors@1.0.0:
- resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
- dev: true
+ path-type@4.0.0: {}
- /picocolors@1.0.1:
- resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
- dev: true
+ pathe@2.0.3: {}
- /picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
- dev: true
+ pathval@2.0.1: {}
- /pify@4.0.1:
- resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
- engines: {node: '>=6'}
- dev: true
+ picocolors@1.1.1: {}
- /pirates@4.0.5:
- resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
- engines: {node: '>= 6'}
- dev: true
+ picomatch@2.3.1: {}
- /pkg-dir@4.2.0:
- resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
- engines: {node: '>=8'}
- dependencies:
- find-up: 4.1.0
- dev: true
+ picomatch@4.0.3: {}
- /postcss-load-config@3.1.4(ts-node@10.9.1):
- resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
- engines: {node: '>= 10'}
- peerDependencies:
- postcss: '>=8.0.9'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- postcss:
- optional: true
- ts-node:
- optional: true
- dependencies:
- lilconfig: 2.1.0
- ts-node: 10.9.1(@types/node@18.15.13)(typescript@5.0.4)
- yaml: 1.10.2
- dev: true
+ pify@4.0.1: {}
- /postcss@8.4.39:
- resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
- engines: {node: ^10 || ^12 || >=14}
- dependencies:
- nanoid: 3.3.7
- picocolors: 1.0.1
- source-map-js: 1.2.0
- dev: true
+ possible-typed-array-names@1.1.0: {}
- /preferred-pm@3.0.3:
- resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==}
- engines: {node: '>=10'}
+ postcss@8.5.6:
dependencies:
- find-up: 5.0.0
- find-yarn-workspace-root2: 1.2.16
- path-exists: 4.0.0
- which-pm: 2.0.0
- dev: true
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
- /prelude-ls@1.1.2:
- resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
- engines: {node: '>= 0.8.0'}
- dev: true
+ prettier@2.8.8: {}
- /prettier@2.8.7:
- resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==}
- engines: {node: '>=10.13.0'}
- hasBin: true
- dev: true
-
- /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}
+ pretty-format@27.5.1:
dependencies:
ansi-regex: 5.0.1
ansi-styles: 5.2.0
react-is: 17.0.2
- dev: true
- /pretty-format@29.5.0:
- resolution: {integrity: sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==}
- engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ pretty-format@30.2.0:
dependencies:
- '@jest/schemas': 29.4.3
+ '@jest/schemas': 30.0.5
ansi-styles: 5.2.0
- react-is: 18.2.0
- dev: true
-
- /pseudomap@1.0.2:
- resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
- dev: true
+ react-is: 18.3.1
- /psl@1.9.0:
- resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
- dev: true
-
- /punycode@2.3.0:
- resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
- engines: {node: '>=6'}
- dev: true
+ punycode@2.3.1: {}
- /querystringify@2.2.0:
- resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
- dev: true
+ quansync@0.2.11: {}
- /queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- dev: true
+ quansync@1.0.0: {}
- /quick-lru@4.0.1:
- resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
- engines: {node: '>=8'}
- dev: true
+ queue-microtask@1.2.3: {}
- /react-dom@18.2.0(react@18.2.0):
- resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
- peerDependencies:
- react: ^18.2.0
+ react-dom@18.3.1(react@18.3.1):
dependencies:
loose-envify: 1.4.0
- react: 18.2.0
- scheduler: 0.23.0
- dev: true
+ react: 18.3.1
+ scheduler: 0.23.2
- /react-is@17.0.2:
- resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
- dev: true
+ react-is@17.0.2: {}
- /react-is@18.2.0:
- resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
- dev: true
+ react-is@18.3.1: {}
- /react-refresh@0.14.2:
- resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
- engines: {node: '>=0.10.0'}
- dev: true
+ react-refresh@0.17.0: {}
- /react@18.2.0:
- resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
- engines: {node: '>=0.10.0'}
+ react@18.3.1:
dependencies:
loose-envify: 1.4.0
- /read-pkg-up@7.0.1:
- resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
- engines: {node: '>=8'}
- dependencies:
- find-up: 4.1.0
- read-pkg: 5.2.0
- type-fest: 0.8.1
- dev: true
-
- /read-pkg@5.2.0:
- resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
- engines: {node: '>=8'}
- dependencies:
- '@types/normalize-package-data': 2.4.1
- normalize-package-data: 2.5.0
- parse-json: 5.2.0
- type-fest: 0.6.0
- dev: true
-
- /read-yaml-file@1.1.0:
- resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==}
- engines: {node: '>=6'}
+ read-yaml-file@1.1.0:
dependencies:
graceful-fs: 4.2.11
js-yaml: 3.14.1
pify: 4.0.1
strip-bom: 3.0.0
- dev: true
- /readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
+ readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
- dev: true
- /redent@3.0.0:
- resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
- engines: {node: '>=8'}
+ redent@3.0.0:
dependencies:
indent-string: 4.0.0
strip-indent: 3.0.0
- dev: true
-
- /regenerator-runtime@0.13.11:
- resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
- dev: true
- /regexp.prototype.flags@1.5.0:
- resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
- engines: {node: '>= 0.4'}
+ regexp.prototype.flags@1.5.4:
dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- functions-have-names: 1.2.3
- dev: true
-
- /require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
- dev: true
+ call-bind: 1.0.8
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ set-function-name: 2.0.2
- /require-main-filename@2.0.0:
- resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
- dev: true
+ resolve-from@5.0.0: {}
- /requires-port@1.0.0:
- resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
- dev: true
+ resolve-pkg-maps@1.0.0: {}
- /resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
- dev: true
+ reusify@1.1.0: {}
- /resolve@1.22.2:
- resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
- hasBin: true
+ rolldown-plugin-dts@0.18.3(rolldown@1.0.0-beta.53)(typescript@5.9.3):
dependencies:
- is-core-module: 2.12.0
- path-parse: 1.0.7
- supports-preserve-symlinks-flag: 1.0.0
- dev: true
-
- /reusify@1.0.4:
- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- dev: true
-
- /rollup@3.20.7:
- resolution: {integrity: sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==}
- engines: {node: '>=14.18.0', npm: '>=8.0.0'}
- hasBin: true
+ '@babel/generator': 7.28.5
+ '@babel/parser': 7.28.5
+ '@babel/types': 7.28.5
+ ast-kit: 2.2.0
+ birpc: 3.0.0
+ dts-resolver: 2.1.3
+ get-tsconfig: 4.13.0
+ magic-string: 0.30.21
+ obug: 2.1.1
+ rolldown: 1.0.0-beta.53
optionalDependencies:
- fsevents: 2.3.3
- dev: true
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - oxc-resolver
- /rollup@4.18.1:
- resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==}
- engines: {node: '>=18.0.0', npm: '>=8.0.0'}
- hasBin: true
+ rolldown@1.0.0-beta.53:
dependencies:
- '@types/estree': 1.0.5
+ '@oxc-project/types': 0.101.0
+ '@rolldown/pluginutils': 1.0.0-beta.53
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.0-beta.53
+ '@rolldown/binding-darwin-arm64': 1.0.0-beta.53
+ '@rolldown/binding-darwin-x64': 1.0.0-beta.53
+ '@rolldown/binding-freebsd-x64': 1.0.0-beta.53
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53
+ '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53
+ '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53
+ '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53
+
+ rollup@4.52.5:
+ dependencies:
+ '@types/estree': 1.0.8
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.18.1
- '@rollup/rollup-android-arm64': 4.18.1
- '@rollup/rollup-darwin-arm64': 4.18.1
- '@rollup/rollup-darwin-x64': 4.18.1
- '@rollup/rollup-linux-arm-gnueabihf': 4.18.1
- '@rollup/rollup-linux-arm-musleabihf': 4.18.1
- '@rollup/rollup-linux-arm64-gnu': 4.18.1
- '@rollup/rollup-linux-arm64-musl': 4.18.1
- '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1
- '@rollup/rollup-linux-riscv64-gnu': 4.18.1
- '@rollup/rollup-linux-s390x-gnu': 4.18.1
- '@rollup/rollup-linux-x64-gnu': 4.18.1
- '@rollup/rollup-linux-x64-musl': 4.18.1
- '@rollup/rollup-win32-arm64-msvc': 4.18.1
- '@rollup/rollup-win32-ia32-msvc': 4.18.1
- '@rollup/rollup-win32-x64-msvc': 4.18.1
+ '@rollup/rollup-android-arm-eabi': 4.52.5
+ '@rollup/rollup-android-arm64': 4.52.5
+ '@rollup/rollup-darwin-arm64': 4.52.5
+ '@rollup/rollup-darwin-x64': 4.52.5
+ '@rollup/rollup-freebsd-arm64': 4.52.5
+ '@rollup/rollup-freebsd-x64': 4.52.5
+ '@rollup/rollup-linux-arm-gnueabihf': 4.52.5
+ '@rollup/rollup-linux-arm-musleabihf': 4.52.5
+ '@rollup/rollup-linux-arm64-gnu': 4.52.5
+ '@rollup/rollup-linux-arm64-musl': 4.52.5
+ '@rollup/rollup-linux-loong64-gnu': 4.52.5
+ '@rollup/rollup-linux-ppc64-gnu': 4.52.5
+ '@rollup/rollup-linux-riscv64-gnu': 4.52.5
+ '@rollup/rollup-linux-riscv64-musl': 4.52.5
+ '@rollup/rollup-linux-s390x-gnu': 4.52.5
+ '@rollup/rollup-linux-x64-gnu': 4.52.5
+ '@rollup/rollup-linux-x64-musl': 4.52.5
+ '@rollup/rollup-openharmony-arm64': 4.52.5
+ '@rollup/rollup-win32-arm64-msvc': 4.52.5
+ '@rollup/rollup-win32-ia32-msvc': 4.52.5
+ '@rollup/rollup-win32-x64-gnu': 4.52.5
+ '@rollup/rollup-win32-x64-msvc': 4.52.5
fsevents: 2.3.3
- dev: true
- /rrweb-cssom@0.6.0:
- resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
- dev: true
+ rrweb-cssom@0.6.0: {}
- /run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
- dev: true
- /safe-regex-test@1.0.0:
- resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
+ safe-regex-test@1.1.0:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- is-regex: 1.1.4
- dev: true
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ is-regex: 1.2.1
- /safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
- dev: true
+ safer-buffer@2.1.2: {}
- /saxes@6.0.0:
- resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
- engines: {node: '>=v12.22.7'}
+ saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
- dev: true
- /scheduler@0.23.0:
- resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
+ scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
- dev: true
-
- /semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
- dev: true
-
- /semver@7.6.2:
- resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
- engines: {node: '>=10'}
- hasBin: true
- dev: true
-
- /set-blocking@2.0.0:
- resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
- dev: true
- /shebang-command@1.2.0:
- resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
- engines: {node: '>=0.10.0'}
- dependencies:
- shebang-regex: 1.0.0
- dev: true
+ semver@6.3.1: {}
- /shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
+ semver@7.5.3:
dependencies:
- shebang-regex: 3.0.0
- dev: true
-
- /shebang-regex@1.0.0:
- resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
- engines: {node: '>=0.10.0'}
- dev: true
+ lru-cache: 6.0.0
- /shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
- dev: true
+ semver@7.7.3: {}
- /side-channel@1.0.4:
- resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ set-function-length@1.2.2:
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.0
- object-inspect: 1.12.3
- dev: true
-
- /siginfo@2.0.0:
- resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
- dev: true
-
- /signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
- dev: true
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.3.0
+ gopd: 1.2.0
+ has-property-descriptors: 1.0.2
- /signal-exit@4.1.0:
- resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
- engines: {node: '>=14'}
- dev: true
-
- /size-limit@8.2.4:
- resolution: {integrity: sha512-Un16nSreD1v2CYwSorattiJcHuAWqXvg4TsGgzpjnoByqQwsSfCIEQHuaD14HNStzredR8cdsO9oGH91ibypTA==}
- engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
- hasBin: true
+ set-function-name@2.0.2:
dependencies:
- bytes-iec: 3.1.1
- chokidar: 3.5.3
- globby: 11.1.0
- lilconfig: 2.1.0
- nanospinner: 1.1.0
- picocolors: 1.0.0
- dev: true
-
- /slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
- dev: true
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
- /smartwrap@2.0.2:
- resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==}
- engines: {node: '>=6'}
- hasBin: true
+ shebang-command@2.0.0:
dependencies:
- array.prototype.flat: 1.3.1
- breakword: 1.0.5
- grapheme-splitter: 1.0.4
- strip-ansi: 6.0.1
- wcwidth: 1.0.1
- yargs: 15.4.1
- dev: true
+ shebang-regex: 3.0.0
- /source-map-js@1.2.0:
- resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
- engines: {node: '>=0.10.0'}
- dev: true
+ shebang-regex@3.0.0: {}
- /source-map-support@0.5.21:
- resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+ side-channel-list@1.0.0:
dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
- dev: true
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
- /source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /source-map@0.8.0-beta.0:
- resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
- engines: {node: '>= 8'}
+ side-channel-map@1.0.1:
dependencies:
- whatwg-url: 7.1.0
- dev: true
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
- /spawndamnit@2.0.0:
- resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==}
+ side-channel-weakmap@1.0.2:
dependencies:
- cross-spawn: 5.1.0
- signal-exit: 3.0.7
- dev: true
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
- /spdx-correct@3.2.0:
- resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
+ side-channel@1.1.0:
dependencies:
- spdx-expression-parse: 3.0.1
- spdx-license-ids: 3.0.13
- dev: true
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
- /spdx-exceptions@2.3.0:
- resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
- dev: true
+ siginfo@2.0.0: {}
- /spdx-expression-parse@3.0.1:
- resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+ signal-exit@4.1.0: {}
+
+ size-limit@8.2.6:
dependencies:
- spdx-exceptions: 2.3.0
- spdx-license-ids: 3.0.13
- dev: true
+ bytes-iec: 3.1.1
+ chokidar: 3.6.0
+ globby: 11.1.0
+ lilconfig: 2.1.0
+ nanospinner: 1.2.2
+ picocolors: 1.1.1
- /spdx-license-ids@3.0.13:
- resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==}
- dev: true
+ slash@3.0.0: {}
- /sprintf-js@1.0.3:
- resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- dev: true
+ source-map-js@1.2.1: {}
- /stack-utils@2.0.6:
- resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
- engines: {node: '>=10'}
+ source-map-support@0.5.21:
dependencies:
- escape-string-regexp: 2.0.0
- dev: true
+ buffer-from: 1.1.2
+ source-map: 0.6.1
- /stackback@0.0.2:
- resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
- dev: true
+ source-map@0.6.1: {}
+
+ spawndamnit@3.0.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
- /std-env@3.7.0:
- resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
- dev: true
+ sprintf-js@1.0.3: {}
- /stop-iteration-iterator@1.0.0:
- resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
- engines: {node: '>= 0.4'}
+ stack-utils@2.0.6:
dependencies:
- internal-slot: 1.0.5
- dev: true
+ escape-string-regexp: 2.0.0
- /stream-transform@2.1.3:
- resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==}
+ stackback@0.0.2: {}
+
+ std-env@3.10.0: {}
+
+ stop-iteration-iterator@1.1.0:
dependencies:
- mixme: 0.5.9
- dev: true
+ es-errors: 1.3.0
+ internal-slot: 1.1.0
- /string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
+ string-width@4.2.3:
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
- dev: true
- /string-width@5.1.2:
- resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
- engines: {node: '>=12'}
+ string-width@5.1.2:
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
- strip-ansi: 7.1.0
- dev: true
-
- /string.prototype.trim@1.2.7:
- resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.21.2
- dev: true
-
- /string.prototype.trimend@1.0.6:
- resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.21.2
- dev: true
-
- /string.prototype.trimstart@1.0.6:
- resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.21.2
- dev: true
+ strip-ansi: 7.1.2
- /strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
+ strip-ansi@6.0.1:
dependencies:
ansi-regex: 5.0.1
- dev: true
- /strip-ansi@7.1.0:
- resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
- engines: {node: '>=12'}
+ strip-ansi@7.1.2:
dependencies:
- ansi-regex: 6.0.1
- dev: true
-
- /strip-bom@3.0.0:
- resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
- engines: {node: '>=4'}
- dev: true
-
- /strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
- dev: true
+ ansi-regex: 6.2.2
- /strip-final-newline@3.0.0:
- resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
- engines: {node: '>=12'}
- dev: true
+ strip-bom@3.0.0: {}
- /strip-indent@3.0.0:
- resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
- engines: {node: '>=8'}
+ strip-indent@3.0.0:
dependencies:
min-indent: 1.0.1
- dev: true
- /sucrase@3.32.0:
- resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==}
- engines: {node: '>=8'}
- hasBin: true
- dependencies:
- '@jridgewell/gen-mapping': 0.3.3
- commander: 4.1.1
- glob: 7.1.6
- lines-and-columns: 1.2.4
- mz: 2.7.0
- pirates: 4.0.5
- ts-interface-checker: 0.1.13
- dev: true
-
- /supports-color@5.5.0:
- resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
- engines: {node: '>=4'}
+ strip-literal@3.1.0:
dependencies:
- has-flag: 3.0.0
- dev: true
+ js-tokens: 9.0.1
- /supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
+ supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
- dev: true
-
- /supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
- dev: true
- /symbol-tree@3.2.4:
- resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
- dev: true
+ symbol-tree@3.2.4: {}
- /term-size@2.2.1:
- resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
- engines: {node: '>=8'}
- dev: true
+ term-size@2.2.1: {}
- /terser@5.17.1:
- resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==}
- engines: {node: '>=10'}
- hasBin: true
+ terser@5.44.0:
dependencies:
- '@jridgewell/source-map': 0.3.3
- acorn: 8.8.2
+ '@jridgewell/source-map': 0.3.11
+ acorn: 8.15.0
commander: 2.20.3
source-map-support: 0.5.21
- dev: true
- /test-exclude@7.0.1:
- resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
- engines: {node: '>=18'}
+ test-exclude@7.0.1:
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 10.4.5
minimatch: 9.0.5
- dev: true
- /thenify-all@1.6.0:
- resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
- engines: {node: '>=0.8'}
- dependencies:
- thenify: 3.3.1
- dev: true
+ tinybench@2.9.0: {}
- /thenify@3.3.1:
- resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
- dependencies:
- any-promise: 1.3.0
- dev: true
+ tinyexec@0.3.2: {}
- /tinybench@2.8.0:
- resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
- dev: true
+ tinyexec@1.0.2: {}
- /tinypool@1.0.0:
- resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==}
- engines: {node: ^18.0.0 || >=20.0.0}
- dev: true
+ tinyglobby@0.2.15:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
- /tinyrainbow@1.2.0:
- resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
- engines: {node: '>=14.0.0'}
- dev: true
+ tinypool@1.1.1: {}
- /tinyspy@3.0.0:
- resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==}
- engines: {node: '>=14.0.0'}
- dev: true
+ tinyrainbow@2.0.0: {}
- /tmp@0.0.33:
- resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
- engines: {node: '>=0.6.0'}
- dependencies:
- os-tmpdir: 1.0.2
- dev: true
+ tinyspy@4.0.4: {}
- /to-fast-properties@2.0.0:
- resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
- engines: {node: '>=4'}
- dev: true
+ tldts-core@7.0.17: {}
- /to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
+ tldts@7.0.17:
dependencies:
- is-number: 7.0.0
- dev: true
+ tldts-core: 7.0.17
- /tough-cookie@4.1.4:
- resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
- engines: {node: '>=6'}
+ to-regex-range@5.0.1:
dependencies:
- psl: 1.9.0
- punycode: 2.3.0
- universalify: 0.2.0
- url-parse: 1.5.10
- dev: true
+ is-number: 7.0.0
- /tr46@1.0.1:
- resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
+ tough-cookie@6.0.0:
dependencies:
- punycode: 2.3.0
- dev: true
+ tldts: 7.0.17
- /tr46@4.1.1:
- resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
- engines: {node: '>=14'}
+ tr46@4.1.1:
dependencies:
- punycode: 2.3.0
- dev: true
-
- /tree-kill@1.2.2:
- resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
- hasBin: true
- dev: true
-
- /trim-newlines@3.0.1:
- resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
- engines: {node: '>=8'}
- dev: true
+ punycode: 2.3.1
- /ts-interface-checker@0.1.13:
- resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- dev: true
+ tree-kill@1.2.2: {}
- /ts-node@10.9.1(@types/node@18.15.13)(typescript@5.0.4):
- resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
+ ts-node@10.9.2(@types/node@22.18.11)(typescript@5.9.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.9
+ '@tsconfig/node10': 1.0.11
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.3
- '@types/node': 18.15.13
- acorn: 8.8.2
- acorn-walk: 8.2.0
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 22.18.11
+ acorn: 8.15.0
+ acorn-walk: 8.3.4
arg: 4.1.3
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
- typescript: 5.0.4
+ typescript: 5.9.3
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
- dev: true
- /tsup@6.7.0(ts-node@10.9.1)(typescript@5.0.4):
- resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==}
- engines: {node: '>=14.18'}
- hasBin: true
- peerDependencies:
- '@swc/core': ^1
- postcss: ^8.4.12
- typescript: '>=4.1.0'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- postcss:
- optional: true
- typescript:
- optional: true
+ tsdown@0.17.3(typescript@5.9.3):
dependencies:
- bundle-require: 4.0.1(esbuild@0.17.17)
+ ansis: 4.2.0
cac: 6.7.14
- chokidar: 3.5.3
- debug: 4.3.4
- esbuild: 0.17.17
- execa: 5.1.1
- globby: 11.1.0
- joycon: 3.1.1
- postcss-load-config: 3.1.4(ts-node@10.9.1)
- resolve-from: 5.0.0
- rollup: 3.20.7
- source-map: 0.8.0-beta.0
- sucrase: 3.32.0
+ defu: 6.1.4
+ empathic: 2.0.0
+ hookable: 5.5.3
+ import-without-cache: 0.2.3
+ obug: 2.1.1
+ rolldown: 1.0.0-beta.53
+ rolldown-plugin-dts: 0.18.3(rolldown@1.0.0-beta.53)(typescript@5.9.3)
+ semver: 7.7.3
+ tinyexec: 1.0.2
+ tinyglobby: 0.2.15
tree-kill: 1.2.2
- typescript: 5.0.4
+ unconfig-core: 7.4.2
+ unrun: 0.2.19
+ optionalDependencies:
+ typescript: 5.9.3
transitivePeerDependencies:
- - supports-color
- - ts-node
- dev: true
-
- /tty-table@4.2.1:
- resolution: {integrity: sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==}
- engines: {node: '>=8.0.0'}
- hasBin: true
- dependencies:
- chalk: 4.1.2
- csv: 5.5.3
- kleur: 4.1.5
- smartwrap: 2.0.2
- strip-ansi: 6.0.1
- wcwidth: 1.0.1
- yargs: 17.7.1
- dev: true
-
- /type-check@0.3.2:
- resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
- engines: {node: '>= 0.8.0'}
- dependencies:
- prelude-ls: 1.1.2
- dev: true
-
- /type-fest@0.13.1:
- resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
- engines: {node: '>=10'}
- dev: true
-
- /type-fest@0.6.0:
- resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
- engines: {node: '>=8'}
- dev: true
-
- /type-fest@0.8.1:
- resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
- engines: {node: '>=8'}
- dev: true
+ - '@ts-macro/tsc'
+ - '@typescript/native-preview'
+ - oxc-resolver
+ - synckit
+ - vue-tsc
- /typed-array-length@1.0.4:
- resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
- dependencies:
- call-bind: 1.0.2
- for-each: 0.3.3
- is-typed-array: 1.1.10
- dev: true
+ tslib@2.8.1:
+ optional: true
- /typescript@5.0.4:
- resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
- engines: {node: '>=12.20'}
- hasBin: true
- dev: true
+ typescript@5.9.3: {}
- /unbox-primitive@1.0.2:
- resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+ unconfig-core@7.4.2:
dependencies:
- call-bind: 1.0.2
- has-bigints: 1.0.2
- has-symbols: 1.0.3
- which-boxed-primitive: 1.0.2
- dev: true
+ '@quansync/fs': 1.0.0
+ quansync: 1.0.0
- /universalify@0.1.2:
- resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
- engines: {node: '>= 4.0.0'}
- dev: true
+ undici-types@6.21.0: {}
- /universalify@0.2.0:
- resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
- engines: {node: '>= 4.0.0'}
- dev: true
+ universalify@0.1.2: {}
- /update-browserslist-db@1.1.0(browserslist@4.23.2):
- resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
+ unrun@0.2.19:
dependencies:
- browserslist: 4.23.2
- escalade: 3.1.2
- picocolors: 1.0.1
- dev: true
+ rolldown: 1.0.0-beta.53
- /url-parse@1.5.10:
- resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+ update-browserslist-db@1.1.3(browserslist@4.26.3):
dependencies:
- querystringify: 2.2.0
- requires-port: 1.0.0
- dev: true
+ browserslist: 4.26.3
+ escalade: 3.2.0
+ picocolors: 1.1.1
- /v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
- dev: true
-
- /validate-npm-package-license@3.0.4:
- resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
- dependencies:
- spdx-correct: 3.2.0
- spdx-expression-parse: 3.0.1
- dev: true
+ v8-compile-cache-lib@3.0.1: {}
- /vite-node@2.0.3(@types/node@18.15.13)(terser@5.17.1):
- resolution: {integrity: sha512-14jzwMx7XTcMB+9BhGQyoEAmSl0eOr3nrnn+Z12WNERtOvLN+d2scbRUvyni05rT3997Bg+rZb47NyP4IQPKXg==}
- engines: {node: ^18.0.0 || >=20.0.0}
- hasBin: true
+ vite-node@3.2.4(@types/node@22.18.11)(terser@5.44.0):
dependencies:
cac: 6.7.14
- debug: 4.3.5
- pathe: 1.1.2
- tinyrainbow: 1.2.0
- vite: 5.3.3(@types/node@18.15.13)(terser@5.17.1)
+ debug: 4.4.3
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 7.1.11(@types/node@22.18.11)(terser@5.44.0)
transitivePeerDependencies:
- '@types/node'
+ - jiti
- less
- lightningcss
- sass
+ - sass-embedded
- stylus
- sugarss
- supports-color
- terser
- dev: true
+ - tsx
+ - yaml
- /vite@5.3.3(@types/node@18.15.13)(terser@5.17.1):
- resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
- engines: {node: ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@types/node': ^18.0.0 || >=20.0.0
- less: '*'
- lightningcss: ^1.21.0
- sass: '*'
- stylus: '*'
- sugarss: '*'
- terser: ^5.4.0
- peerDependenciesMeta:
- '@types/node':
- optional: true
- less:
- optional: true
- lightningcss:
- optional: true
- sass:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
+ vite@7.1.11(@types/node@22.18.11)(terser@5.44.0):
dependencies:
- '@types/node': 18.15.13
- esbuild: 0.21.5
- postcss: 8.4.39
- rollup: 4.18.1
- terser: 5.17.1
+ esbuild: 0.25.11
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.6
+ rollup: 4.52.5
+ tinyglobby: 0.2.15
optionalDependencies:
+ '@types/node': 22.18.11
fsevents: 2.3.3
- dev: true
-
- /vitest@2.0.3(@types/node@18.15.13)(jsdom@21.1.1)(terser@5.17.1):
- resolution: {integrity: sha512-o3HRvU93q6qZK4rI2JrhKyZMMuxg/JRt30E6qeQs6ueaiz5hr1cPj+Sk2kATgQzMMqsa2DiNI0TIK++1ULx8Jw==}
- engines: {node: ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@edge-runtime/vm': '*'
- '@types/node': ^18.0.0 || >=20.0.0
- '@vitest/browser': 2.0.3
- '@vitest/ui': 2.0.3
- happy-dom: '*'
- jsdom: '*'
- peerDependenciesMeta:
- '@edge-runtime/vm':
- optional: true
- '@types/node':
- optional: true
- '@vitest/browser':
- optional: true
- '@vitest/ui':
- optional: true
- happy-dom:
- optional: true
- jsdom:
- optional: true
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@types/node': 18.15.13
- '@vitest/expect': 2.0.3
- '@vitest/pretty-format': 2.0.3
- '@vitest/runner': 2.0.3
- '@vitest/snapshot': 2.0.3
- '@vitest/spy': 2.0.3
- '@vitest/utils': 2.0.3
- chai: 5.1.1
- debug: 4.3.5
- execa: 8.0.1
- jsdom: 21.1.1
- magic-string: 0.30.10
- pathe: 1.1.2
- std-env: 3.7.0
- tinybench: 2.8.0
- tinypool: 1.0.0
- tinyrainbow: 1.2.0
- vite: 5.3.3(@types/node@18.15.13)(terser@5.17.1)
- vite-node: 2.0.3(@types/node@18.15.13)(terser@5.17.1)
- why-is-node-running: 2.2.2
+ terser: 5.44.0
+
+ vitest@3.2.4(@types/node@22.18.11)(jsdom@21.1.2)(terser@5.44.0):
+ dependencies:
+ '@types/chai': 5.2.2
+ '@vitest/expect': 3.2.4
+ '@vitest/mocker': 3.2.4(vite@7.1.11(@types/node@22.18.11)(terser@5.44.0))
+ '@vitest/pretty-format': 3.2.4
+ '@vitest/runner': 3.2.4
+ '@vitest/snapshot': 3.2.4
+ '@vitest/spy': 3.2.4
+ '@vitest/utils': 3.2.4
+ chai: 5.3.3
+ debug: 4.4.3
+ expect-type: 1.2.2
+ magic-string: 0.30.19
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ std-env: 3.10.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.15
+ tinypool: 1.1.1
+ tinyrainbow: 2.0.0
+ vite: 7.1.11(@types/node@22.18.11)(terser@5.44.0)
+ vite-node: 3.2.4(@types/node@22.18.11)(terser@5.44.0)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 22.18.11
+ jsdom: 21.1.2
transitivePeerDependencies:
+ - jiti
- less
- lightningcss
+ - msw
- sass
+ - sass-embedded
- stylus
- sugarss
- supports-color
- terser
- dev: true
+ - tsx
+ - yaml
- /w3c-xmlserializer@4.0.0:
- resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
- engines: {node: '>=14'}
+ w3c-xmlserializer@4.0.0:
dependencies:
xml-name-validator: 4.0.0
- dev: true
- /wcwidth@1.0.1:
- resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
- dependencies:
- defaults: 1.0.4
- dev: true
-
- /webidl-conversions@4.0.2:
- resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
- dev: true
-
- /webidl-conversions@7.0.0:
- resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
- engines: {node: '>=12'}
- dev: true
+ webidl-conversions@7.0.0: {}
- /whatwg-encoding@2.0.0:
- resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
- engines: {node: '>=12'}
+ whatwg-encoding@2.0.0:
dependencies:
iconv-lite: 0.6.3
- dev: true
- /whatwg-mimetype@3.0.0:
- resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
- engines: {node: '>=12'}
- dev: true
+ whatwg-mimetype@3.0.0: {}
- /whatwg-url@12.0.1:
- resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==}
- engines: {node: '>=14'}
+ whatwg-url@12.0.1:
dependencies:
tr46: 4.1.1
webidl-conversions: 7.0.0
- dev: true
-
- /whatwg-url@7.1.0:
- resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
- dependencies:
- lodash.sortby: 4.7.0
- tr46: 1.0.1
- webidl-conversions: 4.0.2
- dev: true
-
- /which-boxed-primitive@1.0.2:
- resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
- dependencies:
- is-bigint: 1.0.4
- is-boolean-object: 1.1.2
- is-number-object: 1.0.7
- is-string: 1.0.7
- is-symbol: 1.0.4
- dev: true
-
- /which-collection@1.0.1:
- resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==}
- dependencies:
- is-map: 2.0.2
- is-set: 2.0.2
- is-weakmap: 2.0.1
- is-weakset: 2.0.2
- dev: true
-
- /which-module@2.0.1:
- resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
- dev: true
- /which-pm@2.0.0:
- resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==}
- engines: {node: '>=8.15'}
+ which-boxed-primitive@1.1.1:
dependencies:
- load-yaml-file: 0.2.0
- path-exists: 4.0.0
- dev: true
+ is-bigint: 1.1.0
+ is-boolean-object: 1.2.2
+ is-number-object: 1.1.1
+ is-string: 1.1.1
+ is-symbol: 1.1.1
- /which-typed-array@1.1.9:
- resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==}
- engines: {node: '>= 0.4'}
+ which-collection@1.0.2:
dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- for-each: 0.3.3
- gopd: 1.0.1
- has-tostringtag: 1.0.0
- is-typed-array: 1.1.10
- dev: true
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-weakmap: 2.0.2
+ is-weakset: 2.0.4
- /which@1.3.1:
- resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
- hasBin: true
+ which-typed-array@1.1.19:
dependencies:
- isexe: 2.0.0
- dev: true
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.8
+ call-bound: 1.0.4
+ for-each: 0.3.5
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-tostringtag: 1.0.2
- /which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
+ which@2.0.2:
dependencies:
isexe: 2.0.0
- dev: true
- /why-is-node-running@2.2.2:
- resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
- engines: {node: '>=8'}
- hasBin: true
+ why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
- dev: true
-
- /word-wrap@1.2.5:
- resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /wrap-ansi@6.2.0:
- resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
- engines: {node: '>=8'}
- dependencies:
- ansi-styles: 4.3.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
- dev: true
- /wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
+ wrap-ansi@7.0.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
- dev: true
- /wrap-ansi@8.1.0:
- resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
- engines: {node: '>=12'}
+ wrap-ansi@8.1.0:
dependencies:
- ansi-styles: 6.2.1
+ ansi-styles: 6.2.3
string-width: 5.1.2
- strip-ansi: 7.1.0
- dev: true
-
- /wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- dev: true
-
- /ws@8.18.0:
- resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
- engines: {node: '>=10.0.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: '>=5.0.2'
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
- dev: true
-
- /xml-name-validator@4.0.0:
- resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
- engines: {node: '>=12'}
- dev: true
-
- /xmlchars@2.2.0:
- resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
- dev: true
-
- /y18n@4.0.3:
- resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
- dev: true
-
- /y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
- dev: true
-
- /yallist@2.1.2:
- resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
- dev: true
-
- /yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
- dev: true
-
- /yaml@1.10.2:
- resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
- engines: {node: '>= 6'}
- dev: true
+ strip-ansi: 7.1.2
- /yargs-parser@18.1.3:
- resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
- engines: {node: '>=6'}
- dependencies:
- camelcase: 5.3.1
- decamelize: 1.2.0
- dev: true
+ ws@8.18.3: {}
- /yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
- dev: true
+ xml-name-validator@4.0.0: {}
- /yargs@15.4.1:
- resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
- engines: {node: '>=8'}
- dependencies:
- cliui: 6.0.0
- decamelize: 1.2.0
- find-up: 4.1.0
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- require-main-filename: 2.0.0
- set-blocking: 2.0.0
- string-width: 4.2.3
- which-module: 2.0.1
- y18n: 4.0.3
- yargs-parser: 18.1.3
- dev: true
+ xmlchars@2.2.0: {}
- /yargs@17.7.1:
- resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==}
- engines: {node: '>=12'}
- dependencies:
- cliui: 8.0.1
- escalade: 3.1.1
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.1.1
- dev: true
+ yallist@3.1.1: {}
- /yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
- dev: true
+ yallist@4.0.0: {}
- /yocto-queue@0.1.0:
- resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
- engines: {node: '>=10'}
- dev: true
+ yn@3.1.1: {}
diff --git a/src/index.tsx b/src/index.tsx
index 7a25d51..d5fc4e1 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,18 +1,29 @@
import * as React from 'react'
export { useEventListener as useEventListener } from './lib/use-event-listener'
+export { default as useWindowResize } from './lib/use-window-resize'
+export { default as useOutsideClick } from './lib/use-outside-click'
+
export { default as useCopyToClipboard, copyToClipboardFn } from './lib/use-copy-to-clipboard'
export { default as useLocalStorage } from './lib/use-local-storage'
-export { default as useOutsideClick } from './lib/use-outside-click'
-export { default as useDebouncedFn, debouncedFnWrapper } from './lib/use-debounced-fn'
+
+export { useDebouncedFn, debouncedFnWrapper } from './lib/use-debounced-fn'
export { default as useThrottledFn, throttledFnWrapper } from './lib/use-throttled-fn'
-export { default as useIsOnline } from './lib/use-is-online'
+
+export { default as useCanReachToInternet } from './lib/use-can-reach-to-internet'
+export {
+ useCanReachToInternetCtx,
+ CanReachToInternetCtxProvider as CanReachToInternetProvider,
+} from './lib/use-can-reach-to-internet/can-reach-to-internet-context'
+
+export { default as useSyncedRef } from './lib/use-synced-ref'
+
export { default as useTimeoutEffect } from './lib/use-timeout-effect'
export { default as useIntervalEffect } from './lib/use-interval-effect'
-export { default as useSyncedRef } from './lib/use-synced-ref'
export { default as useSyncedEffect } from './lib/use-synced-effect'
export { default as useOnMountEffect } from './lib/use-on-mount-effect'
+
export { default as useCounter } from './lib/use-counter'
-export { default as useWindowResize } from './lib/use-window-resize'
export { default as useInterSectionObserver } from './lib/use-intersection-observer'
+export { default as useMultiIntersectionObserver } from './lib/use-multi-intersection-observer'
diff --git a/src/lib/use-can-reach-to-internet/can-reach-to-internet-context.tsx b/src/lib/use-can-reach-to-internet/can-reach-to-internet-context.tsx
new file mode 100644
index 0000000..d9edb78
--- /dev/null
+++ b/src/lib/use-can-reach-to-internet/can-reach-to-internet-context.tsx
@@ -0,0 +1,104 @@
+'use client'
+import type { ReactNode, Context } from 'react'
+
+import React, { createContext, useContext, useRef } from 'react'
+import useCanReachToInternet, { CanReachToInternetOptions } from '.'
+
+/**
+ * Type definition for the context values containing all return values from useCanReachToInternet hook
+ */
+type CtxValues = ReturnType
+
+/**
+ * React Context for sharing internet connectivity status across the component tree
+ *
+ * @description
+ * This context provides all the connectivity status and control methods from
+ * useCanReachToInternet hook to any component in the React component tree
+ * without prop drilling.
+ *
+ */
+let CanReachToInternetCtx: Context
+
+/**
+ * Props interface for the CanReachToInternetCtxProvider component
+ */
+interface CanReachToInternetCtxProviderProps extends CanReachToInternetOptions {
+ /** React children components that will have access to the connectivity context */
+ children: ReactNode
+}
+
+/**
+ * Context Provider component for internet connectivity monitoring
+ *
+ * @description
+ * This provider component wraps your application or component tree to provide
+ * internet connectivity status and controls to all child components. It uses
+ * the useCanReachToInternet hook internally and shares its values through React Context.
+ *
+ * The provider accepts all the same configuration options as the useCanReachToInternet
+ * hook, allowing you to configure network polling, test URLs, and polling intervals
+ * at the application level.
+ *
+ *
+ * @example
+ * // Basic usage - wrap your app with the provider
+ import { CanReachToInternetCtxProvider } from 'classic-react-hooks'
+
+ function App() {
+ return (
+
+
+
+
+
+ )
+ }
+ *
+ * */
+export function CanReachToInternetCtxProvider({ children, ...options }: CanReachToInternetCtxProviderProps) {
+ CanReachToInternetCtx = useRef(createContext({} as CtxValues)).current
+ const values = useCanReachToInternet(options)
+
+ return {children}
+}
+
+/**
+ * Custom hook to consume the internet connectivity context
+ *
+ * @description
+ * This hook provides access to all the internet connectivity status and control
+ * methods from the nearest CanReachToInternetCtxProvider in the component tree.
+ * It must be used within a component that is wrapped by CanReachToInternetCtxProvider,
+ * otherwise it will throw an error.
+ *
+ * The hook returns the same values as useCanReachToInternet, but accessed through
+ * React Context instead of being created locally in each component.
+ *
+ * @throws {Error} Throws an error if used outside of CanReachToInternetCtxProvider
+ *
+ * @example
+ * // Basic usage in a component
+ import { useCanReachToInternetCtx } from 'classic-react-hooks'
+
+ function NetworkStatusBadge() {
+ const { isFullyConnected, isCheckingConnection } = useCanReachToInternetCtx()
+
+ if (isCheckingConnection) {
+ return Checking...
+ }
+
+ return (
+
+ {isFullyConnected ? '🟢 Online' : '🔴 Offline'}
+
+ )
+ }
+ *
+ * */
+export function useCanReachToInternetCtx() {
+ if (!CanReachToInternetCtx) {
+ throw new Error('useCanReachToInternetCtx must be used within an CanReachToInternetCtxProvider')
+ }
+ return useContext(CanReachToInternetCtx)
+}
diff --git a/src/lib/use-can-reach-to-internet/index.test.tsx b/src/lib/use-can-reach-to-internet/index.test.tsx
new file mode 100644
index 0000000..aa8cf41
--- /dev/null
+++ b/src/lib/use-can-reach-to-internet/index.test.tsx
@@ -0,0 +1,395 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+import { renderHook, act, waitFor } from '@testing-library/react'
+import useCanReachToInternet, { type CanReachToInternetOptions } from '.'
+
+// Mock fetch
+const mockFetch = vi.fn()
+global.fetch = mockFetch
+
+// Mock navigator.onLine
+const mockNavigator = {
+ onLine: true,
+}
+Object.defineProperty(window, 'navigator', {
+ value: mockNavigator,
+ writable: true,
+})
+
+// Mock window.(add/remove)EventListener
+const mockAddEventListener = vi.fn()
+const mockRemoveEventListener = vi.fn()
+Object.defineProperty(window, 'addEventListener', {
+ value: mockAddEventListener,
+ writable: true,
+})
+Object.defineProperty(window, 'removeEventListener', {
+ value: mockRemoveEventListener,
+ writable: true,
+})
+
+describe('useCanReachToInternet', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ mockNavigator.onLine = true
+ mockFetch.mockClear()
+ })
+
+ afterEach(() => {
+ vi.useRealTimers()
+ vi.clearAllTimers()
+ })
+
+ describe('Initial state', () => {
+ it('should initialize with correct default values', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ expect(result.current.isOnline).toBe(true)
+ expect(result.current.canReachToInternet).toBe(false)
+ expect(result.current.isFullyConnected).toBe(false)
+ expect(result.current.isNetworkPollingEnabled).toBe(true)
+ expect(result.current.isCheckingConnection).toBe(true)
+ })
+
+ it('should prioritize custom options', () => {
+ const options: CanReachToInternetOptions = {
+ enableNetworkPolling: false,
+ networkPollingInterval: 5000,
+ testUrl: 'https://custom.test',
+ }
+
+ const { result } = renderHook(() => useCanReachToInternet(options))
+
+ expect(result.current.isNetworkPollingEnabled).toBe(false)
+ })
+ })
+
+ describe('Network connectivity checking', () => {
+ it('should set canReachToInternet to true when fetch succeeds', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ expect(result.current.isFullyConnected).toBe(true)
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+ })
+
+ it('should set canReachToInternet to false when fetch fails', async () => {
+ mockFetch.mockRejectedValue(new Error('Network error'))
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ expect(result.current.canReachToInternet).toBe(false)
+ })
+
+ expect(result.current.isFullyConnected).toBe(false)
+ expect(result.current.isCheckingConnection).toBe(false)
+ })
+
+ it('should use correct fetch options', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ vi.clearAllTimers()
+ expect(mockFetch).toHaveBeenCalledWith(
+ 'https://dns.google',
+ expect.objectContaining({
+ method: 'HEAD',
+ cache: 'no-cache',
+ mode: 'no-cors',
+ headers: {
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
+ Pragma: 'no-cache',
+ },
+ signal: expect.any(AbortSignal),
+ })
+ )
+ })
+ })
+
+ it('should use custom testUrl when provided', async () => {
+ mockFetch.mockResolvedValue(new Response())
+ const customUrl = 'https://custom.test'
+
+ renderHook(() => useCanReachToInternet({ testUrl: customUrl }))
+
+ expect(mockFetch).toHaveBeenCalledWith(customUrl, expect.any(Object))
+ })
+ })
+
+ describe('Network polling', () => {
+ beforeEach(() => {
+ vi.useFakeTimers()
+ })
+ afterEach(() => {
+ vi.useRealTimers()
+ })
+
+ it('should poll network at specified intervals when enabled', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ renderHook(() => useCanReachToInternet({ networkPollingInterval: 1000 }))
+
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+
+ await vi.advanceTimersByTimeAsync(1000)
+ expect(mockFetch).toHaveBeenCalledTimes(2)
+
+ await vi.advanceTimersByTimeAsync(1000)
+ expect(mockFetch).toHaveBeenCalledTimes(3)
+
+ await vi.advanceTimersByTimeAsync(3000)
+ expect(mockFetch).toHaveBeenCalledTimes(6)
+ })
+
+ it('should not poll when network polling is disabled', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+ vi.advanceTimersByTimeAsync(1000)
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+ })
+
+ it('should stop polling when stopNetworkPolling is called', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet({ networkPollingInterval: 1000 }))
+
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ result.current.stopNetworkPolling()
+ })
+ expect(result.current.isNetworkPollingEnabled).toBe(false)
+ expect(mockFetch).toHaveBeenCalledTimes(2)
+
+ vi.advanceTimersByTimeAsync(1000)
+ expect(mockFetch).toHaveBeenCalledTimes(2)
+ })
+
+ it('should start polling when startNetworkPolling is called', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+ expect(result.current.isNetworkPollingEnabled).toBe(false)
+
+ await vi.advanceTimersByTimeAsync(3000)
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ result.current.startNetworkPolling()
+ })
+
+ expect(result.current.isNetworkPollingEnabled).toBe(true)
+ expect(mockFetch).toHaveBeenCalledTimes(2)
+
+ await vi.advanceTimersByTimeAsync(3000)
+ expect(mockFetch).toHaveBeenCalledTimes(3)
+
+ await vi.advanceTimersByTimeAsync(3000)
+ expect(mockFetch).toHaveBeenCalledTimes(4)
+ })
+ })
+
+ describe('Manual network checking', () => {
+ it('should check network when forceCheckNetwork is called', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ expect(mockFetch).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ result.current.forceCheckNetwork()
+ })
+
+ expect(mockFetch).toHaveBeenCalledTimes(2)
+ })
+
+ it('should update isCheckingConnection state during manual check', async () => {
+ let resolvePromise: (value: Response) => void
+ const pendingPromise = new Promise((resolve) => {
+ resolvePromise = resolve
+ })
+ mockFetch.mockReturnValue(pendingPromise)
+
+ const { result } = renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ act(() => {
+ result.current.forceCheckNetwork()
+ })
+
+ expect(result.current.isCheckingConnection).toBe(true)
+
+ act(() => {
+ resolvePromise(new Response())
+ })
+
+ await waitFor(() => {
+ expect(result.current.isCheckingConnection).toBe(false)
+ })
+ })
+ })
+
+ describe('Browser online/offline detection', () => {
+ it('should return false for canReachToInternet when browser is offline', async () => {
+ mockNavigator.onLine = false
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ expect(result.current.isOnline).toBe(false)
+ expect(result.current.canReachToInternet).toBe(false)
+ expect(result.current.isFullyConnected).toBe(false)
+ })
+
+ // Should not make fetch call when offline
+ expect(mockFetch).not.toHaveBeenCalled()
+ })
+
+ it('should listen to online/offline events', () => {
+ renderHook(() => useCanReachToInternet())
+
+ expect(mockAddEventListener).toHaveBeenCalledWith('online', expect.any(Function))
+ expect(mockAddEventListener).toHaveBeenCalledWith('offline', expect.any(Function))
+ })
+
+ it('should update the state when online/offline events are triggered without polling enabled', async () => {
+ const { result, rerender } = renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ await waitFor(() => {
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+
+ // Should update the state when offline
+ await waitFor(() => {
+ mockNavigator.onLine = false
+ rerender()
+ expect(result.current.canReachToInternet).toBe(false)
+ })
+
+ // Should update the state when online
+ await waitFor(() => {
+ mockNavigator.onLine = true
+ rerender()
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+ })
+ })
+
+ describe('Cleanup and abort handling', () => {
+ it('should abort pending requests on unmount', async () => {
+ mockFetch.mockImplementation(() => {
+ // Never resolving the operation for aborting at unmount phase
+ return new Promise(() => {})
+ })
+
+ const { unmount } = renderHook(() => useCanReachToInternet())
+
+ expect(mockFetch).toHaveBeenCalled()
+
+ const abortSpy = vi.spyOn(AbortController.prototype, 'abort')
+
+ unmount()
+
+ expect(abortSpy).toHaveBeenCalledWith('cleanup')
+ })
+
+ it('should not update state if request was aborted', async () => {
+ const abortError = new Error('AbortError')
+ abortError.name = 'AbortError'
+
+ mockFetch.mockRejectedValue(abortError)
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ // The state should not be updated when request is aborted
+ await waitFor(() => {
+ expect(result.current.isCheckingConnection).toBe(false)
+ })
+ })
+ })
+
+ describe('getCanReachToInternetStatus method', () => {
+ it('should return current canReachToInternet status', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+
+ expect(result.current.getCanReachToInternetStatus()).toBe(true)
+ })
+
+ it('should return false when cannot reach internet', async () => {
+ mockFetch.mockRejectedValue(new Error('Network error'))
+
+ const { result } = renderHook(() => useCanReachToInternet())
+
+ await waitFor(() => {
+ expect(result.current.canReachToInternet).toBe(false)
+ })
+
+ expect(result.current.getCanReachToInternetStatus()).toBe(false)
+ })
+ })
+
+ describe('Edge cases', () => {
+ it('should handle multiple rapid calls to forceCheckNetwork', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result } = renderHook(() => useCanReachToInternet({ enableNetworkPolling: false }))
+
+ // Make multiple rapid calls
+ act(() => {
+ result.current.forceCheckNetwork()
+ result.current.forceCheckNetwork()
+ result.current.forceCheckNetwork()
+ })
+
+ await waitFor(() => {
+ expect(result.current.isCheckingConnection).toBe(false)
+ })
+
+ // Should handle gracefully without errors
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+
+ it('should handle network status changes during polling', async () => {
+ mockFetch.mockResolvedValue(new Response())
+
+ const { result, rerender } = renderHook(
+ ({ online }) => {
+ mockNavigator.onLine = online
+ return useCanReachToInternet({ networkPollingInterval: 1000 })
+ },
+ { initialProps: { online: true } }
+ )
+
+ await waitFor(() => {
+ expect(result.current.canReachToInternet).toBe(true)
+ })
+
+ // Simulate going offline
+ rerender({ online: false })
+
+ await waitFor(() => {
+ expect(result.current.isOnline).toBe(false)
+ expect(result.current.canReachToInternet).toBe(false)
+ expect(result.current.isFullyConnected).toBe(false)
+ })
+ })
+ })
+})
diff --git a/src/lib/use-can-reach-to-internet/index.tsx b/src/lib/use-can-reach-to-internet/index.tsx
new file mode 100644
index 0000000..4f2df1f
--- /dev/null
+++ b/src/lib/use-can-reach-to-internet/index.tsx
@@ -0,0 +1,223 @@
+import { useEffect, useRef, useState, useSyncExternalStore } from 'react'
+import useSyncedRef from '../use-synced-ref'
+
+export type CanReachToInternetOptions = {
+ /** Enable automatic network polling to continuously check connectivity */
+ enableNetworkPolling?: boolean
+ /** Interval in milliseconds between network polls */
+ networkPollingInterval?: number
+ /** URL to test internet connectivity against */
+ testUrl?: string
+}
+export type CanReachToInternetBoolean = boolean
+
+const DEFAULT_OPTIONS: Required = {
+ enableNetworkPolling: true,
+ networkPollingInterval: 3000,
+ testUrl: 'https://dns.google', // https://8.8.8.8
+}
+
+/**
+ * @description
+ * A comprehensive React hook for monitoring internet connectivity status that goes beyond basic online/offline detection by actually testing network reachability.
+
+ * @example
+ * import { useCanReachToInternet } from 'classic-react-hooks'
+ *
+ * function ConnectivityStatus() {
+ const {
+ isOnline,
+ canReachToInternet,
+ isFullyConnected,
+ isCheckingConnection,
+ isNetworkPollingEnabled,
+ startNetworkPolling,
+ stopNetworkPolling,
+ forceCheckNetwork
+ } = useCanReachToInternet()
+
+ return (
+
+
Connectivity Status
+
+
+
+
+ Browser Online: {isOnline ? 'Yes' : 'No'}
+
+
+
+
+ Internet Reachable: {canReachToInternet ? 'Yes' : 'No'}
+
+
+
+
+ Fully Connected: {isFullyConnected ? 'Yes' : 'No'}
+
+
+ {isCheckingConnection && (
+
Checking connectivity...
+ )}
+
+
+
+
+ Check Now
+
+
+ {isNetworkPollingEnabled ? (
+
+ Stop Polling
+
+ ) : (
+
+ Start Polling
+
+ )}
+
+
+ )
+ }
+ *
+ * @see Docs https://classic-react-hooks.vercel.app/hooks/use-can-reach-to-internet.html
+ */
+export default function useCanReachToInternet(options: CanReachToInternetOptions = {}) {
+ const config = { ...DEFAULT_OPTIONS, ...options }
+
+ // Getting browser's online/offline status
+ const isOnline = useSyncExternalStore(subscribe, getSnapshot, () => true)
+
+ const [canReachToInternet, setCanReachToInternet] = useState(false)
+ const [isNetworkPollingEnabled, setIsNetworkPollingEnabled] = useState(config.enableNetworkPolling)
+ const [isCheckingConnection, setIsCheckingConnection] = useState(false)
+ const canReachToInternetRef = useSyncedRef(canReachToInternet)
+ let isInitialCallDone = useRef(false)
+
+ // Use refs to track cleanup and prevent memory leaks
+ const abortControllerRef = useRef(null)
+ const timeoutRef = useRef(null)
+
+ const handlers = useRef({
+ clearPendingOperations: () => {
+ if (abortControllerRef.current) {
+ abortControllerRef.current.abort('cleanup')
+ abortControllerRef.current = null
+ }
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current)
+ timeoutRef.current = null
+ }
+ },
+ stopNetworkPolling: () => setIsNetworkPollingEnabled(false),
+ startNetworkPolling: () => setIsNetworkPollingEnabled(true),
+ getCanReachToInternetStatus: () => canReachToInternetRef.current as CanReachToInternetBoolean,
+ })
+
+ /**
+ * Performs an actual network request to test internet connectivity
+ *
+ * @description
+ * This function makes a HEAD request to the configured test URL to verify
+ * that the device can actually reach the internet, not just that the browser
+ * thinks it's online.
+ *
+ */
+ const checkIfCanReachToInternet = async (
+ { pollingEnabled }: { pollingEnabled?: boolean } = { pollingEnabled: true }
+ ) => {
+ // If offline then early return with flag update
+ if (!isOnline) {
+ setCanReachToInternet(false)
+ return
+ }
+
+ // Clear any existing operations
+ handlers.current.clearPendingOperations()
+
+ const abortController = new AbortController()
+ abortControllerRef.current = abortController
+
+ setIsCheckingConnection(true)
+
+ try {
+ // ping to dns server to check if really connected to internet
+ await fetch(config.testUrl, {
+ method: 'HEAD',
+ cache: 'no-cache',
+ mode: 'no-cors',
+ headers: {
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
+ Pragma: 'no-cache',
+ },
+ signal: abortController.signal,
+ })
+ setCanReachToInternet(true)
+ } catch (err) {
+ // Only update state if the request wasn't aborted
+ if (!abortController.signal.aborted) {
+ setCanReachToInternet(false)
+ }
+ } finally {
+ if (isNetworkPollingEnabled && !abortController.signal.aborted) {
+ if (pollingEnabled) {
+ timeoutRef.current = setTimeout(() => checkIfCanReachToInternet(), config.networkPollingInterval)
+ }
+ }
+ setIsCheckingConnection(false)
+ }
+ }
+
+ useEffect(() => {
+ // If network polling is stopped, then do not run again.
+ // Initially trigger checker function
+ if (isInitialCallDone.current && !isNetworkPollingEnabled) {
+ // Even if polling is stopped, check if the device is online.
+ // And update the state
+ if (!isOnline) {
+ setCanReachToInternet(false)
+ } else {
+ checkIfCanReachToInternet({ pollingEnabled: false })
+ }
+ return
+ }
+ isInitialCallDone.current = true
+ checkIfCanReachToInternet()
+
+ return handlers.current.clearPendingOperations
+ }, [isOnline, isNetworkPollingEnabled, config.networkPollingInterval])
+
+ return {
+ isOnline,
+ canReachToInternet,
+ isFullyConnected: isOnline && canReachToInternet,
+ isNetworkPollingEnabled,
+ isCheckingConnection,
+ stopNetworkPolling: handlers.current.stopNetworkPolling,
+ startNetworkPolling: handlers.current.startNetworkPolling,
+ getCanReachToInternetStatus: handlers.current.getCanReachToInternetStatus,
+ forceCheckNetwork: checkIfCanReachToInternet,
+ }
+}
+
+// Handler to listen "online" and "offline" events
+function subscribe(callback: () => void) {
+ window.addEventListener('online', callback)
+ window.addEventListener('offline', callback)
+
+ return () => {
+ window.removeEventListener('online', callback)
+ window.removeEventListener('offline', callback)
+ }
+}
+// getting network connection status
+const getSnapshot = () => navigator.onLine
diff --git a/src/lib/use-combined-key-event-listener/index.tsx b/src/lib/use-combined-key-event-listener/index.tsx
deleted file mode 100644
index 8bae0ad..0000000
--- a/src/lib/use-combined-key-event-listener/index.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-'use client'
-import React, { useRef } from 'react'
-import { useEventListener } from '../use-event-listener'
-
-type Options = AddEventListenerOptions & {
- preventDefault?: boolean
- shouldAddEvent?: boolean
-}
-
-export default function useCombinedKeyEventListener(
- type: K,
- keys: string[],
- handler: (event: GlobalEventHandlersEventMap[K]) => void,
- options?: boolean | Options
-) {
- const pressedKeysMap = useRef>([])
- let shouldInjectEvent: boolean | undefined = true
- let eventOptions: Options = {}
-
- if (options && options instanceof Object && !Array.isArray(options)) {
- const { shouldAddEvent, ...restOptions } = options
- eventOptions = restOptions
- shouldInjectEvent = shouldAddEvent
- }
-
- const listener = (event: GlobalEventHandlersEventMap[K]) => {
- if ('key' in event) {
- event.ctrlKey && pressedKeysMap.current.push('Control')
- event.shiftKey && pressedKeysMap.current.push('Shift')
- event.altKey && pressedKeysMap.current.push('Alt')
-
- !pressedKeysMap.current.includes(event.key) && pressedKeysMap.current.push(event.key)
-
- if (keys.toString() == pressedKeysMap.current.toString()) {
- if (eventOptions?.preventDefault) event.preventDefault()
- handler(event)
- }
- }
- }
-
- const clearPressedKey = () => {
- pressedKeysMap.current.pop()
- }
-
- useEventListener(document, type, listener, options)
-
- useEventListener(document, 'keyup', clearPressedKey, options)
- useEventListener(window, 'blur', () => (pressedKeysMap.current = []), shouldInjectEvent)
- useEventListener(window, 'contextmenu', () => (pressedKeysMap.current = []), shouldInjectEvent)
-}
diff --git a/src/lib/use-copy-to-clipboard/index.test.tsx b/src/lib/use-copy-to-clipboard/index.test.tsx
new file mode 100644
index 0000000..dcec6b8
--- /dev/null
+++ b/src/lib/use-copy-to-clipboard/index.test.tsx
@@ -0,0 +1,370 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
+import { render, screen, fireEvent, waitFor, renderHook } from '@testing-library/react'
+import React, { useState } from 'react'
+import useCopyToClipboard, { copyToClipboardFn } from '.'
+
+describe('use-copy-to-clipboard', () => {
+ // Mock clipboard API
+ const mockWriteText = vi.fn()
+ const originalClipboard = navigator.clipboard
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+
+ Object.defineProperty(navigator, 'clipboard', {
+ value: {
+ writeText: mockWriteText,
+ },
+ configurable: true,
+ })
+
+ mockWriteText.mockResolvedValue(undefined)
+ })
+
+ afterEach(() => {
+ Object.defineProperty(navigator, 'clipboard', {
+ value: originalClipboard,
+ configurable: true,
+ })
+ })
+
+ describe('Hook behavior', () => {
+ it('should return a function', () => {
+ const { result } = renderHook(() => useCopyToClipboard())
+ expect(typeof result.current).toBe('function')
+ expect(result.current.length).toBe(3)
+ })
+
+ it('should use props callbacks when provided', async () => {
+ const onSuccess = vi.fn()
+ const onError = vi.fn()
+
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith('test data')
+ expect(onSuccess).toHaveBeenCalled()
+ })
+ })
+
+ it('should prioritize callback parameters over props', async () => {
+ const propsOnSuccess = vi.fn()
+ const overrideOnSuccess = vi.fn()
+
+ render( )
+
+ const button = screen.getByTestId('copy-button-with-callbacks')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(overrideOnSuccess).toHaveBeenCalled()
+ expect(propsOnSuccess).not.toHaveBeenCalled()
+ })
+ })
+ })
+
+ describe('Successful copy scenarios', () => {
+ it('should copy text successfully and call onSuccess', async () => {
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith('test data')
+ expect(screen.getByTestId('success-message')).toBeInTheDocument()
+ })
+ })
+
+ it('should copy different text data', async () => {
+ let customData = 'custom clipboard data'
+ const { rerender } = render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith(customData)
+ })
+
+ customData = 'updated text data'
+ rerender( )
+
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith(customData)
+ })
+ })
+
+ it('should work with empty string', async () => {
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith('')
+ })
+ })
+ })
+
+ describe('Error scenarios', () => {
+ it('should handle clipboard writeText rejection', async () => {
+ const error = new Error('Clipboard write failed')
+ mockWriteText.mockRejectedValue(error)
+
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(screen.getByTestId('error-message')).toHaveTextContent('Clipboard write failed')
+ })
+ })
+
+ it('should handle missing clipboard API', async () => {
+ // Removing clipboard API
+ Object.defineProperty(navigator, 'clipboard', {
+ value: undefined,
+ configurable: true,
+ })
+
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(screen.getByTestId('error-message')).toHaveTextContent('Cliboard not available')
+ })
+ })
+
+ it('should handle exceptions in try-catch block', async () => {
+ // Mock clipboard to throw an exception
+ Object.defineProperty(navigator, 'clipboard', {
+ get() {
+ throw new Error('Clipboard access denied')
+ },
+ configurable: true,
+ })
+
+ render( )
+
+ const button = screen.getByTestId('copy-button')
+ fireEvent.click(button)
+
+ await waitFor(() => {
+ expect(screen.getByTestId('error-message')).toHaveTextContent('Clipboard access denied')
+ })
+ })
+ })
+})
+
+// copyToClipboardFn utility function
+describe('copyToClipboardFn', () => {
+ const mockWriteText = vi.fn()
+ const originalClipboard = navigator.clipboard
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+
+ Object.defineProperty(navigator, 'clipboard', {
+ value: {
+ writeText: mockWriteText,
+ },
+ configurable: true,
+ })
+
+ mockWriteText.mockResolvedValue(undefined)
+ })
+
+ afterEach(() => {
+ Object.defineProperty(navigator, 'clipboard', {
+ value: originalClipboard,
+ configurable: true,
+ })
+ })
+
+ describe('Successful operations', () => {
+ it('should copy text and call onSuccess callback', async () => {
+ const onSuccess = vi.fn()
+ const onError = vi.fn()
+
+ await copyToClipboardFn('test text', onSuccess, onError)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith('test text')
+ expect(onSuccess).toHaveBeenCalled()
+ expect(onError).not.toHaveBeenCalled()
+ })
+ })
+
+ it('should work without callbacks', async () => {
+ await expect(copyToClipboardFn('test text')).resolves.toBeUndefined()
+ expect(mockWriteText).toHaveBeenCalledWith('test text')
+ })
+
+ it('should work with only onSuccess callback', async () => {
+ const onSuccess = vi.fn()
+
+ await copyToClipboardFn('test text', onSuccess)
+
+ await waitFor(() => {
+ expect(onSuccess).toHaveBeenCalled()
+ })
+ })
+
+ it('should work with only onError callback', async () => {
+ const onError = vi.fn()
+
+ await copyToClipboardFn('test text', undefined, onError)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith('test text')
+ expect(onError).not.toHaveBeenCalled()
+ })
+ })
+ })
+
+ describe('Error scenarios', () => {
+ it('should call onError when writeText fails', async () => {
+ const error = new Error('Write failed')
+ mockWriteText.mockRejectedValue(error)
+
+ const onSuccess = vi.fn()
+ const onError = vi.fn()
+
+ await copyToClipboardFn('test text', onSuccess, onError)
+
+ await waitFor(() => {
+ expect(onError).toHaveBeenCalledWith(error)
+ expect(onSuccess).not.toHaveBeenCalled()
+ })
+ })
+
+ it('should handle missing clipboard API', async () => {
+ Object.defineProperty(navigator, 'clipboard', {
+ value: undefined,
+ configurable: true,
+ })
+
+ const onError = vi.fn()
+
+ await copyToClipboardFn('test text', undefined, onError)
+
+ await waitFor(() => {
+ expect(onError).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: 'Cliboard not available',
+ })
+ )
+ })
+ })
+
+ it('should handle exceptions in try block', async () => {
+ Object.defineProperty(navigator, 'clipboard', {
+ get() {
+ throw new Error('Access denied')
+ },
+ configurable: true,
+ })
+
+ const onError = vi.fn()
+
+ await copyToClipboardFn('test text', undefined, onError)
+
+ await waitFor(() => {
+ expect(onError).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: 'Access denied',
+ })
+ )
+ })
+ })
+
+ it('should not throw when onError is not provided and error occurs', async () => {
+ mockWriteText.mockRejectedValue(new Error('Write failed'))
+
+ await expect(copyToClipboardFn('test text')).resolves.toBeUndefined()
+ })
+ })
+
+ describe('Edge cases', () => {
+ it('should handle special characters', async () => {
+ const specialText = '🚀 Special chars: áéíóú ñ €$¥'
+ const onSuccess = vi.fn()
+
+ await copyToClipboardFn(specialText, onSuccess)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith(specialText)
+ expect(onSuccess).toHaveBeenCalled()
+ })
+ })
+
+ it('should handle very long text', async () => {
+ const longText = 'a'.repeat(10000)
+ const onSuccess = vi.fn()
+
+ await copyToClipboardFn(longText, onSuccess)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith(longText)
+ expect(onSuccess).toHaveBeenCalled()
+ })
+ })
+
+ it('should handle newlines and tabs', async () => {
+ const textWithWhitespace = 'Line 1\nLine 2\tTabbed'
+ const onSuccess = vi.fn()
+
+ await copyToClipboardFn(textWithWhitespace, onSuccess)
+
+ await waitFor(() => {
+ expect(mockWriteText).toHaveBeenCalledWith(textWithWhitespace)
+ expect(onSuccess).toHaveBeenCalled()
+ })
+ })
+ })
+})
+
+const DummyTestComponent: React.FC<{
+ onSuccess?: () => void
+ onError?: (err: Error) => void
+ overrideOnSuccess?: () => void
+ testData?: string
+}> = ({ onSuccess, overrideOnSuccess, onError, testData = 'test data' }) => {
+ const [copied, setCopied] = useState(false)
+ const [error, setError] = useState(null)
+
+ const copyToClipboard = useCopyToClipboard({
+ onSuccess: onSuccess || (() => setCopied(true)),
+ onError: onError || ((err) => setError(err.message)),
+ })
+
+ return (
+
+
copyToClipboard(testData)} data-testid='copy-button'>
+ Copy
+
+
+ copyToClipboard(testData, () => {
+ setCopied(true)
+ overrideOnSuccess?.()
+ })
+ }
+ data-testid='copy-button-with-callbacks'
+ >
+ Copy with callbacks
+
+ {copied &&
Copied!
}
+ {error &&
{error}
}
+
+ )
+}
diff --git a/src/lib/use-copy-to-clipboard/index.tsx b/src/lib/use-copy-to-clipboard/index.tsx
index 26d5a07..ec85519 100644
--- a/src/lib/use-copy-to-clipboard/index.tsx
+++ b/src/lib/use-copy-to-clipboard/index.tsx
@@ -1,4 +1,3 @@
-'use client'
import React, { useRef } from 'react'
import useSyncedRef from '../use-synced-ref'
@@ -8,7 +7,31 @@ type CopyToClipboardFn = (data: string, onSuccess?: OnSuccess, onError?: OnError
/**
* @description
- * A hook for copying the data in the clipboard with success and error callbacks.
+ * A React hook that provides simple and reliable way to copy text to the clipboard with success and error handling callbacks.
+ *
+ * @example
+ import { useState } from 'react'
+ import { useCopyToClipboard } from 'classic-react-hooks'
+
+ export default function CopyButton() {
+ const [copied, setCopied] = useState(false)
+
+ const copyToClipboard = useCopyToClipboard({
+ onSuccess: () => {
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ },
+ onError: (error) => {
+ console.error('Failed to copy:', error)
+ },
+ })
+
+ const handleCopy = () => {
+ copyToClipboard('Hello, World!')
+ }
+
+ return {copied ? 'Copied!' : 'Copy Text'}
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-copy-to-clipboard.html
*
@@ -23,6 +46,16 @@ export default function useCopyToClipboard(props?: { onSuccess?: OnSuccess; onEr
return copyToClipboard.current
}
+/**
+ *
+ * @example
+ copyToClipboardFn(
+ 'Text to copy',
+ () => console.log('Copied successfully!'),
+ (error) => console.error('Copy failed:', error)
+ )
+ *
+ */
export async function copyToClipboardFn(data: string, onSuccess?: OnSuccess, onError?: OnError) {
try {
if (navigator.clipboard) {
diff --git a/src/lib/use-counter/index.test.tsx b/src/lib/use-counter/index.test.tsx
index b5636df..cf4535e 100644
--- a/src/lib/use-counter/index.test.tsx
+++ b/src/lib/use-counter/index.test.tsx
@@ -7,7 +7,7 @@ describe('use-counter', () => {
})
it('should return counter value of zero, incrementCounter and decrementCounter handlers with default key', () => {
- const { result } = renderHook(() => useCounter('', 1))
+ const { result } = renderHook(() => useCounter('', { initialValue: 1 }))
expect('counter' in result.current).not.toBeUndefined()
expect(result.current.counter).toBe(1)
diff --git a/src/lib/use-counter/index.tsx b/src/lib/use-counter/index.tsx
index 593df73..0670cd7 100644
--- a/src/lib/use-counter/index.tsx
+++ b/src/lib/use-counter/index.tsx
@@ -1,4 +1,3 @@
-'use client'
import type { Prettify } from '../../types'
import React, { useRef, useState } from 'react'
import { capitalizeFirstLetter } from '../../utils/capitalize-first-letter'
@@ -8,13 +7,37 @@ const LOWERCASED_COUNTER_TEXT = COUNTER_TEXT.toLowerCase() as Lowercase
+
+
decrement
+
{counter}
+
increment
+
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-counter.html
*
*/
-export default function useCounter(key = '' as K, initialValue: number = 0) {
- const [counter, setCounter] = useState(initialValue)
+export default function useCounter(
+ key = '' as K,
+ options?: { initialValue?: number; stepper?: number }
+) {
+ const [counter, setCounter] = useState(options?.initialValue ?? 0)
+ let jumpBy = options?.stepper ?? 1
const capitalizedKey = capitalizeFirstLetter(key)
@@ -30,10 +53,10 @@ export default function useCounter(key = '' as K, initial
const handlers = useRef({
incrementHandler: () => {
- setCounter((c) => c + 1)
+ setCounter((c) => c + jumpBy)
},
decrementHandler: () => {
- setCounter((c) => c - 1)
+ setCounter((c) => c - jumpBy)
},
})
diff --git a/src/lib/use-debounced-fn/index.test.tsx b/src/lib/use-debounced-fn/index.test.tsx
index 8f5fce2..e493df7 100644
--- a/src/lib/use-debounced-fn/index.test.tsx
+++ b/src/lib/use-debounced-fn/index.test.tsx
@@ -1,135 +1,1357 @@
import { vi } from 'vitest'
import { renderHook } from '@testing-library/react'
-import useDebouncedFn from '.'
+import { useDebouncedFn } from '.'
+import { act } from 'react'
describe('use-debounced-fn', () => {
beforeEach(() => {
vi.useFakeTimers()
})
+
afterEach(() => {
vi.useRealTimers()
+ vi.clearAllMocks()
+ })
+
+ describe('mounting', () => {
+ it('should return an object with debouncedFn and cleanup functions', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ expect(typeof result.current.debouncedFn).toBe('function')
+ expect(typeof result.current.cleanup).toBe('function')
+ })
+
+ it('should not call callback on initialization', () => {
+ const callback = vi.fn()
+ renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should not call callback immediately when invoked', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ result.current.debouncedFn()
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('unmounting', () => {
+ it('should cleanup timer on unmount', async () => {
+ const callback = vi.fn()
+
+ const { result, unmount } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 500 }))
+
+ result.current.debouncedFn()
+
+ unmount()
+
+ await act(() => {
+ vi.advanceTimersByTime(600)
+ })
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should cleanup multiple pending timers on unmount', async () => {
+ const callback = vi.fn()
+
+ const { result, unmount } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ act(() => {
+ result.current.debouncedFn() // First call
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn() // Second call (cancels first)
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn() // Third call (cancels second)
+ })
+
+ unmount()
+
+ await act(() => {
+ vi.advanceTimersByTime(500)
+ })
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should not cause memory leaks with repeated mount/unmount', async () => {
+ const callback = vi.fn()
+
+ for (let i = 0; i < 10; i++) {
+ const { result, unmount } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 100 }))
+
+ result.current.debouncedFn()
+
+ unmount()
+ }
+
+ await act(() => {
+ vi.advanceTimersByTime(200)
+ })
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should abort pending async operations on unmount', () => {
+ const callback = vi.fn(async (signal: AbortSignal) => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => resolve('completed'), 100)
+ signal.addEventListener('abort', () => {
+ clearTimeout(timeout)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ })
+ const onError = vi.fn()
+
+ const { result, unmount } = renderHook(() =>
+ useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 })
+ )
+
+ result.current.debouncedFn()
+
+ act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ unmount()
+
+ act(() => {
+ vi.advanceTimersByTime(100)
+ })
+
+ // AbortError should be caught but not passed to onError
+ expect(onError).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('Debouncing behavior', () => {
+ it('should use default delay of 300ms', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn()
+
+ act(() => {
+ vi.advanceTimersByTime(299)
+ })
+ expect(callback).not.toHaveBeenCalled()
+
+ act(() => {
+ vi.advanceTimersByTime(1) // Total 300ms
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should respect custom delay', () => {
+ const callback = vi.fn()
+ const customDelay = 500
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: customDelay }))
+
+ result.current.debouncedFn()
+
+ act(() => {
+ vi.advanceTimersByTime(499)
+ })
+ expect(callback).not.toHaveBeenCalled()
+
+ act(() => {
+ vi.advanceTimersByTime(1) // Total 500ms
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should debounce multiple rapid calls', async () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 200 }))
+
+ act(() => {
+ result.current.debouncedFn() // Call 1
+ result.current.debouncedFn() // Call 2 - should reset timer
+ result.current.debouncedFn() // Call 3 - should reset timer
+ })
+
+ act(() => {
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn() // Call 4 - should reset timer again
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(199)
+ })
+ expect(callback).not.toHaveBeenCalled()
+
+ await act(() => {
+ vi.advanceTimersByTime(1) // 200ms from last call
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should allow multiple executions after delay periods', async () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 100 }))
+
+ // First execution
+ result.current.debouncedFn('first')
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenNthCalledWith(1, expect.any(AbortSignal), 'first')
+
+ // Second execution
+ result.current.debouncedFn('second')
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ })
+ expect(callback).toHaveBeenCalledTimes(2)
+ expect(callback).toHaveBeenNthCalledWith(2, expect.any(AbortSignal), 'second')
+ })
+ })
+
+ describe('AbortSignal behavior', () => {
+ it('should pass AbortSignal as first argument to callbackToBounce', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn('arg1', 'arg2', 123)
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ const callArgs = callback.mock.calls[0]!
+ expect(callArgs[0]).toBeInstanceOf(AbortSignal)
+ expect(callArgs[1]).toBe('arg1')
+ expect(callArgs[2]).toBe('arg2')
+ expect(callArgs[3]).toBe(123)
+ })
+
+ it('should abort previous operation when new call is made', async () => {
+ let abortedCount = 0
+ const callback = vi.fn(async (signal: AbortSignal, value: string) => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => resolve(value), 100)
+ signal.addEventListener('abort', () => {
+ abortedCount++
+ clearTimeout(timeout)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ })
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 200 }))
+
+ result.current.debouncedFn('first')
+
+ await act(() => {
+ vi.advanceTimersByTime(200)
+ })
+
+ result.current.debouncedFn('second') // Should abort first
+
+ expect(abortedCount).toBe(1)
+ })
+
+ it('should not call onError when AbortError is thrown', async () => {
+ const callback = vi.fn(async (signal: AbortSignal) => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => resolve('completed'), 100)
+ signal.addEventListener('abort', () => {
+ clearTimeout(timeout)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ })
+ const onError = vi.fn()
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ result.current.debouncedFn()
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ // Trigger abort by calling again
+ result.current.debouncedFn()
+
+ // AbortError should be caught internally and not trigger onError
+ expect(onError).not.toHaveBeenCalled()
+ })
+
+ it('should call onError for non-abort errors', async () => {
+ const testError = new Error('Regular error')
+ const callback = vi.fn(async (signal: AbortSignal) => {
+ throw testError
+ })
+ const onError = vi.fn()
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ result.current.debouncedFn('test')
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onError).toHaveBeenCalledWith(testError, 'test')
+ })
+
+ it('should provide non-aborted signal on first execution', async () => {
+ const callback = vi.fn((signal: AbortSignal) => {
+ expect(signal.aborted).toBe(false)
+ })
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn()
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should handle fetch requests with abort signal', async () => {
+ const mockFetch = vi.fn((url: string, options: any) => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(
+ () => resolve({ ok: true, json: () => Promise.resolve({ data: 'test' }) }),
+ 100
+ )
+ options.signal.addEventListener('abort', () => {
+ clearTimeout(timeout)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ })
+
+ global.fetch = mockFetch as any
+
+ const callback = vi.fn(async (signal: AbortSignal, query: string) => {
+ const response = await fetch(`/api/search?q=${query}`, { signal })
+ return response
+ })
+
+ const onError = vi.fn()
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ act(() => {
+ result.current.debouncedFn('first')
+ })
+
+ act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ // Cancel with new call before fetch completes
+ act(() => {
+ result.current.debouncedFn('second')
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(200)
+ })
+
+ // First fetch should be aborted, onError should not be called for AbortError
+ expect(onError).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('Argument passing to callback', () => {
+ it('should pass arguments correctly to the callback', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn('arg1', 'arg2', 123)
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'arg1', 'arg2', 123)
+ })
+
+ it('should use arguments from the latest call', async () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 200 }))
+
+ act(() => {
+ result.current.debouncedFn('first')
+ result.current.debouncedFn('second')
+ result.current.debouncedFn('third') // This should be the final call
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(200)
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'third')
+ })
+
+ it('should preserve argument references', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ const originalObj = { value: 'original' }
+
+ act(() => {
+ result.current.debouncedFn(originalObj)
+ })
+
+ // Modify the object before debounce executes
+ originalObj.value = 'modified'
+
+ act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), originalObj)
+ expect(callback.mock.calls?.[0]?.[1].value).toBe('modified')
+ })
+ })
+
+ describe('immediateCallback', () => {
+ it('should call immediateCallback synchronously', () => {
+ const immediate = vi.fn()
+ const callback = vi.fn()
+ const { result } = renderHook(() =>
+ useDebouncedFn({ immediateCallback: immediate, callbackToBounce: callback, delay: 300 })
+ )
+
+ act(() => {
+ result.current.debouncedFn('test')
+ })
+
+ expect(immediate).toHaveBeenCalledTimes(1)
+ expect(immediate).toHaveBeenCalledWith('test')
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should call immediateCallback on every invocation', () => {
+ const immediate = vi.fn()
+ const callback = vi.fn()
+ const { result } = renderHook(() =>
+ useDebouncedFn({ immediateCallback: immediate, callbackToBounce: callback, delay: 200 })
+ )
+
+ act(() => {
+ result.current.debouncedFn('first')
+ result.current.debouncedFn('second')
+ result.current.debouncedFn('third')
+ })
+
+ expect(immediate).toHaveBeenCalledTimes(3)
+ expect(immediate).toHaveBeenNthCalledWith(1, 'first')
+ expect(immediate).toHaveBeenNthCalledWith(2, 'second')
+ expect(immediate).toHaveBeenNthCalledWith(3, 'third')
+ expect(callback).not.toHaveBeenCalled()
+
+ act(() => {
+ vi.advanceTimersByTime(200)
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'third')
+ })
+
+ it('should pass all arguments to immediateCallback', () => {
+ const immediate = vi.fn()
+ const callback = vi.fn()
+ const { result } = renderHook(() =>
+ useDebouncedFn({ immediateCallback: immediate, callbackToBounce: callback })
+ )
+
+ result.current.debouncedFn('arg1', 42, { key: 'value' })
+
+ expect(immediate).toHaveBeenCalledWith('arg1', 42, { key: 'value' })
+ })
+
+ it('should work without immediateCallback', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn('test')
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ })
+ })
+
+ describe('onSuccess', () => {
+ it('should call onSuccess after sync callbackToBounce completes', async () => {
+ const callback = vi.fn()
+ const onSuccess = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onSuccess, delay: 300 }))
+
+ result.current.debouncedFn('test')
+
+ // Wait for the scheduled callbacks to get resolved
+ // then check the status
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ expect(onSuccess).toHaveBeenCalledWith('test')
+ expect(callback).toHaveBeenCalledBefore(onSuccess)
+ })
+
+ it('should call onSuccess after async callbackToBounce completes', async () => {
+ const callback = vi.fn(async (signal: AbortSignal, val: string) => {
+ await new Promise((resolve) => setTimeout(resolve, 100))
+ return val
+ })
+ const onSuccess = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onSuccess, delay: 300 }))
+
+ result.current.debouncedFn('async-test')
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'async-test')
+
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ })
+
+ expect(onSuccess).toHaveBeenCalledWith('async-test')
+ })
+
+ it('should pass same arguments to onSuccess', async () => {
+ const callback = vi.fn()
+ const onSuccess = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onSuccess }))
+
+ result.current.debouncedFn('arg1', 123, { nested: true })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onSuccess).toHaveBeenCalledWith('arg1', 123, { nested: true })
+ })
+
+ it('should work without onSuccess', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ act(() => {
+ result.current.debouncedFn('test')
+ })
+
+ act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ })
+
+ it('should not call onSuccess if execution is cancelled', async () => {
+ const callback = vi.fn()
+ const onSuccess = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onSuccess, delay: 300 }))
+
+ result.current.debouncedFn('first')
+
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn('second') // Cancels first
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'second')
+ expect(onSuccess).toHaveBeenCalledTimes(1)
+ expect(onSuccess).toHaveBeenCalledWith('second')
+ })
+ })
+
+ describe('onError', () => {
+ it('should call onError when callbackToBounce throws synchronously', () => {
+ const error = new Error('Test error')
+ const callback = vi.fn(() => {
+ throw error
+ })
+ const onError = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ result.current.debouncedFn('test')
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ expect(onError).toHaveBeenCalledWith(error, 'test')
+ })
+
+ it('should pass all arguments to onError', () => {
+ const error = new Error('Test error')
+ const callback = vi.fn(() => {
+ throw error
+ })
+ const onError = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError }))
+
+ result.current.debouncedFn('arg1', 42, { key: 'value' })
+ vi.advanceTimersByTime(300)
+
+ expect(onError).toHaveBeenCalledWith(error, 'arg1', 42, { key: 'value' })
+ })
+
+ it('should not call onSuccess when onError is called', () => {
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onSuccess = vi.fn()
+ const onError = vi.fn()
+ const { result } = renderHook(() =>
+ useDebouncedFn({ callbackToBounce: callback, onSuccess, onError, delay: 300 })
+ )
+
+ result.current.debouncedFn('test')
+ vi.advanceTimersByTime(300)
+
+ expect(onError).toHaveBeenCalled()
+ expect(onSuccess).not.toHaveBeenCalled()
+ })
+
+ it('should work without onError (error is not caught)', async () => {
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn('test')
+ // Error is thrown but not caught
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ })
+
+ it('should not call onError if execution is cancelled', async () => {
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onError = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ result.current.debouncedFn('first')
+
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn('second') // Cancels first
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onError).toHaveBeenCalledTimes(1)
+ expect(onError).toHaveBeenCalledWith(expect.any(Error), 'second')
+ })
})
- it('should return the debounced callback', () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useDebouncedFn(callback, 300))
+ describe('onFinally', () => {
+ it('should call onFinally after successful execution', async () => {
+ const callback = vi.fn()
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onFinally, delay: 300 }))
+
+ result.current.debouncedFn('test')
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ expect(onFinally).toHaveBeenCalledWith('test')
+ })
+
+ it('should call onFinally after error', () => {
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onFinally, delay: 300 }))
+
+ result.current.debouncedFn('test')
+ vi.advanceTimersByTime(300)
+
+ expect(onFinally).toHaveBeenCalledWith('test')
+ })
+
+ it('should call onFinally with all arguments', async () => {
+ const callback = vi.fn()
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onFinally }))
+
+ result.current.debouncedFn('arg1', 42, { key: 'value' })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onFinally).toHaveBeenCalledWith('arg1', 42, { key: 'value' })
+ })
+
+ it('should work without onFinally', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn('test')
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ })
+
+ it('should not call onFinally if execution is cancelled', async () => {
+ const callback = vi.fn()
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onFinally, delay: 300 }))
- expect(typeof result.current).toBe('function')
+ result.current.debouncedFn('first')
+
+ await act(() => {
+ vi.advanceTimersByTime(100)
+ result.current.debouncedFn('second') // Cancels first
+ })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onFinally).toHaveBeenCalledTimes(1)
+ expect(onFinally).toHaveBeenCalledWith('second')
+ })
})
- it('should not fire callback on initialization', () => {
- const callback = vi.fn()
- renderHook(() => useDebouncedFn(callback, 300))
+ describe('All callbacks together', () => {
+ it('should execute callbacks in correct order: immediate -> debounced -> success -> finally', async () => {
+ const executionOrder: string[] = []
+ const immediate = vi.fn(() => executionOrder.push('immediate'))
+ const callback = vi.fn(() => executionOrder.push('debounced'))
+ const onSuccess = vi.fn(() => executionOrder.push('success'))
+ const onFinally = vi.fn(() => executionOrder.push('finally'))
+
+ const { result } = renderHook(() =>
+ useDebouncedFn({
+ immediateCallback: immediate,
+ callbackToBounce: callback,
+ onSuccess,
+ onFinally,
+ delay: 300,
+ })
+ )
+
+ result.current.debouncedFn('test')
+
+ expect(executionOrder).toEqual(['immediate'])
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(executionOrder).toEqual(['immediate', 'debounced', 'success', 'finally'])
+ })
+
+ it('should execute callbacks in correct order on error: immediate -> debounced -> error -> finally', () => {
+ const executionOrder: string[] = []
+ const immediate = vi.fn(() => executionOrder.push('immediate'))
+ const callback = vi.fn(() => {
+ executionOrder.push('debounced')
+ throw new Error('Test error')
+ })
+ const onError = vi.fn(() => executionOrder.push('error'))
+ const onFinally = vi.fn(() => executionOrder.push('finally'))
+
+ const { result } = renderHook(() =>
+ useDebouncedFn({
+ immediateCallback: immediate,
+ callbackToBounce: callback,
+ onError,
+ onFinally,
+ delay: 300,
+ })
+ )
+
+ result.current.debouncedFn('test')
+ expect(executionOrder).toEqual(['immediate'])
+ vi.advanceTimersByTime(300)
+
+ expect(executionOrder).toEqual(['immediate', 'debounced', 'error', 'finally'])
+ })
+
+ it('should pass same arguments to all callbacks (except AbortSignal to debounced)', async () => {
+ const immediate = vi.fn()
+ const callback = vi.fn()
+ const onSuccess = vi.fn()
+ const onFinally = vi.fn()
+
+ const { result } = renderHook(() =>
+ useDebouncedFn({
+ immediateCallback: immediate,
+ callbackToBounce: callback,
+ onSuccess,
+ onFinally,
+ })
+ )
+
+ const testObj = { id: 1, name: 'test' }
+
+ result.current.debouncedFn(testObj, 'extra', 42)
+
+ expect(immediate).toHaveBeenCalledWith(testObj, 'extra', 42)
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), testObj, 'extra', 42)
+ expect(onSuccess).toHaveBeenCalledWith(testObj, 'extra', 42)
+ expect(onFinally).toHaveBeenCalledWith(testObj, 'extra', 42)
+ })
- expect(callback).not.toHaveBeenCalled()
+ it('should pass same arguments to error and finally callbacks', async () => {
+ const immediate = vi.fn()
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onError = vi.fn()
+ const onFinally = vi.fn()
+
+ const { result } = renderHook(() =>
+ useDebouncedFn({
+ immediateCallback: immediate,
+ callbackToBounce: callback,
+ onError,
+ onFinally,
+ })
+ )
+
+ const testObj = { id: 1, name: 'test' }
+
+ act(() => {
+ result.current.debouncedFn(testObj, 'extra', 42)
+ })
+
+ expect(immediate).toHaveBeenCalledWith(testObj, 'extra', 42)
+
+ await vi.advanceTimersByTime(300)
+
+ expect(onError).toHaveBeenCalledWith(expect.any(Error), testObj, 'extra', 42)
+ expect(onFinally).toHaveBeenCalledWith(testObj, 'extra', 42)
+ })
+ })
+
+ describe('Manual cleanup', () => {
+ it('should cancel pending execution when cleanup is called', async () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ result.current.debouncedFn('test')
+ await vi.advanceTimersByTime(100)
+ result.current.cleanup()
+
+ await vi.advanceTimersByTime(300)
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should not call onSuccess when cleanup cancels execution', async () => {
+ const callback = vi.fn()
+ const onSuccess = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onSuccess, delay: 300 }))
+
+ result.current.debouncedFn('test')
+ result.current.cleanup()
+ await vi.advanceTimersByTime(300)
+
+ expect(callback).not.toHaveBeenCalled()
+ expect(onSuccess).not.toHaveBeenCalled()
+ })
+
+ it('should not call onFinally when cleanup cancels execution', async () => {
+ const callback = vi.fn()
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onFinally, delay: 300 }))
+
+ result.current.debouncedFn('test')
+ result.current.cleanup()
+ await vi.advanceTimersByTime(300)
+
+ expect(callback).not.toHaveBeenCalled()
+ expect(onFinally).not.toHaveBeenCalled()
+ })
+
+ it('should allow new calls after cleanup', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 300 }))
+
+ result.current.debouncedFn('first')
+ result.current.cleanup()
+
+ result.current.debouncedFn('second')
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'second')
+ })
+
+ it('should abort async operations when cleanup is called', async () => {
+ let wasAborted = false
+ const callback = vi.fn(async (signal: AbortSignal) => {
+ return new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => resolve('completed'), 100)
+ signal.addEventListener('abort', () => {
+ wasAborted = true
+ clearTimeout(timeout)
+ reject(new DOMException('Aborted', 'AbortError'))
+ })
+ })
+ })
+ const onError = vi.fn()
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError, delay: 300 }))
+
+ result.current.debouncedFn()
+ vi.advanceTimersByTime(300)
+
+ act(() => {
+ result.current.cleanup()
+ })
+
+ expect(wasAborted).toBe(true)
+ // AbortError should not trigger onError
+ expect(onError).not.toHaveBeenCalled()
+ })
})
- it('should return the debounced callback with default 300ms delay', async () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useDebouncedFn(callback))
+ describe('Context binding', () => {
+ it('should not preserve this context (calls with null)', async () => {
+ let capturedThis: any = 'not-set'
+ const testObj = {
+ name: 'test',
+ callback: function () {
+ capturedThis = this
+ },
+ }
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: testObj.callback }))
+
+ result.current.debouncedFn.call(testObj) // Try to set context
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(capturedThis).toBeNull()
+ })
+ })
+
+ describe('Hook updates and re-renders', () => {
+ it('should update callback when it changes', () => {
+ const callback1 = vi.fn()
+ const callback2 = vi.fn(() => 'second')
+
+ const { result, rerender } = renderHook(({ callback }) => useDebouncedFn({ callbackToBounce: callback }), {
+ initialProps: { callback: callback1 },
+ })
+
+ result.current.debouncedFn()
+
+ rerender({ callback: callback2 })
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback1).not.toHaveBeenCalled()
+ expect(callback2).toHaveBeenCalledTimes(1)
+ })
+
+ it('should update delay and cleanup previous timer', () => {
+ const callback = vi.fn()
+
+ const { result, rerender } = renderHook(({ delay }) => useDebouncedFn({ callbackToBounce: callback, delay }), {
+ initialProps: { delay: 200 },
+ })
+
+ result.current.debouncedFn()
+
+ rerender({ delay: 500 })
+
+ vi.advanceTimersByTime(200)
+ expect(callback).not.toHaveBeenCalled()
+
+ result.current.debouncedFn()
+ vi.advanceTimersByTime(500)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should update immediateCallback when it changes', () => {
+ const immediate1 = vi.fn()
+ const immediate2 = vi.fn()
+ const callback = vi.fn()
+
+ const { result, rerender } = renderHook(
+ ({ immediate }) => useDebouncedFn({ immediateCallback: immediate, callbackToBounce: callback }),
+ { initialProps: { immediate: immediate1 } }
+ )
+
+ result.current.debouncedFn('test1')
+
+ expect(immediate1).toHaveBeenCalledWith('test1')
+
+ rerender({ immediate: immediate2 })
+
+ act(() => {
+ result.current.debouncedFn('test2')
+ })
+
+ expect(immediate2).toHaveBeenCalledWith('test2')
+ expect(immediate1).toHaveBeenCalledTimes(1)
+ })
+
+ it('should update onSuccess when it changes', async () => {
+ const callback = vi.fn()
+ const onSuccess1 = vi.fn()
+ const onSuccess2 = vi.fn()
+
+ const { result, rerender } = renderHook(
+ ({ onSuccess }) => useDebouncedFn({ callbackToBounce: callback, onSuccess }),
+ { initialProps: { onSuccess: onSuccess1 } }
+ )
+
+ result.current.debouncedFn('test1')
+
+ rerender({ onSuccess: onSuccess2 })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onSuccess1).not.toHaveBeenCalled()
+ expect(onSuccess2).toHaveBeenCalledWith('test1')
+ })
+
+ it('should update onError when it changes', async () => {
+ const callback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onError1 = vi.fn()
+ const onError2 = vi.fn()
- result.current(10)
- vi.advanceTimersByTime(100)
- expect(callback).toHaveBeenCalledTimes(0)
+ const { result, rerender } = renderHook(
+ ({ onError }) => useDebouncedFn({ callbackToBounce: callback, onError }),
+ { initialProps: { onError: onError1 } }
+ )
- vi.advanceTimersByTime(100)
- expect(callback).toHaveBeenCalledTimes(0)
+ result.current.debouncedFn('test1')
- vi.advanceTimersByTime(100)
- expect(callback).toHaveBeenCalledTimes(1)
+ rerender({ onError: onError2 })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onError1).not.toHaveBeenCalled()
+ expect(onError2).toHaveBeenCalledWith(expect.any(Error), 'test1')
+ })
+
+ it('should update onFinally when it changes', async () => {
+ const callback = vi.fn()
+ const onFinally1 = vi.fn()
+ const onFinally2 = vi.fn()
+
+ const { result, rerender } = renderHook(
+ ({ onFinally }) => useDebouncedFn({ callbackToBounce: callback, onFinally }),
+ { initialProps: { onFinally: onFinally1 } }
+ )
+
+ result.current.debouncedFn('test1')
+
+ rerender({ onFinally: onFinally2 })
+
+ await act(() => {
+ vi.advanceTimersByTime(300)
+ })
+
+ expect(onFinally1).not.toHaveBeenCalled()
+ expect(onFinally2).toHaveBeenCalledWith('test1')
+ })
+
+ it('should handle callback updates during pending execution', () => {
+ let message = 'original'
+ const logFn = vi.fn()
+ const createCallback = () =>
+ vi.fn(() => {
+ logFn(message)
+ return message
+ })
+
+ let callback = createCallback()
+ const { result, rerender } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ result.current.debouncedFn()
+
+ // Update both message and callback
+ message = 'updated'
+ callback = createCallback()
+ rerender()
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(logFn).toHaveBeenCalledTimes(1)
+ expect(logFn).toHaveBeenNthCalledWith(1, 'updated')
+ })
})
- it('should call deboucnced function with given arguments', async () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useDebouncedFn(callback))
+ describe('Error handling', () => {
+ it('should handle callback that throws an error without onError', () => {
+ const errorCallback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: errorCallback }))
+
+ result.current.debouncedFn()
+ vi.advanceTimersByTime(300)
+
+ expect(errorCallback).toHaveBeenCalledTimes(1)
+ })
+
+ it('should continue working after callback error', () => {
+ let shouldThrow = true
+ const callback = vi.fn(() => {
+ if (shouldThrow) {
+ throw new Error('Test error')
+ }
+ return 'success'
+ })
+ const onError = vi.fn()
+
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, onError }))
+
+ // First call throws
+ result.current.debouncedFn()
- result.current(10)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenNthCalledWith(1, 10)
+ vi.advanceTimersByTime(300)
- result.current(30)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenNthCalledWith(2, 30)
+ expect(onError).toHaveBeenCalled()
+
+ // Second call succeeds
+ shouldThrow = false
+ result.current.debouncedFn()
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
+
+ it('should not call onSuccess if callbackToBounce throws', () => {
+ const errorCallback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onSuccess = vi.fn()
+ const onError = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: errorCallback, onSuccess, onError }))
+
+ result.current.debouncedFn()
+ vi.advanceTimersByTime(300)
+
+ expect(onSuccess).not.toHaveBeenCalled()
+ expect(onError).toHaveBeenCalled()
+ })
+
+ it('should call onFinally even if callbackToBounce throws', () => {
+ const errorCallback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const onError = vi.fn()
+ const onFinally = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: errorCallback, onError, onFinally }))
+
+ result.current.debouncedFn('test')
+
+ vi.advanceTimersByTime(300)
+
+ expect(onError).toHaveBeenCalledWith(expect.any(Error), 'test')
+ expect(onFinally).toHaveBeenCalledWith('test')
+ })
})
- it('should debounce the callback with custom delay', () => {
- const callback = vi.fn()
+ describe('Edge cases', () => {
+ it('should handle rapid delay changes', () => {
+ const callback = vi.fn()
+ const delays = [100, 200, 50, 500, 300]
+ let currentDelay = delays[0]
+
+ const { result, rerender } = renderHook(() =>
+ useDebouncedFn({ callbackToBounce: callback, delay: currentDelay })
+ )
+
+ delays.forEach((delay, index) => {
+ currentDelay = delay
+ rerender()
- const { result } = renderHook(() => useDebouncedFn(callback, 500))
+ act(() => {
+ result.current.debouncedFn(`call-${index}`)
+ })
+ })
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'call-4')
+ })
- result.current(2)
- vi.advanceTimersByTime(300)
- result.current(2)
- result.current(2)
- vi.advanceTimersByTime(500)
+ it('should handle zero delay', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 0 }))
- expect(callback).toHaveBeenCalledTimes(1)
- expect(callback).toHaveBeenCalledWith(2)
+ act(() => {
+ result.current.debouncedFn('test')
+ })
- result.current(5)
- vi.advanceTimersByTime(500)
- expect(callback).toHaveBeenCalledTimes(2)
- expect(callback).toHaveBeenCalledWith(2)
+ vi.advanceTimersByTime(0)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test')
+ })
})
- it('should cleanup the timers on unmount', async () => {
- const callback = vi.fn()
+ describe('Performance and memory', () => {
+ it('should not create new debounced function on every render', () => {
+ const callback = vi.fn()
+ const { result, rerender } = renderHook(() => useDebouncedFn({ callbackToBounce: callback }))
+
+ const firstResult = result.current
+ rerender()
+ const secondResult = result.current
+
+ expect(firstResult).toBe(secondResult)
+ expect(firstResult.debouncedFn).toBe(secondResult.debouncedFn)
+ expect(firstResult.cleanup).toBe(secondResult.cleanup)
+ })
+
+ it('should handle many rapid calls efficiently', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 100 }))
+
+ act(() => {
+ for (let i = 0; i < 1000; i++) {
+ result.current.debouncedFn(i)
+ }
+ })
+
+ vi.advanceTimersByTime(100)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 999)
+ })
+
+ it('should not cause memory leaks with immediateCallback on many calls', () => {
+ const immediate = vi.fn()
+ const callback = vi.fn()
+ const { result } = renderHook(() =>
+ useDebouncedFn({ immediateCallback: immediate, callbackToBounce: callback, delay: 100 })
+ )
- const { result, unmount } = renderHook(() => useDebouncedFn(callback, 500))
+ for (let i = 0; i < 100; i++) {
+ result.current.debouncedFn(i)
+ }
- result.current()
- unmount()
- vi.advanceTimersByTime(600)
- expect(callback).toHaveBeenCalledTimes(0)
+ expect(immediate).toHaveBeenCalledTimes(100)
+
+ vi.advanceTimersByTime(100)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
})
- it('should sync with updated delay param and cleanup the timers with it', () => {
- let delay = 200
- const callback = vi.fn()
+ describe('Integration with React lifecycle', () => {
+ it('should work correctly with React.StrictMode (double effect execution)', () => {
+ const callback = vi.fn()
- const { result, rerender } = renderHook(() => useDebouncedFn(callback, delay))
- result.current()
- vi.advanceTimersByTime(200)
- expect(callback).toHaveBeenCalledTimes(1)
+ // Simulate StrictMode by manually calling effects twice
+ const { result, rerender } = renderHook(() => useDebouncedFn({ callbackToBounce: callback, delay: 200 }))
- // should run with updated timer
- delay = 500
- rerender()
- result.current()
- vi.advanceTimersByTime(200)
- expect(callback).toHaveBeenCalledTimes(1)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenCalledTimes(2)
+ // Simulate StrictMode re-render
+ rerender()
+
+ result.current.debouncedFn()
+ vi.advanceTimersByTime(200)
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
- // should cleanup scheduled call when timer is updated
- result.current()
- delay = 1000
- rerender()
- vi.advanceTimersByTime(500)
- expect(callback).toHaveBeenCalledTimes(2)
+ it('should handle component re-renders during debounce period', () => {
+ const callback = vi.fn()
+ let renderCount = 0
+
+ const { result, rerender } = renderHook(() => {
+ renderCount++
+ return useDebouncedFn({ callbackToBounce: callback, delay: 300 })
+ })
+
+ result.current.debouncedFn()
+
+ act(() => {
+ vi.advanceTimersByTime(100)
+ rerender()
+ vi.advanceTimersByTime(100)
+ rerender()
+ vi.advanceTimersByTime(100) // Total 300ms
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(renderCount).toBeGreaterThan(1)
+ })
})
- it('callback param should be reactive', () => {
- let tempValue = 'temp'
+ describe('Type safety with function overloads', () => {
+ it('should handle event objects with proper typing', () => {
+ const callback = vi.fn()
+ const immediate = vi.fn()
+
+ const { result } = renderHook(() =>
+ useDebouncedFn>({
+ immediateCallback: immediate,
+ callbackToBounce: callback,
+ })
+ )
- vi.spyOn(console, 'log')
+ const mockEvent = {
+ target: { value: 'test' },
+ } as React.ChangeEvent
- const callback = vi.fn(() => {
- console.log(tempValue)
+ result.current.debouncedFn(mockEvent)
+
+ expect(immediate).toHaveBeenCalledWith(mockEvent)
+
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), mockEvent)
})
- const { result, rerender } = renderHook(() => useDebouncedFn(callback))
+ it('should handle multiple arguments with proper typing', () => {
+ const callback = vi.fn()
- result.current()
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenCalledTimes(1)
- expect(console.log).toHaveBeenCalledWith('temp')
+ const { result } = renderHook(() =>
+ useDebouncedFn({
+ callbackToBounce: callback,
+ })
+ )
- tempValue = 'this is temp'
- rerender()
- result.current()
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenCalledTimes(2)
- expect(console.log).toHaveBeenCalledWith('this is temp')
+ result.current.debouncedFn('test', 42, true)
+ vi.advanceTimersByTime(300)
+
+ expect(callback).toHaveBeenCalledWith(expect.any(AbortSignal), 'test', 42, true)
+ })
})
})
diff --git a/src/lib/use-debounced-fn/index.tsx b/src/lib/use-debounced-fn/index.tsx
index b51a672..2e30055 100644
--- a/src/lib/use-debounced-fn/index.tsx
+++ b/src/lib/use-debounced-fn/index.tsx
@@ -1,32 +1,136 @@
-'use client'
import React, { useEffect, useRef } from 'react'
-import useSyncedRef from '../use-synced-ref'
const DEFAULT_DELAY = 300
/**
* @description
- * A hook which returns a debounced function.
+ *
+ * use-debounced-fn is an async-aware React hook that provides a powerful, declarative way to implement debouncing with full lifecycle control.
+ *
+ * @example
+ *
+ import React, { useState, useEffect } from 'react'
+ import { useDebouncedFn } from 'classic-react-hooks'
+
+ export default function SearchInput() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const { debouncedFn:debouncedSearch } = useDebouncedFn({
+ immediateCallback: (searchTerm) =>{
+ setQuery(searchTerm)
+ },
+ callbackToBounce: async (searchTerm) => {
+ if (searchTerm.trim()) {
+ const url = "https://dummyjson.com/users/search?q="+searchTerm
+ const response = await fetch(url)
+ const data = await response.json()
+ setResults(data.results)
+ }
+ },
+ onSuccess: (searchTerm) => {
+ console.log('Search successful')
+ },
+ onError: (error, searchTerm) => {
+ console.error(error)
+ },
+ onFinally: (searchTerm) => {
+ console.log('Search completed')
+ },
+ delay: 500,
+ })
+
+ useEffect(() => {
+ ;(async function () {
+ const response = await fetch(`https://dummyjson.com/users`)
+ const data = await response.json()
+ setResults(data.results)
+ })()
+ }, [])
+
+ return (
+
+
debouncedSearch(e.target.value)} placeholder='Search products...' />
+
+ {results.map((result) => (
+
{result.name}
+ ))}
+
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-debounced-fn.html
*
*/
-export default function useDebouncedFn any>(cb: T, delay = DEFAULT_DELAY) {
- const paramsRef = useSyncedRef({
- cb,
+export function useDebouncedFn({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ onError,
+ onFinally,
+ delay,
+}: {
+ immediateCallback?: (...args: any[]) => void
+ callbackToBounce: (signal: AbortSignal, ...args: any[]) => void
+ onSuccess?: (...args: any[]) => void
+ onError?: (error: Error, ...args: any[]) => void
+ onFinally?: (...args: any[]) => void
+ delay?: number
+}): {
+ debouncedFn: (...args: any[]) => void
+ cleanup: () => void
+}
+export function useDebouncedFn({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ delay,
+}: {
+ immediateCallback?: (ev: Ev, ...args: Args) => void
+ callbackToBounce: (signal: AbortSignal, ev: Ev, ...args: Args) => any
+ onSuccess?: (ev: Ev, ...args: Args) => void
+ onError?: (error: Error, ev: Ev, ...args: Args) => void
+ onFinally?: (ev: Ev, ...args: Args) => void
+ delay?: number
+}): {
+ debouncedFn: (ev: Ev, ...args: Args) => void
+ cleanup: () => void
+}
+export function useDebouncedFn({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ onError,
+ onFinally,
+ delay,
+}: {
+ immediateCallback?: (...args: any[]) => void
+ callbackToBounce: (signal: AbortSignal, ...args: any[]) => any
+ onSuccess?: (...args: any[]) => void
+ onError?: (error: Error, ...args: any[]) => void
+ onFinally?: (...args: any[]) => void
+ delay?: number
+}) {
+ const paramsRef = useRef({
+ immediateCallback,
+ callbackToBounce,
+ onSuccess,
+ onError,
+ onFinally,
delay,
})
- const timerId = useRef()
-
- const debouncedCb = useRef({
- fn: (...args: Parameters) => {
- if (timerId.current) {
- clearTimeout(timerId.current)
- }
- timerId.current = setTimeout(() => paramsRef.current.cb.call(null, ...args), paramsRef.current.delay)
- },
- cleanup: () => clearTimeout(timerId.current),
- })
+
+ // tracking props with immutable object
+ paramsRef.current.delay = delay
+ paramsRef.current.callbackToBounce = callbackToBounce
+ paramsRef.current.immediateCallback = immediateCallback
+ paramsRef.current.onSuccess = onSuccess
+ paramsRef.current.onError = onError
+ paramsRef.current.onFinally = onFinally
+
+ // so can access the updated props inside debouncedFnWrapper function
+ const debouncedCb = useRef(debouncedFnWrapper(paramsRef.current))
useEffect(() => {
return () => {
@@ -34,24 +138,100 @@ export default function useDebouncedFn any>(cb: T,
}
}, [delay])
- return debouncedCb.current.fn
+ return debouncedCb.current
}
/**
* @description
- * A wrapper function which returns debounced version of passed callback.
- * If needed to work outside of react, then use this wrapper function.
+ * A React hook that returns a debounced version of any function, delaying its execution until after a specified delay has passed since the last time it was invoked.
+ *
+ * @example
+ import { useState, useEffect } from 'react'
+ import { useDebouncedFn } from 'classic-react-hooks'
+
+ export default function SearchInput() {
+ const [query, setQuery] = useState('')
+ const [results, setResults] = useState([])
+
+ const debouncedSearch = useDebouncedFn({
+ callbackToBounce: async (searchTerm: string) => {
+ if (searchTerm.trim()) {
+ const response = await fetch(`https://dummyjson.com/users/search?q=${searchTerm}`)
+ const data = await response.json()
+ setResults(data.results)
+ }
+ },
+ delay: 500,
+ })
+
+ const handleInputChange = (e: React.ChangeEvent) => {
+ const value = e.target.value
+ setQuery(value)
+ debouncedSearch(value)
+ }
+
+ useEffect(() => {
+ ;(async function () {
+ const response = await fetch(`https://dummyjson.com/users`)
+ const data = await response.json()
+ setResults(data.results)
+ })()
+ }, [])
+
+ return (
+
+
+
+ {results.map((result) => (
+
{result.name}
+ ))}
+
+
+ )
+ }
+ *
+ * @see Docs https://classic-react-hooks.vercel.app/hooks/use-debounced-fn.html
*/
-export function debouncedFnWrapper any>(cb: T, delay = DEFAULT_DELAY) {
- let timerId: NodeJS.Timeout
+export function debouncedFnWrapper any>(props: {
+ immediateCallback?: (...args: Parameters) => void
+ callbackToBounce: (signal: AbortSignal, ...args: Parameters) => any
+ onSuccess?: (...args: Parameters) => void
+ onError?: (error: Error, ...args: Parameters) => void
+ onFinally?: (...args: Parameters) => void
+ delay?: number
+}) {
+ let timerId: ReturnType
+ let controller: AbortController | null = null
return {
- fn: (...args: Parameters) => {
- if (timerId) {
- clearTimeout(timerId)
- }
- timerId = setTimeout(() => cb.call(null, ...args), delay)
+ debouncedFn: (...args: Parameters) => {
+ // Immediate phase
+ props.immediateCallback?.(...args)
+
+ // Cancel previous async work
+ controller?.abort()
+
+ if (timerId) clearTimeout(timerId)
+
+ controller = new AbortController()
+
+ timerId = setTimeout(async () => {
+ try {
+ await props.callbackToBounce.call(null, controller!.signal, ...args)
+ props.onSuccess?.(...args)
+ } catch (err) {
+ if ((err as DOMException).name !== 'AbortError') {
+ props.onError?.(err as Error, ...args)
+ }
+ } finally {
+ props.onFinally?.(...args)
+ }
+ }, props.delay ?? DEFAULT_DELAY)
+ },
+
+ cleanup: () => {
+ controller?.abort()
+ clearTimeout(timerId)
},
- cleanup: () => clearTimeout(timerId),
}
}
diff --git a/src/lib/use-event-listener/index.test.tsx b/src/lib/use-event-listener/index.test.tsx
index 5d4db95..463b3b5 100644
--- a/src/lib/use-event-listener/index.test.tsx
+++ b/src/lib/use-event-listener/index.test.tsx
@@ -1,99 +1,271 @@
-import { renderHook } from '@testing-library/react'
-import { vi } from 'vitest'
+import { fireEvent, render, renderHook, screen } from '@testing-library/react'
+import { expect, vi } from 'vitest'
import { useEventListener } from '.'
+import { ElementRef, useRef, useState } from 'react'
+import { EvTarget } from '../../types'
describe('use-event-listener', () => {
- it('should render', () => {
- renderHook(() => useEventListener(null, 'click', () => {}))
- })
-
- it('should add listener on-mount and remove it on un-mount', () => {
- const div = document.createElement('div')
- const addSpy = vi.spyOn(div, 'addEventListener')
- const removeSpy = vi.spyOn(div, 'removeEventListener')
-
- const { rerender, unmount } = renderHook(() => {
- useEventListener(
- () => div,
- 'resize',
- () => {},
- { passive: true }
+ describe('mounting', () => {
+ it('should render without errors', () => {
+ renderHook(() =>
+ useEventListener({
+ target: () => null,
+ event: 'click',
+ options: {},
+ })
)
+
+ // @ts-expect-error handling the edge case if target is not type of function
+ renderHook(() => useEventListener({ target: null, event: 'click' }))
+ })
+
+ it('should not add event if handler is not provided', () => {
+ const div = document.createElement('div')
+ const addSpy = vi.spyOn(div, 'addEventListener')
+ const removeSpy = vi.spyOn(div, 'removeEventListener')
+ const fn = vi.fn()
+
+ renderHook(() => {
+ useEventListener({
+ target: () => div,
+ event: 'click',
+ })
+ })
+
+ expect(addSpy).toHaveBeenCalledTimes(0)
+ expect(removeSpy).not.toHaveBeenCalled()
+
+ renderHook(() => {
+ useEventListener({
+ target: () => div,
+ event: 'click',
+ handler: fn,
+ options: { shouldInjectEvent: false },
+ })
+ })
+ expect(addSpy).toHaveBeenCalledTimes(0)
+ expect(removeSpy).not.toHaveBeenCalled()
+
+ renderHook(() => {
+ useEventListener({ target: () => null, event: 'click', handler: fn })
+ })
+ expect(addSpy).toHaveBeenCalledTimes(0)
+ expect(removeSpy).not.toHaveBeenCalled()
})
+ })
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ describe('unmounting', () => {
+ it('should remove event on-un-mount', () => {
+ const div = document.createElement('div')
+ const addSpy = vi.spyOn(div, 'addEventListener')
+ const removeSpy = vi.spyOn(div, 'removeEventListener')
+ const fn = vi.fn()
- rerender()
- expect(addSpy).toHaveBeenCalledTimes(2)
- expect(removeSpy).toHaveBeenCalledTimes(1)
+ const { unmount } = renderHook(() => {
+ useEventListener({ target: () => div, event: 'click', handler: fn })
+ })
- unmount()
- expect(addSpy).toHaveBeenCalledTimes(2)
- expect(removeSpy).toHaveBeenCalledTimes(2)
+ unmount()
+ expect(addSpy).toHaveBeenCalledTimes(1) // should be 1 on unmount
+ expect(removeSpy).toHaveBeenCalledTimes(1)
+ })
})
- it('should work with refs', () => {
- const div = document.createElement('div')
- const addSpy = vi.spyOn(div, 'addEventListener')
- const removeSpy = vi.spyOn(div, 'removeEventListener')
+ describe('event attach', () => {
+ it('should not re-add the event if the , and props are not changed', () => {
+ const div = document.createElement('div')
+ const addSpy = vi.spyOn(div, 'addEventListener')
+ const removeSpy = vi.spyOn(div, 'removeEventListener')
+
+ const fn = vi.fn()
- const ref = { current: div }
+ const { rerender } = renderHook(() => {
+ useEventListener({ target: () => div, event: 'click', handler: fn })
+ })
- const { rerender, unmount } = renderHook(() => {
- useEventListener(ref, 'resize', () => {}, { passive: true })
+ expect(addSpy).toHaveBeenCalledTimes(1)
+ rerender()
+ expect(addSpy).toHaveBeenCalledTimes(1)
+ expect(removeSpy).not.toHaveBeenCalled()
})
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ it('should re-run the effect if the , and props are changed', () => {
+ const div = document.createElement('div')
+ div.textContent = 'div'
+
+ const addSpy = vi.spyOn(div, 'addEventListener')
+ const removeSpy = vi.spyOn(div, 'removeEventListener')
+
+ const handler = vi.fn()
+ const t = () => div
+
+ const { rerender, unmount } = renderHook(
+ (props: {
+ capture: boolean
+ shouldInjectEvent: boolean
+ event: keyof DocumentEventMap
+ target: EvTarget
+ }) => {
+ useEventListener({
+ target: props.target,
+ event: props.event,
+ handler: handler,
+ options: {
+ capture: props.capture,
+ shouldInjectEvent: props.shouldInjectEvent,
+ },
+ })
+ },
+ { initialProps: { capture: true, target: t, event: 'click', shouldInjectEvent: true } }
+ )
+
+ expect(addSpy).toHaveBeenCalledTimes(1)
+
+ // re-render with updated options.capture prop
+ rerender({ capture: false, target: t, event: 'click', shouldInjectEvent: true })
+ expect(addSpy).toHaveBeenCalledTimes(2)
+ expect(removeSpy).toHaveBeenCalledTimes(1)
- rerender()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ // re-render with updated options.shouldInjectEvent prop
+ rerender({ shouldInjectEvent: false, target: t, event: 'click', capture: false })
+ expect(addSpy).toHaveBeenCalledTimes(2)
+ expect(removeSpy).toHaveBeenCalledTimes(2)
- unmount()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(1)
+ // re-render with updated event prop
+ rerender({ event: 'mousedown', shouldInjectEvent: true, capture: false, target: t })
+ expect(addSpy).toHaveBeenCalledTimes(3)
+ expect(removeSpy).toHaveBeenCalledTimes(2)
+
+ const div2 = document.createElement('div')
+ div2.textContent = 'div2'
+ const addSpy2 = vi.spyOn(div2, 'addEventListener')
+ const removeSpy2 = vi.spyOn(div2, 'removeEventListener')
+
+ // re-render with updated target
+ rerender({ target: () => div2, capture: false, event: 'mousedown', shouldInjectEvent: true })
+ expect(addSpy2).toHaveBeenCalledTimes(1)
+ expect(removeSpy).toHaveBeenCalledTimes(3) // remove old target event
+
+ // extra re-render test same target
+ rerender({ target: () => div2, capture: false, event: 'mousedown', shouldInjectEvent: true })
+ expect(addSpy2).toHaveBeenCalledTimes(1)
+
+ // unmount
+ expect(removeSpy2).not.toHaveBeenCalled()
+ unmount()
+ expect(addSpy2).toHaveBeenCalledTimes(1)
+ expect(removeSpy2).toHaveBeenCalledTimes(1)
+ })
})
- it('should fire listener on event trigger with proper context', () => {
- const div = document.createElement('div')
- const listener = vi.fn()
- renderHook(() => {
- useEventListener(div, 'click', listener, { passive: true })
+ describe('event trigger', () => {
+ it('should trigger event with proper event context', () => {
+ const div = document.createElement('div')
+ const fn = vi.fn()
+
+ renderHook(() => useEventListener({ target: () => div, event: 'click', handler: fn }))
+
+ const ev = new Event('click')
+
+ // first trigger
+ div.dispatchEvent(ev)
+ expect(fn).toHaveBeenCalledTimes(1)
+ expect(fn).toHaveBeenCalledWith(ev)
+
+ // second trigger
+ div.dispatchEvent(ev)
+ expect(fn).toHaveBeenCalledTimes(2)
+ expect(fn).toHaveBeenCalledWith(ev)
})
- const event = new Event('click')
- div.dispatchEvent(event)
+ it('should not trigger event after unmount', () => {
+ const div = document.createElement('div')
+ const fn = vi.fn()
- expect(listener).toHaveBeenCalledTimes(1)
- expect(listener).toHaveBeenCalledWith(event)
+ // const { unmount } = renderHook(() => useEventListener(() => div, 'click', handler))
+ const { unmount } = renderHook(() => useEventListener({ target: () => div, event: 'click', handler: fn }))
- div.dispatchEvent(event)
- expect(listener).toHaveBeenCalledTimes(2)
+ // unmount
+ unmount()
+
+ // test whether it is being triggered or not
+ const ev = new Event('click')
+ div.dispatchEvent(ev)
+ expect(fn).not.toHaveBeenCalled()
+ })
})
- it('should remove listener when shouldInjectEvent becomes false', () => {
- const div = document.createElement('div')
- const removeSpy = vi.spyOn(div, 'removeEventListener')
+ describe('integration with react component', () => {
+ it('should log the latest value of counter in handler', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useRef>(null))
+
+ const Wrapper = () => {
+ const [counter, setCounter] = useState(0)
+ useEventListener({
+ target: () => result.current.current,
+ event: 'click',
+ handler: () => {
+ fn(counter)
+ },
+ })
+
+ return (
+
+
setCounter((c) => c + 1)}>
+ update counter {counter}
+
+
+ log value
+
+
+ )
+ }
+
+ render( )
- const listener = vi.fn()
- const { rerender } = renderHook((shouldInjectEvent: boolean = true) => {
- useEventListener(div, 'click', listener, { passive: true, shouldInjectEvent })
+ fireEvent.click(screen.getByTestId('btn'))
+ result.current.current?.click()
+ expect(fn).toHaveBeenNthCalledWith(1, 1)
+
+ fireEvent.click(screen.getByTestId('btn'))
+ result.current.current?.click()
+ expect(fn).toHaveBeenNthCalledWith(2, 2)
})
- const event = new Event('click')
- div.dispatchEvent(event)
+ it('should be able to set target using `setElementRef` function', () => {
+ const fn = vi.fn()
+
+ const Wrapper = () => {
+ const [counter, setCounter] = useState(0)
+ const { setElementRef } = useEventListener({
+ event: 'click',
+ handler: () => {
+ fn(counter)
+ },
+ })
- expect(listener).toHaveBeenCalledTimes(1)
- expect(listener).toHaveBeenCalledWith(event)
+ return (
+
+
setCounter((c) => c + 1)}>
+ update counter {counter}
+
+
+ log value
+
+
+ )
+ }
- rerender(false)
- expect(listener).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(1)
+ render( )
- // check whether event is cleanup or not
- div.dispatchEvent(event)
- expect(listener).toHaveBeenCalledTimes(1)
+ fireEvent.click(screen.getByTestId('btn'))
+ fireEvent.click(screen.getByTestId('log'))
+ expect(fn).toHaveBeenNthCalledWith(1, 1)
+
+ fireEvent.click(screen.getByTestId('btn'))
+ fireEvent.click(screen.getByTestId('log'))
+ expect(fn).toHaveBeenNthCalledWith(2, 2)
+ })
})
})
diff --git a/src/lib/use-event-listener/index.tsx b/src/lib/use-event-listener/index.tsx
index cac6d67..96743d2 100644
--- a/src/lib/use-event-listener/index.tsx
+++ b/src/lib/use-event-listener/index.tsx
@@ -1,70 +1,129 @@
-'use client'
-import type { Prettify } from '../../types'
-import React, { RefObject, useEffect } from 'react'
-import useSyncedRef from '../use-synced-ref'
+import type { EvHandler, EvOptions, EvTarget, UseEventListenerReturnValues } from '../../types'
-export type Target = null | EventTarget | RefObject | (() => EventTarget | null)
-export type Options = boolean | Prettify
-export type Handler = (event: Event) => void
+import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
+import useSyncedRef from '../use-synced-ref'
/* Have taken reference from ChakraUI's use-event-listener for typing out the props in type-safe manner. */
/**
* @description
- * A hook which handles dom events in efficient and declarative manner.
+ * A React hook that makes it easy to attach DOM event listeners declaratively with automatic cleanup.
+ *
+ * @example
+ import { useEventListener } from 'classic-react-hooks'
+
+ export default function ClickExample() {
+
+ const {setElementRef} = useEventListener({
+ event: 'click',
+ handler: (e) => {
+ console.log('Button clicked!', e)
+ },
+ })
+
+ return Click me
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-event-listener.html
*/
-export function useEventListener(
- target: Target,
- event: K,
- handler?: (event: DocumentEventMap[K]) => void,
- options?: Options
-): void
-export function useEventListener(
- target: Target,
- event: K,
- handler?: (event: WindowEventMap[K]) => void,
- options?: Options
-): void
-export function useEventListener(
- target: Target,
- event: K,
- handler?: (event: GlobalEventHandlersEventMap[K]) => void,
- options?: Options
-): void
-export function useEventListener(target: Target, event: string, handler?: Handler, options?: Options) {
+export function useEventListener({
+ target,
+ event,
+ handler,
+ options,
+ layoutEffect,
+}: {
+ target?: EvTarget
+ event: K
+ handler?: (event: DocumentEventMap[K]) => void
+ options?: EvOptions
+ layoutEffect?: boolean
+}): UseEventListenerReturnValues
+export function useEventListener({
+ target,
+ event,
+ handler,
+ options,
+ layoutEffect,
+}: {
+ target?: EvTarget
+ event: K
+ handler?: (event: WindowEventMap[K]) => void
+ options?: EvOptions
+ layoutEffect?: boolean
+}): UseEventListenerReturnValues
+export function useEventListener({
+ target,
+ event,
+ handler,
+ options,
+ layoutEffect,
+}: {
+ target?: EvTarget
+ event: K
+ handler?: (event: GlobalEventHandlersEventMap[K]) => void
+ options?: EvOptions
+ layoutEffect?: boolean
+}): UseEventListenerReturnValues
+export function useEventListener({
+ target,
+ event,
+ handler,
+ options,
+ layoutEffect,
+}: {
+ target?: EvTarget
+ event: string
+ handler?: EvHandler
+ options?: EvOptions
+ layoutEffect?: boolean
+}) {
+ // Determining which hook to use -> layout or effect
+ const useSelectedHook = layoutEffect ? useLayoutEffect : useEffect
+
+ const [elementNode, setElementNode] = useState(null)
+
+ const setElementRef = useRef((elementNode: HTMLElement | null) => {
+ setElementNode(elementNode)
+ })
+
const listener = useSyncedRef({
handler,
options,
- })
- let shouldInjectEvent = true
- if (typeof options == 'object' && 'shouldInjectEvent' in options) {
- shouldInjectEvent = !!options.shouldInjectEvent
- }
-
- useEffect(() => {
- const node = typeof target === 'function' ? target() : target
+ effectCb: () => {
+ if (!shouldInjectEvent || !listener.current.handler || !elementNode) return
- if (!listener.current.handler || !node) return
+ const callback = (e: Event) => listener.current.handler?.(e)
+ elementNode.addEventListener(event, callback, listener.current.options)
- const callback = (e: Event) => listener.current.handler?.(e)
- const options = listener.current.options
-
- if (shouldInjectEvent) {
- if ('current' in node) {
- node.current?.addEventListener(event, callback, options)
- } else {
- node.addEventListener(event, callback, options)
+ return () => {
+ elementNode.removeEventListener(event, callback, listener.current.options)
}
+ },
+ })
+ let shouldInjectEvent = true,
+ capture,
+ once,
+ passive,
+ signal
+
+ if (typeof options == 'object') {
+ if ('shouldInjectEvent' in options) {
+ shouldInjectEvent = !!options.shouldInjectEvent
}
+ capture = options.capture
+ once = options.once
+ passive = options.passive
+ signal = options.signal
+ }
- return () => {
- if ('current' in node) {
- node.current?.removeEventListener(event, callback, options)
- } else {
- node.removeEventListener(event, callback, options)
- }
+ useEffect(() => {
+ if (typeof target == 'function' && shouldInjectEvent) {
+ setElementRef.current(target() as HTMLElement)
}
- }, [event, target, shouldInjectEvent])
+ }, [target, shouldInjectEvent])
+
+ useSelectedHook(listener.current.effectCb, [elementNode, event, shouldInjectEvent, capture, once, passive, signal])
+
+ return { setElementRef: setElementRef.current }
}
diff --git a/src/lib/use-intersection-observer/index.test.tsx b/src/lib/use-intersection-observer/index.test.tsx
index 6ea0b43..789e18e 100644
--- a/src/lib/use-intersection-observer/index.test.tsx
+++ b/src/lib/use-intersection-observer/index.test.tsx
@@ -1,41 +1,409 @@
-import { renderHook } from '@testing-library/react'
-import { vi } from 'vitest'
-import useInterSectionObserver from '.'
+import { act, render, renderHook, screen } from '@testing-library/react'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-describe('use-intersection-observer', () => {
- const InitialObserver = global.IntersectionObserver
-
- let IntersectionObserverSpy = vi.fn(() => ({
- observe: vi.fn(),
- unobserve: vi.fn(),
- disconnect: vi.fn(),
- takeRecords: () => [],
- root: document,
- rootMargin: '0px',
- thresholds: [0],
+import useIntersectionObserver from '.'
+
+// Mock IntersectionObserver
+const mockIntersectionObserver = vi.fn()
+const mockObserve = vi.fn()
+const mockUnobserve = vi.fn()
+const mockDisconnect = vi.fn()
+
+beforeEach(() => {
+ mockIntersectionObserver.mockImplementation((callback) => ({
+ observe: mockObserve,
+ unobserve: mockUnobserve,
+ disconnect: mockDisconnect,
+ // Store callback for manual triggering
+ _callback: callback,
}))
- beforeAll(() => {
- global.IntersectionObserver = IntersectionObserverSpy
+ // Mock window.IntersectionObserver
+ Object.defineProperty(window, 'IntersectionObserver', {
+ writable: true,
+ configurable: true,
+ value: mockIntersectionObserver,
})
+})
+
+afterEach(() => {
+ vi.clearAllMocks()
+})
+
+// Helper function to trigger intersection
+const forcefullyTriggerIntersection = (entry?: Partial, mockIndex = 0) => {
+ const mockInstance = mockIntersectionObserver.mock.results[mockIndex]?.value
+ mockInstance._callback([
+ {
+ isIntersecting: !!entry?.isIntersecting,
+ target: entry?.target || document.createElement('div'),
+ },
+ ])
+}
+
+describe('use-intersection-observer', () => {
+ describe('basic functionality', () => {
+ it('should return correct default property names when no key is provided', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+
+ expect(result.current).toHaveProperty('setElementRef')
+ expect(result.current).toHaveProperty('isElementIntersecting')
+ expect(result.current).toHaveProperty('element')
+ expect(typeof result.current.setElementRef).toBe('function')
+ expect(typeof result.current.isElementIntersecting).toBe('boolean')
+ expect(result.current.element).toBeNull()
+ })
+
+ it('should return correct property names when key is provided', () => {
+ const { result } = renderHook(() => useIntersectionObserver({ key: 'hero' }))
+
+ expect(result.current).toHaveProperty('setHeroElementRef')
+ expect(result.current).toHaveProperty('isHeroElementIntersecting')
+ expect(result.current).toHaveProperty('heroElement')
+ expect(typeof result.current.setHeroElementRef).toBe('function')
+ expect(typeof result.current.isHeroElementIntersecting).toBe('boolean')
+ expect(result.current.heroElement).toBeNull()
+ })
- afterAll(() => {
- global.IntersectionObserver = InitialObserver
+ it('should initialize with default state', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+
+ expect(result.current.element).toBeNull()
+ expect(result.current.isElementIntersecting).toBe(false)
+ })
})
- it('should run without error', () => {
- const div = document.createElement('div')
+ describe('element reference management', () => {
+ it('should update element when setElementRef is called', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(result.current.element).toBe(mockElement)
+ })
+
+ it('should handle null element', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(result.current.element).toBe(mockElement)
- renderHook(() => useInterSectionObserver([div]))
+ act(() => {
+ result.current.setElementRef(null)
+ })
+
+ expect(result.current.element).toBeNull()
+ })
})
- it('should call disconnect on un-mount', () => {
- const div = document.createElement('div')
+ describe('IntersectionObserver integration', () => {
+ it('should not create observer when element is null', () => {
+ renderHook(() => useIntersectionObserver())
+
+ expect(mockIntersectionObserver).not.toHaveBeenCalled()
+ })
+
+ it('should create observer when element is set', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(mockIntersectionObserver).toHaveBeenCalledWith(
+ expect.any(Function),
+ expect.objectContaining({
+ root: undefined,
+ rootMargin: undefined,
+ threshold: undefined,
+ })
+ )
+ expect(mockObserve).toHaveBeenCalledWith(mockElement)
+ })
+
+ it('should pass through IntersectionObserver options', () => {
+ const { result } = renderHook(() =>
+ useIntersectionObserver({
+ root: document.body,
+ rootMargin: '10px',
+ threshold: 0.5,
+ })
+ )
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(mockIntersectionObserver).toHaveBeenCalledWith(
+ expect.any(Function),
+ expect.objectContaining({
+ root: document.body,
+ rootMargin: '10px',
+ threshold: 0.5,
+ })
+ )
+ })
+
+ it('should update intersection state when observer triggers', () => {
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(result.current.isElementIntersecting).toBe(false)
+
+ // forcefully updating the state
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true })
+ })
+
+ expect(result.current.isElementIntersecting).toBe(true)
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: false })
+ })
+
+ expect(result.current.isElementIntersecting).toBe(false)
+ })
+
+ it('should disconnect observer on cleanup', () => {
+ const { result, unmount } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ unmount()
+
+ expect(mockDisconnect).toHaveBeenCalled()
+ })
+
+ it('should reset intersection state on cleanup', () => {
+ const { result, rerender } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true })
+ })
+
+ expect(result.current.isElementIntersecting).toBe(true)
+
+ // Trigger cleanup by changing element
+ act(() => {
+ result.current.setElementRef(null)
+ })
+
+ rerender()
+
+ expect(result.current.isElementIntersecting).toBe(false)
+ })
+ })
+
+ describe('onIntersection callback', () => {
+ it('should call onIntersection callback when intersection occurs', () => {
+ const onIntersection = vi.fn()
+ const { result } = renderHook(() => useIntersectionObserver({ onIntersection }))
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ act(() => {
+ forcefullyTriggerIntersection({ target: mockElement })
+ })
+
+ expect(onIntersection).toHaveBeenCalledWith({ target: mockElement, isIntersecting: false })
+ })
+
+ it('should handle callback updates', () => {
+ const callback1 = vi.fn()
+ const callback2 = vi.fn()
+
+ const { result, rerender } = renderHook(
+ ({ callback }) => useIntersectionObserver({ onIntersection: callback }),
+ { initialProps: { callback: callback1 } }
+ )
+
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ // Update callback
+ rerender({ callback: callback2 })
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true, target: mockElement })
+ })
+
+ expect(callback1).not.toHaveBeenCalled()
+ expect(callback2).toHaveBeenCalledWith({ target: mockElement, isIntersecting: true })
+ })
+ })
+
+ describe('onlyTriggerOnce option', () => {
+ it('should unobserve element when onlyTriggerOnce is true', () => {
+ const { result } = renderHook(() => useIntersectionObserver({ onlyTriggerOnce: true }))
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true, target: mockElement })
+ })
+
+ expect(mockUnobserve).toHaveBeenCalledWith(mockElement)
+ })
+
+ it('should not unobserve when onlyTriggerOnce is false', () => {
+ const { result } = renderHook(() => useIntersectionObserver({ onlyTriggerOnce: false }))
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true, target: mockElement })
+ })
+
+ expect(mockUnobserve).not.toHaveBeenCalled()
+ })
+ })
+
+ // gracefully handling un-availability of the API
+ describe('IntersectionObserver availability', () => {
+ it('should warn when IntersectionObserver is not available', () => {
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+
+ let copiedObserver = window.IntersectionObserver
+ // @ts-expect-error Deleting the observer
+ window.IntersectionObserver = undefined
+
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(consoleSpy).toHaveBeenCalledWith('IntersectionObserver is not available.')
+
+ consoleSpy.mockRestore()
+ window.IntersectionObserver = copiedObserver
+ })
+ it('should not log out warning in Production environment', () => {
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
+
+ process.env.NODE_ENV = 'production'
+
+ let copiedObserver = window.IntersectionObserver
+ // @ts-expect-error Deleting the observer
+ window.IntersectionObserver = undefined
+
+ const { result } = renderHook(() => useIntersectionObserver())
+ const mockElement = document.createElement('div')
+
+ act(() => {
+ result.current.setElementRef(mockElement)
+ })
+
+ expect(consoleSpy).not.toHaveBeenCalledWith('IntersectionObserver is not available.')
+ consoleSpy.mockRestore()
+ window.IntersectionObserver = copiedObserver
+ })
+ })
+
+ describe('TypeScript type safety', () => {
+ it('should provide correct types for different key configurations', () => {
+ // Test with no key
+ const { result: result1 } = renderHook(() => useIntersectionObserver())
+
+ // should be accessible without TypeScript errors
+ result1.current.element
+ result1.current.setElementRef
+ result1.current.isElementIntersecting
+
+ // Test with key
+ const { result: result2 } = renderHook(() => useIntersectionObserver({ key: 'header' }))
+
+ // should be accessible without TypeScript errors
+ result2.current.headerElement
+ result2.current.setHeaderElementRef
+ result2.current.isHeaderElementIntersecting
+ })
+ })
+})
+
+// Integration test component
+function TestComponent({ hookKey }: { hookKey?: string }) {
+ const observer = hookKey ? useIntersectionObserver({ key: hookKey as any }) : useIntersectionObserver()
+
+ return (
+
+
+ Observed Element
+
+
+ {hookKey
+ ? String((observer as any)[`is${hookKey.charAt(0).toUpperCase()}${hookKey.slice(1)}ElementIntersecting`])
+ : String(observer.isElementIntersecting)}
+
+
+ )
+}
+
+describe('use-intersection-observer integration tests', () => {
+ it('should work in a real component without key', () => {
+ render( )
+
+ expect(screen.getByTestId('observed-element')).toBeInTheDocument()
+ expect(screen.getByTestId('intersection-status')).toHaveTextContent('false')
+
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true })
+ })
+
+ expect(screen.getByTestId('intersection-status')).toHaveTextContent('true')
+ })
+
+ it('should work in a real component with key', () => {
+ render( )
+
+ expect(screen.getByTestId('observed-element')).toBeInTheDocument()
+ expect(screen.getByTestId('intersection-status')).toHaveTextContent('false')
- const { unmount } = renderHook(() => useInterSectionObserver([div]))
+ act(() => {
+ forcefullyTriggerIntersection({ isIntersecting: true })
+ })
- expect(IntersectionObserverSpy.mock.results[0]?.value.disconnect).toHaveBeenCalledTimes(0)
- unmount()
- expect(IntersectionObserverSpy.mock.results[0]?.value.disconnect).toHaveBeenCalledTimes(1)
+ expect(screen.getByTestId('intersection-status')).toHaveTextContent('true')
})
})
diff --git a/src/lib/use-intersection-observer/index.tsx b/src/lib/use-intersection-observer/index.tsx
index 10fcfe9..ebeb458 100644
--- a/src/lib/use-intersection-observer/index.tsx
+++ b/src/lib/use-intersection-observer/index.tsx
@@ -1,93 +1,139 @@
-import type { RefObject } from 'react'
import type { Prettify } from '../../types'
-import { useState, useEffect } from 'react'
+import { useEffect, useRef, useState } from 'react'
+import { capitalizeFirstLetter } from '../../utils/capitalize-first-letter'
+import useSyncedRef from '../use-synced-ref'
-export type Target = HTMLElement | RefObject | (() => HTMLElement | null) | null
+export interface BaseIntersectionObserverOptions {
+ onIntersection?: (entry: IntersectionObserverEntry) => void
+ onlyTriggerOnce?: boolean
+}
+
+// prettier-ignore
+export interface IntersectionObserverOptions extends IntersectionObserverInit, BaseIntersectionObserverOptions {
+ key?: Key
+}
-type Options = {
- mode?: 'lazy' | 'virtualized'
-} & IntersectionObserverInit
+export type IntersectionObserverResult = Prettify<
+ {
+ [K in Key as Key extends '' ? 'element' : `${Key}Element`]: HTMLElement | null // element
+ } & {
+ [K in Key as Key extends '' ? 'setElementRef' : `set${Capitalize}ElementRef`]: (
+ elementNode: HTMLElement | null
+ ) => void // setElement
+ } & {
+ [K in Key as Key extends '' ? 'isElementIntersecting' : `is${Capitalize}ElementIntersecting`]: boolean // isElementIntersecting
+ }
+>
/**
* @description
- * A hook which provides a way for listening to the Intersection Observer event for given target.
+ * A React hook that provides a declarative way to observe element visibility using the [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) API.
*
- * It takes an array of targets and returns an array of boolean values which represents whether the targets are intersecting the screen or not.
+ * @example
+ import { useIntersectionObserver } from 'classic-react-hooks'
+
+ export default function BasicExample() {
+ const { element, setElementRef, isElementIntersecting } = useIntersectionObserver({
+ threshold: 0.5,
+ onIntersection: (entry) => {
+ console.log('Intersection changed:', entry.isIntersecting)
+ },
+ })
+
+ return (
+
+
+
+ {isElementIntersecting ? 'Visible!' : 'Not visible'}
+
+
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-intersection-observer.html
*/
-export default function useInterSectionObserver(targets: Target[], options: Prettify = {}): Array {
- const [visibilityStates, setVisiblilityStates] = useState(() => {
- return new Array(targets.length).fill(false) as Array
- })
+export default function useIntersectionObserver(
+ options?: IntersectionObserverOptions
+): IntersectionObserverResult {
+ const {
+ key = '' as Key,
+ onIntersection,
+ onlyTriggerOnce = false,
+ root,
+ rootMargin,
+ threshold,
+ ...restOptions
+ } = options ?? {}
- const intersection_options: IntersectionObserverInit = {
- root: options.root,
- rootMargin: options.rootMargin,
- threshold: options.threshold,
- }
+ const [element, setElement] = useState(null)
+ const [isIntersecting, setIsIntersecting] = useState(false)
- if (!options.mode) {
- options.mode = 'lazy'
- }
+ const onIntersectionRef = useSyncedRef(onIntersection)
+ const observerOptions = useSyncedRef({
+ root,
+ rootMargin,
+ threshold,
+ ...restOptions,
+ })
+
+ const setElementRef = useRef((elementNode: HTMLElement | null) => {
+ setElement(elementNode)
+ })
useEffect(() => {
if (!window.IntersectionObserver) {
- console.warn('IntersectionObserver is not available.')
+ if (process.env.NODE_ENV !== 'production') {
+ console.warn('IntersectionObserver is not available.')
+ }
return
}
- const io = new IntersectionObserver((entries) => {
- entries.forEach((entry) => {
- const entry_idx = entry.target.getAttribute('idx')
- if (entry.isIntersecting) {
- setVisiblilityStates((_visibilityState) => {
- if (entry_idx == null) return _visibilityState
-
- _visibilityState[+entry_idx] = true
- return [..._visibilityState]
- })
- if (options.mode == 'lazy') {
- io.unobserve(entry.target)
- }
- } else {
- setVisiblilityStates((_visibilityState) => {
- if (entry_idx == null) return _visibilityState
-
- _visibilityState[+entry_idx] = false
- return [..._visibilityState]
- })
- }
- })
- }, intersection_options)
-
- targets.forEach((element, idx) => observer(element, idx))
-
- function observer(element: Target, idx: number) {
- let target: HTMLElement | null = null
-
- try {
- if (element && 'current' in element) {
- target = element.current
- } else if (typeof element == 'function') {
- const ele = element()
- target = ele
- } else {
- target = element
+
+ if (!element) {
+ return
+ }
+
+ const observer = new IntersectionObserver((entries) => {
+ for (const entry of entries) {
+ const isCurrentlyIntersecting = entry.isIntersecting
+
+ setIsIntersecting(entry.isIntersecting)
+
+ // trigger onIntersection callback after intersection/non-intersection of the element
+ if (onIntersectionRef.current) {
+ onIntersectionRef.current?.(entry)
}
- if (target) {
- target.setAttribute('idx', idx.toString())
- io.observe(target)
+
+ // handle onlyTriggerOnce
+ if (onlyTriggerOnce && isCurrentlyIntersecting) {
+ observer.unobserve(entry.target)
+ observer.disconnect()
}
- } catch (err) {
- console.warn(err)
}
- }
+ }, observerOptions.current)
+
+ observer.observe(element)
return () => {
- io.disconnect()
+ if (element) {
+ observer.unobserve(element)
+ observer.disconnect()
+ }
+ setIsIntersecting(false)
}
- }, [])
+ }, [element, onlyTriggerOnce])
+
+ const capKey = key ? capitalizeFirstLetter(key) : ''
+ const propertyNames = {
+ elementKey: key ? `${key}Element` : 'element',
+ setRefKey: key ? `set${capKey}ElementRef` : 'setElementRef',
+ isIntersectingKey: key ? `is${capKey}ElementIntersecting` : 'isElementIntersecting',
+ }
- return visibilityStates
+ return {
+ [propertyNames.setRefKey]: setElementRef.current,
+ [propertyNames.isIntersectingKey]: isIntersecting,
+ [propertyNames.elementKey]: element,
+ } as IntersectionObserverResult
}
diff --git a/src/lib/use-interval-effect/index.test.tsx b/src/lib/use-interval-effect/index.test.tsx
index a3cafdd..8355f5f 100644
--- a/src/lib/use-interval-effect/index.test.tsx
+++ b/src/lib/use-interval-effect/index.test.tsx
@@ -8,65 +8,273 @@ describe('use-interval-effect', () => {
})
afterEach(() => {
vi.useRealTimers()
- })
- afterEach(() => {
vi.clearAllTimers()
})
- it('should fire callback with default interval of 100ms after the mount', () => {
- const fn = vi.fn()
- renderHook(() => useIntervalEffect(fn))
+ describe('mounting', () => {
+ it('should fire callback with default interval of 100ms after the mount', () => {
+ const fn = vi.fn()
+ renderHook(() => useIntervalEffect({ handler: fn }))
+
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(99)
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(1) // Total 100ms
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ vi.advanceTimersByTime(100) // Total 200ms
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
+
+ it('should fire callback after the given interval', () => {
+ const fn = vi.fn()
+ renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(499)
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(1) // Total 500ms
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ vi.advanceTimersByTime(500) // Total 1000ms
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
- expect(fn).toHaveBeenCalledTimes(0)
- vi.advanceTimersByTime(100)
- expect(fn).toHaveBeenCalledTimes(1)
+ it('should fire callback multiple times at regular intervals', () => {
+ const fn = vi.fn()
+ renderHook(() => useIntervalEffect({ handler: fn, interval: 200 }))
+
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(2)
+
+ vi.advanceTimersByTime(400) // two more intervals
+ expect(fn).toHaveBeenCalledTimes(4)
+ })
})
- it('should fire callback after the given interval', () => {
- const fn = vi.fn()
- renderHook(() => useIntervalEffect(fn, 500))
+ describe('unmounting', () => {
+ it('should clear interval on unmount', () => {
+ const fn = vi.fn()
+ const { unmount } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ vi.advanceTimersByTime(400) // Before first interval
+ unmount()
+ vi.advanceTimersByTime(1000) // Advance past where intervals would have fired
+ expect(fn).not.toHaveBeenCalled()
+ })
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(1)
+ it('should not interfere with callback execution if unmounted after an interval has fired', () => {
+ const fn = vi.fn()
+ const { unmount } = renderHook(() => useIntervalEffect({ handler: fn, interval: 100 }))
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(2)
+ vi.advanceTimersByTime(100)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ unmount()
+ vi.advanceTimersByTime(1000)
+ expect(fn).toHaveBeenCalledTimes(1) // Should not fire again
+ })
})
- it('should clear the interval with clearTimer', () => {
- const fn = vi.fn()
- const { result } = renderHook(() => useIntervalEffect(fn, 500))
+ describe('clearTimer functionality', () => {
+ it('should clear the interval with clearTimer', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ vi.advanceTimersByTime(200)
+ result.current.clearTimer()
+ vi.advanceTimersByTime(1000)
+ expect(fn).not.toHaveBeenCalled()
+ })
+
+ it('should allow clearing timer multiple times without error', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
- result.current.clearTimer()
- vi.advanceTimersByTime(500)
- expect(fn).not.toHaveBeenCalled()
+ result.current.clearTimer()
+ result.current.clearTimer()
+ result.current.clearTimer()
+
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+ })
+
+ it('should clear the interval when prop changes', () => {
+ const fn = vi.fn()
+
+ let interval = 300
+ const { rerender } = renderHook(() => useIntervalEffect({ handler: fn, interval }))
+
+ vi.advanceTimersByTime(200)
+ expect(fn).not.toHaveBeenCalled()
+
+ // Change interval, this should clear the old one and set a new one
+ interval = 500
+ rerender()
+
+ vi.advanceTimersByTime(200) // Advance remaining time for old 300ms interval (100ms) + 100ms for new 500ms interval
+ expect(fn).not.toHaveBeenCalled() // Old 300ms interval shouldn't fire
+
+ vi.advanceTimersByTime(300) // Remaining for new 500ms interval
+ expect(fn).toHaveBeenCalledTimes(1) // New 500ms interval fires
+
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
})
- it('should set the interval with restartTimer', () => {
- const fn = vi.fn()
- const { result } = renderHook(() => useIntervalEffect(fn, 500))
+ describe('restartTimer functionality', () => {
+ it('should restart timer with original interval', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ // Let original timer fire once
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ // Clear and restart timer
+ result.current.restartTimer()
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(2)
+
+ // It should continue to fire
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(3)
+ })
+
+ it('should restart timer with new interval value provided in restartTimer function', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ // Restart with new interval before original fires
+ vi.advanceTimersByTime(200) // partially advance original 500ms interval
+ result.current.restartTimer(600)
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(1)
+ // Original interval should not fire at 500ms
+ vi.advanceTimersByTime(300) // This would have been 500ms for original
+ expect(fn).not.toHaveBeenCalled()
- result.current.clearTimer()
- vi.advanceTimersByTime(500)
- vi.advanceTimersByTime(500)
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(1)
+ // New 600ms interval should fire
+ vi.advanceTimersByTime(300) // 300 + 300 = 600ms for new interval
+ expect(fn).toHaveBeenCalledTimes(1)
- // restart
- result.current.restartTimer()
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(2)
+ // New 600ms interval should fire again
+ vi.advanceTimersByTime(600)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
+
+ it('should restart timer with original value after overriding with restartTimer(new_interval)', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ vi.advanceTimersByTime(200)
+ result.current.restartTimer(600) // Override with 600ms
+
+ vi.advanceTimersByTime(600)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ // Now restart without arguments, it should pick up the original interval (500ms)
+ result.current.restartTimer()
+
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(2)
+
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(3)
+ })
+
+ it('should cancel previous timer when restarting', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ // Restart before original interval
+ vi.advanceTimersByTime(200)
+ result.current.restartTimer() // Should restart with 500ms
+
+ // Advance to where original would have fired
+ vi.advanceTimersByTime(300)
+ expect(fn).not.toHaveBeenCalled() // Original 500ms interval should be cancelled
+
+ // Advance to where restarted timer should fire
+ vi.advanceTimersByTime(200) // 300 + 200 = 500ms from restart
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
+
+ it('should handle restart followed by clear', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useIntervalEffect({ handler: fn, interval: 500 }))
+
+ result.current.restartTimer() // Starts a new 500ms interval
+ result.current.clearTimer() // Clears it immediately
+ vi.advanceTimersByTime(1000)
+ expect(fn).not.toHaveBeenCalled()
+
+ // Should be able to restart again after clearing
+ result.current.restartTimer(200)
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
})
- it('should clear interval on unmount', () => {
- const fn = vi.fn()
- const { unmount, result } = renderHook(() => useIntervalEffect(fn, 500))
- // cleanup the timer
- vi.advanceTimersByTime(400)
- unmount()
- expect(fn).toHaveBeenCalledTimes(0)
+ describe('parameter updates', () => {
+ it('should use latest handler when interval fires', () => {
+ const fn1 = vi.fn()
+ const fn2 = vi.fn()
+ let currentHandler = fn1
+
+ const { rerender } = renderHook(() => useIntervalEffect({ handler: currentHandler, interval: 500 }))
+
+ // Update handler before first interval fires
+ vi.advanceTimersByTime(200)
+ currentHandler = fn2
+ rerender()
+
+ vi.advanceTimersByTime(300) // First interval fires
+ expect(fn1).not.toHaveBeenCalled()
+ expect(fn2).toHaveBeenCalledTimes(1)
+
+ vi.advanceTimersByTime(500) // Second interval fires
+ expect(fn2).toHaveBeenCalledTimes(2)
+ })
+
+ it('should use latest interval value for restartTimer', () => {
+ const fn = vi.fn()
+ let currentInterval = 500
+
+ const { result, rerender } = renderHook(() => useIntervalEffect({ handler: fn, interval: currentInterval }))
+
+ // Update interval and restart
+ currentInterval = 200
+ rerender() // This will clear the existing interval and set up a new one with 200ms
+ result.current.restartTimer() // This should restart with the *latest* prop value (200ms)
+
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
+ })
+
+ describe('error handling', () => {
+ it('should not throw when handler throws an error', () => {
+ const errorHandler = vi.fn(() => {
+ throw new Error('Test error')
+ })
+
+ // Vitest's fake timers will re-throw the error when advanceTimersByTime is called
+ // if the handler within the timer throws. So we wrap it in a try/catch or expect to throw.
+ const { rerender } = renderHook(() => useIntervalEffect({ handler: errorHandler, interval: 100 }))
+
+ expect(() => {
+ vi.advanceTimersByTime(100)
+ }).toThrow('Test error')
+ expect(errorHandler).toHaveBeenCalledTimes(1)
+ })
})
})
diff --git a/src/lib/use-interval-effect/index.tsx b/src/lib/use-interval-effect/index.tsx
index ae18fdb..df2d6e8 100644
--- a/src/lib/use-interval-effect/index.tsx
+++ b/src/lib/use-interval-effect/index.tsx
@@ -1,16 +1,38 @@
-'use client'
import React, { useEffect, useRef } from 'react'
import useSyncedRef from '../use-synced-ref'
/**
* @description
- * A hook which fires the provided callback every time when the given interval is passed, just like the setInterval.
+ * A React hook that executes a callback function at regular intervals, similar to `setInterval` but with additional control methods for clearing and restarting the timer.
+ *
+ * @example
+ import { useState } from 'react'
+ import { useIntervalEffect } from 'classic-react-hooks'
+
+ export default function Counter() {
+ const [count, setCount] = useState(0)
+
+ const { clearTimer, restartTimer } = useIntervalEffect({
+ handler: () => setCount((prev) => prev + 1),
+ interval: 1000, // 1 second
+ })
+
+ return (
+
+
Count: {count}
+ Pause
+ restartTimer()}>Resume
+ restartTimer(500)}>Speed Up (500ms)
+ restartTimer(2000)}>Slow Down (2s)
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-interval-effect.html
*/
-export default function useIntervalEffect(cb: () => void, interval = 100) {
+export default function useIntervalEffect({ handler, interval = 100 }: { handler: () => void; interval?: number }) {
let paramsRef = useSyncedRef({
- cb,
+ handler,
interval,
})
const intervalId = useRef()
@@ -19,14 +41,14 @@ export default function useIntervalEffect(cb: () => void, interval = 100) {
clearTimer: () => clearInterval(intervalId.current),
restartTimer: (new_interval?: number) => {
handlers.current.clearTimer()
- intervalId.current = setInterval(paramsRef.current.cb, new_interval ?? paramsRef.current.interval)
+ intervalId.current = setInterval(() => paramsRef.current.handler(), new_interval ?? paramsRef.current.interval)
},
})
useEffect(() => {
- intervalId.current = setInterval(paramsRef.current.cb, paramsRef.current.interval)
+ intervalId.current = setInterval(() => paramsRef.current.handler(), interval)
return handlers.current.clearTimer
- }, [])
+ }, [interval])
return {
clearTimer: handlers.current.clearTimer,
diff --git a/src/lib/use-is-online/index.tsx b/src/lib/use-is-online/index.tsx
deleted file mode 100644
index fb1f445..0000000
--- a/src/lib/use-is-online/index.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-'use client'
-import React, { useSyncExternalStore } from 'react'
-
-/**
- * @description
- * A simple hook for getting the network connection state.
- *
- * @see Docs https://classic-react-hooks.vercel.app/hooks/use-is-online.html
- */
-export default function useIsOnline() {
- return useSyncExternalStore(subscribe, getSnapshot, () => true)
-}
-
-function subscribe(callback: () => void) {
- window.addEventListener('online', callback)
- window.addEventListener('offline', callback)
-
- return () => {
- window.addEventListener('online', callback)
- window.addEventListener('offline', callback)
- }
-}
-const getSnapshot = () => navigator.onLine
diff --git a/src/lib/use-local-storage/index.test.tsx b/src/lib/use-local-storage/index.test.tsx
index 1a153b9..f1dfa52 100644
--- a/src/lib/use-local-storage/index.test.tsx
+++ b/src/lib/use-local-storage/index.test.tsx
@@ -1,58 +1,840 @@
-import { act, renderHook } from '@testing-library/react'
-import useLocalStorage from '.'
+import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
+import { renderHook, act, waitFor } from '@testing-library/react'
+import useLocalStorage from '.' // adjust path as needed
+
+// Mock localStorage
+const createMockStorage = () => {
+ let store: Record = {}
+ return {
+ getItem: vi.fn((key: string) => store[key] || null),
+ setItem: vi.fn((key: string, value: string) => {
+ store[key] = value.toString()
+ }),
+ removeItem: vi.fn((key: string) => {
+ delete store[key]
+ }),
+ clear: vi.fn(() => {
+ store = {}
+ }),
+ _getStore: () => ({ ...store }),
+ _setStore: (newStore: Record) => {
+ store = { ...newStore }
+ },
+ }
+}
+
+// Mock event system
+const createMockEventSystem = () => {
+ const eventListeners: Record = {}
+
+ return {
+ addEventListener: vi.fn((event: string, callback: Function) => {
+ if (!eventListeners[event]) {
+ eventListeners[event] = []
+ }
+ eventListeners[event]?.push(callback)
+ }),
+ removeEventListener: vi.fn((event: string, callback: Function) => {
+ if (eventListeners[event]) {
+ const index = eventListeners[event]?.indexOf(callback)
+ if (index && index > -1) {
+ eventListeners[event]?.splice(index, 1)
+ }
+ }
+ }),
+ dispatchEvent: vi.fn((event: Event) => {
+ const listeners = eventListeners[event.type] || []
+ listeners.forEach((listener) => listener(event))
+ }),
+ _triggerCustomEvent: (eventType: string) => {
+ const listeners = eventListeners[eventType] || []
+ listeners.forEach((listener) => listener(new Event(eventType)))
+ },
+ _triggerStorageEvent: (key: string, newValue: string) => {
+ const listeners = eventListeners['storage'] || []
+ const event = new StorageEvent('storage', { key, newValue })
+ listeners.forEach((listener) => listener(event))
+ },
+ _getListeners: () => ({ ...eventListeners }),
+ _clearListeners: () => {
+ Object.keys(eventListeners).forEach((key) => {
+ eventListeners[key] = []
+ })
+ },
+ }
+}
+
+let mockStorage: ReturnType
+let mockEvents: ReturnType
+
+// Global setup
+beforeEach(() => {
+ mockStorage = createMockStorage()
+ mockEvents = createMockEventSystem()
+
+ Object.defineProperty(window, 'localStorage', { value: mockStorage })
+ Object.defineProperty(window, 'addEventListener', { value: mockEvents.addEventListener })
+ Object.defineProperty(window, 'removeEventListener', { value: mockEvents.removeEventListener })
+ Object.defineProperty(window, 'dispatchEvent', { value: mockEvents.dispatchEvent })
+
+ vi.clearAllMocks()
+})
+
+afterEach(() => {
+ vi.clearAllMocks()
+})
describe('use-local-storage', () => {
- afterEach(() => {
- localStorage.clear()
+ describe('Initialization Tests', () => {
+ it('should initialize with primitive value when localStorage is empty', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-primitive', initialValue: 'hello' }))
+
+ expect(result.current[0]).toBe('hello')
+ expect(mockStorage.getItem).toHaveBeenCalledWith('test-primitive')
+ })
+
+ it('should initialize with ssr', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-primitive', initialValue: 'hello' }), {
+ hydrate: true,
+ })
+
+ expect(result.current[0]).toBe('hello')
+ expect(mockStorage.getItem).toHaveBeenCalledWith('test-primitive')
+ })
+
+ it('should initialize with function in ssr', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-primitive', initialValue: () => 'hello' }), {
+ hydrate: true,
+ })
+
+ expect(result.current[0]).toBe('hello')
+ expect(mockStorage.getItem).toHaveBeenCalledWith('test-primitive')
+ })
+
+ it('should initialize with object value when localStorage is empty', () => {
+ const initialObj = { name: 'John', age: 30 }
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-object', initialValue: initialObj }))
+
+ expect(result.current[0]).toEqual(initialObj)
+ })
+
+ it('should initialize with array value when localStorage is empty', () => {
+ const initialArray = [1, 2, 3, 'test', { nested: true }]
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-array', initialValue: initialArray }))
+
+ expect(result.current[0]).toEqual(initialArray)
+ })
+
+ it('should initialize with function-based value', () => {
+ const initialValueFn = vi.fn(() => ({ computed: true }))
+ const { result } = renderHook(() =>
+ useLocalStorage({ key: 'test-function-init', initialValue: initialValueFn })
+ )
+
+ expect(initialValueFn).toHaveBeenCalledOnce()
+ expect(result.current[0]).toEqual(expect.objectContaining({ computed: true }))
+ })
+
+ it('should initialize with null value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-null', initialValue: null }))
+
+ expect(result.current[0]).toBe(null)
+ })
+
+ it('should initialize with undefined value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-undefined', initialValue: undefined }))
+
+ expect(result.current[0]).toBe(undefined)
+ })
+
+ it('should initialize with boolean value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-boolean', initialValue: false }))
+
+ expect(result.current[0]).toBe(false)
+ })
+
+ it('should initialize with number value including zero', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'test-zero', initialValue: 0 }))
+
+ expect(result.current[0]).toBe(0)
+ })
+ })
+
+ describe('LocalStorage Retrieval Tests', () => {
+ it('should retrieve existing string value from localStorage', () => {
+ mockStorage._setStore({ 'existing-key': '"stored-string"' })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'existing-key', initialValue: 'default' }))
+
+ expect(result.current[0]).toBe('stored-string')
+ })
+
+ it('should retrieve existing object from localStorage', () => {
+ const storedObj = { user: 'Alice', settings: { theme: 'dark' } }
+ mockStorage._setStore({ 'obj-key': JSON.stringify(storedObj) })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'obj-key', initialValue: {} }))
+
+ expect(result.current[0]).toEqual(storedObj)
+ })
+
+ it('should retrieve existing array from localStorage', () => {
+ const storedArray = ['item1', 'item2', { nested: 'object' }]
+ mockStorage._setStore({ 'array-key': JSON.stringify(storedArray) })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'array-key', initialValue: [] }))
+
+ expect(result.current[0]).toEqual(storedArray)
+ })
+
+ it('should retrieve boolean values from localStorage', () => {
+ mockStorage._setStore({ 'bool-key': 'true' })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'bool-key', initialValue: false }))
+
+ expect(result.current[0]).toBe(true)
+ })
+
+ it('should retrieve numeric values from localStorage', () => {
+ mockStorage._setStore({ 'num-key': '42' })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'num-key', initialValue: 0 }))
+
+ expect(result.current[0]).toBe(42)
+ })
+ })
+
+ describe('State Update Tests', () => {
+ it('should update state with primitive value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-primitive', initialValue: 'initial' }))
+
+ act(() => {
+ result.current[1]('updated')
+ })
+
+ expect(result.current[0]).toBe('updated')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('update-primitive', '"updated"')
+ })
+
+ it('should update state with object value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-object', initialValue: { count: 0 } }))
+
+ const newObj = { count: 5, name: 'test' }
+ act(() => {
+ result.current[1](newObj)
+ })
+
+ expect(result.current[0]).toEqual(newObj)
+ expect(mockStorage.setItem).toHaveBeenCalledWith('update-object', JSON.stringify(newObj))
+ })
+
+ it('should update state with function-based setter', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-function', initialValue: 10 }))
+
+ act(() => {
+ result.current[1]((prev) => prev * 2)
+ })
+
+ expect(result.current[0]).toBe(20)
+ expect(mockStorage.setItem).toHaveBeenCalledWith('update-function', '20')
+ })
+
+ it('should update state with complex function-based setter', () => {
+ const initialState = { items: ['a', 'b'], count: 2 }
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-complex', initialValue: initialState }))
+
+ act(() => {
+ result.current[1]((prev) => ({
+ ...prev,
+ items: [...prev.items, 'c'],
+ count: prev.count + 1,
+ }))
+ })
+
+ expect(result.current[0]).toEqual({
+ items: ['a', 'b', 'c'],
+ count: 3,
+ })
+ })
+
+ it('should handle multiple rapid updates', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'rapid-updates', initialValue: 0 }))
+
+ act(() => {
+ result.current[1](1)
+ result.current[1](2)
+ result.current[1](3)
+ })
+
+ expect(result.current[0]).toBe(3)
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(3)
+ })
+
+ it('should update with null value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-null', initialValue: 'something' }))
+
+ act(() => {
+ // @ts-expect-error Forcefully passing null
+ result.current[1](null)
+ })
+
+ expect(result.current[0]).toBe(null)
+ expect(mockStorage.setItem).toHaveBeenCalledWith('update-null', 'null')
+ })
+
+ it('should update with undefined value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'update-undefined', initialValue: 'something' }))
+
+ act(() => {
+ // @ts-expect-error Forcefully passing undefined
+ result.current[1](undefined)
+ })
+
+ expect(result.current[0]).toBe(undefined)
+ expect(mockStorage.setItem).toHaveBeenCalledWith('update-undefined', 'null')
+ })
+ })
+
+ describe('Event System Tests', () => {
+ it('should set up event listeners on mount', () => {
+ renderHook(() => useLocalStorage({ key: 'event-test', initialValue: 'initial' }))
+
+ expect(mockEvents.addEventListener).toHaveBeenCalledWith('event-test', expect.any(Function))
+ expect(mockEvents.addEventListener).toHaveBeenCalledWith('storage', expect.any(Function))
+ expect(mockEvents.addEventListener).toHaveBeenCalledTimes(2)
+ })
+
+ it('should clean up event listeners on unmount', () => {
+ const { unmount } = renderHook(() => useLocalStorage({ key: 'cleanup-test', initialValue: 'initial' }))
+
+ unmount()
+
+ expect(mockEvents.removeEventListener).toHaveBeenCalledWith('cleanup-test', expect.any(Function))
+ expect(mockEvents.removeEventListener).toHaveBeenCalledWith('storage', expect.any(Function))
+ expect(mockEvents.removeEventListener).toHaveBeenCalledTimes(2)
+ })
+
+ it('should dispatch custom event on state update', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'dispatch-test', initialValue: 'initial' }))
+
+ act(() => {
+ result.current[1]('updated')
+ })
+
+ expect(mockEvents.dispatchEvent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: 'dispatch-test',
+ })
+ )
+ })
+
+ it('should respond to custom events from other instances', async () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'sync-test', initialValue: 'initial' }))
+
+ // Simulate external update
+ mockStorage._setStore({ 'sync-test': '"external-update"' })
+
+ // Trigger custom event
+ act(() => {
+ mockEvents._triggerCustomEvent('sync-test')
+ })
+
+ await waitFor(() => {
+ expect(result.current[0]).toBe('external-update')
+ })
+ })
+
+ it('should respond to storage events from other tabs', async () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'cross-tab-test', initialValue: 'initial' }))
+
+ // Simulate cross-tab update
+ mockStorage._setStore({ 'cross-tab-test': '"from-other-tab"' })
+
+ act(() => {
+ mockEvents._triggerStorageEvent('cross-tab-test', '"from-other-tab"')
+ })
+
+ await waitFor(() => {
+ expect(result.current[0]).toBe('from-other-tab')
+ })
+ })
+
+ it('should ignore storage events for different keys', async () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'specific-key', initialValue: 'initial' }))
+
+ act(() => {
+ mockEvents._triggerStorageEvent('different-key', '"different-value"')
+ })
+
+ // Should remain unchanged
+ expect(result.current[0]).toBe('initial')
+ })
+ })
+
+ describe('Key Change Tests', () => {
+ it('should handle key changes and migrate data to new key', () => {
+ let key = 'original-key'
+ const { result, rerender } = renderHook(() => useLocalStorage({ key, initialValue: 'initial' }))
+
+ // Set value with original key
+ act(() => {
+ result.current[1]('value-for-original')
+ })
+
+ // Change key
+ key = 'new-key'
+ rerender()
+
+ // Should remove old key and set new key with the cached value
+ expect(mockStorage.removeItem).toHaveBeenCalledWith('original-key')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('new-key', '"value-for-original"')
+ })
+
+ it('should update event listeners when key changes', () => {
+ let key = 'event-key-1'
+ const { rerender } = renderHook(() => useLocalStorage({ key, initialValue: 'initial' }))
+
+ // Change key
+ key = 'event-key-2'
+ rerender()
+
+ // Should remove old listeners and add new ones
+ expect(mockEvents.removeEventListener).toHaveBeenCalledWith('event-key-1', expect.any(Function))
+ expect(mockEvents.addEventListener).toHaveBeenCalledWith('event-key-2', expect.any(Function))
+ })
+
+ it('should handle multiple key changes', () => {
+ let key = 'key-1'
+ const { result, rerender } = renderHook(() => useLocalStorage({ key, initialValue: 0 }))
+
+ act(() => {
+ result.current[1](1)
+ })
+
+ key = 'key-2'
+ rerender()
+
+ act(() => {
+ result.current[1](2)
+ })
+
+ key = 'key-3'
+ rerender()
+
+ expect(mockStorage.removeItem).toHaveBeenCalledWith('key-1')
+ expect(mockStorage.removeItem).toHaveBeenCalledWith('key-2')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('key-3', '2')
+ })
})
- it('should return state and setState', () => {
- const { result } = renderHook(() => useLocalStorage('user'))
+ describe('Error Handling Tests', () => {
+ it('should handle JSON.parse errors and return initial value', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ mockStorage.getItem.mockReturnValueOnce('invalid-json-{')
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'parse-error', initialValue: 'fallback' }))
+
+ expect(result.current[0]).toBe('fallback')
+ expect(consoleSpy).toHaveBeenCalled()
+
+ consoleSpy.mockRestore()
+ })
+
+ it('should handle JSON.stringify errors gracefully', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'stringify-error', initialValue: 'initial' }))
+
+ // Create circular reference
+ const circularObj: any = { name: 'test' }
+ circularObj.self = circularObj
+
+ act(() => {
+ result.current[1](circularObj)
+ })
+
+ expect(consoleSpy).toHaveBeenCalled()
+ // State should remain unchanged due to error
+ expect(result.current[0]).toBe('initial')
+
+ consoleSpy.mockRestore()
+ })
- expect(result.current[0]).toBe('')
- expect(typeof result.current[1]).toBe('function')
+ it('should handle localStorage.setItem errors (quota exceeded)', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ mockStorage.setItem.mockImplementationOnce(() => {
+ throw new DOMException('QuotaExceededError')
+ })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'quota-error', initialValue: 'initial' }))
+
+ act(() => {
+ result.current[1]('new-value')
+ })
+
+ expect(consoleSpy).toHaveBeenCalled()
+ consoleSpy.mockRestore()
+ })
+
+ it('should handle localStorage.getItem errors', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ mockStorage.getItem.mockImplementationOnce(() => {
+ throw new Error('Storage access denied')
+ })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'get-error', initialValue: 'fallback' }))
+
+ expect(result.current[0]).toBe('fallback')
+ expect(consoleSpy).toHaveBeenCalled()
+
+ consoleSpy.mockRestore()
+ })
+
+ it('should handle null localStorage gracefully', () => {
+ // Simulate environment where localStorage is null
+ Object.defineProperty(window, 'localStorage', { value: null })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'no-storage', initialValue: 'fallback' }))
+
+ expect(result.current[0]).toBe('fallback')
+ })
})
- it('should be able handle error when item is undefined in local-storage', () => {
- localStorage.setItem('key', '') // when getting localStorage.getItem(key) => '', it results into undefined
- const { result } = renderHook(() => useLocalStorage('key'))
- expect(result.current[0]).toBeUndefined()
+ describe('Performance Tests', () => {
+ it('should re-parse only when string value changes', () => {
+ mockStorage._setStore({ 'string-change-test': '"value1"' })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'string-change-test', initialValue: 'initial' }))
+
+ expect(result.current[0]).toBe('value1')
+
+ // Change the stored value
+ mockStorage._setStore({ 'string-change-test': '"value2"' })
+
+ // Trigger re-evaluation
+ act(() => {
+ mockEvents._triggerCustomEvent('string-change-test')
+ })
+
+ expect(result.current[0]).toBe('value2')
+ })
+
+ it('should handle rapid successive updates efficiently', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'rapid-test', initialValue: 0 }))
+
+ // Perform many rapid updates
+ act(() => {
+ for (let i = 1; i <= 100; i++) {
+ result.current[1](i)
+ }
+ })
+
+ expect(result.current[0]).toBe(100)
+ expect(mockStorage.setItem).toHaveBeenCalledTimes(100)
+ expect(mockEvents.dispatchEvent).toHaveBeenCalledTimes(100)
+ })
})
- it('should be able handle error when with default value param', () => {
- localStorage.setItem('key', '')
- const { result } = renderHook(() => useLocalStorage('key', {}))
- expect(result.current[0]).toStrictEqual({})
+ describe('SSR Support Tests', () => {
+ it('should work with server-side rendering (no localStorage)', () => {
+ // Mock server environment
+ const originalLocalStorage = window.localStorage
+ // @ts-ignore
+ delete window.localStorage
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'ssr-test', initialValue: 'server-value' }))
+
+ expect(result.current[0]).toBe('server-value')
+
+ // Restore localStorage
+ window.localStorage = originalLocalStorage
+ })
+
+ it('should handle function-based initial values in SSR', () => {
+ const originalLocalStorage = window.localStorage
+ // @ts-ignore
+ delete window.localStorage
+
+ const initialFn = vi.fn(() => ({ ssr: true, data: 'test' }))
+ const { result } = renderHook(() => useLocalStorage({ key: 'ssr-function-test', initialValue: initialFn }))
+
+ expect(result.current[0]).toEqual({ ssr: true, data: 'test' })
+
+ // Restore localStorage
+ window.localStorage = originalLocalStorage
+ })
})
- it('should set the default value', () => {
- const { result } = renderHook(() => useLocalStorage('user', { name: 'Saitama' }))
+ describe('Edge Cases', () => {
+ it('should handle empty string as a valid value', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'empty-string', initialValue: 'default' }))
+
+ act(() => {
+ result.current[1]('')
+ })
+
+ expect(result.current[0]).toBe('')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('empty-string', '""')
+ })
+
+ it('should handle very large objects', () => {
+ const largeObj = {
+ data: Array(1000)
+ .fill(0)
+ .map((_, i) => ({ id: i, value: `item-${i}` })),
+ }
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'large-object', initialValue: null as any }))
+
+ act(() => {
+ result.current[1](largeObj)
+ })
+
+ expect(result.current[0]).toEqual(largeObj)
+ })
+
+ it('should handle special characters in keys', () => {
+ const specialKey = 'test-key-with-special-chars-!@#$%^&*()'
+ const { result } = renderHook(() => useLocalStorage({ key: specialKey, initialValue: 'special' }))
+
+ act(() => {
+ result.current[1]('updated')
+ })
- expect(result.current[0]).toEqual({ name: 'Saitama' })
+ expect(result.current[0]).toBe('updated')
+ expect(mockStorage.setItem).toHaveBeenCalledWith(specialKey, '"updated"')
+ })
+
+ it('should handle Date objects', () => {
+ const testDate = new Date('2023-01-01T00:00:00Z')
+ const { result } = renderHook(() =>
+ useLocalStorage({ key: 'date-test', initialValue: null as unknown as Date })
+ )
+
+ act(() => {
+ result.current[1](testDate)
+ })
+ // Date
+ expect(result.current[0]).toBe(testDate)
+ expect(mockStorage.getItem('date-test')).toBe(JSON.stringify(testDate))
+ })
+
+ it('should handle nested objects with arrays', () => {
+ const complexObj = {
+ user: {
+ name: 'John',
+ preferences: {
+ theme: 'dark',
+ notifications: ['email', 'push'],
+ settings: {
+ autoSave: true,
+ shortcuts: { save: 'Ctrl+S', open: 'Ctrl+O' },
+ },
+ },
+ },
+ metadata: {
+ created: new Date().toISOString(),
+ version: '1.0.0',
+ },
+ }
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'complex-nested', initialValue: {} }))
+
+ act(() => {
+ result.current[1](complexObj)
+ })
+
+ expect(result.current[0]).toEqual(complexObj)
+ })
+
+ it('should maintain referential integrity for objects', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'ref-test', initialValue: { items: [] as any[] } }))
+
+ act(() => {
+ result.current[1]((prev) => ({
+ ...prev,
+ items: [...prev.items, 'new-item'],
+ }))
+ })
+
+ const state1 = result.current[0]
+
+ act(() => {
+ result.current[1]((prev) => ({
+ ...prev,
+ timestamp: Date.now(),
+ }))
+ })
+
+ const state2 = result.current[0]
+
+ expect(state1).not.toBe(state2) // Different object references
+ expect(state2.items).toContain('new-item')
+ })
})
- it('should update the state in local storage', () => {
- const { result, rerender } = renderHook(() => useLocalStorage('user', { name: 'Saitama' }))
+ describe('Multiple Instance Tests', () => {
+ it('should allow multiple instances with different keys', () => {
+ const { result: result1 } = renderHook(() => useLocalStorage({ key: 'instance-1', initialValue: 'value1' }))
+
+ const { result: result2 } = renderHook(() => useLocalStorage({ key: 'instance-2', initialValue: 'value2' }))
+
+ expect(result1.current[0]).toBe('value1')
+ expect(result2.current[0]).toBe('value2')
- act(() => {
- result.current[1]({ name: 'Genos' })
+ act(() => {
+ result1.current[1]('updated1')
+ })
+
+ act(() => {
+ result2.current[1]('updated2')
+ })
+
+ expect(result1.current[0]).toBe('updated1')
+ expect(result2.current[0]).toBe('updated2')
+ })
+
+ it('should sync multiple instances with the same key', async () => {
+ const { result: result1 } = renderHook(() => useLocalStorage({ key: 'shared-key', initialValue: 'initial' }))
+
+ const { result: result2 } = renderHook(() => useLocalStorage({ key: 'shared-key', initialValue: 'initial' }))
+
+ // Update from first instance
+ act(() => {
+ result1.current[1]('from-instance-1')
+ })
+
+ // Both should have the updated value
+ expect(result1.current[0]).toBe('from-instance-1')
+
+ // Second instance should update via event
+ await waitFor(() => {
+ expect(result2.current[0]).toBe('from-instance-1')
+ })
})
- rerender()
- expect(result.current[0]).toEqual({ name: 'Genos' })
- expect(JSON.parse(localStorage.getItem('user')!)).toEqual({ name: 'Genos' })
})
- it('should be able to handle function in setState', () => {
- const { result, rerender } = renderHook(() => useLocalStorage('user', { name: 'Saitama' }))
+ describe('Encoder/Decoder Tests', () => {
+ it('should encode value before storing', () => {
+ const encoder = vi.fn((val: string) => btoa(val))
+ const { result } = renderHook(() => useLocalStorage({ key: 'encode-test', initialValue: 'hello', encoder }))
+
+ act(() => {
+ result.current[1]('world')
+ })
+
+ expect(encoder).toHaveBeenCalledWith('"world"')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('encode-test', btoa('"world"'))
+ })
+
+ it('should decode value when retrieving', () => {
+ const decoder = vi.fn((val: string) => atob(val))
+ const encoded = btoa('"stored"')
+ mockStorage._setStore({ 'decode-test': encoded })
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'decode-test', initialValue: 'default', decoder }))
- act(() => {
- result.current[1]((old_value) => {
- old_value.name = 'Blast'
- return { ...old_value }
+ expect(decoder).toHaveBeenCalledWith(encoded)
+ expect(result.current[0]).toBe('stored')
+ })
+
+ it('should handle both encoder and decoder', () => {
+ const encoder = (val: string) => btoa(val)
+ const decoder = (val: string) => atob(val)
+
+ const { result } = renderHook(() =>
+ useLocalStorage({ key: 'both-test', initialValue: { data: 'test' }, encoder, decoder })
+ )
+
+ act(() => {
+ result.current[1]({ data: 'updated' })
+ })
+
+ const stored = mockStorage._getStore()['both-test']!
+ expect(stored).toBe(btoa(JSON.stringify({ data: 'updated' })))
+
+ mockStorage._setStore({ 'both-test': stored })
+ act(() => {
+ mockEvents._triggerCustomEvent('both-test')
+ })
+
+ expect(result.current[0]).toEqual({ data: 'updated' })
+ })
+
+ it('should handle encoder errors gracefully', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ const encoder = () => {
+ throw new Error('Encode failed')
+ }
+
+ const { result } = renderHook(() => useLocalStorage({ key: 'encode-error', initialValue: 'init', encoder }))
+
+ act(() => {
+ result.current[1]('new')
+ })
+
+ expect(consoleSpy).toHaveBeenCalled()
+ consoleSpy.mockRestore()
+ })
+
+ it('should handle decoder errors gracefully', () => {
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
+ const decoder = () => {
+ throw new Error('Decode failed')
+ }
+ mockStorage._setStore({ 'decode-error': 'invalid' })
+
+ const { result } = renderHook(() =>
+ useLocalStorage({ key: 'decode-error', initialValue: 'fallback', decoder })
+ )
+
+ expect(result.current[0]).toBe('fallback')
+ expect(consoleSpy).toHaveBeenCalled()
+ consoleSpy.mockRestore()
+ })
+
+ it('should work without encoder/decoder (backward compatibility)', () => {
+ const { result } = renderHook(() => useLocalStorage({ key: 'no-codec', initialValue: 'test' }))
+
+ act(() => {
+ result.current[1]('updated')
+ })
+
+ expect(mockStorage.setItem).toHaveBeenCalledWith('no-codec', '"updated"')
+ expect(result.current[0]).toBe('updated')
+ })
+
+ it('should handle complex objects with encoder/decoder', () => {
+ const encoder = (val: string) => btoa(val)
+ const decoder = (val: string) => atob(val)
+ const obj = { nested: { data: [1, 2, 3] } }
+
+ const { result } = renderHook(() =>
+ useLocalStorage({ key: 'complex-codec', initialValue: obj, encoder, decoder })
+ )
+
+ act(() => {
+ result.current[1]({ nested: { data: [4, 5, 6] } })
})
+
+ expect(result.current[0]).toEqual({ nested: { data: [4, 5, 6] } })
+ })
+
+ it('should apply encoder on key change migration', () => {
+ const encoder = vi.fn((val: string) => btoa(val))
+ let key = 'key-1'
+
+ const { result, rerender } = renderHook(() => useLocalStorage({ key, initialValue: 'value', encoder }))
+
+ act(() => {
+ result.current[1]('migrated')
+ })
+
+ key = 'key-2'
+ rerender()
+
+ expect(encoder).toHaveBeenCalledWith('"migrated"')
+ expect(mockStorage.setItem).toHaveBeenCalledWith('key-2', btoa('"migrated"'))
})
- rerender()
- expect(result.current[0]).toEqual({ name: 'Blast' })
- expect(JSON.parse(localStorage.getItem('user')!)).toEqual({ name: 'Blast' })
})
})
diff --git a/src/lib/use-local-storage/index.tsx b/src/lib/use-local-storage/index.tsx
index 52e9892..e783c11 100644
--- a/src/lib/use-local-storage/index.tsx
+++ b/src/lib/use-local-storage/index.tsx
@@ -1,50 +1,162 @@
-'use client'
-import type { Dispatch, MutableRefObject } from 'react'
-import React, { useRef, useState } from 'react'
+import type { Dispatch, SetStateAction } from 'react'
+import React, { useRef, useCallback, useSyncExternalStore } from 'react'
/**
* @description
- * A hook for managing the states with `local-storage`.
- *
- * It working is just like the `useState`.
- *
- * It automatically updates the state in `local-storage`.
+ * A React hook that provides a seamless way to persist and synchronize state with `localStorage`, offering a `useState`-like API with cross-tab synchronization.
*
+ * @example
+ import { useLocalStorage } from 'classic-react-hooks'
+
+ function UserPreferences() {
+ const [theme, setTheme] = useLocalStorage({ key: 'theme', defaultValue: 'light' })
+ const [language, setLanguage] = useLocalStorage({ key: 'language', defaultValue: 'en' })
+
+ return (
+
+ setTheme(e.target.value)}>
+ Light
+ Dark
+
+
+ setLanguage(e.target.value)}>
+ English
+ Spanish
+ French
+
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-local-storage.html
*/
-export default function useLocalStorage(key: string, defaultValue?: State) {
- const [state, setState] = useState(() => {
+export default function useLocalStorage({
+ key,
+ initialValue,
+ encoder,
+ decoder,
+}: {
+ key: string
+ initialValue?: State | (() => State)
+ encoder?: (value: string) => string
+ decoder?: (value: string) => string
+}) {
+ // Cache the last parse value to avoid unnecessary re-renders
+ const lastValueRef = useRef(null)
+ const lastStringRef = useRef(null)
+ const lastKeyRef = useRef(key)
+
+ const getStoredState = useCallback(() => {
try {
+ // Key has changed, reset cached values
+ if (lastKeyRef.current !== key) {
+ localStorage.removeItem(lastKeyRef.current)
+ const serializedValue = JSON.stringify(lastValueRef.current)
+ localStorage.setItem(key, encoder ? encoder(serializedValue) : serializedValue)
+ lastKeyRef.current = key
+ lastValueRef.current = null
+ lastStringRef.current = null
+ }
+
const item = localStorage.getItem(key)
- if (defaultValue && item == null) {
- return defaultValue
+
+ if (item != null) {
+ // Only parse if the string value has changed
+ if (lastStringRef.current !== item) {
+ lastStringRef.current = item
+ lastValueRef.current = JSON.parse(decoder ? decoder(item) : item)
+ }
+ return lastValueRef.current!
}
- const parsed_value = item == null ? '' : JSON.parse(item)
- return parsed_value
} catch (err) {
- if (defaultValue) {
- return defaultValue
- }
- return undefined
+ console.log(err)
}
- })
-
- const updateState: MutableRefObject>> = useRef(
- (value: State | ((state: State) => State)) => {
- let new_value = value
- if (typeof value == 'function') {
- setState((state) => {
- new_value = (value as (state: State) => State)(state)
- localStorage.setItem(key, JSON.stringify(new_value))
- return new_value
- })
- } else {
- setState(new_value)
- localStorage.setItem(key, JSON.stringify(new_value))
- }
+
+ // Return initial value
+ let returnVal: State
+ if (lastValueRef.current) {
+ returnVal = lastValueRef.current
+ } else if (typeof initialValue == 'function') {
+ returnVal = (initialValue as () => State)()
+ } else {
+ returnVal = initialValue as State
}
+
+ // Cache the initial value
+ lastValueRef.current = returnVal
+
+ return lastValueRef.current!
+ }, [key])
+
+ // Server-side snapshot - return initial value to avoid hydration mismatch
+ const getServerSnapshot = useCallback(() => {
+ if (lastValueRef.current) {
+ return lastValueRef.current
+ }
+ if (typeof initialValue == 'function') {
+ lastValueRef.current = (initialValue as () => State)()
+ } else {
+ lastValueRef.current = initialValue as State
+ }
+ return lastValueRef.current!
+ }, [])
+
+ const storedState = useSyncExternalStore(
+ useCallback(
+ (callback) => {
+ const handleStorageChange = (event: Event) => {
+ callback()
+ }
+
+ // Listen for our custom events
+ window.addEventListener(key, handleStorageChange)
+
+ // Also listen for storage event from other tabs
+ const handleStorageEvent = (event: StorageEvent) => {
+ if (event.key === key) {
+ callback()
+ }
+ }
+
+ window.addEventListener('storage', handleStorageEvent)
+
+ return () => {
+ window.removeEventListener(key, handleStorageChange)
+ window.removeEventListener('storage', handleStorageEvent)
+ }
+ },
+ [key]
+ ),
+ getStoredState,
+ getServerSnapshot
+ )
+
+ const updateState: Dispatch> = useCallback(
+ (state: State | ((prevState: State) => State)) => {
+ try {
+ let newValue: State
+
+ if (typeof state === 'function') {
+ newValue = (state as (state: State) => State)(storedState)
+ } else {
+ newValue = state
+ }
+
+ const serializedValue = JSON.stringify(newValue === undefined ? null : newValue)
+ localStorage.setItem(key, encoder ? encoder(serializedValue) : serializedValue)
+
+ // Update cache
+ lastStringRef.current = serializedValue
+ lastValueRef.current = newValue
+
+ // Notify subscriber
+ window.dispatchEvent(new Event(key))
+ } catch (err) {
+ console.log(err)
+ }
+ },
+ [key, storedState]
)
- return [state, updateState.current] as const
+ return [storedState, updateState] as const
}
diff --git a/src/lib/use-multi-intersection-observer/index.test.tsx b/src/lib/use-multi-intersection-observer/index.test.tsx
new file mode 100644
index 0000000..8ccfb99
--- /dev/null
+++ b/src/lib/use-multi-intersection-observer/index.test.tsx
@@ -0,0 +1,133 @@
+import { act, renderHook } from '@testing-library/react'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+
+import useMultipleIntersectionObserver from '.'
+
+// Mock IntersectionObserver
+const mockIntersectionObserver = vi.fn()
+const mockObserve = vi.fn()
+const mockUnobserve = vi.fn()
+const mockDisconnect = vi.fn()
+
+beforeEach(() => {
+ mockIntersectionObserver.mockImplementation((callback) => ({
+ observe: mockObserve,
+ unobserve: mockUnobserve,
+ disconnect: mockDisconnect,
+ // Store callback for manual triggering
+ _callback: callback,
+ }))
+
+ // Mock window.IntersectionObserver
+ Object.defineProperty(window, 'IntersectionObserver', {
+ writable: true,
+ configurable: true,
+ value: mockIntersectionObserver,
+ })
+})
+
+afterEach(() => {
+ vi.clearAllMocks()
+})
+
+// Helper function to trigger intersection
+const forcefullyTriggerIntersection = (entry?: Partial, mockIndex = 0) => {
+ const mockInstance = mockIntersectionObserver.mock.results[mockIndex]?.value
+ mockInstance._callback([
+ {
+ isIntersecting: !!entry?.isIntersecting,
+ target: entry?.target || document.createElement('div'),
+ },
+ ])
+}
+
+describe('use-multi-intersection-observer', () => {
+ it('creates observers for multiple keys', () => {
+ const { result } = renderHook(() => useMultipleIntersectionObserver(['header', 'footer', 'sidebar']))
+
+ expect(result.current.header).toHaveProperty('setHeaderElementRef')
+ expect(result.current.header).toHaveProperty('isHeaderElementIntersecting')
+ expect(result.current.header).toHaveProperty('headerElement')
+
+ expect(result.current.footer).toHaveProperty('setFooterElementRef')
+ expect(result.current.sidebar).toHaveProperty('setSidebarElementRef')
+ })
+
+ it('passes options to all observers', () => {
+ const onIntersection = vi.fn()
+ const { result } = renderHook(() =>
+ useMultipleIntersectionObserver(['a', 'b'], {
+ threshold: 0.8,
+ onIntersection,
+ onlyTriggerOnce: true,
+ })
+ )
+
+ const elA = document.createElement('div')
+ const elB = document.createElement('div')
+
+ act(() => {
+ result.current.a.setAElementRef(elA)
+ result.current.b.setBElementRef(elB)
+ })
+
+ expect(mockIntersectionObserver).toHaveBeenCalledWith(
+ expect.any(Function),
+ expect.objectContaining({ threshold: 0.8 })
+ )
+
+ act(() => forcefullyTriggerIntersection({ isIntersecting: true, target: elA }))
+ expect(onIntersection).toHaveBeenCalledWith({ target: elA, isIntersecting: true })
+ expect(mockUnobserve).toHaveBeenCalledWith(elA) // onlyTriggerOnce
+ })
+
+ it('handles independent intersection states', () => {
+ const { result } = renderHook(() => useMultipleIntersectionObserver(['left', 'right']))
+
+ const leftEl = document.createElement('div')
+ const rightEl = document.createElement('div')
+
+ act(() => {
+ result.current.left.setLeftElementRef(leftEl)
+ result.current.right.setRightElementRef(rightEl)
+ })
+
+ // Trigger only left intersection
+ act(() => forcefullyTriggerIntersection({ isIntersecting: true, target: leftEl }))
+
+ expect(result.current.left.isLeftElementIntersecting).toBe(true)
+ expect(result.current.right.isRightElementIntersecting).toBe(false)
+
+ // Trigger right intersection
+ act(() => forcefullyTriggerIntersection({ isIntersecting: true, target: rightEl }, 1))
+ expect(result.current.left.isLeftElementIntersecting).toBe(true)
+ expect(result.current.right.isRightElementIntersecting).toBe(true)
+
+ // Again update the status
+ act(() => forcefullyTriggerIntersection({ isIntersecting: false, target: leftEl }))
+ expect(result.current.left.isLeftElementIntersecting).toBe(false)
+ expect(result.current.right.isRightElementIntersecting).toBe(true)
+
+ act(() => forcefullyTriggerIntersection({ isIntersecting: false, target: rightEl }, 1))
+ expect(result.current.left.isLeftElementIntersecting).toBe(false)
+ expect(result.current.right.isRightElementIntersecting).toBe(false)
+ })
+
+ it('works with empty keys array', () => {
+ const { result } = renderHook(() => useMultipleIntersectionObserver([]))
+ expect(result.current).toEqual({})
+ })
+
+ it('maintains type safety for returned observers', () => {
+ const { result } = renderHook(() => useMultipleIntersectionObserver(['nav', 'main'] as const))
+
+ // These should be accessible without TypeScript errors
+ result.current.nav.navElement
+ result.current.nav.setNavElementRef
+ result.current.nav.isNavElementIntersecting
+
+ result.current.main.mainElement
+ result.current.main.setMainElementRef
+ result.current.main.isMainElementIntersecting
+ })
+})
diff --git a/src/lib/use-multi-intersection-observer/index.tsx b/src/lib/use-multi-intersection-observer/index.tsx
new file mode 100644
index 0000000..caff80c
--- /dev/null
+++ b/src/lib/use-multi-intersection-observer/index.tsx
@@ -0,0 +1,15 @@
+import type { IntersectionObserverOptions } from '../use-intersection-observer'
+
+import useIntersectionObserver from '../use-intersection-observer'
+
+export default function useMultiIntersectionObserver(
+ keys: readonly Key[],
+ options?: Omit
+) {
+ const observers = keys.reduce((acc, key) => {
+ acc[key] = useIntersectionObserver({ ...options, key })
+ return acc
+ }, {} as Record>>)
+
+ return observers
+}
diff --git a/src/lib/use-on-mount-effect/index.tsx b/src/lib/use-on-mount-effect/index.tsx
index 18faf98..cc29edb 100644
--- a/src/lib/use-on-mount-effect/index.tsx
+++ b/src/lib/use-on-mount-effect/index.tsx
@@ -1,13 +1,19 @@
-'use client'
import type { EffectCallback } from 'react'
import React, { useEffect } from 'react'
/**
* @description
- * A hooks that fires the given callback only once after the mount.
- *
- * It doesn't take any dependencies.
+ * A React hook that executes a callback function only once after the component mounts. This is a simplified wrapper around useEffect with an empty dependency array.
*
+ * @example
+ import { useOnMountEffect } from 'classic-react-hooks'
+ export default function YourComponent() {
+ useOnMountEffect(() => {
+ console.log('initial mount')
+ })
+
+ return
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-on-mount-effect.html
*/
diff --git a/src/lib/use-outside-click/index.test.tsx b/src/lib/use-outside-click/index.test.tsx
index 2691b24..d4da0e0 100644
--- a/src/lib/use-outside-click/index.test.tsx
+++ b/src/lib/use-outside-click/index.test.tsx
@@ -3,111 +3,110 @@ import { vi } from 'vitest'
import useOutsideClick from '.'
describe('use-outside-click', () => {
- it('should render', () => {
- renderHook(() => useOutsideClick(null, () => {}))
- })
-
- it('should work when Target is null', () => {
- renderHook(() => useOutsideClick(null, () => {}, { shouldInjectEvent: true }))
-
- const event = new Event('click')
- document.dispatchEvent(event)
+ describe('mounting', () => {
+ it('should render with null as target', () => {
+ // @ts-expect-error handling the edge case if target is not type of function
+ renderHook(() => useOutsideClick({ target: null }))
+ })
})
- it('should add listener on-mount and remove it on un-mount', () => {
- const div = document.createElement('div')
- const addSpy = vi.spyOn(document, 'addEventListener')
- const removeSpy = vi.spyOn(document, 'removeEventListener')
+ describe('event trigger', () => {
+ it('should not fire listener if target is null ', () => {
+ // @ts-expect-error handling the edge case if target is not type of function
+ renderHook(() => useOutsideClick({ target: null }))
- const { rerender, unmount } = renderHook(() => {
- useOutsideClick(
- () => div,
- () => {}
- )
+ const event = new Event('click', { bubbles: true })
+ document.dispatchEvent(event)
})
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ it('should fire listener when clicked outside of target', () => {
+ const div = document.createElement('div')
+ const ref = { current: div }
+ const fn = vi.fn()
- rerender()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ renderHook(() => {
+ useOutsideClick({ target: () => ref.current, handler: fn })
+ })
- unmount()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(1)
- })
- it('should work with refs', () => {
- const div = document.createElement('div')
- const addSpy = vi.spyOn(document, 'addEventListener')
- const removeSpy = vi.spyOn(document, 'removeEventListener')
-
- const ref = { current: div }
+ const event = new Event('click', { bubbles: true })
+ document.dispatchEvent(event)
- const { rerender, unmount } = renderHook(() => {
- useOutsideClick(ref, () => {})
+ expect(fn).toHaveBeenCalledTimes(1)
+ expect(fn).toHaveBeenCalledWith(event)
})
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ it('should fire listener when clicked outside of target, when `setElementRef` is used', () => {
+ const div = document.createElement('div')
+ document.body.append(div) // Append to body to make it part of the DOM
- rerender()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(0)
+ const fn = vi.fn()
- unmount()
- expect(addSpy).toHaveBeenCalledTimes(1)
- expect(removeSpy).toHaveBeenCalledTimes(1)
- })
+ const { result, rerender } = renderHook(() => {
+ return useOutsideClick({ handler: fn })
+ })
+
+ result.current.setElementRef(div)
+ rerender()
- it('should fire listener when clicked outside of target element when ref is provided', () => {
- const div = document.createElement('div')
- const ref = { current: div }
- const listener = vi.fn()
+ const event = new Event('click', { bubbles: true })
+ // Simulate click outside of div
+ document.dispatchEvent(event)
- renderHook(() => {
- useOutsideClick(ref, listener)
+ expect(fn).toHaveBeenCalledTimes(1)
+ expect(fn).toHaveBeenCalledWith(event)
+
+ document.body.removeChild(div) // Clean up
})
- const event = new Event('click')
- document.dispatchEvent(event)
+ it('should not fire when clicked on target', () => {
+ const div = document.createElement('div')
- expect(listener).toHaveBeenCalledTimes(1)
- expect(listener).toHaveBeenCalledWith(event)
- })
+ document.body.append(div)
- it('should fire listener when clicked outside of target element', () => {
- const div = document.createElement('div')
+ const fn = vi.fn()
+ renderHook(() => {
+ useOutsideClick({ target: () => div, handler: fn })
+ })
- const listener = vi.fn()
- renderHook(() => {
- useOutsideClick(() => div, listener)
+ const event = new Event('click', { bubbles: true })
+ div.dispatchEvent(event)
+
+ expect(fn).toHaveBeenCalledTimes(0)
})
- const event = new Event('click')
- document.dispatchEvent(event)
+ it('should not fire when clicked inside target', () => {
+ const div = document.createElement('div')
+ const span = document.createElement('span')
- expect(listener).toHaveBeenCalledTimes(1)
- expect(listener).toHaveBeenCalledWith(event)
- })
+ div.append(span)
+ document.body.append(div)
- it('should not fire listener when clicked on target element or inside within it', () => {
- const div = document.createElement('div')
- const span = document.createElement('span')
+ const fn = vi.fn()
+ renderHook(() => {
+ useOutsideClick({ target: () => div, handler: fn })
+ })
- div.append(span)
- document.body.append(div)
+ const event = new Event('click', { bubbles: true })
+ span.dispatchEvent(event)
- const listener = vi.fn()
- renderHook(() => {
- useOutsideClick(() => div, listener)
+ expect(fn).toHaveBeenCalledTimes(0)
})
- const event = new Event('click', { bubbles: true })
- div.dispatchEvent(event)
- expect(listener).toHaveBeenCalledTimes(0)
+ it('should not fire listener when clicked on target, when `setElementRef` is used', () => {
+ const div = document.createElement('div')
- span.dispatchEvent(event)
- expect(listener).toHaveBeenCalledTimes(0)
+ document.body.append(div)
+
+ const fn = vi.fn()
+ const { result, rerender } = renderHook(() => {
+ return useOutsideClick({ handler: fn })
+ })
+ result.current.setElementRef(div)
+ rerender()
+
+ const event = new Event('click', { bubbles: true })
+ div.dispatchEvent(event)
+ expect(fn).toHaveBeenCalledTimes(0)
+ })
})
})
diff --git a/src/lib/use-outside-click/index.tsx b/src/lib/use-outside-click/index.tsx
index 9d4ea54..13c14f1 100644
--- a/src/lib/use-outside-click/index.tsx
+++ b/src/lib/use-outside-click/index.tsx
@@ -1,42 +1,90 @@
-'use client'
-import type { Target } from '../use-event-listener'
-import React, { useRef } from 'react'
+import type { EvOptions, EvTarget } from '../../types'
+
+import React, { useEffect, useRef } from 'react'
import { useEventListener } from '../use-event-listener'
-import useSyncedRef from '../use-synced-ref'
/**
* @description
- * A hook that fires the given callback when clicked outside anywhere of the given html element.
+ * A React hook that detects outside click for specified element and triggers the given callback.
+ *
+ * @example
+ import { useState } from 'react'
+ import { useOutsideClick } from 'classic-react-hooks'
+
+ function Modal() {
+ const [isOpen, setIsOpen] = useState(false)
+
+ const {setElementRef} = useOutsideClick({
+ handler: () => setIsOpen(false),
+ })
+
+ if (!isOpen) {
+ return {
+ e.stopPropagation()
+ setIsOpen(true)
+ }}>Open Modal
+ }
+
+ return (
+
+
+
Modal Title
+
Click outside this modal to close it.
+
setIsOpen(false)}>Close
+
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-outside-click.html
*/
-export default function useOutsideClick(
- target: Target,
- handler: (event: DocumentEventMap['click']) => void,
- options?: { shouldInjectEvent?: boolean | any }
-) {
- const paramsRef = useSyncedRef({
- target,
- handler,
+export default function useOutsideClick({
+ target,
+ handler,
+ options,
+}: {
+ target?: EvTarget
+ handler?: (event: DocumentEventMap['click']) => void
+ options?: EvOptions
+}) {
+ const elementNode = useRef()
+ const setElementRef = useRef((node: HTMLElement | null) => {
+ elementNode.current = node
})
- let shouldInjectEvent = true
- if (typeof options == 'object' && 'shouldInjectEvent' in options) {
- shouldInjectEvent = !!options.shouldInjectEvent
- }
+ const mergedOptions: EvOptions = { shouldInjectEvent: true, ...options }
+
+ const eventCb = (event: DocumentEventMap['click']) => {
+ const node = elementNode.current // node which need to be tracked if click has occured within it or not
- const eventCb = useRef((event: DocumentEventMap['click']) => {
- const node = (typeof target == 'function' ? target() : target) ?? document
- if (event.target == node || ('current' in node && event.target == node.current)) return
+ if (!node) {
+ console.warn('Provided target element is null. Skipping the document click handler.')
+ return
+ }
+ if (event.target == node) return
- if (
- node &&
- (('contains' in node && (node as Node).contains(event.target as Node)) ||
- ('current' in node && 'contains' && (node.current as Node).contains(event.target as Node)))
- ) {
+ if ('contains' in node && (node as Node).contains(event.target as Node)) {
return
}
- paramsRef.current.handler(event)
+ handler?.(event)
+ }
+
+ useEffect(() => {
+ // Setting target inside effect, because effects run after the rendering of dom is done.
+ // Lazily setting target when prop is true
+ if (typeof target == 'function' && mergedOptions.shouldInjectEvent) {
+ setElementRef.current(target() as HTMLElement)
+ }
+ }, [target, options?.shouldInjectEvent])
+
+ useEventListener({
+ target: () => document,
+ event: 'click',
+ handler: eventCb,
+ options: {
+ capture: false, // Let the event bubble from top-to-bottom. Prevent it from user side using e.stopPropagation() on the button click
+ ...options,
+ },
})
- useEventListener(document, 'click', eventCb.current, { shouldInjectEvent: shouldInjectEvent })
+ return { setElementRef: setElementRef.current }
}
diff --git a/src/lib/use-synced-effect/index.test.tsx b/src/lib/use-synced-effect/index.test.tsx
index 06492fb..99fc4c9 100644
--- a/src/lib/use-synced-effect/index.test.tsx
+++ b/src/lib/use-synced-effect/index.test.tsx
@@ -2,53 +2,59 @@ import { renderHook } from '@testing-library/react'
import { vi } from 'vitest'
import useSyncedEffect from '.'
-describe('use-on-mount-effect', () => {
+describe('use-synced-effect', () => {
beforeEach(() => {
vi.useFakeTimers()
})
- it('should not run callback on initial the mount', () => {
- const fn = vi.fn()
- renderHook(() => useSyncedEffect(fn, []))
- expect(fn).toHaveBeenCalledTimes(0)
+ describe('mounting', () => {
+ it('should not run callback on initial the mount', () => {
+ const fn = vi.fn()
+ renderHook(() => useSyncedEffect(fn, []))
+ expect(fn).toHaveBeenCalledTimes(0)
+ })
+ it('should work without dependency passed', () => {
+ const fn = vi.fn()
+ renderHook(() => useSyncedEffect(fn))
+ expect(fn).toHaveBeenCalledTimes(0)
+ })
})
- it('should work without dependency passed', () => {
- const fn = vi.fn()
- renderHook(() => useSyncedEffect(fn))
- expect(fn).toHaveBeenCalledTimes(0)
- })
-
- it('should run callback on when dependency is changed', () => {
- const fn = vi.fn()
- let skill = 'js'
- const { rerender } = renderHook(() => useSyncedEffect(fn, [skill]))
- expect(fn).toHaveBeenCalledTimes(0)
+ describe('unmounting', () => {
+ it('should run cleanup on un-mount', () => {
+ const cleanupFn = vi.fn()
+ const fn = vi.fn(() => cleanupFn)
+ let skill = 'js'
- vi.runAllTimers()
+ const { rerender, unmount } = renderHook(() => useSyncedEffect(fn, [skill]))
+ vi.runAllTimers()
- skill = 'react'
- rerender()
- expect(fn).toHaveBeenCalledTimes(1)
+ skill = 'react'
+ rerender()
+ expect(fn).toHaveBeenCalledTimes(1)
- skill = 'typescript'
- rerender()
- expect(fn).toHaveBeenCalledTimes(2)
+ unmount()
+ expect(cleanupFn).toHaveBeenCalledTimes(1)
+ })
})
- it('should run cleanup on un-mount', () => {
- const cleanupFn = vi.fn()
- const fn = vi.fn(() => cleanupFn)
- let skill = 'js'
+ describe('Reactive behaviour', () => {
+ it('should run callback on when dependency is changed', () => {
+ const fn = vi.fn()
+ let skill = 'js'
+
+ const { rerender } = renderHook(() => useSyncedEffect(fn, [skill]))
+ expect(fn).toHaveBeenCalledTimes(0)
- const { rerender, unmount } = renderHook(() => useSyncedEffect(fn, [skill]))
- vi.runAllTimers()
+ vi.runAllTimers()
- skill = 'react'
- rerender()
- expect(fn).toHaveBeenCalledTimes(1)
+ skill = 'react'
+ rerender()
+ expect(fn).toHaveBeenCalledTimes(1)
- unmount()
- expect(cleanupFn).toHaveBeenCalledTimes(1)
+ skill = 'typescript'
+ rerender()
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
})
})
diff --git a/src/lib/use-synced-effect/index.tsx b/src/lib/use-synced-effect/index.tsx
index 0be5030..50a5b6d 100644
--- a/src/lib/use-synced-effect/index.tsx
+++ b/src/lib/use-synced-effect/index.tsx
@@ -1,4 +1,3 @@
-'use client'
import type { DependencyList, EffectCallback } from 'react'
import React, { useEffect, useRef } from 'react'
@@ -6,9 +5,24 @@ const DEP: DependencyList = []
/**
* @description
- * A hooks that fires the given callback for given dependencies.
- *
- * It works exacatly like `useEffect`. But callback doesn't get fired on initial mount.
+ * A React hook that executes a callback when dependencies change, similar to `useEffect`, but skips execution on the initial mount.
+ * @example
+ import { useState } from 'react'
+ import { useSyncedEffect } from 'classic-react-hooks'
+
+ export default function YourComponent() {
+ const [counter, setCounter] = useState(0)
+
+ useSyncedEffect(() => {
+ console.log('counter changed to ', counter)
+ }, [counter])
+
+ return (
+
+ setCounter((c) => c + 1)}>increment
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-synced-effect.html
*/
diff --git a/src/lib/use-synced-ref/index.tsx b/src/lib/use-synced-ref/index.tsx
index 306c8bf..c7b64b2 100644
--- a/src/lib/use-synced-ref/index.tsx
+++ b/src/lib/use-synced-ref/index.tsx
@@ -1,11 +1,33 @@
-'use client'
import React, { useRef } from 'react'
/**
* @description
- * A replacement for `useRef` hook, which automatically synces up with the given state.
+ * A React hook that creates a ref that automatically stays in sync with the provided value, ensuring you always have access to the latest state in asynchronous operations.
*
- * No need to manually update the ref.
+ * @example
+ import { useState } from 'react'
+ import { useSyncedRef } from 'classic-react-hooks'
+
+ export default function Counter() {
+ const [count, setCount] = useState(0)
+ const countRef = useSyncedRef(count)
+
+ const handleAsyncOperation = () => {
+ setTimeout(() => {
+ // countRef.current always has the latest value
+ console.log('Current count:', countRef.current)
+ alert(`Count is now: ${countRef.current}`)
+ }, 2000)
+ }
+
+ return (
+
+
Count: {count}
+
setCount((c) => c + 1)}>Increment
+
Show count after 2 seconds
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-synced-ref.html
*/
diff --git a/src/lib/use-throttled-fn/index.test.tsx b/src/lib/use-throttled-fn/index.test.tsx
index 869e41f..90995aa 100644
--- a/src/lib/use-throttled-fn/index.test.tsx
+++ b/src/lib/use-throttled-fn/index.test.tsx
@@ -1,95 +1,363 @@
import { vi } from 'vitest'
-import { renderHook } from '@testing-library/react'
+import { renderHook, act } from '@testing-library/react'
import useThrottledFn from '.'
describe('use-throttled-fn', () => {
beforeEach(() => {
vi.useFakeTimers()
})
+
afterEach(() => {
vi.useRealTimers()
+ vi.clearAllMocks()
})
- it('should return the throttled callback', () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useThrottledFn(callback, 300))
+ describe('mounting', () => {
+ it('should return a function', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ expect(typeof result.current).toBe('function')
+ })
+
+ it('should not call callback on initialization', () => {
+ const callback = vi.fn()
+ renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ expect(callback).not.toHaveBeenCalled()
+ })
+
+ it('should call callback immediately on first invocation', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ act(() => {
+ result.current()
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ })
+ })
+
+ describe('Throttling behavior', () => {
+ it('should use default delay of 300ms', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ act(() => {
+ result.current()
+ result.current() // Should be ignored
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(299)
+ result.current() // Should still be ignored
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(1) // Total 300ms
+ result.current() // Should be called
+ })
+
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
+
+ it('should respect custom delay', () => {
+ const callback = vi.fn()
+ const customDelay = 500
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: customDelay }))
+
+ act(() => {
+ result.current()
+ result.current() // Should be ignored
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(499)
+ result.current() // Should still be ignored
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(1) // Total 500ms
+ result.current() // Should be called
+ })
+
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
+
+ it('should throttle multiple rapid calls', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: 100 }))
+
+ act(() => {
+ result.current() // Call 1 - should execute
+ result.current() // Call 2 - should be throttled
+ result.current() // Call 3 - should be throttled
+ result.current() // Call 4 - should be throttled
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(100)
+ result.current() // Call 5 - should execute
+ })
+
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
+
+ it('should allow execution after delay has passed', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: 200 }))
+
+ act(() => {
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(200)
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(2)
- expect(typeof result.current).toBe('function')
+ act(() => {
+ vi.advanceTimersByTime(200)
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(3)
+ })
})
- it('should not fire callback on initialization', () => {
- const callback = vi.fn()
- renderHook(() => useThrottledFn(callback, 300))
+ describe('Arguments handling', () => {
+ it('should pass arguments correctly to the callback', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
- expect(callback).not.toHaveBeenCalled()
+ act(() => {
+ result.current('arg1', 'arg2', 123)
+ })
+
+ expect(callback).toHaveBeenCalledWith('arg1', 'arg2', 123)
+ })
+
+ it('should pass different arguments on subsequent calls', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: 100 }))
+
+ act(() => {
+ result.current('first')
+ })
+ expect(callback).toHaveBeenNthCalledWith(1, 'first')
+
+ act(() => {
+ vi.advanceTimersByTime(100)
+ result.current('second')
+ })
+ expect(callback).toHaveBeenNthCalledWith(2, 'second')
+ })
})
- it('should return the throttled callback with default 300ms delay', async () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useThrottledFn(callback))
+ describe('Context binding', () => {
+ it('should preserve this context when called with call()', () => {
+ let capturedThis: any = null
+ const testObj = {
+ name: 'test',
+ callback: function () {
+ capturedThis = this
+ },
+ }
- result.current(10)
- expect(callback).toHaveBeenCalledTimes(1)
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: testObj.callback }))
- result.current(10)
- vi.advanceTimersByTime(500)
+ act(() => {
+ result.current.call(testObj)
+ })
- result.current(10)
- expect(callback).toHaveBeenCalledTimes(2)
+ expect(capturedThis).toBe(testObj)
+ })
- result.current(10)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenCalledTimes(2)
+ it('should preserve this context when called with apply()', () => {
+ let capturedThis: any = null
+ const testObj = {
+ name: 'test',
+ callback: function (arg: string) {
+ capturedThis = this
+ return arg
+ },
+ }
- result.current(10)
- vi.advanceTimersByTime(1000)
- expect(callback).toHaveBeenCalledTimes(3)
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: testObj.callback }))
+
+ act(() => {
+ result.current.apply(testObj, ['test-arg'])
+ })
+
+ expect(capturedThis).toBe(testObj)
+ })
})
- it('should call throttled function with given arguments', async () => {
- const callback = vi.fn()
- const { result } = renderHook(() => useThrottledFn(callback))
- result.current(10)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenNthCalledWith(1, 10)
+ describe('Hook updates and re-renders', () => {
+ it('should update callback when it changes', () => {
+ const callback1 = vi.fn()
+ const callback2 = vi.fn()
+
+ const { result, rerender } = renderHook(({ callback }) => useThrottledFn({ callbackToThrottle: callback }), {
+ initialProps: { callback: callback1 },
+ })
+
+ act(() => {
+ result.current()
+ })
+ expect(callback1).toHaveBeenCalledTimes(1)
+ expect(callback2).not.toHaveBeenCalled()
+
+ // Update the callback
+ rerender({ callback: callback2 })
+
+ act(() => {
+ vi.advanceTimersByTime(300)
+ result.current()
+ })
+ expect(callback1).toHaveBeenCalledTimes(1)
+ expect(callback2).toHaveBeenCalledTimes(1)
+ })
+
+ it('should update delay when it changes', () => {
+ const callback = vi.fn()
+
+ const { result, rerender } = renderHook(
+ ({ delay }) => useThrottledFn({ callbackToThrottle: callback, delay }),
+ { initialProps: { delay: 100 } }
+ )
+
+ act(() => {
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ // Update delay
+ rerender({ delay: 500 })
+
+ act(() => {
+ vi.advanceTimersByTime(100) // Old delay
+ result.current() // Should still be throttled with new delay
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
- result.current(30)
- vi.advanceTimersByTime(300)
- expect(callback).toHaveBeenNthCalledWith(2, 30)
+ act(() => {
+ vi.advanceTimersByTime(400) // Total 500ms (new delay)
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
+
+ it('should maintain throttle state across re-renders', () => {
+ const callback = vi.fn()
+
+ const { result, rerender } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: 200 }))
+
+ act(() => {
+ result.current()
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ // Re-render the component
+ rerender()
+
+ act(() => {
+ result.current() // Should still be throttled
+ })
+ expect(callback).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ vi.advanceTimersByTime(200)
+ result.current() // Should now execute
+ })
+ expect(callback).toHaveBeenCalledTimes(2)
+ })
})
- it('should throttle the callback with custom delay', async () => {
- const callback = vi.fn()
+ describe('Error handling', () => {
+ it('should handle callback that throws an error', () => {
+ const errorCallback = vi.fn(() => {
+ throw new Error('Test error')
+ })
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: errorCallback }))
- const { result } = renderHook(() => useThrottledFn(callback, 500))
+ expect(() => {
+ act(() => {
+ result.current()
+ })
+ }).toThrow('Test error')
- result.current(2)
- vi.advanceTimersByTime(300)
- result.current(2)
- result.current(2)
- vi.advanceTimersByTime(500)
+ expect(errorCallback).toHaveBeenCalledTimes(1)
- expect(callback).toHaveBeenCalledTimes(1)
- expect(callback).toHaveBeenNthCalledWith(1, 2)
+ // Should still throttle after error
+ expect(() => {
+ act(() => {
+ result.current()
+ })
+ }).not.toThrow()
- result.current(5)
- vi.advanceTimersByTime(500)
- expect(callback).toHaveBeenCalledTimes(2)
- expect(callback).toHaveBeenNthCalledWith(2, 5)
+ expect(errorCallback).toHaveBeenCalledTimes(1) // Still throttled
+ })
})
- it('should bind the this context', () => {
- let res: any = ''
- const obj = {
- details: 'this is details',
- callback: function () {
- res = this
- },
- }
+ describe('Performance and memory', () => {
+ it('should not create new throttled function on every render', () => {
+ const callback = vi.fn()
+ const { result, rerender } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ const firstDebouncedFn = result.current
+ rerender()
+ const secondDebouncedFn = result.current
+
+ expect(firstDebouncedFn).toBe(secondDebouncedFn)
+ })
+ })
+
+ describe('Memory and performance', () => {
+ it('should not create new throttled function on every render', () => {
+ const callback = vi.fn()
+ const { result, rerender } = renderHook(() => useThrottledFn({ callbackToThrottle: callback }))
+
+ const firstThrottledFn = result.current
+ rerender()
+ const secondThrottledFn = result.current
+
+ expect(firstThrottledFn).toBe(secondThrottledFn)
+ })
+
+ it('should handle rapid successive calls efficiently', () => {
+ const callback = vi.fn()
+ const { result } = renderHook(() => useThrottledFn({ callbackToThrottle: callback, delay: 100 }))
+
+ act(() => {
+ // Simulate rapid calls
+ for (let i = 0; i < 1000; i++) {
+ result.current(i)
+ }
+ })
+
+ expect(callback).toHaveBeenCalledTimes(1)
+ expect(callback).toHaveBeenCalledWith(0) // First call's argument
- const { result } = renderHook(() => useThrottledFn(obj.callback, 500))
- result.current.call(obj)
+ act(() => {
+ vi.advanceTimersByTime(100)
+ result.current(1001)
+ })
- expect(res).toBe(obj)
+ expect(callback).toHaveBeenCalledTimes(2)
+ expect(callback).toHaveBeenNthCalledWith(2, 1001)
+ })
})
})
diff --git a/src/lib/use-throttled-fn/index.tsx b/src/lib/use-throttled-fn/index.tsx
index 591c9f6..11b7827 100644
--- a/src/lib/use-throttled-fn/index.tsx
+++ b/src/lib/use-throttled-fn/index.tsx
@@ -1,40 +1,95 @@
-'use client'
import React, { useRef } from 'react'
-import useSyncedRef from '../use-synced-ref'
const DEFAULT_DELAY = 300
/**
* @description
- * A hook which returns a throttled function.
+ * A React hook that returns a throttled version of provided function, ensuring it executes at most once per specified time interval, regardless of how frequently it's called.
+ *
+ * @example
+ import { useState } from 'react'
+ import { useThrottledFn } from 'classic-react-hooks'
+
+ export default function AutoSave() {
+ const [content, setContent] = useState('')
+ const [saving, setSaving] = useState(false)
+
+ const saveContent = useThrottledFn({
+ callbackToThrottle: async (text) => {
+ setSaving(true)
+ try {
+ await saveToAPI(text)
+ console.log('Content saved!')
+ } catch (error) {
+ console.error('Save failed:', error)
+ } finally {
+ setSaving(false)
+ }
+ },
+ delay: 2000, // Auto-save every 2 seconds at most
+ })
+
+ const handleChange = (e) => {
+ const newContent = e.target.value
+ setContent(newContent)
+ saveContent(newContent)
+ }
+
+ return (
+
+
+ {saving &&
Saving...
}
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-throttled-fn.html
*
*/
-export default function useThrottledFn any>(cb: T, delay = DEFAULT_DELAY) {
- const paramsRef = useSyncedRef({
- cb,
+export default function useThrottledFn any>({
+ callbackToThrottle,
+ delay,
+}: {
+ callbackToThrottle: T
+ delay?: number
+}) {
+ const paramsRef = useRef({
+ callbackToThrottle,
delay,
})
- const throttledCb = useRef(throttledFnWrapper(paramsRef.current.cb, paramsRef.current.delay))
+ // tracking props with immutable object
+ paramsRef.current.delay = delay
+ paramsRef.current.callbackToThrottle = callbackToThrottle
+
+ // so can access the updated props inside debouncedFnWrapper function
+ const throttledCb = useRef(throttledFnWrapper(paramsRef.current))
+
return throttledCb.current
}
/**
* @description
- * A wrapper function which is used internally in `useThrttledFn` hook.
+ * A wrapper function which is used internally in `useThrottledFn` hook.
*/
-export function throttledFnWrapper any>(cb: T, delay = DEFAULT_DELAY) {
+export function throttledFnWrapper any>(props: {
+ callbackToThrottle: T
+ delay?: number
+}) {
let lastExecutionTime = 0
- return function (...args: Parameters) {
+ return function (...args: Parameters) {
const currentTime = Date.now()
- if (currentTime - lastExecutionTime >= delay) {
- // @ts-ignore
- cb.call(this, ...args)
- lastExecutionTime = currentTime
+ if (currentTime - lastExecutionTime >= (props.delay ?? DEFAULT_DELAY)) {
+ try {
+ // @ts-expect-error -> making "this" as "any" type working
+ props.callbackToThrottle.call(this, ...args)
+ } catch (err) {
+ throw err
+ } finally {
+ lastExecutionTime = currentTime
+ }
}
}
}
diff --git a/src/lib/use-timeout-effect/index.test.tsx b/src/lib/use-timeout-effect/index.test.tsx
index 131c56a..4b72191 100644
--- a/src/lib/use-timeout-effect/index.test.tsx
+++ b/src/lib/use-timeout-effect/index.test.tsx
@@ -1,82 +1,254 @@
import { vi } from 'vitest'
import { renderHook } from '@testing-library/react'
-import useTimoeoutEffect from '.'
+import useTimeoutEffect from '.'
describe('use-timeout-effect', () => {
beforeEach(() => {
vi.useFakeTimers()
})
+
afterEach(() => {
vi.useRealTimers()
- })
- afterEach(() => {
vi.clearAllTimers()
})
- it('should fire callback with default timeout of 0ms after the mount', () => {
- const fn = vi.fn()
- renderHook(() => useTimoeoutEffect(fn))
-
- expect(fn).toHaveBeenCalledTimes(0)
- vi.advanceTimersByTime(100)
- expect(fn).toHaveBeenCalledTimes(1)
+ describe('mounting', () => {
+ it('should fire callback with default timeout of 100ms after mount', () => {
+ const fn = vi.fn()
+ renderHook(() => useTimeoutEffect({ handler: fn }))
+
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(99)
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(1)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
+
+ it('should fire callback with specified timeout prop', () => {
+ const fn = vi.fn()
+ renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(499)
+ expect(fn).not.toHaveBeenCalled()
+ vi.advanceTimersByTime(1)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
+
+ it('should only fire callback once', () => {
+ const fn = vi.fn()
+ renderHook(() => useTimeoutEffect({ handler: fn, timeout: 100 }))
+
+ vi.advanceTimersByTime(100)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ // Advance more time to ensure it doesn't fire again
+ vi.advanceTimersByTime(1000)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
})
- it('should fire callback after the given timeout', () => {
- const fn = vi.fn()
- renderHook(() => useTimoeoutEffect(fn, 500))
+ describe('unmounting', () => {
+ it('should clear timeout on unmount before timeout expires', () => {
+ const fn = vi.fn()
+ const { unmount } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ vi.advanceTimersByTime(200)
+ unmount()
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+ })
- expect(fn).toHaveBeenCalledTimes(0)
- vi.advanceTimersByTime(0)
- expect(fn).toHaveBeenCalledTimes(0)
+ it('should not interfere with callback execution if unmounted after timeout', () => {
+ const fn = vi.fn()
+ const { unmount } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 100 }))
- vi.advanceTimersByTime(400)
- expect(fn).toHaveBeenCalledTimes(0)
+ vi.advanceTimersByTime(100)
+ expect(fn).toHaveBeenCalledTimes(1)
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(1)
+ unmount()
+ vi.advanceTimersByTime(1000)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
})
- it('should clear the timeout with clearTimer', () => {
- const fn = vi.fn()
- const { result } = renderHook(() => useTimoeoutEffect(fn, 500))
+ describe('clearTimer functionality', () => {
+ it('should clear the timeout when prop changes', () => {
+ const fn = vi.fn()
+
+ let timeout = 300
+ const { result, rerender } = renderHook(() => useTimeoutEffect({ handler: fn, timeout }))
+
+ vi.advanceTimersByTime(200)
+ expect(fn).not.toHaveBeenCalled()
+
+ timeout = 500
+ rerender()
+
+ vi.advanceTimersByTime(200)
+ expect(fn).not.toHaveBeenCalled()
+
+ vi.advanceTimersByTime(300)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
- result.current.clearTimer()
- vi.advanceTimersByTime(500)
- expect(fn).not.toHaveBeenCalled()
+ it('should clear the timeout with clearTimer before timeout expires', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ vi.advanceTimersByTime(200)
+ result.current.clearTimer()
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+ })
+
+ it('should allow clearing timer multiple times without error', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ result.current.clearTimer()
+ result.current.clearTimer()
+ result.current.clearTimer()
+
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+ })
+ })
+
+ describe('restartTimer functionality', () => {
+ it('should restart timer with original timeout', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ // Let original timer fire
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ // Restart timer
+ result.current.restartTimer()
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
+
+ it('should restart timer with new timeout value provided in restartTimer function', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ // Restart with new timeout before original fires
+ vi.advanceTimersByTime(200)
+ result.current.restartTimer(600)
+
+ // Original timeout should not fire
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+
+ // New timeout should fire
+ vi.advanceTimersByTime(100) // 500 + 100 = 600
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
+ it('should restart timer with original value after overriding of timer with restartTimer function', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ // Restart with new timeout before original fires
+ vi.advanceTimersByTime(200)
+ result.current.restartTimer(600)
+
+ // Original timeout should not fire
+ vi.advanceTimersByTime(500)
+ expect(fn).not.toHaveBeenCalled()
+
+ // New timeout should fire
+ vi.advanceTimersByTime(100) // 500 + 100 = 600
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ // will pickup the original timer value = 500
+ result.current.restartTimer()
+
+ // Fire after 500ms
+ vi.advanceTimersByTime(500)
+ expect(fn).toHaveBeenCalledTimes(2)
+ })
+
+ it('should cancel previous timer when restarting', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ // Restart before original timeout
+ vi.advanceTimersByTime(200)
+ result.current.restartTimer()
+
+ // Advance to where original would have fired
+ vi.advanceTimersByTime(300)
+ expect(fn).not.toHaveBeenCalled()
+
+ // Advance to where restarted timer should fire
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
+
+ it('should handle restart followed by clear', () => {
+ const fn = vi.fn()
+ const { result } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: 500 }))
+
+ result.current.restartTimer()
+ result.current.clearTimer()
+ vi.advanceTimersByTime(1000)
+ expect(fn).not.toHaveBeenCalled()
+
+ // Should be able to restart again after clearing
+ result.current.restartTimer(200)
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
})
- it('should set the timeout with restartTimer', () => {
- const fn = vi.fn()
- const { result } = renderHook(() => useTimoeoutEffect(fn, 500))
+ describe('parameter updates', () => {
+ it('should use latest handler when timeout fires', () => {
+ const fn1 = vi.fn()
+ const fn2 = vi.fn()
+ let currentHandler = fn1
+
+ const { rerender } = renderHook(() => useTimeoutEffect({ handler: currentHandler, timeout: 500 }))
+
+ // Update handler before timeout fires
+ vi.advanceTimersByTime(200)
+ currentHandler = fn2
+ rerender()
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalled()
- expect(fn).toHaveBeenCalledTimes(1)
+ vi.advanceTimersByTime(300)
+ expect(fn1).not.toHaveBeenCalled()
+ expect(fn2).toHaveBeenCalledTimes(1)
+ })
- // restart
- result.current.restartTimer()
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(2)
+ it('should use latest timeout value for restartTimer', () => {
+ const fn = vi.fn()
+ let currentTimeout = 500
- // restart and clear and restart
- result.current.restartTimer()
- result.current.clearTimer()
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(2)
+ const { result, rerender } = renderHook(() => useTimeoutEffect({ handler: fn, timeout: currentTimeout }))
- result.current.restartTimer()
- vi.advanceTimersByTime(500)
- expect(fn).toHaveBeenCalledTimes(3)
+ // Update timeout and restart
+ currentTimeout = 200
+ rerender()
+ result.current.restartTimer()
+
+ vi.advanceTimersByTime(200)
+ expect(fn).toHaveBeenCalledTimes(1)
+ })
})
- it('should clear interval on unmount', () => {
- const fn = vi.fn()
- const { unmount } = renderHook(() => useTimoeoutEffect(fn, 500))
+ describe('error handling', () => {
+ it('should not throw when handler throws an error', () => {
+ const errorHandler = vi.fn(() => {
+ throw new Error('Test error')
+ })
+
+ expect(() => {
+ renderHook(() => useTimeoutEffect({ handler: errorHandler, timeout: 100 }))
+ vi.advanceTimersByTime(100)
+ }).toThrow('Test error')
- // cleanup the timer
- vi.advanceTimersByTime(400)
- unmount()
- expect(fn).toHaveBeenCalledTimes(0)
+ expect(errorHandler).toHaveBeenCalledTimes(1)
+ })
})
})
diff --git a/src/lib/use-timeout-effect/index.tsx b/src/lib/use-timeout-effect/index.tsx
index d63448b..7a66382 100644
--- a/src/lib/use-timeout-effect/index.tsx
+++ b/src/lib/use-timeout-effect/index.tsx
@@ -1,16 +1,32 @@
-'use client'
import React, { useEffect, useRef } from 'react'
import useSyncedRef from '../use-synced-ref'
/**
* @description
- * A hook which fires the provided callback only once when the given timeout is passed, just like the setTimeout.
+ * A React hook that fires a provided callback after a specified timeout, similar to `setTimeout`, but with additional control methods for clearing and restarting the timer.
+ *
+ * @example
+ * import { useState } from 'react'
+ import useTimeoutEffect from './useTimeoutEffect'
+
+ export default function BasicExample() {
+ const [message, setMessage] = useState('')
+
+ useTimeoutEffect({
+ handler: () => {
+ setMessage('Timer executed!')
+ },
+ timeout: 2000,
+ })
+
+ return {message}
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-timeout-effect.html
*/
-export default function useTimeoutEffect(cb: () => void, timeout = 100) {
+export default function useTimeoutEffect({ handler, timeout = 100 }: { handler: () => void; timeout?: number }) {
let paramsRef = useSyncedRef({
- cb,
+ handler,
timeout,
})
const timeoutId = useRef()
@@ -19,14 +35,14 @@ export default function useTimeoutEffect(cb: () => void, timeout = 100) {
clearTimer: () => clearTimeout(timeoutId.current),
restartTimer: (new_interval?: number) => {
handlers.current.clearTimer()
- timeoutId.current = setTimeout(paramsRef.current.cb, new_interval ?? paramsRef.current.timeout)
+ timeoutId.current = setTimeout(() => paramsRef.current.handler(), new_interval ?? paramsRef.current.timeout)
},
})
useEffect(() => {
- timeoutId.current = setTimeout(paramsRef.current.cb, paramsRef.current.timeout)
+ timeoutId.current = setTimeout(() => paramsRef.current.handler(), timeout)
return handlers.current.clearTimer
- }, [])
+ }, [timeout])
return {
clearTimer: handlers.current.clearTimer,
diff --git a/src/lib/use-window-resize/index.test.tsx b/src/lib/use-window-resize/index.test.tsx
index c011735..1a428db 100644
--- a/src/lib/use-window-resize/index.test.tsx
+++ b/src/lib/use-window-resize/index.test.tsx
@@ -1,56 +1,158 @@
-import { renderHook } from '@testing-library/react'
+import { act, render, renderHook, screen } from '@testing-library/react'
import { vi } from 'vitest'
import useWindowResize from '.'
-import { act } from 'react-dom/test-utils'
describe('use-window-resize', () => {
- it('should run without errors', () => {
- renderHook(() => useWindowResize(() => window.innerWidth < 400))
+ describe('mounting', () => {
+ it('should render without errors', () => {
+ renderHook(() => useWindowResize({ handler: () => window.innerWidth < 400 }))
+ })
})
+ describe('unmounting', () => {
+ it('should remove event on unmount', () => {
+ vi.spyOn(window, 'removeEventListener')
- it('should return defaultValue, if defaultValue is passed', () => {
- const { result } = renderHook(() => useWindowResize(() => window.innerWidth < 400, { defaultValue: true }))
- expect(result.current).toBe(true)
- })
+ const { unmount } = renderHook(() => useWindowResize({ handler: () => window.innerWidth < 400 }))
+ expect(window.removeEventListener).not.toHaveBeenCalled()
+ unmount()
+ expect(window.removeEventListener).toHaveBeenCalledWith('resize', expect.any(Function), expect.any(Object))
+ })
+
+ it('should remove resize event when shouldInjectEvent becomes false', () => {
+ let shouldInjectEvent = true
+ const fn = vi.fn()
+ vi.spyOn(window, 'removeEventListener')
- it('should update the result when window is resized', () => {
- const { result } = renderHook(() =>
- useWindowResize(() => {
- return window.innerWidth < 400
+ const { rerender } = renderHook(() => useWindowResize({ handler: fn, options: { shouldInjectEvent } }))
+ expect(fn).toHaveBeenCalledTimes(1)
+
+ act(() => {
+ window.dispatchEvent(new Event('resize'))
})
- )
- expect(result.current).toBe(false)
+ expect(fn).toHaveBeenCalledTimes(2)
+ expect(fn).toHaveBeenCalledTimes(2)
+ expect(window.removeEventListener).not.toHaveBeenCalled()
+
+ shouldInjectEvent = false
+ rerender()
+ expect(window.removeEventListener).toHaveBeenCalledWith('resize', expect.any(Function), expect.any(Object))
- act(() => {
- window.innerWidth = 200
- window.dispatchEvent(new Event('resize'))
+ act(() => {
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(fn).toHaveBeenCalledTimes(2)
})
- expect(result.current).toBe(true)
+ })
- act(() => {
- window.innerWidth = 600
- window.dispatchEvent(new Event('resize'))
+ describe('defaultValue behavior', () => {
+ it('should return defaultValue as result if defaultValue is passed', () => {
+ const { result } = renderHook(() => useWindowResize({ handler: vi.fn(), options: { defaultValue: true } }))
+ expect(result.current).toBe(true)
})
- expect(result.current).toBe(false)
})
- it('should remove resize event when shouldInjectEvent becomes false', () => {
- let shouldInjectEvent = true
- const cb = vi.fn()
+ describe('resize event trigger', () => {
+ it('should update the result when window is resized', () => {
+ const { result } = renderHook(() =>
+ useWindowResize({
+ handler: () => {
+ return window.innerWidth < 400
+ },
+ })
+ )
+ expect(result.current).toBe(false)
+
+ act(() => {
+ window.innerWidth = 200
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(result.current).toBe(true)
+
+ act(() => {
+ window.innerWidth = 600
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(result.current).toBe(false)
+ })
+
+ it('should dynamically add and remove event listener based on shouldInjectEvent', () => {
+ let shouldInjectEvent = true
+ const handler = vi.fn(() => window.innerWidth < 400)
+
+ // Initial render with shouldInjectEvent: true
+ const { rerender } = renderHook(() =>
+ useWindowResize({
+ handler,
+ options: { shouldInjectEvent },
+ })
+ )
+ expect(handler).toHaveBeenCalledTimes(1) // Called once on initial render
- const { rerender } = renderHook(() => useWindowResize(cb, { shouldInjectEvent }))
- expect(cb).toHaveBeenCalledTimes(1)
- act(() => {
- window.dispatchEvent(new Event('resize'))
+ // Trigger resize, handler should be called
+ act(() => {
+ window.innerWidth = 300
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(handler).toHaveBeenCalledTimes(2)
+
+ // Change shouldInjectEvent to false and rerender
+ shouldInjectEvent = false
+ rerender()
+ expect(handler).toHaveBeenCalledTimes(2) // Handler not called on rerender with shouldInjectEvent: false
+
+ // Trigger resize, handler should NOT be called
+ act(() => {
+ window.innerWidth = 200
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(handler).toHaveBeenCalledTimes(2) // Still 2, event listener removed
+
+ // Change shouldInjectEvent back to true and rerender
+ shouldInjectEvent = true
+ rerender()
+ act(() => {
+ window.dispatchEvent(new Event('resize'))
+ expect(handler).toHaveBeenCalledTimes(3) // Handler called again because event listener re-added
+ })
+
+ // Trigger resize, handler should be called again
+ act(() => {
+ window.innerWidth = 100
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(handler).toHaveBeenCalledTimes(4)
})
- expect(cb).toHaveBeenCalledTimes(2)
- expect(cb).toHaveBeenCalledTimes(2)
+ })
+
+ describe('integration with React component', () => {
+ it('should update component based on window resize', () => {
+ // Initial width: Desktop View
+ window.innerWidth = 1024
+ render( )
+ expect(screen.getByText('Desktop View')).toBeInTheDocument()
+ expect(screen.queryByText('Mobile View')).not.toBeInTheDocument()
+
+ // Resize to mobile width
+ act(() => {
+ window.innerWidth = 500
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(screen.getByText('Mobile View')).toBeInTheDocument()
+ expect(screen.queryByText('Desktop View')).not.toBeInTheDocument()
- shouldInjectEvent = false
- rerender()
- act(() => {
- window.dispatchEvent(new Event('resize'))
+ // Resize back to desktop width
+ act(() => {
+ window.innerWidth = 800
+ window.dispatchEvent(new Event('resize'))
+ })
+ expect(screen.getByText('Desktop View')).toBeInTheDocument()
+ expect(screen.queryByText('Mobile View')).not.toBeInTheDocument()
})
- expect(cb).toHaveBeenCalledTimes(2)
})
})
+
+function TestComponent() {
+ const isMobile = useWindowResize({ handler: () => window.innerWidth < 768 })
+
+ return {isMobile ? 'Mobile View' : 'Desktop View'}
+}
diff --git a/src/lib/use-window-resize/index.tsx b/src/lib/use-window-resize/index.tsx
index 49d5fa7..a707825 100644
--- a/src/lib/use-window-resize/index.tsx
+++ b/src/lib/use-window-resize/index.tsx
@@ -1,17 +1,51 @@
-'use client'
import { useState } from 'react'
import { useEventListener } from '../use-event-listener'
/**
* @description
- * A hook which evaluates the passed callback on window resize event and returns the result of that callback.
+ * A React hook that evaluates provided callback function on window resize event and returns the result of it.
+ *
+ * @example
+ import { useWindowResize } from 'classic-react-hooks'
+
+ function ResponsiveComponent() {
+ const breakpoint = useWindowResize(() => {
+ const width = window.innerWidth
+ if (width < 640) return 'sm'
+ if (width < 768) return 'md'
+ if (width < 1024) return 'lg'
+ return 'xl'
+ })
+
+ return (
+
+
Current breakpoint: {breakpoint}
+ {breakpoint === 'sm' &&
}
+ {breakpoint === 'md' &&
}
+ {['lg', 'xl'].includes(breakpoint) &&
}
+
+ )
+ }
*
* @see Docs https://classic-react-hooks.vercel.app/hooks/use-window-resize.html
*/
-export default function useWindowResize(cb: () => T, options?: { defaultValue?: T; shouldInjectEvent?: boolean }) {
- const [result, setResult] = useState(options?.defaultValue ?? cb)
-
- useEventListener(window, 'resize', () => setResult(cb), { shouldInjectEvent: options?.shouldInjectEvent ?? true })
+export default function useWindowResize({
+ handler,
+ options,
+}: {
+ handler: () => T
+ options?: { defaultValue?: T; shouldInjectEvent?: boolean }
+}) {
+ const [result, setResult] = useState(options?.defaultValue ?? handler)
+ useEventListener({
+ target: () => window,
+ event: 'resize',
+ handler: () => setResult(handler),
+ options: {
+ shouldInjectEvent: options?.shouldInjectEvent ?? true,
+ },
+ layoutEffect: true,
+ })
return result
}
diff --git a/src/types/index.ts b/src/types/index.ts
index 948daa1..68e3fcf 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,3 +1,13 @@
export type Prettify = {
[Key in keyof K]: K[Key]
} & {}
+
+export type EvTarget = () => EventTarget | null
+export interface EvOptions extends AddEventListenerOptions {
+ shouldInjectEvent?: boolean | any
+}
+export type EvHandler = (event: Event) => void
+
+export type UseEventListenerReturnValues = {
+ setElementRef: (elementNode: HTMLElement | null) => void
+}
diff --git a/tsup.config.ts b/tsdown.config.ts
similarity index 60%
rename from tsup.config.ts
rename to tsdown.config.ts
index e59b603..e9eaf7d 100644
--- a/tsup.config.ts
+++ b/tsdown.config.ts
@@ -1,18 +1,16 @@
-import { defineConfig } from 'tsup'
+import { defineConfig } from 'tsdown'
export default defineConfig({
entry: ['src/index.tsx'],
- splitting: true,
+ platform:'neutral',
sourcemap: true,
clean: true,
dts: true,
format: ['cjs', 'esm'],
- minify: 'terser',
+ minify: true,
shims: true,
outDir: 'dist',
- target: 'es2017',
+ target: 'esnext',
treeshake: true,
- jsxFragment: 'React.Fragment',
- metafile: true,
tsconfig: './tsconfig.json',
})
diff --git a/vitest.config.mts b/vitest.config.mts
index d5adfc5..c3eb360 100644
--- a/vitest.config.mts
+++ b/vitest.config.mts
@@ -14,8 +14,9 @@ export default defineConfig({
all: true,
include: ['src/lib/**/*'],
exclude: ['src/lib/use-combined-key-event-listener'],
+ reporter:['html','text']
},
- include: ['src/lib/**/*.{test,spec}.{js,jsx,ts,tsx}'],
+ include: ['src/lib/**/*.test.{tsx,ts}'],
exclude: [
'**/node_modules/**',
'**/dist/**',