stickyScrollBar.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _typeof = require("@babel/runtime/helpers/typeof");
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = void 0;
  8. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  9. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  10. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  11. var _context = require("@rc-component/context");
  12. var _classnames = _interopRequireDefault(require("classnames"));
  13. var _addEventListener = _interopRequireDefault(require("rc-util/lib/Dom/addEventListener"));
  14. var _getScrollBarSize = _interopRequireDefault(require("rc-util/lib/getScrollBarSize"));
  15. var React = _interopRequireWildcard(require("react"));
  16. var _TableContext = _interopRequireDefault(require("./context/TableContext"));
  17. var _useFrame = require("./hooks/useFrame");
  18. var _raf = _interopRequireDefault(require("rc-util/lib/raf"));
  19. var _offsetUtil = require("./utils/offsetUtil");
  20. var _findDOMNode = require("rc-util/lib/Dom/findDOMNode");
  21. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
  22. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  23. var StickyScrollBar = function StickyScrollBar(_ref, ref) {
  24. var _scrollBodyRef$curren, _scrollBodyRef$curren2;
  25. var scrollBodyRef = _ref.scrollBodyRef,
  26. onScroll = _ref.onScroll,
  27. offsetScroll = _ref.offsetScroll,
  28. container = _ref.container,
  29. direction = _ref.direction;
  30. var prefixCls = (0, _context.useContext)(_TableContext.default, 'prefixCls');
  31. var bodyScrollWidth = ((_scrollBodyRef$curren = scrollBodyRef.current) === null || _scrollBodyRef$curren === void 0 ? void 0 : _scrollBodyRef$curren.scrollWidth) || 0;
  32. var bodyWidth = ((_scrollBodyRef$curren2 = scrollBodyRef.current) === null || _scrollBodyRef$curren2 === void 0 ? void 0 : _scrollBodyRef$curren2.clientWidth) || 0;
  33. var scrollBarWidth = bodyScrollWidth && bodyWidth * (bodyWidth / bodyScrollWidth);
  34. var scrollBarRef = React.useRef();
  35. var _useLayoutState = (0, _useFrame.useLayoutState)({
  36. scrollLeft: 0,
  37. isHiddenScrollBar: true
  38. }),
  39. _useLayoutState2 = (0, _slicedToArray2.default)(_useLayoutState, 2),
  40. scrollState = _useLayoutState2[0],
  41. setScrollState = _useLayoutState2[1];
  42. var refState = React.useRef({
  43. delta: 0,
  44. x: 0
  45. });
  46. var _React$useState = React.useState(false),
  47. _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
  48. isActive = _React$useState2[0],
  49. setActive = _React$useState2[1];
  50. var rafRef = React.useRef(null);
  51. React.useEffect(function () {
  52. return function () {
  53. _raf.default.cancel(rafRef.current);
  54. };
  55. }, []);
  56. var onMouseUp = function onMouseUp() {
  57. setActive(false);
  58. };
  59. var onMouseDown = function onMouseDown(event) {
  60. event.persist();
  61. refState.current.delta = event.pageX - scrollState.scrollLeft;
  62. refState.current.x = 0;
  63. setActive(true);
  64. event.preventDefault();
  65. };
  66. var onMouseMove = function onMouseMove(event) {
  67. var _window;
  68. // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
  69. var _ref2 = event || ((_window = window) === null || _window === void 0 ? void 0 : _window.event),
  70. buttons = _ref2.buttons;
  71. if (!isActive || buttons === 0) {
  72. // If out body mouse up, we can set isActive false when mouse move
  73. if (isActive) {
  74. setActive(false);
  75. }
  76. return;
  77. }
  78. var left = refState.current.x + event.pageX - refState.current.x - refState.current.delta;
  79. var isRTL = direction === 'rtl';
  80. // Limit scroll range
  81. left = Math.max(isRTL ? scrollBarWidth - bodyWidth : 0, Math.min(isRTL ? 0 : bodyWidth - scrollBarWidth, left));
  82. // Calculate the scroll position and update
  83. var shouldScroll = !isRTL || Math.abs(left) + Math.abs(scrollBarWidth) < bodyWidth;
  84. if (shouldScroll) {
  85. onScroll({
  86. scrollLeft: left / bodyWidth * (bodyScrollWidth + 2)
  87. });
  88. refState.current.x = event.pageX;
  89. }
  90. };
  91. var checkScrollBarVisible = function checkScrollBarVisible() {
  92. _raf.default.cancel(rafRef.current);
  93. rafRef.current = (0, _raf.default)(function () {
  94. if (!scrollBodyRef.current) {
  95. return;
  96. }
  97. var tableOffsetTop = (0, _offsetUtil.getOffset)(scrollBodyRef.current).top;
  98. var tableBottomOffset = tableOffsetTop + scrollBodyRef.current.offsetHeight;
  99. var currentClientOffset = container === window ? document.documentElement.scrollTop + window.innerHeight : (0, _offsetUtil.getOffset)(container).top + container.clientHeight;
  100. setScrollState(function (state) {
  101. return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, state), {}, {
  102. isHiddenScrollBar: tableBottomOffset - (0, _getScrollBarSize.default)() <= currentClientOffset || tableOffsetTop >= currentClientOffset - offsetScroll
  103. });
  104. });
  105. });
  106. };
  107. var setScrollLeft = function setScrollLeft(left) {
  108. setScrollState(function (state) {
  109. return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, state), {}, {
  110. scrollLeft: bodyScrollWidth ? left / bodyScrollWidth * bodyWidth : 0
  111. });
  112. });
  113. };
  114. React.useImperativeHandle(ref, function () {
  115. return {
  116. setScrollLeft: setScrollLeft,
  117. checkScrollBarVisible: checkScrollBarVisible
  118. };
  119. });
  120. React.useEffect(function () {
  121. var onMouseUpListener = (0, _addEventListener.default)(document.body, 'mouseup', onMouseUp, false);
  122. var onMouseMoveListener = (0, _addEventListener.default)(document.body, 'mousemove', onMouseMove, false);
  123. checkScrollBarVisible();
  124. return function () {
  125. onMouseUpListener.remove();
  126. onMouseMoveListener.remove();
  127. };
  128. }, [scrollBarWidth, isActive]);
  129. // Loop for scroll event check
  130. React.useEffect(function () {
  131. if (!scrollBodyRef.current) return;
  132. var scrollParents = [];
  133. var parent = (0, _findDOMNode.getDOM)(scrollBodyRef.current);
  134. while (parent) {
  135. scrollParents.push(parent);
  136. parent = parent.parentElement;
  137. }
  138. scrollParents.forEach(function (p) {
  139. return p.addEventListener('scroll', checkScrollBarVisible, false);
  140. });
  141. window.addEventListener('resize', checkScrollBarVisible, false);
  142. window.addEventListener('scroll', checkScrollBarVisible, false);
  143. container.addEventListener('scroll', checkScrollBarVisible, false);
  144. return function () {
  145. scrollParents.forEach(function (p) {
  146. return p.removeEventListener('scroll', checkScrollBarVisible);
  147. });
  148. window.removeEventListener('resize', checkScrollBarVisible);
  149. window.removeEventListener('scroll', checkScrollBarVisible);
  150. container.removeEventListener('scroll', checkScrollBarVisible);
  151. };
  152. }, [container]);
  153. React.useEffect(function () {
  154. if (!scrollState.isHiddenScrollBar) {
  155. setScrollState(function (state) {
  156. var bodyNode = scrollBodyRef.current;
  157. if (!bodyNode) {
  158. return state;
  159. }
  160. return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, state), {}, {
  161. scrollLeft: bodyNode.scrollLeft / bodyNode.scrollWidth * bodyNode.clientWidth
  162. });
  163. });
  164. }
  165. }, [scrollState.isHiddenScrollBar]);
  166. if (bodyScrollWidth <= bodyWidth || !scrollBarWidth || scrollState.isHiddenScrollBar) {
  167. return null;
  168. }
  169. return /*#__PURE__*/React.createElement("div", {
  170. style: {
  171. height: (0, _getScrollBarSize.default)(),
  172. width: bodyWidth,
  173. bottom: offsetScroll
  174. },
  175. className: "".concat(prefixCls, "-sticky-scroll")
  176. }, /*#__PURE__*/React.createElement("div", {
  177. onMouseDown: onMouseDown,
  178. ref: scrollBarRef,
  179. className: (0, _classnames.default)("".concat(prefixCls, "-sticky-scroll-bar"), (0, _defineProperty2.default)({}, "".concat(prefixCls, "-sticky-scroll-bar-active"), isActive)),
  180. style: {
  181. width: "".concat(scrollBarWidth, "px"),
  182. transform: "translate3d(".concat(scrollState.scrollLeft, "px, 0, 0)")
  183. }
  184. }));
  185. };
  186. var _default = exports.default = /*#__PURE__*/React.forwardRef(StickyScrollBar);