svelte
Version:
Cybernetically enhanced web apps
67 lines (56 loc) • 1.76 kB
JavaScript
import { effect, render_effect, teardown } from '../../../reactivity/effects.js';
import { listen, without_reactive_context } from './shared.js';
/**
* @param {'x' | 'y'} type
* @param {() => number} get
* @param {(value: number) => void} set
* @returns {void}
*/
export function bind_window_scroll(type, get, set = get) {
var is_scrolling_x = type === 'x';
var target_handler = () =>
without_reactive_context(() => {
scrolling = true;
clearTimeout(timeout);
timeout = setTimeout(clear, 100); // TODO use scrollend event if supported (or when supported everywhere?)
set(window[is_scrolling_x ? 'scrollX' : 'scrollY']);
});
addEventListener('scroll', target_handler, {
passive: true
});
var scrolling = false;
/** @type {ReturnType<typeof setTimeout>} */
var timeout;
var clear = () => {
scrolling = false;
};
var first = true;
render_effect(() => {
var latest_value = get();
// Don't scroll to the initial value for accessibility reasons
if (first) {
first = false;
} else if (!scrolling && latest_value != null) {
scrolling = true;
clearTimeout(timeout);
if (is_scrolling_x) {
scrollTo(latest_value, window.scrollY);
} else {
scrollTo(window.scrollX, latest_value);
}
timeout = setTimeout(clear, 100);
}
});
// Browsers don't fire the scroll event for the initial scroll position when scroll style isn't set to smooth
effect(target_handler);
teardown(() => {
removeEventListener('scroll', target_handler);
});
}
/**
* @param {'innerWidth' | 'innerHeight' | 'outerWidth' | 'outerHeight'} type
* @param {(size: number) => void} set
*/
export function bind_window_size(type, set) {
listen(window, ['resize'], () => without_reactive_context(() => set(window[type])));
}