gjendje 1.0.10 → 1.1.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 CHANGED
@@ -23,24 +23,33 @@ import { state } from 'gjendje'
23
23
 
24
24
  const store = state({ count: 0 })
25
25
 
26
- function increment() {
27
- store.set((prev) => ({ ...prev, count: prev.count + 1 }))
28
- }
26
+ // set
27
+ store.set({ count: 1 })
28
+
29
+ store.set((prev) => ({ ...prev, count: prev.count + 1 }))
30
+
31
+ // get
32
+ store.get()
29
33
 
30
- const { counter } = store.get()
34
+ const { count } = store.get()
35
+
36
+ // reset
37
+ store.reset()
31
38
  ```
32
39
 
33
40
  [Examples](https://github.com/charliebeckstrand/gjendje/blob/main/docs/examples.md)
34
41
 
35
- ## Configure
42
+ ## API
36
43
 
37
- `configure` allows you to set global values for all state instances.
44
+ `get`, `peek`, `set`, `patch`, `reset`, `destroy`, `subscribe`, `watch`, `intercept`, `onChange`
38
45
 
39
- ---
46
+ [API reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/api.md)
40
47
 
41
- `scope`, `maxKeys`, `prefix`, `requireValidation`, `registry`, `ssr`, `sync`, `warnOnDuplicate`, `onChange`, `onDestroy`, `onError`, `onExpire`, `onHydrate`, `onIntercept`, `onMigrate`, `onQuotaExceeded`, `onRegister`, `onReset`, `onSync`, `onValidationFail`
48
+ ## Primitives
42
49
 
43
- [Configure guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/configure.md)
50
+ `computed`, `select`, `previous`, `readonly`, `collection`, `effect`
51
+
52
+ [Primitives reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/primitives.md)
44
53
 
45
54
  ## Scopes
46
55
 
@@ -48,17 +57,42 @@ const { counter } = store.get()
48
57
 
49
58
  [Scope guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/scopes.md)
50
59
 
51
- ## API
60
+ ## Framework Bindings
52
61
 
53
- `get`, `peek`, `set`, `patch`, `reset`, `destroy`, `subscribe`, `watch`, `intercept`, `onChange`
62
+ ### React
54
63
 
55
- [API reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/api.md)
64
+ ```tsx
65
+ import { state } from 'gjendje'
66
+ import { useGjendje } from 'gjendje/react'
56
67
 
57
- ## Primitives
68
+ const counter = state({ counter: 0 })
58
69
 
