feat : add signin ,signout, forgot password features
This commit is contained in:
32
node_modules/.package-lock.json
generated
vendored
32
node_modules/.package-lock.json
generated
vendored
@@ -597,13 +597,13 @@
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
|
||||
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -5208,6 +5208,34 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
|
||||
"integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=18.0.0",
|
||||
"use-sync-external-store": ">=1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
node_modules/.vite/deps/_metadata.json
generated
vendored
26
node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,53 +1,59 @@
|
||||
{
|
||||
"hash": "6cbb90ff",
|
||||
"browserHash": "c7ceac79",
|
||||
"hash": "ff6fda40",
|
||||
"browserHash": "b50068b3",
|
||||
"optimized": {
|
||||
"react/jsx-runtime": {
|
||||
"src": "../../react/jsx-runtime.js",
|
||||
"file": "react_jsx-runtime.js",
|
||||
"fileHash": "dd501a3d",
|
||||
"fileHash": "ddd613d5",
|
||||
"needsInterop": true
|
||||
},
|
||||
"react/jsx-dev-runtime": {
|
||||
"src": "../../react/jsx-dev-runtime.js",
|
||||
"file": "react_jsx-dev-runtime.js",
|
||||
"fileHash": "734127f4",
|
||||
"fileHash": "db7123d4",
|
||||
"needsInterop": true
|
||||
},
|
||||
"react": {
|
||||
"src": "../../react/index.js",
|
||||
"file": "react.js",
|
||||
"fileHash": "04b54be7",
|
||||
"fileHash": "f0784960",
|
||||
"needsInterop": true
|
||||
},
|
||||
"axios": {
|
||||
"src": "../../axios/index.js",
|
||||
"file": "axios.js",
|
||||
"fileHash": "0645ca65",
|
||||
"fileHash": "b9f81ab8",
|
||||
"needsInterop": false
|
||||
},
|
||||
"lucide-react": {
|
||||
"src": "../../lucide-react/dist/esm/lucide-react.mjs",
|
||||
"file": "lucide-react.js",
|
||||
"fileHash": "f1ba9b47",
|
||||
"fileHash": "a5656c81",
|
||||
"needsInterop": false
|
||||
},
|
||||
"react-dom/client": {
|
||||
"src": "../../react-dom/client.js",
|
||||
"file": "react-dom_client.js",
|
||||
"fileHash": "eb1306a5",
|
||||
"fileHash": "ae58904b",
|
||||
"needsInterop": true
|
||||
},
|
||||
"react-router-dom": {
|
||||
"src": "../../react-router-dom/dist/index.js",
|
||||
"file": "react-router-dom.js",
|
||||
"fileHash": "1d841c06",
|
||||
"fileHash": "420348ee",
|
||||
"needsInterop": false
|
||||
},
|
||||
"recharts": {
|
||||
"src": "../../recharts/es6/index.js",
|
||||
"file": "recharts.js",
|
||||
"fileHash": "7cd4b4b9",
|
||||
"fileHash": "dafddd35",
|
||||
"needsInterop": false
|
||||
},
|
||||
"zustand": {
|
||||
"src": "../../zustand/esm/index.mjs",
|
||||
"file": "zustand.js",
|
||||
"fileHash": "f2ee525b",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
|
||||
56
node_modules/.vite/deps/zustand.js
generated
vendored
Normal file
56
node_modules/.vite/deps/zustand.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
require_react
|
||||
} from "./chunk-WQMOH32Y.js";
|
||||
import {
|
||||
__toESM
|
||||
} from "./chunk-5WWUZCGV.js";
|
||||
|
||||
// node_modules/zustand/esm/vanilla.mjs
|
||||
var createStoreImpl = (createState) => {
|
||||
let state;
|
||||
const listeners = /* @__PURE__ */ new Set();
|
||||
const setState = (partial, replace) => {
|
||||
const nextState = typeof partial === "function" ? partial(state) : partial;
|
||||
if (!Object.is(nextState, state)) {
|
||||
const previousState = state;
|
||||
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
||||
listeners.forEach((listener) => listener(state, previousState));
|
||||
}
|
||||
};
|
||||
const getState = () => state;
|
||||
const getInitialState = () => initialState;
|
||||
const subscribe = (listener) => {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
};
|
||||
const api = { setState, getState, getInitialState, subscribe };
|
||||
const initialState = state = createState(setState, getState, api);
|
||||
return api;
|
||||
};
|
||||
var createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
|
||||
|
||||
// node_modules/zustand/esm/react.mjs
|
||||
var import_react = __toESM(require_react(), 1);
|
||||
var identity = (arg) => arg;
|
||||
function useStore(api, selector = identity) {
|
||||
const slice = import_react.default.useSyncExternalStore(
|
||||
api.subscribe,
|
||||
import_react.default.useCallback(() => selector(api.getState()), [api, selector]),
|
||||
import_react.default.useCallback(() => selector(api.getInitialState()), [api, selector])
|
||||
);
|
||||
import_react.default.useDebugValue(slice);
|
||||
return slice;
|
||||
}
|
||||
var createImpl = (createState) => {
|
||||
const api = createStore(createState);
|
||||
const useBoundStore = (selector) => useStore(api, selector);
|
||||
Object.assign(useBoundStore, api);
|
||||
return useBoundStore;
|
||||
};
|
||||
var create = (createState) => createState ? createImpl(createState) : createImpl;
|
||||
export {
|
||||
create,
|
||||
createStore,
|
||||
useStore
|
||||
};
|
||||
//# sourceMappingURL=zustand.js.map
|
||||
7
node_modules/.vite/deps/zustand.js.map
generated
vendored
Normal file
7
node_modules/.vite/deps/zustand.js.map
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../zustand/esm/vanilla.mjs", "../../zustand/esm/react.mjs"],
|
||||
"sourcesContent": ["const createStoreImpl = (createState) => {\n let state;\n const listeners = /* @__PURE__ */ new Set();\n const setState = (partial, replace) => {\n const nextState = typeof partial === \"function\" ? partial(state) : partial;\n if (!Object.is(nextState, state)) {\n const previousState = state;\n state = (replace != null ? replace : typeof nextState !== \"object\" || nextState === null) ? nextState : Object.assign({}, state, nextState);\n listeners.forEach((listener) => listener(state, previousState));\n }\n };\n const getState = () => state;\n const getInitialState = () => initialState;\n const subscribe = (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n };\n const api = { setState, getState, getInitialState, subscribe };\n const initialState = state = createState(setState, getState, api);\n return api;\n};\nconst createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);\n\nexport { createStore };\n", "import React from 'react';\nimport { createStore } from 'zustand/vanilla';\n\nconst identity = (arg) => arg;\nfunction useStore(api, selector = identity) {\n const slice = React.useSyncExternalStore(\n api.subscribe,\n React.useCallback(() => selector(api.getState()), [api, selector]),\n React.useCallback(() => selector(api.getInitialState()), [api, selector])\n );\n React.useDebugValue(slice);\n return slice;\n}\nconst createImpl = (createState) => {\n const api = createStore(createState);\n const useBoundStore = (selector) => useStore(api, selector);\n Object.assign(useBoundStore, api);\n return useBoundStore;\n};\nconst create = ((createState) => createState ? createImpl(createState) : createImpl);\n\nexport { create, useStore };\n"],
|
||||
"mappings": ";;;;;;;;AAAA,IAAM,kBAAkB,CAAC,gBAAgB;AACvC,MAAI;AACJ,QAAM,YAA4B,oBAAI,IAAI;AAC1C,QAAM,WAAW,CAAC,SAAS,YAAY;AACrC,UAAM,YAAY,OAAO,YAAY,aAAa,QAAQ,KAAK,IAAI;AACnE,QAAI,CAAC,OAAO,GAAG,WAAW,KAAK,GAAG;AAChC,YAAM,gBAAgB;AACtB,eAAS,WAAW,OAAO,UAAU,OAAO,cAAc,YAAY,cAAc,QAAQ,YAAY,OAAO,OAAO,CAAC,GAAG,OAAO,SAAS;AAC1I,gBAAU,QAAQ,CAAC,aAAa,SAAS,OAAO,aAAa,CAAC;AAAA,IAChE;AAAA,EACF;AACA,QAAM,WAAW,MAAM;AACvB,QAAM,kBAAkB,MAAM;AAC9B,QAAM,YAAY,CAAC,aAAa;AAC9B,cAAU,IAAI,QAAQ;AACtB,WAAO,MAAM,UAAU,OAAO,QAAQ;AAAA,EACxC;AACA,QAAM,MAAM,EAAE,UAAU,UAAU,iBAAiB,UAAU;AAC7D,QAAM,eAAe,QAAQ,YAAY,UAAU,UAAU,GAAG;AAChE,SAAO;AACT;AACA,IAAM,cAAe,CAAC,gBAAgB,cAAc,gBAAgB,WAAW,IAAI;;;ACrBnF,mBAAkB;AAGlB,IAAM,WAAW,CAAC,QAAQ;AAC1B,SAAS,SAAS,KAAK,WAAW,UAAU;AAC1C,QAAM,QAAQ,aAAAA,QAAM;AAAA,IAClB,IAAI;AAAA,IACJ,aAAAA,QAAM,YAAY,MAAM,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,IACjE,aAAAA,QAAM,YAAY,MAAM,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,EAC1E;AACA,eAAAA,QAAM,cAAc,KAAK;AACzB,SAAO;AACT;AACA,IAAM,aAAa,CAAC,gBAAgB;AAClC,QAAM,MAAM,YAAY,WAAW;AACnC,QAAM,gBAAgB,CAAC,aAAa,SAAS,KAAK,QAAQ;AAC1D,SAAO,OAAO,eAAe,GAAG;AAChC,SAAO;AACT;AACA,IAAM,SAAU,CAAC,gBAAgB,cAAc,WAAW,WAAW,IAAI;",
|
||||
"names": ["React"]
|
||||
}
|
||||
21
node_modules/zustand/LICENSE
generated
vendored
Normal file
21
node_modules/zustand/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Paul Henschel
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
506
node_modules/zustand/README.md
generated
vendored
Normal file
506
node_modules/zustand/README.md
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
<p align="center">
|
||||
<img src="docs/bear.jpg" />
|
||||
</p>
|
||||
|
||||
[](https://github.com/pmndrs/zustand/actions?query=workflow%3ALint)
|
||||
[](https://bundlejs.com/?q=zustand)
|
||||
[](https://www.npmjs.com/package/zustand)
|
||||
[](https://www.npmjs.com/package/zustand)
|
||||
[](https://discord.gg/poimandres)
|
||||
|
||||
A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy API based on hooks, isn't boilerplatey or opinionated.
|
||||
|
||||
Don't disregard it because it's cute. It has quite the claws, lots of time was spent dealing with common pitfalls, like the dreaded [zombie child problem](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children), [react concurrency](https://github.com/bvaughn/rfcs/blob/useMutableSource/text/0000-use-mutable-source.md), and [context loss](https://github.com/facebook/react/issues/13332) between mixed renderers. It may be the one state-manager in the React space that gets all of these right.
|
||||
|
||||
You can try a live [demo](https://zustand-demo.pmnd.rs/) and read the [docs](https://zustand.docs.pmnd.rs/).
|
||||
|
||||
```bash
|
||||
npm install zustand
|
||||
```
|
||||
|
||||
:warning: This readme is written for JavaScript users. If you are a TypeScript user, be sure to check out our [TypeScript Usage section](#typescript-usage).
|
||||
|
||||
## First create a store
|
||||
|
||||
Your store is a hook! You can put anything in it: primitives, objects, functions. State has to be updated immutably and the `set` function [merges state](./docs/guides/immutable-state-and-merging.md) to help it.
|
||||
|
||||
```jsx
|
||||
import { create } from 'zustand'
|
||||
|
||||
const useBearStore = create((set) => ({
|
||||
bears: 0,
|
||||
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
|
||||
removeAllBears: () => set({ bears: 0 }),
|
||||
}))
|
||||
```
|
||||
|
||||
## Then bind your components, and that's it!
|
||||
|
||||
Use the hook anywhere, no providers are needed. Select your state and the component will re-render on changes.
|
||||
|
||||
```jsx
|
||||
function BearCounter() {
|
||||
const bears = useBearStore((state) => state.bears)
|
||||
return <h1>{bears} around here ...</h1>
|
||||
}
|
||||
|
||||
function Controls() {
|
||||
const increasePopulation = useBearStore((state) => state.increasePopulation)
|
||||
return <button onClick={increasePopulation}>one up</button>
|
||||
}
|
||||
```
|
||||
|
||||
### Why zustand over redux?
|
||||
|
||||
- Simple and un-opinionated
|
||||
- Makes hooks the primary means of consuming state
|
||||
- Doesn't wrap your app in context providers
|
||||
- [Can inform components transiently (without causing render)](#transient-updates-for-often-occurring-state-changes)
|
||||
|
||||
### Why zustand over context?
|
||||
|
||||
- Less boilerplate
|
||||
- Renders components only on changes
|
||||
- Centralized, action-based state management
|
||||
|
||||
---
|
||||
|
||||
# Recipes
|
||||
|
||||
## Fetching everything
|
||||
|
||||
You can, but bear in mind that it will cause the component to update on every state change!
|
||||
|
||||
```jsx
|
||||
const state = useBearStore()
|
||||
```
|
||||
|
||||
## Selecting multiple state slices
|
||||
|
||||
It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.
|
||||
|
||||
```jsx
|
||||
const nuts = useBearStore((state) => state.nuts)
|
||||
const honey = useBearStore((state) => state.honey)
|
||||
```
|
||||
|
||||
If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can use [useShallow](./docs/guides/prevent-rerenders-with-use-shallow.md) to prevent unnecessary rerenders when the selector output does not change according to shallow equal.
|
||||
|
||||
```jsx
|
||||
import { create } from 'zustand'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
|
||||
const useBearStore = create((set) => ({
|
||||
nuts: 0,
|
||||
honey: 0,
|
||||
treats: {},
|
||||
// ...
|
||||
}))
|
||||
|
||||
// Object pick, re-renders the component when either state.nuts or state.honey change
|
||||
const { nuts, honey } = useBearStore(
|
||||
useShallow((state) => ({ nuts: state.nuts, honey: state.honey })),
|
||||
)
|
||||
|
||||
// Array pick, re-renders the component when either state.nuts or state.honey change
|
||||
const [nuts, honey] = useBearStore(
|
||||
useShallow((state) => [state.nuts, state.honey]),
|
||||
)
|
||||
|
||||
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
|
||||
const treats = useBearStore(useShallow((state) => Object.keys(state.treats)))
|
||||
```
|
||||
|
||||
For more control over re-rendering, you may provide any custom equality function (this example requires the use of [`createWithEqualityFn`](./docs/migrations/migrating-to-v5.md#using-custom-equality-functions-such-as-shallow)).
|
||||
|
||||
```jsx
|
||||
const treats = useBearStore(
|
||||
(state) => state.treats,
|
||||
(oldTreats, newTreats) => compare(oldTreats, newTreats),
|
||||
)
|
||||
```
|
||||
|
||||
## Overwriting state
|
||||
|
||||
The `set` function has a second argument, `false` by default. Instead of merging, it will replace the state model. Be careful not to wipe out parts you rely on, like actions.
|
||||
|
||||
```jsx
|
||||
const useFishStore = create((set) => ({
|
||||
salmon: 1,
|
||||
tuna: 2,
|
||||
deleteEverything: () => set({}, true), // clears the entire store, actions included
|
||||
deleteTuna: () => set(({ tuna, ...rest }) => rest, true),
|
||||
}))
|
||||
```
|
||||
|
||||
## Async actions
|
||||
|
||||
Just call `set` when you're ready, zustand doesn't care if your actions are async or not.
|
||||
|
||||
```jsx
|
||||
const useFishStore = create((set) => ({
|
||||
fishies: {},
|
||||
fetch: async (pond) => {
|
||||
const response = await fetch(pond)
|
||||
set({ fishies: await response.json() })
|
||||
},
|
||||
}))
|
||||
```
|
||||
|
||||
## Read from state in actions
|
||||
|
||||
`set` allows fn-updates `set(state => result)`, but you still have access to state outside of it through `get`.
|
||||
|
||||
```jsx
|
||||
const useSoundStore = create((set, get) => ({
|
||||
sound: 'grunt',
|
||||
action: () => {
|
||||
const sound = get().sound
|
||||
...
|
||||
```
|
||||
|
||||
## Reading/writing state and reacting to changes outside of components
|
||||
|
||||
Sometimes you need to access state in a non-reactive way or act upon the store. For these cases, the resulting hook has utility functions attached to its prototype.
|
||||
|
||||
:warning: This technique is not recommended for adding state in [React Server Components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) (typically in Next.js 13 and above). It can lead to unexpected bugs and privacy issues for your users. For more details, see [#2200](https://github.com/pmndrs/zustand/discussions/2200).
|
||||
|
||||
```jsx
|
||||
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }))
|
||||
|
||||
// Getting non-reactive fresh state
|
||||
const paw = useDogStore.getState().paw
|
||||
// Listening to all changes, fires synchronously on every change
|
||||
const unsub1 = useDogStore.subscribe(console.log)
|
||||
// Updating state, will trigger listeners
|
||||
useDogStore.setState({ paw: false })
|
||||
// Unsubscribe listeners
|
||||
unsub1()
|
||||
|
||||
// You can of course use the hook as you always would
|
||||
function Component() {
|
||||
const paw = useDogStore((state) => state.paw)
|
||||
...
|
||||
```
|
||||
|
||||
### Using subscribe with selector
|
||||
|
||||
If you need to subscribe with a selector,
|
||||
`subscribeWithSelector` middleware will help.
|
||||
|
||||
With this middleware `subscribe` accepts an additional signature:
|
||||
|
||||
```ts
|
||||
subscribe(selector, callback, options?: { equalityFn, fireImmediately }): Unsubscribe
|
||||
```
|
||||
|
||||
```js
|
||||
import { subscribeWithSelector } from 'zustand/middleware'
|
||||
const useDogStore = create(
|
||||
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })),
|
||||
)
|
||||
|
||||
// Listening to selected changes, in this case when "paw" changes
|
||||
const unsub2 = useDogStore.subscribe((state) => state.paw, console.log)
|
||||
// Subscribe also exposes the previous value
|
||||
const unsub3 = useDogStore.subscribe(
|
||||
(state) => state.paw,
|
||||
(paw, previousPaw) => console.log(paw, previousPaw),
|
||||
)
|
||||
// Subscribe also supports an optional equality function
|
||||
const unsub4 = useDogStore.subscribe(
|
||||
(state) => [state.paw, state.fur],
|
||||
console.log,
|
||||
{ equalityFn: shallow },
|
||||
)
|
||||
// Subscribe and fire immediately
|
||||
const unsub5 = useDogStore.subscribe((state) => state.paw, console.log, {
|
||||
fireImmediately: true,
|
||||
})
|
||||
```
|
||||
|
||||
## Using zustand without React
|
||||
|
||||
Zustand core can be imported and used without the React dependency. The only difference is that the create function does not return a hook, but the API utilities.
|
||||
|
||||
```jsx
|
||||
import { createStore } from 'zustand/vanilla'
|
||||
|
||||
const store = createStore((set) => ...)
|
||||
const { getState, setState, subscribe, getInitialState } = store
|
||||
|
||||
export default store
|
||||
```
|
||||
|
||||
You can use a vanilla store with `useStore` hook available since v4.
|
||||
|
||||
```jsx
|
||||
import { useStore } from 'zustand'
|
||||
import { vanillaStore } from './vanillaStore'
|
||||
|
||||
const useBoundStore = (selector) => useStore(vanillaStore, selector)
|
||||
```
|
||||
|
||||
:warning: Note that middlewares that modify `set` or `get` are not applied to `getState` and `setState`.
|
||||
|
||||
## Transient updates (for often occurring state-changes)
|
||||
|
||||
The subscribe function allows components to bind to a state-portion without forcing re-render on changes. Best combine it with useEffect for automatic unsubscribe on unmount. This can make a [drastic](https://codesandbox.io/s/peaceful-johnson-txtws) performance impact when you are allowed to mutate the view directly.
|
||||
|
||||
```jsx
|
||||
const useScratchStore = create((set) => ({ scratches: 0, ... }))
|
||||
|
||||
const Component = () => {
|
||||
// Fetch initial state
|
||||
const scratchRef = useRef(useScratchStore.getState().scratches)
|
||||
// Connect to the store on mount, disconnect on unmount, catch state-changes in a reference
|
||||
useEffect(() => useScratchStore.subscribe(
|
||||
state => (scratchRef.current = state.scratches)
|
||||
), [])
|
||||
...
|
||||
```
|
||||
|
||||
## Sick of reducers and changing nested states? Use Immer!
|
||||
|
||||
Reducing nested structures is tiresome. Have you tried [immer](https://github.com/mweststrate/immer)?
|
||||
|
||||
```jsx
|
||||
import { produce } from 'immer'
|
||||
|
||||
const useLushStore = create((set) => ({
|
||||
lush: { forest: { contains: { a: 'bear' } } },
|
||||
clearForest: () =>
|
||||
set(
|
||||
produce((state) => {
|
||||
state.lush.forest.contains = null
|
||||
}),
|
||||
),
|
||||
}))
|
||||
|
||||
const clearForest = useLushStore((state) => state.clearForest)
|
||||
clearForest()
|
||||
```
|
||||
|
||||
[Alternatively, there are some other solutions.](./docs/guides/updating-state.md#with-immer)
|
||||
|
||||
## Persist middleware
|
||||
|
||||
You can persist your store's data using any kind of storage.
|
||||
|
||||
```jsx
|
||||
import { create } from 'zustand'
|
||||
import { persist, createJSONStorage } from 'zustand/middleware'
|
||||
|
||||
const useFishStore = create(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
fishes: 0,
|
||||
addAFish: () => set({ fishes: get().fishes + 1 }),
|
||||
}),
|
||||
{
|
||||
name: 'food-storage', // name of the item in the storage (must be unique)
|
||||
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
|
||||
},
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
[See the full documentation for this middleware.](./docs/integrations/persisting-store-data.md)
|
||||
|
||||
## Immer middleware
|
||||
|
||||
Immer is available as middleware too.
|
||||
|
||||
```jsx
|
||||
import { create } from 'zustand'
|
||||
import { immer } from 'zustand/middleware/immer'
|
||||
|
||||
const useBeeStore = create(
|
||||
immer((set) => ({
|
||||
bees: 0,
|
||||
addBees: (by) =>
|
||||
set((state) => {
|
||||
state.bees += by
|
||||
}),
|
||||
})),
|
||||
)
|
||||
```
|
||||
|
||||
## Can't live without redux-like reducers and action types?
|
||||
|
||||
```jsx
|
||||
const types = { increase: 'INCREASE', decrease: 'DECREASE' }
|
||||
|
||||
const reducer = (state, { type, by = 1 }) => {
|
||||
switch (type) {
|
||||
case types.increase:
|
||||
return { grumpiness: state.grumpiness + by }
|
||||
case types.decrease:
|
||||
return { grumpiness: state.grumpiness - by }
|
||||
}
|
||||
}
|
||||
|
||||
const useGrumpyStore = create((set) => ({
|
||||
grumpiness: 0,
|
||||
dispatch: (args) => set((state) => reducer(state, args)),
|
||||
}))
|
||||
|
||||
const dispatch = useGrumpyStore((state) => state.dispatch)
|
||||
dispatch({ type: types.increase, by: 2 })
|
||||
```
|
||||
|
||||
Or, just use our redux-middleware. It wires up your main-reducer, sets the initial state, and adds a dispatch function to the state itself and the vanilla API.
|
||||
|
||||
```jsx
|
||||
import { redux } from 'zustand/middleware'
|
||||
|
||||
const useGrumpyStore = create(redux(reducer, initialState))
|
||||
```
|
||||
|
||||
## Redux devtools
|
||||
|
||||
Install the [Redux DevTools Chrome extension](https://chromewebstore.google.com/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) to use the devtools middleware.
|
||||
|
||||
```jsx
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
// Usage with a plain action store, it will log actions as "setState"
|
||||
const usePlainStore = create(devtools((set) => ...))
|
||||
// Usage with a redux store, it will log full action types
|
||||
const useReduxStore = create(devtools(redux(reducer, initialState)))
|
||||
```
|
||||
|
||||
One redux devtools connection for multiple stores
|
||||
|
||||
```jsx
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
// Usage with a plain action store, it will log actions as "setState"
|
||||
const usePlainStore1 = create(devtools((set) => ..., { name, store: storeName1 }))
|
||||
const usePlainStore2 = create(devtools((set) => ..., { name, store: storeName2 }))
|
||||
// Usage with a redux store, it will log full action types
|
||||
const useReduxStore1 = create(devtools(redux(reducer, initialState)), { name, store: storeName3 })
|
||||
const useReduxStore2 = create(devtools(redux(reducer, initialState)), { name, store: storeName4 })
|
||||
```
|
||||
|
||||
Assigning different connection names will separate stores in redux devtools. This also helps group different stores into separate redux devtools connections.
|
||||
|
||||
devtools takes the store function as its first argument, optionally you can name the store or configure [serialize](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#serialize) options with a second argument.
|
||||
|
||||
Name store: `devtools(..., {name: "MyStore"})`, which will create a separate instance named "MyStore" in the devtools.
|
||||
|
||||
Serialize options: `devtools(..., { serialize: { options: true } })`.
|
||||
|
||||
#### Logging Actions
|
||||
|
||||
devtools will only log actions from each separated store unlike in a typical _combined reducers_ redux store. See an approach to combining stores https://github.com/pmndrs/zustand/issues/163
|
||||
|
||||
You can log a specific action type for each `set` function by passing a third parameter:
|
||||
|
||||
```jsx
|
||||
const useBearStore = create(devtools((set) => ({
|
||||
...
|
||||
eatFish: () => set(
|
||||
(prev) => ({ fishes: prev.fishes > 1 ? prev.fishes - 1 : 0 }),
|
||||
undefined,
|
||||
'bear/eatFish'
|
||||
),
|
||||
...
|
||||
```
|
||||
|
||||
You can also log the action's type along with its payload:
|
||||
|
||||
```jsx
|
||||
...
|
||||
addFishes: (count) => set(
|
||||
(prev) => ({ fishes: prev.fishes + count }),
|
||||
undefined,
|
||||
{ type: 'bear/addFishes', count, }
|
||||
),
|
||||
...
|
||||
```
|
||||
|
||||
If an action type is not provided, it is defaulted to "anonymous". You can customize this default value by providing an `anonymousActionType` parameter:
|
||||
|
||||
```jsx
|
||||
devtools(..., { anonymousActionType: 'unknown', ... })
|
||||
```
|
||||
|
||||
If you wish to disable devtools (on production for instance). You can customize this setting by providing the `enabled` parameter:
|
||||
|
||||
```jsx
|
||||
devtools(..., { enabled: false, ... })
|
||||
```
|
||||
|
||||
## React context
|
||||
|
||||
The store created with `create` doesn't require context providers. In some cases, you may want to use contexts for dependency injection or if you want to initialize your store with props from a component. Because the normal store is a hook, passing it as a normal context value may violate the rules of hooks.
|
||||
|
||||
The recommended method available since v4 is to use the vanilla store.
|
||||
|
||||
```jsx
|
||||
import { createContext, useContext } from 'react'
|
||||
import { createStore, useStore } from 'zustand'
|
||||
|
||||
const store = createStore(...) // vanilla store without hooks
|
||||
|
||||
const StoreContext = createContext()
|
||||
|
||||
const App = () => (
|
||||
<StoreContext.Provider value={store}>
|
||||
...
|
||||
</StoreContext.Provider>
|
||||
)
|
||||
|
||||
const Component = () => {
|
||||
const store = useContext(StoreContext)
|
||||
const slice = useStore(store, selector)
|
||||
...
|
||||
```
|
||||
|
||||
## TypeScript Usage
|
||||
|
||||
Basic typescript usage doesn't require anything special except for writing `create<State>()(...)` instead of `create(...)`...
|
||||
|
||||
```ts
|
||||
import { create } from 'zustand'
|
||||
import { devtools, persist } from 'zustand/middleware'
|
||||
import type {} from '@redux-devtools/extension' // required for devtools typing
|
||||
|
||||
interface BearState {
|
||||
bears: number
|
||||
increase: (by: number) => void
|
||||
}
|
||||
|
||||
const useBearStore = create<BearState>()(
|
||||
devtools(
|
||||
persist(
|
||||
(set) => ({
|
||||
bears: 0,
|
||||
increase: (by) => set((state) => ({ bears: state.bears + by })),
|
||||
}),
|
||||
{
|
||||
name: 'bear-storage',
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
A more complete TypeScript guide is [here](docs/guides/typescript.md).
|
||||
|
||||
## Best practices
|
||||
|
||||
- You may wonder how to organize your code for better maintenance: [Splitting the store into separate slices](./docs/guides/slices-pattern.md).
|
||||
- Recommended usage for this unopinionated library: [Flux inspired practice](./docs/guides/flux-inspired-practice.md).
|
||||
- [Calling actions outside a React event handler in pre-React 18](./docs/guides/event-handler-in-pre-react-18.md).
|
||||
- [Testing](./docs/guides/testing.md)
|
||||
- For more, have a look [in the docs folder](./docs/)
|
||||
|
||||
## Third-Party Libraries
|
||||
|
||||
Some users may want to extend Zustand's feature set which can be done using third-party libraries made by the community. For information regarding third-party libraries with Zustand, visit [the doc](./docs/integrations/third-party-libraries.md).
|
||||
|
||||
## Comparison with other libraries
|
||||
|
||||
- [Difference between zustand and other state management libraries for React](https://zustand.docs.pmnd.rs/getting-started/comparison)
|
||||
2
node_modules/zustand/esm/index.d.mts
generated
vendored
Normal file
2
node_modules/zustand/esm/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from 'zustand/vanilla';
|
||||
export * from 'zustand/react';
|
||||
2
node_modules/zustand/esm/index.mjs
generated
vendored
Normal file
2
node_modules/zustand/esm/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from 'zustand/vanilla';
|
||||
export * from 'zustand/react';
|
||||
5
node_modules/zustand/esm/middleware.d.mts
generated
vendored
Normal file
5
node_modules/zustand/esm/middleware.d.mts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export { redux } from './middleware/redux.mjs';
|
||||
export { devtools, type DevtoolsOptions, type NamedSet, } from './middleware/devtools.mjs';
|
||||
export { subscribeWithSelector } from './middleware/subscribeWithSelector.mjs';
|
||||
export { combine } from './middleware/combine.mjs';
|
||||
export { persist, createJSONStorage, type StateStorage, type StorageValue, type PersistStorage, type PersistOptions, } from './middleware/persist.mjs';
|
||||
462
node_modules/zustand/esm/middleware.mjs
generated
vendored
Normal file
462
node_modules/zustand/esm/middleware.mjs
generated
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
const reduxImpl = (reducer, initial) => (set, _get, api) => {
|
||||
api.dispatch = (action) => {
|
||||
set((state) => reducer(state, action), false, action);
|
||||
return action;
|
||||
};
|
||||
api.dispatchFromDevtools = true;
|
||||
return { dispatch: (...args) => api.dispatch(...args), ...initial };
|
||||
};
|
||||
const redux = reduxImpl;
|
||||
|
||||
const trackedConnections = /* @__PURE__ */ new Map();
|
||||
const getTrackedConnectionState = (name) => {
|
||||
const api = trackedConnections.get(name);
|
||||
if (!api) return {};
|
||||
return Object.fromEntries(
|
||||
Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])
|
||||
);
|
||||
};
|
||||
const extractConnectionInformation = (store, extensionConnector, options) => {
|
||||
if (store === void 0) {
|
||||
return {
|
||||
type: "untracked",
|
||||
connection: extensionConnector.connect(options)
|
||||
};
|
||||
}
|
||||
const existingConnection = trackedConnections.get(options.name);
|
||||
if (existingConnection) {
|
||||
return { type: "tracked", store, ...existingConnection };
|
||||
}
|
||||
const newConnection = {
|
||||
connection: extensionConnector.connect(options),
|
||||
stores: {}
|
||||
};
|
||||
trackedConnections.set(options.name, newConnection);
|
||||
return { type: "tracked", store, ...newConnection };
|
||||
};
|
||||
const removeStoreFromTrackedConnections = (name, store) => {
|
||||
if (store === void 0) return;
|
||||
const connectionInfo = trackedConnections.get(name);
|
||||
if (!connectionInfo) return;
|
||||
delete connectionInfo.stores[store];
|
||||
if (Object.keys(connectionInfo.stores).length === 0) {
|
||||
trackedConnections.delete(name);
|
||||
}
|
||||
};
|
||||
const findCallerName = (stack) => {
|
||||
var _a, _b;
|
||||
if (!stack) return void 0;
|
||||
const traceLines = stack.split("\n");
|
||||
const apiSetStateLineIndex = traceLines.findIndex(
|
||||
(traceLine) => traceLine.includes("api.setState")
|
||||
);
|
||||
if (apiSetStateLineIndex < 0) return void 0;
|
||||
const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || "";
|
||||
return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];
|
||||
};
|
||||
const devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {
|
||||
const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;
|
||||
let extensionConnector;
|
||||
try {
|
||||
extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
|
||||
} catch (e) {
|
||||
}
|
||||
if (!extensionConnector) {
|
||||
return fn(set, get, api);
|
||||
}
|
||||
const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);
|
||||
let isRecording = true;
|
||||
api.setState = ((state, replace, nameOrAction) => {
|
||||
const r = set(state, replace);
|
||||
if (!isRecording) return r;
|
||||
const action = nameOrAction === void 0 ? {
|
||||
type: anonymousActionType || findCallerName(new Error().stack) || "anonymous"
|
||||
} : typeof nameOrAction === "string" ? { type: nameOrAction } : nameOrAction;
|
||||
if (store === void 0) {
|
||||
connection == null ? void 0 : connection.send(action, get());
|
||||
return r;
|
||||
}
|
||||
connection == null ? void 0 : connection.send(
|
||||
{
|
||||
...action,
|
||||
type: `${store}/${action.type}`
|
||||
},
|
||||
{
|
||||
...getTrackedConnectionState(options.name),
|
||||
[store]: api.getState()
|
||||
}
|
||||
);
|
||||
return r;
|
||||
});
|
||||
api.devtools = {
|
||||
cleanup: () => {
|
||||
if (connection && typeof connection.unsubscribe === "function") {
|
||||
connection.unsubscribe();
|
||||
}
|
||||
removeStoreFromTrackedConnections(options.name, store);
|
||||
}
|
||||
};
|
||||
const setStateFromDevtools = (...a) => {
|
||||
const originalIsRecording = isRecording;
|
||||
isRecording = false;
|
||||
set(...a);
|
||||
isRecording = originalIsRecording;
|
||||
};
|
||||
const initialState = fn(api.setState, get, api);
|
||||
if (connectionInformation.type === "untracked") {
|
||||
connection == null ? void 0 : connection.init(initialState);
|
||||
} else {
|
||||
connectionInformation.stores[connectionInformation.store] = api;
|
||||
connection == null ? void 0 : connection.init(
|
||||
Object.fromEntries(
|
||||
Object.entries(connectionInformation.stores).map(([key, store2]) => [
|
||||
key,
|
||||
key === connectionInformation.store ? initialState : store2.getState()
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
if (api.dispatchFromDevtools && typeof api.dispatch === "function") {
|
||||
let didWarnAboutReservedActionType = false;
|
||||
const originalDispatch = api.dispatch;
|
||||
api.dispatch = (...args) => {
|
||||
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && args[0].type === "__setState" && !didWarnAboutReservedActionType) {
|
||||
console.warn(
|
||||
'[zustand devtools middleware] "__setState" action type is reserved to set state from the devtools. Avoid using it.'
|
||||
);
|
||||
didWarnAboutReservedActionType = true;
|
||||
}
|
||||
originalDispatch(...args);
|
||||
};
|
||||
}
|
||||
connection.subscribe((message) => {
|
||||
var _a;
|
||||
switch (message.type) {
|
||||
case "ACTION":
|
||||
if (typeof message.payload !== "string") {
|
||||
console.error(
|
||||
"[zustand devtools middleware] Unsupported action format"
|
||||
);
|
||||
return;
|
||||
}
|
||||
return parseJsonThen(
|
||||
message.payload,
|
||||
(action) => {
|
||||
if (action.type === "__setState") {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(action.state);
|
||||
return;
|
||||
}
|
||||
if (Object.keys(action.state).length !== 1) {
|
||||
console.error(
|
||||
`
|
||||
[zustand devtools middleware] Unsupported __setState action format.
|
||||
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
|
||||
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
|
||||
`
|
||||
);
|
||||
}
|
||||
const stateFromDevtools = action.state[store];
|
||||
if (stateFromDevtools === void 0 || stateFromDevtools === null) {
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {
|
||||
setStateFromDevtools(stateFromDevtools);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!api.dispatchFromDevtools) return;
|
||||
if (typeof api.dispatch !== "function") return;
|
||||
api.dispatch(action);
|
||||
}
|
||||
);
|
||||
case "DISPATCH":
|
||||
switch (message.payload.type) {
|
||||
case "RESET":
|
||||
setStateFromDevtools(initialState);
|
||||
if (store === void 0) {
|
||||
return connection == null ? void 0 : connection.init(api.getState());
|
||||
}
|
||||
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
case "COMMIT":
|
||||
if (store === void 0) {
|
||||
connection == null ? void 0 : connection.init(api.getState());
|
||||
return;
|
||||
}
|
||||
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
case "ROLLBACK":
|
||||
return parseJsonThen(message.state, (state) => {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(state);
|
||||
connection == null ? void 0 : connection.init(api.getState());
|
||||
return;
|
||||
}
|
||||
setStateFromDevtools(state[store]);
|
||||
connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
});
|
||||
case "JUMP_TO_STATE":
|
||||
case "JUMP_TO_ACTION":
|
||||
return parseJsonThen(message.state, (state) => {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(state);
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {
|
||||
setStateFromDevtools(state[store]);
|
||||
}
|
||||
});
|
||||
case "IMPORT_STATE": {
|
||||
const { nextLiftedState } = message.payload;
|
||||
const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;
|
||||
if (!lastComputedState) return;
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(lastComputedState);
|
||||
} else {
|
||||
setStateFromDevtools(lastComputedState[store]);
|
||||
}
|
||||
connection == null ? void 0 : connection.send(
|
||||
null,
|
||||
// FIXME no-any
|
||||
nextLiftedState
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "PAUSE_RECORDING":
|
||||
return isRecording = !isRecording;
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
return initialState;
|
||||
};
|
||||
const devtools = devtoolsImpl;
|
||||
const parseJsonThen = (stringified, fn) => {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(stringified);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[zustand devtools middleware] Could not parse the received json",
|
||||
e
|
||||
);
|
||||
}
|
||||
if (parsed !== void 0) fn(parsed);
|
||||
};
|
||||
|
||||
const subscribeWithSelectorImpl = (fn) => (set, get, api) => {
|
||||
const origSubscribe = api.subscribe;
|
||||
api.subscribe = ((selector, optListener, options) => {
|
||||
let listener = selector;
|
||||
if (optListener) {
|
||||
const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;
|
||||
let currentSlice = selector(api.getState());
|
||||
listener = (state) => {
|
||||
const nextSlice = selector(state);
|
||||
if (!equalityFn(currentSlice, nextSlice)) {
|
||||
const previousSlice = currentSlice;
|
||||
optListener(currentSlice = nextSlice, previousSlice);
|
||||
}
|
||||
};
|
||||
if (options == null ? void 0 : options.fireImmediately) {
|
||||
optListener(currentSlice, currentSlice);
|
||||
}
|
||||
}
|
||||
return origSubscribe(listener);
|
||||
});
|
||||
const initialState = fn(set, get, api);
|
||||
return initialState;
|
||||
};
|
||||
const subscribeWithSelector = subscribeWithSelectorImpl;
|
||||
|
||||
function combine(initialState, create) {
|
||||
return (...args) => Object.assign({}, initialState, create(...args));
|
||||
}
|
||||
|
||||
function createJSONStorage(getStorage, options) {
|
||||
let storage;
|
||||
try {
|
||||
storage = getStorage();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
const persistStorage = {
|
||||
getItem: (name) => {
|
||||
var _a;
|
||||
const parse = (str2) => {
|
||||
if (str2 === null) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(str2, options == null ? void 0 : options.reviver);
|
||||
};
|
||||
const str = (_a = storage.getItem(name)) != null ? _a : null;
|
||||
if (str instanceof Promise) {
|
||||
return str.then(parse);
|
||||
}
|
||||
return parse(str);
|
||||
},
|
||||
setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),
|
||||
removeItem: (name) => storage.removeItem(name)
|
||||
};
|
||||
return persistStorage;
|
||||
}
|
||||
const toThenable = (fn) => (input) => {
|
||||
try {
|
||||
const result = fn(input);
|
||||
if (result instanceof Promise) {
|
||||
return result;
|
||||
}
|
||||
return {
|
||||
then(onFulfilled) {
|
||||
return toThenable(onFulfilled)(result);
|
||||
},
|
||||
catch(_onRejected) {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
then(_onFulfilled) {
|
||||
return this;
|
||||
},
|
||||
catch(onRejected) {
|
||||
return toThenable(onRejected)(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const persistImpl = (config, baseOptions) => (set, get, api) => {
|
||||
let options = {
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => state,
|
||||
version: 0,
|
||||
merge: (persistedState, currentState) => ({
|
||||
...currentState,
|
||||
...persistedState
|
||||
}),
|
||||
...baseOptions
|
||||
};
|
||||
let hasHydrated = false;
|
||||
const hydrationListeners = /* @__PURE__ */ new Set();
|
||||
const finishHydrationListeners = /* @__PURE__ */ new Set();
|
||||
let storage = options.storage;
|
||||
if (!storage) {
|
||||
return config(
|
||||
(...args) => {
|
||||
console.warn(
|
||||
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
|
||||
);
|
||||
set(...args);
|
||||
},
|
||||
get,
|
||||
api
|
||||
);
|
||||
}
|
||||
const setItem = () => {
|
||||
const state = options.partialize({ ...get() });
|
||||
return storage.setItem(options.name, {
|
||||
state,
|
||||
version: options.version
|
||||
});
|
||||
};
|
||||
const savedSetState = api.setState;
|
||||
api.setState = (state, replace) => {
|
||||
savedSetState(state, replace);
|
||||
return setItem();
|
||||
};
|
||||
const configResult = config(
|
||||
(...args) => {
|
||||
set(...args);
|
||||
return setItem();
|
||||
},
|
||||
get,
|
||||
api
|
||||
);
|
||||
api.getInitialState = () => configResult;
|
||||
let stateFromStorage;
|
||||
const hydrate = () => {
|
||||
var _a, _b;
|
||||
if (!storage) return;
|
||||
hasHydrated = false;
|
||||
hydrationListeners.forEach((cb) => {
|
||||
var _a2;
|
||||
return cb((_a2 = get()) != null ? _a2 : configResult);
|
||||
});
|
||||
const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;
|
||||
return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {
|
||||
if (deserializedStorageValue) {
|
||||
if (typeof deserializedStorageValue.version === "number" && deserializedStorageValue.version !== options.version) {
|
||||
if (options.migrate) {
|
||||
const migration = options.migrate(
|
||||
deserializedStorageValue.state,
|
||||
deserializedStorageValue.version
|
||||
);
|
||||
if (migration instanceof Promise) {
|
||||
return migration.then((result) => [true, result]);
|
||||
}
|
||||
return [true, migration];
|
||||
}
|
||||
console.error(
|
||||
`State loaded from storage couldn't be migrated since no migrate function was provided`
|
||||
);
|
||||
} else {
|
||||
return [false, deserializedStorageValue.state];
|
||||
}
|
||||
}
|
||||
return [false, void 0];
|
||||
}).then((migrationResult) => {
|
||||
var _a2;
|
||||
const [migrated, migratedState] = migrationResult;
|
||||
stateFromStorage = options.merge(
|
||||
migratedState,
|
||||
(_a2 = get()) != null ? _a2 : configResult
|
||||
);
|
||||
set(stateFromStorage, true);
|
||||
if (migrated) {
|
||||
return setItem();
|
||||
}
|
||||
}).then(() => {
|
||||
postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0);
|
||||
stateFromStorage = get();
|
||||
hasHydrated = true;
|
||||
finishHydrationListeners.forEach((cb) => cb(stateFromStorage));
|
||||
}).catch((e) => {
|
||||
postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);
|
||||
});
|
||||
};
|
||||
api.persist = {
|
||||
setOptions: (newOptions) => {
|
||||
options = {
|
||||
...options,
|
||||
...newOptions
|
||||
};
|
||||
if (newOptions.storage) {
|
||||
storage = newOptions.storage;
|
||||
}
|
||||
},
|
||||
clearStorage: () => {
|
||||
storage == null ? void 0 : storage.removeItem(options.name);
|
||||
},
|
||||
getOptions: () => options,
|
||||
rehydrate: () => hydrate(),
|
||||
hasHydrated: () => hasHydrated,
|
||||
onHydrate: (cb) => {
|
||||
hydrationListeners.add(cb);
|
||||
return () => {
|
||||
hydrationListeners.delete(cb);
|
||||
};
|
||||
},
|
||||
onFinishHydration: (cb) => {
|
||||
finishHydrationListeners.add(cb);
|
||||
return () => {
|
||||
finishHydrationListeners.delete(cb);
|
||||
};
|
||||
}
|
||||
};
|
||||
if (!options.skipHydration) {
|
||||
hydrate();
|
||||
}
|
||||
return stateFromStorage || configResult;
|
||||
};
|
||||
const persist = persistImpl;
|
||||
|
||||
export { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector };
|
||||
4
node_modules/zustand/esm/middleware/combine.d.mts
generated
vendored
Normal file
4
node_modules/zustand/esm/middleware/combine.d.mts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
export declare function combine<T extends object, U extends object, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initialState: T, create: StateCreator<T, Mps, Mcs, U>): StateCreator<Write<T, U>, Mps, Mcs>;
|
||||
export {};
|
||||
58
node_modules/zustand/esm/middleware/devtools.d.mts
generated
vendored
Normal file
58
node_modules/zustand/esm/middleware/devtools.d.mts
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Config = Parameters<(Window extends {
|
||||
__REDUX_DEVTOOLS_EXTENSION__?: infer T;
|
||||
} ? T : {
|
||||
connect: (param: any) => any;
|
||||
})['connect']>[0];
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/devtools': WithDevtools<S>;
|
||||
}
|
||||
}
|
||||
type Cast<T, U> = T extends U ? T : U;
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type TakeTwo<T> = T extends {
|
||||
length: 0;
|
||||
} ? [undefined, undefined] : T extends {
|
||||
length: 1;
|
||||
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
|
||||
length: 0 | 1;
|
||||
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
|
||||
length: 2;
|
||||
} ? T : T extends {
|
||||
length: 1 | 2;
|
||||
} ? T : T extends {
|
||||
length: 0 | 1 | 2;
|
||||
} ? T : T extends [infer A0, infer A1, ...unknown[]] ? [A0, A1] : T extends [infer A0, (infer A1)?, ...unknown[]] ? [A0, A1?] : T extends [(infer A0)?, (infer A1)?, ...unknown[]] ? [A0?, A1?] : never;
|
||||
type WithDevtools<S> = Write<S, StoreDevtools<S>>;
|
||||
type Action = string | {
|
||||
type: string;
|
||||
[x: string | number | symbol]: unknown;
|
||||
};
|
||||
type StoreDevtools<S> = S extends {
|
||||
setState: {
|
||||
(...args: infer Sa1): infer Sr1;
|
||||
(...args: infer Sa2): infer Sr2;
|
||||
};
|
||||
} ? {
|
||||
setState(...args: [...args: TakeTwo<Sa1>, action?: Action]): Sr1;
|
||||
setState(...args: [...args: TakeTwo<Sa2>, action?: Action]): Sr2;
|
||||
devtools: {
|
||||
cleanup: () => void;
|
||||
};
|
||||
} : never;
|
||||
export interface DevtoolsOptions extends Config {
|
||||
name?: string;
|
||||
enabled?: boolean;
|
||||
anonymousActionType?: string;
|
||||
store?: string;
|
||||
}
|
||||
type Devtools = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/devtools', never]], Mcs, U>, devtoolsOptions?: DevtoolsOptions) => StateCreator<T, Mps, [['zustand/devtools', never], ...Mcs]>;
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/devtools': WithDevtools<S>;
|
||||
}
|
||||
}
|
||||
export type NamedSet<T> = WithDevtools<StoreApi<T>>['setState'];
|
||||
export declare const devtools: Devtools;
|
||||
export {};
|
||||
29
node_modules/zustand/esm/middleware/immer.d.mts
generated
vendored
Normal file
29
node_modules/zustand/esm/middleware/immer.d.mts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Draft } from 'immer';
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Immer = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>) => StateCreator<T, Mps, [['zustand/immer', never], ...Mcs]>;
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
['zustand/immer']: WithImmer<S>;
|
||||
}
|
||||
}
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type SkipTwo<T> = T extends {
|
||||
length: 0;
|
||||
} ? [] : T extends {
|
||||
length: 1;
|
||||
} ? [] : T extends {
|
||||
length: 0 | 1;
|
||||
} ? [] : T extends [unknown, unknown, ...infer A] ? A : T extends [unknown, unknown?, ...infer A] ? A : T extends [unknown?, unknown?, ...infer A] ? A : never;
|
||||
type SetStateType<T extends unknown[]> = Exclude<T[0], (...args: any[]) => any>;
|
||||
type WithImmer<S> = Write<S, StoreImmer<S>>;
|
||||
type StoreImmer<S> = S extends {
|
||||
setState: infer SetState;
|
||||
} ? SetState extends {
|
||||
(...args: infer A1): infer Sr1;
|
||||
(...args: infer A2): infer Sr2;
|
||||
} ? {
|
||||
setState(nextStateOrUpdater: SetStateType<A2> | Partial<SetStateType<A2>> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace?: false, ...args: SkipTwo<A1>): Sr1;
|
||||
setState(nextStateOrUpdater: SetStateType<A2> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace: true, ...args: SkipTwo<A2>): Sr2;
|
||||
} : never : never;
|
||||
export declare const immer: Immer;
|
||||
export {};
|
||||
12
node_modules/zustand/esm/middleware/immer.mjs
generated
vendored
Normal file
12
node_modules/zustand/esm/middleware/immer.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { produce } from 'immer';
|
||||
|
||||
const immerImpl = (initializer) => (set, get, store) => {
|
||||
store.setState = (updater, replace, ...args) => {
|
||||
const nextState = typeof updater === "function" ? produce(updater) : updater;
|
||||
return set(nextState, replace, ...args);
|
||||
};
|
||||
return initializer(store.setState, get, store);
|
||||
};
|
||||
const immer = immerImpl;
|
||||
|
||||
export { immer };
|
||||
99
node_modules/zustand/esm/middleware/persist.d.mts
generated
vendored
Normal file
99
node_modules/zustand/esm/middleware/persist.d.mts
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
export interface StateStorage<R = unknown> {
|
||||
getItem: (name: string) => string | null | Promise<string | null>;
|
||||
setItem: (name: string, value: string) => R;
|
||||
removeItem: (name: string) => R;
|
||||
}
|
||||
export type StorageValue<S> = {
|
||||
state: S;
|
||||
version?: number;
|
||||
};
|
||||
export interface PersistStorage<S, R = unknown> {
|
||||
getItem: (name: string) => StorageValue<S> | null | Promise<StorageValue<S> | null>;
|
||||
setItem: (name: string, value: StorageValue<S>) => R;
|
||||
removeItem: (name: string) => R;
|
||||
}
|
||||
type JsonStorageOptions = {
|
||||
reviver?: (key: string, value: unknown) => unknown;
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
};
|
||||
export declare function createJSONStorage<S, R = unknown>(getStorage: () => StateStorage<R>, options?: JsonStorageOptions): PersistStorage<S, unknown> | undefined;
|
||||
export interface PersistOptions<S, PersistedState = S, PersistReturn = unknown> {
|
||||
/** Name of the storage (must be unique) */
|
||||
name: string;
|
||||
/**
|
||||
* Use a custom persist storage.
|
||||
*
|
||||
* Combining `createJSONStorage` helps creating a persist storage
|
||||
* with JSON.parse and JSON.stringify.
|
||||
*
|
||||
* @default createJSONStorage(() => localStorage)
|
||||
*/
|
||||
storage?: PersistStorage<PersistedState, PersistReturn> | undefined;
|
||||
/**
|
||||
* Filter the persisted value.
|
||||
*
|
||||
* @params state The state's value
|
||||
*/
|
||||
partialize?: (state: S) => PersistedState;
|
||||
/**
|
||||
* A function returning another (optional) function.
|
||||
* The main function will be called before the state rehydration.
|
||||
* The returned function will be called after the state rehydration or when an error occurred.
|
||||
*/
|
||||
onRehydrateStorage?: (state: S) => ((state?: S, error?: unknown) => void) | void;
|
||||
/**
|
||||
* If the stored state's version mismatch the one specified here, the storage will not be used.
|
||||
* This is useful when adding a breaking change to your store.
|
||||
*/
|
||||
version?: number;
|
||||
/**
|
||||
* A function to perform persisted state migration.
|
||||
* This function will be called when persisted state versions mismatch with the one specified here.
|
||||
*/
|
||||
migrate?: (persistedState: unknown, version: number) => PersistedState | Promise<PersistedState>;
|
||||
/**
|
||||
* A function to perform custom hydration merges when combining the stored state with the current one.
|
||||
* By default, this function does a shallow merge.
|
||||
*/
|
||||
merge?: (persistedState: unknown, currentState: S) => S;
|
||||
/**
|
||||
* An optional boolean that will prevent the persist middleware from triggering hydration on initialization,
|
||||
* This allows you to call `rehydrate()` at a specific point in your apps rendering life-cycle.
|
||||
*
|
||||
* This is useful in SSR application.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
skipHydration?: boolean;
|
||||
}
|
||||
type PersistListener<S> = (state: S) => void;
|
||||
type StorePersist<S, Ps, Pr> = S extends {
|
||||
getState: () => infer T;
|
||||
setState: {
|
||||
(...args: infer Sa1): infer Sr1;
|
||||
(...args: infer Sa2): infer Sr2;
|
||||
};
|
||||
} ? {
|
||||
setState(...args: Sa1): Sr1 | Pr;
|
||||
setState(...args: Sa2): Sr2 | Pr;
|
||||
persist: {
|
||||
setOptions: (options: Partial<PersistOptions<T, Ps, Pr>>) => void;
|
||||
clearStorage: () => void;
|
||||
rehydrate: () => Promise<void> | void;
|
||||
hasHydrated: () => boolean;
|
||||
onHydrate: (fn: PersistListener<T>) => () => void;
|
||||
onFinishHydration: (fn: PersistListener<T>) => () => void;
|
||||
getOptions: () => Partial<PersistOptions<T, Ps, Pr>>;
|
||||
};
|
||||
} : never;
|
||||
type Persist = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/persist', unknown]], Mcs>, options: PersistOptions<T, U>) => StateCreator<T, Mps, [['zustand/persist', U], ...Mcs]>;
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/persist': WithPersist<S, A>;
|
||||
}
|
||||
}
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type WithPersist<S, A> = Write<S, StorePersist<S, A, unknown>>;
|
||||
export declare const persist: Persist;
|
||||
export {};
|
||||
21
node_modules/zustand/esm/middleware/redux.d.mts
generated
vendored
Normal file
21
node_modules/zustand/esm/middleware/redux.d.mts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type Action = {
|
||||
type: string;
|
||||
};
|
||||
type StoreRedux<A> = {
|
||||
dispatch: (a: A) => A;
|
||||
dispatchFromDevtools: true;
|
||||
};
|
||||
type ReduxState<A> = {
|
||||
dispatch: StoreRedux<A>['dispatch'];
|
||||
};
|
||||
type WithRedux<S, A> = Write<S, StoreRedux<A>>;
|
||||
type Redux = <T, A extends Action, Cms extends [StoreMutatorIdentifier, unknown][] = []>(reducer: (state: T, action: A) => T, initialState: T) => StateCreator<Write<T, ReduxState<A>>, Cms, [['zustand/redux', A]]>;
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/redux': WithRedux<S, A>;
|
||||
}
|
||||
}
|
||||
export declare const redux: Redux;
|
||||
export {};
|
||||
25
node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts
generated
vendored
Normal file
25
node_modules/zustand/esm/middleware/subscribeWithSelector.d.mts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type SubscribeWithSelector = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [
|
||||
...Mps,
|
||||
['zustand/subscribeWithSelector', never]
|
||||
], Mcs>) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>;
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type WithSelectorSubscribe<S> = S extends {
|
||||
getState: () => infer T;
|
||||
} ? Write<S, StoreSubscribeWithSelector<T>> : never;
|
||||
declare module '../vanilla.mjs' {
|
||||
interface StoreMutators<S, A> {
|
||||
['zustand/subscribeWithSelector']: WithSelectorSubscribe<S>;
|
||||
}
|
||||
}
|
||||
type StoreSubscribeWithSelector<T> = {
|
||||
subscribe: {
|
||||
(listener: (selectedState: T, previousSelectedState: T) => void): () => void;
|
||||
<U>(selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
||||
equalityFn?: (a: U, b: U) => boolean;
|
||||
fireImmediately?: boolean;
|
||||
}): () => void;
|
||||
};
|
||||
};
|
||||
export declare const subscribeWithSelector: SubscribeWithSelector;
|
||||
export {};
|
||||
14
node_modules/zustand/esm/react.d.mts
generated
vendored
Normal file
14
node_modules/zustand/esm/react.d.mts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
|
||||
export declare function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
|
||||
export declare function useStore<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U): U;
|
||||
export type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
|
||||
(): ExtractState<S>;
|
||||
<U>(selector: (state: ExtractState<S>) => U): U;
|
||||
} & S;
|
||||
type Create = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): UseBoundStore<Mutate<StoreApi<T>, Mos>>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => UseBoundStore<Mutate<StoreApi<T>, Mos>>;
|
||||
};
|
||||
export declare const create: Create;
|
||||
export {};
|
||||
22
node_modules/zustand/esm/react.mjs
generated
vendored
Normal file
22
node_modules/zustand/esm/react.mjs
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { createStore } from 'zustand/vanilla';
|
||||
|
||||
const identity = (arg) => arg;
|
||||
function useStore(api, selector = identity) {
|
||||
const slice = React.useSyncExternalStore(
|
||||
api.subscribe,
|
||||
React.useCallback(() => selector(api.getState()), [api, selector]),
|
||||
React.useCallback(() => selector(api.getInitialState()), [api, selector])
|
||||
);
|
||||
React.useDebugValue(slice);
|
||||
return slice;
|
||||
}
|
||||
const createImpl = (createState) => {
|
||||
const api = createStore(createState);
|
||||
const useBoundStore = (selector) => useStore(api, selector);
|
||||
Object.assign(useBoundStore, api);
|
||||
return useBoundStore;
|
||||
};
|
||||
const create = ((createState) => createState ? createImpl(createState) : createImpl);
|
||||
|
||||
export { create, useStore };
|
||||
1
node_modules/zustand/esm/react/shallow.d.mts
generated
vendored
Normal file
1
node_modules/zustand/esm/react/shallow.d.mts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;
|
||||
12
node_modules/zustand/esm/react/shallow.mjs
generated
vendored
Normal file
12
node_modules/zustand/esm/react/shallow.mjs
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'zustand/vanilla/shallow';
|
||||
|
||||
function useShallow(selector) {
|
||||
const prev = React.useRef(void 0);
|
||||
return (state) => {
|
||||
const next = selector(state);
|
||||
return shallow(prev.current, next) ? prev.current : prev.current = next;
|
||||
};
|
||||
}
|
||||
|
||||
export { useShallow };
|
||||
2
node_modules/zustand/esm/shallow.d.mts
generated
vendored
Normal file
2
node_modules/zustand/esm/shallow.d.mts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { shallow } from 'zustand/vanilla/shallow';
|
||||
export { useShallow } from 'zustand/react/shallow';
|
||||
2
node_modules/zustand/esm/shallow.mjs
generated
vendored
Normal file
2
node_modules/zustand/esm/shallow.mjs
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { shallow } from 'zustand/vanilla/shallow';
|
||||
export { useShallow } from 'zustand/react/shallow';
|
||||
14
node_modules/zustand/esm/traditional.d.mts
generated
vendored
Normal file
14
node_modules/zustand/esm/traditional.d.mts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
|
||||
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
|
||||
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
||||
export type UseBoundStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>> = {
|
||||
(): ExtractState<S>;
|
||||
<U>(selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
||||
} & S;
|
||||
type CreateWithEqualityFn = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
|
||||
};
|
||||
export declare const createWithEqualityFn: CreateWithEqualityFn;
|
||||
export {};
|
||||
26
node_modules/zustand/esm/traditional.mjs
generated
vendored
Normal file
26
node_modules/zustand/esm/traditional.mjs
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import useSyncExternalStoreExports from 'use-sync-external-store/shim/with-selector.js';
|
||||
import { createStore } from 'zustand/vanilla';
|
||||
|
||||
const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
|
||||
const identity = (arg) => arg;
|
||||
function useStoreWithEqualityFn(api, selector = identity, equalityFn) {
|
||||
const slice = useSyncExternalStoreWithSelector(
|
||||
api.subscribe,
|
||||
api.getState,
|
||||
api.getInitialState,
|
||||
selector,
|
||||
equalityFn
|
||||
);
|
||||
React.useDebugValue(slice);
|
||||
return slice;
|
||||
}
|
||||
const createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
|
||||
const api = createStore(createState);
|
||||
const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
|
||||
Object.assign(useBoundStoreWithEqualityFn, api);
|
||||
return useBoundStoreWithEqualityFn;
|
||||
};
|
||||
const createWithEqualityFn = ((createState, defaultEqualityFn) => createState ? createWithEqualityFnImpl(createState, defaultEqualityFn) : createWithEqualityFnImpl);
|
||||
|
||||
export { createWithEqualityFn, useStoreWithEqualityFn };
|
||||
31
node_modules/zustand/esm/vanilla.d.mts
generated
vendored
Normal file
31
node_modules/zustand/esm/vanilla.d.mts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
type SetStateInternal<T> = {
|
||||
_(partial: T | Partial<T> | {
|
||||
_(state: T): T | Partial<T>;
|
||||
}['_'], replace?: false): void;
|
||||
_(state: T | {
|
||||
_(state: T): T;
|
||||
}['_'], replace: true): void;
|
||||
}['_'];
|
||||
export interface StoreApi<T> {
|
||||
setState: SetStateInternal<T>;
|
||||
getState: () => T;
|
||||
getInitialState: () => T;
|
||||
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
|
||||
}
|
||||
export type ExtractState<S> = S extends {
|
||||
getState: () => infer T;
|
||||
} ? T : never;
|
||||
type Get<T, K, F> = K extends keyof T ? T[K] : F;
|
||||
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs> : never;
|
||||
export type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>, getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>, store: Mutate<StoreApi<T>, Mis>) => U) & {
|
||||
$$storeMutators?: Mos;
|
||||
};
|
||||
export interface StoreMutators<S, A> {
|
||||
}
|
||||
export type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>;
|
||||
type CreateStore = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): Mutate<StoreApi<T>, Mos>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => Mutate<StoreApi<T>, Mos>;
|
||||
};
|
||||
export declare const createStore: CreateStore;
|
||||
export {};
|
||||
24
node_modules/zustand/esm/vanilla.mjs
generated
vendored
Normal file
24
node_modules/zustand/esm/vanilla.mjs
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const createStoreImpl = (createState) => {
|
||||
let state;
|
||||
const listeners = /* @__PURE__ */ new Set();
|
||||
const setState = (partial, replace) => {
|
||||
const nextState = typeof partial === "function" ? partial(state) : partial;
|
||||
if (!Object.is(nextState, state)) {
|
||||
const previousState = state;
|
||||
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
||||
listeners.forEach((listener) => listener(state, previousState));
|
||||
}
|
||||
};
|
||||
const getState = () => state;
|
||||
const getInitialState = () => initialState;
|
||||
const subscribe = (listener) => {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
};
|
||||
const api = { setState, getState, getInitialState, subscribe };
|
||||
const initialState = state = createState(setState, getState, api);
|
||||
return api;
|
||||
};
|
||||
const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
|
||||
|
||||
export { createStore };
|
||||
1
node_modules/zustand/esm/vanilla/shallow.d.mts
generated
vendored
Normal file
1
node_modules/zustand/esm/vanilla/shallow.d.mts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare function shallow<T>(valueA: T, valueB: T): boolean;
|
||||
55
node_modules/zustand/esm/vanilla/shallow.mjs
generated
vendored
Normal file
55
node_modules/zustand/esm/vanilla/shallow.mjs
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
const isIterable = (obj) => Symbol.iterator in obj;
|
||||
const hasIterableEntries = (value) => (
|
||||
// HACK: avoid checking entries type
|
||||
"entries" in value
|
||||
);
|
||||
const compareEntries = (valueA, valueB) => {
|
||||
const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
|
||||
const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
|
||||
if (mapA.size !== mapB.size) {
|
||||
return false;
|
||||
}
|
||||
for (const [key, value] of mapA) {
|
||||
if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const compareIterables = (valueA, valueB) => {
|
||||
const iteratorA = valueA[Symbol.iterator]();
|
||||
const iteratorB = valueB[Symbol.iterator]();
|
||||
let nextA = iteratorA.next();
|
||||
let nextB = iteratorB.next();
|
||||
while (!nextA.done && !nextB.done) {
|
||||
if (!Object.is(nextA.value, nextB.value)) {
|
||||
return false;
|
||||
}
|
||||
nextA = iteratorA.next();
|
||||
nextB = iteratorB.next();
|
||||
}
|
||||
return !!nextA.done && !!nextB.done;
|
||||
};
|
||||
function shallow(valueA, valueB) {
|
||||
if (Object.is(valueA, valueB)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) {
|
||||
return false;
|
||||
}
|
||||
if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
|
||||
return false;
|
||||
}
|
||||
if (isIterable(valueA) && isIterable(valueB)) {
|
||||
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
|
||||
return compareEntries(valueA, valueB);
|
||||
}
|
||||
return compareIterables(valueA, valueB);
|
||||
}
|
||||
return compareEntries(
|
||||
{ entries: () => Object.entries(valueA) },
|
||||
{ entries: () => Object.entries(valueB) }
|
||||
);
|
||||
}
|
||||
|
||||
export { shallow };
|
||||
2
node_modules/zustand/index.d.ts
generated
vendored
Normal file
2
node_modules/zustand/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from 'zustand/vanilla';
|
||||
export * from 'zustand/react';
|
||||
19
node_modules/zustand/index.js
generated
vendored
Normal file
19
node_modules/zustand/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
var vanilla = require('zustand/vanilla');
|
||||
var react = require('zustand/react');
|
||||
|
||||
|
||||
|
||||
Object.keys(vanilla).forEach(function (k) {
|
||||
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
||||
enumerable: true,
|
||||
get: function () { return vanilla[k]; }
|
||||
});
|
||||
});
|
||||
Object.keys(react).forEach(function (k) {
|
||||
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
||||
enumerable: true,
|
||||
get: function () { return react[k]; }
|
||||
});
|
||||
});
|
||||
5
node_modules/zustand/middleware.d.ts
generated
vendored
Normal file
5
node_modules/zustand/middleware.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export { redux } from './middleware/redux';
|
||||
export { devtools, type DevtoolsOptions, type NamedSet, } from './middleware/devtools';
|
||||
export { subscribeWithSelector } from './middleware/subscribeWithSelector';
|
||||
export { combine } from './middleware/combine';
|
||||
export { persist, createJSONStorage, type StateStorage, type StorageValue, type PersistStorage, type PersistOptions, } from './middleware/persist';
|
||||
469
node_modules/zustand/middleware.js
generated
vendored
Normal file
469
node_modules/zustand/middleware.js
generated
vendored
Normal file
@@ -0,0 +1,469 @@
|
||||
'use strict';
|
||||
|
||||
const reduxImpl = (reducer, initial) => (set, _get, api) => {
|
||||
api.dispatch = (action) => {
|
||||
set((state) => reducer(state, action), false, action);
|
||||
return action;
|
||||
};
|
||||
api.dispatchFromDevtools = true;
|
||||
return { dispatch: (...args) => api.dispatch(...args), ...initial };
|
||||
};
|
||||
const redux = reduxImpl;
|
||||
|
||||
const trackedConnections = /* @__PURE__ */ new Map();
|
||||
const getTrackedConnectionState = (name) => {
|
||||
const api = trackedConnections.get(name);
|
||||
if (!api) return {};
|
||||
return Object.fromEntries(
|
||||
Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])
|
||||
);
|
||||
};
|
||||
const extractConnectionInformation = (store, extensionConnector, options) => {
|
||||
if (store === void 0) {
|
||||
return {
|
||||
type: "untracked",
|
||||
connection: extensionConnector.connect(options)
|
||||
};
|
||||
}
|
||||
const existingConnection = trackedConnections.get(options.name);
|
||||
if (existingConnection) {
|
||||
return { type: "tracked", store, ...existingConnection };
|
||||
}
|
||||
const newConnection = {
|
||||
connection: extensionConnector.connect(options),
|
||||
stores: {}
|
||||
};
|
||||
trackedConnections.set(options.name, newConnection);
|
||||
return { type: "tracked", store, ...newConnection };
|
||||
};
|
||||
const removeStoreFromTrackedConnections = (name, store) => {
|
||||
if (store === void 0) return;
|
||||
const connectionInfo = trackedConnections.get(name);
|
||||
if (!connectionInfo) return;
|
||||
delete connectionInfo.stores[store];
|
||||
if (Object.keys(connectionInfo.stores).length === 0) {
|
||||
trackedConnections.delete(name);
|
||||
}
|
||||
};
|
||||
const findCallerName = (stack) => {
|
||||
var _a, _b;
|
||||
if (!stack) return void 0;
|
||||
const traceLines = stack.split("\n");
|
||||
const apiSetStateLineIndex = traceLines.findIndex(
|
||||
(traceLine) => traceLine.includes("api.setState")
|
||||
);
|
||||
if (apiSetStateLineIndex < 0) return void 0;
|
||||
const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || "";
|
||||
return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];
|
||||
};
|
||||
const devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {
|
||||
const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;
|
||||
let extensionConnector;
|
||||
try {
|
||||
extensionConnector = (enabled != null ? enabled : process.env.NODE_ENV !== "production") && window.__REDUX_DEVTOOLS_EXTENSION__;
|
||||
} catch (e) {
|
||||
}
|
||||
if (!extensionConnector) {
|
||||
return fn(set, get, api);
|
||||
}
|
||||
const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);
|
||||
let isRecording = true;
|
||||
api.setState = ((state, replace, nameOrAction) => {
|
||||
const r = set(state, replace);
|
||||
if (!isRecording) return r;
|
||||
const action = nameOrAction === void 0 ? {
|
||||
type: anonymousActionType || findCallerName(new Error().stack) || "anonymous"
|
||||
} : typeof nameOrAction === "string" ? { type: nameOrAction } : nameOrAction;
|
||||
if (store === void 0) {
|
||||
connection == null ? void 0 : connection.send(action, get());
|
||||
return r;
|
||||
}
|
||||
connection == null ? void 0 : connection.send(
|
||||
{
|
||||
...action,
|
||||
type: `${store}/${action.type}`
|
||||
},
|
||||
{
|
||||
...getTrackedConnectionState(options.name),
|
||||
[store]: api.getState()
|
||||
}
|
||||
);
|
||||
return r;
|
||||
});
|
||||
api.devtools = {
|
||||
cleanup: () => {
|
||||
if (connection && typeof connection.unsubscribe === "function") {
|
||||
connection.unsubscribe();
|
||||
}
|
||||
removeStoreFromTrackedConnections(options.name, store);
|
||||
}
|
||||
};
|
||||
const setStateFromDevtools = (...a) => {
|
||||
const originalIsRecording = isRecording;
|
||||
isRecording = false;
|
||||
set(...a);
|
||||
isRecording = originalIsRecording;
|
||||
};
|
||||
const initialState = fn(api.setState, get, api);
|
||||
if (connectionInformation.type === "untracked") {
|
||||
connection == null ? void 0 : connection.init(initialState);
|
||||
} else {
|
||||
connectionInformation.stores[connectionInformation.store] = api;
|
||||
connection == null ? void 0 : connection.init(
|
||||
Object.fromEntries(
|
||||
Object.entries(connectionInformation.stores).map(([key, store2]) => [
|
||||
key,
|
||||
key === connectionInformation.store ? initialState : store2.getState()
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
if (api.dispatchFromDevtools && typeof api.dispatch === "function") {
|
||||
let didWarnAboutReservedActionType = false;
|
||||
const originalDispatch = api.dispatch;
|
||||
api.dispatch = (...args) => {
|
||||
if (process.env.NODE_ENV !== "production" && args[0].type === "__setState" && !didWarnAboutReservedActionType) {
|
||||
console.warn(
|
||||
'[zustand devtools middleware] "__setState" action type is reserved to set state from the devtools. Avoid using it.'
|
||||
);
|
||||
didWarnAboutReservedActionType = true;
|
||||
}
|
||||
originalDispatch(...args);
|
||||
};
|
||||
}
|
||||
connection.subscribe((message) => {
|
||||
var _a;
|
||||
switch (message.type) {
|
||||
case "ACTION":
|
||||
if (typeof message.payload !== "string") {
|
||||
console.error(
|
||||
"[zustand devtools middleware] Unsupported action format"
|
||||
);
|
||||
return;
|
||||
}
|
||||
return parseJsonThen(
|
||||
message.payload,
|
||||
(action) => {
|
||||
if (action.type === "__setState") {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(action.state);
|
||||
return;
|
||||
}
|
||||
if (Object.keys(action.state).length !== 1) {
|
||||
console.error(
|
||||
`
|
||||
[zustand devtools middleware] Unsupported __setState action format.
|
||||
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
|
||||
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
|
||||
`
|
||||
);
|
||||
}
|
||||
const stateFromDevtools = action.state[store];
|
||||
if (stateFromDevtools === void 0 || stateFromDevtools === null) {
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {
|
||||
setStateFromDevtools(stateFromDevtools);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!api.dispatchFromDevtools) return;
|
||||
if (typeof api.dispatch !== "function") return;
|
||||
api.dispatch(action);
|
||||
}
|
||||
);
|
||||
case "DISPATCH":
|
||||
switch (message.payload.type) {
|
||||
case "RESET":
|
||||
setStateFromDevtools(initialState);
|
||||
if (store === void 0) {
|
||||
return connection == null ? void 0 : connection.init(api.getState());
|
||||
}
|
||||
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
case "COMMIT":
|
||||
if (store === void 0) {
|
||||
connection == null ? void 0 : connection.init(api.getState());
|
||||
return;
|
||||
}
|
||||
return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
case "ROLLBACK":
|
||||
return parseJsonThen(message.state, (state) => {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(state);
|
||||
connection == null ? void 0 : connection.init(api.getState());
|
||||
return;
|
||||
}
|
||||
setStateFromDevtools(state[store]);
|
||||
connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));
|
||||
});
|
||||
case "JUMP_TO_STATE":
|
||||
case "JUMP_TO_ACTION":
|
||||
return parseJsonThen(message.state, (state) => {
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(state);
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {
|
||||
setStateFromDevtools(state[store]);
|
||||
}
|
||||
});
|
||||
case "IMPORT_STATE": {
|
||||
const { nextLiftedState } = message.payload;
|
||||
const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;
|
||||
if (!lastComputedState) return;
|
||||
if (store === void 0) {
|
||||
setStateFromDevtools(lastComputedState);
|
||||
} else {
|
||||
setStateFromDevtools(lastComputedState[store]);
|
||||
}
|
||||
connection == null ? void 0 : connection.send(
|
||||
null,
|
||||
// FIXME no-any
|
||||
nextLiftedState
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "PAUSE_RECORDING":
|
||||
return isRecording = !isRecording;
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
return initialState;
|
||||
};
|
||||
const devtools = devtoolsImpl;
|
||||
const parseJsonThen = (stringified, fn) => {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(stringified);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[zustand devtools middleware] Could not parse the received json",
|
||||
e
|
||||
);
|
||||
}
|
||||
if (parsed !== void 0) fn(parsed);
|
||||
};
|
||||
|
||||
const subscribeWithSelectorImpl = (fn) => (set, get, api) => {
|
||||
const origSubscribe = api.subscribe;
|
||||
api.subscribe = ((selector, optListener, options) => {
|
||||
let listener = selector;
|
||||
if (optListener) {
|
||||
const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;
|
||||
let currentSlice = selector(api.getState());
|
||||
listener = (state) => {
|
||||
const nextSlice = selector(state);
|
||||
if (!equalityFn(currentSlice, nextSlice)) {
|
||||
const previousSlice = currentSlice;
|
||||
optListener(currentSlice = nextSlice, previousSlice);
|
||||
}
|
||||
};
|
||||
if (options == null ? void 0 : options.fireImmediately) {
|
||||
optListener(currentSlice, currentSlice);
|
||||
}
|
||||
}
|
||||
return origSubscribe(listener);
|
||||
});
|
||||
const initialState = fn(set, get, api);
|
||||
return initialState;
|
||||
};
|
||||
const subscribeWithSelector = subscribeWithSelectorImpl;
|
||||
|
||||
function combine(initialState, create) {
|
||||
return (...args) => Object.assign({}, initialState, create(...args));
|
||||
}
|
||||
|
||||
function createJSONStorage(getStorage, options) {
|
||||
let storage;
|
||||
try {
|
||||
storage = getStorage();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
const persistStorage = {
|
||||
getItem: (name) => {
|
||||
var _a;
|
||||
const parse = (str2) => {
|
||||
if (str2 === null) {
|
||||
return null;
|
||||
}
|
||||
return JSON.parse(str2, options == null ? void 0 : options.reviver);
|
||||
};
|
||||
const str = (_a = storage.getItem(name)) != null ? _a : null;
|
||||
if (str instanceof Promise) {
|
||||
return str.then(parse);
|
||||
}
|
||||
return parse(str);
|
||||
},
|
||||
setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),
|
||||
removeItem: (name) => storage.removeItem(name)
|
||||
};
|
||||
return persistStorage;
|
||||
}
|
||||
const toThenable = (fn) => (input) => {
|
||||
try {
|
||||
const result = fn(input);
|
||||
if (result instanceof Promise) {
|
||||
return result;
|
||||
}
|
||||
return {
|
||||
then(onFulfilled) {
|
||||
return toThenable(onFulfilled)(result);
|
||||
},
|
||||
catch(_onRejected) {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
then(_onFulfilled) {
|
||||
return this;
|
||||
},
|
||||
catch(onRejected) {
|
||||
return toThenable(onRejected)(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
const persistImpl = (config, baseOptions) => (set, get, api) => {
|
||||
let options = {
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => state,
|
||||
version: 0,
|
||||
merge: (persistedState, currentState) => ({
|
||||
...currentState,
|
||||
...persistedState
|
||||
}),
|
||||
...baseOptions
|
||||
};
|
||||
let hasHydrated = false;
|
||||
const hydrationListeners = /* @__PURE__ */ new Set();
|
||||
const finishHydrationListeners = /* @__PURE__ */ new Set();
|
||||
let storage = options.storage;
|
||||
if (!storage) {
|
||||
return config(
|
||||
(...args) => {
|
||||
console.warn(
|
||||
`[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`
|
||||
);
|
||||
set(...args);
|
||||
},
|
||||
get,
|
||||
api
|
||||
);
|
||||
}
|
||||
const setItem = () => {
|
||||
const state = options.partialize({ ...get() });
|
||||
return storage.setItem(options.name, {
|
||||
state,
|
||||
version: options.version
|
||||
});
|
||||
};
|
||||
const savedSetState = api.setState;
|
||||
api.setState = (state, replace) => {
|
||||
savedSetState(state, replace);
|
||||
return setItem();
|
||||
};
|
||||
const configResult = config(
|
||||
(...args) => {
|
||||
set(...args);
|
||||
return setItem();
|
||||
},
|
||||
get,
|
||||
api
|
||||
);
|
||||
api.getInitialState = () => configResult;
|
||||
let stateFromStorage;
|
||||
const hydrate = () => {
|
||||
var _a, _b;
|
||||
if (!storage) return;
|
||||
hasHydrated = false;
|
||||
hydrationListeners.forEach((cb) => {
|
||||
var _a2;
|
||||
return cb((_a2 = get()) != null ? _a2 : configResult);
|
||||
});
|
||||
const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;
|
||||
return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {
|
||||
if (deserializedStorageValue) {
|
||||
if (typeof deserializedStorageValue.version === "number" && deserializedStorageValue.version !== options.version) {
|
||||
if (options.migrate) {
|
||||
const migration = options.migrate(
|
||||
deserializedStorageValue.state,
|
||||
deserializedStorageValue.version
|
||||
);
|
||||
if (migration instanceof Promise) {
|
||||
return migration.then((result) => [true, result]);
|
||||
}
|
||||
return [true, migration];
|
||||
}
|
||||
console.error(
|
||||
`State loaded from storage couldn't be migrated since no migrate function was provided`
|
||||
);
|
||||
} else {
|
||||
return [false, deserializedStorageValue.state];
|
||||
}
|
||||
}
|
||||
return [false, void 0];
|
||||
}).then((migrationResult) => {
|
||||
var _a2;
|
||||
const [migrated, migratedState] = migrationResult;
|
||||
stateFromStorage = options.merge(
|
||||
migratedState,
|
||||
(_a2 = get()) != null ? _a2 : configResult
|
||||
);
|
||||
set(stateFromStorage, true);
|
||||
if (migrated) {
|
||||
return setItem();
|
||||
}
|
||||
}).then(() => {
|
||||
postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0);
|
||||
stateFromStorage = get();
|
||||
hasHydrated = true;
|
||||
finishHydrationListeners.forEach((cb) => cb(stateFromStorage));
|
||||
}).catch((e) => {
|
||||
postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);
|
||||
});
|
||||
};
|
||||
api.persist = {
|
||||
setOptions: (newOptions) => {
|
||||
options = {
|
||||
...options,
|
||||
...newOptions
|
||||
};
|
||||
if (newOptions.storage) {
|
||||
storage = newOptions.storage;
|
||||
}
|
||||
},
|
||||
clearStorage: () => {
|
||||
storage == null ? void 0 : storage.removeItem(options.name);
|
||||
},
|
||||
getOptions: () => options,
|
||||
rehydrate: () => hydrate(),
|
||||
hasHydrated: () => hasHydrated,
|
||||
onHydrate: (cb) => {
|
||||
hydrationListeners.add(cb);
|
||||
return () => {
|
||||
hydrationListeners.delete(cb);
|
||||
};
|
||||
},
|
||||
onFinishHydration: (cb) => {
|
||||
finishHydrationListeners.add(cb);
|
||||
return () => {
|
||||
finishHydrationListeners.delete(cb);
|
||||
};
|
||||
}
|
||||
};
|
||||
if (!options.skipHydration) {
|
||||
hydrate();
|
||||
}
|
||||
return stateFromStorage || configResult;
|
||||
};
|
||||
const persist = persistImpl;
|
||||
|
||||
exports.combine = combine;
|
||||
exports.createJSONStorage = createJSONStorage;
|
||||
exports.devtools = devtools;
|
||||
exports.persist = persist;
|
||||
exports.redux = redux;
|
||||
exports.subscribeWithSelector = subscribeWithSelector;
|
||||
4
node_modules/zustand/middleware/combine.d.ts
generated
vendored
Normal file
4
node_modules/zustand/middleware/combine.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
export declare function combine<T extends object, U extends object, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initialState: T, create: StateCreator<T, Mps, Mcs, U>): StateCreator<Write<T, U>, Mps, Mcs>;
|
||||
export {};
|
||||
58
node_modules/zustand/middleware/devtools.d.ts
generated
vendored
Normal file
58
node_modules/zustand/middleware/devtools.d.ts
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Config = Parameters<(Window extends {
|
||||
__REDUX_DEVTOOLS_EXTENSION__?: infer T;
|
||||
} ? T : {
|
||||
connect: (param: any) => any;
|
||||
})['connect']>[0];
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/devtools': WithDevtools<S>;
|
||||
}
|
||||
}
|
||||
type Cast<T, U> = T extends U ? T : U;
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type TakeTwo<T> = T extends {
|
||||
length: 0;
|
||||
} ? [undefined, undefined] : T extends {
|
||||
length: 1;
|
||||
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
|
||||
length: 0 | 1;
|
||||
} ? [...args0: Cast<T, unknown[]>, arg1: undefined] : T extends {
|
||||
length: 2;
|
||||
} ? T : T extends {
|
||||
length: 1 | 2;
|
||||
} ? T : T extends {
|
||||
length: 0 | 1 | 2;
|
||||
} ? T : T extends [infer A0, infer A1, ...unknown[]] ? [A0, A1] : T extends [infer A0, (infer A1)?, ...unknown[]] ? [A0, A1?] : T extends [(infer A0)?, (infer A1)?, ...unknown[]] ? [A0?, A1?] : never;
|
||||
type WithDevtools<S> = Write<S, StoreDevtools<S>>;
|
||||
type Action = string | {
|
||||
type: string;
|
||||
[x: string | number | symbol]: unknown;
|
||||
};
|
||||
type StoreDevtools<S> = S extends {
|
||||
setState: {
|
||||
(...args: infer Sa1): infer Sr1;
|
||||
(...args: infer Sa2): infer Sr2;
|
||||
};
|
||||
} ? {
|
||||
setState(...args: [...args: TakeTwo<Sa1>, action?: Action]): Sr1;
|
||||
setState(...args: [...args: TakeTwo<Sa2>, action?: Action]): Sr2;
|
||||
devtools: {
|
||||
cleanup: () => void;
|
||||
};
|
||||
} : never;
|
||||
export interface DevtoolsOptions extends Config {
|
||||
name?: string;
|
||||
enabled?: boolean;
|
||||
anonymousActionType?: string;
|
||||
store?: string;
|
||||
}
|
||||
type Devtools = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/devtools', never]], Mcs, U>, devtoolsOptions?: DevtoolsOptions) => StateCreator<T, Mps, [['zustand/devtools', never], ...Mcs]>;
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/devtools': WithDevtools<S>;
|
||||
}
|
||||
}
|
||||
export type NamedSet<T> = WithDevtools<StoreApi<T>>['setState'];
|
||||
export declare const devtools: Devtools;
|
||||
export {};
|
||||
29
node_modules/zustand/middleware/immer.d.ts
generated
vendored
Normal file
29
node_modules/zustand/middleware/immer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Draft } from 'immer';
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Immer = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [...Mps, ['zustand/immer', never]], Mcs>) => StateCreator<T, Mps, [['zustand/immer', never], ...Mcs]>;
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
['zustand/immer']: WithImmer<S>;
|
||||
}
|
||||
}
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type SkipTwo<T> = T extends {
|
||||
length: 0;
|
||||
} ? [] : T extends {
|
||||
length: 1;
|
||||
} ? [] : T extends {
|
||||
length: 0 | 1;
|
||||
} ? [] : T extends [unknown, unknown, ...infer A] ? A : T extends [unknown, unknown?, ...infer A] ? A : T extends [unknown?, unknown?, ...infer A] ? A : never;
|
||||
type SetStateType<T extends unknown[]> = Exclude<T[0], (...args: any[]) => any>;
|
||||
type WithImmer<S> = Write<S, StoreImmer<S>>;
|
||||
type StoreImmer<S> = S extends {
|
||||
setState: infer SetState;
|
||||
} ? SetState extends {
|
||||
(...args: infer A1): infer Sr1;
|
||||
(...args: infer A2): infer Sr2;
|
||||
} ? {
|
||||
setState(nextStateOrUpdater: SetStateType<A2> | Partial<SetStateType<A2>> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace?: false, ...args: SkipTwo<A1>): Sr1;
|
||||
setState(nextStateOrUpdater: SetStateType<A2> | ((state: Draft<SetStateType<A2>>) => void), shouldReplace: true, ...args: SkipTwo<A2>): Sr2;
|
||||
} : never : never;
|
||||
export declare const immer: Immer;
|
||||
export {};
|
||||
14
node_modules/zustand/middleware/immer.js
generated
vendored
Normal file
14
node_modules/zustand/middleware/immer.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var immer$1 = require('immer');
|
||||
|
||||
const immerImpl = (initializer) => (set, get, store) => {
|
||||
store.setState = (updater, replace, ...args) => {
|
||||
const nextState = typeof updater === "function" ? immer$1.produce(updater) : updater;
|
||||
return set(nextState, replace, ...args);
|
||||
};
|
||||
return initializer(store.setState, get, store);
|
||||
};
|
||||
const immer = immerImpl;
|
||||
|
||||
exports.immer = immer;
|
||||
99
node_modules/zustand/middleware/persist.d.ts
generated
vendored
Normal file
99
node_modules/zustand/middleware/persist.d.ts
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
export interface StateStorage<R = unknown> {
|
||||
getItem: (name: string) => string | null | Promise<string | null>;
|
||||
setItem: (name: string, value: string) => R;
|
||||
removeItem: (name: string) => R;
|
||||
}
|
||||
export type StorageValue<S> = {
|
||||
state: S;
|
||||
version?: number;
|
||||
};
|
||||
export interface PersistStorage<S, R = unknown> {
|
||||
getItem: (name: string) => StorageValue<S> | null | Promise<StorageValue<S> | null>;
|
||||
setItem: (name: string, value: StorageValue<S>) => R;
|
||||
removeItem: (name: string) => R;
|
||||
}
|
||||
type JsonStorageOptions = {
|
||||
reviver?: (key: string, value: unknown) => unknown;
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
};
|
||||
export declare function createJSONStorage<S, R = unknown>(getStorage: () => StateStorage<R>, options?: JsonStorageOptions): PersistStorage<S, unknown> | undefined;
|
||||
export interface PersistOptions<S, PersistedState = S, PersistReturn = unknown> {
|
||||
/** Name of the storage (must be unique) */
|
||||
name: string;
|
||||
/**
|
||||
* Use a custom persist storage.
|
||||
*
|
||||
* Combining `createJSONStorage` helps creating a persist storage
|
||||
* with JSON.parse and JSON.stringify.
|
||||
*
|
||||
* @default createJSONStorage(() => localStorage)
|
||||
*/
|
||||
storage?: PersistStorage<PersistedState, PersistReturn> | undefined;
|
||||
/**
|
||||
* Filter the persisted value.
|
||||
*
|
||||
* @params state The state's value
|
||||
*/
|
||||
partialize?: (state: S) => PersistedState;
|
||||
/**
|
||||
* A function returning another (optional) function.
|
||||
* The main function will be called before the state rehydration.
|
||||
* The returned function will be called after the state rehydration or when an error occurred.
|
||||
*/
|
||||
onRehydrateStorage?: (state: S) => ((state?: S, error?: unknown) => void) | void;
|
||||
/**
|
||||
* If the stored state's version mismatch the one specified here, the storage will not be used.
|
||||
* This is useful when adding a breaking change to your store.
|
||||
*/
|
||||
version?: number;
|
||||
/**
|
||||
* A function to perform persisted state migration.
|
||||
* This function will be called when persisted state versions mismatch with the one specified here.
|
||||
*/
|
||||
migrate?: (persistedState: unknown, version: number) => PersistedState | Promise<PersistedState>;
|
||||
/**
|
||||
* A function to perform custom hydration merges when combining the stored state with the current one.
|
||||
* By default, this function does a shallow merge.
|
||||
*/
|
||||
merge?: (persistedState: unknown, currentState: S) => S;
|
||||
/**
|
||||
* An optional boolean that will prevent the persist middleware from triggering hydration on initialization,
|
||||
* This allows you to call `rehydrate()` at a specific point in your apps rendering life-cycle.
|
||||
*
|
||||
* This is useful in SSR application.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
skipHydration?: boolean;
|
||||
}
|
||||
type PersistListener<S> = (state: S) => void;
|
||||
type StorePersist<S, Ps, Pr> = S extends {
|
||||
getState: () => infer T;
|
||||
setState: {
|
||||
(...args: infer Sa1): infer Sr1;
|
||||
(...args: infer Sa2): infer Sr2;
|
||||
};
|
||||
} ? {
|
||||
setState(...args: Sa1): Sr1 | Pr;
|
||||
setState(...args: Sa2): Sr2 | Pr;
|
||||
persist: {
|
||||
setOptions: (options: Partial<PersistOptions<T, Ps, Pr>>) => void;
|
||||
clearStorage: () => void;
|
||||
rehydrate: () => Promise<void> | void;
|
||||
hasHydrated: () => boolean;
|
||||
onHydrate: (fn: PersistListener<T>) => () => void;
|
||||
onFinishHydration: (fn: PersistListener<T>) => () => void;
|
||||
getOptions: () => Partial<PersistOptions<T, Ps, Pr>>;
|
||||
};
|
||||
} : never;
|
||||
type Persist = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = [], U = T>(initializer: StateCreator<T, [...Mps, ['zustand/persist', unknown]], Mcs>, options: PersistOptions<T, U>) => StateCreator<T, Mps, [['zustand/persist', U], ...Mcs]>;
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/persist': WithPersist<S, A>;
|
||||
}
|
||||
}
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type WithPersist<S, A> = Write<S, StorePersist<S, A, unknown>>;
|
||||
export declare const persist: Persist;
|
||||
export {};
|
||||
21
node_modules/zustand/middleware/redux.d.ts
generated
vendored
Normal file
21
node_modules/zustand/middleware/redux.d.ts
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type Action = {
|
||||
type: string;
|
||||
};
|
||||
type StoreRedux<A> = {
|
||||
dispatch: (a: A) => A;
|
||||
dispatchFromDevtools: true;
|
||||
};
|
||||
type ReduxState<A> = {
|
||||
dispatch: StoreRedux<A>['dispatch'];
|
||||
};
|
||||
type WithRedux<S, A> = Write<S, StoreRedux<A>>;
|
||||
type Redux = <T, A extends Action, Cms extends [StoreMutatorIdentifier, unknown][] = []>(reducer: (state: T, action: A) => T, initialState: T) => StateCreator<Write<T, ReduxState<A>>, Cms, [['zustand/redux', A]]>;
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
'zustand/redux': WithRedux<S, A>;
|
||||
}
|
||||
}
|
||||
export declare const redux: Redux;
|
||||
export {};
|
||||
25
node_modules/zustand/middleware/subscribeWithSelector.d.ts
generated
vendored
Normal file
25
node_modules/zustand/middleware/subscribeWithSelector.d.ts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import type { StateCreator, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type SubscribeWithSelector = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [
|
||||
...Mps,
|
||||
['zustand/subscribeWithSelector', never]
|
||||
], Mcs>) => StateCreator<T, Mps, [['zustand/subscribeWithSelector', never], ...Mcs]>;
|
||||
type Write<T, U> = Omit<T, keyof U> & U;
|
||||
type WithSelectorSubscribe<S> = S extends {
|
||||
getState: () => infer T;
|
||||
} ? Write<S, StoreSubscribeWithSelector<T>> : never;
|
||||
declare module '../vanilla' {
|
||||
interface StoreMutators<S, A> {
|
||||
['zustand/subscribeWithSelector']: WithSelectorSubscribe<S>;
|
||||
}
|
||||
}
|
||||
type StoreSubscribeWithSelector<T> = {
|
||||
subscribe: {
|
||||
(listener: (selectedState: T, previousSelectedState: T) => void): () => void;
|
||||
<U>(selector: (state: T) => U, listener: (selectedState: U, previousSelectedState: U) => void, options?: {
|
||||
equalityFn?: (a: U, b: U) => boolean;
|
||||
fireImmediately?: boolean;
|
||||
}): () => void;
|
||||
};
|
||||
};
|
||||
export declare const subscribeWithSelector: SubscribeWithSelector;
|
||||
export {};
|
||||
108
node_modules/zustand/package.json
generated
vendored
Normal file
108
node_modules/zustand/package.json
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"name": "zustand",
|
||||
"description": "🐻 Bear necessities for state management in React",
|
||||
"private": false,
|
||||
"type": "commonjs",
|
||||
"version": "5.0.8",
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
"typesVersions": {
|
||||
">=4.5": {
|
||||
"esm/*": [
|
||||
"esm/*"
|
||||
],
|
||||
"*": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"*": {
|
||||
"esm/*": [
|
||||
"ts_version_4.5_and_above_is_required.d.ts"
|
||||
],
|
||||
"*": [
|
||||
"ts_version_4.5_and_above_is_required.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"react-native": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./esm/index.d.mts",
|
||||
"default": "./esm/index.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
}
|
||||
},
|
||||
"./*": {
|
||||
"react-native": {
|
||||
"types": "./*.d.ts",
|
||||
"default": "./*.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./esm/*.d.mts",
|
||||
"default": "./esm/*.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./*.d.ts",
|
||||
"default": "./*.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"**"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pmndrs/zustand.git"
|
||||
},
|
||||
"keywords": [
|
||||
"react",
|
||||
"state",
|
||||
"manager",
|
||||
"management",
|
||||
"redux",
|
||||
"store"
|
||||
],
|
||||
"author": "Paul Henschel",
|
||||
"contributors": [
|
||||
"Jeremy Holcomb (https://github.com/JeremyRH)",
|
||||
"Daishi Kato (https://github.com/dai-shi)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pmndrs/zustand/issues"
|
||||
},
|
||||
"homepage": "https://github.com/pmndrs/zustand",
|
||||
"packageManager": "pnpm@9.15.5",
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=18.0.0",
|
||||
"use-sync-external-store": ">=1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
14
node_modules/zustand/react.d.ts
generated
vendored
Normal file
14
node_modules/zustand/react.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
|
||||
export declare function useStore<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
|
||||
export declare function useStore<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U): U;
|
||||
export type UseBoundStore<S extends ReadonlyStoreApi<unknown>> = {
|
||||
(): ExtractState<S>;
|
||||
<U>(selector: (state: ExtractState<S>) => U): U;
|
||||
} & S;
|
||||
type Create = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): UseBoundStore<Mutate<StoreApi<T>, Mos>>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => UseBoundStore<Mutate<StoreApi<T>, Mos>>;
|
||||
};
|
||||
export declare const create: Create;
|
||||
export {};
|
||||
25
node_modules/zustand/react.js
generated
vendored
Normal file
25
node_modules/zustand/react.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var vanilla = require('zustand/vanilla');
|
||||
|
||||
const identity = (arg) => arg;
|
||||
function useStore(api, selector = identity) {
|
||||
const slice = React.useSyncExternalStore(
|
||||
api.subscribe,
|
||||
React.useCallback(() => selector(api.getState()), [api, selector]),
|
||||
React.useCallback(() => selector(api.getInitialState()), [api, selector])
|
||||
);
|
||||
React.useDebugValue(slice);
|
||||
return slice;
|
||||
}
|
||||
const createImpl = (createState) => {
|
||||
const api = vanilla.createStore(createState);
|
||||
const useBoundStore = (selector) => useStore(api, selector);
|
||||
Object.assign(useBoundStore, api);
|
||||
return useBoundStore;
|
||||
};
|
||||
const create = ((createState) => createState ? createImpl(createState) : createImpl);
|
||||
|
||||
exports.create = create;
|
||||
exports.useStore = useStore;
|
||||
1
node_modules/zustand/react/shallow.d.ts
generated
vendored
Normal file
1
node_modules/zustand/react/shallow.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare function useShallow<S, U>(selector: (state: S) => U): (state: S) => U;
|
||||
14
node_modules/zustand/react/shallow.js
generated
vendored
Normal file
14
node_modules/zustand/react/shallow.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var shallow = require('zustand/vanilla/shallow');
|
||||
|
||||
function useShallow(selector) {
|
||||
const prev = React.useRef(void 0);
|
||||
return (state) => {
|
||||
const next = selector(state);
|
||||
return shallow.shallow(prev.current, next) ? prev.current : prev.current = next;
|
||||
};
|
||||
}
|
||||
|
||||
exports.useShallow = useShallow;
|
||||
2
node_modules/zustand/shallow.d.ts
generated
vendored
Normal file
2
node_modules/zustand/shallow.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { shallow } from 'zustand/vanilla/shallow';
|
||||
export { useShallow } from 'zustand/react/shallow';
|
||||
15
node_modules/zustand/shallow.js
generated
vendored
Normal file
15
node_modules/zustand/shallow.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var shallow = require('zustand/vanilla/shallow');
|
||||
var shallow$1 = require('zustand/react/shallow');
|
||||
|
||||
|
||||
|
||||
Object.defineProperty(exports, "shallow", {
|
||||
enumerable: true,
|
||||
get: function () { return shallow.shallow; }
|
||||
});
|
||||
Object.defineProperty(exports, "useShallow", {
|
||||
enumerable: true,
|
||||
get: function () { return shallow$1.useShallow; }
|
||||
});
|
||||
14
node_modules/zustand/traditional.d.ts
generated
vendored
Normal file
14
node_modules/zustand/traditional.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { ExtractState, Mutate, StateCreator, StoreApi, StoreMutatorIdentifier } from 'zustand/vanilla';
|
||||
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'getInitialState' | 'subscribe'>;
|
||||
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>>(api: S): ExtractState<S>;
|
||||
export declare function useStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>, U>(api: S, selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
||||
export type UseBoundStoreWithEqualityFn<S extends ReadonlyStoreApi<unknown>> = {
|
||||
(): ExtractState<S>;
|
||||
<U>(selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U;
|
||||
} & S;
|
||||
type CreateWithEqualityFn = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>, defaultEqualityFn?: <U>(a: U, b: U) => boolean) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>;
|
||||
};
|
||||
export declare const createWithEqualityFn: CreateWithEqualityFn;
|
||||
export {};
|
||||
29
node_modules/zustand/traditional.js
generated
vendored
Normal file
29
node_modules/zustand/traditional.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var useSyncExternalStoreExports = require('use-sync-external-store/shim/with-selector');
|
||||
var vanilla = require('zustand/vanilla');
|
||||
|
||||
const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
|
||||
const identity = (arg) => arg;
|
||||
function useStoreWithEqualityFn(api, selector = identity, equalityFn) {
|
||||
const slice = useSyncExternalStoreWithSelector(
|
||||
api.subscribe,
|
||||
api.getState,
|
||||
api.getInitialState,
|
||||
selector,
|
||||
equalityFn
|
||||
);
|
||||
React.useDebugValue(slice);
|
||||
return slice;
|
||||
}
|
||||
const createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
|
||||
const api = vanilla.createStore(createState);
|
||||
const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
|
||||
Object.assign(useBoundStoreWithEqualityFn, api);
|
||||
return useBoundStoreWithEqualityFn;
|
||||
};
|
||||
const createWithEqualityFn = ((createState, defaultEqualityFn) => createState ? createWithEqualityFnImpl(createState, defaultEqualityFn) : createWithEqualityFnImpl);
|
||||
|
||||
exports.createWithEqualityFn = createWithEqualityFn;
|
||||
exports.useStoreWithEqualityFn = useStoreWithEqualityFn;
|
||||
0
node_modules/zustand/ts_version_4.5_and_above_is_required.d.ts
generated
vendored
Normal file
0
node_modules/zustand/ts_version_4.5_and_above_is_required.d.ts
generated
vendored
Normal file
31
node_modules/zustand/vanilla.d.ts
generated
vendored
Normal file
31
node_modules/zustand/vanilla.d.ts
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
type SetStateInternal<T> = {
|
||||
_(partial: T | Partial<T> | {
|
||||
_(state: T): T | Partial<T>;
|
||||
}['_'], replace?: false): void;
|
||||
_(state: T | {
|
||||
_(state: T): T;
|
||||
}['_'], replace: true): void;
|
||||
}['_'];
|
||||
export interface StoreApi<T> {
|
||||
setState: SetStateInternal<T>;
|
||||
getState: () => T;
|
||||
getInitialState: () => T;
|
||||
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
|
||||
}
|
||||
export type ExtractState<S> = S extends {
|
||||
getState: () => infer T;
|
||||
} ? T : never;
|
||||
type Get<T, K, F> = K extends keyof T ? T[K] : F;
|
||||
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms] ? S : Ms extends [] ? S : Ms extends [[infer Mi, infer Ma], ...infer Mrs] ? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs> : never;
|
||||
export type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: Get<Mutate<StoreApi<T>, Mis>, 'setState', never>, getState: Get<Mutate<StoreApi<T>, Mis>, 'getState', never>, store: Mutate<StoreApi<T>, Mis>) => U) & {
|
||||
$$storeMutators?: Mos;
|
||||
};
|
||||
export interface StoreMutators<S, A> {
|
||||
}
|
||||
export type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>;
|
||||
type CreateStore = {
|
||||
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>): Mutate<StoreApi<T>, Mos>;
|
||||
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [], Mos>) => Mutate<StoreApi<T>, Mos>;
|
||||
};
|
||||
export declare const createStore: CreateStore;
|
||||
export {};
|
||||
26
node_modules/zustand/vanilla.js
generated
vendored
Normal file
26
node_modules/zustand/vanilla.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
const createStoreImpl = (createState) => {
|
||||
let state;
|
||||
const listeners = /* @__PURE__ */ new Set();
|
||||
const setState = (partial, replace) => {
|
||||
const nextState = typeof partial === "function" ? partial(state) : partial;
|
||||
if (!Object.is(nextState, state)) {
|
||||
const previousState = state;
|
||||
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
|
||||
listeners.forEach((listener) => listener(state, previousState));
|
||||
}
|
||||
};
|
||||
const getState = () => state;
|
||||
const getInitialState = () => initialState;
|
||||
const subscribe = (listener) => {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
};
|
||||
const api = { setState, getState, getInitialState, subscribe };
|
||||
const initialState = state = createState(setState, getState, api);
|
||||
return api;
|
||||
};
|
||||
const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
|
||||
|
||||
exports.createStore = createStore;
|
||||
1
node_modules/zustand/vanilla/shallow.d.ts
generated
vendored
Normal file
1
node_modules/zustand/vanilla/shallow.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare function shallow<T>(valueA: T, valueB: T): boolean;
|
||||
57
node_modules/zustand/vanilla/shallow.js
generated
vendored
Normal file
57
node_modules/zustand/vanilla/shallow.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
|
||||
const isIterable = (obj) => Symbol.iterator in obj;
|
||||
const hasIterableEntries = (value) => (
|
||||
// HACK: avoid checking entries type
|
||||
"entries" in value
|
||||
);
|
||||
const compareEntries = (valueA, valueB) => {
|
||||
const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
|
||||
const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
|
||||
if (mapA.size !== mapB.size) {
|
||||
return false;
|
||||
}
|
||||
for (const [key, value] of mapA) {
|
||||
if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const compareIterables = (valueA, valueB) => {
|
||||
const iteratorA = valueA[Symbol.iterator]();
|
||||
const iteratorB = valueB[Symbol.iterator]();
|
||||
let nextA = iteratorA.next();
|
||||
let nextB = iteratorB.next();
|
||||
while (!nextA.done && !nextB.done) {
|
||||
if (!Object.is(nextA.value, nextB.value)) {
|
||||
return false;
|
||||
}
|
||||
nextA = iteratorA.next();
|
||||
nextB = iteratorB.next();
|
||||
}
|
||||
return !!nextA.done && !!nextB.done;
|
||||
};
|
||||
function shallow(valueA, valueB) {
|
||||
if (Object.is(valueA, valueB)) {
|
||||
return true;
|
||||
}
|
||||
if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) {
|
||||
return false;
|
||||
}
|
||||
if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
|
||||
return false;
|
||||
}
|
||||
if (isIterable(valueA) && isIterable(valueB)) {
|
||||
if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
|
||||
return compareEntries(valueA, valueB);
|
||||
}
|
||||
return compareIterables(valueA, valueB);
|
||||
}
|
||||
return compareEntries(
|
||||
{ entries: () => Object.entries(valueA) },
|
||||
{ entries: () => Object.entries(valueB) }
|
||||
);
|
||||
}
|
||||
|
||||
exports.shallow = shallow;
|
||||
35
package-lock.json
generated
35
package-lock.json
generated
@@ -13,7 +13,8 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"recharts": "^2.5.0"
|
||||
"recharts": "^2.5.0",
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.28",
|
||||
@@ -958,13 +959,13 @@
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"dev": true
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
|
||||
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -5583,6 +5584,34 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
|
||||
"integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
"immer": ">=9.0.6",
|
||||
"react": ">=18.0.0",
|
||||
"use-sync-external-store": ">=1.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"immer": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"use-sync-external-store": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"lucide-react": "^0.263.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"axios": "^1.3.4",
|
||||
"recharts": "^2.5.0",
|
||||
"lucide-react": "^0.263.1"
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.28",
|
||||
|
||||
21
src/App.jsx
21
src/App.jsx
@@ -1,16 +1,18 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { AuthProvider, useAuth } from './context/AuthContext';
|
||||
import { useAuthStore } from './store/authStore';
|
||||
import Sidebar from './components/Sidebar';
|
||||
import Navbar from './components/Navbar';
|
||||
import Login from './pages/Login';
|
||||
import Dashboard from './pages/Dashboard';
|
||||
import Transactions from './pages/Transactions';
|
||||
import Settings from './pages/Settings';
|
||||
import ForgotPassword from './pages/ForgotPassword';
|
||||
|
||||
// Protected Route Component
|
||||
const ProtectedRoute = ({ children }) => {
|
||||
const { isAuthenticated, loading } = useAuth();
|
||||
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
|
||||
const loading = useAuthStore((s) => s.loading);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
@@ -20,7 +22,7 @@ const ProtectedRoute = ({ children }) => {
|
||||
);
|
||||
}
|
||||
|
||||
return isAuthenticated ? children : <Navigate to="/login" />;
|
||||
return isLoggedIn ? children : <Navigate to="/login" />;
|
||||
};
|
||||
|
||||
// Main Layout Component
|
||||
@@ -58,6 +60,7 @@ const AppRoutes = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/forgot-password" element={<ForgotPassword />} />
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
@@ -96,13 +99,11 @@ const AppRoutes = () => {
|
||||
// Main App Component
|
||||
const App = () => {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<Router>
|
||||
<div className="App">
|
||||
<AppRoutes />
|
||||
</div>
|
||||
</Router>
|
||||
</AuthProvider>
|
||||
<Router>
|
||||
<div className="App">
|
||||
<AppRoutes />
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Menu, Sun, Moon, User, LogOut, ChevronDown } from 'lucide-react';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { signOut } from '../services/api';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
const Navbar = ({ onSidebarToggle }) => {
|
||||
const { user, logout } = useAuth();
|
||||
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
|
||||
const [isDarkMode, setIsDarkMode] = useState(() => {
|
||||
return localStorage.getItem('theme') === 'dark' ||
|
||||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
@@ -25,9 +26,14 @@ const Navbar = ({ onSidebarToggle }) => {
|
||||
setIsDarkMode(!isDarkMode);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
setIsUserMenuOpen(false);
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await signOut();
|
||||
} catch (e) {
|
||||
// no-op; interceptor handles redirect and state
|
||||
} finally {
|
||||
setIsUserMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -71,7 +77,7 @@ const Navbar = ({ onSidebarToggle }) => {
|
||||
<User className="h-4 w-4 text-blue-600 dark:text-blue-400" />
|
||||
</div>
|
||||
<span className="hidden sm:block text-sm font-medium">
|
||||
{user?.name || 'Admin'}
|
||||
{isLoggedIn ? 'Admin' : 'Guest'}
|
||||
</span>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
</button>
|
||||
@@ -81,10 +87,10 @@ const Navbar = ({ onSidebarToggle }) => {
|
||||
<div className="absolute right-0 mt-2 w-48 bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 py-1 z-50">
|
||||
<div className="px-4 py-2 border-b border-gray-200 dark:border-gray-700">
|
||||
<p className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{user?.name || 'Admin User'}
|
||||
{isLoggedIn ? 'Admin User' : 'Guest'}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{user?.email || 'admin@example.com'}
|
||||
{isLoggedIn ? 'admin@example.com' : ''}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
||||
100
src/pages/ForgotPassword.jsx
Normal file
100
src/pages/ForgotPassword.jsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate, Link } from 'react-router-dom';
|
||||
import { CreditCard } from 'lucide-react';
|
||||
import { forgotPassword } from '../services/api';
|
||||
|
||||
const ForgotPassword = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [success, setSuccess] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
setError('');
|
||||
setSuccess('');
|
||||
|
||||
try {
|
||||
const res = await forgotPassword(email);
|
||||
setSuccess(res?.message || 'If the email exists, a reset link was sent.');
|
||||
} catch (err) {
|
||||
setError(typeof err === 'string' ? err : 'Request failed. Please try again.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="flex justify-center">
|
||||
<div className="bg-primary-600 p-3 rounded-full">
|
||||
<CreditCard className="h-8 w-8 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<h2 className="mt-6 text-center text-3xl font-bold text-gray-900 dark:text-white">
|
||||
Forgot Password
|
||||
</h2>
|
||||
<p className="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
|
||||
Enter your email to receive a new password
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="bg-white dark:bg-gray-800 py-8 px-4 shadow sm:rounded-lg sm:px-10 border border-gray-200 dark:border-gray-700">
|
||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
||||
{error && (
|
||||
<div className="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 text-red-700 dark:text-red-300 px-4 py-3 rounded-md text-sm">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
{success && (
|
||||
<div className="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 text-green-700 dark:text-green-300 px-4 py-3 rounded-md text-sm">
|
||||
{success}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
Email address
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
className="input-field"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full btn-primary disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
|
||||
>
|
||||
{loading ? 'Sending...' : 'Send new password'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div className="mt-6 text-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<Link to="/login" className="text-primary-600 hover:text-primary-700">Back to Login</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForgotPassword;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { CreditCard, Eye, EyeOff } from 'lucide-react';
|
||||
import { login as apiLogin } from '../services/api';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
const Login = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
@@ -10,7 +11,7 @@ const Login = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const { login } = useAuth();
|
||||
const setLoggedIn = useAuthStore((s) => s.setLoggedIn);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
@@ -19,14 +20,16 @@ const Login = () => {
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const result = await login(email, password);
|
||||
if (result.success) {
|
||||
const result = await apiLogin(email, password);
|
||||
// If server responds successfully, consider logged in (session cookie via withCredentials)
|
||||
if (result) {
|
||||
setLoggedIn(true);
|
||||
navigate('/');
|
||||
} else {
|
||||
setError('Invalid email or password');
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Login failed. Please try again.');
|
||||
setError(typeof err === 'string' ? err : 'Login failed. Please try again.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -140,8 +143,8 @@ const Login = () => {
|
||||
</div>
|
||||
|
||||
<div className="mt-4 text-center text-sm text-gray-600 dark:text-gray-400">
|
||||
<p>Email: admin@example.com</p>
|
||||
<p>Password: password</p>
|
||||
<p>Forget Password? <a href="/forgot-password" className="text-primary-600 hover:text-primary-700">Reset Password</a></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,43 +1,95 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// Create axios instance
|
||||
import { useAuthStore } from "../store/authStore";
|
||||
|
||||
const BASE_URL = import.meta.env.DEV ? "/" : "https://khalijpay-core.qaserver.ir";
|
||||
|
||||
// ساخت instance از axios
|
||||
const api = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:3001/api',
|
||||
timeout: 10000,
|
||||
baseURL: BASE_URL,
|
||||
withCredentials: true, // ارسال و دریافت cookie/session
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
// Request interceptor to add JWT token
|
||||
api.interceptors.request.use(
|
||||
(config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
// -----------------------------
|
||||
// Interceptor پاسخها
|
||||
// -----------------------------
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
if (error.response?.status === 401) {
|
||||
// session منقضی شده → هدایت به login
|
||||
const setLoggedIn = useAuthStore.getState().setLoggedIn;
|
||||
setLoggedIn(false);
|
||||
window.location.href = "/";
|
||||
}
|
||||
return Promise.reject(error.response?.data || error);
|
||||
}
|
||||
);
|
||||
|
||||
// Response interceptor to handle token expiration
|
||||
api.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
// Token expired or invalid
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('user');
|
||||
window.location.href = '/login';
|
||||
}
|
||||
return Promise.reject(error);
|
||||
// -----------------------------
|
||||
// توابع API
|
||||
// -----------------------------
|
||||
|
||||
// Login
|
||||
export async function login(username, password) {
|
||||
try {
|
||||
const res = await api.post("/api/v1/Auth/SignIn", {
|
||||
// include common variants to satisfy different backends
|
||||
userName: username,
|
||||
username: username,
|
||||
email: username,
|
||||
password: password,
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// خروج از سیستم
|
||||
export async function signOut() {
|
||||
try {
|
||||
const res = await api.post("/api/v1/Auth/SignOut");
|
||||
// پاک کردن وضعیت login در Zustand
|
||||
const setLoggedIn = useAuthStore.getState().setLoggedIn;
|
||||
setLoggedIn(false);
|
||||
window.location.href = "/";
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// فراموشی رمز عبور
|
||||
export async function forgotPassword(email) {
|
||||
try {
|
||||
const res = await api.post("/api/v1/Auth/ForgotPassword", { email });
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// گرفتن دادههای محافظتشده
|
||||
export async function fetchProtectedData(endpoint) {
|
||||
try {
|
||||
const res = await api.get(endpoint);
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Mock data for development
|
||||
const mockData = {
|
||||
@@ -99,62 +151,12 @@ const mockData = {
|
||||
]
|
||||
};
|
||||
|
||||
// API functions
|
||||
export const authAPI = {
|
||||
login: async (email, password) => {
|
||||
try {
|
||||
const response = await api.post('/auth/login', { email, password });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// Return mock data for demo
|
||||
return {
|
||||
token: 'mock-jwt-token-' + Date.now(),
|
||||
user: {
|
||||
id: 1,
|
||||
email: email,
|
||||
name: 'Admin User',
|
||||
role: 'admin'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Expose mock payment API for dashboard until real endpoints are integrated
|
||||
export const paymentsAPI = {
|
||||
getStats: async () => {
|
||||
try {
|
||||
const response = await api.get('/payments/stats');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// Return mock data for demo
|
||||
return mockData.stats;
|
||||
}
|
||||
async getStats() {
|
||||
return mockData.stats;
|
||||
},
|
||||
|
||||
getPayments: async (page = 1, limit = 10) => {
|
||||
try {
|
||||
const response = await api.get(`/payments?page=${page}&limit=${limit}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// Return mock data for demo
|
||||
return {
|
||||
data: mockData.payments,
|
||||
total: mockData.payments.length,
|
||||
page,
|
||||
limit
|
||||
};
|
||||
}
|
||||
async getChartData() {
|
||||
return mockData.chartData;
|
||||
},
|
||||
|
||||
getChartData: async () => {
|
||||
try {
|
||||
const response = await api.get('/payments/chart-data');
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
// Return mock data for demo
|
||||
return mockData.chartData;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default api;
|
||||
|
||||
8
src/store/authStore.js
Normal file
8
src/store/authStore.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
export const useAuthStore = create((set) => ({
|
||||
isLoggedIn: false,
|
||||
loading: false,
|
||||
setLoggedIn: (status) => set({ isLoggedIn: status }),
|
||||
setLoading: (status) => set({ loading: status }),
|
||||
}));
|
||||
@@ -4,4 +4,20 @@ import react from '@vitejs/plugin-react'
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'https://khalijpay-core.qaserver.ir',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
configure: (proxy) => {
|
||||
proxy.on('proxyReq', (proxyReq, req) => {
|
||||
// Ensure cookies are forwarded for withCredentials
|
||||
const origin = req.headers.origin;
|
||||
if (origin) proxyReq.setHeader('origin', origin);
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user