use-state-redux 0.0.0-stage → 1.0.1

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 CHANGED
@@ -1,3 +1,153 @@
1
- # Temporary Holding Version
1
+ # usestate-redux
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A small React global state hook built on Redux Toolkit and Redux Persist. Use a
4
+ named state value from multiple components with an API similar to React's
5
+ `useState`:
6
+
7
+ ```tsx
8
+ const [state, setState] = usestateRedux("name", initialState);
9
+ ```
10
+
11
+ The hook uses an internal Redux store, so you do not need to add a Redux
12
+ `<Provider>` to your app.
13
+
14
+ ## Installation
15
+
16
+ Install this package and its peer dependencies:
17
+
18
+ ```sh
19
+ npm install use-state-redux @reduxjs/toolkit react react-redux redux-persist
20
+ ```
21
+
22
+
23
+ ## Basic usage
24
+
25
+ ```tsx
26
+ import { usestateRedux } from "usestate-redux";
27
+
28
+ function Counter() {
29
+ const [count, setCount] = usestateRedux("count", 0);
30
+
31
+ return (
32
+ <button onClick={() => setCount((current) => current + 1)}>
33
+ Count: {count}
34
+ </button>
35
+ );
36
+ }
37
+ ```
38
+
39
+ Every component that calls the hook with the same name reads and updates the
40
+ same value:
41
+
42
+ ```tsx
43
+ function CountLabel() {
44
+ const [count] = usestateRedux("count", 0);
45
+ return <p>{count}</p>;
46
+ }
47
+
48
+ function ResetCountButton() {
49
+ const [, setCount] = usestateRedux("count", 0);
50
+ return <button onClick={() => setCount(0)}>Reset count</button>;
51
+ }
52
+ ```
53
+
54
+ The first call for a name supplies its initial value. Later calls with that
55
+ name share the value and ignore their own `initialState` argument. Choose
56
+ distinct names for unrelated state.
57
+
58
+ The setter accepts either a value or an updater function, like React's
59
+ `useState` setter:
60
+
61
+ ```tsx
62
+ setCount(5);
63
+ setCount((current) => current + 1);
64
+ ```
65
+
66
+ ## Persisting state
67
+
68
+ State is not persisted by default. Set `persist: true` in the third argument to
69
+ save a named value with Redux Persist:
70
+
71
+ ```tsx
72
+ const [theme, setTheme] = usestateRedux("theme", "light", {
73
+ persist: true,
74
+ });
75
+ ```
76
+
77
+ The package uses Redux Persist's web storage adapter, which stores values in
78
+ `localStorage`. Only names that opt into persistence are included in persisted
79
+ state. Persisted values should be JSON-serializable.
80
+
81
+ Redux Persist rehydrates the store asynchronously. A hook can initially return
82
+ its `initialState`, then update to its restored value when rehydration finishes.
83
+
84
+ If multiple components use the same name, opting in from any one of them
85
+ enables persistence for that name for the lifetime of the app session. Keep the
86
+ `persist` setting consistent between components that share a name.
87
+
88
+ ## API
89
+
90
+ ### `usestateRedux(name, initialState, options?)`
91
+
92
+ Returns a tuple of the current value and setter:
93
+
94
+ ```ts
95
+ const [state, setState] = usestateRedux<T>(name, initialState, options?);
96
+ ```
97
+
98
+ | Argument | Type | Description |
99
+ | --- | --- | --- |
100
+ | `name` | `string` | Global name used to share a value between components. |
101
+ | `initialState` | `T` | Value used before the state is set or restored. The first call for a name wins. |
102
+ | `options.persist` | `boolean` | Save this named value across page refreshes. Defaults to `false`. |
103
+
104
+ ### `useRedux(name, initialState, options?)`
105
+
106
+ The `useRedux` export is an alias for `usestateRedux`.
107
+
108
+ ### `setGlobalStateValue(name, value)`
109
+
110
+ Set a named value outside a component. The matching hook updates when the Redux
111
+ store changes.
112
+
113
+ ```ts
114
+ import { setGlobalStateValue } from "usestate-redux";
115
+
116
+ setGlobalStateValue("count", 10);
117
+ ```
118
+
119
+ ### `resetGlobalState(name)`
120
+
121
+ Restore a registered name to the initial value from its first hook call.
122
+
123
+ ```ts
124
+ import { resetGlobalState } from "usestate-redux";
125
+
126
+ resetGlobalState("count");
127
+ ```
128
+
129
+ ### `resetAllGlobalState()`
130
+
131
+ Reset all named values to their initial values.
132
+
133
+ ### Advanced Redux Persist access
134
+
135
+ The package also exports `reduxStore` and `reduxPersistor` for integrations that
136
+ need direct access to the internal Redux store or persistor. For example, the
137
+ persistor can be used to flush pending writes or purge persisted data:
138
+
139
+ ```ts
140
+ import { reduxPersistor } from "usestate-redux";
141
+
142
+ await reduxPersistor.flush();
143
+ // To remove the persisted store instead:
144
+ // await reduxPersistor.purge();
145
+ ```
146
+
147
+ ## Exports
148
+
149
+ - `usestateRedux` and `useRedux`
150
+ - `setGlobalStateValue`
151
+ - `resetGlobalState` and `resetAllGlobalState`
152
+ - `reduxStore` and `reduxPersistor`
153
+ - `UseReduxOptions` and `GlobalStateSetter` TypeScript types
@@ -0,0 +1 @@
1
+ export * from './src/index'
package/dist/index.js ADDED
@@ -0,0 +1,147 @@
1
+ import { useCallback as f, useSyncExternalStore as R } from "react";
2
+ import { createSlice as E, configureStore as G } from "@reduxjs/toolkit";
3
+ import { persistReducer as w, FLUSH as V, REHYDRATE as P, PAUSE as x, PERSIST as N, PURGE as D, REGISTER as M, persistStore as k } from "redux-persist";
4
+ var p = {}, g = {};
5
+ g.__esModule = !0;
6
+ g.default = $;
7
+ function i(e) {
8
+ return typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? i = function(r) {
9
+ return typeof r;
10
+ } : i = function(r) {
11
+ return r && typeof Symbol == "function" && r.constructor === Symbol && r !== Symbol.prototype ? "symbol" : typeof r;
12
+ }, i(e);
13
+ }
14
+ function d() {
15
+ }
16
+ var A = {
17
+ getItem: d,
18
+ setItem: d,
19
+ removeItem: d
20
+ };
21
+ function O(e) {
22
+ if ((typeof self > "u" ? "undefined" : i(self)) !== "object" || !(e in self))
23
+ return !1;
24
+ try {
25
+ var t = self[e], r = "redux-persist ".concat(e, " test");
26
+ t.setItem(r, "test"), t.getItem(r), t.removeItem(r);
27
+ } catch {
28
+ return process.env.NODE_ENV !== "production" && console.warn("redux-persist ".concat(e, " test failed, persistence will be disabled.")), !1;
29
+ }
30
+ return !0;
31
+ }
32
+ function $(e) {
33
+ var t = "".concat(e, "Storage");
34
+ return O(t) ? self[t] : (process.env.NODE_ENV !== "production" && console.error("redux-persist failed to create sync storage. falling back to noop storage."), A);
35
+ }
36
+ p.__esModule = !0;
37
+ p.default = q;
38
+ var U = W(g);
39
+ function W(e) {
40
+ return e && e.__esModule ? e : { default: e };
41
+ }
42
+ function q(e) {
43
+ var t = (0, U.default)(e);
44
+ return {
45
+ getItem: function(o) {
46
+ return new Promise(function(a, l) {
47
+ a(t.getItem(o));
48
+ });
49
+ },
50
+ setItem: function(o, a) {
51
+ return new Promise(function(l, b) {
52
+ l(t.setItem(o, a));
53
+ });
54
+ },
55
+ removeItem: function(o) {
56
+ return new Promise(function(a, l) {
57
+ a(t.removeItem(o));
58
+ });
59
+ }
60
+ };
61
+ }
62
+ var m = void 0, C = H(p);
63
+ function H(e) {
64
+ return e && e.__esModule ? e : { default: e };
65
+ }
66
+ var T = (0, C.default)("local");
67
+ m = T;
68
+ const y = E({
69
+ name: "globalState",
70
+ initialState: {},
71
+ reducers: {
72
+ setGlobalStateValue(e, t) {
73
+ e[t.payload.name] = t.payload.value;
74
+ },
75
+ removeGlobalStateValue(e, t) {
76
+ delete e[t.payload];
77
+ },
78
+ resetGlobalStateValues() {
79
+ return {};
80
+ }
81
+ }
82
+ }), {
83
+ setGlobalStateValue: v,
84
+ removeGlobalStateValue: z,
85
+ resetGlobalStateValues: F
86
+ } = y.actions, L = y.reducer, h = [], S = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), Y = w(
87
+ {
88
+ key: "useredux",
89
+ storage: m,
90
+ // The array is filled as hooks opt into persistence. Other named values
91
+ // remain in Redux but are excluded from the persisted copy.
92
+ whitelist: h
93
+ },
94
+ L
95
+ ), s = G({
96
+ reducer: Y,
97
+ middleware: (e) => e({
98
+ serializableCheck: {
99
+ ignoredActions: [V, P, x, N, D, M],
100
+ ignoredPaths: ["_persist"]
101
+ }
102
+ })
103
+ }), u = /* @__PURE__ */ new Map(), Z = k(s);
104
+ function B(e, t, r) {
105
+ u.has(e) || u.set(e, t), r.persist && !S.has(e) && (S.add(e), h.push(e));
106
+ }
107
+ function K(e, t, r = {}) {
108
+ B(e, t, r);
109
+ const o = f(() => {
110
+ const n = s.getState();
111
+ return Object.prototype.hasOwnProperty.call(n, e) && (S.has(e) || c.has(e)) ? n[e] : u.get(e);
112
+ }, [e]), a = f(
113
+ () => u.get(e),
114
+ [e]
115
+ ), l = R(
116
+ s.subscribe,
117
+ o,
118
+ a
119
+ ), b = f(
120
+ (n) => {
121
+ const _ = o(), I = typeof n == "function" ? n(_) : n;
122
+ c.add(e), s.dispatch(v({ name: e, value: I }));
123
+ },
124
+ [o, e]
125
+ );
126
+ return [l, b];
127
+ }
128
+ function j(e, t) {
129
+ c.add(e), s.dispatch(v({ name: e, value: t }));
130
+ }
131
+ function ee(e) {
132
+ u.has(e) ? (c.add(e), s.dispatch(
133
+ v({ name: e, value: u.get(e) })
134
+ )) : s.dispatch(z(e));
135
+ }
136
+ function te() {
137
+ c.clear(), s.dispatch(F());
138
+ }
139
+ export {
140
+ Z as reduxPersistor,
141
+ s as reduxStore,
142
+ te as resetAllGlobalState,
143
+ ee as resetGlobalState,
144
+ j as setGlobalStateValue,
145
+ K as useRedux,
146
+ K as usestateRedux
147
+ };
@@ -0,0 +1 @@
1
+ (function(o,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("react"),require("@reduxjs/toolkit"),require("redux-persist")):typeof define=="function"&&define.amd?define(["exports","react","@reduxjs/toolkit","redux-persist"],n):(o=typeof globalThis<"u"?globalThis:o||self,n(o.UsestateRedux={},o.React,o.ReduxToolkit,o.ReduxPersist))})(this,function(o,n,h,u){"use strict";var p={},g={};g.__esModule=!0,g.default=V;function S(e){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?S=function(r){return typeof r}:S=function(r){return r&&typeof Symbol=="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r},S(e)}function b(){}var E={getItem:b,setItem:b,removeItem:b};function w(e){if((typeof self>"u"?"undefined":S(self))!=="object"||!(e in self))return!1;try{var t=self[e],r="redux-persist ".concat(e," test");t.setItem(r,"test"),t.getItem(r),t.removeItem(r)}catch{return process.env.NODE_ENV!=="production"&&console.warn("redux-persist ".concat(e," test failed, persistence will be disabled.")),!1}return!0}function V(e){var t="".concat(e,"Storage");return w(t)?self[t]:(process.env.NODE_ENV!=="production"&&console.error("redux-persist failed to create sync storage. falling back to noop storage."),E)}p.__esModule=!0,p.default=N;var k=M(g);function M(e){return e&&e.__esModule?e:{default:e}}function N(e){var t=(0,k.default)(e);return{getItem:function(s){return new Promise(function(l,d){l(t.getItem(s))})},setItem:function(s,l){return new Promise(function(d,G){d(t.setItem(s,l))})},removeItem:function(s){return new Promise(function(l,d){l(t.removeItem(s))})}}}var m=void 0,T=q(p);function q(e){return e&&e.__esModule?e:{default:e}}var x=(0,T.default)("local");m=x;const _=h.createSlice({name:"globalState",initialState:{},reducers:{setGlobalStateValue(e,t){e[t.payload.name]=t.payload.value},removeGlobalStateValue(e,t){delete e[t.payload]},resetGlobalStateValues(){return{}}}}),{setGlobalStateValue:y,removeGlobalStateValue:A,resetGlobalStateValues:D}=_.actions,O=_.reducer,R=[],v=new Set,f=new Set,P=u.persistReducer({key:"useredux",storage:m,whitelist:R},O),a=h.configureStore({reducer:P,middleware:e=>e({serializableCheck:{ignoredActions:[u.FLUSH,u.REHYDRATE,u.PAUSE,u.PERSIST,u.PURGE,u.REGISTER],ignoredPaths:["_persist"]}})}),i=new Map,C=u.persistStore(a);function U(e,t,r){i.has(e)||i.set(e,t),r.persist&&!v.has(e)&&(v.add(e),R.push(e))}function I(e,t,r={}){U(e,t,r);const s=n.useCallback(()=>{const c=a.getState();return Object.prototype.hasOwnProperty.call(c,e)&&(v.has(e)||f.has(e))?c[e]:i.get(e)},[e]),l=n.useCallback(()=>i.get(e),[e]),d=n.useSyncExternalStore(a.subscribe,s,l),G=n.useCallback(c=>{const z=s(),F=typeof c=="function"?c(z):c;f.add(e),a.dispatch(y({name:e,value:F}))},[s,e]);return[d,G]}function $(e,t){f.add(e),a.dispatch(y({name:e,value:t}))}function W(e){i.has(e)?(f.add(e),a.dispatch(y({name:e,value:i.get(e)}))):a.dispatch(A(e))}function H(){f.clear(),a.dispatch(D())}o.reduxPersistor=C,o.reduxStore=a,o.resetAllGlobalState=H,o.resetGlobalState=W,o.setGlobalStateValue=$,o.useRedux=I,o.usestateRedux=I,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,3 @@
1
+ export { resetAllGlobalState, resetGlobalState, reduxStore, reduxPersistor, setGlobalStateValue, usestateRedux, useRedux, } from './usestateRedux.js';
2
+ export type { GlobalStateSetter, UseReduxOptions } from './usestateRedux.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type GlobalState = Record<string, unknown>;
2
+ type SetValuePayload = {
3
+ name: string;
4
+ value: unknown;
5
+ };
6
+ export declare const setGlobalStateValue: import('@reduxjs/toolkit').ActionCreatorWithPayload<SetValuePayload, "globalState/setGlobalStateValue">, removeGlobalStateValue: import('@reduxjs/toolkit').ActionCreatorWithPayload<string, "globalState/removeGlobalStateValue">, resetGlobalStateValues: import('@reduxjs/toolkit').ActionCreatorWithoutPayload<"globalState/resetGlobalStateValues">;
7
+ declare const _default: import('redux').Reducer<GlobalState>;
8
+ export default _default;
9
+ //# sourceMappingURL=slice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/slice.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAkBF,eAAO,MACL,mBAAmB,2GACnB,sBAAsB,qGACtB,sBAAsB,8FACI,CAAC;;AAE7B,wBAAwC"}
@@ -0,0 +1,28 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ import { GlobalState } from './slice.js';
3
+
4
+ declare const store: import('@reduxjs/toolkit').EnhancedStore<GlobalState & import('redux-persist/es/persistReducer').PersistPartial, import('redux').UnknownAction, import('@reduxjs/toolkit').Tuple<[import('redux').StoreEnhancer<{
5
+ dispatch: import('redux-thunk').ThunkDispatch<GlobalState & import('redux-persist/es/persistReducer').PersistPartial, undefined, import('redux').UnknownAction>;
6
+ }>, import('redux').StoreEnhancer]>>;
7
+ export declare const reduxPersistor: import('redux-persist').Persistor;
8
+ export interface UseReduxOptions {
9
+ /** Save this named value between page loads. Defaults to false. */
10
+ persist?: boolean;
11
+ }
12
+ export type GlobalStateSetter<T> = Dispatch<SetStateAction<T>>;
13
+ /**
14
+ * Read and update a globally shared state value.
15
+ * The first call for a name supplies its initial value; later calls with that
16
+ * name share the same value and ignore their own initial value. Persistence is
17
+ * enabled for a name when any caller opts in; it stays enabled for that name.
18
+ */
19
+ export declare function usestateRedux<T>(name: string, initialState: T, options?: UseReduxOptions): [T, GlobalStateSetter<T>];
20
+ /** Set a named global value outside a React component. */
21
+ export declare function setGlobalStateValue<T>(name: string, value: T): void;
22
+ /** Restore a named value to the initial value supplied to its first hook call. */
23
+ export declare function resetGlobalState(name: string): void;
24
+ /** Reset every named value to its initial value. */
25
+ export declare function resetAllGlobalState(): void;
26
+ export { store as reduxStore };
27
+ export { usestateRedux as useRedux };
28
+ //# sourceMappingURL=usestateRedux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usestateRedux.d.ts","sourceRoot":"","sources":["../../src/usestateRedux.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAatD,OAA2B,EAIzB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAiBpB,QAAA,MAAM,KAAK;;oCAST,CAAC;AAGH,eAAO,MAAM,cAAc,mCAAsB,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiBD,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,CAAC,EACf,OAAO,GAAE,eAAoB,GAC5B,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAuC3B;AAED,0DAA0D;AAC1D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAGnE;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CASnD;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,CAAC;AAG/B,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const _default: import('vite').UserConfig;
2
+ export default _default;
3
+ //# sourceMappingURL=vite.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.config.d.ts","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":";AAOA,wBA2BG"}
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "use-state-redux",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "A zero-boilerplate Redux wrapper providing a useState-like global hook experience",
5
+ "type": "module",
6
+ "main": "./dist/index.umd.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.umd.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "vite build",
21
+ "dev": "vite build --watch"
22
+ },
23
+ "peerDependencies": {
24
+ "@reduxjs/toolkit": "^1.9.0 || ^2.0.0",
25
+ "react": "^18.0.0 || ^19.0.0",
26
+ "react-redux": "^8.0.0 || ^9.0.0",
27
+ "redux-persist": "^6.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^26.6.6",
31
+ "@types/react": "^18.0.0",
32
+ "typescript": "^5.0.0",
33
+ "vite": "^5.0.0",
34
+ "vite-plugin-dts": "^3.0.0"
35
+ },
36
+ "dependencies": {
37
+ "@types/redux-persist": "^4.0.0"
38
+ }
39
+ }