UNPKG

7.91 kBJavaScriptView Raw
1import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
2import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
3import * as React from 'react';
4import classNames from 'classnames';
5import raf from "rc-util/es/raf";
6function getPageXY(e, horizontal) {
7 var obj = 'touches' in e ? e.touches[0] : e;
8 return obj[horizontal ? 'pageX' : 'pageY'];
9}
10var ScrollBar = /*#__PURE__*/React.forwardRef(function (props, ref) {
11 var _classNames;
12 var prefixCls = props.prefixCls,
13 rtl = props.rtl,
14 scrollOffset = props.scrollOffset,
15 scrollRange = props.scrollRange,
16 onStartMove = props.onStartMove,
17 onStopMove = props.onStopMove,
18 onScroll = props.onScroll,
19 horizontal = props.horizontal,
20 spinSize = props.spinSize,
21 containerSize = props.containerSize;
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(false),
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 clearTimeout(visibleTimeoutRef.current);
46 setVisible(true);
47 visibleTimeoutRef.current = setTimeout(function () {
48 setVisible(false);
49 }, 3000);
50 };
51 // ======================== Range =========================
52 var enableScrollRange = scrollRange - containerSize || 0;
53 var enableOffsetRange = containerSize - spinSize || 0;
54 // `scrollWidth` < `clientWidth` means no need to show scrollbar
55 var canScroll = enableScrollRange > 0;
56 // ========================= Top ==========================
57 var top = React.useMemo(function () {
58 if (scrollOffset === 0 || enableScrollRange === 0) {
59 return 0;
60 }
61 var ptg = scrollOffset / enableScrollRange;
62 return ptg * enableOffsetRange;
63 }, [scrollOffset, enableScrollRange, enableOffsetRange]);
64 // ====================== Container =======================
65 var onContainerMouseDown = function onContainerMouseDown(e) {
66 e.stopPropagation();
67 e.preventDefault();
68 };
69 // ======================== Thumb =========================
70 var stateRef = React.useRef({
71 top: top,
72 dragging: dragging,
73 pageY: pageXY,
74 startTop: startTop
75 });
76 stateRef.current = {
77 top: top,
78 dragging: dragging,
79 pageY: pageXY,
80 startTop: startTop
81 };
82 var onThumbMouseDown = function onThumbMouseDown(e) {
83 setDragging(true);
84 setPageXY(getPageXY(e, horizontal));
85 setStartTop(stateRef.current.top);
86 onStartMove();
87 e.stopPropagation();
88 e.preventDefault();
89 };
90 // ======================== Effect ========================
91 // React make event as passive, but we need to preventDefault
92 // Add event on dom directly instead.
93 // ref: https://github.com/facebook/react/issues/9809
94 React.useEffect(function () {
95 var onScrollbarTouchStart = function onScrollbarTouchStart(e) {
96 e.preventDefault();
97 };
98 var scrollbarEle = scrollbarRef.current;
99 var thumbEle = thumbRef.current;
100 scrollbarEle.addEventListener('touchstart', onScrollbarTouchStart);
101 thumbEle.addEventListener('touchstart', onThumbMouseDown);
102 return function () {
103 scrollbarEle.removeEventListener('touchstart', onScrollbarTouchStart);
104 thumbEle.removeEventListener('touchstart', onThumbMouseDown);
105 };
106 }, []);
107 React.useEffect(function () {
108 if (dragging) {
109 var moveRafId;
110 var onMouseMove = function onMouseMove(e) {
111 var _stateRef$current = stateRef.current,
112 stateDragging = _stateRef$current.dragging,
113 statePageY = _stateRef$current.pageY,
114 stateStartTop = _stateRef$current.startTop;
115 raf.cancel(moveRafId);
116 if (stateDragging) {
117 var offset = getPageXY(e, horizontal) - statePageY;
118 var newTop = stateStartTop;
119 if (!isLTR && horizontal) {
120 newTop -= offset;
121 } else {
122 newTop += offset;
123 }
124 var ptg = enableOffsetRange ? newTop / enableOffsetRange : 0;
125 var newScrollTop = Math.ceil(ptg * enableScrollRange);
126 newScrollTop = Math.max(newScrollTop, 0);
127 newScrollTop = Math.min(newScrollTop, enableScrollRange);
128 moveRafId = raf(function () {
129 onScroll(newScrollTop, horizontal);
130 });
131 }
132 };
133 var onMouseUp = function onMouseUp() {
134 setDragging(false);
135 onStopMove();
136 };
137 window.addEventListener('mousemove', onMouseMove);
138 window.addEventListener('touchmove', onMouseMove);
139 window.addEventListener('mouseup', onMouseUp);
140 window.addEventListener('touchend', onMouseUp);
141 return function () {
142 window.removeEventListener('mousemove', onMouseMove);
143 window.removeEventListener('touchmove', onMouseMove);
144 window.removeEventListener('mouseup', onMouseUp);
145 window.removeEventListener('touchend', onMouseUp);
146 raf.cancel(moveRafId);
147 };
148 }
149 }, [dragging]);
150 React.useEffect(function () {
151 delayHidden();
152 }, [scrollOffset]);
153 // ====================== Imperative ======================
154 React.useImperativeHandle(ref, function () {
155 return {
156 delayHidden: delayHidden
157 };
158 });
159 // ======================== Render ========================
160 var scrollbarPrefixCls = "".concat(prefixCls, "-scrollbar");
161 var containerStyle = {
162 position: 'absolute',
163 visibility: visible && canScroll ? null : 'hidden'
164 };
165 var thumbStyle = {
166 position: 'absolute',
167 background: 'rgba(0, 0, 0, 0.5)',
168 borderRadius: 99,
169 cursor: 'pointer',
170 userSelect: 'none'
171 };
172 if (horizontal) {
173 // Container
174 containerStyle.height = 8;
175 containerStyle.left = 0;
176 containerStyle.right = 0;
177 containerStyle.bottom = 0;
178 // Thumb
179 thumbStyle.height = '100%';
180 thumbStyle.width = spinSize;
181 if (isLTR) {
182 thumbStyle.left = top;
183 } else {
184 thumbStyle.right = top;
185 }
186 } else {
187 // Container
188 containerStyle.width = 8;
189 containerStyle.top = 0;
190 containerStyle.bottom = 0;
191 if (isLTR) {
192 containerStyle.right = 0;
193 } else {
194 containerStyle.left = 0;
195 }
196 // Thumb
197 thumbStyle.width = '100%';
198 thumbStyle.height = spinSize;
199 thumbStyle.top = top;
200 }
201 return /*#__PURE__*/React.createElement("div", {
202 ref: scrollbarRef,
203 className: classNames(scrollbarPrefixCls, (_classNames = {}, _defineProperty(_classNames, "".concat(scrollbarPrefixCls, "-horizontal"), horizontal), _defineProperty(_classNames, "".concat(scrollbarPrefixCls, "-vertical"), !horizontal), _defineProperty(_classNames, "".concat(scrollbarPrefixCls, "-visible"), visible), _classNames)),
204 style: containerStyle,
205 onMouseDown: onContainerMouseDown,
206 onMouseMove: delayHidden
207 }, /*#__PURE__*/React.createElement("div", {
208 ref: thumbRef,
209 className: classNames("".concat(scrollbarPrefixCls, "-thumb"), _defineProperty({}, "".concat(scrollbarPrefixCls, "-thumb-moving"), dragging)),
210 style: thumbStyle,
211 onMouseDown: onThumbMouseDown
212 }));
213});
214if (process.env.NODE_ENV !== 'production') {
215 ScrollBar.displayName = 'ScrollBar';
216}
217export default ScrollBar;
\No newline at end of file