Find the cost of adding an npm package to your app's bundle size teardown.kelinci.dev
14
fork

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 72 lines 2.2 kB view raw
1import { createEffect, createMemo, createSignal, onCleanup, type Accessor, type Signal } from 'solid-js'; 2 3/** 4 * creates a signal that derives its initial value from an accessor but can be overwritten. 5 * when the source accessor changes, the signal resets to the new derived value. 6 * 7 * @param accessor the source accessor to derive from 8 * @returns a signal tuple [getter, setter] 9 */ 10export function createDerivedSignal<T>(accessor: Accessor<T>): Signal<T> { 11 const computable = createMemo(() => createSignal(accessor())); 12 13 // @ts-expect-error: setter type mismatch is fine 14 // oxlint-disable-next-line typescript/no-unsafe-type-assertion 15 return [() => computable()[0](), (next) => computable()[1](next)] as Signal<T>; 16} 17 18/** 19 * creates an abortable signal pair for cancelling async operations. 20 * calling create() aborts any previous signal and returns a fresh one. 21 * automatically aborts on component cleanup. 22 * 23 * @returns tuple of [create, abort] functions 24 */ 25export const makeAbortable = (): [create: () => AbortSignal, abort: () => void] => { 26 let controller: AbortController | undefined; 27 28 const abort = (): void => { 29 controller?.abort(); 30 }; 31 const create = (): AbortSignal => { 32 abort(); 33 controller = new AbortController(); 34 return controller.signal; 35 }; 36 37 onCleanup(abort); 38 39 return [create, abort]; 40}; 41 42/** 43 * creates a throttled accessor that emits the source value at most once per interval. 44 * uses trailing edge only: waits for the interval to elapse, then emits the latest value. 45 * 46 * @param source the source accessor to throttle 47 * @param ms throttle interval in milliseconds 48 * @returns throttled accessor 49 */ 50export function createTrailingThrottle<T>(source: Accessor<T>, ms: number): Accessor<T> { 51 let lastSource = source(); 52 let timeout: number | undefined; 53 54 const [throttled, setThrottled] = createSignal(lastSource); 55 56 createEffect((initialMount: boolean) => { 57 lastSource = source(); 58 59 if (initialMount || timeout !== undefined) { 60 return false; 61 } 62 63 timeout = setTimeout(() => { 64 timeout = undefined; 65 return setThrottled(() => lastSource); 66 }, ms); 67 68 return false; 69 }, true); 70 71 return throttled; 72}