@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
JavaScript
;
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;