overlayscrollbars-svelte
Version:
OverlayScrollbars for Svelte.
85 lines (84 loc) • 2.88 kB
JavaScript
import { untrack } from 'svelte';
import { OverlayScrollbars } from 'overlayscrollbars';
const createDefer = () => {
/* c8 ignore start */
if (typeof window === 'undefined') {
// mock ssr calls with "noop"
const noop = () => { };
return [noop, noop];
}
/* c8 ignore end */
let idleId;
let rafId;
const wnd = window;
const idleSupported = typeof wnd.requestIdleCallback === 'function';
const rAF = wnd.requestAnimationFrame;
const cAF = wnd.cancelAnimationFrame;
const rIdle = idleSupported ? wnd.requestIdleCallback : rAF;
const cIdle = idleSupported ? wnd.cancelIdleCallback : cAF;
const clear = () => {
cIdle(idleId);
cAF(rafId);
};
return [
(callback, options) => {
clear();
idleId = rIdle(idleSupported
? () => {
clear();
// inside idle its best practice to use rAF to change DOM for best performance
rafId = rAF(callback);
}
: callback, typeof options === 'object' ? options : { timeout: 2233 });
},
clear,
];
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isAccessor = (obj) => typeof obj === 'function';
const unwrapAccessor = (obj) => (isAccessor(obj) ? obj() : obj);
export const useOverlayScrollbars = (params) => {
let instance = null;
const [requestDefer, clearDefer] = createDefer();
const unwrappedParams = unwrapAccessor(params || {});
const options = $derived(unwrapAccessor(unwrappedParams.options));
const events = $derived(unwrapAccessor(unwrappedParams.events));
const defer = $derived(unwrapAccessor(unwrappedParams.defer));
$effect.pre(() => {
const currOptions = options;
if (OverlayScrollbars.valid(instance)) {
instance.options(currOptions || {}, true);
}
});
$effect.pre(() => {
const currEvents = events;
if (OverlayScrollbars.valid(instance)) {
instance.on(currEvents || {}, true);
}
});
$effect(() => {
return () => {
clearDefer();
instance?.destroy();
};
});
return [
(target) => {
// if already initialized do nothing
if (OverlayScrollbars.valid(instance)) {
return instance;
}
const currOptions = untrack(() => options);
const currEvents = untrack(() => events);
const currDefer = untrack(() => defer);
const init = () => (instance = OverlayScrollbars(target, currOptions || {}, currEvents || {}));
if (currDefer) {
requestDefer(init, currDefer);
}
else {
init();
}
},
() => instance,
];
};