flatsignals 0.1.0 β†’ 0.2.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,81 +1,102 @@
1
1
  # FlatSignals
2
2
 
3
- FlatSignals is an extremely fast reactivity library (~0.7kb).
3
+ **FlatSignals** is an ultra-fast reactivity library (~0.5 KB) optimized for **high-frequency, few-to-many updates**.
4
4
 
5
- - Lightning-fast batch updates.
6
- - No graph traversals.
7
- - Dynamic dependencies managed in O(1) time.
8
- - Automatic disposals.
9
- - Computeds are lazy by default.
5
+ ## πŸš€ Why it’s fast:
6
+
7
+ - No graph traversals
8
+ - O(1) dynamic dependency management
9
+ - Lazy computations by default
10
10
 
11
11
  ## Benchmarks
12
12
 
13
- You can execute the [benchmarks](https://github.com/kevintakeda/flatsignals/tree/main/benchmarks) by running `pnpm bench`.
14
-
15
- ```console
16
- flatsignals - benchmarks/signals.bench.ts > one to many sparse (32x)
17
- 1.60x faster than @preact/signals
18
- 1.70x faster than @reactively/core
19
- 1.95x faster than alien-signals
20
- 2.27x faster than @maverick-js/signals
21
-
22
- flatsignals - benchmarks/signals.bench.ts > wide propagation (32x)
23
- 1.72x faster than @preact/signals
24
- 1.74x faster than alien-signals
25
- 2.22x faster than @reactively/core
26
- 2.94x faster than @maverick-js/signals
27
-
28
- flatsignals - benchmarks/signals.bench.ts > deep propagation (32x)
29
- 1.02x faster than alien-signals
30
- 1.29x faster than @preact/signals
31
- 1.55x faster than @reactively/core
32
- 1.97x faster than @maverick-js/signals
33
-
34
- flatsignals - benchmarks/signals.bench.ts > dynamic
35
- 2.82x faster than @preact/signals
36
- 2.98x faster than @reactively/core
37
- 3.54x faster than @maverick-js/signals
38
- 4.56x faster than alien-signals
39
-
40
- flatsignals - benchmarks/signals.bench.ts > batch 25%
41
- 1.26x faster than @preact/signals
42
- 1.56x faster than alien-signals
43
- 1.66x faster than @reactively/core
44
- 1.97x faster than @maverick-js/signals
45
-
46
- flatsignals - benchmarks/signals.bench.ts > batch 50%
47
- 1.48x faster than @preact/signals
48
- 1.62x faster than alien-signals
49
- 1.72x faster than @reactively/core
50
- 2.09x faster than @maverick-js/signals
51
-
52
- flatsignals - benchmarks/signals.bench.ts > packed 30%
53
- 1.49x faster than @reactively/core
54
- 1.77x faster than alien-signals
55
- 1.77x faster than @preact/signals
56
- 1.99x faster than @maverick-js/signals
57
-
58
- flatsignals - benchmarks/signals.bench.ts > dense batch ~1/3 (2x layers)
59
- 1.72x faster than @preact/signals
60
- 2.17x faster than @reactively/core
61
- 2.25x faster than alien-signals
62
- 2.86x faster than @maverick-js/signals
63
-
64
- flatsignals - benchmarks/signals.bench.ts > dense batch ~1/3 (4x layers)
65
- 1.98x faster than @preact/signals
66
- 2.11x faster than @reactively/core
67
- 2.75x faster than alien-signals
68
- 3.05x faster than @maverick-js/signals
69
-
70
- alien-signals - benchmarks/signals.bench.ts > one to one to one (32x)
71
- 1.00x faster than @preact/signals
72
- 1.05x faster than flatsignals
73
- 1.16x faster than @maverick-js/signals
74
- 1.94x faster than @reactively/core
13
+ > **Note:** Benchmarks were run in a controlled environment. Results may vary based on hardware and JavaScript engine. You can reproduce these benchmarks by cloning the repo and running `pnpm bench`.
14
+
15
+ ### 1-to-64 fanout
16
+
17
+ | Library | Operations/sec ⚑ | vs flatsignals |
18
+ | -------------------- | ----------------- | -------------- |
19
+ | **flatsignals** πŸ† | **449,848** | **baseline** |
20
+ | alien-signals | 261,082 | 1.72x slower |
21
+ | @preact/signals | 230,899 | 1.95x slower |
22
+ | @reactively/core | 182,403 | 2.47x slower |
23
+ | @vue/reactivity | 152,709 | 2.95x slower |
24
+ | @maverick-js/signals | 137,712 | 3.27x slower |
25
+ | Angular Signals | 98,597 | 4.56x slower |
26
+ | @solidjs/signals | 78,849 | 5.71x slower |
27
+
28
+ ### High-frequency updates
29
+
30
+ | Library | Operations/sec ⚑ | vs flatsignals |
31
+ | -------------------- | ----------------- | -------------- |
32
+ | **flatsignals** πŸ† | **976,139** | **baseline** |
33
+ | alien-signals | 502,513 | 1.94x slower |
34
+ | @preact/signals | 492,543 | 1.98x slower |
35
+ | @reactively/core | 438,882 | 2.22x slower |
36
+ | @maverick-js/signals | 343,368 | 2.84x slower |
37
+ | Angular Signals | 241,189 | 4.05x slower |
38
+ | @vue/reactivity | 221,537 | 4.41x slower |
39
+ | @solidjs/signals | 202,492 | 4.82x slower |
40
+
41
+ ### Diamond
42
+
43
+ | Library | Operations/sec ⚑ | vs flatsignals |
44
+ | -------------------- | ----------------- | -------------- |
45
+ | **flatsignals** πŸ† | **4,556,987** | **baseline** |
46
+ | alien-signals | 3,028,320 | 1.50x slower |
47
+ | @preact/signals | 2,531,788 | 1.80x slower |
48
+ | @reactively/core | 1,688,053 | 2.70x slower |
49
+ | Angular Signals | 1,614,432 | 2.82x slower |
50
+ | @vue/reactivity | 1,563,865 | 2.91x slower |
51
+ | @maverick-js/signals | 1,407,975 | 3.24x slower |
52
+ | @solidjs/signals | 870,080 | 5.24x slower |
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ # npm
58
+ npm install flatsignals
59
+
60
+ # pnpm
61
+ pnpm add flatsignals
62
+
63
+ # yarn
64
+ yarn add flatsignals
65
+ ```
66
+
67
+ ## Usage
68
+
69
+ ```ts
70
+ import { signal, computed, effect } from "flatsignals";
71
+
72
+ const counter = signal(0);
73
+ const double = computed(() => counter.val * 2);
74
+ const log = effect(() => console.log(double.val));
75
+ ```
76
+
77
+ ## With React
78
+
79
+ ```tsx
80
+ import { useFlatSignal, useFlatReader } from "flatsignals/react";
81
+ import { counter, double } from "./signals";
82
+
83
+ function MyCounter() {
84
+ const [val, setVal] = useFlatSignal(counter);
85
+ return <button onClick={() => setVal(val + 1)}>Count: {val}</button>;
86
+ }
87
+
88
+ function ReadDouble() {
89
+ const val = useFlatReader(double);
90
+ return <div>{val}</div>;
91
+ }
75
92
  ```
76
93
 
77
- ## Tradeoffs
94
+ ## Use Case
95
+
96
+ > **Best suited for:** Scenarios with a small number of reactive signals driving many dependent computations.
97
+
98
+ **Limitations:**
78
99
 
79
- 1. Supports only 32 signals per root.
80
- 2. Set operations have 𝑂(𝑁) complexity, where 𝑁 is the number of computations. However, multiple updates can be batched into a single operation.
81
- 3. When data sources change, all dependent nodes are marked dirty, even if intermediate values stay the same.
100
+ - **Signal limit**: Maximum of 32 signals per root. Beyond this limit, effects may trigger even when their tracked signals haven't changed.
101
+ - **Set complexity**: O(N) time proportional to dependent computations (amortized through batching)
102
+ - **Eager propagation**: All downstream nodes marked dirty immediately, even when intermediate values unchanged
@@ -0,0 +1,32 @@
1
+ //#region src/index.d.ts
2
+ declare class FlatRoot {
3
+ #private;
4
+ dispose(): void;
5
+ }
6
+ declare class FlatSignal<T = any> {
7
+ #private;
8
+ equals: typeof defaultEquality;
9
+ constructor(val?: T);
10
+ get val(): T;
11
+ get peek(): T;
12
+ get root(): FlatRoot;
13
+ set val(val: T);
14
+ }
15
+ declare class FlatCompute<T = unknown> {
16
+ #private;
17
+ constructor(compute?: () => T, val?: T, effect?: boolean);
18
+ get val(): T;
19
+ get peek(): T;
20
+ get root(): FlatRoot;
21
+ dispose(): void;
22
+ }
23
+ declare function defaultEquality(a: unknown, b: unknown): boolean;
24
+ declare function batch(fn: () => void): void;
25
+ declare function scoped<T>(fn: () => T, scope?: FlatRoot): T;
26
+ declare function signal<T>(value: T): FlatSignal<T>;
27
+ declare function signal<T = undefined>(): FlatSignal<T | undefined>;
28
+ declare function computed<T>(val: () => T): FlatCompute<T>;
29
+ declare function effect<T = unknown>(fn: () => T): () => void;
30
+ //#endregion
31
+ export { computed as a, signal as c, batch as i, FlatRoot as n, effect as o, FlatSignal as r, scoped as s, FlatCompute as t };
32
+ //# sourceMappingURL=index-BUz21f61.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,32 +1,2 @@
1
- declare class Scope {
2
- constructor();
3
- }
4
- declare class Root extends Scope {
5
- #private;
6
- }
7
- declare class DataSignal<T = any> {
8
- #private;
9
- equals: typeof defaultEquality;
10
- constructor(val?: T);
11
- get val(): T;
12
- set val(val: T);
13
- }
14
- declare class Computation<T = unknown> extends Scope {
15
- #private;
16
- constructor(compute?: () => T, val?: T, effect?: boolean);
17
- get val(): T;
18
- get peek(): T;
19
- getRoot(): Root;
20
- }
21
- declare function defaultEquality(a: unknown, b: unknown): boolean;
22
- declare function getScope(): Scope | null;
23
- declare function withScope(scope: Scope, fn: () => void): void;
24
- declare function onDispose(fn: () => void): void;
25
- declare function batch(fn: () => void): void;
26
- declare function root<T>(fn: (dispose: () => void) => T, existingRoot?: Root): T;
27
- declare function signal<T>(value: T): DataSignal<T>;
28
- declare function signal<T = undefined>(): DataSignal<T | undefined>;
29
- declare function computed<T>(val: () => T): Computation<T>;
30
- declare function effect<T = unknown>(fn: () => T): () => void;
31
-
32
- export { Computation, DataSignal, Root, Scope, batch, computed, effect, getScope, onDispose, root, signal, withScope };
1
+ import { a as computed, c as signal, i as batch, n as FlatRoot, o as effect, r as FlatSignal, s as scoped, t as FlatCompute } from "./index-BUz21f61.js";
2
+ export { FlatCompute, FlatRoot, FlatSignal, batch, computed, effect, scoped, signal };
package/dist/index.js CHANGED
@@ -1,209 +1,3 @@
1
- // src/index.ts
2
- var ROOT = null;
3
- var COMPUTED = null;
4
- var BATCHING = false;
5
- var ROOT_QUEUE = [];
6
- var Scope = class {
7
- /* @internal */
8
- _disposing = false;
9
- /* @internal */
10
- _disposals = null;
11
- constructor() {
12
- getScope()?._onDispose(this._dispose.bind(this));
13
- }
14
- /* @internal */
15
- _dispose() {
16
- if (this._disposing) return;
17
- this._disposing = true;
18
- this._disposals?.forEach((fn) => fn());
19
- this._disposing = false;
20
- }
21
- /* @internal */
22
- _onDispose(fn) {
23
- if (!this._disposals) this._disposals = [];
24
- this._disposals.push(fn);
25
- }
26
- };
27
- var Root = class extends Scope {
28
- /* @internal computeds */
29
- _c = [];
30
- /* @internal disposed computeds */
31
- _x = [];
32
- /* @internal id generator */
33
- _i = 0;
34
- /* @internal batch mask */
35
- #batch = 0;
36
- /* @internal */
37
- _dispose() {
38
- super._dispose();
39
- this._c = [];
40
- this._x = [];
41
- this._i = 0;
42
- }
43
- /* @internal Add source */
44
- _as() {
45
- return this._i++ % 32;
46
- }
47
- /* @internal Add computed */
48
- _ac(c) {
49
- if (this._x.length) {
50
- const u = this._x.pop();
51
- this._c[u] = c;
52
- return u;
53
- } else {
54
- return this._c.push(c) - 1;
55
- }
56
- }
57
- /* @internal Destroy computed */
58
- _dc(idx) {
59
- this._x.push(idx);
60
- }
61
- /* @internal */
62
- _queue(mask) {
63
- if (!this.#batch) {
64
- ROOT_QUEUE.push(this);
65
- }
66
- this.#batch |= mask;
67
- if (!BATCHING) this._flush(true);
68
- }
69
- /* @internal */
70
- _flush(force = false) {
71
- if (!this.#batch || !force) return;
72
- for (const item of this._c) {
73
- if (!item._dirty && (item._sources & this.#batch) !== 0) {
74
- item._dirty = true;
75
- if (item._effect) item.val;
76
- }
77
- }
78
- this.#batch = 0;
79
- }
80
- };
81
- var DataSignal = class {
82
- #root;
83
- #val;
84
- #id = 0;
85
- equals = defaultEquality;
86
- constructor(val) {
87
- if (!ROOT) ROOT = new Root();
88
- this.#root = ROOT;
89
- this.#val = val;
90
- this.#id |= 1 << this.#root._as();
91
- }
92
- get val() {
93
- if (COMPUTED) {
94
- COMPUTED._sources |= this.#id;
95
- }
96
- return this.#val;
97
- }
98
- set val(val) {
99
- if (this.equals(val, this.#val)) return;
100
- this.#val = val;
101
- this.#root._queue(this.#id);
102
- }
103
- };
104
- var Computation = class extends Scope {
105
- #root;
106
- #id;
107
- #val;
108
- #fn;
109
- /* @internal */
110
- _effect = false;
111
- /* @internal */
112
- _sources = 0;
113
- /* @internal */
114
- _dirty = true;
115
- /* @internal destroyed */
116
- _d = false;
117
- constructor(compute, val, effect2) {
118
- if (!ROOT) ROOT = new Root();
119
- super();
120
- this.#root = ROOT;
121
- this.#fn = compute;
122
- this.#val = val;
123
- this.#id = this.#root._ac(this);
124
- if (effect2) {
125
- this._effect = effect2;
126
- this.val;
127
- }
128
- }
129
- get val() {
130
- this.#root._flush();
131
- const prevCurrent = COMPUTED;
132
- if (this._dirty) {
133
- super._dispose();
134
- COMPUTED = this;
135
- this._sources = 0;
136
- this.#val = this.#fn();
137
- this._dirty = false;
138
- COMPUTED = prevCurrent;
139
- }
140
- if (prevCurrent) {
141
- prevCurrent._sources |= this._sources;
142
- }
143
- return this.#val;
144
- }
145
- get peek() {
146
- return this.#val;
147
- }
148
- getRoot() {
149
- return this.#root;
150
- }
151
- /* @internal */
152
- _dispose() {
153
- if (this._d) return;
154
- super._dispose();
155
- this._sources = 0;
156
- this._dirty = false;
157
- this._d = true;
158
- this.#root._dc(this.#id);
159
- }
160
- };
161
- function defaultEquality(a, b) {
162
- return a === b;
163
- }
164
- function getScope() {
165
- return COMPUTED || ROOT;
166
- }
167
- function withScope(scope, fn) {
168
- const prevComputed = COMPUTED, prevRoot = ROOT;
169
- if (scope instanceof Computation) COMPUTED = scope;
170
- ROOT = COMPUTED?.getRoot() ?? ROOT;
171
- const result = fn();
172
- COMPUTED = prevComputed;
173
- ROOT = prevRoot;
174
- return result;
175
- }
176
- function onDispose(fn) {
177
- getScope()?._onDispose(fn);
178
- }
179
- function batch(fn) {
180
- if (BATCHING) return fn();
181
- BATCHING = true;
182
- fn();
183
- if (ROOT_QUEUE.length) {
184
- for (const el of ROOT_QUEUE) el._flush(true);
185
- ROOT_QUEUE = [];
186
- }
187
- BATCHING = false;
188
- }
189
- function root(fn, existingRoot) {
190
- const prevRoot = ROOT;
191
- const prevScope = getScope();
192
- ROOT = existingRoot ?? new Root();
193
- prevScope?._onDispose(ROOT._dispose.bind(ROOT));
194
- const result = fn(ROOT._dispose.bind(ROOT));
195
- ROOT = prevRoot;
196
- return result;
197
- }
198
- function signal(value) {
199
- return new DataSignal(value);
200
- }
201
- function computed(val) {
202
- return new Computation(val);
203
- }
204
- function effect(fn) {
205
- const sig = new Computation(fn, void 0, true);
206
- return sig._dispose.bind(sig);
207
- }
1
+ import { a as computed, c as signal, i as batch, n as FlatRoot, o as effect, r as FlatSignal, s as scoped, t as FlatCompute } from "./src-CJj34M6F.js";
208
2
 
209
- export { Computation, DataSignal, Root, Scope, batch, computed, effect, getScope, onDispose, root, signal, withScope };
3
+ export { FlatCompute, FlatRoot, FlatSignal, batch, computed, effect, scoped, signal };
@@ -0,0 +1,11 @@
1
+ import { n as FlatRoot, r as FlatSignal, t as FlatCompute } from "./index-BUz21f61.js";
2
+
3
+ //#region src/react/index.d.ts
4
+ declare function useFlatReader<T>(signal: FlatSignal<T> | FlatCompute<T>, isEqual?: (a: T, b: T) => boolean): T;
5
+ declare function useFlatWriter<T>(signal: FlatSignal<T>): (val: T | ((oldVal: T) => T)) => void;
6
+ declare function useFlatSignal<T>(signal: FlatSignal<T>): readonly [T, (val: T | ((oldVal: T) => T)) => void];
7
+ declare function useFlatEffect(fn: () => undefined | (() => void)): void;
8
+ declare function useFlatScope<T>(callback: () => T, scope?: FlatRoot): T;
9
+ //#endregion
10
+ export { useFlatEffect, useFlatReader, useFlatScope, useFlatSignal, useFlatWriter };
11
+ //# sourceMappingURL=react.d.ts.map
package/dist/react.js ADDED
@@ -0,0 +1,43 @@
1
+ import { o as effect, s as scoped } from "./src-CJj34M6F.js";
2
+ import { useCallback, useEffect, useMemo, useRef, useSyncExternalStore } from "react";
3
+
4
+ //#region src/react/index.ts
5
+ function useFlatReader(signal, isEqual = Object.is) {
6
+ const lastValueRef = useRef(signal.peek);
7
+ return useSyncExternalStore(useCallback((onStoreChange) => scoped(() => effect(() => {
8
+ const newValue = signal.val;
9
+ if (!isEqual(lastValueRef.current, newValue)) {
10
+ lastValueRef.current = newValue;
11
+ onStoreChange();
12
+ }
13
+ }), signal.root), [signal, isEqual]), () => signal.val, () => signal.peek);
14
+ }
15
+ function useFlatWriter(signal) {
16
+ return useCallback((val) => {
17
+ if (typeof val === "function") signal.val = val(signal.peek);
18
+ else signal.val = val;
19
+ }, [signal]);
20
+ }
21
+ function useFlatSignal(signal) {
22
+ return [useFlatReader(signal), useFlatWriter(signal)];
23
+ }
24
+ function useFlatEffect(fn) {
25
+ useEffect(() => {
26
+ let cleanup;
27
+ const stop = effect(() => {
28
+ if (cleanup) cleanup();
29
+ cleanup = fn();
30
+ });
31
+ return () => {
32
+ if (cleanup) cleanup();
33
+ stop();
34
+ };
35
+ }, [fn]);
36
+ }
37
+ function useFlatScope(callback, scope) {
38
+ return useMemo(() => scoped(callback, scope), [callback, scope]);
39
+ }
40
+
41
+ //#endregion
42
+ export { useFlatEffect, useFlatReader, useFlatScope, useFlatSignal, useFlatWriter };
43
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","names":["cleanup: undefined | (() => void)"],"sources":["../src/react/index.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\nimport {\n effect,\n type FlatCompute,\n type FlatRoot,\n type FlatSignal,\n scoped,\n} from \"../index.js\";\n\nexport function useFlatReader<T>(\n signal: FlatSignal<T> | FlatCompute<T>,\n isEqual: (a: T, b: T) => boolean = Object.is\n): T {\n const lastValueRef = useRef<T>(signal.peek);\n\n return useSyncExternalStore(\n useCallback(\n (onStoreChange) =>\n scoped(\n () =>\n effect(() => {\n const newValue = signal.val;\n if (!isEqual(lastValueRef.current, newValue)) {\n lastValueRef.current = newValue;\n onStoreChange();\n }\n }),\n signal.root\n ),\n [signal, isEqual]\n ),\n () => signal.val,\n () => signal.peek\n );\n}\n\nexport function useFlatWriter<T>(\n signal: FlatSignal<T>\n): (val: T | ((oldVal: T) => T)) => void {\n return useCallback(\n (val) => {\n if (typeof val === \"function\") {\n signal.val = (val as (oldVal: T) => T)(signal.peek);\n } else {\n signal.val = val;\n }\n },\n [signal]\n );\n}\n\nexport function useFlatSignal<T>(signal: FlatSignal<T>) {\n const reader = useFlatReader(signal);\n const writer = useFlatWriter(signal);\n return [reader, writer] as const;\n}\n\nexport function useFlatEffect(fn: () => undefined | (() => void)): void {\n useEffect(() => {\n let cleanup: undefined | (() => void);\n const stop = effect(() => {\n if (cleanup) cleanup();\n cleanup = fn();\n });\n\n return () => {\n if (cleanup) cleanup();\n stop();\n };\n }, [fn]);\n}\n\nexport function useFlatScope<T>(callback: () => T, scope?: FlatRoot): T {\n return useMemo(() => scoped(callback, scope), [callback, scope]);\n}\n"],"mappings":";;;;AAeA,SAAgB,cACd,QACA,UAAmC,OAAO,IACvC;CACH,MAAM,eAAe,OAAU,OAAO,KAAK;AAE3C,QAAO,qBACL,aACG,kBACC,aAEI,aAAa;EACX,MAAM,WAAW,OAAO;AACxB,MAAI,CAAC,QAAQ,aAAa,SAAS,SAAS,EAAE;AAC5C,gBAAa,UAAU;AACvB,kBAAe;;GAEjB,EACJ,OAAO,KACR,EACH,CAAC,QAAQ,QAAQ,CAClB,QACK,OAAO,WACP,OAAO,KACd;;AAGH,SAAgB,cACd,QACuC;AACvC,QAAO,aACJ,QAAQ;AACP,MAAI,OAAO,QAAQ,WACjB,QAAO,MAAO,IAAyB,OAAO,KAAK;MAEnD,QAAO,MAAM;IAGjB,CAAC,OAAO,CACT;;AAGH,SAAgB,cAAiB,QAAuB;AAGtD,QAAO,CAFQ,cAAc,OAAO,EACrB,cAAc,OAAO,CACb;;AAGzB,SAAgB,cAAc,IAA0C;AACtE,iBAAgB;EACd,IAAIA;EACJ,MAAM,OAAO,aAAa;AACxB,OAAI,QAAS,UAAS;AACtB,aAAU,IAAI;IACd;AAEF,eAAa;AACX,OAAI,QAAS,UAAS;AACtB,SAAM;;IAEP,CAAC,GAAG,CAAC;;AAGV,SAAgB,aAAgB,UAAmB,OAAqB;AACtE,QAAO,cAAc,OAAO,UAAU,MAAM,EAAE,CAAC,UAAU,MAAM,CAAC"}
@@ -0,0 +1,145 @@
1
+ //#region src/index.ts
2
+ let ROOT = null, COMPUTED = null, BATCHING = false, ROOT_QUEUE = null;
3
+ var FlatRoot = class {
4
+ _c = [];
5
+ _x = [];
6
+ _i = 0;
7
+ #batch = 0;
8
+ dispose() {
9
+ this._c = [];
10
+ this._x = [];
11
+ this._i = 0;
12
+ }
13
+ _as() {
14
+ return this._i++ % 32;
15
+ }
16
+ _ac(c) {
17
+ if (this._x.length) {
18
+ const u = this._x.pop();
19
+ this._c[u] = c;
20
+ return u;
21
+ } else return this._c.push(c) - 1;
22
+ }
23
+ _dc(idx) {
24
+ this._x.push(idx);
25
+ }
26
+ _queue(mask) {
27
+ if (!this.#batch) ROOT_QUEUE ??= this;
28
+ this.#batch |= mask;
29
+ if (!BATCHING) this._flush(true);
30
+ }
31
+ _flush(force = false) {
32
+ if (!this.#batch || !force) return;
33
+ for (const item of this._c) if (!item._dirty && (item._sources & this.#batch) !== 0) {
34
+ item._dirty = true;
35
+ if (item._effect) item.val;
36
+ }
37
+ this.#batch = 0;
38
+ }
39
+ };
40
+ var FlatSignal = class {
41
+ #root;
42
+ #val;
43
+ #id = 0;
44
+ equals = defaultEquality;
45
+ constructor(val) {
46
+ if (!ROOT) ROOT = new FlatRoot();
47
+ this.#root = ROOT;
48
+ this.#val = val;
49
+ this.#id |= 1 << this.#root._as();
50
+ }
51
+ get val() {
52
+ if (COMPUTED) COMPUTED._sources |= this.#id;
53
+ return this.#val;
54
+ }
55
+ get peek() {
56
+ return this.#val;
57
+ }
58
+ get root() {
59
+ return this.#root;
60
+ }
61
+ set val(val) {
62
+ if (this.equals(val, this.#val)) return;
63
+ this.#val = val;
64
+ this.#root._queue(this.#id);
65
+ }
66
+ };
67
+ var FlatCompute = class {
68
+ #root;
69
+ #id;
70
+ #val;
71
+ #fn;
72
+ _effect = false;
73
+ _sources = 0;
74
+ _dirty = true;
75
+ _d = false;
76
+ constructor(compute, val, effect$1) {
77
+ if (!ROOT) ROOT = new FlatRoot();
78
+ this.#root = ROOT;
79
+ this.#fn = compute;
80
+ this.#val = val;
81
+ this.#id = this.#root._ac(this);
82
+ if (effect$1) {
83
+ this._effect = effect$1;
84
+ this.val;
85
+ }
86
+ }
87
+ get val() {
88
+ this.#root._flush();
89
+ const prevCurrent = COMPUTED;
90
+ if (this._dirty) {
91
+ COMPUTED = this;
92
+ this._sources = 0;
93
+ this.#val = this.#fn();
94
+ this._dirty = false;
95
+ COMPUTED = prevCurrent;
96
+ }
97
+ if (prevCurrent) prevCurrent._sources |= this._sources;
98
+ return this.#val;
99
+ }
100
+ get peek() {
101
+ return this.#val;
102
+ }
103
+ get root() {
104
+ return this.#root;
105
+ }
106
+ dispose() {
107
+ if (this._d) return;
108
+ this._sources = 0;
109
+ this._dirty = false;
110
+ this._d = true;
111
+ this.#root._dc(this.#id);
112
+ }
113
+ };
114
+ function defaultEquality(a, b) {
115
+ return a === b;
116
+ }
117
+ function batch(fn) {
118
+ if (BATCHING) return fn();
119
+ BATCHING = true;
120
+ fn();
121
+ ROOT_QUEUE?._flush(true);
122
+ ROOT_QUEUE = null;
123
+ BATCHING = false;
124
+ }
125
+ function scoped(fn, scope) {
126
+ const prevRoot = ROOT;
127
+ ROOT = scope ?? new FlatRoot();
128
+ const result = fn();
129
+ ROOT = prevRoot;
130
+ return result;
131
+ }
132
+ function signal(value) {
133
+ return new FlatSignal(value);
134
+ }
135
+ function computed(val) {
136
+ return new FlatCompute(val);
137
+ }
138
+ function effect(fn) {
139
+ const sig = new FlatCompute(fn, void 0, true);
140
+ return sig.dispose.bind(sig);
141
+ }
142
+
143
+ //#endregion
144
+ export { computed as a, signal as c, batch as i, FlatRoot as n, effect as o, FlatSignal as r, scoped as s, FlatCompute as t };
145
+ //# sourceMappingURL=src-CJj34M6F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-CJj34M6F.js","names":["ROOT: FlatRoot | null","COMPUTED: FlatCompute | null","ROOT_QUEUE: FlatRoot | null","#batch","#root","#val","#id","#fn","effect"],"sources":["../src/index.ts"],"sourcesContent":["let ROOT: FlatRoot | null = null,\n\tCOMPUTED: FlatCompute | null = null,\n\tBATCHING = false,\n\tROOT_QUEUE: FlatRoot | null = null;\n\nexport class FlatRoot {\n\t/* @internal computeds */\n\t_c: Array<FlatCompute> = [];\n\t/* @internal disposed computeds */\n\t_x: Array<number> = [];\n\t/* @internal id generator */\n\t_i = 0;\n\t/* @internal batch mask */\n\t#batch: number = 0;\n\n\tdispose() {\n\t\tthis._c = [];\n\t\tthis._x = [];\n\t\tthis._i = 0;\n\t}\n\n\t/* @internal Add source */\n\t_as() {\n\t\treturn this._i++ % 32;\n\t}\n\n\t/* @internal Add computed */\n\t_ac(c: FlatCompute) {\n\t\tif (this._x.length) {\n\t\t\tconst u = this._x.pop()!;\n\t\t\tthis._c[u] = c;\n\t\t\treturn u;\n\t\t} else {\n\t\t\treturn this._c.push(c) - 1;\n\t\t}\n\t}\n\n\t/* @internal Destroy computed */\n\t_dc(idx: number) {\n\t\tthis._x.push(idx);\n\t}\n\n\t/* @internal */\n\t_queue(mask: number) {\n\t\tif (!this.#batch) {\n\t\t\tROOT_QUEUE ??= this;\n\t\t}\n\t\tthis.#batch |= mask;\n\t\tif (!BATCHING) this._flush(true);\n\t}\n\n\t/* @internal */\n\t_flush(force: boolean = false) {\n\t\tif (!this.#batch || !force) return;\n\t\tfor (const item of this._c) {\n\t\t\tif (!item._dirty && (item._sources & this.#batch) !== 0) {\n\t\t\t\titem._dirty = true;\n\t\t\t\tif (item._effect) item.val;\n\t\t\t}\n\t\t}\n\t\tthis.#batch = 0;\n\t}\n}\n\nexport class FlatSignal<T = any> {\n\t#root: FlatRoot;\n\t#val: T;\n\t#id = 0;\n\tequals = defaultEquality;\n\n\tconstructor(val?: T) {\n\t\tif (!ROOT) ROOT = new FlatRoot();\n\t\tthis.#root = ROOT;\n\t\tthis.#val = val as T;\n\t\tthis.#id |= 1 << this.#root._as();\n\t}\n\n\tget val(): T {\n\t\tif (COMPUTED) {\n\t\t\tCOMPUTED._sources |= this.#id;\n\t\t}\n\t\treturn this.#val as T;\n\t}\n\n\tget peek() {\n\t\treturn this.#val;\n\t}\n\n\tget root() {\n\t\treturn this.#root;\n\t}\n\n\tset val(val: T) {\n\t\tif (this.equals(val, this.#val)) return;\n\t\tthis.#val = val as T;\n\t\tthis.#root._queue(this.#id);\n\t}\n}\n\nexport class FlatCompute<T = unknown> {\n\t#root: FlatRoot;\n\t#id: number;\n\t#val: T;\n\t#fn: (() => T) | undefined;\n\t/* @internal */\n\t_effect: boolean = false;\n\t/* @internal */\n\t_sources: number = 0;\n\t/* @internal */\n\t_dirty = true;\n\t/* @internal destroyed */\n\t_d = false;\n\n\tconstructor(compute?: () => T, val?: T, effect?: boolean) {\n\t\tif (!ROOT) ROOT = new FlatRoot();\n\t\tthis.#root = ROOT;\n\t\tthis.#fn = compute;\n\t\tthis.#val = val!;\n\t\tthis.#id = this.#root._ac(this as FlatCompute<unknown>);\n\t\tif (effect) {\n\t\t\tthis._effect = effect;\n\t\t\tthis.val;\n\t\t}\n\t}\n\n\tget val(): T {\n\t\tthis.#root._flush();\n\t\tconst prevCurrent = COMPUTED;\n\t\tif (this._dirty) {\n\t\t\tCOMPUTED = this as FlatCompute<unknown>;\n\t\t\tthis._sources = 0;\n\t\t\tthis.#val = this.#fn!();\n\t\t\tthis._dirty = false;\n\t\t\tCOMPUTED = prevCurrent;\n\t\t}\n\t\tif (prevCurrent) {\n\t\t\tprevCurrent._sources |= this._sources;\n\t\t}\n\t\treturn this.#val!;\n\t}\n\n\tget peek() {\n\t\treturn this.#val;\n\t}\n\n\tget root() {\n\t\treturn this.#root;\n\t}\n\n\tdispose() {\n\t\tif (this._d) return;\n\t\tthis._sources = 0;\n\t\tthis._dirty = false;\n\t\tthis._d = true;\n\t\tthis.#root._dc(this.#id);\n\t}\n}\n\nfunction defaultEquality(a: unknown, b: unknown) {\n\treturn a === b;\n}\n\nexport function batch(fn: () => void) {\n\tif (BATCHING) return fn();\n\tBATCHING = true;\n\tfn();\n\tROOT_QUEUE?._flush(true);\n\tROOT_QUEUE = null;\n\tBATCHING = false;\n}\n\nexport function scoped<T>(fn: () => T, scope?: FlatRoot): T {\n\tconst prevRoot = ROOT;\n\tROOT = scope ?? new FlatRoot();\n\tconst result = fn();\n\tROOT = prevRoot;\n\treturn result;\n}\n\nexport function signal<T>(value: T): FlatSignal<T>;\nexport function signal<T = undefined>(): FlatSignal<T | undefined>;\nexport function signal<T>(value?: T): FlatSignal<T> {\n\treturn new FlatSignal(value);\n}\n\nexport function computed<T>(val: () => T): FlatCompute<T> {\n\treturn new FlatCompute(val);\n}\n\nexport function effect<T = unknown>(fn: () => T) {\n\tconst sig = new FlatCompute(fn, undefined, true);\n\treturn sig.dispose.bind(sig);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,39 +1,64 @@
1
1
  {
2
- "name": "flatsignals",
3
- "version": "0.1.0",
4
- "description": "FlatSignals is an extremely fast reactivity library (~0.7kb)",
5
- "main": "dist/index.cjs",
6
- "module": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "files": [
9
- "dist"
10
- ],
11
- "type": "module",
12
- "scripts": {
13
- "build": "tsup",
14
- "dev": "tsup --watch",
15
- "test": "vitest run",
16
- "bench": "vitest bench",
17
- "test:watch": "vitest",
18
- "size": "size-limit"
19
- },
20
- "license": "MIT",
21
- "devDependencies": {
22
- "@maverick-js/signals": "^6.0.0",
23
- "@preact/signals-core": "^1.12.1",
24
- "@reactively/core": "^0.0.8",
25
- "@size-limit/preset-small-lib": "^11.2.0",
26
- "@types/node": "^22.18.11",
27
- "alien-signals": "^3.0.1",
28
- "size-limit": "^11.2.0",
29
- "tsup": "^8.5.0",
30
- "typescript": "^5.9.3",
31
- "vitest": "^2.1.9"
32
- },
33
- "size-limit": [
34
- {
35
- "path": "dist/index.js",
36
- "limit": "1 kB"
37
- }
38
- ]
2
+ "name": "flatsignals",
3
+ "version": "0.2.1",
4
+ "description": "FlatSignals is an extremely fast reactivity library (~0.7kb)",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./react": {
17
+ "import": "./dist/react.js",
18
+ "types": "./dist/react.d.ts"
19
+ }
20
+ },
21
+ "type": "module",
22
+ "scripts": {
23
+ "build": "tsdown",
24
+ "dev": "tsdown --watch",
25
+ "test": "vitest run",
26
+ "bench": "vitest bench",
27
+ "test:watch": "vitest",
28
+ "size": "size-limit"
29
+ },
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "@angular/core": "^20.3.7",
33
+ "@biomejs/biome": "2.2.6",
34
+ "@maverick-js/signals": "^6.0.0",
35
+ "@preact/signals-core": "^1.12.1",
36
+ "@reactively/core": "^0.0.8",
37
+ "@size-limit/preset-small-lib": "^11.2.0",
38
+ "@solidjs/signals": "^0.7.5",
39
+ "@types/node": "^22.18.12",
40
+ "@types/react": "^19.2.2",
41
+ "@vue/reactivity": "^3.5.22",
42
+ "alien-signals": "^3.0.3",
43
+ "react": "^19.2.0",
44
+ "size-limit": "^11.2.0",
45
+ "solid-js": "^1.9.9",
46
+ "tsdown": "^0.15.9",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^2.1.9"
49
+ },
50
+ "peerDependencies": {
51
+ "react": "*"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "react": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "size-limit": [
59
+ {
60
+ "path": "dist/index.js",
61
+ "limit": "1 kB"
62
+ }
63
+ ]
39
64
  }
package/dist/index.cjs DELETED
@@ -1,222 +0,0 @@
1
- 'use strict';
2
-
3
- // src/index.ts
4
- var ROOT = null;
5
- var COMPUTED = null;
6
- var BATCHING = false;
7
- var ROOT_QUEUE = [];
8
- var Scope = class {
9
- /* @internal */
10
- _disposing = false;
11
- /* @internal */
12
- _disposals = null;
13
- constructor() {
14
- getScope()?._onDispose(this._dispose.bind(this));
15
- }
16
- /* @internal */
17
- _dispose() {
18
- if (this._disposing) return;
19
- this._disposing = true;
20
- this._disposals?.forEach((fn) => fn());
21
- this._disposing = false;
22
- }
23
- /* @internal */
24
- _onDispose(fn) {
25
- if (!this._disposals) this._disposals = [];
26
- this._disposals.push(fn);
27
- }
28
- };
29
- var Root = class extends Scope {
30
- /* @internal computeds */
31
- _c = [];
32
- /* @internal disposed computeds */
33
- _x = [];
34
- /* @internal id generator */
35
- _i = 0;
36
- /* @internal batch mask */
37
- #batch = 0;
38
- /* @internal */
39
- _dispose() {
40
- super._dispose();
41
- this._c = [];
42
- this._x = [];
43
- this._i = 0;
44
- }
45
- /* @internal Add source */
46
- _as() {
47
- return this._i++ % 32;
48
- }
49
- /* @internal Add computed */
50
- _ac(c) {
51
- if (this._x.length) {
52
- const u = this._x.pop();
53
- this._c[u] = c;
54
- return u;
55
- } else {
56
- return this._c.push(c) - 1;
57
- }
58
- }
59
- /* @internal Destroy computed */
60
- _dc(idx) {
61
- this._x.push(idx);
62
- }
63
- /* @internal */
64
- _queue(mask) {
65
- if (!this.#batch) {
66
- ROOT_QUEUE.push(this);
67
- }
68
- this.#batch |= mask;
69
- if (!BATCHING) this._flush(true);
70
- }
71
- /* @internal */
72
- _flush(force = false) {
73
- if (!this.#batch || !force) return;
74
- for (const item of this._c) {
75
- if (!item._dirty && (item._sources & this.#batch) !== 0) {
76
- item._dirty = true;
77
- if (item._effect) item.val;
78
- }
79
- }
80
- this.#batch = 0;
81
- }
82
- };
83
- var DataSignal = class {
84
- #root;
85
- #val;
86
- #id = 0;
87
- equals = defaultEquality;
88
- constructor(val) {
89
- if (!ROOT) ROOT = new Root();
90
- this.#root = ROOT;
91
- this.#val = val;
92
- this.#id |= 1 << this.#root._as();
93
- }
94
- get val() {
95
- if (COMPUTED) {
96
- COMPUTED._sources |= this.#id;
97
- }
98
- return this.#val;
99
- }
100
- set val(val) {
101
- if (this.equals(val, this.#val)) return;
102
- this.#val = val;
103
- this.#root._queue(this.#id);
104
- }
105
- };
106
- var Computation = class extends Scope {
107
- #root;
108
- #id;
109
- #val;
110
- #fn;
111
- /* @internal */
112
- _effect = false;
113
- /* @internal */
114
- _sources = 0;
115
- /* @internal */
116
- _dirty = true;
117
- /* @internal destroyed */
118
- _d = false;
119
- constructor(compute, val, effect2) {
120
- if (!ROOT) ROOT = new Root();
121
- super();
122
- this.#root = ROOT;
123
- this.#fn = compute;
124
- this.#val = val;
125
- this.#id = this.#root._ac(this);
126
- if (effect2) {
127
- this._effect = effect2;
128
- this.val;
129
- }
130
- }
131
- get val() {
132
- this.#root._flush();
133
- const prevCurrent = COMPUTED;
134
- if (this._dirty) {
135
- super._dispose();
136
- COMPUTED = this;
137
- this._sources = 0;
138
- this.#val = this.#fn();
139
- this._dirty = false;
140
- COMPUTED = prevCurrent;
141
- }
142
- if (prevCurrent) {
143
- prevCurrent._sources |= this._sources;
144
- }
145
- return this.#val;
146
- }
147
- get peek() {
148
- return this.#val;
149
- }
150
- getRoot() {
151
- return this.#root;
152
- }
153
- /* @internal */
154
- _dispose() {
155
- if (this._d) return;
156
- super._dispose();
157
- this._sources = 0;
158
- this._dirty = false;
159
- this._d = true;
160
- this.#root._dc(this.#id);
161
- }
162
- };
163
- function defaultEquality(a, b) {
164
- return a === b;
165
- }
166
- function getScope() {
167
- return COMPUTED || ROOT;
168
- }
169
- function withScope(scope, fn) {
170
- const prevComputed = COMPUTED, prevRoot = ROOT;
171
- if (scope instanceof Computation) COMPUTED = scope;
172
- ROOT = COMPUTED?.getRoot() ?? ROOT;
173
- const result = fn();
174
- COMPUTED = prevComputed;
175
- ROOT = prevRoot;
176
- return result;
177
- }
178
- function onDispose(fn) {
179
- getScope()?._onDispose(fn);
180
- }
181
- function batch(fn) {
182
- if (BATCHING) return fn();
183
- BATCHING = true;
184
- fn();
185
- if (ROOT_QUEUE.length) {
186
- for (const el of ROOT_QUEUE) el._flush(true);
187
- ROOT_QUEUE = [];
188
- }
189
- BATCHING = false;
190
- }
191
- function root(fn, existingRoot) {
192
- const prevRoot = ROOT;
193
- const prevScope = getScope();
194
- ROOT = existingRoot ?? new Root();
195
- prevScope?._onDispose(ROOT._dispose.bind(ROOT));
196
- const result = fn(ROOT._dispose.bind(ROOT));
197
- ROOT = prevRoot;
198
- return result;
199
- }
200
- function signal(value) {
201
- return new DataSignal(value);
202
- }
203
- function computed(val) {
204
- return new Computation(val);
205
- }
206
- function effect(fn) {
207
- const sig = new Computation(fn, void 0, true);
208
- return sig._dispose.bind(sig);
209
- }
210
-
211
- exports.Computation = Computation;
212
- exports.DataSignal = DataSignal;
213
- exports.Root = Root;
214
- exports.Scope = Scope;
215
- exports.batch = batch;
216
- exports.computed = computed;
217
- exports.effect = effect;
218
- exports.getScope = getScope;
219
- exports.onDispose = onDispose;
220
- exports.root = root;
221
- exports.signal = signal;
222
- exports.withScope = withScope;
package/dist/index.d.cts DELETED
@@ -1,32 +0,0 @@
1
- declare class Scope {
2
- constructor();
3
- }
4
- declare class Root extends Scope {
5
- #private;
6
- }
7
- declare class DataSignal<T = any> {
8
- #private;
9
- equals: typeof defaultEquality;
10
- constructor(val?: T);
11
- get val(): T;
12
- set val(val: T);
13
- }
14
- declare class Computation<T = unknown> extends Scope {
15
- #private;
16
- constructor(compute?: () => T, val?: T, effect?: boolean);
17
- get val(): T;
18
- get peek(): T;
19
- getRoot(): Root;
20
- }
21
- declare function defaultEquality(a: unknown, b: unknown): boolean;
22
- declare function getScope(): Scope | null;
23
- declare function withScope(scope: Scope, fn: () => void): void;
24
- declare function onDispose(fn: () => void): void;
25
- declare function batch(fn: () => void): void;
26
- declare function root<T>(fn: (dispose: () => void) => T, existingRoot?: Root): T;
27
- declare function signal<T>(value: T): DataSignal<T>;
28
- declare function signal<T = undefined>(): DataSignal<T | undefined>;
29
- declare function computed<T>(val: () => T): Computation<T>;
30
- declare function effect<T = unknown>(fn: () => T): () => void;
31
-
32
- export { Computation, DataSignal, Root, Scope, batch, computed, effect, getScope, onDispose, root, signal, withScope };