dev-react-microstore 4.0.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -142
- package/dist/index.d.mts +129 -2
- package/dist/index.d.ts +129 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/example/README.md +54 -0
- package/example/eslint.config.js +28 -0
- package/example/index.html +13 -0
- package/example/package-lock.json +3382 -0
- package/example/package.json +29 -0
- package/example/public/index.html +98 -0
- package/example/public/vite.svg +1 -0
- package/example/src/App.css +613 -0
- package/example/src/App.tsx +34 -0
- package/example/src/assets/react.svg +1 -0
- package/example/src/components/Counter.tsx +112 -0
- package/example/src/components/CustomCompare.tsx +466 -0
- package/example/src/components/Logs.tsx +28 -0
- package/example/src/components/Search.tsx +38 -0
- package/example/src/components/ThemeToggle.tsx +25 -0
- package/example/src/components/TodoList.tsx +63 -0
- package/example/src/components/UserManager.tsx +68 -0
- package/example/src/index.css +68 -0
- package/example/src/main.tsx +10 -0
- package/example/src/store.ts +223 -0
- package/example/src/vite-env.d.ts +1 -0
- package/example/tsconfig.app.json +26 -0
- package/example/tsconfig.json +7 -0
- package/example/tsconfig.node.json +25 -0
- package/example/vite.config.ts +7 -0
- package/package.json +22 -5
- package/src/hooks.test.tsx +271 -0
- package/src/index.ts +514 -87
- package/src/store.test.ts +997 -0
- package/src/types.test.ts +161 -0
- package/vitest.config.ts +10 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
type StoreListener = () => void;
|
|
2
|
+
type MiddlewareFunction<T extends object> = (currentState: T, update: Partial<T>, next: (modifiedUpdate?: Partial<T>) => void) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Creates a new reactive store with fine-grained subscriptions and middleware support.
|
|
5
|
+
*
|
|
6
|
+
* @param initialState - The initial state object for the store
|
|
7
|
+
* @returns Store object with methods: get, set, subscribe, select, addMiddleware, onChange
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const store = createStoreState({ count: 0, name: 'John' });
|
|
12
|
+
* store.set({ count: 1 }); // Update state
|
|
13
|
+
* const { count } = useStoreSelector(store, ['count']); // Subscribe in React
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
2
16
|
declare function createStoreState<T extends object>(initialState: T): {
|
|
3
17
|
get: () => T;
|
|
4
|
-
|
|
18
|
+
getKey: <K extends keyof T>(key: K) => T[K];
|
|
19
|
+
set: (update: Partial<T>) => void;
|
|
20
|
+
setKey: <K extends keyof T>(key: K, value: T[K]) => void;
|
|
21
|
+
merge: <K extends keyof T>(key: K, value: T[K] extends object ? Partial<T[K]> : never) => T[K];
|
|
22
|
+
mergeSet: <K extends keyof T>(key: K, value: T[K] extends object ? Partial<T[K]> : never) => void;
|
|
23
|
+
reset: (keys?: (keyof T)[]) => void;
|
|
24
|
+
batch: (fn: () => void) => void;
|
|
5
25
|
subscribe: (keys: (keyof T)[], listener: StoreListener) => (() => void);
|
|
6
26
|
select: <K extends keyof T>(keys: K[]) => Pick<T, K>;
|
|
27
|
+
addMiddleware: (callbackOrTuple: MiddlewareFunction<T> | [MiddlewareFunction<T>, (keyof T)[]], affectedKeys?: (keyof T)[] | null) => () => void;
|
|
28
|
+
onChange: <K extends keyof T>(keys: K[], callback: (values: Pick<T, K>, prev: Pick<T, K>) => void) => (() => void);
|
|
29
|
+
skipSetWhen: <K extends keyof T>(key: K, fn: (prev: T[K], next: T[K]) => boolean) => void;
|
|
30
|
+
removeSkipSetWhen: (key: keyof T) => void;
|
|
31
|
+
_eqReg: Record<string, ((prev: any, next: any) => boolean) | undefined>;
|
|
7
32
|
};
|
|
8
33
|
type StoreType<T extends object> = ReturnType<typeof createStoreState<T>>;
|
|
9
34
|
type PrimitiveKey<T extends object> = keyof T;
|
|
@@ -17,6 +42,108 @@ type ExtractSelectorKeys<T extends object, S extends SelectorInput<T>> = {
|
|
|
17
42
|
[K in S[number] extends infer Item ? Item extends keyof T ? Item : keyof Item : never]: T[K];
|
|
18
43
|
};
|
|
19
44
|
type Picked<T extends object, S extends SelectorInput<T>> = ExtractSelectorKeys<T, S>;
|
|
45
|
+
/**
|
|
46
|
+
* React hook that subscribes to specific keys in a store with fine-grained re-renders.
|
|
47
|
+
* Only re-renders when the selected keys actually change (using Object.is comparison).
|
|
48
|
+
*
|
|
49
|
+
* @param store - The store created with createStoreState
|
|
50
|
+
* @param selector - Array of keys to subscribe to, or objects with custom compare functions
|
|
51
|
+
* @returns Selected state values from the store
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // Subscribe to specific keys
|
|
56
|
+
* const { count, name } = useStoreSelector(store, ['count', 'name']);
|
|
57
|
+
*
|
|
58
|
+
* // Custom comparison for complex objects
|
|
59
|
+
* const { tasks } = useStoreSelector(store, [
|
|
60
|
+
* { tasks: (prev, next) => prev.length === next.length }
|
|
61
|
+
* ]);
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
20
64
|
declare function useStoreSelector<T extends object, S extends SelectorInput<T>>(store: StoreType<T>, selector: S): Picked<T, S>;
|
|
65
|
+
/**
|
|
66
|
+
* Creates a pre-bound selector hook for a specific store instance.
|
|
67
|
+
* Infers the state type from the store — no manual generics needed.
|
|
68
|
+
*
|
|
69
|
+
* @param store - The store created with createStoreState
|
|
70
|
+
* @returns A React hook with the same API as useStoreSelector, but with the store already bound
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const useMyStore = createSelectorHook(myStore);
|
|
75
|
+
*
|
|
76
|
+
* // In a component:
|
|
77
|
+
* const { count, name } = useMyStore(['count', 'name']);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function createSelectorHook<T extends object>(store: StoreType<T>): <S extends SelectorInput<T>>(selector: S) => Picked<T, S>;
|
|
81
|
+
/**
|
|
82
|
+
* Interface for synchronous storage (localStorage, sessionStorage, etc.).
|
|
83
|
+
*/
|
|
84
|
+
interface StorageSupportingInterface {
|
|
85
|
+
getItem(key: string): string | null;
|
|
86
|
+
setItem(key: string, value: string): void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Interface for asynchronous storage (React Native AsyncStorage, etc.).
|
|
90
|
+
*/
|
|
91
|
+
interface AsyncStorageSupportingInterface {
|
|
92
|
+
getItem(key: string): Promise<string | null>;
|
|
93
|
+
setItem(key: string, value: string): Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
type AnyStorage = Storage | StorageSupportingInterface | AsyncStorageSupportingInterface;
|
|
96
|
+
/**
|
|
97
|
+
* Creates a persistence middleware that saves individual keys to storage.
|
|
98
|
+
* Only writes when the specified keys actually change, using per-key storage.
|
|
99
|
+
* Storage format: `${persistKey}:${keyName}` for each persisted key.
|
|
100
|
+
*
|
|
101
|
+
* Works with both synchronous storage (localStorage) and asynchronous storage
|
|
102
|
+
* (React Native AsyncStorage). Async writes are fire-and-forget — the state
|
|
103
|
+
* update is never blocked by a slow write.
|
|
104
|
+
*
|
|
105
|
+
* @param storage - Storage interface (localStorage, sessionStorage, AsyncStorage, etc.)
|
|
106
|
+
* @param persistKey - Base key prefix for storage (e.g., 'myapp' creates 'myapp:theme')
|
|
107
|
+
* @param keys - Array of state keys to persist
|
|
108
|
+
* @returns Tuple of [middleware function, affected keys] for use with addMiddleware
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* // Sync — localStorage
|
|
113
|
+
* store.addMiddleware(
|
|
114
|
+
* createPersistenceMiddleware(localStorage, 'myapp', ['theme', 'isLoggedIn'])
|
|
115
|
+
* );
|
|
116
|
+
*
|
|
117
|
+
* // Async — React Native AsyncStorage
|
|
118
|
+
* store.addMiddleware(
|
|
119
|
+
* createPersistenceMiddleware(AsyncStorage, 'myapp', ['theme', 'isLoggedIn'])
|
|
120
|
+
* );
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare function createPersistenceMiddleware<T extends object>(storage: AnyStorage, persistKey: string, keys: (keyof T)[]): [MiddlewareFunction<T>, (keyof T)[]];
|
|
124
|
+
/**
|
|
125
|
+
* Loads persisted state from individual key storage during store initialization.
|
|
126
|
+
* Reads keys saved by createPersistenceMiddleware and returns them as partial state.
|
|
127
|
+
*
|
|
128
|
+
* Returns synchronously for sync storage and a Promise for async storage.
|
|
129
|
+
*
|
|
130
|
+
* @param storage - Storage interface to read from (same as used in middleware)
|
|
131
|
+
* @param persistKey - Base key prefix used for storage (same as used in middleware)
|
|
132
|
+
* @param keys - Array of keys to restore (should match middleware keys)
|
|
133
|
+
* @returns Partial state object (sync) or Promise of partial state (async)
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* // Sync — localStorage
|
|
138
|
+
* const persisted = loadPersistedState(localStorage, 'myapp', ['theme']);
|
|
139
|
+
* const store = createStoreState({ theme: 'light', ...persisted });
|
|
140
|
+
*
|
|
141
|
+
* // Async — React Native AsyncStorage
|
|
142
|
+
* const persisted = await loadPersistedState(AsyncStorage, 'myapp', ['theme']);
|
|
143
|
+
* const store = createStoreState({ theme: 'light', ...persisted });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare function loadPersistedState<T extends object>(storage: Storage | StorageSupportingInterface, persistKey: string, keys: (keyof T)[]): Partial<T>;
|
|
147
|
+
declare function loadPersistedState<T extends object>(storage: AsyncStorageSupportingInterface, persistKey: string, keys: (keyof T)[]): Promise<Partial<T>>;
|
|
21
148
|
|
|
22
|
-
export { createStoreState, useStoreSelector };
|
|
149
|
+
export { type AsyncStorageSupportingInterface, type StorageSupportingInterface, createPersistenceMiddleware, createSelectorHook, createStoreState, loadPersistedState, useStoreSelector };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var F=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames,R=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,L=Object.prototype.propertyIsEnumerable;var V=(o,i,r)=>i in o?F(o,i,{enumerable:!0,configurable:!0,writable:!0,value:r}):o[i]=r,h=(o,i)=>{for(var r in i||(i={}))A.call(i,r)&&V(o,r,i[r]);if(R)for(var r of R(i))L.call(i,r)&&V(o,r,i[r]);return o};var N=(o,i)=>{for(var r in i)F(o,r,{get:i[r],enumerable:!0})},W=(o,i,r,t)=>{if(i&&typeof i=="object"||typeof i=="function")for(let l of q(i))!A.call(o,l)&&l!==r&&F(o,l,{get:()=>i[l],enumerable:!(t=$(i,l))||t.enumerable});return o};var _=o=>W(F({},"__esModule",{value:!0}),o);var Q={};N(Q,{createPersistenceMiddleware:()=>D,createSelectorHook:()=>B,createStoreState:()=>J,loadPersistedState:()=>G,useStoreSelector:()=>z});module.exports=_(Q);var I=require("react");function J(o){let i=h({},o),r=o,t=Object.create(null),l=[],f=Object.create(null),S=null,m=()=>r,k=e=>r[e],p=e=>{var n;if(S){S.add(e);return}(n=t[e])==null||n.forEach(s=>s())},u=(e,n)=>{if(Object.is(r[e],n))return;let s=f[e];s&&s(r[e],n)||(r[e]=n,p(e))},d=(e,n)=>{if(l.length===0){u(e,n);return}let s={};s[e]=n,b(s)},y=(e,n)=>h(h({},r[e]),n),K=(e,n)=>{if(l.length===0){u(e,h(h({},r[e]),n));return}let s={};s[e]=h(h({},r[e]),n),b(s)},P=e=>{if(!e)b(h({},i));else{let n={};for(let s of e)n[s]=i[s];b(n)}},x=e=>{var n;if(S){e();return}S=new Set;try{e()}finally{let s=S;S=null;let c=new Set;for(let T of s)(n=t[T])==null||n.forEach(a=>{c.has(a)||(c.add(a),a())})}},b=e=>{if(!e)return;if(l.length===0){v(e);return}let n=e,s=0,c=!1,T=a=>{if(a!==void 0&&(n=a),s>=l.length){c||v(n);return}let g=l[s++];if(!g.keys||g.keys.some(w=>w in n)){let w=!1,j=M=>{w||(w=!0,T(M))};try{g.callback(r,n,j)}catch(M){c=!0,console.error("Middleware error:",M);return}if(!w){c=!0;return}}else T()};T()},v=e=>{var s,c;let n=[];for(let T in e){let a=T;if(Object.is(r[a],e[a]))continue;let g=f[T];g&&g(r[a],e[a])||(r[a]=e[a],n.push(T))}if(n.length!==0){if(S){for(let T of n)S.add(T);return}if(n.length===1)(s=t[n[0]])==null||s.forEach(T=>T());else{let T=new Set;for(let a of n)(c=t[a])==null||c.forEach(g=>{T.has(g)||(T.add(g),g())})}}},O=(e,n=null)=>{let s,c;Array.isArray(e)?[s,c]=e:(s=e,c=n);let T={callback:s,keys:c};return l.push(T),()=>{let a=l.indexOf(T);a>-1&&l.splice(a,1)}},C=(e,n)=>{for(let s of e){let c=s;t[c]||(t[c]=new Set),t[c].add(n)}return()=>{var s;for(let c of e)(s=t[c])==null||s.delete(n)}};return{get:m,getKey:k,set:b,setKey:d,merge:y,mergeSet:K,reset:P,batch:x,subscribe:C,select:e=>{let n={},s=r;for(let c of e)n[c]=s[c];return n},addMiddleware:O,onChange:(e,n)=>{let s={};for(let a of e)s[a]=r[a];let c=!1;return C(e,()=>{c||(c=!0,queueMicrotask(()=>{c=!1;let a=!1;for(let j of e)if(!Object.is(r[j],s[j])){a=!0;break}if(!a)return;let g={};for(let j of e)g[j]=r[j];let w=s;s=g,n(g,w)}))})},skipSetWhen:(e,n)=>{f[e]=n},removeSkipSetWhen:e=>{delete f[e]},_eqReg:f}}function H(o,i){return o.length===i.length&&o.every((r,t)=>r===i[t])}function z(o,i){let t=(0,I.useRef)({lastSelected:{},prevSelector:null,normalized:null,keys:null,isFirstRun:!0,lastValues:{},subscribe:null,store:o}).current,l=t.store!==o;if(l&&(t.store=o,t.lastSelected={},t.prevSelector=null,t.normalized=null,t.keys=null,t.isFirstRun=!0,t.lastValues={},t.subscribe=null),!t.prevSelector||!H(t.prevSelector,i)){let p=[],u=[];for(let d of i)if(typeof d=="string"){let y=d;p.push({key:y}),u.push(y)}else{let y=d;for(let K in y){let P=y[K],x=K;p.push({key:x,compare:P}),u.push(x)}}t.normalized=p,t.keys=u,t.prevSelector=i,t.subscribe=null}let f=t.normalized,S=t.keys,m=()=>{let p=o.get();if(t.isFirstRun){t.isFirstRun=!1;let d={};for(let{key:y}of f){let K=p[y];t.lastValues[y]=K,d[y]=K}return t.lastSelected=d,d}let u=null;for(let d=0;d<f.length;d++){let{key:y,compare:K}=f[d],P=t.lastValues[y],x=p[y];if(!Object.is(P,x)){let b=K||o._eqReg[y];if(!b||!b(P,x)){if(!u){u={};for(let v=0;v<d;v++)u[f[v].key]=t.lastValues[f[v].key]}t.lastValues[y]=x,u[y]=x;continue}}u&&(u[y]=P)}return u?(t.lastSelected=u,u):t.lastSelected},k=(0,I.useMemo)(()=>{let p=o.get(),u={};for(let d of S)u[d]=p[d];return u},[S]);return(!t.subscribe||l)&&(t.subscribe=p=>o.subscribe(S,p)),(0,I.useSyncExternalStore)(t.subscribe,m,()=>k)}function B(o){return function(i){return z(o,i)}}function E(o){return o!=null&&typeof o.then=="function"}function D(o,i,r){return[(l,f,S)=>{let m=r.filter(k=>k in f);if(m.length===0)return S();for(let k of m)try{let p=f[k],u=`${i}:${String(k)}`,d=o.setItem(u,JSON.stringify(p));E(d)&&d.catch(y=>{console.warn(`Failed to persist key ${String(k)}:`,y)})}catch(p){console.warn(`Failed to persist key ${String(k)}:`,p)}S()},r]}function G(o,i,r){let t={},l=[];for(let f of r){let S=`${i}:${String(f)}`;try{let m=o.getItem(S);E(m)?l.push(m.then(k=>{k!==null&&(t[f]=JSON.parse(k))}).catch(k=>{console.warn(`Failed to load persisted key ${String(f)}:`,k)})):m!==null&&(t[f]=JSON.parse(m))}catch(m){console.warn(`Failed to load persisted key ${String(f)}:`,m)}}return l.length>0?Promise.all(l).then(()=>t):t}0&&(module.exports={createPersistenceMiddleware,createSelectorHook,createStoreState,loadPersistedState,useStoreSelector});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useMemo as
|
|
1
|
+
var A=Object.defineProperty;var M=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,E=Object.prototype.propertyIsEnumerable;var C=(s,i,o)=>i in s?A(s,i,{enumerable:!0,configurable:!0,writable:!0,value:o}):s[i]=o,h=(s,i)=>{for(var o in i||(i={}))z.call(i,o)&&C(s,o,i[o]);if(M)for(var o of M(i))E.call(i,o)&&C(s,o,i[o]);return s};import{useMemo as O,useRef as $,useSyncExternalStore as q}from"react";function G(s){let i=h({},s),o=s,t=Object.create(null),S=[],u=Object.create(null),T=null,m=()=>o,k=e=>o[e],p=e=>{var n;if(T){T.add(e);return}(n=t[e])==null||n.forEach(r=>r())},l=(e,n)=>{if(Object.is(o[e],n))return;let r=u[e];r&&r(o[e],n)||(o[e]=n,p(e))},f=(e,n)=>{if(S.length===0){l(e,n);return}let r={};r[e]=n,b(r)},d=(e,n)=>h(h({},o[e]),n),K=(e,n)=>{if(S.length===0){l(e,h(h({},o[e]),n));return}let r={};r[e]=h(h({},o[e]),n),b(r)},P=e=>{if(!e)b(h({},i));else{let n={};for(let r of e)n[r]=i[r];b(n)}},x=e=>{var n;if(T){e();return}T=new Set;try{e()}finally{let r=T;T=null;let c=new Set;for(let y of r)(n=t[y])==null||n.forEach(a=>{c.has(a)||(c.add(a),a())})}},b=e=>{if(!e)return;if(S.length===0){v(e);return}let n=e,r=0,c=!1,y=a=>{if(a!==void 0&&(n=a),r>=S.length){c||v(n);return}let g=S[r++];if(!g.keys||g.keys.some(w=>w in n)){let w=!1,j=I=>{w||(w=!0,y(I))};try{g.callback(o,n,j)}catch(I){c=!0,console.error("Middleware error:",I);return}if(!w){c=!0;return}}else y()};y()},v=e=>{var r,c;let n=[];for(let y in e){let a=y;if(Object.is(o[a],e[a]))continue;let g=u[y];g&&g(o[a],e[a])||(o[a]=e[a],n.push(y))}if(n.length!==0){if(T){for(let y of n)T.add(y);return}if(n.length===1)(r=t[n[0]])==null||r.forEach(y=>y());else{let y=new Set;for(let a of n)(c=t[a])==null||c.forEach(g=>{y.has(g)||(y.add(g),g())})}}},V=(e,n=null)=>{let r,c;Array.isArray(e)?[r,c]=e:(r=e,c=n);let y={callback:r,keys:c};return S.push(y),()=>{let a=S.indexOf(y);a>-1&&S.splice(a,1)}},F=(e,n)=>{for(let r of e){let c=r;t[c]||(t[c]=new Set),t[c].add(n)}return()=>{var r;for(let c of e)(r=t[c])==null||r.delete(n)}};return{get:m,getKey:k,set:b,setKey:f,merge:d,mergeSet:K,reset:P,batch:x,subscribe:F,select:e=>{let n={},r=o;for(let c of e)n[c]=r[c];return n},addMiddleware:V,onChange:(e,n)=>{let r={};for(let a of e)r[a]=o[a];let c=!1;return F(e,()=>{c||(c=!0,queueMicrotask(()=>{c=!1;let a=!1;for(let j of e)if(!Object.is(o[j],r[j])){a=!0;break}if(!a)return;let g={};for(let j of e)g[j]=o[j];let w=r;r=g,n(g,w)}))})},skipSetWhen:(e,n)=>{u[e]=n},removeSkipSetWhen:e=>{delete u[e]},_eqReg:u}}function L(s,i){return s.length===i.length&&s.every((o,t)=>o===i[t])}function N(s,i){let t=$({lastSelected:{},prevSelector:null,normalized:null,keys:null,isFirstRun:!0,lastValues:{},subscribe:null,store:s}).current,S=t.store!==s;if(S&&(t.store=s,t.lastSelected={},t.prevSelector=null,t.normalized=null,t.keys=null,t.isFirstRun=!0,t.lastValues={},t.subscribe=null),!t.prevSelector||!L(t.prevSelector,i)){let p=[],l=[];for(let f of i)if(typeof f=="string"){let d=f;p.push({key:d}),l.push(d)}else{let d=f;for(let K in d){let P=d[K],x=K;p.push({key:x,compare:P}),l.push(x)}}t.normalized=p,t.keys=l,t.prevSelector=i,t.subscribe=null}let u=t.normalized,T=t.keys,m=()=>{let p=s.get();if(t.isFirstRun){t.isFirstRun=!1;let f={};for(let{key:d}of u){let K=p[d];t.lastValues[d]=K,f[d]=K}return t.lastSelected=f,f}let l=null;for(let f=0;f<u.length;f++){let{key:d,compare:K}=u[f],P=t.lastValues[d],x=p[d];if(!Object.is(P,x)){let b=K||s._eqReg[d];if(!b||!b(P,x)){if(!l){l={};for(let v=0;v<f;v++)l[u[v].key]=t.lastValues[u[v].key]}t.lastValues[d]=x,l[d]=x;continue}}l&&(l[d]=P)}return l?(t.lastSelected=l,l):t.lastSelected},k=O(()=>{let p=s.get(),l={};for(let f of T)l[f]=p[f];return l},[T]);return(!t.subscribe||S)&&(t.subscribe=p=>s.subscribe(T,p)),q(t.subscribe,m,()=>k)}function Q(s){return function(i){return N(s,i)}}function R(s){return s!=null&&typeof s.then=="function"}function X(s,i,o){return[(S,u,T)=>{let m=o.filter(k=>k in u);if(m.length===0)return T();for(let k of m)try{let p=u[k],l=`${i}:${String(k)}`,f=s.setItem(l,JSON.stringify(p));R(f)&&f.catch(d=>{console.warn(`Failed to persist key ${String(k)}:`,d)})}catch(p){console.warn(`Failed to persist key ${String(k)}:`,p)}T()},o]}function Y(s,i,o){let t={},S=[];for(let u of o){let T=`${i}:${String(u)}`;try{let m=s.getItem(T);R(m)?S.push(m.then(k=>{k!==null&&(t[u]=JSON.parse(k))}).catch(k=>{console.warn(`Failed to load persisted key ${String(u)}:`,k)})):m!==null&&(t[u]=JSON.parse(m))}catch(m){console.warn(`Failed to load persisted key ${String(u)}:`,m)}}return S.length>0?Promise.all(S).then(()=>t):t}export{X as createPersistenceMiddleware,Q as createSelectorHook,G as createStoreState,Y as loadPersistedState,N as useStoreSelector};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# React + TypeScript + Vite
|
|
2
|
+
|
|
3
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
+
|
|
5
|
+
Currently, two official plugins are available:
|
|
6
|
+
|
|
7
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
|
8
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
+
|
|
10
|
+
## Expanding the ESLint configuration
|
|
11
|
+
|
|
12
|
+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
export default tseslint.config({
|
|
16
|
+
extends: [
|
|
17
|
+
// Remove ...tseslint.configs.recommended and replace with this
|
|
18
|
+
...tseslint.configs.recommendedTypeChecked,
|
|
19
|
+
// Alternatively, use this for stricter rules
|
|
20
|
+
...tseslint.configs.strictTypeChecked,
|
|
21
|
+
// Optionally, add this for stylistic rules
|
|
22
|
+
...tseslint.configs.stylisticTypeChecked,
|
|
23
|
+
],
|
|
24
|
+
languageOptions: {
|
|
25
|
+
// other options...
|
|
26
|
+
parserOptions: {
|
|
27
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
28
|
+
tsconfigRootDir: import.meta.dirname,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// eslint.config.js
|
|
38
|
+
import reactX from 'eslint-plugin-react-x'
|
|
39
|
+
import reactDom from 'eslint-plugin-react-dom'
|
|
40
|
+
|
|
41
|
+
export default tseslint.config({
|
|
42
|
+
plugins: {
|
|
43
|
+
// Add the react-x and react-dom plugins
|
|
44
|
+
'react-x': reactX,
|
|
45
|
+
'react-dom': reactDom,
|
|
46
|
+
},
|
|
47
|
+
rules: {
|
|
48
|
+
// other rules...
|
|
49
|
+
// Enable its recommended typescript rules
|
|
50
|
+
...reactX.configs['recommended-typescript'].rules,
|
|
51
|
+
...reactDom.configs.recommended.rules,
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ['dist'] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 2020,
|
|
14
|
+
globals: globals.browser,
|
|
15
|
+
},
|
|
16
|
+
plugins: {
|
|
17
|
+
'react-hooks': reactHooks,
|
|
18
|
+
'react-refresh': reactRefresh,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
...reactHooks.configs.recommended.rules,
|
|
22
|
+
'react-refresh/only-export-components': [
|
|
23
|
+
'warn',
|
|
24
|
+
{ allowConstantExport: true },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite + React + TS</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|