@vielzeug/stateit 2.0.0 → 2.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 +54 -295
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -9
- package/dist/stateit.cjs +1 -1
- package/dist/stateit.cjs.map +1 -1
- package/dist/stateit.d.ts +17 -0
- package/dist/stateit.d.ts.map +1 -0
- package/dist/stateit.js +180 -236
- package/dist/stateit.js.map +1 -1
- package/dist/types.d.ts +19 -20
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -3
- package/dist/batch.cjs +0 -2
- package/dist/batch.cjs.map +0 -1
- package/dist/batch.d.ts +0 -5
- package/dist/batch.d.ts.map +0 -1
- package/dist/batch.js +0 -28
- package/dist/batch.js.map +0 -1
- package/dist/computed.cjs +0 -2
- package/dist/computed.cjs.map +0 -1
- package/dist/computed.d.ts +0 -58
- package/dist/computed.d.ts.map +0 -1
- package/dist/computed.js +0 -65
- package/dist/computed.js.map +0 -1
- package/dist/effect.cjs +0 -2
- package/dist/effect.cjs.map +0 -1
- package/dist/effect.d.ts +0 -31
- package/dist/effect.d.ts.map +0 -1
- package/dist/effect.js +0 -53
- package/dist/effect.js.map +0 -1
- package/dist/runtime.cjs +0 -2
- package/dist/runtime.cjs.map +0 -1
- package/dist/runtime.d.ts +0 -40
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -47
- package/dist/runtime.js.map +0 -1
- package/dist/signal.cjs +0 -2
- package/dist/signal.cjs.map +0 -1
- package/dist/signal.d.ts +0 -26
- package/dist/signal.d.ts.map +0 -1
- package/dist/signal.js +0 -40
- package/dist/signal.js.map +0 -1
- package/dist/store.cjs +0 -2
- package/dist/store.cjs.map +0 -1
- package/dist/store.d.ts +0 -32
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -51
- package/dist/store.js.map +0 -1
- package/dist/types.cjs +0 -2
- package/dist/types.cjs.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
- package/dist/watch.cjs +0 -2
- package/dist/watch.cjs.map +0 -1
- package/dist/watch.d.ts +0 -36
- package/dist/watch.d.ts.map +0 -1
- package/dist/watch.js +0 -32
- package/dist/watch.js.map +0 -1
package/dist/batch.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch.cjs","names":[],"sources":["../src/batch.ts"],"sourcesContent":["import { _DEV, queue } from './runtime';\n\n/** @internal Drain and run all pending effects from the batch queue, collecting errors. */\nexport const _flushPending = (): void => {\n const toFlush = [...queue.pending];\n\n queue.pending.clear();\n\n const errors: unknown[] = [];\n\n for (const f of toFlush) {\n try {\n f();\n } catch (e) {\n errors.push(e);\n }\n }\n\n if (errors.length) throw errors.length === 1 ? errors[0] : new AggregateError(errors, '[stateit] batch errors');\n};\n\n/** Runs fn and defers all Signal notifications until fn returns, then flushes once. */\nexport const batch = <T>(fn: () => T): T => {\n queue.depth++;\n\n try {\n const result = fn();\n\n if (--queue.depth === 0) _flushPending();\n\n return result;\n } catch (e) {\n if (--queue.depth === 0) {\n try {\n _flushPending();\n } catch (flushErr) {\n if (_DEV)\n console.error(\n '[stateit] batch: a secondary flush error was suppressed (callback error takes precedence)',\n flushErr,\n );\n }\n }\n\n throw e;\n }\n};\n"],"mappings":"iCAGA,IAAa,MAA4B,CACvC,IAAM,EAAU,CAAC,GAAG,EAAA,MAAM,QAAQ,CAElC,EAAA,MAAM,QAAQ,OAAO,CAErB,IAAM,EAAoB,EAAE,CAE5B,IAAK,IAAM,KAAK,EACd,GAAI,CACF,GAAG,OACI,EAAG,CACV,EAAO,KAAK,EAAE,CAIlB,GAAI,EAAO,OAAQ,MAAM,EAAO,SAAW,EAAI,EAAO,GAAS,eAAe,EAAQ,yBAAyB,EAIpG,EAAY,GAAmB,CAC1C,EAAA,MAAM,QAEN,GAAI,CACF,IAAM,EAAS,GAAI,CAInB,MAFI,EAAE,EAAA,MAAM,QAAU,GAAG,GAAe,CAEjC,QACA,EAAG,CACV,GAAI,EAAE,EAAA,MAAM,QAAU,EACpB,GAAI,CACF,GAAe,MACE,EASrB,MAAM"}
|
package/dist/batch.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/** @internal Drain and run all pending effects from the batch queue, collecting errors. */
|
|
2
|
-
export declare const _flushPending: () => void;
|
|
3
|
-
/** Runs fn and defers all Signal notifications until fn returns, then flushes once. */
|
|
4
|
-
export declare const batch: <T>(fn: () => T) => T;
|
|
5
|
-
//# sourceMappingURL=batch.d.ts.map
|
package/dist/batch.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AAEA,2FAA2F;AAC3F,eAAO,MAAM,aAAa,QAAO,IAgBhC,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,IAAI,MAAM,CAAC,KAAG,CAwBtC,CAAC"}
|
package/dist/batch.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { queue as e } from "./runtime.js";
|
|
2
|
-
//#region src/batch.ts
|
|
3
|
-
var t = () => {
|
|
4
|
-
let t = [...e.pending];
|
|
5
|
-
e.pending.clear();
|
|
6
|
-
let n = [];
|
|
7
|
-
for (let e of t) try {
|
|
8
|
-
e();
|
|
9
|
-
} catch (e) {
|
|
10
|
-
n.push(e);
|
|
11
|
-
}
|
|
12
|
-
if (n.length) throw n.length === 1 ? n[0] : AggregateError(n, "[stateit] batch errors");
|
|
13
|
-
}, n = (n) => {
|
|
14
|
-
e.depth++;
|
|
15
|
-
try {
|
|
16
|
-
let r = n();
|
|
17
|
-
return --e.depth === 0 && t(), r;
|
|
18
|
-
} catch (n) {
|
|
19
|
-
if (--e.depth === 0) try {
|
|
20
|
-
t();
|
|
21
|
-
} catch {}
|
|
22
|
-
throw n;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
//#endregion
|
|
26
|
-
export { t as _flushPending, n as batch };
|
|
27
|
-
|
|
28
|
-
//# sourceMappingURL=batch.js.map
|
package/dist/batch.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"batch.js","names":[],"sources":["../src/batch.ts"],"sourcesContent":["import { _DEV, queue } from './runtime';\n\n/** @internal Drain and run all pending effects from the batch queue, collecting errors. */\nexport const _flushPending = (): void => {\n const toFlush = [...queue.pending];\n\n queue.pending.clear();\n\n const errors: unknown[] = [];\n\n for (const f of toFlush) {\n try {\n f();\n } catch (e) {\n errors.push(e);\n }\n }\n\n if (errors.length) throw errors.length === 1 ? errors[0] : new AggregateError(errors, '[stateit] batch errors');\n};\n\n/** Runs fn and defers all Signal notifications until fn returns, then flushes once. */\nexport const batch = <T>(fn: () => T): T => {\n queue.depth++;\n\n try {\n const result = fn();\n\n if (--queue.depth === 0) _flushPending();\n\n return result;\n } catch (e) {\n if (--queue.depth === 0) {\n try {\n _flushPending();\n } catch (flushErr) {\n if (_DEV)\n console.error(\n '[stateit] batch: a secondary flush error was suppressed (callback error takes precedence)',\n flushErr,\n );\n }\n }\n\n throw e;\n }\n};\n"],"mappings":";;AAGA,IAAa,UAA4B;CACvC,IAAM,IAAU,CAAC,GAAG,EAAM,QAAQ;AAElC,GAAM,QAAQ,OAAO;CAErB,IAAM,IAAoB,EAAE;AAE5B,MAAK,IAAM,KAAK,EACd,KAAI;AACF,KAAG;UACI,GAAG;AACV,IAAO,KAAK,EAAE;;AAIlB,KAAI,EAAO,OAAQ,OAAM,EAAO,WAAW,IAAI,EAAO,KAAS,eAAe,GAAQ,yBAAyB;GAIpG,KAAY,MAAmB;AAC1C,GAAM;AAEN,KAAI;EACF,IAAM,IAAS,GAAI;AAInB,SAFI,EAAE,EAAM,UAAU,KAAG,GAAe,EAEjC;UACA,GAAG;AACV,MAAI,EAAE,EAAM,UAAU,EACpB,KAAI;AACF,MAAe;UACE;AASrB,QAAM"}
|
package/dist/computed.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./runtime.cjs`),t=require(`./types.cjs`);var n=class extends e.ReactiveNode{[t._SIGNAL_BRAND]=!0;#e;#t=e._UNINITIALIZED;#n=!0;#r=!1;#i;#a=new Set;#o=()=>{this.#n||(this.#n=!0,this._notify())};constructor(e,t){super(),this.#e=e,this.#i=t?.equals??Object.is,t?.lazy||this.#s()}#s(){for(let e of this.#a)e();this.#a.clear();let t=e._withCtx(this.#o,this.#a,null,this.#e);this.#n=!1,(this.#t===e._UNINITIALIZED||!this.#i(this.#t,t))&&(this.#t=t)}get value(){return this.#r?this.#t:(this.#n&&this.#s(),this._track(),this.#t)}peek(){if(this.#t===e._UNINITIALIZED){if(this.#r)return;this.#s()}return this.#t}get stale(){return this.#n||this.#r}dispose(){if(!this.#r){this.#r=!0;for(let e of this.#a)e();this.#a.clear()}}[Symbol.dispose](){this.dispose()}},r=(e,t)=>new n(e,t),i=class extends n{#e;constructor(e,t,n){super(e,n),this.#e=t}get value(){return super.value}set value(e){this.#e(e)}update(e){this.#e(e(this.peek()))}},a=(e,t,n)=>new i(e,t,n),o=(e,t,n)=>r(()=>t(...e.map(e=>e.value)),n);exports.ComputedNode=n,exports.WritableNode=i,exports.computed=r,exports.derived=o,exports.writable=a;
|
|
2
|
-
//# sourceMappingURL=computed.cjs.map
|
package/dist/computed.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"computed.cjs","names":["#onDepChange","#dirty","#compute","#equals","#recompute","#deps","#value","#disposed","#set"],"sources":["../src/computed.ts"],"sourcesContent":["import { ReactiveNode, _DEV, _UNINITIALIZED, _withCtx } from './runtime';\nimport {\n type CleanupFn,\n type Disposable,\n type EffectCallback,\n type EqualityFn,\n type ReactiveOptions,\n type ReadonlySignal,\n type Signal,\n _SIGNAL_BRAND,\n} from './types';\n\n/** A derived read-only signal with an explicit dispose method. */\nexport interface ComputedSignal<T> extends ReadonlySignal<T>, Disposable {\n /** True when the computed value is stale (deps changed but not yet re-read) or disposed. */\n readonly stale: boolean;\n}\n\n/** @internal\n * Lazy computed node. Seeded once at construction so .peek() is immediately valid\n * (unless { lazy: true } is passed, in which case first compute defers to first read).\n * - On dep change: marks dirty, notifies downstream (no recompute yet).\n * - On .value read: recomputes if dirty, re-tracks fresh deps.\n * - After dispose: _track() is skipped to prevent leaking outer effects.\n */\nexport class ComputedNode<T> extends ReactiveNode implements ComputedSignal<T> {\n readonly [_SIGNAL_BRAND] = true as const;\n #compute: () => T;\n #value: T | typeof _UNINITIALIZED = _UNINITIALIZED;\n #dirty = true;\n #disposed = false;\n #equals: EqualityFn<T>;\n #deps = new Set<CleanupFn>();\n\n readonly #onDepChange: EffectCallback = () => {\n if (!this.#dirty) {\n this.#dirty = true;\n this._notify();\n }\n };\n\n constructor(compute: () => T, options?: ReactiveOptions<T> & { lazy?: boolean }) {\n super();\n this.#compute = compute;\n this.#equals = options?.equals ?? Object.is;\n\n if (!options?.lazy) this.#recompute(); // seed: ensures peek() is valid immediately\n }\n\n #recompute(): void {\n for (const unsub of this.#deps) unsub();\n this.#deps.clear();\n\n const result = _withCtx(this.#onDepChange, this.#deps, null, this.#compute);\n\n this.#dirty = false;\n\n if (this.#value === _UNINITIALIZED || !this.#equals(this.#value as T, result)) {\n this.#value = result;\n }\n }\n\n get value(): T {\n if (this.#disposed) {\n if (_DEV) console.warn('[stateit] Reading a disposed ComputedSignal returns a stale value.');\n\n return this.#value as T;\n }\n\n if (this.#dirty) this.#recompute();\n\n this._track();\n\n return this.#value as T;\n }\n\n peek(): T {\n if (this.#value === _UNINITIALIZED) {\n if (this.#disposed) {\n if (_DEV)\n console.warn(\n '[stateit] peek() called on a disposed lazy ComputedSignal that was never read — returning undefined.',\n );\n\n return undefined as unknown as T;\n }\n\n this.#recompute();\n }\n\n return this.#value as T;\n }\n\n get stale(): boolean {\n return this.#dirty || this.#disposed;\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n for (const unsub of this.#deps) unsub();\n this.#deps.clear();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\n/** Creates a derived read-only Signal whose value is recomputed lazily on `.value` read\n * when dependencies have changed. Call `.dispose()` to stop tracking and free dependencies.\n * Pass `{ lazy: true }` to defer the initial computation until the first `.value` read. */\nexport const computed = <T>(compute: () => T, options?: ReactiveOptions<T> & { lazy?: boolean }): ComputedSignal<T> =>\n new ComputedNode(compute, options);\n\n/** A bidirectional computed Signal with an explicit dispose method. */\nexport interface WritableSignal<T> extends Signal<T>, Disposable {\n /** True when the backing computed value is stale (deps changed but not yet re-read) or disposed. */\n readonly stale: boolean;\n}\n\n/** @internal */\nexport class WritableNode<T> extends ComputedNode<T> implements WritableSignal<T> {\n readonly #set: (v: T) => void;\n\n constructor(get: () => T, set: (v: T) => void, options?: ReactiveOptions<T>) {\n super(get, options);\n this.#set = set;\n }\n\n override get value(): T {\n return super.value;\n }\n\n set value(v: T) {\n this.#set(v);\n }\n\n update(fn: (current: T) => T): void {\n this.#set(fn(this.peek()));\n }\n}\n\n/** Creates a bidirectional computed Signal. Reads track the getter reactively;\n * writes are forwarded to `set`. Call `.dispose()` to stop tracking and free dependencies. */\nexport const writable = <T>(get: () => T, set: (value: T) => void, options?: ReactiveOptions<T>): WritableSignal<T> =>\n new WritableNode(get, set, options);\n\n/**\n * Creates a derived ComputedSignal by combining multiple source signals through a projector\n * function. Each source is passed as a positional argument to `fn`; the projector is\n * re-evaluated whenever any source changes.\n *\n * @example\n * const total = derived([price, quantity, discount], (p, q, d) => p * q * (1 - d));\n */\nexport const derived = <const Srcs extends ReadonlyArray<ReadonlySignal<unknown>>, R>(\n sources: Srcs,\n fn: (...values: { [K in keyof Srcs]: Srcs[K] extends ReadonlySignal<infer V> ? V : never }) => R,\n options?: ReactiveOptions<R>,\n): ComputedSignal<R> => computed(() => (fn as (...args: any[]) => R)(...sources.map((s) => s.value)), options);\n"],"mappings":"0DAyBA,IAAa,EAAb,cAAqC,EAAA,YAA0C,CAC7E,CAAU,EAAA,eAAiB,GAC3B,GACA,GAAoC,EAAA,eACpC,GAAS,GACT,GAAY,GACZ,GACA,GAAQ,IAAI,IAEZ,OAA8C,CACvC,MAAA,IACH,MAAA,EAAc,GACd,KAAK,SAAS,GAIlB,YAAY,EAAkB,EAAmD,CAC/E,OAAO,CACP,MAAA,EAAgB,EAChB,MAAA,EAAe,GAAS,QAAU,OAAO,GAEpC,GAAS,MAAM,MAAA,GAAiB,CAGvC,IAAmB,CACjB,IAAK,IAAM,KAAS,MAAA,EAAY,GAAO,CACvC,MAAA,EAAW,OAAO,CAElB,IAAM,EAAS,EAAA,SAAS,MAAA,EAAmB,MAAA,EAAY,KAAM,MAAA,EAAc,CAE3E,MAAA,EAAc,IAEV,MAAA,IAAgB,EAAA,gBAAkB,CAAC,MAAA,EAAa,MAAA,EAAkB,EAAO,IAC3E,MAAA,EAAc,GAIlB,IAAI,OAAW,CAWb,OAVI,MAAA,EAGK,MAAA,GAGL,MAAA,GAAa,MAAA,GAAiB,CAElC,KAAK,QAAQ,CAEN,MAAA,GAGT,MAAU,CACR,GAAI,MAAA,IAAgB,EAAA,eAAgB,CAClC,GAAI,MAAA,EAMF,OAGF,MAAA,GAAiB,CAGnB,OAAO,MAAA,EAGT,IAAI,OAAiB,CACnB,OAAO,MAAA,GAAe,MAAA,EAGxB,SAAgB,CACV,UAAA,EAEJ,OAAA,EAAiB,GACjB,IAAK,IAAM,KAAS,MAAA,EAAY,GAAO,CACvC,MAAA,EAAW,OAAO,EAGpB,CAAC,OAAO,UAAiB,CACvB,KAAK,SAAS,GAOL,GAAe,EAAkB,IAC5C,IAAI,EAAa,EAAS,EAAQ,CASvB,EAAb,cAAqC,CAA6C,CAChF,GAEA,YAAY,EAAc,EAAqB,EAA8B,CAC3E,MAAM,EAAK,EAAQ,CACnB,MAAA,EAAY,EAGd,IAAa,OAAW,CACtB,OAAO,MAAM,MAGf,IAAI,MAAM,EAAM,CACd,MAAA,EAAU,EAAE,CAGd,OAAO,EAA6B,CAClC,MAAA,EAAU,EAAG,KAAK,MAAM,CAAC,CAAC,GAMjB,GAAe,EAAc,EAAyB,IACjE,IAAI,EAAa,EAAK,EAAK,EAAQ,CAUxB,GACX,EACA,EACA,IACsB,MAAgB,EAA6B,GAAG,EAAQ,IAAK,GAAM,EAAE,MAAM,CAAC,CAAE,EAAQ"}
|
package/dist/computed.d.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { ReactiveNode } from './runtime';
|
|
2
|
-
import { type Disposable, type ReactiveOptions, type ReadonlySignal, type Signal, _SIGNAL_BRAND } from './types';
|
|
3
|
-
/** A derived read-only signal with an explicit dispose method. */
|
|
4
|
-
export interface ComputedSignal<T> extends ReadonlySignal<T>, Disposable {
|
|
5
|
-
/** True when the computed value is stale (deps changed but not yet re-read) or disposed. */
|
|
6
|
-
readonly stale: boolean;
|
|
7
|
-
}
|
|
8
|
-
/** @internal
|
|
9
|
-
* Lazy computed node. Seeded once at construction so .peek() is immediately valid
|
|
10
|
-
* (unless { lazy: true } is passed, in which case first compute defers to first read).
|
|
11
|
-
* - On dep change: marks dirty, notifies downstream (no recompute yet).
|
|
12
|
-
* - On .value read: recomputes if dirty, re-tracks fresh deps.
|
|
13
|
-
* - After dispose: _track() is skipped to prevent leaking outer effects.
|
|
14
|
-
*/
|
|
15
|
-
export declare class ComputedNode<T> extends ReactiveNode implements ComputedSignal<T> {
|
|
16
|
-
#private;
|
|
17
|
-
readonly [_SIGNAL_BRAND]: true;
|
|
18
|
-
constructor(compute: () => T, options?: ReactiveOptions<T> & {
|
|
19
|
-
lazy?: boolean;
|
|
20
|
-
});
|
|
21
|
-
get value(): T;
|
|
22
|
-
peek(): T;
|
|
23
|
-
get stale(): boolean;
|
|
24
|
-
dispose(): void;
|
|
25
|
-
[Symbol.dispose](): void;
|
|
26
|
-
}
|
|
27
|
-
/** Creates a derived read-only Signal whose value is recomputed lazily on `.value` read
|
|
28
|
-
* when dependencies have changed. Call `.dispose()` to stop tracking and free dependencies.
|
|
29
|
-
* Pass `{ lazy: true }` to defer the initial computation until the first `.value` read. */
|
|
30
|
-
export declare const computed: <T>(compute: () => T, options?: ReactiveOptions<T> & {
|
|
31
|
-
lazy?: boolean;
|
|
32
|
-
}) => ComputedSignal<T>;
|
|
33
|
-
/** A bidirectional computed Signal with an explicit dispose method. */
|
|
34
|
-
export interface WritableSignal<T> extends Signal<T>, Disposable {
|
|
35
|
-
/** True when the backing computed value is stale (deps changed but not yet re-read) or disposed. */
|
|
36
|
-
readonly stale: boolean;
|
|
37
|
-
}
|
|
38
|
-
/** @internal */
|
|
39
|
-
export declare class WritableNode<T> extends ComputedNode<T> implements WritableSignal<T> {
|
|
40
|
-
#private;
|
|
41
|
-
constructor(get: () => T, set: (v: T) => void, options?: ReactiveOptions<T>);
|
|
42
|
-
get value(): T;
|
|
43
|
-
set value(v: T);
|
|
44
|
-
update(fn: (current: T) => T): void;
|
|
45
|
-
}
|
|
46
|
-
/** Creates a bidirectional computed Signal. Reads track the getter reactively;
|
|
47
|
-
* writes are forwarded to `set`. Call `.dispose()` to stop tracking and free dependencies. */
|
|
48
|
-
export declare const writable: <T>(get: () => T, set: (value: T) => void, options?: ReactiveOptions<T>) => WritableSignal<T>;
|
|
49
|
-
/**
|
|
50
|
-
* Creates a derived ComputedSignal by combining multiple source signals through a projector
|
|
51
|
-
* function. Each source is passed as a positional argument to `fn`; the projector is
|
|
52
|
-
* re-evaluated whenever any source changes.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* const total = derived([price, quantity, discount], (p, q, d) => p * q * (1 - d));
|
|
56
|
-
*/
|
|
57
|
-
export declare const derived: <const Srcs extends ReadonlyArray<ReadonlySignal<unknown>>, R>(sources: Srcs, fn: (...values: { [K in keyof Srcs]: Srcs[K] extends ReadonlySignal<infer V> ? V : never; }) => R, options?: ReactiveOptions<R>) => ComputedSignal<R>;
|
|
58
|
-
//# sourceMappingURL=computed.d.ts.map
|
package/dist/computed.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAkC,MAAM,WAAW,CAAC;AACzE,OAAO,EAEL,KAAK,UAAU,EAGf,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,kEAAkE;AAClE,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU;IACtE,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;GAMG;AACH,qBAAa,YAAY,CAAC,CAAC,CAAE,SAAQ,YAAa,YAAW,cAAc,CAAC,CAAC,CAAC;;IAC5E,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAG,IAAI,CAAU;gBAe7B,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE;IAqB/E,IAAI,KAAK,IAAI,CAAC,CAYb;IAED,IAAI,IAAI,CAAC;IAiBT,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,OAAO,IAAI,IAAI;IAQf,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAGzB;AAED;;2FAE2F;AAC3F,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,SAAS,MAAM,CAAC,EAAE,UAAU,eAAe,CAAC,CAAC,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,KAAG,cAAc,CAAC,CAAC,CAC9E,CAAC;AAErC,uEAAuE;AACvE,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU;IAC9D,oGAAoG;IACpG,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,gBAAgB;AAChB,qBAAa,YAAY,CAAC,CAAC,CAAE,SAAQ,YAAY,CAAC,CAAC,CAAE,YAAW,cAAc,CAAC,CAAC,CAAC;;gBAGnE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;IAK3E,IAAa,KAAK,IAAI,CAAC,CAEtB;IAED,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,EAEb;IAED,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI;CAGpC;AAED;8FAC8F;AAC9F,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,UAAU,eAAe,CAAC,CAAC,CAAC,KAAG,cAAc,CAAC,CAAC,CAC7E,CAAC;AAEtC;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAAI,KAAK,CAAC,IAAI,SAAS,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAClF,SAAS,IAAI,EACb,IAAI,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAAE,KAAK,CAAC,EAChG,UAAU,eAAe,CAAC,CAAC,CAAC,KAC3B,cAAc,CAAC,CAAC,CAA2F,CAAC"}
|
package/dist/computed.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { ReactiveNode as e, _UNINITIALIZED as t, _withCtx as n } from "./runtime.js";
|
|
2
|
-
import { _SIGNAL_BRAND as r } from "./types.js";
|
|
3
|
-
//#region src/computed.ts
|
|
4
|
-
var i = class extends e {
|
|
5
|
-
[r] = !0;
|
|
6
|
-
#e;
|
|
7
|
-
#t = t;
|
|
8
|
-
#n = !0;
|
|
9
|
-
#r = !1;
|
|
10
|
-
#i;
|
|
11
|
-
#a = /* @__PURE__ */ new Set();
|
|
12
|
-
#o = () => {
|
|
13
|
-
this.#n || (this.#n = !0, this._notify());
|
|
14
|
-
};
|
|
15
|
-
constructor(e, t) {
|
|
16
|
-
super(), this.#e = e, this.#i = t?.equals ?? Object.is, t?.lazy || this.#s();
|
|
17
|
-
}
|
|
18
|
-
#s() {
|
|
19
|
-
for (let e of this.#a) e();
|
|
20
|
-
this.#a.clear();
|
|
21
|
-
let e = n(this.#o, this.#a, null, this.#e);
|
|
22
|
-
this.#n = !1, (this.#t === t || !this.#i(this.#t, e)) && (this.#t = e);
|
|
23
|
-
}
|
|
24
|
-
get value() {
|
|
25
|
-
return this.#r ? this.#t : (this.#n && this.#s(), this._track(), this.#t);
|
|
26
|
-
}
|
|
27
|
-
peek() {
|
|
28
|
-
if (this.#t === t) {
|
|
29
|
-
if (this.#r) return;
|
|
30
|
-
this.#s();
|
|
31
|
-
}
|
|
32
|
-
return this.#t;
|
|
33
|
-
}
|
|
34
|
-
get stale() {
|
|
35
|
-
return this.#n || this.#r;
|
|
36
|
-
}
|
|
37
|
-
dispose() {
|
|
38
|
-
if (!this.#r) {
|
|
39
|
-
this.#r = !0;
|
|
40
|
-
for (let e of this.#a) e();
|
|
41
|
-
this.#a.clear();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
[Symbol.dispose]() {
|
|
45
|
-
this.dispose();
|
|
46
|
-
}
|
|
47
|
-
}, a = (e, t) => new i(e, t), o = class extends i {
|
|
48
|
-
#e;
|
|
49
|
-
constructor(e, t, n) {
|
|
50
|
-
super(e, n), this.#e = t;
|
|
51
|
-
}
|
|
52
|
-
get value() {
|
|
53
|
-
return super.value;
|
|
54
|
-
}
|
|
55
|
-
set value(e) {
|
|
56
|
-
this.#e(e);
|
|
57
|
-
}
|
|
58
|
-
update(e) {
|
|
59
|
-
this.#e(e(this.peek()));
|
|
60
|
-
}
|
|
61
|
-
}, s = (e, t, n) => new o(e, t, n), c = (e, t, n) => a(() => t(...e.map((e) => e.value)), n);
|
|
62
|
-
//#endregion
|
|
63
|
-
export { i as ComputedNode, o as WritableNode, a as computed, c as derived, s as writable };
|
|
64
|
-
|
|
65
|
-
//# sourceMappingURL=computed.js.map
|
package/dist/computed.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"computed.js","names":["#onDepChange","#dirty","#compute","#equals","#recompute","#deps","#value","#disposed","#set"],"sources":["../src/computed.ts"],"sourcesContent":["import { ReactiveNode, _DEV, _UNINITIALIZED, _withCtx } from './runtime';\nimport {\n type CleanupFn,\n type Disposable,\n type EffectCallback,\n type EqualityFn,\n type ReactiveOptions,\n type ReadonlySignal,\n type Signal,\n _SIGNAL_BRAND,\n} from './types';\n\n/** A derived read-only signal with an explicit dispose method. */\nexport interface ComputedSignal<T> extends ReadonlySignal<T>, Disposable {\n /** True when the computed value is stale (deps changed but not yet re-read) or disposed. */\n readonly stale: boolean;\n}\n\n/** @internal\n * Lazy computed node. Seeded once at construction so .peek() is immediately valid\n * (unless { lazy: true } is passed, in which case first compute defers to first read).\n * - On dep change: marks dirty, notifies downstream (no recompute yet).\n * - On .value read: recomputes if dirty, re-tracks fresh deps.\n * - After dispose: _track() is skipped to prevent leaking outer effects.\n */\nexport class ComputedNode<T> extends ReactiveNode implements ComputedSignal<T> {\n readonly [_SIGNAL_BRAND] = true as const;\n #compute: () => T;\n #value: T | typeof _UNINITIALIZED = _UNINITIALIZED;\n #dirty = true;\n #disposed = false;\n #equals: EqualityFn<T>;\n #deps = new Set<CleanupFn>();\n\n readonly #onDepChange: EffectCallback = () => {\n if (!this.#dirty) {\n this.#dirty = true;\n this._notify();\n }\n };\n\n constructor(compute: () => T, options?: ReactiveOptions<T> & { lazy?: boolean }) {\n super();\n this.#compute = compute;\n this.#equals = options?.equals ?? Object.is;\n\n if (!options?.lazy) this.#recompute(); // seed: ensures peek() is valid immediately\n }\n\n #recompute(): void {\n for (const unsub of this.#deps) unsub();\n this.#deps.clear();\n\n const result = _withCtx(this.#onDepChange, this.#deps, null, this.#compute);\n\n this.#dirty = false;\n\n if (this.#value === _UNINITIALIZED || !this.#equals(this.#value as T, result)) {\n this.#value = result;\n }\n }\n\n get value(): T {\n if (this.#disposed) {\n if (_DEV) console.warn('[stateit] Reading a disposed ComputedSignal returns a stale value.');\n\n return this.#value as T;\n }\n\n if (this.#dirty) this.#recompute();\n\n this._track();\n\n return this.#value as T;\n }\n\n peek(): T {\n if (this.#value === _UNINITIALIZED) {\n if (this.#disposed) {\n if (_DEV)\n console.warn(\n '[stateit] peek() called on a disposed lazy ComputedSignal that was never read — returning undefined.',\n );\n\n return undefined as unknown as T;\n }\n\n this.#recompute();\n }\n\n return this.#value as T;\n }\n\n get stale(): boolean {\n return this.#dirty || this.#disposed;\n }\n\n dispose(): void {\n if (this.#disposed) return;\n\n this.#disposed = true;\n for (const unsub of this.#deps) unsub();\n this.#deps.clear();\n }\n\n [Symbol.dispose](): void {\n this.dispose();\n }\n}\n\n/** Creates a derived read-only Signal whose value is recomputed lazily on `.value` read\n * when dependencies have changed. Call `.dispose()` to stop tracking and free dependencies.\n * Pass `{ lazy: true }` to defer the initial computation until the first `.value` read. */\nexport const computed = <T>(compute: () => T, options?: ReactiveOptions<T> & { lazy?: boolean }): ComputedSignal<T> =>\n new ComputedNode(compute, options);\n\n/** A bidirectional computed Signal with an explicit dispose method. */\nexport interface WritableSignal<T> extends Signal<T>, Disposable {\n /** True when the backing computed value is stale (deps changed but not yet re-read) or disposed. */\n readonly stale: boolean;\n}\n\n/** @internal */\nexport class WritableNode<T> extends ComputedNode<T> implements WritableSignal<T> {\n readonly #set: (v: T) => void;\n\n constructor(get: () => T, set: (v: T) => void, options?: ReactiveOptions<T>) {\n super(get, options);\n this.#set = set;\n }\n\n override get value(): T {\n return super.value;\n }\n\n set value(v: T) {\n this.#set(v);\n }\n\n update(fn: (current: T) => T): void {\n this.#set(fn(this.peek()));\n }\n}\n\n/** Creates a bidirectional computed Signal. Reads track the getter reactively;\n * writes are forwarded to `set`. Call `.dispose()` to stop tracking and free dependencies. */\nexport const writable = <T>(get: () => T, set: (value: T) => void, options?: ReactiveOptions<T>): WritableSignal<T> =>\n new WritableNode(get, set, options);\n\n/**\n * Creates a derived ComputedSignal by combining multiple source signals through a projector\n * function. Each source is passed as a positional argument to `fn`; the projector is\n * re-evaluated whenever any source changes.\n *\n * @example\n * const total = derived([price, quantity, discount], (p, q, d) => p * q * (1 - d));\n */\nexport const derived = <const Srcs extends ReadonlyArray<ReadonlySignal<unknown>>, R>(\n sources: Srcs,\n fn: (...values: { [K in keyof Srcs]: Srcs[K] extends ReadonlySignal<infer V> ? V : never }) => R,\n options?: ReactiveOptions<R>,\n): ComputedSignal<R> => computed(() => (fn as (...args: any[]) => R)(...sources.map((s) => s.value)), options);\n"],"mappings":";;;AAyBA,IAAa,IAAb,cAAqC,EAA0C;CAC7E,CAAU,KAAiB;CAC3B;CACA,KAAoC;CACpC,KAAS;CACT,KAAY;CACZ;CACA,qBAAQ,IAAI,KAAgB;CAE5B,WAA8C;AAC5C,EAAK,MAAA,MACH,MAAA,IAAc,IACd,KAAK,SAAS;;CAIlB,YAAY,GAAkB,GAAmD;AAK/E,EAJA,OAAO,EACP,MAAA,IAAgB,GAChB,MAAA,IAAe,GAAS,UAAU,OAAO,IAEpC,GAAS,QAAM,MAAA,GAAiB;;CAGvC,KAAmB;AACjB,OAAK,IAAM,KAAS,MAAA,EAAY,IAAO;AACvC,QAAA,EAAW,OAAO;EAElB,IAAM,IAAS,EAAS,MAAA,GAAmB,MAAA,GAAY,MAAM,MAAA,EAAc;AAI3E,EAFA,MAAA,IAAc,KAEV,MAAA,MAAgB,KAAkB,CAAC,MAAA,EAAa,MAAA,GAAkB,EAAO,MAC3E,MAAA,IAAc;;CAIlB,IAAI,QAAW;AAWb,SAVI,MAAA,IAGK,MAAA,KAGL,MAAA,KAAa,MAAA,GAAiB,EAElC,KAAK,QAAQ,EAEN,MAAA;;CAGT,OAAU;AACR,MAAI,MAAA,MAAgB,GAAgB;AAClC,OAAI,MAAA,EAMF;AAGF,SAAA,GAAiB;;AAGnB,SAAO,MAAA;;CAGT,IAAI,QAAiB;AACnB,SAAO,MAAA,KAAe,MAAA;;CAGxB,UAAgB;AACV,aAAA,GAEJ;SAAA,IAAiB;AACjB,QAAK,IAAM,KAAS,MAAA,EAAY,IAAO;AACvC,SAAA,EAAW,OAAO;;;CAGpB,CAAC,OAAO,WAAiB;AACvB,OAAK,SAAS;;GAOL,KAAe,GAAkB,MAC5C,IAAI,EAAa,GAAS,EAAQ,EASvB,IAAb,cAAqC,EAA6C;CAChF;CAEA,YAAY,GAAc,GAAqB,GAA8B;AAE3E,EADA,MAAM,GAAK,EAAQ,EACnB,MAAA,IAAY;;CAGd,IAAa,QAAW;AACtB,SAAO,MAAM;;CAGf,IAAI,MAAM,GAAM;AACd,QAAA,EAAU,EAAE;;CAGd,OAAO,GAA6B;AAClC,QAAA,EAAU,EAAG,KAAK,MAAM,CAAC,CAAC;;GAMjB,KAAe,GAAc,GAAyB,MACjE,IAAI,EAAa,GAAK,GAAK,EAAQ,EAUxB,KACX,GACA,GACA,MACsB,QAAgB,EAA6B,GAAG,EAAQ,KAAK,MAAM,EAAE,MAAM,CAAC,EAAE,EAAQ"}
|
package/dist/effect.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./runtime.cjs`);var t=(t,n)=>{let r,i=new Set,a=!1,o=!1,s=!1,c=n?.maxIterations??e._maxEffectIterations,l=()=>{r?.(),r=void 0;for(let e of i)e();i.clear()},u=()=>{o=!1,l();let a=[],c,u=!1;try{e._withCtx(d,i,a,()=>{let e=t();typeof e==`function`&&a.push(e)})}catch(e){if(n?.onError)u=!0,c=e;else throw e}return r=a.length>0?()=>{for(let e of a)e()}:void 0,u&&(l(),n.onError(c),s=!0),u},d=()=>{if(s||a){a&&(o=!0);return}a=!0;try{let e=0;do{if(++e>c)throw Error(`[stateit] effect: possible infinite reactive loop (> ${c} iterations)`);if(u())break}while(o)}finally{a=!1}};d();let f=()=>{s||(s=!0,l())};return Object.assign(f,{dispose:f,[Symbol.dispose]:f})},n=t=>e._withCtx(null,null,null,t),r=t=>{e.scope.cleanups?.push(t)};exports.effect=t,exports.onCleanup=r,exports.untrack=n;
|
|
2
|
-
//# sourceMappingURL=effect.cjs.map
|
package/dist/effect.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effect.cjs","names":[],"sources":["../src/effect.ts"],"sourcesContent":["import { _DEV, _maxEffectIterations, _withCtx, scope } from './runtime';\nimport { type CleanupFn, type EffectCallback, type Subscription } from './types';\n\n/** Options for the `effect()` primitive. */\nexport type EffectOptions = {\n /**\n * Maximum re-entrant iterations before throwing to prevent infinite loops.\n * Overrides the global value set via `configureStateit` for this specific effect.\n */\n maxIterations?: number;\n /**\n * Called when the effect function throws. When provided, the effect is automatically\n * disposed after the first error — it won't re-run on subsequent dependency changes.\n */\n onError?: (error: unknown) => void;\n};\n\n/** Runs fn immediately and re-runs it whenever any Signal read inside it changes. Returns a dispose handle. */\nexport const effect = (fn: EffectCallback, options?: EffectOptions): Subscription => {\n let cleanup: CleanupFn | undefined;\n const deps = new Set<CleanupFn>();\n let running = false;\n let dirty = false;\n let disposed = false;\n const maxIter = options?.maxIterations ?? _maxEffectIterations;\n\n /** Tears down the current run: calls cleanup and unsubscribes all deps. */\n const teardown = (): void => {\n cleanup?.();\n cleanup = undefined;\n for (const unsub of deps) unsub();\n deps.clear();\n };\n\n /** Runs a single iteration: tears down previous deps/cleanup, re-executes fn, registers fresh deps.\n * Returns true if onError handled a throw (caller should break the loop). */\n const runIteration = (): boolean => {\n dirty = false;\n teardown();\n\n const cleanups: CleanupFn[] = [];\n let thrownError: unknown;\n let threw = false;\n\n try {\n _withCtx(runner, deps, cleanups, () => {\n const result = fn();\n\n if (typeof result === 'function') cleanups.push(result);\n });\n } catch (e) {\n if (options?.onError) {\n threw = true;\n thrownError = e;\n } else throw e;\n }\n\n cleanup =\n cleanups.length > 0\n ? () => {\n for (const c of cleanups) c();\n }\n : undefined;\n\n if (threw) {\n teardown(); // flush onCleanup registrations from the throwing run\n options!.onError!(thrownError);\n disposed = true;\n }\n\n return threw;\n };\n\n const runner: EffectCallback = () => {\n if (disposed || running) {\n if (running) dirty = true;\n\n return;\n }\n\n running = true;\n\n try {\n let iterations = 0;\n\n do {\n if (++iterations > maxIter)\n throw new Error(`[stateit] effect: possible infinite reactive loop (> ${maxIter} iterations)`);\n\n if (runIteration()) break;\n } while (dirty);\n } finally {\n running = false;\n }\n };\n\n runner();\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n teardown();\n };\n\n return Object.assign(dispose, { dispose, [Symbol.dispose]: dispose }) as Subscription;\n};\n\n/** Runs fn without registering any reactive dependencies. */\nexport const untrack = <T>(fn: () => T): T => _withCtx(null, null, null, fn);\n\n/**\n * Registers a cleanup function within the currently running effect.\n * Called before the effect re-runs and on final dispose.\n * Allows nested helpers to register teardown without needing the effect's return value.\n *\n * @example\n * effect(() => {\n * const id = setInterval(() => { ... }, 1000);\n * onCleanup(() => clearInterval(id));\n * });\n */\nexport const onCleanup = (fn: CleanupFn): void => {\n if (_DEV && scope.cleanups === null) {\n console.warn('[stateit] onCleanup() called outside of an active effect — the cleanup will never run.');\n }\n\n scope.cleanups?.push(fn);\n};\n"],"mappings":"iCAkBA,IAAa,GAAU,EAAoB,IAA0C,CACnF,IAAI,EACE,EAAO,IAAI,IACb,EAAU,GACV,EAAQ,GACR,EAAW,GACT,EAAU,GAAS,eAAiB,EAAA,qBAGpC,MAAuB,CAC3B,KAAW,CACX,EAAU,IAAA,GACV,IAAK,IAAM,KAAS,EAAM,GAAO,CACjC,EAAK,OAAO,EAKR,MAA8B,CAClC,EAAQ,GACR,GAAU,CAEV,IAAM,EAAwB,EAAE,CAC5B,EACA,EAAQ,GAEZ,GAAI,CACF,EAAA,SAAS,EAAQ,EAAM,MAAgB,CACrC,IAAM,EAAS,GAAI,CAEf,OAAO,GAAW,YAAY,EAAS,KAAK,EAAO,EACvD,OACK,EAAG,CACV,GAAI,GAAS,QACX,EAAQ,GACR,EAAc,OACT,MAAM,EAgBf,MAbA,GACE,EAAS,OAAS,MACR,CACJ,IAAK,IAAM,KAAK,EAAU,GAAG,EAE/B,IAAA,GAEF,IACF,GAAU,CACV,EAAS,QAAS,EAAY,CAC9B,EAAW,IAGN,GAGH,MAA+B,CACnC,GAAI,GAAY,EAAS,CACnB,IAAS,EAAQ,IAErB,OAGF,EAAU,GAEV,GAAI,CACF,IAAI,EAAa,EAEjB,EAAG,CACD,GAAI,EAAE,EAAa,EACjB,MAAU,MAAM,wDAAwD,EAAQ,cAAc,CAEhG,GAAI,GAAc,CAAE,YACb,UACD,CACR,EAAU,KAId,GAAQ,CAER,IAAM,MAAsB,CACtB,IAEJ,EAAW,GACX,GAAU,GAGZ,OAAO,OAAO,OAAO,EAAS,CAAE,WAAU,OAAO,SAAU,EAAS,CAAC,EAI1D,EAAc,GAAmB,EAAA,SAAS,KAAM,KAAM,KAAM,EAAG,CAa/D,EAAa,GAAwB,CAKhD,EAAA,MAAM,UAAU,KAAK,EAAG"}
|
package/dist/effect.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type CleanupFn, type EffectCallback, type Subscription } from './types';
|
|
2
|
-
/** Options for the `effect()` primitive. */
|
|
3
|
-
export type EffectOptions = {
|
|
4
|
-
/**
|
|
5
|
-
* Maximum re-entrant iterations before throwing to prevent infinite loops.
|
|
6
|
-
* Overrides the global value set via `configureStateit` for this specific effect.
|
|
7
|
-
*/
|
|
8
|
-
maxIterations?: number;
|
|
9
|
-
/**
|
|
10
|
-
* Called when the effect function throws. When provided, the effect is automatically
|
|
11
|
-
* disposed after the first error — it won't re-run on subsequent dependency changes.
|
|
12
|
-
*/
|
|
13
|
-
onError?: (error: unknown) => void;
|
|
14
|
-
};
|
|
15
|
-
/** Runs fn immediately and re-runs it whenever any Signal read inside it changes. Returns a dispose handle. */
|
|
16
|
-
export declare const effect: (fn: EffectCallback, options?: EffectOptions) => Subscription;
|
|
17
|
-
/** Runs fn without registering any reactive dependencies. */
|
|
18
|
-
export declare const untrack: <T>(fn: () => T) => T;
|
|
19
|
-
/**
|
|
20
|
-
* Registers a cleanup function within the currently running effect.
|
|
21
|
-
* Called before the effect re-runs and on final dispose.
|
|
22
|
-
* Allows nested helpers to register teardown without needing the effect's return value.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* effect(() => {
|
|
26
|
-
* const id = setInterval(() => { ... }, 1000);
|
|
27
|
-
* onCleanup(() => clearInterval(id));
|
|
28
|
-
* });
|
|
29
|
-
*/
|
|
30
|
-
export declare const onCleanup: (fn: CleanupFn) => void;
|
|
31
|
-
//# sourceMappingURL=effect.d.ts.map
|
package/dist/effect.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjF,4CAA4C;AAC5C,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF,+GAA+G;AAC/G,eAAO,MAAM,MAAM,GAAI,IAAI,cAAc,EAAE,UAAU,aAAa,KAAG,YAwFpE,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,IAAI,MAAM,CAAC,KAAG,CAAmC,CAAC;AAE7E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,GAAI,IAAI,SAAS,KAAG,IAMzC,CAAC"}
|
package/dist/effect.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { _maxEffectIterations as e, _withCtx as t, scope as n } from "./runtime.js";
|
|
2
|
-
//#region src/effect.ts
|
|
3
|
-
var r = (n, r) => {
|
|
4
|
-
let i, a = /* @__PURE__ */ new Set(), o = !1, s = !1, c = !1, l = r?.maxIterations ?? e, u = () => {
|
|
5
|
-
i?.(), i = void 0;
|
|
6
|
-
for (let e of a) e();
|
|
7
|
-
a.clear();
|
|
8
|
-
}, d = () => {
|
|
9
|
-
s = !1, u();
|
|
10
|
-
let e = [], o, l = !1;
|
|
11
|
-
try {
|
|
12
|
-
t(f, a, e, () => {
|
|
13
|
-
let t = n();
|
|
14
|
-
typeof t == "function" && e.push(t);
|
|
15
|
-
});
|
|
16
|
-
} catch (e) {
|
|
17
|
-
if (r?.onError) l = !0, o = e;
|
|
18
|
-
else throw e;
|
|
19
|
-
}
|
|
20
|
-
return i = e.length > 0 ? () => {
|
|
21
|
-
for (let t of e) t();
|
|
22
|
-
} : void 0, l && (u(), r.onError(o), c = !0), l;
|
|
23
|
-
}, f = () => {
|
|
24
|
-
if (c || o) {
|
|
25
|
-
o && (s = !0);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
o = !0;
|
|
29
|
-
try {
|
|
30
|
-
let e = 0;
|
|
31
|
-
do {
|
|
32
|
-
if (++e > l) throw Error(`[stateit] effect: possible infinite reactive loop (> ${l} iterations)`);
|
|
33
|
-
if (d()) break;
|
|
34
|
-
} while (s);
|
|
35
|
-
} finally {
|
|
36
|
-
o = !1;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
f();
|
|
40
|
-
let p = () => {
|
|
41
|
-
c || (c = !0, u());
|
|
42
|
-
};
|
|
43
|
-
return Object.assign(p, {
|
|
44
|
-
dispose: p,
|
|
45
|
-
[Symbol.dispose]: p
|
|
46
|
-
});
|
|
47
|
-
}, i = (e) => t(null, null, null, e), a = (e) => {
|
|
48
|
-
n.cleanups?.push(e);
|
|
49
|
-
};
|
|
50
|
-
//#endregion
|
|
51
|
-
export { r as effect, a as onCleanup, i as untrack };
|
|
52
|
-
|
|
53
|
-
//# sourceMappingURL=effect.js.map
|
package/dist/effect.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","names":[],"sources":["../src/effect.ts"],"sourcesContent":["import { _DEV, _maxEffectIterations, _withCtx, scope } from './runtime';\nimport { type CleanupFn, type EffectCallback, type Subscription } from './types';\n\n/** Options for the `effect()` primitive. */\nexport type EffectOptions = {\n /**\n * Maximum re-entrant iterations before throwing to prevent infinite loops.\n * Overrides the global value set via `configureStateit` for this specific effect.\n */\n maxIterations?: number;\n /**\n * Called when the effect function throws. When provided, the effect is automatically\n * disposed after the first error — it won't re-run on subsequent dependency changes.\n */\n onError?: (error: unknown) => void;\n};\n\n/** Runs fn immediately and re-runs it whenever any Signal read inside it changes. Returns a dispose handle. */\nexport const effect = (fn: EffectCallback, options?: EffectOptions): Subscription => {\n let cleanup: CleanupFn | undefined;\n const deps = new Set<CleanupFn>();\n let running = false;\n let dirty = false;\n let disposed = false;\n const maxIter = options?.maxIterations ?? _maxEffectIterations;\n\n /** Tears down the current run: calls cleanup and unsubscribes all deps. */\n const teardown = (): void => {\n cleanup?.();\n cleanup = undefined;\n for (const unsub of deps) unsub();\n deps.clear();\n };\n\n /** Runs a single iteration: tears down previous deps/cleanup, re-executes fn, registers fresh deps.\n * Returns true if onError handled a throw (caller should break the loop). */\n const runIteration = (): boolean => {\n dirty = false;\n teardown();\n\n const cleanups: CleanupFn[] = [];\n let thrownError: unknown;\n let threw = false;\n\n try {\n _withCtx(runner, deps, cleanups, () => {\n const result = fn();\n\n if (typeof result === 'function') cleanups.push(result);\n });\n } catch (e) {\n if (options?.onError) {\n threw = true;\n thrownError = e;\n } else throw e;\n }\n\n cleanup =\n cleanups.length > 0\n ? () => {\n for (const c of cleanups) c();\n }\n : undefined;\n\n if (threw) {\n teardown(); // flush onCleanup registrations from the throwing run\n options!.onError!(thrownError);\n disposed = true;\n }\n\n return threw;\n };\n\n const runner: EffectCallback = () => {\n if (disposed || running) {\n if (running) dirty = true;\n\n return;\n }\n\n running = true;\n\n try {\n let iterations = 0;\n\n do {\n if (++iterations > maxIter)\n throw new Error(`[stateit] effect: possible infinite reactive loop (> ${maxIter} iterations)`);\n\n if (runIteration()) break;\n } while (dirty);\n } finally {\n running = false;\n }\n };\n\n runner();\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n teardown();\n };\n\n return Object.assign(dispose, { dispose, [Symbol.dispose]: dispose }) as Subscription;\n};\n\n/** Runs fn without registering any reactive dependencies. */\nexport const untrack = <T>(fn: () => T): T => _withCtx(null, null, null, fn);\n\n/**\n * Registers a cleanup function within the currently running effect.\n * Called before the effect re-runs and on final dispose.\n * Allows nested helpers to register teardown without needing the effect's return value.\n *\n * @example\n * effect(() => {\n * const id = setInterval(() => { ... }, 1000);\n * onCleanup(() => clearInterval(id));\n * });\n */\nexport const onCleanup = (fn: CleanupFn): void => {\n if (_DEV && scope.cleanups === null) {\n console.warn('[stateit] onCleanup() called outside of an active effect — the cleanup will never run.');\n }\n\n scope.cleanups?.push(fn);\n};\n"],"mappings":";;AAkBA,IAAa,KAAU,GAAoB,MAA0C;CACnF,IAAI,GACE,oBAAO,IAAI,KAAgB,EAC7B,IAAU,IACV,IAAQ,IACR,IAAW,IACT,IAAU,GAAS,iBAAiB,GAGpC,UAAuB;AAE3B,EADA,KAAW,EACX,IAAU,KAAA;AACV,OAAK,IAAM,KAAS,EAAM,IAAO;AACjC,IAAK,OAAO;IAKR,UAA8B;AAElC,EADA,IAAQ,IACR,GAAU;EAEV,IAAM,IAAwB,EAAE,EAC5B,GACA,IAAQ;AAEZ,MAAI;AACF,KAAS,GAAQ,GAAM,SAAgB;IACrC,IAAM,IAAS,GAAI;AAEnB,IAAI,OAAO,KAAW,cAAY,EAAS,KAAK,EAAO;KACvD;WACK,GAAG;AACV,OAAI,GAAS,QAEX,CADA,IAAQ,IACR,IAAc;OACT,OAAM;;AAgBf,SAbA,IACE,EAAS,SAAS,UACR;AACJ,QAAK,IAAM,KAAK,EAAU,IAAG;MAE/B,KAAA,GAEF,MACF,GAAU,EACV,EAAS,QAAS,EAAY,EAC9B,IAAW,KAGN;IAGH,UAA+B;AACnC,MAAI,KAAY,GAAS;AACvB,GAAI,MAAS,IAAQ;AAErB;;AAGF,MAAU;AAEV,MAAI;GACF,IAAI,IAAa;AAEjB,MAAG;AACD,QAAI,EAAE,IAAa,EACjB,OAAU,MAAM,wDAAwD,EAAQ,cAAc;AAEhG,QAAI,GAAc,CAAE;YACb;YACD;AACR,OAAU;;;AAId,IAAQ;CAER,IAAM,UAAsB;AACtB,QAEJ,IAAW,IACX,GAAU;;AAGZ,QAAO,OAAO,OAAO,GAAS;EAAE;GAAU,OAAO,UAAU;EAAS,CAAC;GAI1D,KAAc,MAAmB,EAAS,MAAM,MAAM,MAAM,EAAG,EAa/D,KAAa,MAAwB;AAKhD,GAAM,UAAU,KAAK,EAAG"}
|
package/dist/runtime.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=Symbol(`stateit.uninitialized`),t={cleanups:null,deps:null,effect:null},n={depth:0,pending:new Set},r=100,i=e=>{e.maxEffectIterations!==void 0&&(r=e.maxEffectIterations)},a=()=>{n.depth=0,t.deps=null,t.effect=null,t.cleanups=null,n.pending.clear()},o=class{#e=new Set;_track(){if(t.deps!==null&&t.effect!==null){let e=t.effect;this.#e.add(e),t.deps.add(()=>this.#e.delete(e))}}_notify(){if(this.#e.size===0)return;if(n.depth>0){for(let e of this.#e)n.pending.add(e);return}let e=[];for(let t of[...this.#e])try{t()}catch(t){e.push(t)}if(e.length)throw e.length===1?e[0]:AggregateError(e,`[stateit] multiple subscriber errors`)}},s=(e,n,r,i)=>{let a=t.effect,o=t.deps,s=t.cleanups;t.effect=e,t.deps=n,t.cleanups=r;try{return i()}finally{t.effect=a,t.deps=o,t.cleanups=s}};exports.ReactiveNode=o,exports._UNINITIALIZED=e,Object.defineProperty(exports,`_maxEffectIterations`,{enumerable:!0,get:function(){return r}}),exports._resetContextForTesting=a,exports._withCtx=s,exports.configureStateit=i,exports.queue=n,exports.scope=t;
|
|
2
|
-
//# sourceMappingURL=runtime.cjs.map
|
package/dist/runtime.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.cjs","names":["#subscribers"],"sources":["../src/runtime.ts"],"sourcesContent":["import type { CleanupFn, EffectCallback } from './types';\n\n/** @internal True outside of production builds; gates dev-only warnings. */\nexport const _DEV = import.meta.env.DEV;\n\nexport const _UNINITIALIZED = Symbol('stateit.uninitialized');\n\n/** @internal Active reactive tracking scope — null outside any effect/computed. */\nexport const scope = {\n cleanups: null as CleanupFn[] | null,\n deps: null as Set<CleanupFn> | null,\n effect: null as EffectCallback | null,\n};\n\n/** @internal Deferred notification queue — active only during batch(). */\nexport const queue = {\n depth: 0,\n pending: new Set<EffectCallback>(),\n};\n\nexport let _maxEffectIterations = 100;\n\n/**\n * Configures global stateit behaviour.\n * @example configureStateit({ maxEffectIterations: 200 });\n */\nexport const configureStateit = (opts: { maxEffectIterations?: number }): void => {\n if (opts.maxEffectIterations !== undefined) _maxEffectIterations = opts.maxEffectIterations;\n};\n\n/**\n * Resets the shared reactive context. Use in test setup/teardown to prevent state\n * leaks between tests when a batch or effect throws without being fully cleaned up.\n */\nexport const _resetContextForTesting = (): void => {\n queue.depth = 0;\n scope.deps = null;\n scope.effect = null;\n scope.cleanups = null;\n queue.pending.clear();\n};\n\n/** @internal Base reactive node: manages a subscriber set and batch-aware notification. */\nexport class ReactiveNode {\n #subscribers = new Set<EffectCallback>();\n\n /** Register the current tracking scope as a subscriber and store an unsubscribe\n * function in scope.deps for automatic cleanup when the effect re-runs. */\n protected _track(): void {\n if (scope.deps !== null && scope.effect !== null) {\n const fn = scope.effect;\n\n this.#subscribers.add(fn);\n scope.deps.add(() => this.#subscribers.delete(fn));\n }\n }\n\n /** Notify all subscribers. Respects batch queue depth. */\n protected _notify(): void {\n if (this.#subscribers.size === 0) return;\n\n if (queue.depth > 0) {\n for (const fn of this.#subscribers) queue.pending.add(fn);\n\n return;\n }\n\n const errors: unknown[] = [];\n\n for (const fn of [...this.#subscribers]) {\n try {\n fn();\n } catch (e) {\n errors.push(e);\n }\n }\n\n if (errors.length) {\n throw errors.length === 1 ? errors[0] : new AggregateError(errors, '[stateit] multiple subscriber errors');\n }\n }\n}\n\n/** @internal Save scope fields, swap to new tracking context, call fn, restore. */\nexport const _withCtx = <T>(\n eff: EffectCallback | null,\n deps: Set<CleanupFn> | null,\n cleanups: CleanupFn[] | null,\n fn: () => T,\n): T => {\n const pe = scope.effect;\n const pd = scope.deps;\n const pc = scope.cleanups;\n\n scope.effect = eff;\n scope.deps = deps;\n scope.cleanups = cleanups;\n\n try {\n return fn();\n } finally {\n scope.effect = pe;\n scope.deps = pd;\n scope.cleanups = pc;\n }\n};\n"],"mappings":"AAKA,IAAa,EAAiB,OAAO,wBAAwB,CAGhD,EAAQ,CACnB,SAAU,KACV,KAAM,KACN,OAAQ,KACT,CAGY,EAAQ,CACnB,MAAO,EACP,QAAS,IAAI,IACd,CAEU,EAAuB,IAMrB,EAAoB,GAAiD,CAC5E,EAAK,sBAAwB,IAAA,KAAW,EAAuB,EAAK,sBAO7D,MAAsC,CACjD,EAAM,MAAQ,EACd,EAAM,KAAO,KACb,EAAM,OAAS,KACf,EAAM,SAAW,KACjB,EAAM,QAAQ,OAAO,EAIV,EAAb,KAA0B,CACxB,GAAe,IAAI,IAInB,QAAyB,CACvB,GAAI,EAAM,OAAS,MAAQ,EAAM,SAAW,KAAM,CAChD,IAAM,EAAK,EAAM,OAEjB,MAAA,EAAkB,IAAI,EAAG,CACzB,EAAM,KAAK,QAAU,MAAA,EAAkB,OAAO,EAAG,CAAC,EAKtD,SAA0B,CACxB,GAAI,MAAA,EAAkB,OAAS,EAAG,OAElC,GAAI,EAAM,MAAQ,EAAG,CACnB,IAAK,IAAM,KAAM,MAAA,EAAmB,EAAM,QAAQ,IAAI,EAAG,CAEzD,OAGF,IAAM,EAAoB,EAAE,CAE5B,IAAK,IAAM,IAAM,CAAC,GAAG,MAAA,EAAkB,CACrC,GAAI,CACF,GAAI,OACG,EAAG,CACV,EAAO,KAAK,EAAE,CAIlB,GAAI,EAAO,OACT,MAAM,EAAO,SAAW,EAAI,EAAO,GAAS,eAAe,EAAQ,uCAAuC,GAMnG,GACX,EACA,EACA,EACA,IACM,CACN,IAAM,EAAK,EAAM,OACX,EAAK,EAAM,KACX,EAAK,EAAM,SAEjB,EAAM,OAAS,EACf,EAAM,KAAO,EACb,EAAM,SAAW,EAEjB,GAAI,CACF,OAAO,GAAI,QACH,CACR,EAAM,OAAS,EACf,EAAM,KAAO,EACb,EAAM,SAAW"}
|
package/dist/runtime.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { CleanupFn, EffectCallback } from './types';
|
|
2
|
-
/** @internal True outside of production builds; gates dev-only warnings. */
|
|
3
|
-
export declare const _DEV: boolean;
|
|
4
|
-
export declare const _UNINITIALIZED: unique symbol;
|
|
5
|
-
/** @internal Active reactive tracking scope — null outside any effect/computed. */
|
|
6
|
-
export declare const scope: {
|
|
7
|
-
cleanups: CleanupFn[] | null;
|
|
8
|
-
deps: Set<CleanupFn> | null;
|
|
9
|
-
effect: EffectCallback | null;
|
|
10
|
-
};
|
|
11
|
-
/** @internal Deferred notification queue — active only during batch(). */
|
|
12
|
-
export declare const queue: {
|
|
13
|
-
depth: number;
|
|
14
|
-
pending: Set<EffectCallback>;
|
|
15
|
-
};
|
|
16
|
-
export declare let _maxEffectIterations: number;
|
|
17
|
-
/**
|
|
18
|
-
* Configures global stateit behaviour.
|
|
19
|
-
* @example configureStateit({ maxEffectIterations: 200 });
|
|
20
|
-
*/
|
|
21
|
-
export declare const configureStateit: (opts: {
|
|
22
|
-
maxEffectIterations?: number;
|
|
23
|
-
}) => void;
|
|
24
|
-
/**
|
|
25
|
-
* Resets the shared reactive context. Use in test setup/teardown to prevent state
|
|
26
|
-
* leaks between tests when a batch or effect throws without being fully cleaned up.
|
|
27
|
-
*/
|
|
28
|
-
export declare const _resetContextForTesting: () => void;
|
|
29
|
-
/** @internal Base reactive node: manages a subscriber set and batch-aware notification. */
|
|
30
|
-
export declare class ReactiveNode {
|
|
31
|
-
#private;
|
|
32
|
-
/** Register the current tracking scope as a subscriber and store an unsubscribe
|
|
33
|
-
* function in scope.deps for automatic cleanup when the effect re-runs. */
|
|
34
|
-
protected _track(): void;
|
|
35
|
-
/** Notify all subscribers. Respects batch queue depth. */
|
|
36
|
-
protected _notify(): void;
|
|
37
|
-
}
|
|
38
|
-
/** @internal Save scope fields, swap to new tracking context, call fn, restore. */
|
|
39
|
-
export declare const _withCtx: <T>(eff: EffectCallback | null, deps: Set<CleanupFn> | null, cleanups: CleanupFn[] | null, fn: () => T) => T;
|
|
40
|
-
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzD,4EAA4E;AAC5E,eAAO,MAAM,IAAI,SAAsB,CAAC;AAExC,eAAO,MAAM,cAAc,eAAkC,CAAC;AAE9D,mFAAmF;AACnF,eAAO,MAAM,KAAK;cACE,SAAS,EAAE,GAAG,IAAI;UACtB,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI;YACnB,cAAc,GAAG,IAAI;CACtC,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,KAAK;;;CAGjB,CAAC;AAEF,eAAO,IAAI,oBAAoB,QAAM,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM;IAAE,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,IAEzE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,QAAO,IAM1C,CAAC;AAEF,2FAA2F;AAC3F,qBAAa,YAAY;;IAGvB;gFAC4E;IAC5E,SAAS,CAAC,MAAM,IAAI,IAAI;IASxB,0DAA0D;IAC1D,SAAS,CAAC,OAAO,IAAI,IAAI;CAuB1B;AAED,mFAAmF;AACnF,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,KAAK,cAAc,GAAG,IAAI,EAC1B,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAC3B,UAAU,SAAS,EAAE,GAAG,IAAI,EAC5B,IAAI,MAAM,CAAC,KACV,CAgBF,CAAC"}
|
package/dist/runtime.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//#region src/runtime.ts
|
|
2
|
-
var e = Symbol("stateit.uninitialized"), t = {
|
|
3
|
-
cleanups: null,
|
|
4
|
-
deps: null,
|
|
5
|
-
effect: null
|
|
6
|
-
}, n = {
|
|
7
|
-
depth: 0,
|
|
8
|
-
pending: /* @__PURE__ */ new Set()
|
|
9
|
-
}, r = 100, i = (e) => {
|
|
10
|
-
e.maxEffectIterations !== void 0 && (r = e.maxEffectIterations);
|
|
11
|
-
}, a = () => {
|
|
12
|
-
n.depth = 0, t.deps = null, t.effect = null, t.cleanups = null, n.pending.clear();
|
|
13
|
-
}, o = class {
|
|
14
|
-
#e = /* @__PURE__ */ new Set();
|
|
15
|
-
_track() {
|
|
16
|
-
if (t.deps !== null && t.effect !== null) {
|
|
17
|
-
let e = t.effect;
|
|
18
|
-
this.#e.add(e), t.deps.add(() => this.#e.delete(e));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
_notify() {
|
|
22
|
-
if (this.#e.size === 0) return;
|
|
23
|
-
if (n.depth > 0) {
|
|
24
|
-
for (let e of this.#e) n.pending.add(e);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
let e = [];
|
|
28
|
-
for (let t of [...this.#e]) try {
|
|
29
|
-
t();
|
|
30
|
-
} catch (t) {
|
|
31
|
-
e.push(t);
|
|
32
|
-
}
|
|
33
|
-
if (e.length) throw e.length === 1 ? e[0] : AggregateError(e, "[stateit] multiple subscriber errors");
|
|
34
|
-
}
|
|
35
|
-
}, s = (e, n, r, i) => {
|
|
36
|
-
let a = t.effect, o = t.deps, s = t.cleanups;
|
|
37
|
-
t.effect = e, t.deps = n, t.cleanups = r;
|
|
38
|
-
try {
|
|
39
|
-
return i();
|
|
40
|
-
} finally {
|
|
41
|
-
t.effect = a, t.deps = o, t.cleanups = s;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
//#endregion
|
|
45
|
-
export { o as ReactiveNode, e as _UNINITIALIZED, r as _maxEffectIterations, a as _resetContextForTesting, s as _withCtx, i as configureStateit, n as queue, t as scope };
|
|
46
|
-
|
|
47
|
-
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":["#subscribers"],"sources":["../src/runtime.ts"],"sourcesContent":["import type { CleanupFn, EffectCallback } from './types';\n\n/** @internal True outside of production builds; gates dev-only warnings. */\nexport const _DEV = import.meta.env.DEV;\n\nexport const _UNINITIALIZED = Symbol('stateit.uninitialized');\n\n/** @internal Active reactive tracking scope — null outside any effect/computed. */\nexport const scope = {\n cleanups: null as CleanupFn[] | null,\n deps: null as Set<CleanupFn> | null,\n effect: null as EffectCallback | null,\n};\n\n/** @internal Deferred notification queue — active only during batch(). */\nexport const queue = {\n depth: 0,\n pending: new Set<EffectCallback>(),\n};\n\nexport let _maxEffectIterations = 100;\n\n/**\n * Configures global stateit behaviour.\n * @example configureStateit({ maxEffectIterations: 200 });\n */\nexport const configureStateit = (opts: { maxEffectIterations?: number }): void => {\n if (opts.maxEffectIterations !== undefined) _maxEffectIterations = opts.maxEffectIterations;\n};\n\n/**\n * Resets the shared reactive context. Use in test setup/teardown to prevent state\n * leaks between tests when a batch or effect throws without being fully cleaned up.\n */\nexport const _resetContextForTesting = (): void => {\n queue.depth = 0;\n scope.deps = null;\n scope.effect = null;\n scope.cleanups = null;\n queue.pending.clear();\n};\n\n/** @internal Base reactive node: manages a subscriber set and batch-aware notification. */\nexport class ReactiveNode {\n #subscribers = new Set<EffectCallback>();\n\n /** Register the current tracking scope as a subscriber and store an unsubscribe\n * function in scope.deps for automatic cleanup when the effect re-runs. */\n protected _track(): void {\n if (scope.deps !== null && scope.effect !== null) {\n const fn = scope.effect;\n\n this.#subscribers.add(fn);\n scope.deps.add(() => this.#subscribers.delete(fn));\n }\n }\n\n /** Notify all subscribers. Respects batch queue depth. */\n protected _notify(): void {\n if (this.#subscribers.size === 0) return;\n\n if (queue.depth > 0) {\n for (const fn of this.#subscribers) queue.pending.add(fn);\n\n return;\n }\n\n const errors: unknown[] = [];\n\n for (const fn of [...this.#subscribers]) {\n try {\n fn();\n } catch (e) {\n errors.push(e);\n }\n }\n\n if (errors.length) {\n throw errors.length === 1 ? errors[0] : new AggregateError(errors, '[stateit] multiple subscriber errors');\n }\n }\n}\n\n/** @internal Save scope fields, swap to new tracking context, call fn, restore. */\nexport const _withCtx = <T>(\n eff: EffectCallback | null,\n deps: Set<CleanupFn> | null,\n cleanups: CleanupFn[] | null,\n fn: () => T,\n): T => {\n const pe = scope.effect;\n const pd = scope.deps;\n const pc = scope.cleanups;\n\n scope.effect = eff;\n scope.deps = deps;\n scope.cleanups = cleanups;\n\n try {\n return fn();\n } finally {\n scope.effect = pe;\n scope.deps = pd;\n scope.cleanups = pc;\n }\n};\n"],"mappings":";AAKA,IAAa,IAAiB,OAAO,wBAAwB,EAGhD,IAAQ;CACnB,UAAU;CACV,MAAM;CACN,QAAQ;CACT,EAGY,IAAQ;CACnB,OAAO;CACP,yBAAS,IAAI,KAAqB;CACnC,EAEU,IAAuB,KAMrB,KAAoB,MAAiD;AAChF,CAAI,EAAK,wBAAwB,KAAA,MAAW,IAAuB,EAAK;GAO7D,UAAsC;AAKjD,CAJA,EAAM,QAAQ,GACd,EAAM,OAAO,MACb,EAAM,SAAS,MACf,EAAM,WAAW,MACjB,EAAM,QAAQ,OAAO;GAIV,IAAb,MAA0B;CACxB,qBAAe,IAAI,KAAqB;CAIxC,SAAyB;AACvB,MAAI,EAAM,SAAS,QAAQ,EAAM,WAAW,MAAM;GAChD,IAAM,IAAK,EAAM;AAGjB,GADA,MAAA,EAAkB,IAAI,EAAG,EACzB,EAAM,KAAK,UAAU,MAAA,EAAkB,OAAO,EAAG,CAAC;;;CAKtD,UAA0B;AACxB,MAAI,MAAA,EAAkB,SAAS,EAAG;AAElC,MAAI,EAAM,QAAQ,GAAG;AACnB,QAAK,IAAM,KAAM,MAAA,EAAmB,GAAM,QAAQ,IAAI,EAAG;AAEzD;;EAGF,IAAM,IAAoB,EAAE;AAE5B,OAAK,IAAM,KAAM,CAAC,GAAG,MAAA,EAAkB,CACrC,KAAI;AACF,MAAI;WACG,GAAG;AACV,KAAO,KAAK,EAAE;;AAIlB,MAAI,EAAO,OACT,OAAM,EAAO,WAAW,IAAI,EAAO,KAAS,eAAe,GAAQ,uCAAuC;;GAMnG,KACX,GACA,GACA,GACA,MACM;CACN,IAAM,IAAK,EAAM,QACX,IAAK,EAAM,MACX,IAAK,EAAM;AAIjB,CAFA,EAAM,SAAS,GACf,EAAM,OAAO,GACb,EAAM,WAAW;AAEjB,KAAI;AACF,SAAO,GAAI;WACH;AAGR,EAFA,EAAM,SAAS,GACf,EAAM,OAAO,GACb,EAAM,WAAW"}
|
package/dist/signal.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./runtime.cjs`),t=require(`./types.cjs`);var n=class extends e.ReactiveNode{[t._SIGNAL_BRAND]=!0;#e;#t;constructor(e,t){super(),this.#e=e,this.#t=t?.equals??Object.is}get value(){return this._track(),this.#e}set value(e){this.#t(this.#e,e)||(this.#e=e,this._notify())}update(e){this.value=e(this.#e)}peek(){return this.#e}},r=(e,t)=>new n(e,t),i=new WeakMap,a=e=>{let n=i.get(e);if(n)return n;let r={get[t._SIGNAL_BRAND](){return!0},peek:()=>e.peek(),get value(){return e.value}};return i.set(e,r),r},o=e=>typeof e==`object`&&!!e&&t._SIGNAL_BRAND in e,s=e=>o(e)?e.value:e,c=e=>o(e)?e.peek():e;exports.SignalImpl=n,exports.isSignal=o,exports.peekValue=c,exports.readonly=a,exports.signal=r,exports.toValue=s;
|
|
2
|
-
//# sourceMappingURL=signal.cjs.map
|
package/dist/signal.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signal.cjs","names":["#value","#equals"],"sources":["../src/signal.ts"],"sourcesContent":["import { ReactiveNode } from './runtime';\nimport { type EqualityFn, type ReactiveOptions, type ReadonlySignal, type Signal, _SIGNAL_BRAND } from './types';\n\n/** @internal */\nexport class SignalImpl<T> extends ReactiveNode implements Signal<T> {\n readonly [_SIGNAL_BRAND] = true as const;\n #value: T;\n #equals: EqualityFn<T>;\n\n constructor(initial: T, options?: ReactiveOptions<T>) {\n super();\n this.#value = initial;\n this.#equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this._track();\n\n return this.#value;\n }\n\n set value(next: T) {\n if (this.#equals(this.#value, next)) return;\n\n this.#value = next;\n this._notify();\n }\n\n update(fn: (current: T) => T): void {\n this.value = fn(this.#value);\n }\n\n peek(): T {\n return this.#value;\n }\n}\n\n/** Creates a reactive signal holding a single value. */\nexport const signal = <T>(initial: T, options?: ReactiveOptions<T>): Signal<T> => new SignalImpl(initial, options);\n\nconst _readonlyCache = new WeakMap<object, ReadonlySignal<unknown>>();\n\n/**\n * Returns a stable read-only view of a signal. Hides the setter at both type and runtime\n * level. The wrapper is cached — repeated calls with the same signal return the same reference.\n */\nexport const readonly = <T>(sig: ReadonlySignal<T>): ReadonlySignal<T> => {\n const cached = _readonlyCache.get(sig as object);\n\n if (cached) return cached as ReadonlySignal<T>;\n\n const wrapper: ReadonlySignal<T> = {\n get [_SIGNAL_BRAND]() {\n return true as const;\n },\n peek: () => sig.peek(),\n get value() {\n return sig.value;\n },\n };\n\n _readonlyCache.set(sig as object, wrapper as ReadonlySignal<unknown>);\n\n return wrapper;\n};\n\n/** Type guard -- identifies Signal instances (works through composition and subclasses). */\nexport const isSignal = <T = unknown>(value: unknown): value is ReadonlySignal<T> =>\n typeof value === 'object' && value !== null && _SIGNAL_BRAND in (value as object);\n\n/** Unwraps a plain value or Signal to its current value. Reads are tracked if called inside an effect. */\nexport const toValue = <T>(v: T | ReadonlySignal<T>): T => (isSignal<T>(v) ? v.value : v);\n\n/** Unwraps a plain value or Signal to its current value without registering a reactive subscription. */\nexport const peekValue = <T>(v: T | ReadonlySignal<T>): T => (isSignal<T>(v) ? v.peek() : v);\n"],"mappings":"0DAIA,IAAa,EAAb,cAAmC,EAAA,YAAkC,CACnE,CAAU,EAAA,eAAiB,GAC3B,GACA,GAEA,YAAY,EAAY,EAA8B,CACpD,OAAO,CACP,MAAA,EAAc,EACd,MAAA,EAAe,GAAS,QAAU,OAAO,GAG3C,IAAI,OAAW,CAGb,OAFA,KAAK,QAAQ,CAEN,MAAA,EAGT,IAAI,MAAM,EAAS,CACb,MAAA,EAAa,MAAA,EAAa,EAAK,GAEnC,MAAA,EAAc,EACd,KAAK,SAAS,EAGhB,OAAO,EAA6B,CAClC,KAAK,MAAQ,EAAG,MAAA,EAAY,CAG9B,MAAU,CACR,OAAO,MAAA,IAKE,GAAa,EAAY,IAA4C,IAAI,EAAW,EAAS,EAAQ,CAE5G,EAAiB,IAAI,QAMd,EAAe,GAA8C,CACxE,IAAM,EAAS,EAAe,IAAI,EAAc,CAEhD,GAAI,EAAQ,OAAO,EAEnB,IAAM,EAA6B,CACjC,IAAK,EAAA,gBAAiB,CACpB,MAAO,IAET,SAAY,EAAI,MAAM,CACtB,IAAI,OAAQ,CACV,OAAO,EAAI,OAEd,CAID,OAFA,EAAe,IAAI,EAAe,EAAmC,CAE9D,GAII,EAAyB,GACpC,OAAO,GAAU,YAAY,GAAkB,EAAA,iBAAkB,EAGtD,EAAc,GAAiC,EAAY,EAAE,CAAG,EAAE,MAAQ,EAG1E,EAAgB,GAAiC,EAAY,EAAE,CAAG,EAAE,MAAM,CAAG"}
|
package/dist/signal.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ReactiveNode } from './runtime';
|
|
2
|
-
import { type ReactiveOptions, type ReadonlySignal, type Signal, _SIGNAL_BRAND } from './types';
|
|
3
|
-
/** @internal */
|
|
4
|
-
export declare class SignalImpl<T> extends ReactiveNode implements Signal<T> {
|
|
5
|
-
#private;
|
|
6
|
-
readonly [_SIGNAL_BRAND]: true;
|
|
7
|
-
constructor(initial: T, options?: ReactiveOptions<T>);
|
|
8
|
-
get value(): T;
|
|
9
|
-
set value(next: T);
|
|
10
|
-
update(fn: (current: T) => T): void;
|
|
11
|
-
peek(): T;
|
|
12
|
-
}
|
|
13
|
-
/** Creates a reactive signal holding a single value. */
|
|
14
|
-
export declare const signal: <T>(initial: T, options?: ReactiveOptions<T>) => Signal<T>;
|
|
15
|
-
/**
|
|
16
|
-
* Returns a stable read-only view of a signal. Hides the setter at both type and runtime
|
|
17
|
-
* level. The wrapper is cached — repeated calls with the same signal return the same reference.
|
|
18
|
-
*/
|
|
19
|
-
export declare const readonly: <T>(sig: ReadonlySignal<T>) => ReadonlySignal<T>;
|
|
20
|
-
/** Type guard -- identifies Signal instances (works through composition and subclasses). */
|
|
21
|
-
export declare const isSignal: <T = unknown>(value: unknown) => value is ReadonlySignal<T>;
|
|
22
|
-
/** Unwraps a plain value or Signal to its current value. Reads are tracked if called inside an effect. */
|
|
23
|
-
export declare const toValue: <T>(v: T | ReadonlySignal<T>) => T;
|
|
24
|
-
/** Unwraps a plain value or Signal to its current value without registering a reactive subscription. */
|
|
25
|
-
export declare const peekValue: <T>(v: T | ReadonlySignal<T>) => T;
|
|
26
|
-
//# sourceMappingURL=signal.d.ts.map
|
package/dist/signal.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEjH,gBAAgB;AAChB,qBAAa,UAAU,CAAC,CAAC,CAAE,SAAQ,YAAa,YAAW,MAAM,CAAC,CAAC,CAAC;;IAClE,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAG,IAAI,CAAU;gBAI7B,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;IAMpD,IAAI,KAAK,IAAI,CAAC,CAIb;IAED,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,EAKhB;IAED,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI;IAInC,IAAI,IAAI,CAAC;CAGV;AAED,wDAAwD;AACxD,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,SAAS,CAAC,EAAE,UAAU,eAAe,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,CAAC,CAAqC,CAAC;AAInH;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,cAAc,CAAC,CAAC,CAAC,KAAG,cAAc,CAAC,CAAC,CAkBpE,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,OAAO,EAAE,OAAO,OAAO,KAAG,KAAK,IAAI,cAAc,CAAC,CAAC,CACG,CAAC;AAEpF,0GAA0G;AAC1G,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,KAAG,CAAmC,CAAC;AAE1F,wGAAwG;AACxG,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,KAAG,CAAoC,CAAC"}
|
package/dist/signal.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ReactiveNode as e } from "./runtime.js";
|
|
2
|
-
import { _SIGNAL_BRAND as t } from "./types.js";
|
|
3
|
-
//#region src/signal.ts
|
|
4
|
-
var n = class extends e {
|
|
5
|
-
[t] = !0;
|
|
6
|
-
#e;
|
|
7
|
-
#t;
|
|
8
|
-
constructor(e, t) {
|
|
9
|
-
super(), this.#e = e, this.#t = t?.equals ?? Object.is;
|
|
10
|
-
}
|
|
11
|
-
get value() {
|
|
12
|
-
return this._track(), this.#e;
|
|
13
|
-
}
|
|
14
|
-
set value(e) {
|
|
15
|
-
this.#t(this.#e, e) || (this.#e = e, this._notify());
|
|
16
|
-
}
|
|
17
|
-
update(e) {
|
|
18
|
-
this.value = e(this.#e);
|
|
19
|
-
}
|
|
20
|
-
peek() {
|
|
21
|
-
return this.#e;
|
|
22
|
-
}
|
|
23
|
-
}, r = (e, t) => new n(e, t), i = /* @__PURE__ */ new WeakMap(), a = (e) => {
|
|
24
|
-
let n = i.get(e);
|
|
25
|
-
if (n) return n;
|
|
26
|
-
let r = {
|
|
27
|
-
get [t]() {
|
|
28
|
-
return !0;
|
|
29
|
-
},
|
|
30
|
-
peek: () => e.peek(),
|
|
31
|
-
get value() {
|
|
32
|
-
return e.value;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
return i.set(e, r), r;
|
|
36
|
-
}, o = (e) => typeof e == "object" && !!e && t in e, s = (e) => o(e) ? e.value : e, c = (e) => o(e) ? e.peek() : e;
|
|
37
|
-
//#endregion
|
|
38
|
-
export { n as SignalImpl, o as isSignal, c as peekValue, a as readonly, r as signal, s as toValue };
|
|
39
|
-
|
|
40
|
-
//# sourceMappingURL=signal.js.map
|
package/dist/signal.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signal.js","names":["#value","#equals"],"sources":["../src/signal.ts"],"sourcesContent":["import { ReactiveNode } from './runtime';\nimport { type EqualityFn, type ReactiveOptions, type ReadonlySignal, type Signal, _SIGNAL_BRAND } from './types';\n\n/** @internal */\nexport class SignalImpl<T> extends ReactiveNode implements Signal<T> {\n readonly [_SIGNAL_BRAND] = true as const;\n #value: T;\n #equals: EqualityFn<T>;\n\n constructor(initial: T, options?: ReactiveOptions<T>) {\n super();\n this.#value = initial;\n this.#equals = options?.equals ?? Object.is;\n }\n\n get value(): T {\n this._track();\n\n return this.#value;\n }\n\n set value(next: T) {\n if (this.#equals(this.#value, next)) return;\n\n this.#value = next;\n this._notify();\n }\n\n update(fn: (current: T) => T): void {\n this.value = fn(this.#value);\n }\n\n peek(): T {\n return this.#value;\n }\n}\n\n/** Creates a reactive signal holding a single value. */\nexport const signal = <T>(initial: T, options?: ReactiveOptions<T>): Signal<T> => new SignalImpl(initial, options);\n\nconst _readonlyCache = new WeakMap<object, ReadonlySignal<unknown>>();\n\n/**\n * Returns a stable read-only view of a signal. Hides the setter at both type and runtime\n * level. The wrapper is cached — repeated calls with the same signal return the same reference.\n */\nexport const readonly = <T>(sig: ReadonlySignal<T>): ReadonlySignal<T> => {\n const cached = _readonlyCache.get(sig as object);\n\n if (cached) return cached as ReadonlySignal<T>;\n\n const wrapper: ReadonlySignal<T> = {\n get [_SIGNAL_BRAND]() {\n return true as const;\n },\n peek: () => sig.peek(),\n get value() {\n return sig.value;\n },\n };\n\n _readonlyCache.set(sig as object, wrapper as ReadonlySignal<unknown>);\n\n return wrapper;\n};\n\n/** Type guard -- identifies Signal instances (works through composition and subclasses). */\nexport const isSignal = <T = unknown>(value: unknown): value is ReadonlySignal<T> =>\n typeof value === 'object' && value !== null && _SIGNAL_BRAND in (value as object);\n\n/** Unwraps a plain value or Signal to its current value. Reads are tracked if called inside an effect. */\nexport const toValue = <T>(v: T | ReadonlySignal<T>): T => (isSignal<T>(v) ? v.value : v);\n\n/** Unwraps a plain value or Signal to its current value without registering a reactive subscription. */\nexport const peekValue = <T>(v: T | ReadonlySignal<T>): T => (isSignal<T>(v) ? v.peek() : v);\n"],"mappings":";;;AAIA,IAAa,IAAb,cAAmC,EAAkC;CACnE,CAAU,KAAiB;CAC3B;CACA;CAEA,YAAY,GAAY,GAA8B;AAGpD,EAFA,OAAO,EACP,MAAA,IAAc,GACd,MAAA,IAAe,GAAS,UAAU,OAAO;;CAG3C,IAAI,QAAW;AAGb,SAFA,KAAK,QAAQ,EAEN,MAAA;;CAGT,IAAI,MAAM,GAAS;AACb,QAAA,EAAa,MAAA,GAAa,EAAK,KAEnC,MAAA,IAAc,GACd,KAAK,SAAS;;CAGhB,OAAO,GAA6B;AAClC,OAAK,QAAQ,EAAG,MAAA,EAAY;;CAG9B,OAAU;AACR,SAAO,MAAA;;GAKE,KAAa,GAAY,MAA4C,IAAI,EAAW,GAAS,EAAQ,EAE5G,oBAAiB,IAAI,SAA0C,EAMxD,KAAe,MAA8C;CACxE,IAAM,IAAS,EAAe,IAAI,EAAc;AAEhD,KAAI,EAAQ,QAAO;CAEnB,IAAM,IAA6B;EACjC,KAAK,KAAiB;AACpB,UAAO;;EAET,YAAY,EAAI,MAAM;EACtB,IAAI,QAAQ;AACV,UAAO,EAAI;;EAEd;AAID,QAFA,EAAe,IAAI,GAAe,EAAmC,EAE9D;GAII,KAAyB,MACpC,OAAO,KAAU,cAAY,KAAkB,KAAkB,GAGtD,KAAc,MAAiC,EAAY,EAAE,GAAG,EAAE,QAAQ,GAG1E,KAAgB,MAAiC,EAAY,EAAE,GAAG,EAAE,MAAM,GAAG"}
|
package/dist/store.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./types.cjs`),t=require(`./computed.cjs`),n=require(`./signal.cjs`);var r=(e,t)=>{if(e===t)return!0;if(e==null||t==null)return e===t;if(typeof e!=`object`||typeof t!=`object`)return!1;let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r of n)if(!Object.is(e[r],t[r]))return!1;return!0},i=class extends n.SignalImpl{[e._STORE_BRAND]=!0;#e;#t=!1;constructor(e,t){super(e,{equals:t?.equals??r}),this.#e={...e}}get frozen(){return this.#t}get value(){return super.value}set value(e){this.#t||(super.value=e)}patch(e){this.value={...this.peek(),...e}}update(e){this.value=e({...this.peek()})}reset(){this.value={...this.#e}}select(e,n){return t.computed(()=>e(this.value),n)}freeze(){this.#t=!0}},a=(e,t)=>new i(e,t),o=t=>typeof t==`object`&&!!t&&e._STORE_BRAND in t;exports.isStore=o,exports.shallowEqual=r,exports.store=a;
|
|
2
|
-
//# sourceMappingURL=store.cjs.map
|
package/dist/store.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store.cjs","names":["#initial","#frozen"],"sources":["../src/store.ts"],"sourcesContent":["import { type ComputedSignal, computed } from './computed';\nimport { _DEV } from './runtime';\nimport { SignalImpl } from './signal';\nimport { type EqualityFn, type ReactiveOptions, type Signal, _STORE_BRAND } from './types';\n\n/**\n * Shallow structural equality — compares own enumerable keys by reference.\n * This is the default equality function used by `store()`. Export it to avoid\n * reimplementation when composing custom `StoreOptions.equals`.\n */\nexport const shallowEqual: EqualityFn<unknown> = (a, b) => {\n if (a === b) return true;\n\n if (a == null || b == null) return a === b;\n\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n\n const keysA = Object.keys(a as object);\n const keysB = Object.keys(b as object);\n\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.is((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) return false;\n }\n\n return true;\n};\n\nexport type StoreOptions<T extends object> = {\n /** Custom equality for top-level change detection. Default: shallowEqual */\n equals?: EqualityFn<T>;\n};\n\n/** Reactive store for object state. Implements Signal<T> so all signal primitives work natively. */\nexport interface Store<T extends object> extends Signal<T> {\n readonly frozen: boolean;\n /** Shallow-merge a partial object into the current state. */\n patch(partial: Partial<T>): void;\n /** Derive the next state from the current state via an updater function.\n * Receives a shallow copy of the current state — mutations in the updater are safe. */\n update(fn: (s: T) => T): void;\n /** Reset to the original initial state. */\n reset(): void;\n /** Create a lazily recomputed derived signal from a slice of this store's state. */\n select<U>(selector: (s: T) => U, options?: ReactiveOptions<U>): ComputedSignal<U>;\n /** Freeze the store. Further writes via patch/update/reset are silently ignored. */\n freeze(): void;\n}\n\n/** @internal */\nclass StoreImpl<T extends object> extends SignalImpl<T> implements Store<T> {\n readonly [_STORE_BRAND] = true as const;\n\n readonly #initial: T;\n #frozen = false;\n\n constructor(initial: T, options?: StoreOptions<T>) {\n super(initial, { equals: options?.equals ?? (shallowEqual as EqualityFn<T>) });\n this.#initial = { ...initial }; // defensive copy — external mutation cannot corrupt reset()\n }\n\n get frozen(): boolean {\n return this.#frozen;\n }\n\n override get value(): T {\n return super.value;\n }\n\n override set value(next: T) {\n if (this.#frozen) {\n if (_DEV) console.warn('[stateit] store is frozen — write ignored.');\n\n return;\n }\n\n super.value = next;\n }\n\n patch(partial: Partial<T>): void {\n this.value = { ...this.peek(), ...partial };\n }\n\n update(fn: (s: T) => T): void {\n this.value = fn({ ...this.peek() });\n }\n\n reset(): void {\n this.value = { ...this.#initial };\n }\n\n select<U>(selector: (s: T) => U, options?: ReactiveOptions<U>): ComputedSignal<U> {\n return computed(() => selector(this.value), options);\n }\n\n freeze(): void {\n this.#frozen = true;\n }\n}\n\n/** Creates a reactive store for the object state. */\nexport const store = <T extends object>(initial: T, options?: StoreOptions<T>): Store<T> =>\n new StoreImpl(initial, options);\n\n/** Type guard -- identifies Store instances. */\nexport const isStore = <T extends object = Record<string, unknown>>(value: unknown): value is Store<T> =>\n typeof value === 'object' && value !== null && _STORE_BRAND in value;\n"],"mappings":"qFAUA,IAAa,GAAqC,EAAG,IAAM,CACzD,GAAI,IAAM,EAAG,MAAO,GAEpB,GAAI,GAAK,MAAQ,GAAK,KAAM,OAAO,IAAM,EAEzC,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,SAAU,MAAO,GAE3D,IAAM,EAAQ,OAAO,KAAK,EAAY,CAChC,EAAQ,OAAO,KAAK,EAAY,CAEtC,GAAI,EAAM,SAAW,EAAM,OAAQ,MAAO,GAE1C,IAAK,IAAM,KAAO,EAChB,GAAI,CAAC,OAAO,GAAI,EAA8B,GAAO,EAA8B,GAAK,CAAE,MAAO,GAGnG,MAAO,IAyBH,EAAN,cAA0C,EAAA,UAAkC,CAC1E,CAAU,EAAA,cAAgB,GAE1B,GACA,GAAU,GAEV,YAAY,EAAY,EAA2B,CACjD,MAAM,EAAS,CAAE,OAAQ,GAAS,QAAW,EAAgC,CAAC,CAC9E,MAAA,EAAgB,CAAE,GAAG,EAAS,CAGhC,IAAI,QAAkB,CACpB,OAAO,MAAA,EAGT,IAAa,OAAW,CACtB,OAAO,MAAM,MAGf,IAAa,MAAM,EAAS,CACtB,MAAA,IAMJ,MAAM,MAAQ,GAGhB,MAAM,EAA2B,CAC/B,KAAK,MAAQ,CAAE,GAAG,KAAK,MAAM,CAAE,GAAG,EAAS,CAG7C,OAAO,EAAuB,CAC5B,KAAK,MAAQ,EAAG,CAAE,GAAG,KAAK,MAAM,CAAE,CAAC,CAGrC,OAAc,CACZ,KAAK,MAAQ,CAAE,GAAG,MAAA,EAAe,CAGnC,OAAU,EAAuB,EAAiD,CAChF,OAAO,EAAA,aAAe,EAAS,KAAK,MAAM,CAAE,EAAQ,CAGtD,QAAe,CACb,MAAA,EAAe,KAKN,GAA2B,EAAY,IAClD,IAAI,EAAU,EAAS,EAAQ,CAGpB,EAAuD,GAClE,OAAO,GAAU,YAAY,GAAkB,EAAA,gBAAgB"}
|
package/dist/store.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { type ComputedSignal } from './computed';
|
|
2
|
-
import { type EqualityFn, type ReactiveOptions, type Signal } from './types';
|
|
3
|
-
/**
|
|
4
|
-
* Shallow structural equality — compares own enumerable keys by reference.
|
|
5
|
-
* This is the default equality function used by `store()`. Export it to avoid
|
|
6
|
-
* reimplementation when composing custom `StoreOptions.equals`.
|
|
7
|
-
*/
|
|
8
|
-
export declare const shallowEqual: EqualityFn<unknown>;
|
|
9
|
-
export type StoreOptions<T extends object> = {
|
|
10
|
-
/** Custom equality for top-level change detection. Default: shallowEqual */
|
|
11
|
-
equals?: EqualityFn<T>;
|
|
12
|
-
};
|
|
13
|
-
/** Reactive store for object state. Implements Signal<T> so all signal primitives work natively. */
|
|
14
|
-
export interface Store<T extends object> extends Signal<T> {
|
|
15
|
-
readonly frozen: boolean;
|
|
16
|
-
/** Shallow-merge a partial object into the current state. */
|
|
17
|
-
patch(partial: Partial<T>): void;
|
|
18
|
-
/** Derive the next state from the current state via an updater function.
|
|
19
|
-
* Receives a shallow copy of the current state — mutations in the updater are safe. */
|
|
20
|
-
update(fn: (s: T) => T): void;
|
|
21
|
-
/** Reset to the original initial state. */
|
|
22
|
-
reset(): void;
|
|
23
|
-
/** Create a lazily recomputed derived signal from a slice of this store's state. */
|
|
24
|
-
select<U>(selector: (s: T) => U, options?: ReactiveOptions<U>): ComputedSignal<U>;
|
|
25
|
-
/** Freeze the store. Further writes via patch/update/reset are silently ignored. */
|
|
26
|
-
freeze(): void;
|
|
27
|
-
}
|
|
28
|
-
/** Creates a reactive store for the object state. */
|
|
29
|
-
export declare const store: <T extends object>(initial: T, options?: StoreOptions<T>) => Store<T>;
|
|
30
|
-
/** Type guard -- identifies Store instances. */
|
|
31
|
-
export declare const isStore: <T extends object = Record<string, unknown>>(value: unknown) => value is Store<T>;
|
|
32
|
-
//# sourceMappingURL=store.d.ts.map
|