@dvcol/svelte-utils
Version:
Svelte library for common utility functions and constants
102 lines (101 loc) • 3.43 kB
JavaScript
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);
};