@virtuoso.dev/gurx
Advanced tools
+17
| # Change Log - @virtuoso.dev/gurx | ||
| ## 1.1.0 | ||
| ### Minor Changes | ||
| - 59ba51f: Support legacy react | ||
| This log was last generated on Sat, 04 Jan 2025 18:09:03 GMT and should not be manually modified. | ||
| ## 1.0.0 | ||
| Sat, 04 Jan 2025 18:09:03 GMT | ||
| ### Breaking changes | ||
| - Initial version publish |
+208
-206
@@ -116,5 +116,5 @@ import { JSX as JSX_2 } from 'react/jsx-runtime'; | ||
| */ | ||
| export declare function handlePromise<I, OutSuccess, OnLoad, OutError>(onLoad: () => OnLoad, onSuccess: (value: I) => OutSuccess, onError: (error: unknown) => OutError): Operator<I | Promise<I>, OutSuccess | OnLoad | OutError>; | ||
| export declare function handlePromise<I, OutSuccess, OnLoad, OutError>(onLoad: () => OnLoad, onSuccess: (value: I) => OutSuccess, onError: (error: unknown) => OutError): Operator<I | Promise<I>, OnLoad | OutError | OutSuccess>; | ||
| export declare type Inp<T = unknown> = NodeRef<T> | PipeRef<T, unknown>; | ||
| export declare type Inp<T = unknown> = NodeRef<T> | PipeRef<T>; | ||
@@ -196,22 +196,22 @@ export declare const link: Realm['link']; | ||
| declare interface QueryErrorResult { | ||
| type: 'error'; | ||
| isLoading: false; | ||
| data: null; | ||
| error: Error; | ||
| isLoading: false; | ||
| type: 'error'; | ||
| } | ||
| declare interface QueryLoadingResult { | ||
| type: 'loading'; | ||
| isLoading: true; | ||
| data: null; | ||
| error: null; | ||
| isLoading: true; | ||
| type: 'loading'; | ||
| } | ||
| declare type QueryResult<T> = QueryLoadingResult | QuerySuccessResult<T> | QueryErrorResult; | ||
| declare type QueryResult<T> = QueryErrorResult | QueryLoadingResult | QuerySuccessResult<T>; | ||
| declare interface QuerySuccessResult<T> { | ||
| type: 'success'; | ||
| isLoading: false; | ||
| data: T; | ||
| error: null; | ||
| isLoading: false; | ||
| type: 'success'; | ||
| } | ||
@@ -224,10 +224,10 @@ | ||
| export declare class Realm { | ||
| private readonly subscriptions; | ||
| private readonly singletonSubscriptions; | ||
| private readonly graph; | ||
| private readonly state; | ||
| private readonly definitionRegistry; | ||
| private readonly distinctNodes; | ||
| private readonly executionMaps; | ||
| private readonly definitionRegistry; | ||
| private readonly graph; | ||
| private readonly pipeMap; | ||
| private readonly singletonSubscriptions; | ||
| private readonly state; | ||
| private readonly subscriptions; | ||
| /** | ||
@@ -248,186 +248,21 @@ * Creates a new realm. | ||
| /** | ||
| * Creates or resolves an existing signal instance in the realm. Useful as a joint point when building your own operators. | ||
| * @returns a reference to the signal. | ||
| * @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle. | ||
| * @param node - optional, a reference to a signal. If the signal has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference. | ||
| */ | ||
| signalInstance<T>(distinct?: Distinct<T>, node?: symbol): NodeRef<T>; | ||
| /** | ||
| * Subscribes to the values published in the referred node. | ||
| * @param node - the cell/signal to subscribe to. | ||
| * @param subscription - the callback to execute when the node receives a new value. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * Convenient for mutation of cells that contian non-primitive values (e.g. arrays, or objects). | ||
| * Specifies that the cell value should be changed when source emits, with the result of the map callback parameter. | ||
| * the map parameter gets called with the current value of the cell and the value published through the source. | ||
| * @typeParam T - the type of the cell value. | ||
| * @typeParam K - the type of the value published through the source. | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * const unsub = r.sub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * unsub() | ||
| * r.pub(signal$, 3) | ||
| * ``` | ||
| */ | ||
| sub<T>(node: Out<T>, subscription: Subscription<T>): UnsubscribeHandle; | ||
| /** | ||
| * Subscribes exclusively to values in the referred node. | ||
| * Calling this multiple times on a single node will remove the previous subscription created through `singletonSub`. | ||
| * Subscriptions created through `sub` are not affected. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * // console.log will run only once. | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * ``` | ||
| */ | ||
| singletonSub<T>(node: Out<T>, subscription: Subscription<T> | undefined): UnsubscribeHandle; | ||
| /** | ||
| * Clears all exclusive subscriptions. | ||
| */ | ||
| resetSingletonSubs(): void; | ||
| /** | ||
| * Subscribes to multiple nodes at once. If any of the nodes emits a value, the subscription will be called with an array of the latest values from each node. | ||
| * If the nodes change within a single execution cycle, the subscription will be called only once with the final node values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const trigger$ = Signal<number>(true, (r) => { | ||
| * r.link(r.pipe(trigger$, map(i => `foo${i}`)), foo$) | ||
| * r.link(r.pipe(trigger$, map(i => `bar${i}`)), bar$) | ||
| * const items$ = Cell<string[]([]) | ||
| * const addItem$ = Signal<string>(false, (r) => { | ||
| * r.changeWith(items$, addItem$, (items, item) => [...items, item]) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.subMultiple([foo$, bar$], ([foo, bar]) => console.log(foo, bar)) | ||
| * r.pub(trigger$, 2) | ||
| * r.pub(addItem$, 'foo') | ||
| * r.pub(addItem$, 'bar') | ||
| * r.getValue(items$) // ['foo', 'bar'] | ||
| * ``` | ||
| */ | ||
| subMultiple<T1>(nodes: [Out<T1>], subscription: Subscription<[T1]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2>(nodes: [Out<T1>, Out<T2>], subscription: Subscription<[T1, T2]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3>(nodes: [Out<T1>, Out<T2>, Out<T3>], subscription: Subscription<[T1, T2, T3]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>], subscription: Subscription<[T1, T2, T3, T4]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>], subscription: Subscription<[T1, T2, T3, T4, T5]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>], subscription: Subscription<[T1, T2, T3, T4, T5, T6]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6, T7>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>, Out<T7>], subscription: Subscription<[T1, T2, T3, T4, T5, T6, T7]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6, T7, T8>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>, Out<T7>, Out<T8>], subscription: Subscription<[T1, T2, T3, T4, T5, T6, T7, T8]>): UnsubscribeHandle; | ||
| subMultiple(nodes: Out[], subscription: Subscription<any>): UnsubscribeHandle; | ||
| changeWith<T, K>(cell: Inp<T>, source: Out<K>, map: (cellValue: T, signalValue: K) => T): void; | ||
| /** | ||
| * Publishes into multiple nodes simultaneously, triggering a single re-computation cycle. | ||
| * @param values - a record of node references and their values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const r = new Realm() | ||
| * r.pubIn({[foo$]: 'foo1', [bar$]: 'bar1'}) | ||
| * ``` | ||
| */ | ||
| pubIn(values: Record<symbol, unknown>): void; | ||
| /** | ||
| * A low-level utility that connects multiple nodes to a sink node with a map function. Used as a foundation for the higher-level operators. | ||
| * The nodes can be active (sources) or passive (pulls). | ||
| */ | ||
| connect<T extends unknown[] = unknown[]>({ sources, pulls, map, sink, }: { | ||
| /** | ||
| * The source nodes that emit values to the sink node. The values will be passed as arguments to the map function. | ||
| */ | ||
| sources: Out[]; | ||
| /** | ||
| * The nodes which values will be pulled. The values will be passed as arguments to the map function. | ||
| */ | ||
| pulls?: Out[]; | ||
| /** | ||
| * The sink node that will receive the result of the map function. | ||
| */ | ||
| sink: Inp; | ||
| /** | ||
| * The projection function that will be called when any of the source nodes emits. | ||
| */ | ||
| map: ProjectionFunc<T>; | ||
| }): void; | ||
| /** | ||
| * Runs the subscrptions of this node. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Action((r) => { | ||
| * r.sub(foo$, console.log) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.pub(foo$) | ||
| */ | ||
| pub<T>(node: Inp<T>): void; | ||
| /** | ||
| * Publishes the specified value into a node. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const r = new Realm() | ||
| * r.pub(foo$, 'bar') | ||
| */ | ||
| pub<T>(node: Inp<T>, value: T): void; | ||
| /** | ||
| * Creates a new node that emits the values of the source node transformed through the specified operators. | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>(true, (r) => { | ||
| * const signalPlusOne$ = r.pipe(signal$, map(i => i + 1)) | ||
| * r.sub(signalPlusOne$, console.log) | ||
| * }) | ||
| * const r = new Realm() | ||
| * r.pub(signal$, 1) | ||
| */ | ||
| pipe<T>(s: Out<T>): NodeRef<T>; | ||
| pipe<T, O1>(s: Out<T>, o1: O<T, O1>): NodeRef<O1>; | ||
| pipe<T, O1, O2>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>]): NodeRef<O2>; | ||
| pipe<T, O1, O2, O3>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>]): NodeRef<O3>; | ||
| pipe<T, O1, O2, O3, O4>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>]): NodeRef<O4>; | ||
| pipe<T, O1, O2, O3, O4, O5>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>]): NodeRef<O5>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>]): NodeRef<O6>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>]): NodeRef<O7>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7, O8>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>, O<O7, O8>]): NodeRef<O8>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7, O8, O9>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>, O<O7, O8>, O<O8, O9>]): NodeRef<O9>; | ||
| pipe<T>(source: Out<T>, ...operators: O<unknown, unknown>[]): NodeRef; | ||
| /** | ||
| * Works as a reverse pipe. | ||
| * Constructs a function, that, when passed a certain node (sink), will create a node that will work as a publisher through the specified pipes into the sink. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * const entry$ = Signal<number>(true, (r) => { | ||
| * const transform = r.transformer(map(x: number => `num${x}`)) | ||
| * const transformFoo$ = transform(foo$) | ||
| * const transformBar$ = transform(bar$) | ||
| * r.link(entry$, transformFoo$) | ||
| * r.link(entry$, transformBar$) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.pub(entry$, 1) // Both foo$ and bar$ now contain `num1` | ||
| * ``` | ||
| */ | ||
| transformer<In>(...o: []): (s: Inp<In>) => Inp<In>; | ||
| transformer<In, Out>(...o: [O<In, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1>(...o: [O<In, O1>, O<O1, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2>(...o: [O<In, O1>, O<O1, O2>, O<O2, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3, O4>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3, O4, O5>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out>(...operators: O<unknown, unknown>[]): (s: Inp<Out>) => Inp<In>; | ||
| /** | ||
| * Links the output of a node to the input of another node. | ||
| */ | ||
| link<T>(source: Out<T>, sink: Inp<T>): void; | ||
| /** | ||
| * Combines the values from multiple nodes into a single node that emits an array of the latest values of the nodes. | ||
@@ -734,2 +569,24 @@ * | ||
| /** | ||
| * A low-level utility that connects multiple nodes to a sink node with a map function. Used as a foundation for the higher-level operators. | ||
| * The nodes can be active (sources) or passive (pulls). | ||
| */ | ||
| connect<T extends unknown[] = unknown[]>({ map, pulls, sink, sources, }: { | ||
| /** | ||
| * The projection function that will be called when any of the source nodes emits. | ||
| */ | ||
| map: ProjectionFunc<T>; | ||
| /** | ||
| * The nodes which values will be pulled. The values will be passed as arguments to the map function. | ||
| */ | ||
| pulls?: Out[]; | ||
| /** | ||
| * The sink node that will receive the result of the map function. | ||
| */ | ||
| sink: Inp; | ||
| /** | ||
| * The source nodes that emit values to the sink node. The values will be passed as arguments to the map function. | ||
| */ | ||
| sources: Out[]; | ||
| }): void; | ||
| /** | ||
| * Gets the current value of a node. The node must be stateful. | ||
@@ -768,3 +625,65 @@ * @remark if possible, use {@link withLatestFrom} or {@link combine}, as getValue will not create a dependency to the passed node, | ||
| getValues<T>(nodes: Out<T>[]): unknown[]; | ||
| inContext<T>(fn: () => T): T; | ||
| /** | ||
| * Links the output of a node to the input of another node. | ||
| */ | ||
| link<T>(source: Out<T>, sink: Inp<T>): void; | ||
| /** | ||
| * Creates a new node that emits the values of the source node transformed through the specified operators. | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>(true, (r) => { | ||
| * const signalPlusOne$ = r.pipe(signal$, map(i => i + 1)) | ||
| * r.sub(signalPlusOne$, console.log) | ||
| * }) | ||
| * const r = new Realm() | ||
| * r.pub(signal$, 1) | ||
| */ | ||
| pipe<T>(s: Out<T>): NodeRef<T>; | ||
| pipe<T, O1>(s: Out<T>, o1: O<T, O1>): NodeRef<O1>; | ||
| pipe<T, O1, O2>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>]): NodeRef<O2>; | ||
| pipe<T, O1, O2, O3>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>]): NodeRef<O3>; | ||
| pipe<T, O1, O2, O3, O4>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>]): NodeRef<O4>; | ||
| pipe<T, O1, O2, O3, O4, O5>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>]): NodeRef<O5>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>]): NodeRef<O6>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>]): NodeRef<O7>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7, O8>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>, O<O7, O8>]): NodeRef<O8>; | ||
| pipe<T, O1, O2, O3, O4, O5, O6, O7, O8, O9>(s: Out<T>, ...o: [O<T, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, O6>, O<O6, O7>, O<O7, O8>, O<O8, O9>]): NodeRef<O9>; | ||
| pipe<T>(source: Out<T>, ...operators: O<unknown, unknown>[]): NodeRef; | ||
| /** | ||
| * Runs the subscrptions of this node. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Action((r) => { | ||
| * r.sub(foo$, console.log) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.pub(foo$) | ||
| */ | ||
| pub<T>(node: Inp<T>): void; | ||
| /** | ||
| * Publishes the specified value into a node. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const r = new Realm() | ||
| * r.pub(foo$, 'bar') | ||
| */ | ||
| pub<T>(node: Inp<T>, value: T): void; | ||
| /** | ||
| * Publishes into multiple nodes simultaneously, triggering a single re-computation cycle. | ||
| * @param values - a record of node references and their values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const r = new Realm() | ||
| * r.pubIn({[foo$]: 'foo1', [bar$]: 'bar1'}) | ||
| * ``` | ||
| */ | ||
| pubIn(values: Record<symbol, unknown>): void; | ||
| /** | ||
| * Explicitly includes the specified cell/signal/pipe reference in the realm. | ||
@@ -775,25 +694,106 @@ * Most of the time you don't need to do that, since any interaction with the node through a realm will register it. | ||
| register(node$: NodeRef | PipeRef): NodeRef<any> | PipeRef<unknown, unknown>; | ||
| inContext<T>(fn: () => T): T; | ||
| /** | ||
| * Convenient for mutation of cells that contian non-primitive values (e.g. arrays, or objects). | ||
| * Specifies that the cell value should be changed when source emits, with the result of the map callback parameter. | ||
| * the map parameter gets called with the current value of the cell and the value published through the source. | ||
| * @typeParam T - the type of the cell value. | ||
| * @typeParam K - the type of the value published through the source. | ||
| * Clears all exclusive subscriptions. | ||
| */ | ||
| resetSingletonSubs(): void; | ||
| /** | ||
| * Creates or resolves an existing signal instance in the realm. Useful as a joint point when building your own operators. | ||
| * @returns a reference to the signal. | ||
| * @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle. | ||
| * @param node - optional, a reference to a signal. If the signal has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference. | ||
| */ | ||
| signalInstance<T>(distinct?: Distinct<T>, node?: symbol): NodeRef<T>; | ||
| /** | ||
| * Subscribes exclusively to values in the referred node. | ||
| * Calling this multiple times on a single node will remove the previous subscription created through `singletonSub`. | ||
| * Subscriptions created through `sub` are not affected. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const items$ = Cell<string[]([]) | ||
| * const addItem$ = Signal<string>(false, (r) => { | ||
| * r.changeWith(items$, addItem$, (items, item) => [...items, item]) | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * // console.log will run only once. | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * ``` | ||
| */ | ||
| singletonSub<T>(node: Out<T>, subscription: Subscription<T> | undefined): UnsubscribeHandle; | ||
| /** | ||
| * Subscribes to the values published in the referred node. | ||
| * @param node - the cell/signal to subscribe to. | ||
| * @param subscription - the callback to execute when the node receives a new value. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * const unsub = r.sub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * unsub() | ||
| * r.pub(signal$, 3) | ||
| * ``` | ||
| */ | ||
| sub<T>(node: Out<T>, subscription: Subscription<T>): UnsubscribeHandle; | ||
| /** | ||
| * Subscribes to multiple nodes at once. If any of the nodes emits a value, the subscription will be called with an array of the latest values from each node. | ||
| * If the nodes change within a single execution cycle, the subscription will be called only once with the final node values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const trigger$ = Signal<number>(true, (r) => { | ||
| * r.link(r.pipe(trigger$, map(i => `foo${i}`)), foo$) | ||
| * r.link(r.pipe(trigger$, map(i => `bar${i}`)), bar$) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.pub(addItem$, 'foo') | ||
| * r.pub(addItem$, 'bar') | ||
| * r.getValue(items$) // ['foo', 'bar'] | ||
| * r.subMultiple([foo$, bar$], ([foo, bar]) => console.log(foo, bar)) | ||
| * r.pub(trigger$, 2) | ||
| * ``` | ||
| */ | ||
| changeWith<T, K>(cell: Inp<T>, source: Out<K>, map: (cellValue: T, signalValue: K) => T): void; | ||
| subMultiple<T1>(nodes: [Out<T1>], subscription: Subscription<[T1]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2>(nodes: [Out<T1>, Out<T2>], subscription: Subscription<[T1, T2]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3>(nodes: [Out<T1>, Out<T2>, Out<T3>], subscription: Subscription<[T1, T2, T3]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>], subscription: Subscription<[T1, T2, T3, T4]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>], subscription: Subscription<[T1, T2, T3, T4, T5]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>], subscription: Subscription<[T1, T2, T3, T4, T5, T6]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6, T7>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>, Out<T7>], subscription: Subscription<[T1, T2, T3, T4, T5, T6, T7]>): UnsubscribeHandle; | ||
| subMultiple<T1, T2, T3, T4, T5, T6, T7, T8>(nodes: [Out<T1>, Out<T2>, Out<T3>, Out<T4>, Out<T5>, Out<T6>, Out<T7>, Out<T8>], subscription: Subscription<[T1, T2, T3, T4, T5, T6, T7, T8]>): UnsubscribeHandle; | ||
| subMultiple(nodes: Out[], subscription: Subscription<any>): UnsubscribeHandle; | ||
| /** | ||
| * Works as a reverse pipe. | ||
| * Constructs a function, that, when passed a certain node (sink), will create a node that will work as a publisher through the specified pipes into the sink. | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * const entry$ = Signal<number>(true, (r) => { | ||
| * const transform = r.transformer(map(x: number => `num${x}`)) | ||
| * const transformFoo$ = transform(foo$) | ||
| * const transformBar$ = transform(bar$) | ||
| * r.link(entry$, transformFoo$) | ||
| * r.link(entry$, transformBar$) | ||
| * }) | ||
| * | ||
| * const r = new Realm() | ||
| * r.pub(entry$, 1) // Both foo$ and bar$ now contain `num1` | ||
| * ``` | ||
| */ | ||
| transformer<In>(...o: []): (s: Inp<In>) => Inp<In>; | ||
| transformer<In, Out>(...o: [O<In, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1>(...o: [O<In, O1>, O<O1, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2>(...o: [O<In, O1>, O<O1, O2>, O<O2, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3, O4>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out, O1, O2, O3, O4, O5>(...o: [O<In, O1>, O<O1, O2>, O<O2, O3>, O<O3, O4>, O<O4, O5>, O<O5, Out>]): (s: Inp<Out>) => Inp<In>; | ||
| transformer<In, Out>(...operators: O<unknown, unknown>[]): (s: Inp<Out>) => Inp<In>; | ||
| private calculateExecutionMap; | ||
| private combineOperators; | ||
| private getExecutionMap; | ||
| private combineOperators; | ||
| } | ||
@@ -900,3 +900,3 @@ | ||
| */ | ||
| export declare function useCellValue<T>(cell: Out<T>): T; | ||
| export declare const useCellValue: typeof useCellValueWithStore; | ||
@@ -945,2 +945,4 @@ /** | ||
| declare function useCellValueWithStore<T>(cell: Out<T>): T; | ||
| /** | ||
@@ -947,0 +949,0 @@ * Returns a function that publishes its passed argument into the specified node. |
+362
-350
@@ -1,7 +0,7 @@ | ||
| var v = Object.defineProperty; | ||
| var A = (s, t, e) => t in s ? v(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e; | ||
| var h = (s, t, e) => A(s, typeof t != "symbol" ? t + "" : t, e); | ||
| import * as d from "react"; | ||
| import { jsx as L } from "react/jsx-runtime"; | ||
| class C { | ||
| var T = Object.defineProperty; | ||
| var L = (s, t, e) => t in s ? T(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e; | ||
| var g = (s, t, e) => L(s, typeof t != "symbol" ? t + "" : t, e); | ||
| import * as h from "react"; | ||
| import { jsx as A } from "react/jsx-runtime"; | ||
| class x { | ||
| constructor(t = /* @__PURE__ */ new Map()) { | ||
@@ -11,4 +11,8 @@ this.map = t; | ||
| clone() { | ||
| return new C(new Map(this.map)); | ||
| return new x(new Map(this.map)); | ||
| } | ||
| decrement(t, e) { | ||
| let n = this.map.get(t); | ||
| n !== void 0 && (n -= 1, this.map.set(t, n), n === 0 && e()); | ||
| } | ||
| increment(t) { | ||
@@ -18,11 +22,13 @@ const e = this.map.get(t) ?? 0; | ||
| } | ||
| decrement(t, e) { | ||
| let n = this.map.get(t); | ||
| n !== void 0 && (n -= 1, this.map.set(t, n), n === 0 && e()); | ||
| } | ||
| } | ||
| class k { | ||
| class M { | ||
| constructor() { | ||
| h(this, "map", /* @__PURE__ */ new Map()); | ||
| g(this, "map", /* @__PURE__ */ new Map()); | ||
| } | ||
| delete(t) { | ||
| return this.map.delete(t); | ||
| } | ||
| get(t) { | ||
| return this.map.get(t); | ||
| } | ||
| getOrCreate(t) { | ||
@@ -32,5 +38,2 @@ let e = this.map.get(t); | ||
| } | ||
| get(t) { | ||
| return this.map.get(t); | ||
| } | ||
| use(t, e) { | ||
@@ -40,18 +43,15 @@ const n = this.get(t); | ||
| } | ||
| delete(t) { | ||
| return this.map.delete(t); | ||
| } | ||
| } | ||
| function f(s, t) { | ||
| function m(s, t) { | ||
| return t(s), s; | ||
| } | ||
| function x() { | ||
| function E() { | ||
| } | ||
| const E = "cell", j = "signal", K = "pipe"; | ||
| function V(s, t) { | ||
| const V = "cell", j = "signal", W = "pipe"; | ||
| function R(s, t) { | ||
| return s === t; | ||
| } | ||
| const M = /* @__PURE__ */ new Map(); | ||
| const w = /* @__PURE__ */ new Map(); | ||
| let I; | ||
| class W { | ||
| class K { | ||
| /** | ||
@@ -63,10 +63,10 @@ * Creates a new realm. | ||
| constructor(t = {}) { | ||
| h(this, "subscriptions", new k()); | ||
| h(this, "singletonSubscriptions", /* @__PURE__ */ new Map()); | ||
| h(this, "graph", new k()); | ||
| h(this, "state", /* @__PURE__ */ new Map()); | ||
| h(this, "distinctNodes", /* @__PURE__ */ new Map()); | ||
| h(this, "executionMaps", /* @__PURE__ */ new Map()); | ||
| h(this, "definitionRegistry", /* @__PURE__ */ new Set()); | ||
| h(this, "pipeMap", /* @__PURE__ */ new Map()); | ||
| g(this, "definitionRegistry", /* @__PURE__ */ new Set()); | ||
| g(this, "distinctNodes", /* @__PURE__ */ new Map()); | ||
| g(this, "executionMaps", /* @__PURE__ */ new Map()); | ||
| g(this, "graph", new M()); | ||
| g(this, "pipeMap", /* @__PURE__ */ new Map()); | ||
| g(this, "singletonSubscriptions", /* @__PURE__ */ new Map()); | ||
| g(this, "state", /* @__PURE__ */ new Map()); | ||
| g(this, "subscriptions", new M()); | ||
| for (const e of Object.getOwnPropertySymbols(t)) | ||
@@ -83,170 +83,30 @@ this.state.set(e, t[e]); | ||
| cellInstance(t, e = !0, n = Symbol()) { | ||
| return this.state.has(n) || this.state.set(n, t), e !== !1 && !this.distinctNodes.has(n) && this.distinctNodes.set(n, e === !0 ? V : e), n; | ||
| return this.state.has(n) || this.state.set(n, t), e !== !1 && !this.distinctNodes.has(n) && this.distinctNodes.set(n, e === !0 ? R : e), n; | ||
| } | ||
| /** | ||
| * Creates or resolves an existing signal instance in the realm. Useful as a joint point when building your own operators. | ||
| * @returns a reference to the signal. | ||
| * @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle. | ||
| * @param node - optional, a reference to a signal. If the signal has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference. | ||
| */ | ||
| signalInstance(t = !0, e = Symbol()) { | ||
| return t !== !1 && this.distinctNodes.set(e, t === !0 ? V : t), e; | ||
| } | ||
| /** | ||
| * Subscribes to the values published in the referred node. | ||
| * @param node - the cell/signal to subscribe to. | ||
| * @param subscription - the callback to execute when the node receives a new value. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * Convenient for mutation of cells that contian non-primitive values (e.g. arrays, or objects). | ||
| * Specifies that the cell value should be changed when source emits, with the result of the map callback parameter. | ||
| * the map parameter gets called with the current value of the cell and the value published through the source. | ||
| * @typeParam T - the type of the cell value. | ||
| * @typeParam K - the type of the value published through the source. | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const items$ = Cell<string[]([]) | ||
| * const addItem$ = Signal<string>(false, (r) => { | ||
| * r.changeWith(items$, addItem$, (items, item) => [...items, item]) | ||
| * }) | ||
| * const r = new Realm() | ||
| * const unsub = r.sub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * unsub() | ||
| * r.pub(signal$, 3) | ||
| * r.pub(addItem$, 'foo') | ||
| * r.pub(addItem$, 'bar') | ||
| * r.getValue(items$) // ['foo', 'bar'] | ||
| * ``` | ||
| */ | ||
| sub(t, e) { | ||
| this.register(t); | ||
| const n = this.subscriptions.getOrCreate(t); | ||
| return n.add(e), () => n.delete(e); | ||
| } | ||
| /** | ||
| * Subscribes exclusively to values in the referred node. | ||
| * Calling this multiple times on a single node will remove the previous subscription created through `singletonSub`. | ||
| * Subscriptions created through `sub` are not affected. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * // console.log will run only once. | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * ``` | ||
| */ | ||
| singletonSub(t, e) { | ||
| return this.register(t), e === void 0 ? this.singletonSubscriptions.delete(t) : this.singletonSubscriptions.set(t, e), () => this.singletonSubscriptions.delete(t); | ||
| } | ||
| /** | ||
| * Clears all exclusive subscriptions. | ||
| */ | ||
| resetSingletonSubs() { | ||
| this.singletonSubscriptions.clear(); | ||
| } | ||
| // biome-ignore lint/suspicious/noExplicitAny: I know why we need any here | ||
| subMultiple(t, e) { | ||
| const n = this.signalInstance(); | ||
| return this.connect({ | ||
| map: (i) => (...r) => { | ||
| i(r); | ||
| }, | ||
| sink: n, | ||
| sources: t | ||
| }), this.sub(n, e); | ||
| } | ||
| /** | ||
| * Publishes into multiple nodes simultaneously, triggering a single re-computation cycle. | ||
| * @param values - a record of node references and their values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const r = new Realm() | ||
| * r.pubIn({[foo$]: 'foo1', [bar$]: 'bar1'}) | ||
| * ``` | ||
| */ | ||
| pubIn(t) { | ||
| var w; | ||
| const e = Reflect.ownKeys(t).map((a) => this.pipeMap.get(a) ?? a), n = Reflect.ownKeys(t).reduce( | ||
| (a, c) => { | ||
| const g = c, b = t[g], p = this.pipeMap.get(g) ?? g; | ||
| return a[p] = b, a; | ||
| }, | ||
| {} | ||
| ), i = this.getExecutionMap(e), r = i.refCount.clone(), o = i.participatingNodes.slice(), u = new Map(this.state), l = (a) => { | ||
| this.graph.use(a, (c) => { | ||
| for (const { sources: g, sink: b } of c) | ||
| g.has(a) && r.decrement(b, () => { | ||
| o.splice(o.indexOf(b), 1), l(b); | ||
| }); | ||
| }); | ||
| }; | ||
| for (; ; ) { | ||
| const a = o.shift(); | ||
| if (a === void 0) | ||
| break; | ||
| const c = a; | ||
| let g = !1; | ||
| const b = (p) => { | ||
| const m = this.distinctNodes.get(c); | ||
| if (m != null && m(u.get(c), p)) { | ||
| g = !1; | ||
| return; | ||
| } | ||
| g = !0, u.set(c, p), this.state.has(c) && this.state.set(c, p); | ||
| }; | ||
| if (Object.hasOwn(n, c) ? b(n[c]) : i.projections.use(c, (p) => { | ||
| for (const m of p) { | ||
| const S = [...Array.from(m.sources), ...Array.from(m.pulls)].map((T) => u.get(T)); | ||
| m.map(b)(...S); | ||
| } | ||
| }), g) { | ||
| const p = u.get(c); | ||
| this.inContext(() => { | ||
| this.subscriptions.use(c, (m) => { | ||
| for (const S of m) | ||
| S(p); | ||
| }); | ||
| }), (w = this.singletonSubscriptions.get(c)) == null || w(p); | ||
| } else | ||
| l(c); | ||
| } | ||
| } | ||
| /** | ||
| * A low-level utility that connects multiple nodes to a sink node with a map function. Used as a foundation for the higher-level operators. | ||
| * The nodes can be active (sources) or passive (pulls). | ||
| */ | ||
| connect({ | ||
| sources: t, | ||
| pulls: e = [], | ||
| map: n, | ||
| sink: i | ||
| }) { | ||
| const r = { | ||
| map: n, | ||
| pulls: new Set(e), | ||
| sink: this.register(i), | ||
| sources: new Set(t) | ||
| }; | ||
| for (const o of [...t, ...e]) | ||
| this.register(o), this.graph.getOrCreate(o).add(r); | ||
| this.executionMaps.clear(); | ||
| } | ||
| pub(t, e) { | ||
| this.pubIn({ [t]: e }); | ||
| } | ||
| pipe(t, ...e) { | ||
| return this.combineOperators(...e)(t); | ||
| } | ||
| transformer(...t) { | ||
| return (e) => f(this.signalInstance(), (n) => (this.link(this.pipe(n, ...t), e), n)); | ||
| } | ||
| /** | ||
| * Links the output of a node to the input of another node. | ||
| */ | ||
| link(t, e) { | ||
| changeWith(t, e, n) { | ||
| this.connect({ | ||
| map: (n) => (i) => { | ||
| n(i); | ||
| map: (i) => (r, u) => { | ||
| i(n(u, r)); | ||
| }, | ||
| sink: e, | ||
| sources: [t] | ||
| pulls: [t], | ||
| sink: t, | ||
| sources: [e] | ||
| }); | ||
@@ -256,3 +116,3 @@ } | ||
| combine(...t) { | ||
| return f(this.signalInstance(), (e) => { | ||
| return m(this.signalInstance(), (e) => { | ||
| this.connect({ | ||
@@ -269,3 +129,3 @@ map: (n) => (...i) => { | ||
| combineCells(...t) { | ||
| return f( | ||
| return m( | ||
| this.cellInstance( | ||
@@ -287,2 +147,22 @@ t.map((e) => this.getValue(e)), | ||
| /** | ||
| * A low-level utility that connects multiple nodes to a sink node with a map function. Used as a foundation for the higher-level operators. | ||
| * The nodes can be active (sources) or passive (pulls). | ||
| */ | ||
| connect({ | ||
| map: t, | ||
| pulls: e = [], | ||
| sink: n, | ||
| sources: i | ||
| }) { | ||
| const r = { | ||
| map: t, | ||
| pulls: new Set(e), | ||
| sink: this.register(n), | ||
| sources: new Set(i) | ||
| }; | ||
| for (const u of [...i, ...e]) | ||
| this.register(u), this.graph.getOrCreate(u).add(r); | ||
| this.executionMaps.clear(); | ||
| } | ||
| /** | ||
| * Gets the current value of a node. The node must be stateful. | ||
@@ -309,3 +189,84 @@ * @remark if possible, use {@link withLatestFrom} or {@link combine}, as getValue will not create a dependency to the passed node, | ||
| } | ||
| inContext(t) { | ||
| const e = I; | ||
| I = this; | ||
| const n = t(); | ||
| return I = e, n; | ||
| } | ||
| /** | ||
| * Links the output of a node to the input of another node. | ||
| */ | ||
| link(t, e) { | ||
| this.connect({ | ||
| map: (n) => (i) => { | ||
| n(i); | ||
| }, | ||
| sink: e, | ||
| sources: [t] | ||
| }); | ||
| } | ||
| pipe(t, ...e) { | ||
| return this.combineOperators(...e)(t); | ||
| } | ||
| pub(t, e) { | ||
| this.pubIn({ [t]: e }); | ||
| } | ||
| /** | ||
| * Publishes into multiple nodes simultaneously, triggering a single re-computation cycle. | ||
| * @param values - a record of node references and their values. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const foo$ = Cell('foo') | ||
| * const bar$ = Cell('bar') | ||
| * | ||
| * const r = new Realm() | ||
| * r.pubIn({[foo$]: 'foo1', [bar$]: 'bar1'}) | ||
| * ``` | ||
| */ | ||
| pubIn(t) { | ||
| var d; | ||
| const e = Reflect.ownKeys(t).map((a) => this.pipeMap.get(a) ?? a), n = Reflect.ownKeys(t).reduce((a, o) => { | ||
| const p = o, S = t[p], f = this.pipeMap.get(p) ?? p; | ||
| return a[f] = S, a; | ||
| }, {}), i = this.getExecutionMap(e), r = i.refCount.clone(), u = i.participatingNodes.slice(), c = new Map(this.state), l = (a) => { | ||
| this.graph.use(a, (o) => { | ||
| for (const { sink: p, sources: S } of o) | ||
| S.has(a) && r.decrement(p, () => { | ||
| u.splice(u.indexOf(p), 1), l(p); | ||
| }); | ||
| }); | ||
| }; | ||
| for (; ; ) { | ||
| const a = u.shift(); | ||
| if (a === void 0) | ||
| break; | ||
| const o = a; | ||
| let p = !1; | ||
| const S = (f) => { | ||
| const b = this.distinctNodes.get(o); | ||
| if (b != null && b(c.get(o), f)) { | ||
| p = !1; | ||
| return; | ||
| } | ||
| p = !0, c.set(o, f), this.state.has(o) && this.state.set(o, f); | ||
| }; | ||
| if (Object.hasOwn(n, o) ? S(n[o]) : i.projections.use(o, (f) => { | ||
| for (const b of f) { | ||
| const k = [...Array.from(b.sources), ...Array.from(b.pulls)].map((v) => c.get(v)); | ||
| b.map(S)(...k); | ||
| } | ||
| }), p) { | ||
| const f = c.get(o); | ||
| this.inContext(() => { | ||
| this.subscriptions.use(o, (b) => { | ||
| for (const k of b) | ||
| k(f); | ||
| }); | ||
| }), (d = this.singletonSubscriptions.get(o)) == null || d(f); | ||
| } else | ||
| l(o); | ||
| } | ||
| } | ||
| /** | ||
| * Explicitly includes the specified cell/signal/pipe reference in the realm. | ||
@@ -316,16 +277,16 @@ * Most of the time you don't need to do that, since any interaction with the node through a realm will register it. | ||
| register(t) { | ||
| const e = M.get(t); | ||
| const e = w.get(t); | ||
| if (e === void 0) | ||
| return t; | ||
| if (!this.definitionRegistry.has(t)) { | ||
| if (this.definitionRegistry.add(t), e.type === E) | ||
| return f(this.cellInstance(e.initial, e.distinct, t), (o) => { | ||
| if (this.definitionRegistry.add(t), e.type === V) | ||
| return m(this.cellInstance(e.initial, e.distinct, t), (u) => { | ||
| this.inContext(() => { | ||
| e.init(this, o); | ||
| e.init(this, u); | ||
| }); | ||
| }); | ||
| if (e.type === j) | ||
| return f(this.signalInstance(e.distinct, t), (o) => { | ||
| return m(this.signalInstance(e.distinct, t), (u) => { | ||
| this.inContext(() => { | ||
| e.init(this, o); | ||
| e.init(this, u); | ||
| }); | ||
@@ -340,47 +301,90 @@ }); | ||
| } | ||
| inContext(t) { | ||
| const e = I; | ||
| I = this; | ||
| const n = t(); | ||
| return I = e, n; | ||
| /** | ||
| * Clears all exclusive subscriptions. | ||
| */ | ||
| resetSingletonSubs() { | ||
| this.singletonSubscriptions.clear(); | ||
| } | ||
| /** | ||
| * Convenient for mutation of cells that contian non-primitive values (e.g. arrays, or objects). | ||
| * Specifies that the cell value should be changed when source emits, with the result of the map callback parameter. | ||
| * the map parameter gets called with the current value of the cell and the value published through the source. | ||
| * @typeParam T - the type of the cell value. | ||
| * @typeParam K - the type of the value published through the source. | ||
| * Creates or resolves an existing signal instance in the realm. Useful as a joint point when building your own operators. | ||
| * @returns a reference to the signal. | ||
| * @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle. | ||
| * @param node - optional, a reference to a signal. If the signal has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference. | ||
| */ | ||
| signalInstance(t = !0, e = Symbol()) { | ||
| return t !== !1 && this.distinctNodes.set(e, t === !0 ? R : t), e; | ||
| } | ||
| /** | ||
| * Subscribes exclusively to values in the referred node. | ||
| * Calling this multiple times on a single node will remove the previous subscription created through `singletonSub`. | ||
| * Subscriptions created through `sub` are not affected. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const items$ = Cell<string[]([]) | ||
| * const addItem$ = Signal<string>(false, (r) => { | ||
| * r.changeWith(items$, addItem$, (items, item) => [...items, item]) | ||
| * }) | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * r.pub(addItem$, 'foo') | ||
| * r.pub(addItem$, 'bar') | ||
| * r.getValue(items$) // ['foo', 'bar'] | ||
| * // console.log will run only once. | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.singletonSub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * ``` | ||
| */ | ||
| changeWith(t, e, n) { | ||
| this.connect({ | ||
| sources: [e], | ||
| pulls: [t], | ||
| sink: t, | ||
| map: (i) => (r, o) => { | ||
| i(n(o, r)); | ||
| } | ||
| }); | ||
| singletonSub(t, e) { | ||
| return this.register(t), e === void 0 ? this.singletonSubscriptions.delete(t) : this.singletonSubscriptions.set(t, e), () => this.singletonSubscriptions.delete(t); | ||
| } | ||
| /** | ||
| * Subscribes to the values published in the referred node. | ||
| * @param node - the cell/signal to subscribe to. | ||
| * @param subscription - the callback to execute when the node receives a new value. | ||
| * @returns a function that, when called, will cancel the subscription. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * const signal$ = Signal<number>() | ||
| * const r = new Realm() | ||
| * const unsub = r.sub(signal$, console.log) | ||
| * r.pub(signal$, 2) | ||
| * unsub() | ||
| * r.pub(signal$, 3) | ||
| * ``` | ||
| */ | ||
| sub(t, e) { | ||
| this.register(t); | ||
| const n = this.subscriptions.getOrCreate(t); | ||
| return n.add(e), () => n.delete(e); | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| subMultiple(t, e) { | ||
| const n = this.signalInstance(); | ||
| return this.connect({ | ||
| map: (i) => (...r) => { | ||
| i(r); | ||
| }, | ||
| sink: n, | ||
| sources: t | ||
| }), this.sub(n, e); | ||
| } | ||
| transformer(...t) { | ||
| return (e) => m(this.signalInstance(), (n) => (this.link(this.pipe(n, ...t), e), n)); | ||
| } | ||
| calculateExecutionMap(t) { | ||
| const e = [], n = /* @__PURE__ */ new Set(), i = new k(), r = new C(), o = new k(), u = (l, w = 0) => { | ||
| const e = [], n = /* @__PURE__ */ new Set(), i = new M(), r = new x(), u = new M(), c = (l, d = 0) => { | ||
| r.increment(l), !n.has(l) && (this.register(l), i.use(l, (a) => { | ||
| w = Math.max(...Array.from(a).map((c) => e.indexOf(c))) + 1; | ||
| d = Math.max(...Array.from(a).map((o) => e.indexOf(o))) + 1; | ||
| }), this.graph.use(l, (a) => { | ||
| for (const c of a) | ||
| c.sources.has(l) ? (o.getOrCreate(c.sink).add(c), u(c.sink, w)) : i.getOrCreate(c.sink).add(l); | ||
| }), n.add(l), e.splice(w, 0, l)); | ||
| for (const o of a) | ||
| o.sources.has(l) ? (u.getOrCreate(o.sink).add(o), c(o.sink, d)) : i.getOrCreate(o.sink).add(l); | ||
| }), n.add(l), e.splice(d, 0, l)); | ||
| }; | ||
| return t.forEach(u), { participatingNodes: e, pendingPulls: i, projections: o, refCount: r }; | ||
| return t.forEach(c), { participatingNodes: e, pendingPulls: i, projections: u, refCount: r }; | ||
| } | ||
| combineOperators(...t) { | ||
| return (e) => { | ||
| for (const n of t) | ||
| e = n(e, this); | ||
| return e; | ||
| }; | ||
| } | ||
| getExecutionMap(t) { | ||
@@ -395,3 +399,3 @@ let e = t; | ||
| for (const [i, r] of this.executionMaps.entries()) | ||
| if (Array.isArray(i) && i.length === t.length && i.every((o) => t.includes(o))) | ||
| if (Array.isArray(i) && i.length === t.length && i.every((u) => t.includes(u))) | ||
| return r; | ||
@@ -401,40 +405,33 @@ const n = this.calculateExecutionMap(t); | ||
| } | ||
| combineOperators(...t) { | ||
| return (e) => { | ||
| for (const n of t) | ||
| e = n(e, this); | ||
| return e; | ||
| }; | ||
| } | ||
| } | ||
| function U(s, t = x, e = !0) { | ||
| return f(Symbol(), (n) => { | ||
| M.set(n, { type: E, distinct: e, initial: s, init: t }); | ||
| function G(s, t = E, e = !0) { | ||
| return m(Symbol(), (n) => { | ||
| w.set(n, { distinct: e, init: t, initial: s, type: V }); | ||
| }); | ||
| } | ||
| function Y(s, t, e = !0) { | ||
| return f(Symbol(), (n) => { | ||
| M.set(n, { type: K, initial: s, init: t, distinct: e }); | ||
| return m(Symbol(), (n) => { | ||
| w.set(n, { distinct: e, init: t, initial: s, type: W }); | ||
| }); | ||
| } | ||
| function q(s, t, e = !0) { | ||
| return f(Symbol(), (n) => { | ||
| M.set(n, { | ||
| type: E, | ||
| function z(s, t, e = !0) { | ||
| return m(Symbol(), (n) => { | ||
| w.set(n, { | ||
| distinct: e, | ||
| initial: s, | ||
| init: (i, r) => { | ||
| i.link(t(i, r), r); | ||
| } | ||
| }, | ||
| initial: s, | ||
| type: V | ||
| }); | ||
| }); | ||
| } | ||
| function F(s = x, t = !1) { | ||
| return f(Symbol(), (e) => { | ||
| M.set(e, { type: "signal", distinct: t, init: s }); | ||
| function B(s = E, t = !1) { | ||
| return m(Symbol(), (e) => { | ||
| w.set(e, { distinct: t, init: s, type: "signal" }); | ||
| }); | ||
| } | ||
| function G(s = x) { | ||
| return f(Symbol(), (t) => { | ||
| M.set(t, { type: "signal", distinct: !1, init: s }); | ||
| function H(s = E) { | ||
| return m(Symbol(), (t) => { | ||
| w.set(t, { distinct: !1, init: s, type: "signal" }); | ||
| }); | ||
@@ -447,12 +444,25 @@ } | ||
| } | ||
| const z = (s, t) => { | ||
| const J = (s, t) => { | ||
| y().link(s, t); | ||
| }, B = (...s) => { | ||
| }, X = (...s) => { | ||
| y().pub(...s); | ||
| }, H = (...s) => y().sub(...s), J = (...s) => { | ||
| }, Z = (...s) => y().sub(...s), $ = (...s) => { | ||
| y().pubIn(...s); | ||
| }, X = (...s) => y().pipe(...s), Z = (...s) => { | ||
| }, tt = (...s) => y().pipe(...s), et = (...s) => { | ||
| y().changeWith(...s); | ||
| }, $ = (...s) => y().combine(...s), tt = (s) => y().getValue(s), O = d.createContext(null); | ||
| function et({ | ||
| }, nt = (...s) => y().combine(...s), st = (s) => y().getValue(s), N = { data: null, error: null, isLoading: !0, type: "loading" }; | ||
| function it(s, t) { | ||
| return Y(N, (e, n, i) => { | ||
| function r(u) { | ||
| e.pub(i, N), s(u).then((c) => { | ||
| e.pub(i, { data: c, error: null, isLoading: !1, type: "success" }); | ||
| }).catch((c) => { | ||
| e.pub(i, { data: null, error: c, isLoading: !1, type: "error" }); | ||
| }); | ||
| } | ||
| r(t), e.sub(n, r); | ||
| }); | ||
| } | ||
| const O = h.createContext(null); | ||
| function rt({ | ||
| children: s, | ||
@@ -462,9 +472,10 @@ initWith: t, | ||
| }) { | ||
| const n = d.useMemo(() => new W(t), []); | ||
| return d.useEffect(() => { | ||
| const n = h.useMemo(() => new K(t), []); | ||
| return h.useEffect(() => { | ||
| n.pubIn(e); | ||
| }, [e, n]), /* @__PURE__ */ L(O.Provider, { value: n, children: s }); | ||
| }, [e, n]), /* @__PURE__ */ A(O.Provider, { value: n, children: s }); | ||
| } | ||
| function R() { | ||
| const s = d.useContext(O); | ||
| const _ = typeof document < "u" ? h.useLayoutEffect : h.useEffect; | ||
| function C() { | ||
| const s = h.useContext(O); | ||
| if (s === null) | ||
@@ -474,7 +485,7 @@ throw new Error("useRealm must be used within a RealmContextProvider"); | ||
| } | ||
| function P(s) { | ||
| const t = R(); | ||
| function Q(s) { | ||
| const t = C(); | ||
| t.register(s); | ||
| const e = d.useCallback((n) => t.sub(s, n), [t, s]); | ||
| return d.useSyncExternalStore( | ||
| const e = h.useCallback((n) => t.sub(s, n), [t, s]); | ||
| return h.useSyncExternalStore( | ||
| e, | ||
@@ -485,9 +496,23 @@ () => t.getValue(s), | ||
| } | ||
| function nt(...s) { | ||
| const t = R(); | ||
| function D(s) { | ||
| const t = C(); | ||
| t.register(s); | ||
| const [e, n] = h.useState(() => t.getValue(s)); | ||
| return _(() => { | ||
| const i = t.sub(s, () => { | ||
| n(() => t.getValue(s)); | ||
| }); | ||
| return () => { | ||
| i(); | ||
| }; | ||
| }, [t, s]), e; | ||
| } | ||
| const P = "useSyncExternalStore" in h ? Q : D; | ||
| function ut(...s) { | ||
| const t = C(); | ||
| return P(t.combineCells.apply(t, s)); | ||
| } | ||
| function _(s) { | ||
| const t = R(); | ||
| return t.register(s), d.useCallback( | ||
| function U(s) { | ||
| const t = C(); | ||
| return t.register(s), h.useCallback( | ||
| (e) => { | ||
@@ -499,6 +524,6 @@ t.pub(s, e); | ||
| } | ||
| function st(s) { | ||
| return [P(s), _(s)]; | ||
| function ot(s) { | ||
| return [P(s), U(s)]; | ||
| } | ||
| function it(s) { | ||
| function ct(s) { | ||
| return (t, e) => { | ||
@@ -515,3 +540,3 @@ const n = e.signalInstance(); | ||
| } | ||
| function rt(...s) { | ||
| function at(...s) { | ||
| return (t, e) => { | ||
@@ -529,3 +554,3 @@ const n = e.signalInstance(); | ||
| } | ||
| function ot(s) { | ||
| function lt(s) { | ||
| return (t, e) => { | ||
@@ -542,3 +567,3 @@ const n = e.signalInstance(); | ||
| } | ||
| function ct(s) { | ||
| function pt(s) { | ||
| return (t, e) => { | ||
@@ -555,3 +580,3 @@ const n = e.signalInstance(); | ||
| } | ||
| function ut() { | ||
| function ht() { | ||
| return (s, t) => { | ||
@@ -569,8 +594,8 @@ const e = t.signalInstance(); | ||
| } | ||
| function at(s, t) { | ||
| function ft(s, t) { | ||
| return (e, n) => { | ||
| const i = n.signalInstance(); | ||
| return n.connect({ | ||
| map: (r) => (o) => { | ||
| r(t = s(t, o)); | ||
| map: (r) => (u) => { | ||
| r(t = s(t, u)); | ||
| }, | ||
@@ -582,8 +607,8 @@ sink: i, | ||
| } | ||
| function lt(s) { | ||
| function gt(s) { | ||
| return (t, e) => { | ||
| const n = e.signalInstance(); | ||
| let i, r = null; | ||
| return e.sub(t, (o) => { | ||
| i = o, r === null && (r = setTimeout(() => { | ||
| return e.sub(t, (u) => { | ||
| i = u, r === null && (r = setTimeout(() => { | ||
| r = null, e.pub(n, i); | ||
@@ -594,8 +619,8 @@ }, s)); | ||
| } | ||
| function pt(s) { | ||
| function mt(s) { | ||
| return (t, e) => { | ||
| const n = e.signalInstance(); | ||
| let i, r = null; | ||
| return e.sub(t, (o) => { | ||
| i = o, r !== null && clearTimeout(r), r = setTimeout(() => { | ||
| return e.sub(t, (u) => { | ||
| i = u, r !== null && clearTimeout(r), r = setTimeout(() => { | ||
| e.pub(n, i); | ||
@@ -606,3 +631,3 @@ }, s); | ||
| } | ||
| function ht() { | ||
| function bt() { | ||
| return (s, t) => { | ||
@@ -617,3 +642,3 @@ const e = t.signalInstance(); | ||
| } | ||
| function ft(s) { | ||
| function yt(s) { | ||
| return (t, e) => { | ||
@@ -623,72 +648,59 @@ const n = e.signalInstance(), i = Symbol(); | ||
| return e.connect({ | ||
| map: (o) => (u) => { | ||
| r !== i && (o([r, u]), r = i); | ||
| map: (u) => (c) => { | ||
| r !== i && (u([r, c]), r = i); | ||
| }, | ||
| sink: n, | ||
| sources: [s] | ||
| }), e.sub(t, (o) => { | ||
| r = o; | ||
| }), e.sub(t, (u) => { | ||
| r = u; | ||
| }), n; | ||
| }; | ||
| } | ||
| function gt(s, t, e) { | ||
| function dt(s, t, e) { | ||
| return (n, i) => { | ||
| const r = i.signalInstance(); | ||
| return i.sub(n, (o) => { | ||
| o !== null && typeof o == "object" && "then" in o ? (i.pub(r, s()), o.then((u) => { | ||
| i.pub(r, t(u)); | ||
| }).catch((u) => { | ||
| i.pub(r, e(u)); | ||
| })) : i.pub(r, t(o)); | ||
| return i.sub(n, (u) => { | ||
| u !== null && typeof u == "object" && "then" in u ? (i.pub(r, s()), u.then((c) => { | ||
| i.pub(r, t(c)); | ||
| }).catch((c) => { | ||
| i.pub(r, e(c)); | ||
| })) : i.pub(r, t(u)); | ||
| }), r; | ||
| }; | ||
| } | ||
| const N = { type: "loading", isLoading: !0, data: null, error: null }; | ||
| function mt(s, t) { | ||
| return Y(N, (e, n, i) => { | ||
| function r(o) { | ||
| e.pub(i, N), s(o).then((u) => { | ||
| e.pub(i, { type: "success", isLoading: !1, data: u, error: null }); | ||
| }).catch((u) => { | ||
| e.pub(i, { type: "error", isLoading: !1, data: null, error: u }); | ||
| }); | ||
| } | ||
| r(t), e.sub(n, r); | ||
| }); | ||
| } | ||
| export { | ||
| G as Action, | ||
| mt as AsyncQuery, | ||
| U as Cell, | ||
| q as DerivedCell, | ||
| H as Action, | ||
| it as AsyncQuery, | ||
| G as Cell, | ||
| z as DerivedCell, | ||
| Y as Pipe, | ||
| W as Realm, | ||
| K as Realm, | ||
| O as RealmContext, | ||
| et as RealmProvider, | ||
| F as Signal, | ||
| Z as changeWith, | ||
| $ as combine, | ||
| pt as debounceTime, | ||
| V as defaultComparator, | ||
| ht as delayWithMicrotask, | ||
| ct as filter, | ||
| tt as getValue, | ||
| gt as handlePromise, | ||
| z as link, | ||
| it as map, | ||
| ot as mapTo, | ||
| ft as onNext, | ||
| ut as once, | ||
| X as pipe, | ||
| B as pub, | ||
| J as pubIn, | ||
| at as scan, | ||
| H as sub, | ||
| lt as throttleTime, | ||
| st as useCell, | ||
| rt as RealmProvider, | ||
| B as Signal, | ||
| et as changeWith, | ||
| nt as combine, | ||
| mt as debounceTime, | ||
| R as defaultComparator, | ||
| bt as delayWithMicrotask, | ||
| pt as filter, | ||
| st as getValue, | ||
| dt as handlePromise, | ||
| J as link, | ||
| ct as map, | ||
| lt as mapTo, | ||
| yt as onNext, | ||
| ht as once, | ||
| tt as pipe, | ||
| X as pub, | ||
| $ as pubIn, | ||
| ft as scan, | ||
| Z as sub, | ||
| gt as throttleTime, | ||
| ot as useCell, | ||
| P as useCellValue, | ||
| nt as useCellValues, | ||
| _ as usePublisher, | ||
| R as useRealm, | ||
| rt as withLatestFrom | ||
| ut as useCellValues, | ||
| U as usePublisher, | ||
| C as useRealm, | ||
| at as withLatestFrom | ||
| }; |
+24
-21
@@ -6,6 +6,13 @@ { | ||
| "type": "module", | ||
| "version": "1.0.0", | ||
| "version": "1.1.0", | ||
| "module": "dist/index.js", | ||
| "main": "dist/index.js", | ||
| "types": "dist/index.d.ts", | ||
| "scripts": { | ||
| "build": "tsc && vite build", | ||
| "test": "vitest", | ||
| "ci-lint": "eslint", | ||
| "lint": "eslint", | ||
| "typecheck": "tsc --noEmit" | ||
| }, | ||
| "publishConfig": { | ||
@@ -18,12 +25,8 @@ "access": "public" | ||
| }, | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "license": "MIT", | ||
| "peerDependencies": { | ||
| "react": ">= 18 || >= 19", | ||
| "react-dom": ">= 18 || >= 19" | ||
| "react": ">= 16 || >= 17 || >= 18 || >= 19", | ||
| "react-dom": ">= 16 || >= 17 || >= 18 || >= 19" | ||
| }, | ||
| "devDependencies": { | ||
| "@biomejs/biome": "1.9.4", | ||
| "@microsoft/api-extractor": "^7.48.0", | ||
@@ -33,20 +36,20 @@ "@types/node": "^22.10.1", | ||
| "@types/react-dom": "^18.3.1", | ||
| "@virtuoso.dev/tooling": "*", | ||
| "@vitejs/plugin-react-swc": "^3.7.2", | ||
| "@vitest/browser": "3.0.0-beta.3", | ||
| "@vitest/browser": "3.1.1", | ||
| "eslint": "^9.24.0", | ||
| "playwright": "^1.49.0", | ||
| "prettier": "^3.5.3", | ||
| "react": "^18.3.1", | ||
| "react-dom": "^18.3.1", | ||
| "typescript": "^5.7.2", | ||
| "vite": "^6.0.1", | ||
| "vite-plugin-dts": "^4.3.0", | ||
| "vitest": "3.0.0-beta.3", | ||
| "vitest-browser-react": "^0.0.4" | ||
| "typescript": "~5.7.2", | ||
| "vite": "^6.2.6", | ||
| "vite-plugin-dts": "~4.4.0", | ||
| "vitest": "3.1.1", | ||
| "vitest-browser-react": "^0.1.1" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsc && vite build", | ||
| "test": "vitest", | ||
| "ci-lint": "biome ci", | ||
| "lint": "biome check", | ||
| "typecheck": "tsc --noEmit" | ||
| } | ||
| } | ||
| "files": [ | ||
| "dist", | ||
| "CHANGELOG.md" | ||
| ] | ||
| } |
73069
1.06%6
20%1590
0.82%17
13.33%