UNPKG

ixfx

Version:

A framework for programming interactivity

1,338 lines (1,291 loc) 84.7 kB
import { l as ReactiveOrSource, T as TransformOpts, k as Reactive, m as ReactiveOp, n as ChunkOptions, o as CombineLatestOptions, p as RxValueTypes, q as RxValueTypeRx, r as RxValueTypeObject, s as ReactiveDiff, t as ReactiveInitial, u as ReactivePingable, D as DebounceOptions, F as FieldOptions, v as FilterPredicate, w as InitStreamOptions, S as SingleFromArrayOptions, x as SplitOptions, y as ReactiveStream, z as SwitcherOptions, A as SyncOptions, B as Processors, E as ReactiveWritable, G as ThrottleOptions, H as TimeoutValueOptions, J as TimeoutPingOptions, V as ValueToPingOptions, W as WithValueOptions, K as ToArrayOptions, P as Passed, L as PassedSignal, M as PassedValue, N as Wrapped, O as Trigger, Q as TriggerValue, X as TriggerFunction, Y as TriggerGenerator, Z as GeneratorOptions, _ as FunctionOptions, $ as ObjectFieldHandler, a0 as PathDataChange, a1 as DomBindSourceValue, a2 as PipeDomBinding, a3 as DomBindValueTarget, a4 as DomBindUnresolvedSource, a5 as BindUpdateOpts, a6 as ElementsOptions, a7 as ArrayOptions, a8 as ReactiveFinite, a9 as ArrayObjectOptions, aa as ReactiveArray, R as ReactiveNonInitial, ab as CountOptions, ac as DerivedOptions, ad as DomNumberInputValueOptions, ae as DomValueOptions, af as DomFormOptions, ag as EventOptions, ah as EventTriggerOptions, ai as FunctionFunction, aj as InitLazyStreamOptions, ak as ObjectOptions, al as symbol, am as DerivedFunction, an as EventPluckedFieldOptions, ao as EventPluckedFieldOptions2, ap as PingedFunctionFunction, aq as PingedFunctionOptions, ar as UpstreamOptions, as as InitLazyStreamInitedOptions, at as ReactiveInitialStream, au as SetHtmlOptions, av as OpMathOptions, aw as TallyOptions, U as Unsubscriber, ax as DomBindInputOptions, ay as DomBindResolvedSource, az as DomBindTargetNode, aA as DomBindTargetNodeResolved, aB as DomCreateOptions, aC as ElementBind, aD as Lazy, aE as OpAsAnnotation, aF as Optional, aG as PipeSet, aH as PrimitiveValueTypeObject, aI as ReactiveOpInit, aJ as ReactiveOpLinks, aK as ResolveOptions, aL as RxValueTypeObjectOrUndefined, aM as SetHtmlOptionsElement, aN as SetHtmlOptionsQuery, aO as SignalKinds, aP as UpstreamInitialOptions, aQ as average, aR as max, aS as min, aT as rank, aU as setHtmlText, aV as sum, aW as tally } from './Types-ZTmH-4jX.js'; import { R as RankFunction, a as RankOptions } from './Types-DaSeYFCm.js'; import { I as Interval } from './IntervalType-B4PbUkjV.js'; import { I as InterpolateOptions } from './Interpolate-Doc6ee_I.js'; import { a as RecursivePartial } from './TsUtil-D3MueCxS.js'; import { C as Colourish, H as Hsl } from './Types-ZQdFqX9n.js'; /** * Annotates values from `source`. Output values will be * in the form `{ value: TIn, annotation: TAnnotation }`. * Where `TIn` is the type of the input, and `TAnnotation` is * the return type of the annotator function. * * Example calculating area from width & height: * ```js * const data = Rx.From.array( * { w: 1, h: 3 }, { w: 1, h: 1 }, { w: 2, h: 2 } * ); * const annotated = Rx.Ops.annotate(data, v => { * return { area: v.w * v.h } * }); * const data = await Rx.toArray(annotated); * // Data = [ { value: { w:1, h:3 }, annotation: { area:3 } } ...] * ``` * * If you would rather annotate and have values merge with the input, * use `transform`: * ```js * const data = Rx.From.array( * { w: 1, h: 3 }, { w: 1, h: 1 }, { w: 2, h: 2 } * ); * const withArea = Rx.Ops.transform(data, v => { * return { ...v, area: v.w * v.h } * }); * const data = await Rx.toArray(withArea); * // Data = [ { w:1, h:3, area:3 }, ...] * ``` */ declare function annotate<In, TAnnotation>(input: ReactiveOrSource<In>, annotator: (value: In) => TAnnotation, options?: Partial<TransformOpts>): Reactive<{ value: In; annotation: TAnnotation; }>; /** * Annotates the input stream using {@link ReactiveOp} as the source of annotations. * The output values will have the shape of `{ value: TIn, annotation: TAnnotation }`. * Meaning that the original value is stored under `.value`, and the annotation under `.annotation`. * * ```js * const data = Rx.From.array([ 1, 2, 3 ]); * const annotated = Rx.Ops.annotateWithOp(data, Rx.Ops.sum()); * const data = await annotated.toArray(annotated); * // Data = [ { value: 1, annotation: 1 }, { value: 2, annotation: 3 }, { value: 3, annotation: 6 } ] * ``` * @param annotatorOp Operator to generate annotations * @param input Input stream * @returns */ declare function annotateWithOp<In, TAnnotation>(input: ReactiveOrSource<In>, annotatorOp: ReactiveOp<In, TAnnotation>): Reactive<{ value: In; annotation: TAnnotation; }>; /** * Queue from `source`, emitting when thresholds are reached. * The resulting Reactive produces arrays. * * Can use a combination of elapsed time or number of data items. * * By default options are OR'ed together. * * ```js * // Emit data in chunks of 5 items * chunk(source, { quantity: 5 }); * // Emit a chunk of data every second * chunk(source, { elapsed: 1000 }); * ``` * @param source * @param options * @returns */ declare function chunk<V>(source: ReactiveOrSource<V>, options?: Partial<ChunkOptions>): Reactive<Array<V>>; /** * Create a new object from input, based on cloning fields rather than a destructured copy. * This is useful for event args. * @param source * @returns */ declare const cloneFromFields: <In>(source: ReactiveOrSource<In>) => Reactive<In>; /** * Monitors input reactive values, storing values as they happen to an array. * Whenever a new value is emitted, the whole array is sent out, containing current * values from each source, or _undefined_ if not yet emitted. * * See {@link combineLatestToObject} to combine streams by name into an object, rather than array. * * ``` * const sources = [ * Rx.fromFunction(Math.random, { loop: true, interval: 100 }), * Rx.fromFunction(Math.random, { loop: true, interval: 200 }) * ]; * const r = Rx.combineLatestToArray(sources); * r.onValue(value => { * // Value will be an array of last value from each source: * // [number,number] * }); * ``` * * The tempo of this stream will be set by the fastest source stream. * See {@link syncToArray} to have pace determined by slowest source, and only * send when each source has produce a new value compared to last time. * * Set `onSourceDone` to choose behaviour if a source stops. By default it * is 'break', meaning the whole merged stream stops. * * Note: unlike RxJS's `combineLatest`, does not wait for each source to emit once * before emitting first value. * @param reactiveSources Sources to merge * @param options Options for merging * @returns */ declare function combineLatestToArray<const T extends ReadonlyArray<ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<CombineLatestOptions>): Reactive<RxValueTypes<T>>; type CombineLatestToObject<T extends Record<string, ReactiveOrSource<any>>> = { hasSource: (field: string) => boolean; replaceSource: (field: Extract<keyof T, string>, source: ReactiveOrSource<any>) => void; /** * Reactive sources being combined */ sources: RxValueTypeRx<T>; /** * Updates writable sources with values. * @param data * @returns Keys and values set to writable source(s) */ setWith: (data: Partial<RxValueTypeObject<T>>) => Partial<RxValueTypeObject<T>>; } & ReactiveDiff<RxValueTypeObject<T>> & ReactiveInitial<RxValueTypeObject<T>>; /** * Monitors input reactive values, storing values as they happen to an object. * Whenever a new value is emitted, the whole object is sent out, containing current * values from each source (or _undefined_ if not yet emitted) * * See {@link combineLatestToArray} to combine streams by name into an array instead. * * ``` * const sources = { * fast: Rx.fromFunction(Math.random, { loop: true, interval: 100 }), * slow: Rx.fromFunction(Math.random, { loop: true, interval: 200 }) * ]; * const r = Rx.combineLatestToObject(sources); * r.onValue(value => { * // 'value' will be an object containing the labelled latest * // values from each source. * // { fast: number, slow: number } * }); * ``` * * The tempo of this stream will be set by the fastest source stream. * See {@link syncToObject} to have pace determined by slowest source, and only * send when each source has produce a new value compared to last time. * * This source ends if all source streams end. * @param reactiveSources Sources to merge * @param options Options for merging * @returns */ declare function combineLatestToObject<const T extends Record<string, ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<CombineLatestOptions>): CombineLatestToObject<T>; /** * When there is a value from `input`, or the reactive is pinged, * this reactive emits the result of `fn`. * * `fn` is provided the previous value as well as the most recent value. * * If no previous value is available, the current value is emitted and `fn` is not called. * @param input * @param fn * @returns */ declare function computeWithPrevious<TIn>(input: ReactiveOrSource<TIn>, fn: (previous: TIn, current: TIn) => TIn): ReactivePingable<TIn>; /** * Debounce waits for `elapsed` time after the last received value before emitting it. * * If a flurry of values are received that are within the interval, it won't emit anything. But then * as soon as there is a gap in the messages that meets the interval, the last received value is sent out. * * `debounce` always emits with at least `elapsed` as a delay after a value received. While {@link throttle} potentially * sends immediately, if it's outside of the elapsed period. * * This is a subtly different logic to {@link throttle}. `throttle` more eagerly sends the first value, potentially * not sending later values. `debouce` however will send later values, potentially ignoring earlier ones. * @param source * @param options * @returns */ declare function debounce<V>(source: ReactiveOrSource<V>, options?: Partial<DebounceOptions>): Reactive<V>; /** * Emits time in milliseconds since last message. * If it is the first value, 0 is used. * @param input * @returns */ declare const elapsed: <In>(input: ReactiveOrSource<In>) => Reactive<number>; /** * From a source value, yields a field from it. Only works * if stream values are objects. * * If a source value doesn't have that field, it is skipped. * * @returns */ declare function field<TIn extends object, TFieldType>(fieldSource: ReactiveOrSource<TIn>, fieldName: keyof TIn, options?: Partial<FieldOptions<TIn, TFieldType>>): Reactive<TFieldType>; /** * Passes all values where `predicate` function returns _true_. */ declare function filter<In>(input: ReactiveOrSource<In>, predicate: FilterPredicate<In>, options: Partial<InitStreamOptions>): Reactive<In>; /** * Drops all values where `predicate` function returns _true_. */ declare function drop<In>(input: ReactiveOrSource<In>, predicate: FilterPredicate<In>, options: Partial<InitStreamOptions>): Reactive<In>; type OpInterpolateOptions = InterpolateOptions & { amount: number; /** * Percentage of value that we consider 'done'. * Since interpolation can never converge to target exactly, this allows us to snap to completion. * Default: 0.99, meaning if value gets to within 99%, return the target. */ snapAt: number; }; /** * Interpolates to the source value. * * Outputs one value for every input value. Thus, to interpolation * over time, it's necessary to get the source to emit values at the desired rate. * * Options can specify an easing name or custom transform of easing progress. * @param input * @param options * @returns */ declare function interpolate(input: ReactiveOrSource<number>, options?: Partial<OpInterpolateOptions>): ReactivePingable<number>; /** * Pipes the output of one stream into another, in order. * The stream returned is a new stream which captures the final output. * * If any stream in the pipe closes the whole pipe is closed. * @param streams * @returns */ declare const pipe: <TInput, TOutput>(streams_0: Reactive<TInput>, ...streams: (Reactive<any> & { set(value: any): void; })[]) => Reactive<TOutput>; /** * For a stream that emits arrays of values, this op will select a single value. * * Can select based on: * * predicate: a function that returns _true_ for a value * * at: selection based on array index (can be combined with random ordering to select a random value) * * ```js * // If source is Reactive<Array<number>>, picks the first even number * singleFromArray(source, { * predicate: v => v % 2 === 0 * }); * * // Selects a random value from source * singleFromArray(source, { * order: `random`, * at: 0 * }); * ``` * * If neither `predicate` or `at` options are given, exception is thrown. * @param source Source to read from * @param options Options for selection * @returns */ declare function singleFromArray<V>(source: ReactiveOrSource<Array<V>>, options?: Partial<SingleFromArrayOptions<V>>): Reactive<V>; /** * Creates a set of streams each of which receives data from `source`. * By default these are lazy and dispose if the upstream source closes. * * See also {@link splitLabelled} to split into named streams. * @param rxOrSource * @param options * @returns */ declare const split: <T>(rxOrSource: ReactiveOrSource<T>, options?: Partial<SplitOptions>) => ReactiveStream<T>[]; /** * Splits `source` into several duplicated streams. * Returns an object with keys according to `labels`. * Each value is a stream which echos the values from `source`. * ```js * const { a, b, c} = splitLabelled(source, `a`, `b`, `c`); * // a, b, c are Reactive types * ``` * * See also {@link split} to get an unlabelled split * @param rxOrSource * @param labels * @returns */ declare const splitLabelled: <T, K extends PropertyKey>(rxOrSource: ReactiveOrSource<T>, labels: Array<K>) => Record<K, Reactive<T>>; /** * Switcher generates several output streams, labelled according to the values of `cases`. * Values from `source` are fed to the output streams if their associated predicate function returns _true_. * * In this way, we can split one input stream into several output streams, each potentially getting a different * subset of the input. * * With `options`, you can specify whether to send to multiple outputs if several match, or just the first (default behaviour). * * The below example shows setting up a switcher and consuming the output streams. * @example * ```js * // Initialise a reactive number, starting at 0 * const switcherSource = Reactive.number(0); * // Set up the switcher * const x = Reactive.switcher(switcherSource, { * even: v => v % 2 === 0, * odd: v => v % 2 !== 0 * }); * // Listen for outputs from each of the resulting streams * x.even.on(msg => { * log(`even: ${msg.value}`); * }); * x.odd.on(msg => { * log(`odd: ${msg.value}`); * }) * // Set new values to the number source, counting upwards * // ...this will in turn trigger the outputs above * setInterval(() => { * switcherSource.set(switcherSource.last() + 1); * }, 1000); * ``` * * If `source` closes, all the output streams will be closed as well. * @param reactiveOrSource * @param cases * @param options * @returns */ declare const switcher: <TValue, TRec extends Record<string, FilterPredicate<TValue>>, TLabel extends keyof TRec>(reactiveOrSource: ReactiveOrSource<TValue>, cases: TRec, options?: Partial<SwitcherOptions>) => Record<TLabel, Reactive<TValue>>; /** * Waits for all sources to produce a value, sending the combined results as an array. * After sending, it waits again for each source to send at least one value. * * Use {@link syncToObject} to output objects based on labelled sources rather than an array of values. * * Pace will be set by the slowest source. Alternatively, use {@link combineLatestToArray} where the rate is determined by fastest source. * * Only complete results are sent. For example if source A & B finish and source C is still producing values, * synchronisation is not possible because A & B stopped producing values. Thus the stream will self-terminate * after `maximumWait` (2 seconds). The newer values from C are lost. */ declare function syncToArray<const T extends ReadonlyArray<ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<SyncOptions>): Reactive<RxValueTypes<T>>; declare function syncToObject<const T extends Record<string, ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<SyncOptions>): Reactive<RxValueTypeObject<T>>; /** * 'Taps' the values from 'input', passing them to the 'process' function. * Return stream is the input stream, unaffected by what 'process' does. * @param input Input stream * @param processors List of processors * @returns */ declare function tapProcess<In, T2, T3, T4, T5, T6>(input: ReactiveOrSource<In>, ...processors: Processors<In, T2, T3, T4, T5, T6>): Reactive<In>; /** * 'Taps' the values from 'input', passing them to 'diverged' * Returns the original input stream, unaffected by what 'diverged' does. * @param input Input stream * @param diverged Stream to write to * @returns */ declare function tapStream<In>(input: ReactiveOrSource<In>, diverged: ReactiveWritable<In>): Reactive<In>; /** * Create a parallel 'tap' of processing * @param input Input stream * @param ops Series of ops to process data * @returns */ declare const tapOps: <TIn, TOut>(input: ReactiveOrSource<TIn>, ...ops: Array<ReactiveOp<TIn, TOut>>) => Reactive<TOut>; /** * Only allow a value through if a minimum amount of time has elapsed. * since the last value. This effectively slows down a source to a given number * of values/ms. Values emitted by the source which are too fast are discarded. * * Throttle will fire on the first value received. * * In more detail: * Every time throttle passes a value, it records the time it allowed something through. For every * value received, it checks the elapsed time against this timestamp, throwing away values if * the period hasn't elapsed. * * With this logic, a fury of values of the source might be discarded if they fall within the elapsed time * window. But then if there is not a new value for a while, the actual duration between values can be longer * than expected. This is in contrast to {@link debounce}, which will emit the last value received after a duration, * even if the source stops sending. * @param options * @returns */ declare function throttle<V>(throttleSource: ReactiveOrSource<V>, options?: Partial<ThrottleOptions>): Reactive<V>; /** * Emits a value if `source` does not emit a value after `interval` * has elapsed. This can be useful to reset a reactive to some * 'zero' state if nothing is going on. * * If `source` emits faster than the `interval`, it won't get triggered. * * Default for 'timeout': 1000s. * * ```js * // Emit 'hello' if 'source' doesn't emit a value after 1 minute * const r = Rx.timeoutValue(source, { value: 'hello', interval: { mins: 1 } }); * ``` * * Can also emit results from a function or generator * ```js * // Emits a random number if 'source' doesn't emit a value after 500ms * const r = Rx.timeoutValue(source, { fn: Math.random, interval: 500 }); * ``` * * If `immediate` option is _true_ (default), the timer starts from stream initialisation. * Otherwise it won't start until it observes the first value from `source`. * @param source * @param options */ declare function timeoutValue<TSource, TTriggerValue>(source: ReactiveOrSource<TSource>, options: TimeoutValueOptions<TTriggerValue>): Reactive<TSource | TTriggerValue>; /** * Pings a reactive if no value is emitted at after `interval`. * Returns `source`. * * ```js * // Ping `source` if no value is emitted after one minute * const r = Rx.timeoutPing(source, { mins: 1 }); * ``` * * Behavior can be stopped using an abort signal. * @see {@link ReactivePingable} * @param source * @param options */ declare function timeoutPing<TSource>(source: ReactiveOrSource<TSource>, options: TimeoutPingOptions): Reactive<TSource>; /** * Transforms values from `source` using the `transformer` function. * @param transformer * @returns */ declare function transform<In, Out>(input: ReactiveOrSource<In>, transformer: (value: In) => Out, options?: Partial<TransformOpts>): Reactive<Out>; /** * Pings `target` whenever `source` emits a value. The value itself is ignored, it just * acts as a trigger. * * Returns a new stream capturing the output of `target`. * * It `source` or `target` closes, output stream closes too. * * @returns */ declare function valueToPing<TSource, TTarget>(source: ReactiveOrSource<TSource>, target: ReactivePingable<TTarget>, options?: Partial<ValueToPingOptions<TSource>>): Reactive<TTarget>; /** * A reactive where the last value can be read at any time. * An initial value must be provided. * ```js * const r = Rx.withValue(source, { initial: `hello` }); * r.last(); // Read last value * ``` * * Warning: Since most reactives only active when subscribed to, it's important to also subscribe * to the results of `r` for this flow to happen. Alternatively, use `lazy: 'never'` as an option. * @param input * @param options * @returns */ declare function withValue<In>(input: ReactiveOrSource<In>, options: WithValueOptions<In>): ReactiveInitial<In>; /** * Build a graph of reactive dependencies for `rx` * @param _rx */ declare function prepare<V extends Record<string, any>>(_rx: V): Reactive<V>; /** * Reads a set number of values from `source`, returning as an array. May contain * empty values if desired values is not reached. * * After the limit is reached (or `source` completes), `source` is unsubscribed from. * * If no limit is set, it will read until `source` completes or `maximumWait` is reached. * `maximumWait` is 10 seconds by default. * * Use {@link toArrayOrThrow} to throw if desired limit is not reached. * * ```js * // Read from `source` for 5 seconds * const data = await toArray()(source); * // Read 5 items from `source` * const data = await toArray({ limit: 5 })(source); * // Read for 10s * const data = await toArray({ maximumWait: 10_1000 })(source); * ``` * @param source * @param options * @returns */ declare function toArray<V>(source: ReactiveOrSource<V>, options?: Partial<ToArrayOptions<V>>): Promise<Array<V | undefined>>; /** * By default, reads all the values from `source`, or until 5 seconds has elapsed. * * If `limit` is provided as an option, it will exit early, or throw if that number of values was not acheived. * * ```js * // Read from `source` for 5 seconds * const data = await toArrayOrThrow()(source); * // Read 5 items from `source` * const data = await toArrayOrThrow({ limit: 5 })(source); * // Read for 10s * const data = await toArrayOrThrow({ maximumWait: 10_1000 })(source); * ``` * @param source * @param options * @returns */ declare function toArrayOrThrow<V>(source: ReactiveOrSource<V>, options?: Partial<ToArrayOptions<V>>): Promise<Array<V>>; /** * Returns an AsyncGenerator wrapper around Reactive. * This allows values to be iterated over using a `for await` loop, * like Chains. * * ```js * // Reactive numerical value * const number = Reactive.number(10); * * const g = Reactive.toGenerator(number); * for await (const v of g) { * console.log(v); // Prints out whenever the reactive value changes * } * // Execution doesn't continue until Reactive finishes * ``` * * When/if `source` closes, an exception is thrown. * To catch this, wrap the calling `for await` in a try-catch block * ```js * try { * for await (const v of g) { * } * } catch (error) { * } * // Completed * ``` * * Use something like `setTimeout` to loop over the generator * without impeding the rest of your code flow. For example: * ```js * // Listen for every pointerup event * const ptr = Reactive.fromEvent(document.body, `pointerup`); * // Start iterating * setTimeout(async () => { * const gen = Reactive.toGenerator(ptr); * try { * for await (const v of gen) { * // Prints out whenever there is a click * console.log(v); * } * } catch (e) { } * console.log(`Iteration done`); * }); * * // Execution continues here immediately * ``` * @param source */ declare function toGenerator<V>(source: ReactiveOrSource<V>): AsyncGenerator<V>; declare function messageIsSignal<V>(message: Passed<V> | PassedSignal): message is PassedSignal; declare function messageIsDoneSignal<V>(message: Passed<V> | PassedSignal): boolean; /** * Returns _true_ if `v` has a non-undefined value. Note that sometimes * _undefined_ is a legal value to pass * @param v * @returns */ declare function messageHasValue<V>(v: Passed<V> | PassedSignal): v is PassedValue<V>; declare const isPingable: <V>(rx: Reactive<V> | ReactiveDiff<V> | object) => rx is ReactivePingable<V>; declare const hasLast: <V>(rx: Reactive<V> | ReactiveDiff<V> | object) => rx is ReactiveInitial<V>; /** * Returns _true_ if `rx` is a Reactive * @param rx * @returns */ declare const isReactive: <V>(rx: object) => rx is Reactive<V>; /** * Returns true if `rx` is a disposable reactive. * @param rx * @returns */ /** * Returns _true_ if `rx` is a writable Reactive * @param rx * @returns */ declare const isWritable: <V>(rx: Reactive<V> | ReactiveWritable<V>) => rx is ReactiveWritable<V>; declare const isWrapped: <T>(v: any) => v is Wrapped<T>; declare const opify: <TIn, TRxOut = Reactive<TIn>>(fn: (source: ReactiveOrSource<TIn>, ...args: Array<any>) => TRxOut, ...args: Array<any>) => (source: ReactiveOrSource<TIn>) => TRxOut; declare const isTriggerValue: <V>(t: Trigger<V>) => t is TriggerValue<V>; declare const isTriggerFunction: <V>(t: Trigger<V>) => t is TriggerFunction<V>; declare const isTriggerGenerator: <V>(t: Trigger<V>) => t is TriggerGenerator<V>; declare const isTrigger: <V>(t: any) => t is Trigger<V>; type ResolveTriggerValue<V> = [value: V, false]; type ResolveTriggerDone = [undefined, true]; /** * Resolves a trigger value. * * A trigger can be a value, a function or generator. Value triggers never complete. * A trigger function is considered complete if it returns undefined. * A trigger generator is considered complete if it returns done. * * Returns `[value, _false_]` if we have a value and trigger is not completed. * Returns `[value, _true_]` trigger is completed * @param t * @returns */ declare function resolveTriggerValue<V>(t: Trigger<V>): ResolveTriggerDone | ResolveTriggerValue<V>; /** * Wrap a reactive source to allow for chained * function calls. * * Example: * For every `pointerup` event on the body, chunk the events over * periods of 200ms, get the number of events in that period, * and print it out. * * eg. detecting single or double-clicks * ```js * wrap(Rx.fromEvent<{ x: number, y: number }>(document.body, `pointerup`)) * .chunk({ elapsed: 200 }) * .transform(v => v.length) * .onValue(v => { console.log(v) }); * ``` * @param source * @returns */ declare function wrap<TIn>(source: ReactiveOrSource<TIn>): Wrapped<TIn>; type ResolveSourceOptions = { /** * Options when creating a reactive from a generator * Default: `{ lazy: true, interval: 5 }` */ generator: GeneratorOptions; /** * Options when creating a reactive from a function. */ function: FunctionOptions; }; /** * Resolves various kinds of sources into a Reactive. * If `source` is an iterable/generator, it gets wrapped via `generator()`. * * Default options: * * generator: `{ lazy: true, interval: 5 }` * @param source * @returns */ declare const resolveSource: <V>(source: ReactiveOrSource<V>, options?: Partial<ResolveSourceOptions>) => Reactive<V>; /** * A stream that caches its last value */ type CacheStream<T> = { /** * Clears the last cached value * @returns */ resetCachedValue: () => void; /** * Gets the cached value, if available * @returns */ last: () => T | undefined; }; /** * A {@link CacheStream} with an initial value */ type CacheStreamInitial<T> = CacheStream<T> & { last: () => T; }; /** * Wraps an input stream to cache values, and provide an initial value * @param r Input stream * @param initialValue Initial value */ declare function cache<TValue, RT extends Reactive<TValue>>(r: RT, initialValue: TValue): CacheStreamInitial<TValue> & RT; /** * Reactive stream of array of elements that match `query`. * @param query * @returns */ declare function fromDomQuery(query: string): Reactive<HTMLElement[]> & { set(value: HTMLElement[]): void; } & { onField(fieldName: string, handler: (result: ObjectFieldHandler) => void): () => void; onDiff(changes: (changes: Array<PathDataChange<any>>) => void): () => void; update(changedPart: (RecursivePartial<HTMLElement> | undefined)[]): HTMLElement[]; updateField(field: string, value: any): void; } & { last(): HTMLElement[]; }; /** * Updates an element's `textContent` when the source value changes. * ```js * bindText(source, `#blah`); * ``` * @param elOrQuery * @param source * @param bindOpts */ declare const bindText: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, bindOpts?: Partial<DomBindSourceValue<TSource, string>>) => PipeDomBinding; /** * Updates an element's `value` (as well as the 'value' attribute) when the source value changes.s * @param source * @param elOrQuery * @param bindOpts * @returns */ declare const bindValueText: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLInputElement | null, bindOpts?: Partial<DomBindSourceValue<TSource, string>>) => PipeDomBinding; /** * Updates an element's `innerHTML` when the source value changes * ```js * bindHtml(source, `#blah`); * ``` * * Uses {@link bindElement}, with `{elField:'innerHTML'}` as the options. * @param elOrQuery * @param source * @param bindOpts * @returns */ declare const bindHtml: <TSource>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, bindOpts?: DomBindSourceValue<TSource, string>) => PipeDomBinding; /** * Shortcut to bind to an elements attribute * @param elOrQuery * @param source * @param attribute * @param bindOpts * @returns */ /** * Shortcut to bind to a CSS variable * @param elOrQuery * @param source * @param cssVariable * @param bindOpts * @returns */ /** * Creates a new HTML element, calling {@link bind} on it to update when `source` emits new values. * * * ```js * // Set textContent of a SPAN with values from `source` * create(source, { tagName: `span`, parentEl: document.body }) * ``` * * If `parentEl` is not given in the options, the created element needs to be manually added * ```js * const b = create(source); * someEl.append(b.el); // Append manually * ``` * * ``` * // Set 'title' attribute based on values from `source` * create(source, { parentEl: document.body, attribName: `title` }) * ``` * @param source * @param options * @returns */ /** * Update a DOM element's field, attribute or CSS variable when `source` produces a value. * * ```js * // Access via DOM query. Binds to 'textContent' by default * bind(readableSource, `#someEl`); * * // Set innerHTML instead * bind(readableSource, someEl, { elField: `innerHTML` }); * * // An attribute * bind(readableSource, someEl, { attribName: `width` }); * * // A css variable ('--' optiona) * bind(readableSource, someEl, { cssVariable: `hue` }); * * // Pluck a particular field from source data. * // Ie someEl.textContent = value.colour * bind(readableSource, someEl, { sourceField: `colour` }); * * // Transform value before setting it to field * bind(readableSource, someEl, { * field: `innerHTML`, * transform: (v) => `Colour: ${v.colour}` * }) * ``` * * If `source` has an initial value, this is used when first bound. * * Returns {@link PipeDomBinding} to control binding: * ```js * const bind = bind(source, `#someEl`); * bind.remove(); // Unbind * bind.remove(true); // Unbind and remove HTML element * ``` * * If several fields need to be updated based on a new value, consider using {@link bindUpdate} instead. * @param elOrQuery Element to update to, or query string such as '#someid' * @param source Source of data * @param binds Bindings */ declare const bindElement: <TSource, TDestination>(source: Reactive<TSource>, elOrQuery: string | HTMLElement | null, ...binds: Array<DomBindSourceValue<TSource, TDestination> & DomBindValueTarget>) => PipeDomBinding; /** * Binds `source` to one or more element(s). One or more bindings for the same source * can be provided. * * ```js * bind(source, * // Binds .name field of source values to textContent of #some-element * { query: `#some-element`, sourceField: `name` }, * { query: `section`, } * ); * ``` * * Can update * * CSS variables * * CSS styles * * textContent / innerHTML * * HTML DOM attributes and object fields * * Can use a particular field on source values, or use the whole value. These can * pass through `transformValue` or `transform` respectively. * * Returns a function to unbind from source and optionally remove HTML element * ```js * const unbind = bind( . . . ); * unbind(); // Unbind * unbind(true); // Unbind and remove HTML element(s) * ``` * @param source * @param bindsUnresolvedElements * @returns */ declare const bind: <TSource, TDestination>(source: Reactive<TSource>, ...bindsUnresolvedElements: Array<DomBindUnresolvedSource<TSource, TDestination>>) => PipeDomBinding; /** * Calls `updater` whenever `source` produces a value. Useful when several fields from a value * are needed to update an element. * ```js * bindUpdate(source, `#someEl`, (v, el) => { * el.setAttribute(`width`, v.width); * el.setAttribute(`height`, v.height); * }); * ``` * * Returns a {@link PipeDomBinding} to manage binding * ```js * const b = bindUpdate(...); * b.remove(); // Disconnect binding * b.remove(true); // Disconnect binding and remove element * b.el; // HTML element * ``` * @param elOrQuery * @param source * @param updater * @returns */ declare const bindUpdate: <V>(source: Reactive<V>, elOrQuery: string | HTMLElement, updater: (v: V, el: HTMLElement) => void) => PipeDomBinding; /** * Updates a HTML element based on diffs on an object. * ```js * // Wrap an object * const o = Rx.object({ name: `Jane`, ticks: 0 }); * const b = bindDiffUpdate(`#test`, o, (diffs, el) => { * // el = reference to #test * // diff = Array of Changes, * // eg [ { path: `ticks`, value: 797, previous: 0 } ] * for (const diff of diffs) { * if (diff.path === `ticks`) el.textContent = `${diff.previous} -> ${diff.value}` * } * }) * * // Eg. update field * o.updateField(`ticks`, Math.floor(Math.random()*1000)); * ``` * * If `initial` is provided as an option, this will be called if `source` has an initial value. Without this, the DOM won't be updated until the first data * update happens. * ```js * bindDiffUpdate(el, source, updater, { * initial: (v, el) => { * el.innerHTML = v.name; * } * }) * ``` * @param elOrQuery * @param source * @param updater * @param opts * @returns */ declare const bindDiffUpdate: <V>(source: ReactiveDiff<V>, elOrQuery: string | HTMLElement | null, updater: (diffs: Array<PathDataChange<any>>, el: HTMLElement) => void, opts?: Partial<BindUpdateOpts<V>>) => PipeDomBinding & { refresh: () => void; }; /** * Creates a new HTML element and calls `bindUpdate` so values from `source` can be used * to update it. * * * ```js * // Creates a span, adding it to <body> * const b = createUpdate(dataSource, (value, el) => { * el.width = value.width; * el.height = value.height; * }, { * tagName: `SPAN`, * parentEl: document.body * }) * ``` * @param source * @param updater * @param options * @returns */ /** * Creates, updates & deletes elements based on pathed values from a reactive. * * This means that elements are only manipulated if its associated data changes, * and elements are not modified if there's no need to. * @param source * @param options */ declare const elements: <T>(source: ReactiveDiff<T> | (ReactiveDiff<T> & ReactiveInitial<T>), options: Partial<ElementsOptions>) => void; declare function win(): { dispose: (reason?: string) => void; size: Reactive<{ lazy: string; transform: () => { width: number; height: number; }; }> & { last(): { lazy: string; transform: () => { width: number; height: number; }; }; }; pointer: Reactive<{ lazy: string; transform: (args: Event | undefined) => { x: number; y: number; }; }> & { last(): { lazy: string; transform: (args: Event | undefined) => { x: number; y: number; }; }; }; }; declare const Dom_bind: typeof bind; declare const Dom_bindDiffUpdate: typeof bindDiffUpdate; declare const Dom_bindElement: typeof bindElement; declare const Dom_bindHtml: typeof bindHtml; declare const Dom_bindText: typeof bindText; declare const Dom_bindUpdate: typeof bindUpdate; declare const Dom_bindValueText: typeof bindValueText; declare const Dom_elements: typeof elements; declare const Dom_fromDomQuery: typeof fromDomQuery; declare const Dom_win: typeof win; declare namespace Dom { export { Dom_bind as bind, Dom_bindDiffUpdate as bindDiffUpdate, Dom_bindElement as bindElement, Dom_bindHtml as bindHtml, Dom_bindText as bindText, Dom_bindUpdate as bindUpdate, Dom_bindValueText as bindValueText, Dom_elements as elements, Dom_fromDomQuery as fromDomQuery, Dom_win as win }; } declare const of: <V>(source: Array<V> | Iterable<V>, options?: Partial<ArrayOptions>) => (Reactive<V> & ReactiveFinite & { last(): V; }) | undefined; /** * Reads the contents of `array` into a Reactive, with optional time interval * between values. A copy of the array is used, so changes will not * affect the reactive. * * See also {@link arrayObject} which monitors changes to array values. * * Reads items from an array with a given interval, by default 5ms * * ```js * const data = [`apples`, `oranges`, `pears` ]; * const rx = Rx.From.array(data); * rx.onValue(v => { * // v will be each fruit in turn * }) * ``` * * Note that there is the possibility of missing values since there is delay between subscribing and when items start getting emitted. * If a new subscriber connects to the reactive, they won't get values already emitted. * @param sourceArray * @param options * @returns */ declare const array: <V>(sourceArray: Array<V>, options?: Partial<ArrayOptions>) => Reactive<V> & ReactiveFinite & ReactiveInitial<V>; /** * Wraps an array object. * * It returns an reactive along with some array-ish functions to manipulating it. * @param initialValue * @param options * @returns */ declare function arrayObject<V>(initialValue?: ReadonlyArray<V>, options?: Partial<ArrayObjectOptions<V>>): ReactiveArray<V> & ReactiveInitial<ReadonlyArray<V>>; declare function boolean(initialValue: boolean): ReactiveWritable<boolean> & ReactiveInitial<boolean>; declare function boolean(): ReactiveWritable<boolean> & ReactiveNonInitial<boolean>; type ReactiveColour = ReactiveWritable<Colourish> & { setHsl: (hsl: Hsl) => void; }; declare function colour(initialValue: Colourish): ReactiveColour & ReactiveInitial<Colourish>; declare function colour(): ReactiveColour & ReactiveNonInitial<Colourish>; /** * Produces an incrementing value. By default starts at 0 and counts * forever, incrementing every second. * * ```js * const r = Rx.From.count(); * r.onValue(c => { * // 0, 1, 2, 3 ... every second * }); * ``` * * The `limit` is exclusive * ```js * const r = Rx.From.count({limit:5}); * // Yields 0,1,2,3,4 * ``` * * If limit is less than start, it will count down instead. * ```js * const r = Rx.count({start:5, limit: 0}); * // Yie:ds 5,4,3,2,1 * ``` * * ```js * // Count 10, 12, 14 ... every 500ms * const r = Rx.From.count({ start: 10, amount: 2, interval: 500 }); * ``` * * In addition to setting `limit` (which is exclusive), you can stop with an abort signal * ```js * const ac = new AbortController(); * const r = Rx.From.count({signal:ac.signal}); * ... * ac.abort(`stop`); * ``` * @param options */ declare function count(options?: Partial<CountOptions>): ReactiveStream<number>; declare function derived<TResult, const T extends Record<string, ReactiveOrSource<any>>>(fn: (combined: RxValueTypeObject<T>) => TResult | undefined, reactiveSources: T, options?: Partial<DerivedOptions<TResult, CombineLatestToObject<T>>>): ReactiveNonInitial<TResult>; /** * Reactive getting/setting of values to a HTML INPUT element. * * Options: * - relative: if _true_, values are 0..1 (default: false) * - inverted: if _true_, values are 1..0 (default: false) * * If element is missing a 'type' attribute, this will be set to 'range'. * @param targetOrQuery * @param options * @returns */ declare function domNumberInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomNumberInputValueOptions>): ReactiveInitial<number> & ReactiveWritable<number>; declare function domHslInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomValueOptions>): ReactiveInitial<Hsl> & Reactive<Hsl> & ReactiveWritable<Hsl>; /** * A stream of values when the a HTMLInputElement changes. Eg a <input type="range"> * ```js * const r = Rx.From.domInputValue(`#myEl`); * r.onValue(value => { * // value will be string * }); * ``` * * Options: * * emitInitialValue: If _true_ emits the HTML value of element (default: false) * * attributeName: If set, this is the HTML attribute value is set to when writing to stream (default: 'value') * * fieldName: If set, this is the DOM object field set when writing to stream (default: 'value') * * when: 'changed'|'changing' when values are emitted. (default: 'changed') * * fallbackValue: Fallback value to use if field/attribute cannot be read (default: '') * @param targetOrQuery * @param options * @returns */ declare function domInputValue(targetOrQuery: HTMLInputElement | string, options?: Partial<DomValueOptions>): { el: HTMLInputElement; } & ReactiveInitial<string> & ReactiveWritable<string>; /** * Listens for data changes from elements within a HTML form element. * Input elements must have a 'name' attribute. * * Simple usage: * ```js * const rx = Rx.From.domForm(`#my-form`); * rx.onValue(value => { * // Object containing values from form * }); * * rx.last(); // Read current values of form * ``` * * UI can be updated * ```js * // Set using an object of key-value pairs * rx.set({ * size: 'large' * }); * * // Or set a single name-value pair * rx.setNamedValue(`size`, `large`); * ``` * * If an 'upstream' reactive is provided, this is used to set initial values of the UI, overriding * whatever may be in the HTML. Upstream changes modify UI elements, but UI changes do not modify the upstream * source. * * ```js * // Create a reactive object * const obj = Rx.From.object({ * when: `2024-10-03`, * size: 12, * checked: true * }); * * // Use this as initial values for a HTML form * // (assuming appropriate INPUT/SELECT elements exist) * const rx = Rx.From.domForm(`form`, { * upstreamSource: obj * }); * * // Listen for changes in the UI * rx.onValue(value => { * * }); * ``` * @param formElOrQuery * @param options * @returns */ declare function domForm<T extends Record<string, any>>(formElOrQuery: HTMLFormElement | string, options?: Partial<DomFormOptions<T>>): { setNamedValue: (name: string, value: any) => void; el: HTMLFormElement; } & ReactiveInitial<T> & ReactiveWritable<T>; /** * Fired when `eventName` fires on `target`. * * Rather than whole event args being emitted on the stream, * it plucks a field from the event args, or if that's missing, from the target. * * ```js * // Emits the the value of a field named 'x' * // on the change event args * eventField(el, `pointermove`, `x`); * ``` * @param targetOrQuery Event target, HTML element or HTML query (eg '#someId') * @param eventName Name of event, eg. 'pointermove' * @param fieldName Name of field, eg 'x' * @param initialValue Initial data * @param options Options for source */ declare function eventField<TFieldValue = string>(targetOrQuery: EventTarget | string | null, eventName: string, fieldName: string, initialValue: TFieldValue, options?: Partial<EventOptions & FieldOptions<any, TFieldValue>>): Reactive<TFieldValue>; /** * Subscribes to an event, emitting data * * @example Print x,y position of mouse as it moves * ```js * const r = Rx.From.event(document, `pointermove`); * r.onValue(event => { * const { x, y } = event; * }); * ``` * * If `options.lazy` is _true_ (default: _false_), event will only be subscribed to when the stream * itself has a subscriber. * * `options.debugFiring` and `options.debugLifecycle` can be turned on to troubleshoot behaviour * of the stream if necessary. * @param targetOrQuery Event emitter, HTML element or string. If a string, it will be queryed as a selector. * @param name Event name * @param options Options * @returns */ declare function event<TEventArgs extends Record<string, any>>(targetOrQuery: EventTarget | null | string, name: string, initialValue: TEventArgs | undefined, options?: Partial<EventOptions>): ReactiveInitial<TEventArgs> & Reactive<TEventArgs>; type TriggerData = { sinceLast: number; total: number; }; /** * Emits a value whenever event happens. * Data emitted is `{ sinceLast, total }`, where 'sinceLast' * is milliseconds since last event and 'total' is total number of * times event has been fired. * @param targetOrQuery * @param name * @param options * @returns */ declare function eventTrigger(targetOrQuery: EventTarget | null | string, name: string, options?: Partial<EventTriggerOptions>): Reactive<TriggerData>; /** * Produces a reactive from the basis of a function. `callback` is executed, with its result emitted via the returned reactive. * * ```js * // Produce a random number every second * const r = Rx.From.func(Math.random, { interval: 1000 }); * ``` * * `callback` can be called repeatedly by providing the `interval` option to set the rate of repeat. * Looping can be limited with `options.maximumRepeats`, or passing a signal `options.signal` * and then activating it. * ```js * // Reactive that emits a random number every second, five times * const r1 = Rx.From.func(Math.random, { interval: 1000, maximumRepeats: 5 } * ``` * * ```js * // Generate a random number every second until ac.abort() is called * const ac = new AbortController(); * const r2 = Rx.From.func(Math.random, { interval: 1000, signal: ac.signal }); * ``` * * The third option is for `callback` to fire the provided abort function. * ```js * Rx.From.func((abort) => { * if (Math.random() > 0.5) abort('Random exit'); * return 1; * }); * ``` * * By default has a laziness of 'very' meaning that `callback` is run only when there's a subscriber * By default stream closes if `callback` throws an error. Use `options.closeOnError:'ignore'` to change. * @param callback * @param options * @returns */ declare function func<V>(callback: FunctionFunction<V>, options?: Partial<FunctionOptions>): ReactivePingable<V>; /** * Creates a Reactive from an AsyncGenerator or Generator * @param gen * @returns */ /** * Creates a readable reactive based on a (async)generator or iterator * ```js * // Generator a random value every 5 seconds * const valuesOverTime = Flow.interval(() => Math.random(), 5000); * // Wrap the generator * const r = Rx.From.iterator(time); * // Get notified when there is a new value * r.onValue(v => { * console.log(v); * }); * ``` * * Awaiting values could potentially hang code. Thus there is a `readTimeout`, the maximum time to wait for a value from the generator. Default: 5 minutes. * If `signal` is given, this will also cancel waiting for the value. * @param source */ declare function iterator<V>(source: IterableIterator<V> | Array<V> | AsyncIterableIterator<V> | Generator<V> | AsyncGenerator<V>, options?: Partial<GeneratorOptions>): Reactive<V>; /** * Returns a stream that merges the output of a list of homogenous streams. * Use {@link mergedWithOptions} to specify additional options. * @param sources * @returns */ declare function merged<T>(...sources: Reactive<T>[]): Reactive<T>; /** * Returns a stream that merges the output of a list of homogenous streams. * * @param sources * @param options * @returns */ declare function mergedWithOptions<T>(sources: Reactive<T>[], options?: Partial<InitLazyStreamOptions>): Reactive<T>; declare function number(initialValue: number): ReactiveWritable<number> & ReactiveInitial<number>; declare function number(): ReactiveWritable<number> & ReactiveNonInitial<number>; declare function object<V extends Record<string, any>>(initialValue: V, options?: Partial<ObjectOptions<V>>): ReactiveDiff<V> & ReactiveInitial<V>; declare function object<V extends Record<string, any>>(initialValue: undefined, options?: Partial<ObjectOptions<V>>): ReactiveDiff<V> & ReactiveNonInitial<V>; type ReactiveProxied<V> = V & { [symbol]: ReactiveDiff<V> & ReactiveInitial<V>; }; /** * Creates a proxy of `target` object (or array), so that regular property setting will be intercepted and output * on a {@link Reactive} object as well. * * ```js * const { proxy, rx } = Rx.From.objectProxy({ co