SideEffect.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.RemoveScrollSideCar = exports.getDeltaXY = exports.getTouchXY = void 0;
  4. var tslib_1 = require("tslib");
  5. var React = tslib_1.__importStar(require("react"));
  6. var react_remove_scroll_bar_1 = require("react-remove-scroll-bar");
  7. var react_style_singleton_1 = require("react-style-singleton");
  8. var aggresiveCapture_1 = require("./aggresiveCapture");
  9. var handleScroll_1 = require("./handleScroll");
  10. var getTouchXY = function (event) {
  11. return 'changedTouches' in event ? [event.changedTouches[0].clientX, event.changedTouches[0].clientY] : [0, 0];
  12. };
  13. exports.getTouchXY = getTouchXY;
  14. var getDeltaXY = function (event) { return [event.deltaX, event.deltaY]; };
  15. exports.getDeltaXY = getDeltaXY;
  16. var extractRef = function (ref) {
  17. return ref && 'current' in ref ? ref.current : ref;
  18. };
  19. var deltaCompare = function (x, y) { return x[0] === y[0] && x[1] === y[1]; };
  20. var generateStyle = function (id) { return "\n .block-interactivity-".concat(id, " {pointer-events: none;}\n .allow-interactivity-").concat(id, " {pointer-events: all;}\n"); };
  21. var idCounter = 0;
  22. var lockStack = [];
  23. function RemoveScrollSideCar(props) {
  24. var shouldPreventQueue = React.useRef([]);
  25. var touchStartRef = React.useRef([0, 0]);
  26. var activeAxis = React.useRef();
  27. var id = React.useState(idCounter++)[0];
  28. var Style = React.useState(function () { return (0, react_style_singleton_1.styleSingleton)(); })[0];
  29. var lastProps = React.useRef(props);
  30. React.useEffect(function () {
  31. lastProps.current = props;
  32. }, [props]);
  33. React.useEffect(function () {
  34. if (props.inert) {
  35. document.body.classList.add("block-interactivity-".concat(id));
  36. var allow_1 = tslib_1.__spreadArray([props.lockRef.current], (props.shards || []).map(extractRef), true).filter(Boolean);
  37. allow_1.forEach(function (el) { return el.classList.add("allow-interactivity-".concat(id)); });
  38. return function () {
  39. document.body.classList.remove("block-interactivity-".concat(id));
  40. allow_1.forEach(function (el) { return el.classList.remove("allow-interactivity-".concat(id)); });
  41. };
  42. }
  43. return;
  44. }, [props.inert, props.lockRef.current, props.shards]);
  45. var shouldCancelEvent = React.useCallback(function (event, parent) {
  46. if ('touches' in event && event.touches.length === 2) {
  47. return !lastProps.current.allowPinchZoom;
  48. }
  49. var touch = (0, exports.getTouchXY)(event);
  50. var touchStart = touchStartRef.current;
  51. var deltaX = 'deltaX' in event ? event.deltaX : touchStart[0] - touch[0];
  52. var deltaY = 'deltaY' in event ? event.deltaY : touchStart[1] - touch[1];
  53. var currentAxis;
  54. var target = event.target;
  55. var moveDirection = Math.abs(deltaX) > Math.abs(deltaY) ? 'h' : 'v';
  56. // allow horizontal touch move on Range inputs. They will not cause any scroll
  57. if ('touches' in event && moveDirection === 'h' && target.type === 'range') {
  58. return false;
  59. }
  60. var canBeScrolledInMainDirection = (0, handleScroll_1.locationCouldBeScrolled)(moveDirection, target);
  61. if (!canBeScrolledInMainDirection) {
  62. return true;
  63. }
  64. if (canBeScrolledInMainDirection) {
  65. currentAxis = moveDirection;
  66. }
  67. else {
  68. currentAxis = moveDirection === 'v' ? 'h' : 'v';
  69. canBeScrolledInMainDirection = (0, handleScroll_1.locationCouldBeScrolled)(moveDirection, target);
  70. // other axis might be not scrollable
  71. }
  72. if (!canBeScrolledInMainDirection) {
  73. return false;
  74. }
  75. if (!activeAxis.current && 'changedTouches' in event && (deltaX || deltaY)) {
  76. activeAxis.current = currentAxis;
  77. }
  78. if (!currentAxis) {
  79. return true;
  80. }
  81. var cancelingAxis = activeAxis.current || currentAxis;
  82. return (0, handleScroll_1.handleScroll)(cancelingAxis, parent, event, cancelingAxis === 'h' ? deltaX : deltaY, true);
  83. }, []);
  84. var shouldPrevent = React.useCallback(function (_event) {
  85. var event = _event;
  86. if (!lockStack.length || lockStack[lockStack.length - 1] !== Style) {
  87. // not the last active
  88. return;
  89. }
  90. var delta = 'deltaY' in event ? (0, exports.getDeltaXY)(event) : (0, exports.getTouchXY)(event);
  91. var sourceEvent = shouldPreventQueue.current.filter(function (e) { return e.name === event.type && e.target === event.target && deltaCompare(e.delta, delta); })[0];
  92. // self event, and should be canceled
  93. if (sourceEvent && sourceEvent.should) {
  94. if (event.cancelable) {
  95. event.preventDefault();
  96. }
  97. return;
  98. }
  99. // outside or shard event
  100. if (!sourceEvent) {
  101. var shardNodes = (lastProps.current.shards || [])
  102. .map(extractRef)
  103. .filter(Boolean)
  104. .filter(function (node) { return node.contains(event.target); });
  105. var shouldStop = shardNodes.length > 0 ? shouldCancelEvent(event, shardNodes[0]) : !lastProps.current.noIsolation;
  106. if (shouldStop) {
  107. if (event.cancelable) {
  108. event.preventDefault();
  109. }
  110. }
  111. }
  112. }, []);
  113. var shouldCancel = React.useCallback(function (name, delta, target, should) {
  114. var event = { name: name, delta: delta, target: target, should: should };
  115. shouldPreventQueue.current.push(event);
  116. setTimeout(function () {
  117. shouldPreventQueue.current = shouldPreventQueue.current.filter(function (e) { return e !== event; });
  118. }, 1);
  119. }, []);
  120. var scrollTouchStart = React.useCallback(function (event) {
  121. touchStartRef.current = (0, exports.getTouchXY)(event);
  122. activeAxis.current = undefined;
  123. }, []);
  124. var scrollWheel = React.useCallback(function (event) {
  125. shouldCancel(event.type, (0, exports.getDeltaXY)(event), event.target, shouldCancelEvent(event, props.lockRef.current));
  126. }, []);
  127. var scrollTouchMove = React.useCallback(function (event) {
  128. shouldCancel(event.type, (0, exports.getTouchXY)(event), event.target, shouldCancelEvent(event, props.lockRef.current));
  129. }, []);
  130. React.useEffect(function () {
  131. lockStack.push(Style);
  132. props.setCallbacks({
  133. onScrollCapture: scrollWheel,
  134. onWheelCapture: scrollWheel,
  135. onTouchMoveCapture: scrollTouchMove,
  136. });
  137. document.addEventListener('wheel', shouldPrevent, aggresiveCapture_1.nonPassive);
  138. document.addEventListener('touchmove', shouldPrevent, aggresiveCapture_1.nonPassive);
  139. document.addEventListener('touchstart', scrollTouchStart, aggresiveCapture_1.nonPassive);
  140. return function () {
  141. lockStack = lockStack.filter(function (inst) { return inst !== Style; });
  142. document.removeEventListener('wheel', shouldPrevent, aggresiveCapture_1.nonPassive);
  143. document.removeEventListener('touchmove', shouldPrevent, aggresiveCapture_1.nonPassive);
  144. document.removeEventListener('touchstart', scrollTouchStart, aggresiveCapture_1.nonPassive);
  145. };
  146. }, []);
  147. var removeScrollBar = props.removeScrollBar, inert = props.inert;
  148. return (React.createElement(React.Fragment, null,
  149. inert ? React.createElement(Style, { styles: generateStyle(id) }) : null,
  150. removeScrollBar ? React.createElement(react_remove_scroll_bar_1.RemoveScrollBar, { gapMode: "margin" }) : null));
  151. }
  152. exports.RemoveScrollSideCar = RemoveScrollSideCar;