{"version":3,"file":"index.cjs","names":[],"sources":["../src/lib/composition.ts","../src/lib/index.ts"],"sourcesContent":["import {makeSignal, Subscriber, Unsubscribe, ReadonlySignal} from './index.js';\n\n/**\n * Create a signal that emits whenever the passed signal emits. The original\n * emitted value gets transformed by the passed function and the result gets\n * emitted.\n *\n * Example:\n * ```ts\n * const signal$ = makeSignal<number>();\n * const derived$ = deriveSignal(signal$, (n) => n + 100);\n * derived$.subscribe((v) => console.log(v));\n * signal$.emit(3); // will trigger console.log, echoing 103\n * ```\n * @param signal$ a signal.\n * @param transform a transformation function.\n * @returns a new signal that will emit the transformed data.\n */\nexport function deriveSignal<T, U>(signal$: ReadonlySignal<T>, transform: (data: T) => U): ReadonlySignal<U> {\n\tconst base$ = makeSignal<U>();\n\tconst emitTransformed: Subscriber<T> = (data: T) => {\n\t\tbase$.emit(transform(data));\n\t};\n\tconst handleUnsubscribe = () => {\n\t\tif (unsubscribeOriginal && base$.nOfSubscriptions() === 0) {\n\t\t\tunsubscribeOriginal();\n\t\t\tunsubscribeOriginal = null;\n\t\t}\n\t};\n\tlet unsubscribeOriginal: Unsubscribe | null = null;\n\treturn {\n\t\tnOfSubscriptions: base$.nOfSubscriptions,\n\t\tsubscribe: (s) => {\n\t\t\tconst unsubscribe = base$.subscribe(s);\n\t\t\tif (!unsubscribeOriginal) {\n\t\t\t\tunsubscribeOriginal = signal$.subscribe(emitTransformed);\n\t\t\t}\n\t\t\treturn () => {\n\t\t\t\tunsubscribe();\n\t\t\t\thandleUnsubscribe();\n\t\t\t};\n\t\t},\n\t\tsubscribeOnce: (s) => {\n\t\t\tconst unsubscribe = base$.subscribeOnce((v) => {\n\t\t\t\ts(v);\n\t\t\t\thandleUnsubscribe();\n\t\t\t});\n\t\t\tif (!unsubscribeOriginal) {\n\t\t\t\tunsubscribeOriginal = signal$.subscribe(emitTransformed);\n\t\t\t}\n\t\t\treturn () => {\n\t\t\t\tunsubscribe();\n\t\t\t\thandleUnsubscribe();\n\t\t\t};\n\t\t},\n\t};\n}\n\n/**\n * Coalesce multiple signals into one that will emit the latest value emitted\n * by any of the source signals.\n *\n * Example:\n * ```ts\n * const lastUpdate1$ = makeSignal<number>();\n * const lastUpdate2$ = makeSignal<number>();\n * const latestUpdate$ = coalesceSignals([lastUpdate1$, lastUpdate2$]);\n * latestUpdate$.subscribe((v) => console.log(v));\n * lastUpdate1$.emit(1577923200000); // will log 1577923200000\n * lastUpdate2$.emit(1653230659450); // will log 1653230659450\n * ```\n * @param signals$ an array of signals to observe.\n * @returns a new signal that emits whenever one of the source signals emits.\n */\nexport function coalesceSignals<T extends unknown[]>(signals$: {[P in keyof T]: ReadonlySignal<T[P]>}): ReadonlySignal<T[number]> {\n\tconst base$ = makeSignal<T[number]>();\n\tconst emit = (data: T[number]) => {\n\t\tbase$.emit(data);\n\t};\n\tconst handleUnsubscribe = () => {\n\t\tif (unsubscribeOriginals && base$.nOfSubscriptions() === 0) {\n\t\t\tunsubscribeOriginals.forEach((unsub) => unsub());\n\t\t\tunsubscribeOriginals = null;\n\t\t}\n\t};\n\tlet unsubscribeOriginals: Array<Unsubscribe> | null = null;\n\treturn {\n\t\tnOfSubscriptions: base$.nOfSubscriptions,\n\t\tsubscribe: (s) => {\n\t\t\tconst unsubscribe = base$.subscribe(s);\n\t\t\tif (!unsubscribeOriginals) {\n\t\t\t\tunsubscribeOriginals = signals$.map((signal$) => (signal$ as ReadonlySignal<T[number]>).subscribe(emit));\n\t\t\t}\n\t\t\treturn () => {\n\t\t\t\tunsubscribe();\n\t\t\t\thandleUnsubscribe();\n\t\t\t};\n\t\t},\n\t\tsubscribeOnce: (s) => {\n\t\t\tconst unsubscribe = base$.subscribeOnce((v) => {\n\t\t\t\ts(v);\n\t\t\t\thandleUnsubscribe();\n\t\t\t});\n\t\t\tif (!unsubscribeOriginals) {\n\t\t\t\tunsubscribeOriginals = signals$.map((signal$) => (signal$ as ReadonlySignal<T[number]>).subscribe(emit));\n\t\t\t}\n\t\t\treturn () => {\n\t\t\t\tunsubscribe();\n\t\t\t\thandleUnsubscribe();\n\t\t\t};\n\t\t},\n\t};\n}\n","/** A generic subscriber that takes a value emitted by a signal as its only parameter. */\nexport type Subscriber<T> = (current: T) => void;\n/** A function that's used to unsubscribe a subscriber from a signal. */\nexport type Unsubscribe = () => void;\n\n/** A signal that can have subscribers and emit values to them. */\nexport type ReadonlySignal<T> = {\n\t/**\n\t * Subscribe a function to this signal.\n\t *\n\t * Note: subscribers are deduplicated, if you need to subscribe the same\n\t * function more than once wrap it in an arrow function, e.g.\n\t * `signal$.subscribe((v) => myFunc(v));`\n\t * @param subscriber a function that will be called when this signal emits.\n\t */\n\tsubscribe(subscriber: Subscriber<T>): Unsubscribe;\n\t/**\n\t * Subscribe a function to this signal and automatically unsubscribe it after one emit occurs.\n\t *\n\t * @param subscriber a function that will be called when this signal emits.\n\t */\n\tsubscribeOnce(subscriber: Subscriber<T>): Unsubscribe;\n\t/**\n\t * Return the current number of active subscriptions.\n\t */\n\tnOfSubscriptions(): number;\n};\n\n/** A signal that can have subscribers and emit values to them. */\nexport type Signal<T> = ReadonlySignal<T> & {\n\t/**\n\t * Emit a value to all subscribers.\n\t * @param v the value to emit.\n\t */\n\temit(v: T): void;\n};\n\n/**\n * Make a signal of type T.\n *\n * Example usage:\n * ```ts\n * const signal$ = makeSignal<number>();\n * signal$.emit(10);\n * ```\n * Example usage with no data:\n * ```ts\n * const signal$ = makeSignal<void>();\n * signal$.emit();\n * ```\n * @returns a signal.\n */\nexport function makeSignal<T>(): Signal<T> {\n\tconst subscribers: Subscriber<T>[] = [];\n\tfunction emit(v: T): void {\n\t\tif (subscribers.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\t// Create a snapshot of all subscribers before emitting,\n\t\t// so that if subscriptions are added or removed\n\t\t// they won't affect the current emit loop.\n\t\tfor (const subscriber of subscribers.slice()) {\n\t\t\tsubscriber(v);\n\t\t}\n\t}\n\tfunction unsubscribe(subscriber: Subscriber<T>) {\n\t\tconst index = subscribers.indexOf(subscriber);\n\t\tif (index !== -1) {\n\t\t\tsubscribers.splice(index, 1);\n\t\t}\n\t}\n\tfunction subscribe(subscriber: Subscriber<T>) {\n\t\tconst index = subscribers.indexOf(subscriber);\n\t\tif (index === -1) {\n\t\t\tsubscribers.push(subscriber);\n\t\t}\n\n\t\treturn () => unsubscribe(subscriber);\n\t}\n\tfunction subscribeOnce(subscriber: Subscriber<T>) {\n\t\tconst unsubscribeWrapper = subscribe((v) => {\n\t\t\t// this must happen first to let the subscriber\n\t\t\t// know that it has already been removed from this signal\n\t\t\t// (this is used for example in composition.ts).\n\t\t\tunsubscribeWrapper();\n\t\t\tsubscriber(v);\n\t\t});\n\t\treturn unsubscribeWrapper;\n\t}\n\n\treturn {\n\t\temit,\n\t\tsubscribe,\n\t\tsubscribeOnce,\n\t\tnOfSubscriptions() {\n\t\t\treturn subscribers.length;\n\t\t},\n\t};\n}\n\nexport * from './composition.js';\n"],"mappings":"mEAkBA,SAAgB,EAAmB,EAA4B,EAA8C,CAC5G,IAAM,EAAQ,GAAe,CACvB,EAAkC,GAAY,CACnD,EAAM,KAAK,EAAU,EAAK,CAAC,EAEtB,MAA0B,CAC3B,GAAuB,EAAM,kBAAkB,GAAK,IACvD,GAAqB,CACrB,EAAsB,OAGpB,EAA0C,KAC9C,MAAO,CACN,iBAAkB,EAAM,iBACxB,UAAY,GAAM,CACjB,IAAM,EAAc,EAAM,UAAU,EAAE,CAItC,MAHA,CACC,IAAsB,EAAQ,UAAU,EAAgB,KAE5C,CACZ,GAAa,CACb,GAAmB,GAGrB,cAAgB,GAAM,CACrB,IAAM,EAAc,EAAM,cAAe,GAAM,CAC9C,EAAE,EAAE,CACJ,GAAmB,EAClB,CAIF,MAHA,CACC,IAAsB,EAAQ,UAAU,EAAgB,KAE5C,CACZ,GAAa,CACb,GAAmB,GAGrB,CAmBF,SAAgB,EAAqC,EAA6E,CACjI,IAAM,EAAQ,GAAuB,CAC/B,EAAQ,GAAoB,CACjC,EAAM,KAAK,EAAK,EAEX,MAA0B,CAC3B,GAAwB,EAAM,kBAAkB,GAAK,IACxD,EAAqB,QAAS,GAAU,GAAO,CAAC,CAChD,EAAuB,OAGrB,EAAkD,KACtD,MAAO,CACN,iBAAkB,EAAM,iBACxB,UAAY,GAAM,CACjB,IAAM,EAAc,EAAM,UAAU,EAAE,CAItC,MAHA,CACC,IAAuB,EAAS,IAAK,GAAa,EAAsC,UAAU,EAAK,CAAC,KAE5F,CACZ,GAAa,CACb,GAAmB,GAGrB,cAAgB,GAAM,CACrB,IAAM,EAAc,EAAM,cAAe,GAAM,CAC9C,EAAE,EAAE,CACJ,GAAmB,EAClB,CAIF,MAHA,CACC,IAAuB,EAAS,IAAK,GAAa,EAAsC,UAAU,EAAK,CAAC,KAE5F,CACZ,GAAa,CACb,GAAmB,GAGrB,CC3DF,SAAgB,GAA2B,CAC1C,IAAM,EAA+B,EAAE,CACvC,SAAS,EAAK,EAAY,CACrB,KAAY,SAAW,EAM3B,IAAK,IAAM,KAAc,EAAY,OAAO,CAC3C,EAAW,EAAE,CAGf,SAAS,EAAY,EAA2B,CAC/C,IAAM,EAAQ,EAAY,QAAQ,EAAW,CACzC,IAAU,IACb,EAAY,OAAO,EAAO,EAAE,CAG9B,SAAS,EAAU,EAA2B,CAM7C,OALc,EAAY,QAAQ,EAC9B,GAAU,IACb,EAAY,KAAK,EAAW,KAGhB,EAAY,EAAW,CAErC,SAAS,EAAc,EAA2B,CACjD,IAAM,EAAqB,EAAW,GAAM,CAI3C,GAAoB,CACpB,EAAW,EAAE,EACZ,CACF,OAAO,EAGR,MAAO,CACN,OACA,YACA,gBACA,kBAAmB,CAClB,OAAO,EAAY,QAEpB"}