UNPKG

@kiwicom/orbit-components

Version:

Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com’s products.

275 lines (216 loc) 8.88 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.enableBodyScroll = exports.clearAllBodyScrollLocks = exports.disableBodyScroll = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); /* eslint-disable no-param-reassign */ /** * body-scroll-lock library adjusted to fix an issue with scrolling being enabled regardless * of the number of locks, which causes scrolling to be enabled after a nested Popover is closed * * https://github.com/willmcpo/body-scroll-lock/issues/235 */ // Older browsers don't support event options, feature detect it. var hasPassiveEvents = false; if (typeof window !== "undefined") { var passiveTestOptions = { get passive() { hasPassiveEvents = true; return undefined; } }; window.addEventListener("testPassive", null, passiveTestOptions); window.removeEventListener("testPassive", null, passiveTestOptions); } var isIosDevice = typeof window !== "undefined" && window.navigator && window.navigator.platform && (/iP(ad|hone|od)/.test(window.navigator.platform) || window.navigator.platform === "MacIntel" && window.navigator.maxTouchPoints > 1); var locks = []; var documentListenerAdded = false; var initialClientY = -1; var previousBodyOverflowSetting; var previousBodyPosition; var previousBodyPaddingRight; var preventDefault = function preventDefault(rawEvent) { var e = rawEvent || window.event; // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom). if (e.touches.length > 1) return true; if (e.preventDefault) e.preventDefault(); return false; }; var setOverflowHidden = function setOverflowHidden() { if (!document.body || !document.documentElement) return; // If previousBodyPaddingRight is already set, don't set it again. if (previousBodyPaddingRight === undefined) { var scrollBarGap = window.innerWidth - document.documentElement.clientWidth; if (scrollBarGap > 0) { var computedBodyPaddingRight = parseInt(window.getComputedStyle(document.body).getPropertyValue("padding-right"), 10); if (document.body) { previousBodyPaddingRight = document.body.style.paddingRight; document.body.style.paddingRight = "".concat(computedBodyPaddingRight + scrollBarGap, "px"); } } } // If previousBodyOverflowSetting is already set, don't set it again. if (previousBodyOverflowSetting === undefined) { previousBodyOverflowSetting = document.body.style.overflow; document.body.style.overflow = "hidden"; } }; var restoreOverflowSetting = function restoreOverflowSetting() { if (!document.body) return; if (previousBodyPaddingRight !== undefined) { document.body.style.paddingRight = previousBodyPaddingRight; // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it // can be set again. previousBodyPaddingRight = undefined; } if (previousBodyOverflowSetting !== undefined) { document.body.style.overflow = previousBodyOverflowSetting; // Restore previousBodyOverflowSetting to undefined // so setOverflowHidden knows it can be set again. previousBodyOverflowSetting = undefined; } }; var setPositionFixed = function setPositionFixed() { return window.requestAnimationFrame(function () { if (!document.body) return; // If previousBodyPosition is already set, don't set it again. if (previousBodyPosition === undefined) { previousBodyPosition = { position: document.body.style.position, top: document.body.style.top, left: document.body.style.left, right: document.body.style.right }; // Update the dom inside an animation frame var _window = window, scrollY = _window.scrollY, scrollX = _window.scrollX, innerHeight = _window.innerHeight; document.body.style.position = "fixed"; document.body.style.top = "".concat(-scrollY, "px"); document.body.style.left = "".concat(-scrollX, "px"); // avoid a bug on iOS Safari where body doesn't take up full width document.body.style.right = "0px"; setTimeout(function () { return window.requestAnimationFrame(function () { if (!document.body) return; // Attempt to check if the bottom bar appeared due to the position change var bottomBarHeight = innerHeight - window.innerHeight; if (bottomBarHeight && scrollY >= innerHeight) { // Move the content further up so that the bottom bar doesn't hide it document.body.style.top = -(scrollY + bottomBarHeight); } }); }, 300); } }); }; var restorePositionSetting = function restorePositionSetting() { if (!document.body) return; if (previousBodyPosition) { var _document$body$style = document.body.style, top = _document$body$style.top, left = _document$body$style.left; // Restore styles document.body.style.position = previousBodyPosition.position; document.body.style.top = previousBodyPosition.top; document.body.style.left = previousBodyPosition.left; document.body.style.right = previousBodyPosition.right; // Convert the position from "px" to Int var y = -parseInt(top, 10); var x = -parseInt(left, 10); // Restore scroll window.scrollTo(x, y); previousBodyPosition = undefined; } }; // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions var isTargetElementTotallyScrolled = function isTargetElementTotallyScrolled(targetElement) { return !!targetElement && targetElement.scrollHeight - targetElement.scrollTop <= targetElement.clientHeight; }; var handleScroll = function handleScroll(event, targetElement) { var clientY = event.targetTouches[0].clientY - initialClientY; if (targetElement && targetElement.scrollTop === 0 && clientY > 0) { // element is at the top of its scroll. return preventDefault(event); } if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) { // element is at the bottom of its scroll. return preventDefault(event); } event.stopPropagation(); return true; }; var disableBodyScroll = function disableBodyScroll(targetElement) { // disableBodyScroll must not have been called on this targetElement before if (locks.some(function (lock) { return lock === targetElement; })) { return; } var lock = targetElement; locks = [].concat((0, _toConsumableArray2.default)(locks), [lock]); if (isIosDevice) { setPositionFixed(); } else { setOverflowHidden(); } if (isIosDevice) { // $FlowExpectedError targetElement.ontouchstart = function (event) { if (event.targetTouches.length === 1) { // detect single touch. initialClientY = event.targetTouches[0].clientY; } }; // $FlowExpectedError targetElement.ontouchmove = function (event) { if (event.targetTouches.length === 1) { // detect single touch. handleScroll(event, targetElement); } }; if (!documentListenerAdded) { document.addEventListener("touchmove", preventDefault, hasPassiveEvents ? { passive: false } : undefined); documentListenerAdded = true; } } }; exports.disableBodyScroll = disableBodyScroll; var clearAllBodyScrollLocks = function clearAllBodyScrollLocks() { if (isIosDevice) { // Clear all locks ontouchstart/ontouchmove handlers, and the references. locks.forEach(function (lock) { // $FlowExpectedError lock.ontouchstart = null; // $FlowExpectedError lock.ontouchmove = null; }); if (documentListenerAdded) { document.removeEventListener("touchmove", preventDefault, hasPassiveEvents ? { passive: false } : undefined); documentListenerAdded = false; } // Reset initial clientY. initialClientY = -1; } if (isIosDevice) { restorePositionSetting(); } else { restoreOverflowSetting(); } locks = []; }; exports.clearAllBodyScrollLocks = clearAllBodyScrollLocks; var enableBodyScroll = function enableBodyScroll(targetElement) { locks = locks.filter(function (lock) { return lock !== targetElement; }); if (isIosDevice) { targetElement.ontouchstart = null; targetElement.ontouchmove = null; if (documentListenerAdded && locks.length === 0) { document.removeEventListener("touchmove", preventDefault, hasPassiveEvents ? { passive: false } : undefined); documentListenerAdded = false; } } if (locks.length === 0) { if (isIosDevice) { restorePositionSetting(); } else { restoreOverflowSetting(); } } }; exports.enableBodyScroll = enableBodyScroll;