@ereo/state 0.1.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/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @ereo/state
2
+
3
+ Signals and reactivity system for the EreoJS framework. Provides fine-grained reactive state management with a simple API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @ereo/state
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { signal, computed, createStore } from '@ereo/state';
15
+
16
+ // Create a signal
17
+ const count = signal(0);
18
+
19
+ // Read value
20
+ console.log(count.get()); // 0
21
+
22
+ // Update value
23
+ count.set(1);
24
+ count.update(n => n + 1);
25
+
26
+ // Subscribe to changes
27
+ const unsubscribe = count.subscribe(value => {
28
+ console.log('Count changed:', value);
29
+ });
30
+
31
+ // Create computed signals
32
+ const doubled = computed(() => count.get() * 2, [count]);
33
+ ```
34
+
35
+ ## Using Stores
36
+
37
+ ```typescript
38
+ import { createStore } from '@ereo/state';
39
+
40
+ interface AppState {
41
+ user: string | null;
42
+ theme: 'light' | 'dark';
43
+ count: number;
44
+ }
45
+
46
+ const store = createStore<AppState>({
47
+ user: null,
48
+ theme: 'light',
49
+ count: 0,
50
+ });
51
+
52
+ // Get signal for a specific key
53
+ const userSignal = store.get('user');
54
+
55
+ // Set value
56
+ store.set('theme', 'dark');
57
+
58
+ // Get snapshot of all values
59
+ const snapshot = store.getSnapshot();
60
+ ```
61
+
62
+ ## Key Features
63
+
64
+ - **Signals**: Fine-grained reactive primitives with automatic change detection
65
+ - **Computed Values**: Derived state that updates automatically when dependencies change
66
+ - **Stores**: Centralized state management with key-value access
67
+ - **Subscriptions**: React to state changes with subscribe/unsubscribe pattern
68
+ - **Batch Updates**: Group multiple updates to minimize re-renders
69
+ - **Map Transform**: Transform signals with the `map()` method
70
+ - **TypeScript Support**: Full type inference and safety
71
+
72
+ ## API Reference
73
+
74
+ - `signal<T>(value)` - Create a reactive signal
75
+ - `atom<T>(value)` - Alias for signal
76
+ - `computed<T>(fn, deps)` - Create a computed signal
77
+ - `batch(fn)` - Batch multiple updates
78
+ - `createStore<T>(state)` - Create a reactive store
79
+
80
+ ## Documentation
81
+
82
+ For full documentation, visit the [EreoJS Documentation](https://ereojs.dev/docs/state).
83
+
84
+ ## Part of EreoJS
85
+
86
+ This package is part of the [EreoJS](https://github.com/ereojs/ereo) monorepo - a modern full-stack JavaScript framework.
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @ereo/state - Main exports
3
+ */
4
+ export { Signal, Store, signal, atom, computed, batch, createStore, } from './signals';
5
+ export { useSignal, useStoreKey, useStore, } from './react';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,MAAM,EACN,KAAK,EACL,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,WAAW,GACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,SAAS,EACT,WAAW,EACX,QAAQ,GACT,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,115 @@
1
+ // @bun
2
+ // src/signals.ts
3
+ class Signal {
4
+ _value;
5
+ _subscribers = new Set;
6
+ _derivedFrom = [];
7
+ constructor(initialValue) {
8
+ this._value = initialValue;
9
+ }
10
+ get() {
11
+ return this._value;
12
+ }
13
+ set(value) {
14
+ if (this._value !== value) {
15
+ this._value = value;
16
+ this._notify();
17
+ }
18
+ }
19
+ update(updater) {
20
+ this.set(updater(this._value));
21
+ }
22
+ subscribe(subscriber) {
23
+ this._subscribers.add(subscriber);
24
+ return () => this._subscribers.delete(subscriber);
25
+ }
26
+ map(fn) {
27
+ const computed = new Signal(fn(this._value));
28
+ this.subscribe((v) => computed.set(fn(v)));
29
+ return computed;
30
+ }
31
+ _notify() {
32
+ for (const subscriber of this._subscribers) {
33
+ subscriber(this._value);
34
+ }
35
+ }
36
+ }
37
+ function signal(initialValue) {
38
+ return new Signal(initialValue);
39
+ }
40
+ function computed(fn, deps) {
41
+ const computed2 = new Signal(fn());
42
+ const update = () => {
43
+ computed2.set(fn());
44
+ };
45
+ for (const dep of deps) {
46
+ dep.subscribe(update);
47
+ }
48
+ return computed2;
49
+ }
50
+ function atom(initialValue) {
51
+ return signal(initialValue);
52
+ }
53
+ function batch(fn) {
54
+ return fn();
55
+ }
56
+
57
+ class Store {
58
+ _state = new Map;
59
+ constructor(initialState) {
60
+ for (const [key, value] of Object.entries(initialState)) {
61
+ this._state.set(key, signal(value));
62
+ }
63
+ }
64
+ get(key) {
65
+ return this._state.get(key);
66
+ }
67
+ set(key, value) {
68
+ const s = this._state.get(key);
69
+ if (s) {
70
+ s.set(value);
71
+ } else {
72
+ this._state.set(key, signal(value));
73
+ }
74
+ }
75
+ getSnapshot() {
76
+ const snapshot = {};
77
+ for (const [key, sig] of this._state) {
78
+ snapshot[key] = sig.get();
79
+ }
80
+ return snapshot;
81
+ }
82
+ }
83
+ function createStore(initialState) {
84
+ return new Store(initialState);
85
+ }
86
+ // src/react.ts
87
+ import { useSyncExternalStore, useCallback } from "react";
88
+ function useSignal(signal2) {
89
+ return useSyncExternalStore(useCallback((callback) => signal2.subscribe(callback), [signal2]), () => signal2.get(), () => signal2.get());
90
+ }
91
+ function useStoreKey(store, key) {
92
+ const signal2 = store.get(key);
93
+ return useSignal(signal2);
94
+ }
95
+ function useStore(store) {
96
+ return useSyncExternalStore(useCallback((callback) => {
97
+ const unsubscribers = [];
98
+ for (const [key, sig] of store._state.entries()) {
99
+ unsubscribers.push(sig.subscribe(callback));
100
+ }
101
+ return () => unsubscribers.forEach((unsub) => unsub());
102
+ }, [store]), () => store.getSnapshot(), () => store.getSnapshot());
103
+ }
104
+ export {
105
+ useStoreKey,
106
+ useStore,
107
+ useSignal,
108
+ signal,
109
+ createStore,
110
+ computed,
111
+ batch,
112
+ atom,
113
+ Store,
114
+ Signal
115
+ };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @ereo/state - React Integration
3
+ *
4
+ * useSyncExternalStore wrappers for signals to ensure React Compiler compatibility.
5
+ */
6
+ import type { Signal, Store } from './signals';
7
+ /**
8
+ * Hook to use a signal value with React's useSyncExternalStore.
9
+ * This makes signals compatible with React Compiler.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const count = signal(0);
14
+ *
15
+ * function Counter() {
16
+ * const value = useSignal(count);
17
+ * return <button>{value}</button>;
18
+ * }
19
+ * ```
20
+ */
21
+ export declare function useSignal<T>(signal: Signal<T>): T;
22
+ /**
23
+ * Hook to use a single key from a store with React's useSyncExternalStore.
24
+ * Only re-renders when the specific key changes.
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * const store = createStore({ count: 0, name: 'test' });
29
+ *
30
+ * function Counter() {
31
+ * const count = useStoreKey(store, 'count');
32
+ * return <button>{count}</button>;
33
+ * }
34
+ * ```
35
+ */
36
+ export declare function useStoreKey<T extends Record<string, unknown>, K extends keyof T>(store: Store<T>, key: K): T[K];
37
+ /**
38
+ * Hook to use the entire store snapshot with React's useSyncExternalStore.
39
+ * Re-renders when any key in the store changes.
40
+ *
41
+ * @example
42
+ * ```tsx
43
+ * const store = createStore({ count: 0, name: 'test' });
44
+ *
45
+ * function App() {
46
+ * const state = useStore(store);
47
+ * return <div>{state.count} - {state.name}</div>;
48
+ * }
49
+ * ```
50
+ */
51
+ export declare function useStore<T extends Record<string, unknown>>(store: Store<T>): T;
52
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAMjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAC9E,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EACf,GAAG,EAAE,CAAC,GACL,CAAC,CAAC,CAAC,CAAC,CAGN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAY9E"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @ereo/state - Signals and reactivity system
3
+ *
4
+ * Fine-grained reactivity for state management.
5
+ */
6
+ /** Subscriber function */
7
+ type Subscriber<T> = (value: T) => void;
8
+ /** Signal with reactive value */
9
+ export declare class Signal<T> {
10
+ private _value;
11
+ private _subscribers;
12
+ private _derivedFrom;
13
+ constructor(initialValue: T);
14
+ /** Get current value (subscribes in reactive context) */
15
+ get(): T;
16
+ /** Set new value (notifies subscribers) */
17
+ set(value: T): void;
18
+ /** Update value with function */
19
+ update(updater: (value: T) => T): void;
20
+ /** Subscribe to changes */
21
+ subscribe(subscriber: Subscriber<T>): () => void;
22
+ /** Create computed signal from this signal */
23
+ map<U>(fn: (value: T) => U): Signal<U>;
24
+ private _notify;
25
+ }
26
+ /** Create a new signal */
27
+ export declare function signal<T>(initialValue: T): Signal<T>;
28
+ /** Create a computed signal */
29
+ export declare function computed<T>(fn: () => T, deps: Signal<unknown>[]): Signal<T>;
30
+ /** Atom (alias for signal) */
31
+ export declare function atom<T>(initialValue: T): Signal<T>;
32
+ /** Batch multiple updates */
33
+ export declare function batch<T>(fn: () => T): T;
34
+ /** Store for global state */
35
+ export declare class Store<T extends Record<string, unknown>> {
36
+ private _state;
37
+ constructor(initialState: T);
38
+ /** Get signal for key */
39
+ get<K extends keyof T>(key: K): Signal<T[K]>;
40
+ /** Set value for key */
41
+ set<K extends keyof T>(key: K, value: T[K]): void;
42
+ /** Get current snapshot of all values */
43
+ getSnapshot(): T;
44
+ }
45
+ /** Create a store */
46
+ export declare function createStore<T extends Record<string, unknown>>(initialState: T): Store<T>;
47
+ export {};
48
+ //# sourceMappingURL=signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,0BAA0B;AAC1B,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAExC,iCAAiC;AACjC,qBAAa,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,YAAY,CAAyB;gBAEjC,YAAY,EAAE,CAAC;IAI3B,yDAAyD;IACzD,GAAG,IAAI,CAAC;IAIR,2CAA2C;IAC3C,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI;IAOnB,iCAAiC;IACjC,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI;IAItC,2BAA2B;IAC3B,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAKhD,8CAA8C;IAC9C,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAMtC,OAAO,CAAC,OAAO;CAKhB;AAED,0BAA0B;AAC1B,wBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAEpD;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAY3E;AAED,8BAA8B;AAC9B,wBAAgB,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAElD;AAED,6BAA6B;AAC7B,wBAAgB,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAGvC;AAED,6BAA6B;AAC7B,qBAAa,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAElD,OAAO,CAAC,MAAM,CAAuC;gBAEzC,YAAY,EAAE,CAAC;IAM3B,yBAAyB;IACzB,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAI5C,wBAAwB;IACxB,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IASjD,yCAAyC;IACzC,WAAW,IAAI,CAAC;CAOjB;AAED,qBAAqB;AACrB,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAExF"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@ereo/state",
3
+ "version": "0.1.6",
4
+ "license": "MIT",
5
+ "author": "Ereo Team",
6
+ "homepage": "https://ereo.dev",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ereojs/ereo.git",
10
+ "directory": "packages/state"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ereojs/ereo/issues"
14
+ },
15
+ "description": "Signals and reactivity system for EreoJS framework",
16
+ "type": "module",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "bun build ./src/index.ts --outdir ./dist --target bun --external @ereo/core --external react && bun run build:types",
30
+ "build:types": "tsc --emitDeclarationOnly --outDir dist",
31
+ "dev": "bun build ./src/index.ts --outdir ./dist --target bun --watch",
32
+ "test": "bun test",
33
+ "typecheck": "tsc --noEmit"
34
+ },
35
+ "dependencies": {
36
+ "@ereo/core": "workspace:*"
37
+ },
38
+ "peerDependencies": {
39
+ "react": "^18.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/bun": "^1.1.0",
43
+ "@types/react": "^18.2.0",
44
+ "typescript": "^5.4.0"
45
+ }
46
+ }