zeno-state 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Rob Watson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Simple state
2
+
3
+ A (hopefully) simple global state management system.
4
+
5
+ ## Demo (this repository)
6
+
7
+ 1. Download the code (`git checkout`, or some other way of downloading)
8
+ 2. Run `pnpm install`
9
+ 3. Run `pnpm run dev`
10
+ 4. Open your browser at the location given by pnpm (usually http://localhost:5173)
11
+ 5. Open your browser dev tools and enable the React dev tools feature of "Highlight updates when components render."
12
+ 6. Have a play and watch how the different start management types handle their rendering
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install zeno-state
18
+ ```
19
+
20
+ ## Library usage
21
+
22
+
23
+ ### Step 1: Define a store
24
+
25
+ I recommend setting a default value that contains all your keys alongside specifying the shape of the data to help
26
+ reduce null value exceptions and to help define the shape of objects contained within empty arrays
27
+
28
+
29
+ ```tsx
30
+ import { createStore } from 'zeno-state'
31
+
32
+ const carStore = createStore<{
33
+ cars: [{
34
+ make: 'Ford'|'Jaguar',
35
+ model: string,
36
+ engineSize: number,
37
+ colour: string
38
+ }]
39
+ }>({ cars: [] })
40
+ ```
41
+
42
+
43
+ ### Step 2: Use it
44
+
45
+ The second argument of `useStore` is a _selector function_. This allows a portion of the whole state to be used by your
46
+ component and enables re-rendering only when that selection changes.
47
+
48
+ ```tsx
49
+ import { useStore } from 'zeno-state'
50
+
51
+ function CarList() {
52
+ const cars = useStore(carStore, state => state.cars)
53
+
54
+ return cars.map((car, index) => (
55
+ <p>{ car.make } - { car.model }</p>
56
+ ))
57
+ }
58
+ ```
59
+
60
+
61
+ ### Step 3: Update state inside a store
62
+
63
+ `createStore` returns `get` and `set` methods to update the state, you can use these directly and any components that
64
+ have selected part of the state you update will be re-rendered. The `set` function accepts an object which is merged
65
+ with the current state object, allowing additions and partial updates to the state.
66
+
67
+ > Note: this only allows for updating and adding keys to the stored state, not deleting any root-level keys not directly
68
+ > updating deep-nested properties.
69
+
70
+ ```tsx
71
+ function addCar() {
72
+ carStore.set({ cars: [...cars, { make: 'Ford', model: 'Focus', engineSize: 1.6, colour: 'silver'}]})
73
+ }
74
+ ```
@@ -0,0 +1,3 @@
1
+ import { Store } from "./simpleState";
2
+ export declare function createStore<State>(state: State): Store<State>;
3
+ //# sourceMappingURL=createStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStore.d.ts","sourceRoot":"","sources":["../src/lib/simple-state/createStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,EAA6B,MAAM,eAAe,CAAC;AAEhE,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CA2B7D"}
@@ -0,0 +1,22 @@
1
+ export function createStore(state) {
2
+ const subscribers = new Set();
3
+ function subscribe(callback) {
4
+ subscribers.add(callback);
5
+ return () => subscribers.delete(callback);
6
+ }
7
+ function getSnapshot() {
8
+ return state;
9
+ }
10
+ function alertSubscribers() {
11
+ subscribers.forEach(subscriber => subscriber(state));
12
+ }
13
+ function updateState(slice) {
14
+ state = { ...state, ...slice };
15
+ alertSubscribers();
16
+ }
17
+ return {
18
+ subscribe,
19
+ get: getSnapshot,
20
+ set: updateState,
21
+ };
22
+ }
@@ -0,0 +1,4 @@
1
+ export { createStore } from './createStore';
2
+ export { useStore } from './useStore';
3
+ export type { Store, SubscribeFn, UnsubscribeFn } from './simpleState';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/simple-state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createStore } from './createStore';
2
+ export { useStore } from './useStore';
@@ -0,0 +1,12 @@
1
+ export type SubscribeFn<State> = (state: State) => void;
2
+ export type UnsubscribeFn = () => void;
3
+ type SubscriberFn<State> = (callback: SubscribeFn<State>) => UnsubscribeFn;
4
+ type GetSnapshotFn<State> = () => State;
5
+ type UpdateStateFn<State> = (state: Partial<State>) => void;
6
+ export type Store<State> = {
7
+ subscribe: SubscriberFn<State>;
8
+ get: GetSnapshotFn<State>;
9
+ set: UpdateStateFn<State>;
10
+ };
11
+ export {};
12
+ //# sourceMappingURL=simpleState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simpleState.d.ts","sourceRoot":"","sources":["../src/lib/simple-state/simpleState.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,WAAW,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;AACvD,MAAM,MAAM,aAAa,GAAG,MAAM,IAAI,CAAA;AAEtC,KAAK,YAAY,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,aAAa,CAAA;AAC1E,KAAK,aAAa,CAAC,KAAK,IAAI,MAAM,KAAK,CAAA;AACvC,KAAK,aAAa,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAA;AAE3D,MAAM,MAAM,KAAK,CAAC,KAAK,IAAI;IACzB,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAA;IAC9B,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;IACzB,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAC1B,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { Store } from "./simpleState";
2
+ export declare function useStore<State, Slice>(store: Store<State>, selector: (state: State) => Slice): Slice;
3
+ //# sourceMappingURL=useStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStore.d.ts","sourceRoot":"","sources":["../src/lib/simple-state/useStore.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,KAAK,SAI5F"}
@@ -0,0 +1,4 @@
1
+ import { useSyncExternalStore } from "react";
2
+ export function useStore(store, selector) {
3
+ return useSyncExternalStore(store.subscribe, () => (selector(store.get())));
4
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "zeno-state",
3
+ "private": false,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "description": "A simple global state management library for React",
7
+ "keywords": ["react", "state", "state-management", "hooks", "global-state"],
8
+ "author": "Rob Watson",
9
+ "license": "MIT",
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": ["dist", "README.md", "LICENSE"],
19
+ "scripts": {
20
+ "dev": "vite",
21
+ "build": "tsc -b && vite build",
22
+ "build:lib": "vite build --mode lib && tsc --project tsconfig.lib.json",
23
+ "lint": "eslint .",
24
+ "preview": "vite preview",
25
+ "prepublishOnly": "npm run build:lib"
26
+ },
27
+ "peerDependencies": {
28
+ "react": "^18.0.0 || ^19.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@eslint/js": "^9.19.0",
32
+ "@tailwindcss/vite": "^4.0.6",
33
+ "@types/react": "^19.0.8",
34
+ "@types/react-dom": "^19.0.3",
35
+ "@vitejs/plugin-react": "^4.3.4",
36
+ "eslint": "^9.19.0",
37
+ "eslint-plugin-react-hooks": "^5.0.0",
38
+ "eslint-plugin-react-refresh": "^0.4.18",
39
+ "globals": "^15.14.0",
40
+ "react": "^19.0.0",
41
+ "react-dom": "^19.0.0",
42
+ "tailwindcss": "^4.0.6",
43
+ "typescript": "~5.7.2",
44
+ "typescript-eslint": "^8.22.0",
45
+ "vite": "^6.1.0"
46
+ }
47
+ }