UNPKG

@melt-ui/svelte

Version:
77 lines (76 loc) 3 kB
// Modified from @zag-js/remove-scroll v0.10.2 (2023-06-10) // Source: https://github.com/chakra-ui/zag // https://github.com/chakra-ui/zag/blob/main/packages/utilities/remove-scroll/src/index.ts import { noop } from './callbacks.js'; import { isIos } from './platform.js'; const LOCK_CLASSNAME = 'data-melt-scroll-lock'; function assignStyle(el, style) { if (!el) return; const previousStyle = el.style.cssText; Object.assign(el.style, style); return () => { el.style.cssText = previousStyle; }; } function setCSSProperty(el, property, value) { if (!el) return; const previousValue = el.style.getPropertyValue(property); el.style.setProperty(property, value); return () => { if (previousValue) { el.style.setProperty(property, previousValue); } else { el.style.removeProperty(property); } }; } function getPaddingProperty(documentElement) { // RTL <body> scrollbar const documentLeft = documentElement.getBoundingClientRect().left; const scrollbarX = Math.round(documentLeft) + documentElement.scrollLeft; return scrollbarX ? 'paddingLeft' : 'paddingRight'; } export function removeScroll(_document) { const doc = _document ?? document; const win = doc.defaultView ?? window; const { documentElement, body } = doc; const locked = body.hasAttribute(LOCK_CLASSNAME); if (locked) return noop; body.setAttribute(LOCK_CLASSNAME, ''); const scrollbarWidth = win.innerWidth - documentElement.clientWidth; const setScrollbarWidthProperty = () => setCSSProperty(documentElement, '--scrollbar-width', `${scrollbarWidth}px`); const paddingProperty = getPaddingProperty(documentElement); const scrollbarSidePadding = win.getComputedStyle(body)[paddingProperty]; const setStyle = () => assignStyle(body, { overflow: 'hidden', [paddingProperty]: `calc(${scrollbarSidePadding} + ${scrollbarWidth}px)`, }); // Only iOS doesn't respect `overflow: hidden` on document.body const setIOSStyle = () => { const { scrollX, scrollY, visualViewport } = win; // iOS 12 does not support `visuaViewport`. const offsetLeft = visualViewport?.offsetLeft ?? 0; const offsetTop = visualViewport?.offsetTop ?? 0; const restoreStyle = assignStyle(body, { position: 'fixed', overflow: 'hidden', top: `${-(scrollY - Math.floor(offsetTop))}px`, left: `${-(scrollX - Math.floor(offsetLeft))}px`, right: '0', [paddingProperty]: `calc(${scrollbarSidePadding} + ${scrollbarWidth}px)`, }); return () => { restoreStyle?.(); win.scrollTo(scrollX, scrollY); }; }; const cleanups = [setScrollbarWidthProperty(), isIos() ? setIOSStyle() : setStyle()]; return () => { cleanups.forEach((fn) => fn?.()); body.removeAttribute(LOCK_CLASSNAME); }; }