@t8/react-store 1.2.4 → 1.2.6
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/dist/index.cjs +58 -0
- package/dist/index.d.ts +7 -10
- package/dist/index.mjs +54 -0
- package/package.json +8 -9
- package/dist/index.js +0 -152
- package/tsconfig.build.json +0 -4
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
let __t8_store = require("@t8/store");
|
|
2
|
+
let react = require("react");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the state value of `store` passed as the parameter and
|
|
6
|
+
* a function to update the store state value.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```js
|
|
10
|
+
* let [value, setValue] = useStore(store);
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* The optional second parameter `shouldUpdate` controls whether
|
|
14
|
+
* the component using this hook should be updated in response to
|
|
15
|
+
* the store updates, which is set to `true` by default.
|
|
16
|
+
*
|
|
17
|
+
* `shouldUpdate` can be set to `false` to prevent subscription
|
|
18
|
+
* to the store updates. Use case: if the component only requires
|
|
19
|
+
* the store state setter but not the store state value, the
|
|
20
|
+
* component may not need to respond to the store updates at all:
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```js
|
|
24
|
+
* let [, setValue] = useStore(store, false);
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* `shouldUpdate` can also be a function `(nextState, prevState) => boolean`
|
|
28
|
+
* to make the component respond only to specific store state changes,
|
|
29
|
+
* when this function returns `true`.
|
|
30
|
+
*/
|
|
31
|
+
function useStore(store, shouldUpdate = true) {
|
|
32
|
+
if (!(0, __t8_store.isStore)(store)) throw new Error("'store' is not an instance of Store");
|
|
33
|
+
let [, setRevision] = (0, react.useState)(-1);
|
|
34
|
+
let state = store.getState();
|
|
35
|
+
let setState = (0, react.useMemo)(() => store.setState.bind(store), [store]);
|
|
36
|
+
let initialStoreRevision = (0, react.useRef)(store.revision);
|
|
37
|
+
(0, react.useEffect)(() => {
|
|
38
|
+
if ((0, __t8_store.isPersistentStore)(store)) store.syncOnce();
|
|
39
|
+
if (!shouldUpdate) return;
|
|
40
|
+
let unsubscribe = store.onUpdate((nextState, prevState) => {
|
|
41
|
+
if (typeof shouldUpdate !== "function" || shouldUpdate(nextState, prevState)) setRevision(Math.random());
|
|
42
|
+
});
|
|
43
|
+
if (store.revision !== initialStoreRevision.current) setRevision(Math.random());
|
|
44
|
+
return () => {
|
|
45
|
+
unsubscribe();
|
|
46
|
+
initialStoreRevision.current = store.revision;
|
|
47
|
+
};
|
|
48
|
+
}, [store, shouldUpdate]);
|
|
49
|
+
return [state, setState];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.useStore = useStore;
|
|
53
|
+
Object.keys(__t8_store).forEach(function (k) {
|
|
54
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () { return __t8_store[k]; }
|
|
57
|
+
});
|
|
58
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Store } from "@t8/store";
|
|
2
|
+
export * from "@t8/store";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type SetStoreState<T> = Store<T>["setState"];
|
|
5
|
+
type ShouldUpdateCallback<T> = (nextState: T, prevState: T) => boolean;
|
|
6
|
+
type ShouldUpdate<T> = boolean | ShouldUpdateCallback<T>;
|
|
6
7
|
/**
|
|
7
8
|
* Returns the state value of `store` passed as the parameter and
|
|
8
9
|
* a function to update the store state value.
|
|
@@ -30,10 +31,6 @@ export type ShouldUpdate<T> = boolean | ShouldUpdateCallback<T>;
|
|
|
30
31
|
* to make the component respond only to specific store state changes,
|
|
31
32
|
* when this function returns `true`.
|
|
32
33
|
*/
|
|
33
|
-
|
|
34
|
-
T,
|
|
35
|
-
SetStoreState<T>
|
|
36
|
-
];
|
|
37
|
-
export * from "@t8/store";
|
|
34
|
+
declare function useStore<T>(store: Store<T>, shouldUpdate?: ShouldUpdate<T>): [T, SetStoreState<T>];
|
|
38
35
|
|
|
39
|
-
export {};
|
|
36
|
+
export { SetStoreState, ShouldUpdate, ShouldUpdateCallback, useStore };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { isPersistentStore, isStore } from "@t8/store";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
export * from "@t8/store"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the state value of `store` passed as the parameter and
|
|
8
|
+
* a function to update the store state value.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```js
|
|
12
|
+
* let [value, setValue] = useStore(store);
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The optional second parameter `shouldUpdate` controls whether
|
|
16
|
+
* the component using this hook should be updated in response to
|
|
17
|
+
* the store updates, which is set to `true` by default.
|
|
18
|
+
*
|
|
19
|
+
* `shouldUpdate` can be set to `false` to prevent subscription
|
|
20
|
+
* to the store updates. Use case: if the component only requires
|
|
21
|
+
* the store state setter but not the store state value, the
|
|
22
|
+
* component may not need to respond to the store updates at all:
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```js
|
|
26
|
+
* let [, setValue] = useStore(store, false);
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* `shouldUpdate` can also be a function `(nextState, prevState) => boolean`
|
|
30
|
+
* to make the component respond only to specific store state changes,
|
|
31
|
+
* when this function returns `true`.
|
|
32
|
+
*/
|
|
33
|
+
function useStore(store, shouldUpdate = true) {
|
|
34
|
+
if (!isStore(store)) throw new Error("'store' is not an instance of Store");
|
|
35
|
+
let [, setRevision] = useState(-1);
|
|
36
|
+
let state = store.getState();
|
|
37
|
+
let setState = useMemo(() => store.setState.bind(store), [store]);
|
|
38
|
+
let initialStoreRevision = useRef(store.revision);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (isPersistentStore(store)) store.syncOnce();
|
|
41
|
+
if (!shouldUpdate) return;
|
|
42
|
+
let unsubscribe = store.onUpdate((nextState, prevState) => {
|
|
43
|
+
if (typeof shouldUpdate !== "function" || shouldUpdate(nextState, prevState)) setRevision(Math.random());
|
|
44
|
+
});
|
|
45
|
+
if (store.revision !== initialStoreRevision.current) setRevision(Math.random());
|
|
46
|
+
return () => {
|
|
47
|
+
unsubscribe();
|
|
48
|
+
initialStoreRevision.current = store.revision;
|
|
49
|
+
};
|
|
50
|
+
}, [store, shouldUpdate]);
|
|
51
|
+
return [state, setState];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { useStore };
|
package/package.json
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t8/react-store",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "Small React app state management lib aligned with React's state pattern, condensed to the essentials",
|
|
5
|
-
"main": "dist/index.
|
|
6
|
-
"
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
7
8
|
"type": "module",
|
|
8
9
|
"scripts": {
|
|
9
|
-
"clean": "node -e \"require('node:fs').rmSync('dist', { force: true, recursive: true });\"",
|
|
10
|
-
"compile": "npx esbuild index.ts --bundle --outdir=dist --platform=neutral --external:react",
|
|
11
10
|
"demo": "npx @t8/serve 3000 * tests/counter -b src/index.tsx",
|
|
12
|
-
"preversion": "npx npm-run-all
|
|
13
|
-
"shape": "npx codeshape
|
|
11
|
+
"preversion": "npx npm-run-all shape test",
|
|
12
|
+
"shape": "npx codeshape",
|
|
14
13
|
"test": "npx playwright test --project=chromium",
|
|
15
14
|
"tic-tac-toe": "npx @t8/serve 3000 * tests/tic-tac-toe -b src/index.tsx"
|
|
16
15
|
},
|
|
@@ -33,7 +32,7 @@
|
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"@playwright/test": "^1.56.0",
|
|
36
|
-
"@t8/serve": "^0.1.
|
|
35
|
+
"@t8/serve": "^0.1.38",
|
|
37
36
|
"@types/node": "^24.5.2",
|
|
38
37
|
"@types/react": "^19.2.7",
|
|
39
38
|
"@types/react-dom": "^19.2.3",
|
|
@@ -41,6 +40,6 @@
|
|
|
41
40
|
"react-dom": "^19.2.1"
|
|
42
41
|
},
|
|
43
42
|
"dependencies": {
|
|
44
|
-
"@t8/store": "^1.3.
|
|
43
|
+
"@t8/store": "^1.3.8"
|
|
45
44
|
}
|
|
46
45
|
}
|
package/dist/index.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
// node_modules/@t8/store/src/isStore.ts
|
|
2
|
-
function isStore(x) {
|
|
3
|
-
return x !== null && typeof x === "object" && "onUpdate" in x && typeof x.onUpdate === "function" && "getState" in x && typeof x.getState === "function" && "setState" in x && typeof x.setState === "function";
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
// node_modules/@t8/store/src/isPersistentStore.ts
|
|
7
|
-
function isPersistentStore(x) {
|
|
8
|
-
return isStore(x) && "sync" in x;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// node_modules/@t8/store/src/Store.ts
|
|
12
|
-
var Store = class {
|
|
13
|
-
state;
|
|
14
|
-
callbacks = /* @__PURE__ */ new Set();
|
|
15
|
-
revision = -1;
|
|
16
|
-
constructor(data) {
|
|
17
|
-
this.state = data;
|
|
18
|
-
}
|
|
19
|
-
onUpdate(callback) {
|
|
20
|
-
this.callbacks.add(callback);
|
|
21
|
-
return () => {
|
|
22
|
-
this.callbacks.delete(callback);
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
getState() {
|
|
26
|
-
return this.state;
|
|
27
|
-
}
|
|
28
|
-
setState(update) {
|
|
29
|
-
let prevState = this.state;
|
|
30
|
-
let nextState = update instanceof Function ? update(this.state) : update;
|
|
31
|
-
this.state = nextState;
|
|
32
|
-
this.revision = Math.random();
|
|
33
|
-
for (let callback of this.callbacks) callback(nextState, prevState);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// node_modules/@t8/store/src/PersistentStore.ts
|
|
38
|
-
function getStorage(session = false) {
|
|
39
|
-
if (typeof window === "undefined") return;
|
|
40
|
-
return session ? sessionStorage : localStorage;
|
|
41
|
-
}
|
|
42
|
-
var PersistentStore = class extends Store {
|
|
43
|
-
storageKey;
|
|
44
|
-
options;
|
|
45
|
-
synced = false;
|
|
46
|
-
/**
|
|
47
|
-
* Creates an instance of the container for data persistent across page
|
|
48
|
-
* reloads.
|
|
49
|
-
*
|
|
50
|
-
* The store data is saved to and restored from the given `storageKey`
|
|
51
|
-
* either of `localStorage` (by default) or `sessionStorage` (if `options.session`
|
|
52
|
-
* is set to `true`). Interaction with the browser storage is skipped in
|
|
53
|
-
* non-browser environments.
|
|
54
|
-
*
|
|
55
|
-
* @example
|
|
56
|
-
* ```js
|
|
57
|
-
* let counterStore = new PersistentStore(0, "counter");
|
|
58
|
-
* ```
|
|
59
|
-
*
|
|
60
|
-
* The way data gets saved to and restored from a browser storage entry
|
|
61
|
-
* (including filtering out certain data or otherwise rearranging the
|
|
62
|
-
* saved data) can be overridden by setting `options.serialize` and
|
|
63
|
-
* `options.deserialize`. By default, they are `JSON.stringify()` and
|
|
64
|
-
* `JSON.parse()`.
|
|
65
|
-
*/
|
|
66
|
-
constructor(data, storageKey, options) {
|
|
67
|
-
super(data);
|
|
68
|
-
this.storageKey = storageKey;
|
|
69
|
-
this.options = {
|
|
70
|
-
session: false,
|
|
71
|
-
serialize: (data2) => JSON.stringify(data2),
|
|
72
|
-
deserialize: (content) => JSON.parse(content),
|
|
73
|
-
...options
|
|
74
|
-
};
|
|
75
|
-
this.onUpdate(() => {
|
|
76
|
-
if (this.synced) this.save();
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Saves the store state value to the browser storage.
|
|
81
|
-
*/
|
|
82
|
-
save() {
|
|
83
|
-
let storage = getStorage(this.options?.session);
|
|
84
|
-
let serialize = this.options?.serialize;
|
|
85
|
-
if (this.synced && storage && typeof serialize === "function") {
|
|
86
|
-
try {
|
|
87
|
-
storage.setItem(this.storageKey, serialize(this.state));
|
|
88
|
-
} catch {
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Signals the store to read the state value from the browser storage.
|
|
94
|
-
*/
|
|
95
|
-
sync() {
|
|
96
|
-
let storage = getStorage(this.options?.session);
|
|
97
|
-
let deserialize = this.options?.deserialize;
|
|
98
|
-
let serializedState = null;
|
|
99
|
-
if (storage && typeof deserialize === "function") {
|
|
100
|
-
try {
|
|
101
|
-
serializedState = storage.getItem(this.storageKey);
|
|
102
|
-
if (serializedState !== null)
|
|
103
|
-
this.setState(deserialize(serializedState, this.state));
|
|
104
|
-
} catch {
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (!this.synced) {
|
|
108
|
-
this.synced = true;
|
|
109
|
-
if (serializedState === null) this.save();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Signals the store to read the state value from the browser storage once,
|
|
114
|
-
* disregarding subsequest `syncOnce()` calls.
|
|
115
|
-
*/
|
|
116
|
-
syncOnce() {
|
|
117
|
-
if (!this.synced) this.sync();
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// src/useStore.ts
|
|
122
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
123
|
-
function useStore(store, shouldUpdate = true) {
|
|
124
|
-
if (!isStore(store))
|
|
125
|
-
throw new Error("'store' is not an instance of Store");
|
|
126
|
-
let [, setRevision] = useState(-1);
|
|
127
|
-
let state = store.getState();
|
|
128
|
-
let setState = useMemo(() => store.setState.bind(store), [store]);
|
|
129
|
-
let initialStoreRevision = useRef(store.revision);
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (isPersistentStore(store)) store.syncOnce();
|
|
132
|
-
if (!shouldUpdate) return;
|
|
133
|
-
let unsubscribe = store.onUpdate((nextState, prevState) => {
|
|
134
|
-
if (typeof shouldUpdate !== "function" || shouldUpdate(nextState, prevState))
|
|
135
|
-
setRevision(Math.random());
|
|
136
|
-
});
|
|
137
|
-
if (store.revision !== initialStoreRevision.current)
|
|
138
|
-
setRevision(Math.random());
|
|
139
|
-
return () => {
|
|
140
|
-
unsubscribe();
|
|
141
|
-
initialStoreRevision.current = store.revision;
|
|
142
|
-
};
|
|
143
|
-
}, [store, shouldUpdate]);
|
|
144
|
-
return [state, setState];
|
|
145
|
-
}
|
|
146
|
-
export {
|
|
147
|
-
PersistentStore,
|
|
148
|
-
Store,
|
|
149
|
-
isPersistentStore,
|
|
150
|
-
isStore,
|
|
151
|
-
useStore
|
|
152
|
-
};
|
package/tsconfig.build.json
DELETED