ScrollBar.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
  3. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  4. import classNames from 'classnames';
  5. import raf from "rc-util/es/raf";
  6. import * as React from 'react';
  7. import { getPageXY } from "./hooks/useScrollDrag";
  8. var ScrollBar = /*#__PURE__*/React.forwardRef(function (props, ref) {
  9. var prefixCls = props.prefixCls,
  10. rtl = props.rtl,
  11. scrollOffset = props.scrollOffset,
  12. scrollRange = props.scrollRange,
  13. onStartMove = props.onStartMove,
  14. onStopMove = props.onStopMove,
  15. onScroll = props.onScroll,
  16. horizontal = props.horizontal,
  17. spinSize = props.spinSize,
  18. containerSize = props.containerSize,
  19. style = props.style,
  20. propsThumbStyle = props.thumbStyle,
  21. showScrollBar = props.showScrollBar;
  22. var _React$useState = React.useState(false),
  23. _React$useState2 = _slicedToArray(_React$useState, 2),
  24. dragging = _React$useState2[0],
  25. setDragging = _React$useState2[1];
  26. var _React$useState3 = React.useState(null),
  27. _React$useState4 = _slicedToArray(_React$useState3, 2),
  28. pageXY = _React$useState4[0],
  29. setPageXY = _React$useState4[1];
  30. var _React$useState5 = React.useState(null),
  31. _React$useState6 = _slicedToArray(_React$useState5, 2),
  32. startTop = _React$useState6[0],
  33. setStartTop = _React$useState6[1];
  34. var isLTR = !rtl;
  35. // ========================= Refs =========================
  36. var scrollbarRef = React.useRef();
  37. var thumbRef = React.useRef();
  38. // ======================= Visible ========================
  39. var _React$useState7 = React.useState(showScrollBar),
  40. _React$useState8 = _slicedToArray(_React$useState7, 2),
  41. visible = _React$useState8[0],
  42. setVisible = _React$useState8[1];
  43. var visibleTimeoutRef = React.useRef();
  44. var delayHidden = function delayHidden() {
  45. if (showScrollBar === true || showScrollBar === false) return;
  46. clearTimeout(visibleTimeoutRef.current);
  47. setVisible(true);
  48. visibleTimeoutRef.current = setTimeout(function () {
  49. setVisible(false);
  50. }, 3000);
  51. };
  52. // ======================== Range =========================
  53. var enableScrollRange = scrollRange - containerSize || 0;
  54. var enableOffsetRange = containerSize - spinSize || 0;
  55. // ========================= Top ==========================
  56. var top = React.useMemo(function () {
  57. if (scrollOffset === 0 || enableScrollRange === 0) {
  58. return 0;
  59. }
  60. var ptg = scrollOffset / enableScrollRange;
  61. return ptg * enableOffsetRange;
  62. }, [scrollOffset, enableScrollRange, enableOffsetRange]);
  63. // ====================== Container =======================
  64. var onContainerMouseDown = function onContainerMouseDown(e) {
  65. e.stopPropagation();
  66. e.preventDefault();
  67. };
  68. // ======================== Thumb =========================
  69. var stateRef = React.useRef({
  70. top: top,
  71. dragging: dragging,
  72. pageY: pageXY,
  73. startTop: startTop
  74. });
  75. stateRef.current = {
  76. top: top,
  77. dragging: dragging,
  78. pageY: pageXY,
  79. startTop: startTop
  80. };
  81. var onThumbMouseDown = function onThumbMouseDown(e) {
  82. setDragging(true);
  83. setPageXY(getPageXY(e, horizontal));
  84. setStartTop(stateRef.current.top);
  85. onStartMove();
  86. e.stopPropagation();
  87. e.preventDefault();
  88. };
  89. // ======================== Effect ========================
  90. // React make event as passive, but we need to preventDefault
  91. // Add event on dom directly instead.
  92. // ref: https://github.com/facebook/react/issues/9809
  93. React.useEffect(function () {
  94. var onScrollbarTouchStart = function onScrollbarTouchStart(e) {
  95. e.preventDefault();
  96. };
  97. var scrollbarEle = scrollbarRef.current;
  98. var thumbEle = thumbRef.current;
  99. scrollbarEle.addEventListener('touchstart', onScrollbarTouchStart, {
  100. passive: false
  101. });
  102. thumbEle.addEventListener('touchstart', onThumbMouseDown, {
  103. passive: false
  104. });
  105. return function () {
  106. scrollbarEle.removeEventListener('touchstart', onScrollbarTouchStart);
  107. thumbEle.removeEventListener('touchstart', onThumbMouseDown);
  108. };
  109. }, []);
  110. // Pass to effect
  111. var enableScrollRangeRef = React.useRef();
  112. enableScrollRangeRef.current = enableScrollRange;
  113. var enableOffsetRangeRef = React.useRef();
  114. enableOffsetRangeRef.current = enableOffsetRange;
  115. React.useEffect(function () {
  116. if (dragging) {
  117. var moveRafId;
  118. var onMouseMove = function onMouseMove(e) {
  119. var _stateRef$current = stateRef.current,
  120. stateDragging = _stateRef$current.dragging,
  121. statePageY = _stateRef$current.pageY,
  122. stateStartTop = _stateRef$current.startTop;
  123. raf.cancel(moveRafId);
  124. var rect = scrollbarRef.current.getBoundingClientRect();
  125. var scale = containerSize / (horizontal ? rect.width : rect.height);
  126. if (stateDragging) {
  127. var offset = (getPageXY(e, horizontal) - statePageY) * scale;
  128. var newTop = stateStartTop;
  129. if (!isLTR && horizontal) {
  130. newTop -= offset;
  131. } else {
  132. newTop += offset;
  133. }
  134. var tmpEnableScrollRange = enableScrollRangeRef.current;
  135. var tmpEnableOffsetRange = enableOffsetRangeRef.current;
  136. var ptg = tmpEnableOffsetRange ? newTop / tmpEnableOffsetRange : 0;
  137. var newScrollTop = Math.ceil(ptg * tmpEnableScrollRange);
  138. newScrollTop = Math.max(newScrollTop, 0);
  139. newScrollTop = Math.min(newScrollTop, tmpEnableScrollRange);
  140. moveRafId = raf(function () {
  141. onScroll(newScrollTop, horizontal);
  142. });
  143. }
  144. };
  145. var onMouseUp = function onMouseUp() {
  146. setDragging(false);
  147. onStopMove();
  148. };
  149. window.addEventListener('mousemove', onMouseMove, {
  150. passive: true
  151. });
  152. window.addEventListener('touchmove', onMouseMove, {
  153. passive: true
  154. });
  155. window.addEventListener('mouseup', onMouseUp, {
  156. passive: true
  157. });
  158. window.addEventListener('touchend', onMouseUp, {
  159. passive: true
  160. });
  161. return function () {
  162. window.removeEventListener('mousemove', onMouseMove);
  163. window.removeEventListener('touchmove', onMouseMove);
  164. window.removeEventListener('mouseup', onMouseUp);
  165. window.removeEventListener('touchend', onMouseUp);
  166. raf.cancel(moveRafId);
  167. };
  168. }
  169. }, [dragging]);
  170. React.useEffect(function () {
  171. delayHidden();
  172. return function () {
  173. clearTimeout(visibleTimeoutRef.current);
  174. };
  175. }, [scrollOffset]);
  176. // ====================== Imperative ======================
  177. React.useImperativeHandle(ref, function () {
  178. return {
  179. delayHidden: delayHidden
  180. };
  181. });
  182. // ======================== Render ========================
  183. var scrollbarPrefixCls = "".concat(prefixCls, "-scrollbar");
  184. var containerStyle = {
  185. position: 'absolute',
  186. visibility: visible ? null : 'hidden'
  187. };
  188. var thumbStyle = {
  189. position: 'absolute',
  190. borderRadius: 99,
  191. background: 'var(--rc-virtual-list-scrollbar-bg, rgba(0, 0, 0, 0.5))',
  192. cursor: 'pointer',
  193. userSelect: 'none'
  194. };
  195. if (horizontal) {
  196. Object.assign(containerStyle, {
  197. height: 8,
  198. left: 0,
  199. right: 0,
  200. bottom: 0
  201. });
  202. Object.assign(thumbStyle, _defineProperty({
  203. height: '100%',
  204. width: spinSize
  205. }, isLTR ? 'left' : 'right', top));
  206. } else {
  207. Object.assign(containerStyle, _defineProperty({
  208. width: 8,
  209. top: 0,
  210. bottom: 0
  211. }, isLTR ? 'right' : 'left', 0));
  212. Object.assign(thumbStyle, {
  213. width: '100%',
  214. height: spinSize,
  215. top: top
  216. });
  217. }
  218. return /*#__PURE__*/React.createElement("div", {
  219. ref: scrollbarRef,
  220. className: classNames(scrollbarPrefixCls, _defineProperty(_defineProperty(_defineProperty({}, "".concat(scrollbarPrefixCls, "-horizontal"), horizontal), "".concat(scrollbarPrefixCls, "-vertical"), !horizontal), "".concat(scrollbarPrefixCls, "-visible"), visible)),
  221. style: _objectSpread(_objectSpread({}, containerStyle), style),
  222. onMouseDown: onContainerMouseDown,
  223. onMouseMove: delayHidden
  224. }, /*#__PURE__*/React.createElement("div", {
  225. ref: thumbRef,
  226. className: classNames("".concat(scrollbarPrefixCls, "-thumb"), _defineProperty({}, "".concat(scrollbarPrefixCls, "-thumb-moving"), dragging)),
  227. style: _objectSpread(_objectSpread({}, thumbStyle), propsThumbStyle),
  228. onMouseDown: onThumbMouseDown
  229. }));
  230. });
  231. if (process.env.NODE_ENV !== 'production') {
  232. ScrollBar.displayName = 'ScrollBar';
  233. }
  234. export default ScrollBar;