59
- `computed`, `select`, `previous`, `readonly`, `collection`, `effect`
70
+ function Counter() {
71
+ const [count, setCount, resetCount] = useGjendje(counter)
60
72
 
61
- [Primitives reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/primitives.md)
73
+ return <button onClick={() => setCount(prev => prev + 1)}>{count}</button>
74
+ }
75
+ ```
76
+
77
+ [React guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/react.md)
78
+
79
+ ### Vue
80
+
81
+ ```vue
82
+ <script setup>
83
+ import { state } from 'gjendje'
84
+ import { useGjendje } from 'gjendje/vue'
85
+
86
+ const counter = state({ counter: 0 })
87
+ const count = useGjendje(counter)
88
+ </script>
89
+
90
+ <template>
91
+ <button @click="count++">{{ count }}</button>
92
+ </template>
93
+ ```
94
+
95
+ [Vue guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/vue.md)
62
96
 
63
97
  ## Utilities
64
98
 
@@ -66,6 +100,12 @@ const { counter } = store.get()
66
100
 
67
101
  [Utilities reference](https://github.com/charliebeckstrand/gjendje/blob/main/docs/utilities.md)
68
102
 
103
+ ## Configure (global config)
104
+
105
+ `scope`, `maxKeys`, `prefix`, `requireValidation`, `registry`, `ssr`, `sync`, `warnOnDuplicate`, `onChange`, `onDestroy`, `onError`, `onExpire`, `onHydrate`, `onIntercept`, `onMigrate`, `onQuotaExceeded`, `onRegister`, `onReset`, `onSync`, `onValidationFail`
106
+
107
+ [Configure guide](https://github.com/charliebeckstrand/gjendje/blob/main/docs/configure.md)
108
+
69
109
  ## License
70
110
 
71
111
  MIT
@@ -0,0 +1,6 @@
1
+ // src/is-writable.ts
2
+ function isWritable(instance) {
3
+ return typeof instance.set === "function";
4
+ }
5
+
6
+ export { isWritable };
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ // src/is-writable.ts
4
+ function isWritable(instance) {
5
+ return typeof instance.set === "function";
6
+ }
7
+
8
+ exports.isWritable = isWritable;
package/dist/react.cjs ADDED
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var chunkSGBOKQUT_cjs = require('./chunk-SGBOKQUT.cjs');
4
+ var react = require('react');
5
+
6
+ function useGjendje(instance, selector) {
7
+ const getSnapshot = selector ? () => selector(instance.get()) : () => instance.get();
8
+ const value = react.useSyncExternalStore(
9
+ (onStoreChange) => instance.subscribe(onStoreChange),
10
+ getSnapshot,
11
+ getSnapshot
12
+ );
13
+ if (selector) return value;
14
+ if (chunkSGBOKQUT_cjs.isWritable(instance)) {
15
+ return [value, (v) => instance.set(v), () => instance.reset()];
16
+ }
17
+ return value;
18
+ }
19
+
20
+ exports.useGjendje = useGjendje;
@@ -0,0 +1,23 @@
1
+ import { R as ReadonlyInstance, B as BaseInstance } from './types-D8aJjm3k.cjs';
2
+
3
+ /**
4
+ * Reactive result tuple for writable instances.
5
+ * Mirrors the familiar [value, set, reset] shape of React's useState.
6
+ */
7
+ type UseGjendjeResult<T> = readonly [
8
+ value: T,
9
+ set: (value: T | ((prev: T) => T)) => void,
10
+ reset: () => void
11
+ ];
12
+ /**
13
+ * Subscribe to a gjendje state instance in React.
14
+ *
15
+ * - **Writable instance** → returns `[value, set, reset]`
16
+ * - **Readonly / computed** → returns `value`
17
+ * - **With selector** → returns the selected slice
18
+ */
19
+ declare function useGjendje<T, U>(instance: ReadonlyInstance<T>, selector: (value: T) => U): U;
20
+ declare function useGjendje<T>(instance: BaseInstance<T>): UseGjendjeResult<T>;
21
+ declare function useGjendje<T>(instance: ReadonlyInstance<T>): T;
22
+
23
+ export { type UseGjendjeResult, useGjendje };
@@ -0,0 +1,23 @@
1
+ import { R as ReadonlyInstance, B as BaseInstance } from './types-D8aJjm3k.js';
2
+
3
+ /**
4
+ * Reactive result tuple for writable instances.
5
+ * Mirrors the familiar [value, set, reset] shape of React's useState.
6
+ */
7
+ type UseGjendjeResult<T> = readonly [
8
+ value: T,
9
+ set: (value: T | ((prev: T) => T)) => void,
10
+ reset: () => void
11
+ ];
12
+ /**
13
+ * Subscribe to a gjendje state instance in React.
14
+ *
15
+ * - **Writable instance** → returns `[value, set, reset]`
16
+ * - **Readonly / computed** → returns `value`
17
+ * - **With selector** → returns the selected slice
18
+ */
19
+ declare function useGjendje<T, U>(instance: ReadonlyInstance<T>, selector: (value: T) => U): U;
20
+ declare function useGjendje<T>(instance: BaseInstance<T>): UseGjendjeResult<T>;
21
+ declare function useGjendje<T>(instance: ReadonlyInstance<T>): T;
22
+
23
+ export { type UseGjendjeResult, useGjendje };
package/dist/react.js ADDED
@@ -0,0 +1,18 @@
1
+ import { isWritable } from './chunk-OZ6A5AAY.js';
2
+ import { useSyncExternalStore } from 'react';
3
+
4
+ function useGjendje(instance, selector) {
5
+ const getSnapshot = selector ? () => selector(instance.get()) : () => instance.get();
6
+ const value = useSyncExternalStore(
7
+ (onStoreChange) => instance.subscribe(onStoreChange),
8
+ getSnapshot,
9
+ getSnapshot
10
+ );
11
+ if (selector) return value;
12
+ if (isWritable(instance)) {
13
+ return [value, (v) => instance.set(v), () => instance.reset()];
14
+ }
15
+ return value;
16
+ }
17
+
18
+ export { useGjendje };
package/dist/vue.cjs ADDED
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var chunkSGBOKQUT_cjs = require('./chunk-SGBOKQUT.cjs');
4
+ var vue = require('vue');
5
+
6
+ function useGjendje(instance, selector) {
7
+ const writable = !selector && chunkSGBOKQUT_cjs.isWritable(instance);
8
+ const ref = vue.customRef((track, trigger) => {
9
+ let last = selector ? selector(instance.get()) : instance.get();
10
+ const unsub = instance.subscribe((next) => {
11
+ const value = selector ? selector(next) : next;
12
+ if (!Object.is(value, last)) {
13
+ last = value;
14
+ trigger();
15
+ }
16
+ });
17
+ vue.onScopeDispose(unsub);
18
+ return {
19
+ get() {
20
+ track();
21
+ return selector ? selector(instance.get()) : instance.get();
22
+ },
23
+ set(value) {
24
+ if (writable) {
25
+ instance.set(value);
26
+ }
27
+ }
28
+ };
29
+ });
30
+ return ref;
31
+ }
32
+
33
+ exports.useGjendje = useGjendje;
package/dist/vue.d.cts ADDED
@@ -0,0 +1,17 @@
1
+ import { Ref } from 'vue';
2
+ import { R as ReadonlyInstance, B as BaseInstance } from './types-D8aJjm3k.cjs';
3
+
4
+ /**
5
+ * Subscribe to a gjendje state instance in Vue.
6
+ *
7
+ * Returns a reactive `Ref` that stays in sync with the instance.
8
+ *
9
+ * - **Writable instance** → ref is two-way: read with `.value`, write by assigning to `.value`
10
+ * - **Readonly / computed** → ref is read-only
11
+ * - **With selector** → ref holds the selected slice (read-only)
12
+ */
13
+ declare function useGjendje<T, U>(instance: ReadonlyInstance<T>, selector: (value: T) => U): Readonly<Ref<U>>;
14
+ declare function useGjendje<T>(instance: BaseInstance<T>): Ref<T>;
15
+ declare function useGjendje<T>(instance: ReadonlyInstance<T>): Readonly<Ref<T>>;
16
+
17
+ export { useGjendje };
package/dist/vue.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { Ref } from 'vue';
2
+ import { R as ReadonlyInstance, B as BaseInstance } from './types-D8aJjm3k.js';
3
+
4
+ /**
5
+ * Subscribe to a gjendje state instance in Vue.
6
+ *
7
+ * Returns a reactive `Ref` that stays in sync with the instance.
8
+ *
9
+ * - **Writable instance** → ref is two-way: read with `.value`, write by assigning to `.value`
10
+ * - **Readonly / computed** → ref is read-only
11
+ * - **With selector** → ref holds the selected slice (read-only)
12
+ */
13
+ declare function useGjendje<T, U>(instance: ReadonlyInstance<T>, selector: (value: T) => U): Readonly<Ref<U>>;
14
+ declare function useGjendje<T>(instance: BaseInstance<T>): Ref<T>;
15
+ declare function useGjendje<T>(instance: ReadonlyInstance<T>): Readonly<Ref<T>>;
16
+
17
+ export { useGjendje };
package/dist/vue.js ADDED
@@ -0,0 +1,31 @@
1
+ import { isWritable } from './chunk-OZ6A5AAY.js';
2
+ import { customRef, onScopeDispose } from 'vue';
3
+
4
+ function useGjendje(instance, selector) {
5
+ const writable = !selector && isWritable(instance);
6
+ const ref = customRef((track, trigger) => {
7
+ let last = selector ? selector(instance.get()) : instance.get();
8
+ const unsub = instance.subscribe((next) => {
9
+ const value = selector ? selector(next) : next;
10
+ if (!Object.is(value, last)) {
11
+ last = value;
12
+ trigger();
13
+ }
14
+ });
15
+ onScopeDispose(unsub);
16
+ return {
17
+ get() {
18
+ track();
19
+ return selector ? selector(instance.get()) : instance.get();
20
+ },
21
+ set(value) {
22
+ if (writable) {
23
+ instance.set(value);
24
+ }
25
+ }
26
+ };
27
+ });
28
+ return ref;
29
+ }
30
+
31
+ export { useGjendje };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gjendje",
3
- "version": "1.0.10",
3
+ "version": "1.1.0",
4
4
  "description": "Storage-agnostic state management for TypeScript",
5
5
  "keywords": [
6
6
  "state",
@@ -25,6 +25,7 @@
25
25
  "node": ">=18.0.0"
26
26
  },
27
27
  "type": "module",
28
+ "sideEffects": false,
28
29
  "exports": {
29
30
  ".": {
30
31
  "import": {
@@ -45,6 +46,26 @@
45
46
  "types": "./dist/server.d.cts",
46
47
  "default": "./dist/server.cjs"
47
48
  }
49
+ },
50
+ "./react": {
51
+ "import": {
52
+ "types": "./dist/react.d.ts",
53
+ "default": "./dist/react.js"
54
+ },
55
+ "require": {
56
+ "types": "./dist/react.d.cts",
57
+ "default": "./dist/react.cjs"
58
+ }
59
+ },
60
+ "./vue": {
61
+ "import": {
62
+ "types": "./dist/vue.d.ts",
63
+ "default": "./dist/vue.js"
64
+ },
65
+ "require": {
66
+ "types": "./dist/vue.d.cts",
67
+ "default": "./dist/vue.cjs"
68
+ }
48
69
  }
49
70
  },
50
71
  "main": "./dist/index.cjs",
@@ -58,21 +79,40 @@
58
79
  "provenance": true,
59
80
  "access": "public"
60
81
  },
82
+ "peerDependencies": {
83
+ "react": ">=18.0.0",
84
+ "vue": ">=3.3.0"
85
+ },
86
+ "peerDependenciesMeta": {
87
+ "react": {
88
+ "optional": true
89
+ },
90
+ "vue": {
91
+ "optional": true
92
+ }
93
+ },
61
94
  "devDependencies": {
62
95
  "@biomejs/biome": "^2.4.6",
63
96
  "@changesets/cli": "^2.27.0",
64
97
  "@size-limit/preset-small-lib": "^11.0.0",
98
+ "@testing-library/react": "^16.3.2",
65
99
  "@types/node": "^20.0.0",
100
+ "@types/react": "^19.2.14",
101
+ "@types/react-dom": "^19.2.3",
66
102
  "@vitest/coverage-v8": "^4.0.0",
103
+ "@vue/test-utils": "^2.4.6",
67
104
  "happy-dom": "^20.8.7",
68
105
  "lefthook": "^1.6.0",
69
106
  "publint": "^0.3.0",
107
+ "react": "^19.2.4",
108
+ "react-dom": "^19.2.4",
70
109
  "size-limit": "^11.0.0",
71
110
  "tinybench": "^6.0.0",
72
111
  "tsup": "^8.0.0",
73
112
  "typescript": "^5.4.0",
74
113
  "vite": "^6.0.0",
75
- "vitest": "^4.0.0"
114
+ "vitest": "^4.0.0",
115
+ "vue": "^3.5.31"
76
116
  },
77
117
  "scripts": {
78
118
  "build": "tsup",