54 lines
1.1 KiB
TypeScript
54 lines
1.1 KiB
TypeScript
|
|
type RevealOptions = {
|
||
|
|
delay?: number;
|
||
|
|
distance?: number;
|
||
|
|
threshold?: number;
|
||
|
|
};
|
||
|
|
|
||
|
|
const defaultOptions: Required<RevealOptions> = {
|
||
|
|
delay: 0,
|
||
|
|
distance: 24,
|
||
|
|
threshold: 0.18
|
||
|
|
};
|
||
|
|
|
||
|
|
export function reveal(node: HTMLElement, options: RevealOptions = {}) {
|
||
|
|
const settings = { ...defaultOptions, ...options };
|
||
|
|
const media = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||
|
|
|
||
|
|
if (media.matches) {
|
||
|
|
node.classList.add('reveal-visible');
|
||
|
|
return {
|
||
|
|
destroy() {}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
node.style.setProperty('--reveal-delay', `${settings.delay}ms`);
|
||
|
|
node.style.setProperty('--reveal-distance', `${settings.distance}px`);
|
||
|
|
node.classList.add('reveal-ready');
|
||
|
|
|
||
|
|
const observer = new IntersectionObserver(
|
||
|
|
(entries) => {
|
||
|
|
for (const entry of entries) {
|
||
|
|
if (!entry.isIntersecting) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
node.classList.add('reveal-visible');
|
||
|
|
observer.disconnect();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
},
|
||
|
|
{
|
||
|
|
threshold: settings.threshold,
|
||
|
|
rootMargin: '0px 0px -8% 0px'
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
observer.observe(node);
|
||
|
|
|
||
|
|
return {
|
||
|
|
destroy() {
|
||
|
|
observer.disconnect();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|