UNPKG

@dvcol/svelte-utils

Version:

Svelte library for common utility functions and constants

102 lines (101 loc) 3.43 kB
import { tick, untrack } from 'svelte'; const wait = (options) => { if (!options?.next) return; tick().then(options.next); }; const useUntil = (options) => { let first = 0; return ({ skip = 0 } = {}) => { if (skip <= first) return options?.until?.(); first += 1; return skip <= first || options?.until?.(); }; }; /** * Create a function that wraps the logic to run when the sources change. * * If change returns a callback, it will run: * * immediately before the effect re-runs * * when the component is destroyed * @see https://svelte.dev/docs/svelte/$effect * * @param change - logic to run when sources change * @param sources - getter function including tracked dependencies * @param options - watch options to control the behavior * @param options.tracked - whether to run the logic inside a tracked scope (default: false with sources, true without) */ export const useEffect = (change, sources, { tracked = !sources, ...options } = {}) => { const until = useUntil(options); return () => { sources?.(); if (until(options)) return; const cb = tracked ? change() : untrack(change); wait(options); return cb; }; }; /** * Watch for changes in the sources and run the logic. * * Logic will run outside of the tracked scope if `sources` is provided or if `options.tracked` is explicitly false. * * If change returns a callback, it will run: * * immediately before the effect re-runs * * when the component is destroyed * @see https://svelte.dev/docs/svelte/$effect * * @param change - logic to run when sources change * @param sources - getter function including tracked dependencies * @param options - watch options * @param options.root - run outside tracked scope * @param options.pre - run before tick */ export function watch(change, sources, { root, pre, ...options } = {}) { const logic = useEffect(change, sources, options); if (root) $effect.root(logic); else if (pre) $effect.pre(logic); else $effect(logic); } /** * Watch for changes in the sources and run the logic. * * Logic will run inside of the tracked scope unless `options.tracked` is explicitly false. * * If change returns a callback, it will run: * * immediately before the effect re-runs * * when the component is destroyed * @see https://svelte.dev/docs/svelte/$effect * * @param change - logic to run when sources change * @param sources - getter function including tracked dependencies * @param options - watch options */ export function effect(change, sources, options = {}) { return watch(change, sources, { tracked: true, ...options }); } /** * Watch for differences between two getters output and run the logic if they change. * @param outer - getter function to watch * @param inner - getter function to watch * @param input - logic to run when outer changes (only if different from inner) * @param output - logic to run when inner changes (only if different from outer) * @param options - watch options */ export const doubleBind = ({ outer, inner, input, output, }, options) => { watch(() => { if (outer() === inner()) return; return input(); }, outer, options); watch(() => { if (outer() === inner()) return; return output(); }, inner, options); };