UNPKG

svelte-ux

Version:

- Increment version in `package.json` and commit as `Version bump to x.y.z` - `npm run publish`

166 lines (165 loc) 7.84 kB
import { scrollIntoView as scrollIntoViewUtil } from '../utils/dom'; export function scrollIntoView(node, options) { function update(options) { var _a; if (typeof options.condition === 'boolean' ? options.condition : options.condition(node)) { setTimeout(() => { scrollIntoViewUtil(node); }, (_a = options.delay) !== null && _a !== void 0 ? _a : 0); } } if (options.initial !== false) { update(options); } return { update }; } export function scrollShadow(node, options) { const defaultOptions = { offset: 10, blur: 6, spread: -7, color: 'rgba(0,0,0,0.2)', scrollRatio: 5, }; const resolvedOptions = { top: { ...defaultOptions, ...options === null || options === void 0 ? void 0 : options.top, }, bottom: { ...defaultOptions, ...options === null || options === void 0 ? void 0 : options.bottom, }, left: { ...defaultOptions, ...options === null || options === void 0 ? void 0 : options.left, }, right: { ...defaultOptions, ...options === null || options === void 0 ? void 0 : options.right, }, }; function onScroll(e) { var _a; const { clientWidth, clientHeight, scrollWidth, scrollHeight, scrollTop, scrollLeft } = (_a = e.currentTarget) !== null && _a !== void 0 ? _a : e.target; const verticalScrollPercent = scrollTop / (scrollHeight - clientHeight); const horizontalScrollPercent = scrollLeft / (scrollWidth - clientWidth); const shadows = []; // Top shadow if (verticalScrollPercent > 0) { let { offset, blur, spread, color, scrollRatio } = resolvedOptions.top; offset = Math.min(scrollTop / scrollRatio, offset); shadows.push(`inset 0px ${offset}px ${blur}px ${spread}px ${color}`); } // Bottom shadow if (verticalScrollPercent < 1) { let { offset, blur, spread, color, scrollRatio } = resolvedOptions.bottom; offset = Math.min((scrollHeight - clientHeight - scrollTop) / scrollRatio, offset); shadows.push(`inset 0px -${offset}px ${blur}px ${spread}px ${color}`); } // Left shadow if (horizontalScrollPercent > 0) { let { offset, blur, spread, color, scrollRatio } = resolvedOptions.left; offset = Math.min(scrollLeft / scrollRatio, offset); shadows.push(`inset ${offset}px 0px ${blur}px ${spread}px ${color}`); } // Right shadow if (horizontalScrollPercent < 1) { let { offset, blur, spread, color, scrollRatio } = resolvedOptions.right; offset = Math.min((scrollWidth - clientWidth - scrollLeft) / scrollRatio, offset); shadows.push(`inset -${offset}px 0px ${blur}px ${spread}px ${color}`); } node.style.setProperty('--shadow', shadows.join(', ')); // Apply box-shadow to after pseudo element so it's rendered on top of content node.classList.add('relative', 'overflow-auto', 'after:block', 'after:h-full', 'after:w-full', 'after:sticky', 'after:top-0', 'after:left-0', 'after:mt-[-9999px]', 'after:pointer-events-none', 'after:[box-shadow:var(--shadow)]'); } node.addEventListener('scroll', onScroll, { passive: true }); // Update if transitions are used (ex. children with `animate:flip`) node.addEventListener('transitionend', onScroll); node.addEventListener('animationend', onScroll); // Update when node resized (and on initial mount) let resizeObserver = new ResizeObserver((entries, observer) => { onScroll({ target: node }); }); resizeObserver.observe(node); let mutationObserver = new MutationObserver((entries, observer) => { onScroll({ target: node }); }); mutationObserver.observe(node, { childList: true, subtree: true /*attributes: true, */ }); // TODO: Attributes without filter cause browser to lock up return { destroy() { node.removeEventListener('scroll', onScroll); node.removeEventListener('transitionend', onScroll); node.removeEventListener('animationend', onScroll); resizeObserver.disconnect(); mutationObserver.disconnect(); }, }; } export function scrollFade(node, options) { var _a, _b; const length = (_a = options === null || options === void 0 ? void 0 : options.length) !== null && _a !== void 0 ? _a : 50; const scrollRatio = (_b = options === null || options === void 0 ? void 0 : options.scrollRatio) !== null && _b !== void 0 ? _b : 5; function onScroll(e) { var _a; const { clientWidth, clientHeight, scrollWidth, scrollHeight, scrollTop, scrollLeft } = (_a = e.currentTarget) !== null && _a !== void 0 ? _a : e.target; const verticalScrollPercent = scrollTop / (scrollHeight - clientHeight); const horizontalScrollPercent = scrollLeft / (scrollWidth - clientWidth); let gradient = null; if (scrollHeight != clientHeight) { // Vertically scrollable const gradients = []; if (verticalScrollPercent > 0) { // Top fade const topLength = Math.min(scrollTop / scrollRatio, length); gradients.push(`rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) ${topLength}px`); } // Bottom fade if (verticalScrollPercent < 1) { const bottomLength = Math.min((scrollHeight - clientHeight - scrollTop) / scrollRatio, length); gradients.push(`rgba(0, 0, 0, 1) calc(100% - ${bottomLength}px), rgba(0, 0, 0, 0)`); } gradient = `linear-gradient(to bottom, ${gradients.join(',')})`; } else if (scrollWidth !== clientWidth) { // Horizontally scrollable const gradients = []; if (horizontalScrollPercent > 0) { // Left fade const leftLength = Math.min(scrollLeft / scrollRatio, length); gradients.push(`rgba(0, 0, 0, 0), rgba(0, 0, 0, 1) ${leftLength}px`); } // Right fade if (horizontalScrollPercent < 1) { const rightLength = Math.min((scrollWidth - clientWidth - scrollLeft) / scrollRatio, length); gradients.push(`rgba(0, 0, 0, 1) calc(100% - ${rightLength}px), rgba(0, 0, 0, 0)`); } gradient = `linear-gradient(to right, ${gradients.join(',')})`; } node.style.webkitMaskImage = gradient; node.style.maskImage = gradient; } node.classList.add('overflow-auto'); node.addEventListener('scroll', onScroll, { passive: true }); // Update if transitions are used (ex. children with `animate:flip`) node.addEventListener('transitionend', onScroll); node.addEventListener('animationend', onScroll); // Update when node resized (and on initial mount) let resizeObserver = new ResizeObserver((entries, observer) => { onScroll({ target: node }); }); resizeObserver.observe(node); let mutationObserver = new MutationObserver((entries, observer) => { onScroll({ target: node }); }); mutationObserver.observe(node, { childList: true, subtree: true /*attributes: true, */ }); // TODO: Attributes without filter cause browser to lock up return { destroy() { node.removeEventListener('scroll', onScroll); node.removeEventListener('transitionend', onScroll); node.removeEventListener('animationend', onScroll); resizeObserver.disconnect(); mutationObserver.disconnect(); }, }; }