UNPKG

ixfx

Version:

A framework for programming interactivity

1,770 lines (1,740 loc) 264 kB
import { stringSegmentsWholeToEnd, stringSegmentsWholeToFirst } from "./chunk-KRKQPUZU.js"; import { StackMutable, depthFirst, map } from "./chunk-C5TMTNJN.js"; import { average, dotProduct, weight } from "./chunk-YG33FJI6.js"; import { NumberMap, immutable } from "./chunk-XFNQJV53.js"; import { DispatchList, continuously, hasLast, isPingable, isReactive, isTrigger, isTriggerFunction, isTriggerGenerator, isTriggerValue, isWrapped, isWritable, messageHasValue, messageIsDoneSignal, messageIsSignal, opify, rateMinimum, resolve, resolveSync, resolveTriggerValue, resolveWithFallback, resolveWithFallbackSync, sleep, timeout } from "./chunk-3PQXJLTZ.js"; import { StateMachine_exports, Stopwatch_exports, elapsedMillisecondsAbsolute, elapsedTicksAbsolute, ofTotal, ofTotalTicks, relative, timerWithFunction } from "./chunk-LHELVIWO.js"; import { QueueMutable, isAsyncIterable, isIterable } from "./chunk-VYCNRTDD.js"; import { getOrGenerate, getOrGenerateSync, logSet } from "./chunk-N6YIY4CM.js"; import { SimpleEventEmitter, intervalToMs } from "./chunk-72EKR3DZ.js"; import { resolveEl, resolveEls } from "./chunk-ICXKAKPN.js"; import { arrays_exports, insertAt, remove, zip } from "./chunk-45M4HUXQ.js"; import { addKeepingExisting, addObject, deleteByValue, filter, find, firstEntryByPredicate, firstEntryByValue, fromIterable, fromObject, getClosestIntegerKey, getFromKeys, hasAnyValue, hasKeyValue, mapToArray, mapToObjectTransform, mergeByKey, some, sortByValue, sortByValueProperty, toArray, toObject, transformMap, zipKeyValue } from "./chunk-KVLT2D4E.js"; import { shuffle } from "./chunk-LVLPUJZY.js"; import { isInteger, isPrimitive } from "./chunk-LKZ4HZTV.js"; import { afterMatch, beforeMatch, wildcard } from "./chunk-F2KVRMEV.js"; import { throwResult } from "./chunk-QVTHCRNR.js"; import { getErrorMessage } from "./chunk-4IJNRUE7.js"; import { isPlainObjectOrPrimitive, throwFunctionTest, throwStringTest } from "./chunk-WYMJKVGY.js"; import { parseRgbObject, scale, toHex, toHsl, toRgb, toString } from "./chunk-DLFRRV7R.js"; import { clamp } from "./chunk-QAEJS6HO.js"; import { defaultRandom } from "./chunk-5VWJ6TUI.js"; import { changedDataFields, compareArrays, compareData, compareKeys, maxScore, min } from "./chunk-Z2SF7PPR.js"; import { round } from "./chunk-3UVU2F72.js"; import { isEqualDefault, isEqualValueDefault, toStringDefault } from "./chunk-6UZ3OSJO.js"; import { numberTest, throwIntegerTest, throwNumberTest, throwPercentTest } from "./chunk-UC4AQMTL.js"; import { __export } from "./chunk-L5EJU35C.js"; // src/rx/index.ts var rx_exports = {}; __export(rx_exports, { Dom: () => Dom_exports, From: () => sources_exports, Ops: () => Ops, Sinks: () => Sinks, annotate: () => annotate, annotateWithOp: () => annotateWithOp, average: () => average3, cache: () => cache, chunk: () => chunk, cloneFromFields: () => cloneFromFields, combineLatestToArray: () => combineLatestToArray, combineLatestToObject: () => combineLatestToObject, computeWithPrevious: () => computeWithPrevious, debounce: () => debounce, drop: () => drop, elapsed: () => elapsed, field: () => field, filter: () => filter3, hasLast: () => hasLast, initLazyStream: () => initLazyStream, initLazyStreamWithInitial: () => initLazyStreamWithInitial, initStream: () => initStream, initUpstream: () => initUpstream, interpolate: () => interpolate4, isPingable: () => isPingable, isReactive: () => isReactive, isTrigger: () => isTrigger, isTriggerFunction: () => isTriggerFunction, isTriggerGenerator: () => isTriggerGenerator, isTriggerValue: () => isTriggerValue, isWrapped: () => isWrapped, isWritable: () => isWritable, manual: () => manual, max: () => max4, messageHasValue: () => messageHasValue, messageIsDoneSignal: () => messageIsDoneSignal, messageIsSignal: () => messageIsSignal, min: () => min5, opify: () => opify, pipe: () => pipe, prepare: () => prepare, rank: () => rank2, resolveSource: () => resolveSource, resolveTriggerValue: () => resolveTriggerValue, run: () => run, setHtmlText: () => setHtmlText, singleFromArray: () => singleFromArray, split: () => split, splitLabelled: () => splitLabelled, sum: () => sum3, switcher: () => switcher, symbol: () => symbol, syncToArray: () => syncToArray, syncToObject: () => syncToObject, takeNextValue: () => takeNextValue, tally: () => tally2, tapOps: () => tapOps, tapProcess: () => tapProcess, tapStream: () => tapStream, throttle: () => throttle, timeoutPing: () => timeoutPing, timeoutValue: () => timeoutValue, to: () => to, toArray: () => toArray4, toArrayOrThrow: () => toArrayOrThrow, toGenerator: () => toGenerator, transform: () => transform, valueToPing: () => valueToPing, withValue: () => withValue, wrap: () => wrap3, writable: () => writable }); // src/rx/sources/Function.ts function func(callback, options = {}) { const maximumRepeats = options.maximumRepeats ?? Number.MAX_SAFE_INTEGER; const closeOnError = options.closeOnError ?? true; const intervalMs = options.interval ? intervalToMs(options.interval) : -1; let manual2 = options.manual ?? false; if (options.interval === void 0 && options.manual === void 0) manual2 = true; if (manual2 && options.interval) throw new Error(`If option 'manual' is set, option 'interval' cannot be used`); const predelay = intervalToMs(options.predelay, 0); const lazy = options.lazy ?? `very`; const signal = options.signal; const internalAbort = new AbortController(); const internalAbortCallback = (reason) => { internalAbort.abort(reason); }; let sentResults = 0; let enabled = false; const done = (reason) => { events.dispose(reason); enabled = false; if (run2) run2.cancel(); }; const ping = async () => { if (!enabled) return false; if (predelay) await sleep(predelay); if (sentResults >= maximumRepeats) { done(`Maximum repeats reached ${maximumRepeats.toString()}`); return false; } try { if (signal?.aborted) { done(`Signal (${signal.aborted})`); return false; } const value = await callback(internalAbortCallback); sentResults++; events.set(value); return true; } catch (error) { if (closeOnError) { done(`Function error: ${getErrorMessage(error)}`); return false; } else { events.signal(`warn`, getErrorMessage(error)); return true; } } }; const run2 = manual2 ? void 0 : continuously(async () => { const pingResult = await ping(); if (!pingResult) return false; if (internalAbort.signal.aborted) { done(`callback function aborted (${internalAbort.signal.reason})`); return false; } }, intervalMs); const events = initLazyStream({ lazy, onStart() { enabled = true; if (run2) run2.start(); }, onStop() { enabled = false; if (run2) run2.cancel(); } }); if (lazy === `never` && run2) run2.start(); return { ...events, ping }; } // src/iterables/IterableAsync.ts var IterableAsync_exports = {}; __export(IterableAsync_exports, { asCallback: () => asCallback, chunks: () => chunks, concat: () => concat, dropWhile: () => dropWhile, equals: () => equals, every: () => every, fill: () => fill, filter: () => filter2, find: () => find2, flatten: () => flatten, forEach: () => forEach, fromArray: () => fromArray, fromIterable: () => fromIterable2, map: () => map2, max: () => max, min: () => min2, nextWithTimeout: () => nextWithTimeout, reduce: () => reduce, repeat: () => repeat, slice: () => slice, some: () => some2, toArray: () => toArray2, unique: () => unique, uniqueByValue: () => uniqueByValue, until: () => until, withDelay: () => withDelay, zip: () => zip2 }); async function* fromArray(array3, interval = 1) { for (const v of array3) { yield v; await sleep(interval); } } async function* fromIterable2(iterable, interval = 1) { for await (const v of iterable) { yield v; await sleep(interval); } } async function* chunks(it, size) { let buffer = []; for await (const v of it) { buffer.push(v); if (buffer.length === size) { yield buffer; buffer = []; } } if (buffer.length > 0) yield buffer; } async function* concat(...its) { for await (const it of its) yield* it; } async function* dropWhile(it, f) { for await (const v of it) { if (!f(v)) { yield v; } } } var until = async (it, callback) => { for await (const _ of it) { const value = await callback(); if (typeof value === `boolean` && !value) break; } }; var repeat = async function* (genCreator, repeatsOrSignal) { const repeats = typeof repeatsOrSignal === `number` ? repeatsOrSignal : Number.POSITIVE_INFINITY; const signal = typeof repeatsOrSignal === `number` ? void 0 : repeatsOrSignal; let count2 = repeats; while (true) { for await (const v of genCreator()) { yield v; if (signal?.aborted) break; } if (Number.isFinite(repeats)) { count2--; if (count2 === 0) break; } if (signal?.aborted) break; } }; async function equals(it1, it2, equality) { const iit1 = it1[Symbol.asyncIterator](); const iit2 = it2[Symbol.asyncIterator](); while (true) { const index1 = await iit1.next(); const index2 = await iit2.next(); if (equality !== void 0) { if (!equality(index1.value, index2.value)) return false; } else if (index1.value !== index2.value) return false; if (index1.done ?? index2.done) return index1.done && index2.done; } } async function every(it, f) { for await (const v of it) { const result = await f(v); if (!result) return false; } return true; } async function* fill(it, v) { for await (const _ of it) yield v; } async function* filter2(it, f) { for await (const v of it) { if (!await f(v)) continue; yield v; } } async function find2(it, f) { for await (const v of it) { if (await f(v)) return v; } } async function* flatten(it) { for await (const v of it) { if (typeof v === `object`) { if (Array.isArray(v)) { for (const vv of v) yield vv; } else if (isAsyncIterable(v)) { for await (const vv of v) { yield vv; } } else if (isIterable(v)) { for (const vv of v) { yield vv; } } } else { yield v; } } } var forEach = async function(iterator2, fn, options = {}) { const interval = options.interval; if (Array.isArray(iterator2)) { for (const x of iterator2) { const r = await fn(x); if (typeof r === `boolean` && !r) break; if (interval) await sleep(interval); } } else { for await (const x of iterator2) { const r = await fn(x); if (typeof r === `boolean` && !r) break; if (interval) await sleep(interval); } } }; async function* map2(it, f) { for await (const v of it) { yield f(v); } } async function* max(it, gt = (a, b) => a > b) { let max5; for await (const v of it) { if (max5 === void 0) { max5 = v; yield max5; continue; } if (gt(v, max5)) { max5 = v; yield v; } } } async function* min2(it, gt = (a, b) => a > b) { let min6; for await (const v of it) { if (min6 === void 0) { min6 = v; yield min6; continue; } if (gt(min6, v)) { min6 = v; yield v; } } return min6; } async function reduce(it, f, start) { for await (const v of it) start = f(start, v); return start; } async function asCallback(input, callback, onDone) { for await (const value of input) { callback(value); } if (onDone) onDone(); } async function* slice(it, start = 0, end = Number.POSITIVE_INFINITY) { const iit = it[Symbol.asyncIterator](); if (end < start) throw new Error(`Param 'end' should be more than 'start'`); for (; start > 0; start--, end--) await iit.next(); for await (const v of it) { if (end-- > 0) { yield v; } else { break; } } } async function* withDelay(it, delay) { for (const v of it) { await sleep(delay); yield v; } } async function nextWithTimeout(it, options) { const ms = intervalToMs(options, 1e3); const value = await Promise.race([ (async () => { await sleep({ millis: ms, signal: options.signal }); return void 0; })(), (async () => { return await it.next(); })() ]); if (value === void 0) throw new Error(`Timeout`); return value; } async function some2(it, f) { for await (const v of it) { if (await f(v)) return true; } return false; } async function toArray2(it, options = {}) { const result = []; const iterator2 = it[Symbol.asyncIterator](); const started = Date.now(); const maxItems = options.limit ?? Number.POSITIVE_INFINITY; const whileFunc = options.while; const maxElapsed = intervalToMs(options.elapsed, Number.POSITIVE_INFINITY); while (result.length < maxItems && Date.now() - started < maxElapsed) { if (whileFunc) { if (!whileFunc(result.length)) break; } const r = await iterator2.next(); if (r.done) break; result.push(r.value); } return result; } async function* unique(iterable) { const buffer = []; const itera = Array.isArray(iterable) ? iterable : [iterable]; for await (const it of itera) { for await (const v of it) { if (buffer.includes(v)) continue; buffer.push(v); yield v; } } } async function* uniqueByValue(input, toString5 = toStringDefault, seen = /* @__PURE__ */ new Set()) { for await (const v of input) { const key = toString5(v); if (seen.has(key)) continue; seen.add(key); yield v; } } async function* zip2(...its) { const iits = its.map((it) => it[Symbol.asyncIterator]()); while (true) { const vs = await Promise.all(iits.map((it) => it.next())); if (vs.some((v) => v.done)) return; yield vs.map((v) => v.value); } } // src/rx/sources/Iterator.ts function iterator(source, options = {}) { const lazy = options.lazy ?? `very`; const log = options.traceLifecycle ? (message) => { console.log(`Rx.From.iterator ${message}`); } : (_) => { }; const readIntervalMs = intervalToMs(options.readInterval, 5); const readTimeoutMs = intervalToMs(options.readTimeout, 5 * 60 * 1e3); const whenStopped = options.whenStopped ?? `continue`; let iterator2; let ourAc; let sm = StateMachine_exports.init({ idle: [`wait_for_next`], wait_for_next: [`processing_result`, `stopping`, `disposed`], processing_result: [`queued`, `disposed`, `stopping`], queued: [`wait_for_next`, `disposed`, `stopping`], stopping: `idle`, // eslint-disable-next-line unicorn/no-null disposed: null }, `idle`); const onExternalSignal = () => { log(`onExternalSignal`); ourAc?.abort(options.signal?.reason); }; if (options.signal) { options.signal.addEventListener(`abort`, onExternalSignal, { once: true }); } ; const read = async () => { log(`read. State: ${sm.value}`); ourAc = new AbortController(); try { sm = StateMachine_exports.to(sm, `wait_for_next`); const v = await nextWithTimeout(iterator2, { signal: ourAc.signal, millis: readTimeoutMs }); sm = StateMachine_exports.to(sm, `processing_result`); ourAc?.abort(`nextWithTimeout completed`); if (v.done) { log(`read v.done true`); events.dispose(`Generator complete`); sm = StateMachine_exports.to(sm, `disposed`); } if (sm.value === `stopping`) { log(`read. sm.value = stopping`); sm = StateMachine_exports.to(sm, `idle`); return; } if (sm.value === `disposed`) { log(`read. sm.value = disposed`); return; } events.set(v.value); } catch (error) { events.dispose(`Generator error: ${error.toString()}`); return; } if (sm.value === `processing_result`) { sm = StateMachine_exports.to(sm, `queued`); log(`scheduling read. State: ${sm.value}`); setTimeout(read, readIntervalMs); } else { sm = StateMachine_exports.to(sm, `idle`); } }; const events = initLazyStream({ ...options, lazy, onStart() { log(`onStart state: ${sm.value} whenStopped: ${whenStopped}`); if (sm.value !== `idle`) return; if (sm.value === `idle` && whenStopped === `reset` || iterator2 === void 0) { iterator2 = isAsyncIterable(source) ? source[Symbol.asyncIterator]() : source[Symbol.iterator](); } void read(); }, onStop() { log(`onStop state: ${sm.value} whenStopped: ${whenStopped}`); sm = StateMachine_exports.to(sm, `stopping`); if (whenStopped === `reset`) { log(`onStop reiniting iterator`); iterator2 = isAsyncIterable(source) ? source[Symbol.asyncIterator]() : source[Symbol.iterator](); } }, onDispose(reason) { log(`onDispose (${reason})`); ourAc?.abort(`Rx.From.iterator disposed (${reason})`); if (options.signal) options.signal.removeEventListener(`abort`, onExternalSignal); } }); return events; } // src/rx/ResolveSource.ts var resolveSource = (source, options = {}) => { if (isReactive(source)) return source; const generatorOptions = options.generator ?? { lazy: `initial`, interval: 5 }; const functionOptions = options.function ?? { lazy: `very` }; if (Array.isArray(source)) { return iterator(source.values(), generatorOptions); } else if (typeof source === `function`) { return func(source, functionOptions); } else if (typeof source === `object`) { if (isWrapped(source)) { return source.source; } if (isIterable(source) || isAsyncIterable(source)) { return iterator(source, generatorOptions); } } throw new TypeError(`Unable to resolve source. Supports: array, Reactive, Async/Iterable. Got type: ${typeof source}`); }; // src/rx/Cache.ts function cache(r, initialValue) { let lastValue = initialValue; r.onValue((value) => { lastValue = value; }); return { ...r, last() { return lastValue; }, resetCachedValue() { lastValue = void 0; } }; } // src/rx/InitStream.ts function initUpstream(upstreamSource, options) { const lazy = options.lazy ?? `initial`; const disposeIfSourceDone = options.disposeIfSourceDone ?? true; const onValue = options.onValue ?? ((_v) => { }); const source = resolveSource(upstreamSource); let unsub; const debugLabel = options.debugLabel ? `[${options.debugLabel}]` : ``; const onStop = () => { if (unsub === void 0) return; unsub(); unsub = void 0; if (options.onStop) options.onStop(); }; const onStart = () => { if (unsub !== void 0) return; if (options.onStart) options.onStart(); unsub = source.on((value) => { if (messageIsSignal(value)) { if (value.signal === `done`) { onStop(); events.signal(value.signal, value.context); if (disposeIfSourceDone) events.dispose(`Upstream source ${debugLabel} has completed (${value.context ?? ``})`); } else { events.signal(value.signal, value.context); } } else if (messageHasValue(value)) { onValue(value.value); } }); }; const events = initLazyStream({ ...options, lazy, onStart, onStop }); return events; } function initLazyStreamWithInitial(options) { const r = initLazyStream(options); const c = cache(r, options.initialValue); return c; } function initLazyStream(options) { const lazy = options.lazy ?? `initial`; const onStop = options.onStop ?? (() => { }); const onStart = options.onStart ?? (() => { }); const debugLabel = options.debugLabel ? `[${options.debugLabel}]` : ``; const events = initStream({ ...options, onFirstSubscribe() { if (lazy !== `never`) { onStart(); } }, onNoSubscribers() { if (lazy === `very`) { onStop(); } } }); if (lazy === `never`) onStart(); return events; } function initStream(options = {}) { let dispatcher; let disposed = false; let firstSubscribe = false; let emptySubscriptions = true; const onFirstSubscribe = options.onFirstSubscribe ?? void 0; const onNoSubscribers = options.onNoSubscribers ?? void 0; const debugLabel = options.debugLabel ? `[${options.debugLabel}]` : ``; const isEmpty3 = () => { if (dispatcher === void 0) return; if (!dispatcher.isEmpty) return; if (!emptySubscriptions) { emptySubscriptions = true; firstSubscribe = false; if (onNoSubscribers) onNoSubscribers(); } }; const subscribe = (handler) => { if (disposed) throw new Error(`Disposed, cannot subscribe ${debugLabel}`); if (dispatcher === void 0) dispatcher = new DispatchList(); const id = dispatcher.add(handler); emptySubscriptions = false; if (!firstSubscribe) { firstSubscribe = true; if (onFirstSubscribe) onFirstSubscribe(); } return () => { dispatcher?.remove(id); isEmpty3(); }; }; return { dispose: (reason) => { if (disposed) return; dispatcher?.notify({ value: void 0, signal: `done`, context: `Disposed: ${reason}` }); disposed = true; if (options.onDispose) options.onDispose(reason); }, isDisposed: () => { return disposed; }, removeAllSubscribers: () => { dispatcher?.clear(); isEmpty3(); }, set: (v) => { if (disposed) throw new Error(`${debugLabel} Disposed, cannot set`); dispatcher?.notify({ value: v }); }, // through: (pass: Passed<V>) => { // if (disposed) throw new Error(`Disposed, cannot through`); // dispatcher?.notify(pass) // }, signal: (signal, context) => { if (disposed) throw new Error(`${debugLabel} Disposed, cannot signal`); dispatcher?.notify({ signal, value: void 0, context }); }, on: (handler) => subscribe(handler), onValue: (handler) => { const unsub = subscribe((message) => { if (messageHasValue(message)) { handler(message.value); } }); return unsub; } }; } // src/dom/SetProperty.ts function setText(selectors, value) { return setProperty(`textContent`, selectors, value); } function setHtml(selectors, value) { return setProperty(`innerHTML`, selectors, value); } function setProperty(property, selectors, value) { let elements2 = []; const set = (v) => { const typ = typeof v; const vv = typ === `string` || typ === `number` || typ === `boolean` ? v : JSON.stringify(v); if (elements2.length === 0) { elements2 = resolveEls(selectors); } for (const element of elements2) { element[property] = vv; } return vv; }; return value === void 0 ? set : set(value); } // src/rx/sinks/Dom.ts var setHtmlText = (rxOrSource, optionsOrElementOrQuery) => { let el; let options; if (typeof optionsOrElementOrQuery === `string`) { options = { query: optionsOrElementOrQuery }; } if (typeof optionsOrElementOrQuery === `object`) { if (`nodeName` in optionsOrElementOrQuery) { options = { el: optionsOrElementOrQuery }; } else { options = optionsOrElementOrQuery; } } if (options === void 0) throw new TypeError(`Missing element as second parameter or option`); if (`el` in options) { el = options.el; } else if (`query` in options) { el = document.querySelector(options.query); } else { throw new TypeError(`Options does not include 'el' or 'query' fields`); } if (el === null || el === void 0) throw new Error(`Element could not be resolved.`); const stream = resolveSource(rxOrSource); const setter = setProperty(options.asHtml ? `innerHTML` : `textContent`, el); const off = stream.onValue((value) => { setter(value); }); return off; }; // src/rx/ToReadable.ts var toReadable = (stream) => ({ on: stream.on, dispose: stream.dispose, isDisposed: stream.isDisposed, onValue: stream.onValue }); // src/rx/ops/Annotate.ts function annotate(input, annotator, options = {}) { const upstream = initUpstream(input, { ...options, onValue(value) { const annotation = annotator(value); upstream.set({ value, annotation }); } }); return toReadable(upstream); } function annotateWithOp(input, annotatorOp) { const inputStream = resolveSource(input); const stream = annotatorOp(inputStream); const synced = syncToObject({ value: inputStream, annotation: stream }); return synced; } // src/rx/ops/Chunk.ts function chunk(source, options = {}) { const queue = new QueueMutable(); const quantity = options.quantity ?? 0; const returnRemainder = options.returnRemainder ?? true; const upstreamOpts = { ...options, onStop() { if (returnRemainder && !queue.isEmpty) { const data = queue.toArray(); queue.clear(); upstream.set(data); } }, onValue(value) { queue.enqueue(value); if (quantity > 0 && queue.length >= quantity) { send(); } if (timer !== void 0 && timer.runState === `idle`) { timer.start(); } } }; const upstream = initUpstream(source, upstreamOpts); const send = () => { if (queue.isEmpty) return; if (timer !== void 0) timer.start(); const data = queue.toArray(); queue.clear(); setTimeout(() => upstream.set(data)); }; const timer = options.elapsed ? timeout(send, options.elapsed) : void 0; return toReadable(upstream); } // src/rx/ops/Transform.ts function transform(input, transformer, options = {}) { const traceInput = options.traceInput ?? false; const traceOutput = options.traceOutput ?? false; const upstream = initUpstream(input, { lazy: `initial`, ...options, onValue(value) { const t2 = transformer(value); if (traceInput && traceOutput) { console.log(`Rx.Ops.transform input: ${JSON.stringify(value)} output: ${JSON.stringify(t2)}`); } else if (traceInput) { console.log(`Rx.Ops.transform input: ${JSON.stringify(value)}`); } else if (traceOutput) { console.log(`Rx.Ops.transform output: ${JSON.stringify(t2)}`); } upstream.set(t2); } }); return toReadable(upstream); } // src/rx/ops/CloneFromFields.ts var cloneFromFields = (source) => { return transform(source, (v) => { const entries = []; for (const field2 in v) { const value = v[field2]; if (isPlainObjectOrPrimitive(value)) { entries.push([field2, value]); } } return Object.fromEntries(entries); }); }; // src/rx/ops/CombineLatestToArray.ts function combineLatestToArray(reactiveSources, options = {}) { const event2 = initStream(); const onSourceDone = options.onSourceDone ?? `break`; const data = []; const sources = reactiveSources.map((source) => resolveSource(source)); const noop = () => { }; const sourceOff = sources.map((_) => noop); const doneSources = sources.map((_) => false); const unsub = () => { for (const v of sourceOff) { v(); } }; for (const [index, v] of sources.entries()) { data[index] = void 0; sourceOff[index] = v.on((message) => { if (messageIsDoneSignal(message)) { doneSources[index] = true; sourceOff[index](); sourceOff[index] = noop; if (onSourceDone === `break`) { unsub(); event2.dispose(`Source has completed and 'break' is set`); return; } if (!doneSources.includes(false)) { unsub(); event2.dispose(`All sources completed`); } } else if (messageHasValue(message)) { data[index] = message.value; event2.set([...data]); } }); } return { dispose: event2.dispose, isDisposed: event2.isDisposed, on: event2.on, onValue: event2.onValue }; } // src/data/Pathed.ts var Pathed_exports = {}; __export(Pathed_exports, { applyChanges: () => applyChanges, compareData: () => compareData2, getField: () => getField, getPaths: () => getPaths, getPathsAndData: () => getPathsAndData, updateByPath: () => updateByPath }); // src/data/Util.ts var isEmptyEntries = (value) => [...Object.entries(value)].length === 0; var isEqualContextString = (a, b, _path) => { return JSON.stringify(a) === JSON.stringify(b); }; // src/data/Pathed.ts var getEntries = (target, deepProbe) => { if (target === void 0) throw new Error(`Param 'target' is undefined`); if (target === null) throw new Error(`Param 'target' is null`); if (typeof target !== `object`) throw new Error(`Param 'target' is not an object (got: ${typeof target})`); if (deepProbe) { const entries = []; for (const field2 in target) { const value = target[field2]; if (isPlainObjectOrPrimitive(value)) { entries.push([field2, value]); } } return entries; } else { return Object.entries(target); } }; function* compareData2(a, b, options = {}) { if (a === void 0) { yield { path: options.pathPrefix ?? ``, value: b, state: `added` }; return; } if (b === void 0) { yield { path: options.pathPrefix ?? ``, previous: a, value: void 0, state: `removed` }; return; } const asPartial = options.asPartial ?? false; const undefinedValueMeansRemoved = options.undefinedValueMeansRemoved ?? false; const pathPrefix = options.pathPrefix ?? ``; const deepEntries = options.deepEntries ?? false; const eq = options.eq ?? isEqualContextString; const includeMissingFromA = options.includeMissingFromA ?? false; const includeParents = options.includeParents ?? false; if (isPrimitive(a) && isPrimitive(b)) { if (a !== b) yield { path: pathPrefix, value: b, previous: a, state: `change` }; return; } if (isPrimitive(b)) { yield { path: pathPrefix, value: b, previous: a, state: `change` }; return; } const entriesA = getEntries(a, deepEntries); const entriesAKeys = /* @__PURE__ */ new Set(); for (const [key, valueA] of entriesA) { entriesAKeys.add(key); const keyOfAInB = key in b; const valueOfKeyInB = b[key]; if (typeof valueA === `object` && valueA !== null) { if (keyOfAInB) { if (valueOfKeyInB === void 0) { throw new Error(`Pathed.compareData Value for key ${key} is undefined`); } else { const sub = [...compareData2(valueA, valueOfKeyInB, { ...options, pathPrefix: pathPrefix + key + `.` })]; if (sub.length > 0) { for (const s of sub) yield s; if (includeParents) { yield { path: pathPrefix + key, value: b[key], previous: valueA, state: `change` }; } } } } else { if (asPartial) continue; yield { path: pathPrefix + key, value: void 0, previous: valueA, state: `removed` }; } } else { const subPath = pathPrefix + key; if (keyOfAInB) { if (valueOfKeyInB === void 0 && undefinedValueMeansRemoved) { yield { path: subPath, previous: valueA, value: void 0, state: `removed` }; } else { if (!eq(valueA, valueOfKeyInB, subPath)) { yield { path: subPath, previous: valueA, value: valueOfKeyInB, state: `change` }; } } } else { if (asPartial) continue; yield { path: subPath, previous: valueA, value: void 0, state: `removed` }; } } } if (includeMissingFromA) { const entriesB = getEntries(b, deepEntries); for (const [key, valueB] of entriesB) { if (entriesAKeys.has(key)) continue; yield { path: pathPrefix + key, previous: void 0, value: valueB, state: `added` }; } } } var applyChanges = (source, changes) => { for (const change of changes) { source = updateByPath(source, change.path, change.value); } return source; }; var updateByPath = (target, path, value, allowShapeChange = false) => { if (path === void 0) throw new Error(`Parameter 'path' is undefined`); if (typeof path !== `string`) throw new Error(`Parameter 'path' should be a string. Got: ${typeof path}`); if (target === void 0) throw new Error(`Parameter 'target' is undefined`); if (target === null) throw new Error(`Parameter 'target' is null`); const split2 = path.split(`.`); const r = updateByPathImpl(target, split2, value, allowShapeChange); return r; }; var updateByPathImpl = (o, split2, value, allowShapeChange) => { if (split2.length === 0) { if (allowShapeChange) return value; if (Array.isArray(o) && !Array.isArray(value)) throw new Error(`Expected array value, got: '${JSON.stringify(value)}'. Set allowShapeChange=true to ignore.`); if (!Array.isArray(o) && Array.isArray(value)) throw new Error(`Unexpected array value, got: '${JSON.stringify(value)}'. Set allowShapeChange=true to ignore.`); if (typeof o !== typeof value) throw new Error(`Cannot reassign object type. (${typeof o} -> ${typeof value}). Set allowShapeChange=true to ignore.`); if (typeof o === `object` && !Array.isArray(o)) { const c = compareKeys(o, value); if (c.a.length > 0) { throw new Error(`New value is missing key(s): ${c.a.join(`,`)}`); } if (c.b.length > 0) { throw new Error(`New value cannot add new key(s): ${c.b.join(`,`)}`); } } return value; } const start = split2.shift(); if (!start) return value; const isInt = isInteger(start); if (isInt && Array.isArray(o)) { const index = Number.parseInt(start); if (index >= o.length && !allowShapeChange) throw new Error(`Array index ${index.toString()} is outside of the existing length of ${o.length.toString()}. Use allowShapeChange=true to permit this.`); const copy = [...o]; copy[index] = updateByPathImpl(copy[index], split2, value, allowShapeChange); return copy; } else if (start in o) { const copy = { ...o }; copy[start] = updateByPathImpl(copy[start], split2, value, allowShapeChange); return copy; } else { throw new Error(`Path ${start} not found in data`); } }; var getField = (object2, path) => { if (typeof path !== `string`) throw new Error(`Param 'path' ought to be a string. Got: '${typeof path}'`); if (path.length === 0) throw new Error(`Param string 'path' is empty`); if (object2 === void 0) throw new Error(`Param 'object' is undefined`); if (object2 === null) throw new Error(`Param 'object' is null`); const split2 = path.split(`.`); const v = getFieldImpl(object2, split2); return v; }; var getFieldImpl = (object2, split2) => { if (object2 === void 0) throw new Error(`Param 'object' is undefined`); if (split2.length === 0) throw new Error(`Path has run out`); const start = split2.shift(); if (!start) throw new Error(`Unexpected empty split path`); const isInt = isInteger(start); if (isInt && Array.isArray(object2)) { const index = Number.parseInt(start); if (typeof object2[index] === `undefined`) { return { success: false, error: `Index '${index}' does not exist. Length: ${object2.length}` }; } if (split2.length === 0) { return { value: object2[index], success: true }; } else { return getFieldImpl(object2[index], split2); } } else if (typeof object2 === `object` && start in object2) { if (split2.length === 0) { return { value: object2[start], success: true }; } else { return getFieldImpl(object2[start], split2); } } else { return { success: false, error: `Path '${start}' not found` }; } }; function* getPaths(object2, onlyLeaves = false) { if (object2 === void 0 || object2 === null) return; const iter = depthFirst(object2); for (const c of iter) { if (c.nodeValue === void 0 && onlyLeaves) continue; let path = c.name; if (c.ancestors.length > 0) path = c.ancestors.join(`.`) + `.` + path; yield path; } } function* getPathsAndData(o, onlyLeaves = false, maxDepth = Number.MAX_SAFE_INTEGER, prefix = ``) { if (o === null) return; if (o === void 0) return; yield* getPathsAndDataImpl(o, prefix, onlyLeaves, maxDepth); } function* getPathsAndDataImpl(o, prefix, onlyLeaves = false, maxDepth) { if (maxDepth <= 0) return; if (typeof o !== `object`) return; for (const entries of Object.entries(o)) { const sub = (prefix.length > 0 ? prefix + `.` : ``) + entries[0]; const value = entries[1]; const leaf = typeof value !== `object`; if (onlyLeaves && leaf || !onlyLeaves) { yield { path: sub, value }; } yield* getPathsAndDataImpl(value, sub, onlyLeaves, maxDepth - 1); } } // src/rx/sources/Object.ts function object(initialValue, options = {}) { const eq = options.eq ?? isEqualContextString; const setEvent = initStream(); const diffEvent = initStream(); const fieldChangeEvents = []; let value = initialValue; let disposed = false; const set = (v) => { const diff = [...compareData2(value ?? {}, v, { ...options, includeMissingFromA: true })]; if (diff.length === 0) return; value = v; setEvent.set(v); diffEvent.set(diff); }; const fireFieldUpdate = (field2, value2) => { for (const [matcher, pattern, list] of fieldChangeEvents) { if (matcher(field2)) { list.notify({ fieldName: field2, pattern, value: value2 }); } } }; const updateCompareOptions = { asPartial: true, includeParents: true }; const update = (toMerge) => { if (value === void 0) { value = toMerge; setEvent.set(value); for (const [k, v] of Object.entries(toMerge)) { fireFieldUpdate(k, v); } return value; } else { const diff = [...compareData2(value, toMerge, updateCompareOptions)]; if (diff.length === 0) return value; value = { ...value, ...toMerge }; setEvent.set(value); diffEvent.set(diff); for (const d of diff) { fireFieldUpdate(d.path, d.value); } return value; } }; const updateField = (path, valueForField) => { if (value === void 0) throw new Error(`Cannot update value when it has not already been set`); const existing = getField(value, path); if (!throwResult(existing)) return; if (eq(existing.value, valueForField, path)) { return; } let diff = [...compareData2(existing.value, valueForField, { ...options, includeMissingFromA: true })]; diff = diff.map((d) => { if (d.path.length > 0) return { ...d, path: path + `.` + d.path }; return { ...d, path }; }); const o = updateByPath(value, path, valueForField, true); value = o; setEvent.set(o); diffEvent.set(diff); fireFieldUpdate(path, valueForField); }; const dispose = (reason) => { if (disposed) return; diffEvent.dispose(reason); setEvent.dispose(reason); disposed = true; }; return { dispose, isDisposed() { return disposed; }, /** * Update a field. * Exception is thrown if field does not exist */ updateField, last: () => value, on: setEvent.on, onValue: setEvent.onValue, onDiff: diffEvent.onValue, onField(fieldPattern, handler) { const matcher = wildcard(fieldPattern); const listeners = new DispatchList(); fieldChangeEvents.push([matcher, fieldPattern, listeners]); const id = listeners.add(handler); return () => listeners.remove(id); }, /** * Set the whole object */ set, /** * Update the object with a partial set of fields and values */ update }; } // src/rx/ops/CombineLatestToObject.ts function combineLatestToObject(reactiveSources, options = {}) { const disposeSources = options.disposeSources ?? true; const event2 = object(void 0); const onSourceDone = options.onSourceDone ?? `break`; const emitInitial = options.emitInitial ?? true; let emitInitialDone = false; const states = /* @__PURE__ */ new Map(); for (const [key, source] of Object.entries(reactiveSources)) { const initialData = `last` in source ? source.last() : void 0; const s = { source: resolveSource(source), done: false, data: initialData, off: () => { } }; states.set(key, s); } const sources = Object.fromEntries(Object.entries(states).map((entry) => [entry[0], entry[1].source])); const someUnfinished = () => some(states, (v) => !v.done); const unsub = () => { for (const state of states.values()) state.off(); }; const getData = () => { const r = {}; for (const [key, state] of states) { const d = state.data; if (d !== void 0) { r[key] = state.data; } } return r; }; const trigger = () => { emitInitialDone = true; const d = getData(); event2.set(d); }; const wireUpState = (state) => { state.off = state.source.on((message) => { if (messageIsDoneSignal(message)) { state.done = true; state.off(); state.off = () => { }; if (onSourceDone === `break`) { unsub(); event2.dispose(`Source has completed and 'break' is behaviour`); return; } if (!someUnfinished()) { unsub(); event2.dispose(`All sources completed`); } } else if (messageHasValue(message)) { state.data = message.value; trigger(); } }); }; for (const state of states.values()) { wireUpState(state); } if (!emitInitialDone && emitInitial) { trigger(); } return { ...event2, hasSource(field2) { return states.has(field2); }, replaceSource(field2, source) { const state = states.get(field2); if (state === void 0) throw new Error(`Field does not exist: '${field2}'`); state.off(); const s = resolveSource(source); state.source = s; wireUpState(state); }, setWith(data) { let written = {}; for (const [key, value] of Object.entries(data)) { const state = states.get(key); if (state !== void 0) { if (isWritable(state.source)) { state.source.set(value); written[key] = value; } state.data = value; } } return written; }, sources, last() { return getData(); }, dispose(reason) { unsub(); event2.dispose(reason); if (disposeSources) { for (const v of states.values()) { v.source.dispose(`Part of disposed mergeToObject`); } } } }; } // src/rx/ops/ComputeWithPrevious.ts function computeWithPrevious(input, fn) { let previousValue; let currentValue; if (hasLast(input)) { currentValue = previousValue = input.last(); } const trigger = () => { if (previousValue === void 0 && currentValue !== void 0) { previousValue = currentValue; upstream.set(previousValue); } else if (previousValue !== void 0 && currentValue !== void 0) { const vv = fn(previousValue, currentValue); previousValue = vv; upstream.set(vv); } }; const upstream = initUpstream(input, { lazy: "very", debugLabel: `computeWithPrevious`, onValue(value) { currentValue = value; trigger(); } }); if (currentValue) trigger(); return { ...toReadable(upstream), ping: () => { if (currentValue !== void 0) trigger(); } }; } // src/rx/ops/Debounce.ts function debounce(source, options = {}) { const elapsed2 = intervalToMs(options.elapsed, 50); let lastValue; const timer = timeout(() => { const v = lastValue; if (v) { upstream.set(v); lastValue = void 0; } }, elapsed2); const upstream = initUpstream(source, { ...options, onValue(value) { lastValue = value; timer.start(); } }); return toReadable(upstream); } // src/rx/ops/Elapsed.ts var elapsed = (input) => { let last = 0; return transform(input, (_ignored) => { const elapsed2 = last === 0 ? 0 : Date.now() - last; last = Date.now(); return elapsed2; }); }; // src/rx/ops/Field.ts function field(fieldSource, fieldName, options = {}) { const fallbackFieldValue = options.fallbackFieldValue; const fallbackObject = options.fallbackObject; const upstream = initUpstream(fieldSource, { disposeIfSourceDone: true, ...options, onValue(value) { let v; if (fieldName in value) { v = value[fieldName]; } else if (fallbackObject && fieldName in fallbackObject) { v = fallbackObject[fieldName]; } if (v === void 0) { v = fallbackFieldValue; } if (v !== void 0) { upstream.set(v); } } }); return toReadable(upstream); } // src/rx/ops/Filter.ts function filter3(input, predicate, options) { const upstream = initUpstream(input, { ...options, onValue(value) { if (predicate(value)) { upstream.set(value); } } }); return toReadable(upstream); } function drop(input, predicate, options) { const upstream = initUpstream(input, { ...options, onValue(value) { if (!predicate(value)) { upstream.set(value); } } }); return toReadable(upstream); } // src/numbers/Wrap.ts var wrapInteger = (v, min6 = 0, max5 = 360) => { throwIntegerTest(v, void 0, `v`); throwIntegerTest(min6, void 0, `min`); throwIntegerTest(max5, void 0, `max`); if (v === min6) return min6; if (v === max5) return min6; if (v > 0 && v < min6) v += min6; v -= min6; max5 -= min6; v = v % max5; if (v < 0) v = max5 - Math.abs(v) + min6; return v + min6; }; var wrap = (v, min6 = 0, max5 = 1) => { throwNumberTest(v, ``, `min`); throwNumberTest(min6, ``, `min`); throwNumberTest(max5, ``, `max`); if (v === min6) return min6; if (v === max5) return min6; while (v <= min6 || v >= max5) { if (v === max5) break; if (v === min6) break; if (v > max5) { v = min6 + (v - max5); } else if (v < min6) { v = max5 - (min6 - v); } } return v; }; var wrapRange = (min6, max5, fn, a, b) => { let r = 0; const distF = Math.abs(b - a); const distFwrap = Math.abs(max5 - a + b); const distBWrap = Math.abs(a + (360 - b)); const distMin = Math.min(distF, distFwrap, distBWrap); if (distMin === distBWrap) { r = a - fn(distMin); } else if (distMin === distFwrap) { r = a + fn(distMin); } else { if (a > b) { r = a - fn(distMin); } else { r = a + fn(distMin); } } return wrapInteger(r, min6, max5); }; // src/modulation/easing/index.ts var easing_exports = {}; __export(easing_exports, { Named: () => EasingsNamed_exports, create: () => create2, get: () => get, getEasingNames: () => getEasingNames, line: () => line, tickEasing: () => tickEasing, ticks: () => ticks2, time: () => time2, timeEasing: () => timeEasing }); // src/modulation/easing/EasingsNamed.ts var EasingsNamed_exports = {}; __export(EasingsNamed_exports, { arch: () => arch, backIn: () => backIn, backInOut: () => backInOut, backOut: () => backOut, bell: () => bell, bounceIn: () => bounceIn, bounceInOut: () => bounceInOut, bounceOut: () => bounceOut, circIn: () => circIn, circInOut: () => circInOut, circOut: () => circOut, cubicIn: () => cubicIn, cubicOut: () => cubicOut, elasticIn: () => elasticIn, elasticInOut: () => elasticInOut, elasticOut: () => elasticOut, expoIn: () => expoIn, expoInOut: () => expoInOut, expoOut: () => expoOut, quadIn: () => quadIn, quadInOut: () => quadInOut, quadOut: () => quadOut, quartIn: () => quartIn, quartOut: () => quartOut, quintIn: () => quintIn, quintInOut: () => quintInOut, quintOut: () => quintOut, sineIn: () => sineIn, sineInOut: () => sineInOut, sineOut: () => sineOut, smootherstep: () => smootherstep, smoothstep: () => smoothstep }); // src/modulation/Gaussian.ts var pow = Math.pow; var gaussianA = 1 / Math.sqrt(2 * Math.PI); var gaussian = (standardDeviation = 0.4) => { const mean = 0.5; return (t2) => { const f = gaussianA / standardDeviation; let p = -2.5; let c = (t2 - mean) / standardDeviation; c *= c; p *= c; const v = f * pow(Math.E, p); if (v > 1) return 1; if (v < 0) return 0; return v; }; }; // src/modulation/easing/EasingsNamed.ts var sqrt = Math.sqrt; var pow2 = Math.pow; var cos = Math.cos; var pi = Math.PI; var sin = Math.sin; var bounceOut = (x) => { const n1 = 7.5625; const d1 = 2.75; if (x < 1 / d1) { return n1 * x * x; } else if (x < 2 / d1) { return n1 * (x -= 1.5 / d1) * x + 0.75; } else if (x < 2.5 / d1) { return n1 * (x -= 2.25 / d1) * x + 0.9375; } else { return n1 * (x -= 2.625 / d1) * x + 0.984375; } }; var quintIn = (x) => x * x * x * x * x; var quintOut = (x) => 1 - pow2(1 - x, 5); var arch = (x) => x * (1 - x) * 4; var smoothstep = (x) => x * x * (3 - 2 * x); var smootherstep = (x) => (x * (x * 6 - 15) + 10) * x * x * x; var sineIn = (x) => 1 - cos(x * pi / 2); var sineOut = (x) => sin(x * pi / 2); var quadIn = (x) => x * x; var quadOut = (x) => 1 - (1 - x) * (1 - x); var sineInOut = (x) => -(cos(pi * x) - 1) / 2; var quadInOut = (x) => x < 0.5 ? 2 * x * x : 1 - pow2(-2 * x + 2, 2) / 2; var cubicIn = (x) => x * x * x; var cubicOut = (x) => 1 - pow2(1 - x, 3); var quartIn = (x) => x * x * x * x; var quartOut = (x) => 1 - pow2(1 - x, 4); var expoIn = (x) => x === 0 ? 0 : pow2(2, 10 * x - 10); var expoOut = (x) => x === 1 ? 1 : 1 - pow2(2, -10 * x);