ixfx
Version:
A framework for programming interactivity
1,770 lines (1,740 loc) • 264 kB
JavaScript
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);