@os-design/use-auto-scroll 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +31 -59
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +21 -34
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -4,22 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.getScrollableElements = exports["default"] = void 0;
|
|
7
|
-
|
|
8
|
-
var _react = require("react");
|
|
9
|
-
|
|
10
7
|
var _useCursorPosition = _interopRequireDefault(require("@os-design/use-cursor-position"));
|
|
11
|
-
|
|
8
|
+
var _react = require("react");
|
|
12
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
13
|
-
|
|
14
10
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
15
|
-
|
|
16
11
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
17
|
-
|
|
18
12
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
19
|
-
|
|
20
13
|
var FPS = 60;
|
|
21
14
|
var FRAME_TIMEOUT = 1000 / FPS;
|
|
22
|
-
|
|
23
15
|
var getProps = function getProps(props) {
|
|
24
16
|
return {
|
|
25
17
|
enabled: props.enabled !== undefined ? props.enabled : true,
|
|
@@ -27,7 +19,6 @@ var getProps = function getProps(props) {
|
|
|
27
19
|
maxSpeedPx: 100
|
|
28
20
|
};
|
|
29
21
|
};
|
|
30
|
-
|
|
31
22
|
var getRect = function getRect(el) {
|
|
32
23
|
if (el === document.body) {
|
|
33
24
|
return {
|
|
@@ -37,7 +28,6 @@ var getRect = function getRect(el) {
|
|
|
37
28
|
height: window.innerHeight
|
|
38
29
|
};
|
|
39
30
|
}
|
|
40
|
-
|
|
41
31
|
var rect = el.getBoundingClientRect();
|
|
42
32
|
return {
|
|
43
33
|
x: rect.x,
|
|
@@ -46,45 +36,37 @@ var getRect = function getRect(el) {
|
|
|
46
36
|
height: rect.height
|
|
47
37
|
};
|
|
48
38
|
};
|
|
39
|
+
|
|
49
40
|
/**
|
|
50
41
|
* Detects whether the element is scrollable.
|
|
51
42
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
54
43
|
var isScrollable = function isScrollable(el) {
|
|
55
44
|
var style = getComputedStyle(el);
|
|
56
|
-
|
|
57
45
|
if (el !== document.body && !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
58
46
|
return false;
|
|
59
47
|
}
|
|
60
|
-
|
|
61
48
|
var _getRect = getRect(el),
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
width = _getRect.width,
|
|
50
|
+
height = _getRect.height;
|
|
65
51
|
return el.scrollWidth > width || el.scrollHeight > height;
|
|
66
52
|
};
|
|
53
|
+
|
|
67
54
|
/**
|
|
68
55
|
* Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.
|
|
69
56
|
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
57
|
var getScrollableElements = function getScrollableElements(x, y) {
|
|
73
58
|
var elementsFromPoint = document.elementsFromPoint(x, y);
|
|
74
|
-
var elements = [];
|
|
75
|
-
|
|
59
|
+
var elements = [];
|
|
60
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
76
61
|
var _iterator = _createForOfIteratorHelper(elementsFromPoint),
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
_step;
|
|
79
63
|
try {
|
|
80
64
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
81
65
|
var element = _step.value;
|
|
82
66
|
var el = element === document.documentElement ? document.body : element;
|
|
83
|
-
|
|
84
67
|
if (isScrollable(el)) {
|
|
85
68
|
elements.push(el);
|
|
86
69
|
}
|
|
87
|
-
|
|
88
70
|
if (el === document.body) break;
|
|
89
71
|
}
|
|
90
72
|
} catch (err) {
|
|
@@ -92,12 +74,9 @@ var getScrollableElements = function getScrollableElements(x, y) {
|
|
|
92
74
|
} finally {
|
|
93
75
|
_iterator.f();
|
|
94
76
|
}
|
|
95
|
-
|
|
96
77
|
return elements;
|
|
97
78
|
};
|
|
98
|
-
|
|
99
79
|
exports.getScrollableElements = getScrollableElements;
|
|
100
|
-
|
|
101
80
|
var getScrollOffset = function getScrollOffset(el) {
|
|
102
81
|
if (el === document.body) {
|
|
103
82
|
return {
|
|
@@ -105,13 +84,11 @@ var getScrollOffset = function getScrollOffset(el) {
|
|
|
105
84
|
scrollTop: window.scrollY
|
|
106
85
|
};
|
|
107
86
|
}
|
|
108
|
-
|
|
109
87
|
return {
|
|
110
88
|
scrollLeft: el.scrollLeft,
|
|
111
89
|
scrollTop: el.scrollTop
|
|
112
90
|
};
|
|
113
91
|
};
|
|
114
|
-
|
|
115
92
|
var useAutoScroll = function useAutoScroll() {
|
|
116
93
|
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
117
94
|
var cursorPosition = (0, _useCursorPosition["default"])();
|
|
@@ -119,41 +96,45 @@ var useAutoScroll = function useAutoScroll() {
|
|
|
119
96
|
var propsRef = (0, _react.useRef)(getProps(props));
|
|
120
97
|
var isScrollingRef = (0, _react.useRef)(false);
|
|
121
98
|
var frameRef = (0, _react.useRef)();
|
|
122
|
-
var timeoutRef = (0, _react.useRef)();
|
|
99
|
+
var timeoutRef = (0, _react.useRef)();
|
|
123
100
|
|
|
101
|
+
// Update the ref to the cursor position if it changes
|
|
124
102
|
(0, _react.useEffect)(function () {
|
|
125
103
|
cursorPositionRef.current = cursorPosition;
|
|
126
|
-
}, [cursorPosition]);
|
|
104
|
+
}, [cursorPosition]);
|
|
127
105
|
|
|
106
|
+
// Update the props if it changes
|
|
128
107
|
(0, _react.useEffect)(function () {
|
|
129
108
|
propsRef.current = getProps(props);
|
|
130
|
-
}, [props]);
|
|
109
|
+
}, [props]);
|
|
131
110
|
|
|
111
|
+
// Cancel the animation frame request and clear the timeout if the component was unmounted
|
|
132
112
|
(0, _react.useEffect)(function () {
|
|
133
113
|
return function () {
|
|
134
114
|
if (frameRef.current) window.cancelAnimationFrame(frameRef.current);
|
|
135
115
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
136
116
|
};
|
|
137
|
-
}, []);
|
|
117
|
+
}, []);
|
|
138
118
|
|
|
119
|
+
// Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)
|
|
139
120
|
var getMaxDist = (0, _react.useCallback)(function (el, axis) {
|
|
140
121
|
var distPercent = propsRef.current.distPercent;
|
|
141
|
-
|
|
142
122
|
var _getRect2 = getRect(el),
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
123
|
+
width = _getRect2.width,
|
|
124
|
+
height = _getRect2.height;
|
|
146
125
|
var size = axis === 'x' ? width : height;
|
|
147
126
|
return Math.round(size * distPercent / 100);
|
|
148
|
-
}, []);
|
|
127
|
+
}, []);
|
|
149
128
|
|
|
129
|
+
// Returns the distance by which the scroll position should be changed
|
|
150
130
|
var getScrollStep = (0, _react.useCallback)(function (dist, maxDist) {
|
|
151
131
|
if (dist < 0 || dist > maxDist) return 0;
|
|
152
132
|
var maxSpeedPx = propsRef.current.maxSpeedPx;
|
|
153
133
|
var divisor = maxDist / Math.log(maxSpeedPx);
|
|
154
134
|
return Math.round(Math.exp((maxDist - dist) / divisor));
|
|
155
|
-
}, []);
|
|
135
|
+
}, []);
|
|
156
136
|
|
|
137
|
+
// Scrolls the element to the specified position
|
|
157
138
|
var scrollTo = (0, _react.useCallback)(function (element, options) {
|
|
158
139
|
frameRef.current = window.requestAnimationFrame(function () {
|
|
159
140
|
var el = element === document.body ? window : element;
|
|
@@ -163,29 +144,25 @@ var useAutoScroll = function useAutoScroll() {
|
|
|
163
144
|
var scroll = (0, _react.useCallback)(function () {
|
|
164
145
|
var enabled = propsRef.current.enabled;
|
|
165
146
|
var _cursorPositionRef$cu = cursorPositionRef.current,
|
|
166
|
-
|
|
167
|
-
|
|
147
|
+
x = _cursorPositionRef$cu.x,
|
|
148
|
+
y = _cursorPositionRef$cu.y;
|
|
168
149
|
var scrollableElements = getScrollableElements(x, y).reverse();
|
|
169
|
-
|
|
170
150
|
if (!enabled) {
|
|
171
151
|
isScrollingRef.current = false;
|
|
172
152
|
return;
|
|
173
153
|
}
|
|
154
|
+
isScrollingRef.current = true;
|
|
174
155
|
|
|
175
|
-
|
|
176
|
-
|
|
156
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
177
157
|
var _iterator2 = _createForOfIteratorHelper(scrollableElements),
|
|
178
|
-
|
|
179
|
-
|
|
158
|
+
_step2;
|
|
180
159
|
try {
|
|
181
160
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
182
161
|
var el = _step2.value;
|
|
183
162
|
var rect = getRect(el);
|
|
184
|
-
|
|
185
163
|
var _getScrollOffset = getScrollOffset(el),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
164
|
+
scrollLeft = _getScrollOffset.scrollLeft,
|
|
165
|
+
scrollTop = _getScrollOffset.scrollTop;
|
|
189
166
|
var xMaxDist = getMaxDist(el, 'x');
|
|
190
167
|
var yMaxDist = getMaxDist(el, 'y');
|
|
191
168
|
var leftDist = x - rect.x;
|
|
@@ -201,21 +178,17 @@ var useAutoScroll = function useAutoScroll() {
|
|
|
201
178
|
var canScrollRight = el.scrollWidth - scrollLeft > rect.width;
|
|
202
179
|
var canScrollBottom = el.scrollHeight - scrollTop > rect.height;
|
|
203
180
|
var left = scrollLeft;
|
|
204
|
-
|
|
205
181
|
if (canScrollLeft && leftScrollStep > 0) {
|
|
206
182
|
left = Math.max(scrollLeft - leftScrollStep, 0);
|
|
207
183
|
} else if (canScrollRight && rightScrollStep > 0) {
|
|
208
184
|
left = Math.min(scrollLeft + rightScrollStep, el.scrollWidth - rect.width);
|
|
209
185
|
}
|
|
210
|
-
|
|
211
186
|
var top = scrollTop;
|
|
212
|
-
|
|
213
187
|
if (canScrollTop && topScrollStep > 0) {
|
|
214
188
|
top = Math.max(scrollTop - topScrollStep, 0);
|
|
215
189
|
} else if (canScrollBottom && bottomScrollStep > 0) {
|
|
216
190
|
top = Math.min(scrollTop + bottomScrollStep, el.scrollHeight - rect.height);
|
|
217
191
|
}
|
|
218
|
-
|
|
219
192
|
if (left !== scrollLeft || top !== scrollTop) {
|
|
220
193
|
scrollTo(el, {
|
|
221
194
|
left: left,
|
|
@@ -230,15 +203,14 @@ var useAutoScroll = function useAutoScroll() {
|
|
|
230
203
|
} finally {
|
|
231
204
|
_iterator2.f();
|
|
232
205
|
}
|
|
233
|
-
|
|
234
206
|
isScrollingRef.current = false;
|
|
235
|
-
}, [getMaxDist, getScrollStep, scrollTo]);
|
|
207
|
+
}, [getMaxDist, getScrollStep, scrollTo]);
|
|
236
208
|
|
|
209
|
+
// Start auto scrolling when the cursor position changes only if it is not already running
|
|
237
210
|
(0, _react.useEffect)(function () {
|
|
238
211
|
if (!isScrollingRef.current && props.enabled) scroll();
|
|
239
212
|
}, [scroll, cursorPosition, props.enabled]);
|
|
240
213
|
};
|
|
241
|
-
|
|
242
214
|
var _default = useAutoScroll;
|
|
243
215
|
exports["default"] = _default;
|
|
244
216
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["FPS","FRAME_TIMEOUT","getProps","props","enabled","undefined","distPercent","maxSpeedPx","getRect","el","document","body","x","y","width","window","innerWidth","height","innerHeight","rect","getBoundingClientRect","isScrollable","style","getComputedStyle","test","overflow","overflowY","overflowX","scrollWidth","scrollHeight","getScrollableElements","elementsFromPoint","elements","element","documentElement","push","getScrollOffset","scrollLeft","scrollX","scrollTop","scrollY","useAutoScroll","cursorPosition","useCursorPosition","cursorPositionRef","useRef","propsRef","isScrollingRef","frameRef","timeoutRef","useEffect","current","cancelAnimationFrame","clearTimeout","getMaxDist","useCallback","axis","size","Math","round","getScrollStep","dist","maxDist","divisor","log","exp","scrollTo","options","requestAnimationFrame","scroll","scrollableElements","reverse","xMaxDist","yMaxDist","leftDist","topDist","rightDist","bottomDist","leftScrollStep","topScrollStep","rightScrollStep","bottomScrollStep","canScrollLeft","canScrollTop","canScrollRight","canScrollBottom","left","max","min","top","setTimeout"],"sources":["../../src/index.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport useCursorPosition from '@os-design/use-cursor-position';\n\nconst FPS = 60;\nconst FRAME_TIMEOUT = 1000 / FPS;\n\nexport interface UseAutoScrollProps {\n /**\n * Whether the auto scroll is enabled.\n * @default true\n */\n enabled?: boolean;\n /**\n * The distance to the border at which the container starts to scroll automatically (in percent).\n * @default 20\n */\n distPercent?: number;\n /**\n * The max auto scroll speed (in px).\n * @default 100\n */\n maxSpeedPx?: number;\n}\n\nconst getProps = (props: UseAutoScrollProps): Required<UseAutoScrollProps> => ({\n enabled: props.enabled !== undefined ? props.enabled : true,\n distPercent: 20,\n maxSpeedPx: 100,\n});\n\nconst getRect = (el: Element) => {\n if (el === document.body) {\n return {\n x: 0,\n y: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n }\n const rect = el.getBoundingClientRect();\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Detects whether the element is scrollable.\n */\nconst isScrollable = (el: Element) => {\n const style = getComputedStyle(el);\n if (\n el !== document.body &&\n !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n return false;\n }\n const { width, height } = getRect(el);\n return el.scrollWidth > width || el.scrollHeight > height;\n};\n\n/**\n * Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.\n */\nexport const getScrollableElements = (x: number, y: number): Element[] => {\n const elementsFromPoint = document.elementsFromPoint(x, y);\n const elements: Element[] = [];\n // eslint-disable-next-line no-restricted-syntax\n for (const element of elementsFromPoint) {\n const el = element === document.documentElement ? document.body : element;\n if (isScrollable(el)) {\n elements.push(el);\n }\n if (el === document.body) break;\n }\n return elements;\n};\n\nconst getScrollOffset = (el: Element) => {\n if (el === document.body) {\n return {\n scrollLeft: window.scrollX,\n scrollTop: window.scrollY,\n };\n }\n return {\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop,\n };\n};\n\nconst useAutoScroll = (props: UseAutoScrollProps = {}) => {\n const cursorPosition = useCursorPosition();\n const cursorPositionRef = useRef(cursorPosition);\n const propsRef = useRef<Required<UseAutoScrollProps>>(getProps(props));\n const isScrollingRef = useRef(false);\n const frameRef = useRef<number>();\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n // Update the ref to the cursor position if it changes\n useEffect(() => {\n cursorPositionRef.current = cursorPosition;\n }, [cursorPosition]);\n\n // Update the props if it changes\n useEffect(() => {\n propsRef.current = getProps(props);\n }, [props]);\n\n // Cancel the animation frame request and clear the timeout if the component was unmounted\n useEffect(\n () => () => {\n if (frameRef.current) window.cancelAnimationFrame(frameRef.current);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n },\n []\n );\n\n // Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)\n const getMaxDist = useCallback((el: Element, axis: 'x' | 'y') => {\n const { distPercent } = propsRef.current;\n const { width, height } = getRect(el);\n const size = axis === 'x' ? width : height;\n return Math.round((size * distPercent) / 100);\n }, []);\n\n // Returns the distance by which the scroll position should be changed\n const getScrollStep = useCallback((dist: number, maxDist: number) => {\n if (dist < 0 || dist > maxDist) return 0;\n const { maxSpeedPx } = propsRef.current;\n const divisor = maxDist / Math.log(maxSpeedPx);\n return Math.round(Math.exp((maxDist - dist) / divisor));\n }, []);\n\n // Scrolls the element to the specified position\n const scrollTo = useCallback((element: Element, options: ScrollToOptions) => {\n frameRef.current = window.requestAnimationFrame(() => {\n const el = element === document.body ? window : element;\n el.scrollTo(options);\n });\n }, []);\n\n const scroll = useCallback(() => {\n const { enabled } = propsRef.current;\n const { x, y } = cursorPositionRef.current;\n const scrollableElements = getScrollableElements(x, y).reverse();\n\n if (!enabled) {\n isScrollingRef.current = false;\n return;\n }\n\n isScrollingRef.current = true;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const el of scrollableElements) {\n const rect = getRect(el);\n const { scrollLeft, scrollTop } = getScrollOffset(el);\n\n const xMaxDist = getMaxDist(el, 'x');\n const yMaxDist = getMaxDist(el, 'y');\n\n const leftDist = x - rect.x;\n const topDist = y - rect.y;\n const rightDist = rect.x + rect.width - x;\n const bottomDist = rect.y + rect.height - y;\n\n const leftScrollStep = getScrollStep(leftDist, xMaxDist);\n const topScrollStep = getScrollStep(topDist, yMaxDist);\n const rightScrollStep = getScrollStep(rightDist, xMaxDist);\n const bottomScrollStep = getScrollStep(bottomDist, yMaxDist);\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollTop = scrollTop > 0;\n const canScrollRight = el.scrollWidth - scrollLeft > rect.width;\n const canScrollBottom = el.scrollHeight - scrollTop > rect.height;\n\n let left = scrollLeft;\n if (canScrollLeft && leftScrollStep > 0) {\n left = Math.max(scrollLeft - leftScrollStep, 0);\n } else if (canScrollRight && rightScrollStep > 0) {\n left = Math.min(\n scrollLeft + rightScrollStep,\n el.scrollWidth - rect.width\n );\n }\n\n let top = scrollTop;\n if (canScrollTop && topScrollStep > 0) {\n top = Math.max(scrollTop - topScrollStep, 0);\n } else if (canScrollBottom && bottomScrollStep > 0) {\n top = Math.min(\n scrollTop + bottomScrollStep,\n el.scrollHeight - rect.height\n );\n }\n\n if (left !== scrollLeft || top !== scrollTop) {\n scrollTo(el, { left, top });\n timeoutRef.current = setTimeout(scroll, FRAME_TIMEOUT);\n return;\n }\n }\n\n isScrollingRef.current = false;\n }, [getMaxDist, getScrollStep, scrollTo]);\n\n // Start auto scrolling when the cursor position changes only if it is not already running\n useEffect(() => {\n if (!isScrollingRef.current && props.enabled) scroll();\n }, [scroll, cursorPosition, props.enabled]);\n};\n\nexport default useAutoScroll;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["FPS","FRAME_TIMEOUT","getProps","props","enabled","undefined","distPercent","maxSpeedPx","getRect","el","document","body","x","y","width","window","innerWidth","height","innerHeight","rect","getBoundingClientRect","isScrollable","style","getComputedStyle","test","overflow","overflowY","overflowX","scrollWidth","scrollHeight","getScrollableElements","elementsFromPoint","elements","element","documentElement","push","getScrollOffset","scrollLeft","scrollX","scrollTop","scrollY","useAutoScroll","cursorPosition","useCursorPosition","cursorPositionRef","useRef","propsRef","isScrollingRef","frameRef","timeoutRef","useEffect","current","cancelAnimationFrame","clearTimeout","getMaxDist","useCallback","axis","size","Math","round","getScrollStep","dist","maxDist","divisor","log","exp","scrollTo","options","requestAnimationFrame","scroll","scrollableElements","reverse","xMaxDist","yMaxDist","leftDist","topDist","rightDist","bottomDist","leftScrollStep","topScrollStep","rightScrollStep","bottomScrollStep","canScrollLeft","canScrollTop","canScrollRight","canScrollBottom","left","max","min","top","setTimeout"],"sources":["../../src/index.ts"],"sourcesContent":["import useCursorPosition from '@os-design/use-cursor-position';\nimport { useCallback, useEffect, useRef } from 'react';\n\nconst FPS = 60;\nconst FRAME_TIMEOUT = 1000 / FPS;\n\nexport interface UseAutoScrollProps {\n /**\n * Whether the auto scroll is enabled.\n * @default true\n */\n enabled?: boolean;\n /**\n * The distance to the border at which the container starts to scroll automatically (in percent).\n * @default 20\n */\n distPercent?: number;\n /**\n * The max auto scroll speed (in px).\n * @default 100\n */\n maxSpeedPx?: number;\n}\n\nconst getProps = (props: UseAutoScrollProps): Required<UseAutoScrollProps> => ({\n enabled: props.enabled !== undefined ? props.enabled : true,\n distPercent: 20,\n maxSpeedPx: 100,\n});\n\nconst getRect = (el: Element) => {\n if (el === document.body) {\n return {\n x: 0,\n y: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n }\n const rect = el.getBoundingClientRect();\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Detects whether the element is scrollable.\n */\nconst isScrollable = (el: Element) => {\n const style = getComputedStyle(el);\n if (\n el !== document.body &&\n !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n return false;\n }\n const { width, height } = getRect(el);\n return el.scrollWidth > width || el.scrollHeight > height;\n};\n\n/**\n * Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.\n */\nexport const getScrollableElements = (x: number, y: number): Element[] => {\n const elementsFromPoint = document.elementsFromPoint(x, y);\n const elements: Element[] = [];\n // eslint-disable-next-line no-restricted-syntax\n for (const element of elementsFromPoint) {\n const el = element === document.documentElement ? document.body : element;\n if (isScrollable(el)) {\n elements.push(el);\n }\n if (el === document.body) break;\n }\n return elements;\n};\n\nconst getScrollOffset = (el: Element) => {\n if (el === document.body) {\n return {\n scrollLeft: window.scrollX,\n scrollTop: window.scrollY,\n };\n }\n return {\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop,\n };\n};\n\nconst useAutoScroll = (props: UseAutoScrollProps = {}) => {\n const cursorPosition = useCursorPosition();\n const cursorPositionRef = useRef(cursorPosition);\n const propsRef = useRef<Required<UseAutoScrollProps>>(getProps(props));\n const isScrollingRef = useRef(false);\n const frameRef = useRef<number>();\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n // Update the ref to the cursor position if it changes\n useEffect(() => {\n cursorPositionRef.current = cursorPosition;\n }, [cursorPosition]);\n\n // Update the props if it changes\n useEffect(() => {\n propsRef.current = getProps(props);\n }, [props]);\n\n // Cancel the animation frame request and clear the timeout if the component was unmounted\n useEffect(\n () => () => {\n if (frameRef.current) window.cancelAnimationFrame(frameRef.current);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n },\n []\n );\n\n // Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)\n const getMaxDist = useCallback((el: Element, axis: 'x' | 'y') => {\n const { distPercent } = propsRef.current;\n const { width, height } = getRect(el);\n const size = axis === 'x' ? width : height;\n return Math.round((size * distPercent) / 100);\n }, []);\n\n // Returns the distance by which the scroll position should be changed\n const getScrollStep = useCallback((dist: number, maxDist: number) => {\n if (dist < 0 || dist > maxDist) return 0;\n const { maxSpeedPx } = propsRef.current;\n const divisor = maxDist / Math.log(maxSpeedPx);\n return Math.round(Math.exp((maxDist - dist) / divisor));\n }, []);\n\n // Scrolls the element to the specified position\n const scrollTo = useCallback((element: Element, options: ScrollToOptions) => {\n frameRef.current = window.requestAnimationFrame(() => {\n const el = element === document.body ? window : element;\n el.scrollTo(options);\n });\n }, []);\n\n const scroll = useCallback(() => {\n const { enabled } = propsRef.current;\n const { x, y } = cursorPositionRef.current;\n const scrollableElements = getScrollableElements(x, y).reverse();\n\n if (!enabled) {\n isScrollingRef.current = false;\n return;\n }\n\n isScrollingRef.current = true;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const el of scrollableElements) {\n const rect = getRect(el);\n const { scrollLeft, scrollTop } = getScrollOffset(el);\n\n const xMaxDist = getMaxDist(el, 'x');\n const yMaxDist = getMaxDist(el, 'y');\n\n const leftDist = x - rect.x;\n const topDist = y - rect.y;\n const rightDist = rect.x + rect.width - x;\n const bottomDist = rect.y + rect.height - y;\n\n const leftScrollStep = getScrollStep(leftDist, xMaxDist);\n const topScrollStep = getScrollStep(topDist, yMaxDist);\n const rightScrollStep = getScrollStep(rightDist, xMaxDist);\n const bottomScrollStep = getScrollStep(bottomDist, yMaxDist);\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollTop = scrollTop > 0;\n const canScrollRight = el.scrollWidth - scrollLeft > rect.width;\n const canScrollBottom = el.scrollHeight - scrollTop > rect.height;\n\n let left = scrollLeft;\n if (canScrollLeft && leftScrollStep > 0) {\n left = Math.max(scrollLeft - leftScrollStep, 0);\n } else if (canScrollRight && rightScrollStep > 0) {\n left = Math.min(\n scrollLeft + rightScrollStep,\n el.scrollWidth - rect.width\n );\n }\n\n let top = scrollTop;\n if (canScrollTop && topScrollStep > 0) {\n top = Math.max(scrollTop - topScrollStep, 0);\n } else if (canScrollBottom && bottomScrollStep > 0) {\n top = Math.min(\n scrollTop + bottomScrollStep,\n el.scrollHeight - rect.height\n );\n }\n\n if (left !== scrollLeft || top !== scrollTop) {\n scrollTo(el, { left, top });\n timeoutRef.current = setTimeout(scroll, FRAME_TIMEOUT);\n return;\n }\n }\n\n isScrollingRef.current = false;\n }, [getMaxDist, getScrollStep, scrollTo]);\n\n // Start auto scrolling when the cursor position changes only if it is not already running\n useEffect(() => {\n if (!isScrollingRef.current && props.enabled) scroll();\n }, [scroll, cursorPosition, props.enabled]);\n};\n\nexport default useAutoScroll;\n"],"mappings":";;;;;;AAAA;AACA;AAAuD;AAAA;AAAA;AAAA;AAEvD,IAAMA,GAAG,GAAG,EAAE;AACd,IAAMC,aAAa,GAAG,IAAI,GAAGD,GAAG;AAoBhC,IAAME,QAAQ,GAAG,SAAXA,QAAQ,CAAIC,KAAyB;EAAA,OAAoC;IAC7EC,OAAO,EAAED,KAAK,CAACC,OAAO,KAAKC,SAAS,GAAGF,KAAK,CAACC,OAAO,GAAG,IAAI;IAC3DE,WAAW,EAAE,EAAE;IACfC,UAAU,EAAE;EACd,CAAC;AAAA,CAAC;AAEF,IAAMC,OAAO,GAAG,SAAVA,OAAO,CAAIC,EAAW,EAAK;EAC/B,IAAIA,EAAE,KAAKC,QAAQ,CAACC,IAAI,EAAE;IACxB,OAAO;MACLC,CAAC,EAAE,CAAC;MACJC,CAAC,EAAE,CAAC;MACJC,KAAK,EAAEC,MAAM,CAACC,UAAU;MACxBC,MAAM,EAAEF,MAAM,CAACG;IACjB,CAAC;EACH;EACA,IAAMC,IAAI,GAAGV,EAAE,CAACW,qBAAqB,EAAE;EACvC,OAAO;IACLR,CAAC,EAAEO,IAAI,CAACP,CAAC;IACTC,CAAC,EAAEM,IAAI,CAACN,CAAC;IACTC,KAAK,EAAEK,IAAI,CAACL,KAAK;IACjBG,MAAM,EAAEE,IAAI,CAACF;EACf,CAAC;AACH,CAAC;;AAED;AACA;AACA;AACA,IAAMI,YAAY,GAAG,SAAfA,YAAY,CAAIZ,EAAW,EAAK;EACpC,IAAMa,KAAK,GAAGC,gBAAgB,CAACd,EAAE,CAAC;EAClC,IACEA,EAAE,KAAKC,QAAQ,CAACC,IAAI,IACpB,CAAC,eAAe,CAACa,IAAI,CAACF,KAAK,CAACG,QAAQ,GAAGH,KAAK,CAACI,SAAS,GAAGJ,KAAK,CAACK,SAAS,CAAC,EACzE;IACA,OAAO,KAAK;EACd;EACA,eAA0BnB,OAAO,CAACC,EAAE,CAAC;IAA7BK,KAAK,YAALA,KAAK;IAAEG,MAAM,YAANA,MAAM;EACrB,OAAOR,EAAE,CAACmB,WAAW,GAAGd,KAAK,IAAIL,EAAE,CAACoB,YAAY,GAAGZ,MAAM;AAC3D,CAAC;;AAED;AACA;AACA;AACO,IAAMa,qBAAqB,GAAG,SAAxBA,qBAAqB,CAAIlB,CAAS,EAAEC,CAAS,EAAgB;EACxE,IAAMkB,iBAAiB,GAAGrB,QAAQ,CAACqB,iBAAiB,CAACnB,CAAC,EAAEC,CAAC,CAAC;EAC1D,IAAMmB,QAAmB,GAAG,EAAE;EAC9B;EAAA,2CACsBD,iBAAiB;IAAA;EAAA;IAAvC,oDAAyC;MAAA,IAA9BE,OAAO;MAChB,IAAMxB,EAAE,GAAGwB,OAAO,KAAKvB,QAAQ,CAACwB,eAAe,GAAGxB,QAAQ,CAACC,IAAI,GAAGsB,OAAO;MACzE,IAAIZ,YAAY,CAACZ,EAAE,CAAC,EAAE;QACpBuB,QAAQ,CAACG,IAAI,CAAC1B,EAAE,CAAC;MACnB;MACA,IAAIA,EAAE,KAAKC,QAAQ,CAACC,IAAI,EAAE;IAC5B;EAAC;IAAA;EAAA;IAAA;EAAA;EACD,OAAOqB,QAAQ;AACjB,CAAC;AAAC;AAEF,IAAMI,eAAe,GAAG,SAAlBA,eAAe,CAAI3B,EAAW,EAAK;EACvC,IAAIA,EAAE,KAAKC,QAAQ,CAACC,IAAI,EAAE;IACxB,OAAO;MACL0B,UAAU,EAAEtB,MAAM,CAACuB,OAAO;MAC1BC,SAAS,EAAExB,MAAM,CAACyB;IACpB,CAAC;EACH;EACA,OAAO;IACLH,UAAU,EAAE5B,EAAE,CAAC4B,UAAU;IACzBE,SAAS,EAAE9B,EAAE,CAAC8B;EAChB,CAAC;AACH,CAAC;AAED,IAAME,aAAa,GAAG,SAAhBA,aAAa,GAAuC;EAAA,IAAnCtC,KAAyB,uEAAG,CAAC,CAAC;EACnD,IAAMuC,cAAc,GAAG,IAAAC,6BAAiB,GAAE;EAC1C,IAAMC,iBAAiB,GAAG,IAAAC,aAAM,EAACH,cAAc,CAAC;EAChD,IAAMI,QAAQ,GAAG,IAAAD,aAAM,EAA+B3C,QAAQ,CAACC,KAAK,CAAC,CAAC;EACtE,IAAM4C,cAAc,GAAG,IAAAF,aAAM,EAAC,KAAK,CAAC;EACpC,IAAMG,QAAQ,GAAG,IAAAH,aAAM,GAAU;EACjC,IAAMI,UAAU,GAAG,IAAAJ,aAAM,GAAkB;;EAE3C;EACA,IAAAK,gBAAS,EAAC,YAAM;IACdN,iBAAiB,CAACO,OAAO,GAAGT,cAAc;EAC5C,CAAC,EAAE,CAACA,cAAc,CAAC,CAAC;;EAEpB;EACA,IAAAQ,gBAAS,EAAC,YAAM;IACdJ,QAAQ,CAACK,OAAO,GAAGjD,QAAQ,CAACC,KAAK,CAAC;EACpC,CAAC,EAAE,CAACA,KAAK,CAAC,CAAC;;EAEX;EACA,IAAA+C,gBAAS,EACP;IAAA,OAAM,YAAM;MACV,IAAIF,QAAQ,CAACG,OAAO,EAAEpC,MAAM,CAACqC,oBAAoB,CAACJ,QAAQ,CAACG,OAAO,CAAC;MACnE,IAAIF,UAAU,CAACE,OAAO,EAAEE,YAAY,CAACJ,UAAU,CAACE,OAAO,CAAC;IAC1D,CAAC;EAAA,GACD,EAAE,CACH;;EAED;EACA,IAAMG,UAAU,GAAG,IAAAC,kBAAW,EAAC,UAAC9C,EAAW,EAAE+C,IAAe,EAAK;IAC/D,IAAQlD,WAAW,GAAKwC,QAAQ,CAACK,OAAO,CAAhC7C,WAAW;IACnB,gBAA0BE,OAAO,CAACC,EAAE,CAAC;MAA7BK,KAAK,aAALA,KAAK;MAAEG,MAAM,aAANA,MAAM;IACrB,IAAMwC,IAAI,GAAGD,IAAI,KAAK,GAAG,GAAG1C,KAAK,GAAGG,MAAM;IAC1C,OAAOyC,IAAI,CAACC,KAAK,CAAEF,IAAI,GAAGnD,WAAW,GAAI,GAAG,CAAC;EAC/C,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,IAAMsD,aAAa,GAAG,IAAAL,kBAAW,EAAC,UAACM,IAAY,EAAEC,OAAe,EAAK;IACnE,IAAID,IAAI,GAAG,CAAC,IAAIA,IAAI,GAAGC,OAAO,EAAE,OAAO,CAAC;IACxC,IAAQvD,UAAU,GAAKuC,QAAQ,CAACK,OAAO,CAA/B5C,UAAU;IAClB,IAAMwD,OAAO,GAAGD,OAAO,GAAGJ,IAAI,CAACM,GAAG,CAACzD,UAAU,CAAC;IAC9C,OAAOmD,IAAI,CAACC,KAAK,CAACD,IAAI,CAACO,GAAG,CAAC,CAACH,OAAO,GAAGD,IAAI,IAAIE,OAAO,CAAC,CAAC;EACzD,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,IAAMG,QAAQ,GAAG,IAAAX,kBAAW,EAAC,UAACtB,OAAgB,EAAEkC,OAAwB,EAAK;IAC3EnB,QAAQ,CAACG,OAAO,GAAGpC,MAAM,CAACqD,qBAAqB,CAAC,YAAM;MACpD,IAAM3D,EAAE,GAAGwB,OAAO,KAAKvB,QAAQ,CAACC,IAAI,GAAGI,MAAM,GAAGkB,OAAO;MACvDxB,EAAE,CAACyD,QAAQ,CAACC,OAAO,CAAC;IACtB,CAAC,CAAC;EACJ,CAAC,EAAE,EAAE,CAAC;EAEN,IAAME,MAAM,GAAG,IAAAd,kBAAW,EAAC,YAAM;IAC/B,IAAQnD,OAAO,GAAK0C,QAAQ,CAACK,OAAO,CAA5B/C,OAAO;IACf,4BAAiBwC,iBAAiB,CAACO,OAAO;MAAlCvC,CAAC,yBAADA,CAAC;MAAEC,CAAC,yBAADA,CAAC;IACZ,IAAMyD,kBAAkB,GAAGxC,qBAAqB,CAAClB,CAAC,EAAEC,CAAC,CAAC,CAAC0D,OAAO,EAAE;IAEhE,IAAI,CAACnE,OAAO,EAAE;MACZ2C,cAAc,CAACI,OAAO,GAAG,KAAK;MAC9B;IACF;IAEAJ,cAAc,CAACI,OAAO,GAAG,IAAI;;IAE7B;IAAA,4CACiBmB,kBAAkB;MAAA;IAAA;MAAnC,uDAAqC;QAAA,IAA1B7D,EAAE;QACX,IAAMU,IAAI,GAAGX,OAAO,CAACC,EAAE,CAAC;QACxB,uBAAkC2B,eAAe,CAAC3B,EAAE,CAAC;UAA7C4B,UAAU,oBAAVA,UAAU;UAAEE,SAAS,oBAATA,SAAS;QAE7B,IAAMiC,QAAQ,GAAGlB,UAAU,CAAC7C,EAAE,EAAE,GAAG,CAAC;QACpC,IAAMgE,QAAQ,GAAGnB,UAAU,CAAC7C,EAAE,EAAE,GAAG,CAAC;QAEpC,IAAMiE,QAAQ,GAAG9D,CAAC,GAAGO,IAAI,CAACP,CAAC;QAC3B,IAAM+D,OAAO,GAAG9D,CAAC,GAAGM,IAAI,CAACN,CAAC;QAC1B,IAAM+D,SAAS,GAAGzD,IAAI,CAACP,CAAC,GAAGO,IAAI,CAACL,KAAK,GAAGF,CAAC;QACzC,IAAMiE,UAAU,GAAG1D,IAAI,CAACN,CAAC,GAAGM,IAAI,CAACF,MAAM,GAAGJ,CAAC;QAE3C,IAAMiE,cAAc,GAAGlB,aAAa,CAACc,QAAQ,EAAEF,QAAQ,CAAC;QACxD,IAAMO,aAAa,GAAGnB,aAAa,CAACe,OAAO,EAAEF,QAAQ,CAAC;QACtD,IAAMO,eAAe,GAAGpB,aAAa,CAACgB,SAAS,EAAEJ,QAAQ,CAAC;QAC1D,IAAMS,gBAAgB,GAAGrB,aAAa,CAACiB,UAAU,EAAEJ,QAAQ,CAAC;QAE5D,IAAMS,aAAa,GAAG7C,UAAU,GAAG,CAAC;QACpC,IAAM8C,YAAY,GAAG5C,SAAS,GAAG,CAAC;QAClC,IAAM6C,cAAc,GAAG3E,EAAE,CAACmB,WAAW,GAAGS,UAAU,GAAGlB,IAAI,CAACL,KAAK;QAC/D,IAAMuE,eAAe,GAAG5E,EAAE,CAACoB,YAAY,GAAGU,SAAS,GAAGpB,IAAI,CAACF,MAAM;QAEjE,IAAIqE,IAAI,GAAGjD,UAAU;QACrB,IAAI6C,aAAa,IAAIJ,cAAc,GAAG,CAAC,EAAE;UACvCQ,IAAI,GAAG5B,IAAI,CAAC6B,GAAG,CAAClD,UAAU,GAAGyC,cAAc,EAAE,CAAC,CAAC;QACjD,CAAC,MAAM,IAAIM,cAAc,IAAIJ,eAAe,GAAG,CAAC,EAAE;UAChDM,IAAI,GAAG5B,IAAI,CAAC8B,GAAG,CACbnD,UAAU,GAAG2C,eAAe,EAC5BvE,EAAE,CAACmB,WAAW,GAAGT,IAAI,CAACL,KAAK,CAC5B;QACH;QAEA,IAAI2E,GAAG,GAAGlD,SAAS;QACnB,IAAI4C,YAAY,IAAIJ,aAAa,GAAG,CAAC,EAAE;UACrCU,GAAG,GAAG/B,IAAI,CAAC6B,GAAG,CAAChD,SAAS,GAAGwC,aAAa,EAAE,CAAC,CAAC;QAC9C,CAAC,MAAM,IAAIM,eAAe,IAAIJ,gBAAgB,GAAG,CAAC,EAAE;UAClDQ,GAAG,GAAG/B,IAAI,CAAC8B,GAAG,CACZjD,SAAS,GAAG0C,gBAAgB,EAC5BxE,EAAE,CAACoB,YAAY,GAAGV,IAAI,CAACF,MAAM,CAC9B;QACH;QAEA,IAAIqE,IAAI,KAAKjD,UAAU,IAAIoD,GAAG,KAAKlD,SAAS,EAAE;UAC5C2B,QAAQ,CAACzD,EAAE,EAAE;YAAE6E,IAAI,EAAJA,IAAI;YAAEG,GAAG,EAAHA;UAAI,CAAC,CAAC;UAC3BxC,UAAU,CAACE,OAAO,GAAGuC,UAAU,CAACrB,MAAM,EAAEpE,aAAa,CAAC;UACtD;QACF;MACF;IAAC;MAAA;IAAA;MAAA;IAAA;IAED8C,cAAc,CAACI,OAAO,GAAG,KAAK;EAChC,CAAC,EAAE,CAACG,UAAU,EAAEM,aAAa,EAAEM,QAAQ,CAAC,CAAC;;EAEzC;EACA,IAAAhB,gBAAS,EAAC,YAAM;IACd,IAAI,CAACH,cAAc,CAACI,OAAO,IAAIhD,KAAK,CAACC,OAAO,EAAEiE,MAAM,EAAE;EACxD,CAAC,EAAE,CAACA,MAAM,EAAE3B,cAAc,EAAEvC,KAAK,CAACC,OAAO,CAAC,CAAC;AAC7C,CAAC;AAAC,eAEaqC,aAAa;AAAA"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
2
1
|
import useCursorPosition from '@os-design/use-cursor-position';
|
|
2
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
3
3
|
const FPS = 60;
|
|
4
4
|
const FRAME_TIMEOUT = 1000 / FPS;
|
|
5
|
-
|
|
6
5
|
const getProps = props => ({
|
|
7
6
|
enabled: props.enabled !== undefined ? props.enabled : true,
|
|
8
7
|
distPercent: 20,
|
|
9
8
|
maxSpeedPx: 100
|
|
10
9
|
});
|
|
11
|
-
|
|
12
10
|
const getRect = el => {
|
|
13
11
|
if (el === document.body) {
|
|
14
12
|
return {
|
|
@@ -18,7 +16,6 @@ const getRect = el => {
|
|
|
18
16
|
height: window.innerHeight
|
|
19
17
|
};
|
|
20
18
|
}
|
|
21
|
-
|
|
22
19
|
const rect = el.getBoundingClientRect();
|
|
23
20
|
return {
|
|
24
21
|
x: rect.x,
|
|
@@ -27,46 +24,38 @@ const getRect = el => {
|
|
|
27
24
|
height: rect.height
|
|
28
25
|
};
|
|
29
26
|
};
|
|
27
|
+
|
|
30
28
|
/**
|
|
31
29
|
* Detects whether the element is scrollable.
|
|
32
30
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
31
|
const isScrollable = el => {
|
|
36
32
|
const style = getComputedStyle(el);
|
|
37
|
-
|
|
38
33
|
if (el !== document.body && !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
39
34
|
return false;
|
|
40
35
|
}
|
|
41
|
-
|
|
42
36
|
const {
|
|
43
37
|
width,
|
|
44
38
|
height
|
|
45
39
|
} = getRect(el);
|
|
46
40
|
return el.scrollWidth > width || el.scrollHeight > height;
|
|
47
41
|
};
|
|
42
|
+
|
|
48
43
|
/**
|
|
49
44
|
* Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.
|
|
50
45
|
*/
|
|
51
|
-
|
|
52
|
-
|
|
53
46
|
export const getScrollableElements = (x, y) => {
|
|
54
47
|
const elementsFromPoint = document.elementsFromPoint(x, y);
|
|
55
|
-
const elements = [];
|
|
56
|
-
|
|
48
|
+
const elements = [];
|
|
49
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
57
50
|
for (const element of elementsFromPoint) {
|
|
58
51
|
const el = element === document.documentElement ? document.body : element;
|
|
59
|
-
|
|
60
52
|
if (isScrollable(el)) {
|
|
61
53
|
elements.push(el);
|
|
62
54
|
}
|
|
63
|
-
|
|
64
55
|
if (el === document.body) break;
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
return elements;
|
|
68
58
|
};
|
|
69
|
-
|
|
70
59
|
const getScrollOffset = el => {
|
|
71
60
|
if (el === document.body) {
|
|
72
61
|
return {
|
|
@@ -74,34 +63,36 @@ const getScrollOffset = el => {
|
|
|
74
63
|
scrollTop: window.scrollY
|
|
75
64
|
};
|
|
76
65
|
}
|
|
77
|
-
|
|
78
66
|
return {
|
|
79
67
|
scrollLeft: el.scrollLeft,
|
|
80
68
|
scrollTop: el.scrollTop
|
|
81
69
|
};
|
|
82
70
|
};
|
|
83
|
-
|
|
84
71
|
const useAutoScroll = (props = {}) => {
|
|
85
72
|
const cursorPosition = useCursorPosition();
|
|
86
73
|
const cursorPositionRef = useRef(cursorPosition);
|
|
87
74
|
const propsRef = useRef(getProps(props));
|
|
88
75
|
const isScrollingRef = useRef(false);
|
|
89
76
|
const frameRef = useRef();
|
|
90
|
-
const timeoutRef = useRef();
|
|
77
|
+
const timeoutRef = useRef();
|
|
91
78
|
|
|
79
|
+
// Update the ref to the cursor position if it changes
|
|
92
80
|
useEffect(() => {
|
|
93
81
|
cursorPositionRef.current = cursorPosition;
|
|
94
|
-
}, [cursorPosition]);
|
|
82
|
+
}, [cursorPosition]);
|
|
95
83
|
|
|
84
|
+
// Update the props if it changes
|
|
96
85
|
useEffect(() => {
|
|
97
86
|
propsRef.current = getProps(props);
|
|
98
|
-
}, [props]);
|
|
87
|
+
}, [props]);
|
|
99
88
|
|
|
89
|
+
// Cancel the animation frame request and clear the timeout if the component was unmounted
|
|
100
90
|
useEffect(() => () => {
|
|
101
91
|
if (frameRef.current) window.cancelAnimationFrame(frameRef.current);
|
|
102
92
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
103
|
-
}, []);
|
|
93
|
+
}, []);
|
|
104
94
|
|
|
95
|
+
// Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)
|
|
105
96
|
const getMaxDist = useCallback((el, axis) => {
|
|
106
97
|
const {
|
|
107
98
|
distPercent
|
|
@@ -112,8 +103,9 @@ const useAutoScroll = (props = {}) => {
|
|
|
112
103
|
} = getRect(el);
|
|
113
104
|
const size = axis === 'x' ? width : height;
|
|
114
105
|
return Math.round(size * distPercent / 100);
|
|
115
|
-
}, []);
|
|
106
|
+
}, []);
|
|
116
107
|
|
|
108
|
+
// Returns the distance by which the scroll position should be changed
|
|
117
109
|
const getScrollStep = useCallback((dist, maxDist) => {
|
|
118
110
|
if (dist < 0 || dist > maxDist) return 0;
|
|
119
111
|
const {
|
|
@@ -121,8 +113,9 @@ const useAutoScroll = (props = {}) => {
|
|
|
121
113
|
} = propsRef.current;
|
|
122
114
|
const divisor = maxDist / Math.log(maxSpeedPx);
|
|
123
115
|
return Math.round(Math.exp((maxDist - dist) / divisor));
|
|
124
|
-
}, []);
|
|
116
|
+
}, []);
|
|
125
117
|
|
|
118
|
+
// Scrolls the element to the specified position
|
|
126
119
|
const scrollTo = useCallback((element, options) => {
|
|
127
120
|
frameRef.current = window.requestAnimationFrame(() => {
|
|
128
121
|
const el = element === document.body ? window : element;
|
|
@@ -138,14 +131,13 @@ const useAutoScroll = (props = {}) => {
|
|
|
138
131
|
y
|
|
139
132
|
} = cursorPositionRef.current;
|
|
140
133
|
const scrollableElements = getScrollableElements(x, y).reverse();
|
|
141
|
-
|
|
142
134
|
if (!enabled) {
|
|
143
135
|
isScrollingRef.current = false;
|
|
144
136
|
return;
|
|
145
137
|
}
|
|
138
|
+
isScrollingRef.current = true;
|
|
146
139
|
|
|
147
|
-
|
|
148
|
-
|
|
140
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
149
141
|
for (const el of scrollableElements) {
|
|
150
142
|
const rect = getRect(el);
|
|
151
143
|
const {
|
|
@@ -167,21 +159,17 @@ const useAutoScroll = (props = {}) => {
|
|
|
167
159
|
const canScrollRight = el.scrollWidth - scrollLeft > rect.width;
|
|
168
160
|
const canScrollBottom = el.scrollHeight - scrollTop > rect.height;
|
|
169
161
|
let left = scrollLeft;
|
|
170
|
-
|
|
171
162
|
if (canScrollLeft && leftScrollStep > 0) {
|
|
172
163
|
left = Math.max(scrollLeft - leftScrollStep, 0);
|
|
173
164
|
} else if (canScrollRight && rightScrollStep > 0) {
|
|
174
165
|
left = Math.min(scrollLeft + rightScrollStep, el.scrollWidth - rect.width);
|
|
175
166
|
}
|
|
176
|
-
|
|
177
167
|
let top = scrollTop;
|
|
178
|
-
|
|
179
168
|
if (canScrollTop && topScrollStep > 0) {
|
|
180
169
|
top = Math.max(scrollTop - topScrollStep, 0);
|
|
181
170
|
} else if (canScrollBottom && bottomScrollStep > 0) {
|
|
182
171
|
top = Math.min(scrollTop + bottomScrollStep, el.scrollHeight - rect.height);
|
|
183
172
|
}
|
|
184
|
-
|
|
185
173
|
if (left !== scrollLeft || top !== scrollTop) {
|
|
186
174
|
scrollTo(el, {
|
|
187
175
|
left,
|
|
@@ -191,14 +179,13 @@ const useAutoScroll = (props = {}) => {
|
|
|
191
179
|
return;
|
|
192
180
|
}
|
|
193
181
|
}
|
|
194
|
-
|
|
195
182
|
isScrollingRef.current = false;
|
|
196
|
-
}, [getMaxDist, getScrollStep, scrollTo]);
|
|
183
|
+
}, [getMaxDist, getScrollStep, scrollTo]);
|
|
197
184
|
|
|
185
|
+
// Start auto scrolling when the cursor position changes only if it is not already running
|
|
198
186
|
useEffect(() => {
|
|
199
187
|
if (!isScrollingRef.current && props.enabled) scroll();
|
|
200
188
|
}, [scroll, cursorPosition, props.enabled]);
|
|
201
189
|
};
|
|
202
|
-
|
|
203
190
|
export default useAutoScroll;
|
|
204
191
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["useCallback","useEffect","useRef","useCursorPosition","FPS","FRAME_TIMEOUT","getProps","props","enabled","undefined","distPercent","maxSpeedPx","getRect","el","document","body","x","y","width","window","innerWidth","height","innerHeight","rect","getBoundingClientRect","isScrollable","style","getComputedStyle","test","overflow","overflowY","overflowX","scrollWidth","scrollHeight","getScrollableElements","elementsFromPoint","elements","element","documentElement","push","getScrollOffset","scrollLeft","scrollX","scrollTop","scrollY","useAutoScroll","cursorPosition","cursorPositionRef","propsRef","isScrollingRef","frameRef","timeoutRef","current","cancelAnimationFrame","clearTimeout","getMaxDist","axis","size","Math","round","getScrollStep","dist","maxDist","divisor","log","exp","scrollTo","options","requestAnimationFrame","scroll","scrollableElements","reverse","xMaxDist","yMaxDist","leftDist","topDist","rightDist","bottomDist","leftScrollStep","topScrollStep","rightScrollStep","bottomScrollStep","canScrollLeft","canScrollTop","canScrollRight","canScrollBottom","left","max","min","top","setTimeout"],"sources":["../../src/index.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport useCursorPosition from '@os-design/use-cursor-position';\n\nconst FPS = 60;\nconst FRAME_TIMEOUT = 1000 / FPS;\n\nexport interface UseAutoScrollProps {\n /**\n * Whether the auto scroll is enabled.\n * @default true\n */\n enabled?: boolean;\n /**\n * The distance to the border at which the container starts to scroll automatically (in percent).\n * @default 20\n */\n distPercent?: number;\n /**\n * The max auto scroll speed (in px).\n * @default 100\n */\n maxSpeedPx?: number;\n}\n\nconst getProps = (props: UseAutoScrollProps): Required<UseAutoScrollProps> => ({\n enabled: props.enabled !== undefined ? props.enabled : true,\n distPercent: 20,\n maxSpeedPx: 100,\n});\n\nconst getRect = (el: Element) => {\n if (el === document.body) {\n return {\n x: 0,\n y: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n }\n const rect = el.getBoundingClientRect();\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Detects whether the element is scrollable.\n */\nconst isScrollable = (el: Element) => {\n const style = getComputedStyle(el);\n if (\n el !== document.body &&\n !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n return false;\n }\n const { width, height } = getRect(el);\n return el.scrollWidth > width || el.scrollHeight > height;\n};\n\n/**\n * Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.\n */\nexport const getScrollableElements = (x: number, y: number): Element[] => {\n const elementsFromPoint = document.elementsFromPoint(x, y);\n const elements: Element[] = [];\n // eslint-disable-next-line no-restricted-syntax\n for (const element of elementsFromPoint) {\n const el = element === document.documentElement ? document.body : element;\n if (isScrollable(el)) {\n elements.push(el);\n }\n if (el === document.body) break;\n }\n return elements;\n};\n\nconst getScrollOffset = (el: Element) => {\n if (el === document.body) {\n return {\n scrollLeft: window.scrollX,\n scrollTop: window.scrollY,\n };\n }\n return {\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop,\n };\n};\n\nconst useAutoScroll = (props: UseAutoScrollProps = {}) => {\n const cursorPosition = useCursorPosition();\n const cursorPositionRef = useRef(cursorPosition);\n const propsRef = useRef<Required<UseAutoScrollProps>>(getProps(props));\n const isScrollingRef = useRef(false);\n const frameRef = useRef<number>();\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n // Update the ref to the cursor position if it changes\n useEffect(() => {\n cursorPositionRef.current = cursorPosition;\n }, [cursorPosition]);\n\n // Update the props if it changes\n useEffect(() => {\n propsRef.current = getProps(props);\n }, [props]);\n\n // Cancel the animation frame request and clear the timeout if the component was unmounted\n useEffect(\n () => () => {\n if (frameRef.current) window.cancelAnimationFrame(frameRef.current);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n },\n []\n );\n\n // Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)\n const getMaxDist = useCallback((el: Element, axis: 'x' | 'y') => {\n const { distPercent } = propsRef.current;\n const { width, height } = getRect(el);\n const size = axis === 'x' ? width : height;\n return Math.round((size * distPercent) / 100);\n }, []);\n\n // Returns the distance by which the scroll position should be changed\n const getScrollStep = useCallback((dist: number, maxDist: number) => {\n if (dist < 0 || dist > maxDist) return 0;\n const { maxSpeedPx } = propsRef.current;\n const divisor = maxDist / Math.log(maxSpeedPx);\n return Math.round(Math.exp((maxDist - dist) / divisor));\n }, []);\n\n // Scrolls the element to the specified position\n const scrollTo = useCallback((element: Element, options: ScrollToOptions) => {\n frameRef.current = window.requestAnimationFrame(() => {\n const el = element === document.body ? window : element;\n el.scrollTo(options);\n });\n }, []);\n\n const scroll = useCallback(() => {\n const { enabled } = propsRef.current;\n const { x, y } = cursorPositionRef.current;\n const scrollableElements = getScrollableElements(x, y).reverse();\n\n if (!enabled) {\n isScrollingRef.current = false;\n return;\n }\n\n isScrollingRef.current = true;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const el of scrollableElements) {\n const rect = getRect(el);\n const { scrollLeft, scrollTop } = getScrollOffset(el);\n\n const xMaxDist = getMaxDist(el, 'x');\n const yMaxDist = getMaxDist(el, 'y');\n\n const leftDist = x - rect.x;\n const topDist = y - rect.y;\n const rightDist = rect.x + rect.width - x;\n const bottomDist = rect.y + rect.height - y;\n\n const leftScrollStep = getScrollStep(leftDist, xMaxDist);\n const topScrollStep = getScrollStep(topDist, yMaxDist);\n const rightScrollStep = getScrollStep(rightDist, xMaxDist);\n const bottomScrollStep = getScrollStep(bottomDist, yMaxDist);\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollTop = scrollTop > 0;\n const canScrollRight = el.scrollWidth - scrollLeft > rect.width;\n const canScrollBottom = el.scrollHeight - scrollTop > rect.height;\n\n let left = scrollLeft;\n if (canScrollLeft && leftScrollStep > 0) {\n left = Math.max(scrollLeft - leftScrollStep, 0);\n } else if (canScrollRight && rightScrollStep > 0) {\n left = Math.min(\n scrollLeft + rightScrollStep,\n el.scrollWidth - rect.width\n );\n }\n\n let top = scrollTop;\n if (canScrollTop && topScrollStep > 0) {\n top = Math.max(scrollTop - topScrollStep, 0);\n } else if (canScrollBottom && bottomScrollStep > 0) {\n top = Math.min(\n scrollTop + bottomScrollStep,\n el.scrollHeight - rect.height\n );\n }\n\n if (left !== scrollLeft || top !== scrollTop) {\n scrollTo(el, { left, top });\n timeoutRef.current = setTimeout(scroll, FRAME_TIMEOUT);\n return;\n }\n }\n\n isScrollingRef.current = false;\n }, [getMaxDist, getScrollStep, scrollTo]);\n\n // Start auto scrolling when the cursor position changes only if it is not already running\n useEffect(() => {\n if (!isScrollingRef.current && props.enabled) scroll();\n }, [scroll, cursorPosition, props.enabled]);\n};\n\nexport default useAutoScroll;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["useCursorPosition","useCallback","useEffect","useRef","FPS","FRAME_TIMEOUT","getProps","props","enabled","undefined","distPercent","maxSpeedPx","getRect","el","document","body","x","y","width","window","innerWidth","height","innerHeight","rect","getBoundingClientRect","isScrollable","style","getComputedStyle","test","overflow","overflowY","overflowX","scrollWidth","scrollHeight","getScrollableElements","elementsFromPoint","elements","element","documentElement","push","getScrollOffset","scrollLeft","scrollX","scrollTop","scrollY","useAutoScroll","cursorPosition","cursorPositionRef","propsRef","isScrollingRef","frameRef","timeoutRef","current","cancelAnimationFrame","clearTimeout","getMaxDist","axis","size","Math","round","getScrollStep","dist","maxDist","divisor","log","exp","scrollTo","options","requestAnimationFrame","scroll","scrollableElements","reverse","xMaxDist","yMaxDist","leftDist","topDist","rightDist","bottomDist","leftScrollStep","topScrollStep","rightScrollStep","bottomScrollStep","canScrollLeft","canScrollTop","canScrollRight","canScrollBottom","left","max","min","top","setTimeout"],"sources":["../../src/index.ts"],"sourcesContent":["import useCursorPosition from '@os-design/use-cursor-position';\nimport { useCallback, useEffect, useRef } from 'react';\n\nconst FPS = 60;\nconst FRAME_TIMEOUT = 1000 / FPS;\n\nexport interface UseAutoScrollProps {\n /**\n * Whether the auto scroll is enabled.\n * @default true\n */\n enabled?: boolean;\n /**\n * The distance to the border at which the container starts to scroll automatically (in percent).\n * @default 20\n */\n distPercent?: number;\n /**\n * The max auto scroll speed (in px).\n * @default 100\n */\n maxSpeedPx?: number;\n}\n\nconst getProps = (props: UseAutoScrollProps): Required<UseAutoScrollProps> => ({\n enabled: props.enabled !== undefined ? props.enabled : true,\n distPercent: 20,\n maxSpeedPx: 100,\n});\n\nconst getRect = (el: Element) => {\n if (el === document.body) {\n return {\n x: 0,\n y: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n }\n const rect = el.getBoundingClientRect();\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n };\n};\n\n/**\n * Detects whether the element is scrollable.\n */\nconst isScrollable = (el: Element) => {\n const style = getComputedStyle(el);\n if (\n el !== document.body &&\n !/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)\n ) {\n return false;\n }\n const { width, height } = getRect(el);\n return el.scrollWidth > width || el.scrollHeight > height;\n};\n\n/**\n * Returns an array of the scrollable elements located under the specified coordinates. The first one is the topmost.\n */\nexport const getScrollableElements = (x: number, y: number): Element[] => {\n const elementsFromPoint = document.elementsFromPoint(x, y);\n const elements: Element[] = [];\n // eslint-disable-next-line no-restricted-syntax\n for (const element of elementsFromPoint) {\n const el = element === document.documentElement ? document.body : element;\n if (isScrollable(el)) {\n elements.push(el);\n }\n if (el === document.body) break;\n }\n return elements;\n};\n\nconst getScrollOffset = (el: Element) => {\n if (el === document.body) {\n return {\n scrollLeft: window.scrollX,\n scrollTop: window.scrollY,\n };\n }\n return {\n scrollLeft: el.scrollLeft,\n scrollTop: el.scrollTop,\n };\n};\n\nconst useAutoScroll = (props: UseAutoScrollProps = {}) => {\n const cursorPosition = useCursorPosition();\n const cursorPositionRef = useRef(cursorPosition);\n const propsRef = useRef<Required<UseAutoScrollProps>>(getProps(props));\n const isScrollingRef = useRef(false);\n const frameRef = useRef<number>();\n const timeoutRef = useRef<NodeJS.Timeout>();\n\n // Update the ref to the cursor position if it changes\n useEffect(() => {\n cursorPositionRef.current = cursorPosition;\n }, [cursorPosition]);\n\n // Update the props if it changes\n useEffect(() => {\n propsRef.current = getProps(props);\n }, [props]);\n\n // Cancel the animation frame request and clear the timeout if the component was unmounted\n useEffect(\n () => () => {\n if (frameRef.current) window.cancelAnimationFrame(frameRef.current);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n },\n []\n );\n\n // Returns the max distance from the border of the specified element at which auto scrolling is enabled (in px)\n const getMaxDist = useCallback((el: Element, axis: 'x' | 'y') => {\n const { distPercent } = propsRef.current;\n const { width, height } = getRect(el);\n const size = axis === 'x' ? width : height;\n return Math.round((size * distPercent) / 100);\n }, []);\n\n // Returns the distance by which the scroll position should be changed\n const getScrollStep = useCallback((dist: number, maxDist: number) => {\n if (dist < 0 || dist > maxDist) return 0;\n const { maxSpeedPx } = propsRef.current;\n const divisor = maxDist / Math.log(maxSpeedPx);\n return Math.round(Math.exp((maxDist - dist) / divisor));\n }, []);\n\n // Scrolls the element to the specified position\n const scrollTo = useCallback((element: Element, options: ScrollToOptions) => {\n frameRef.current = window.requestAnimationFrame(() => {\n const el = element === document.body ? window : element;\n el.scrollTo(options);\n });\n }, []);\n\n const scroll = useCallback(() => {\n const { enabled } = propsRef.current;\n const { x, y } = cursorPositionRef.current;\n const scrollableElements = getScrollableElements(x, y).reverse();\n\n if (!enabled) {\n isScrollingRef.current = false;\n return;\n }\n\n isScrollingRef.current = true;\n\n // eslint-disable-next-line no-restricted-syntax\n for (const el of scrollableElements) {\n const rect = getRect(el);\n const { scrollLeft, scrollTop } = getScrollOffset(el);\n\n const xMaxDist = getMaxDist(el, 'x');\n const yMaxDist = getMaxDist(el, 'y');\n\n const leftDist = x - rect.x;\n const topDist = y - rect.y;\n const rightDist = rect.x + rect.width - x;\n const bottomDist = rect.y + rect.height - y;\n\n const leftScrollStep = getScrollStep(leftDist, xMaxDist);\n const topScrollStep = getScrollStep(topDist, yMaxDist);\n const rightScrollStep = getScrollStep(rightDist, xMaxDist);\n const bottomScrollStep = getScrollStep(bottomDist, yMaxDist);\n\n const canScrollLeft = scrollLeft > 0;\n const canScrollTop = scrollTop > 0;\n const canScrollRight = el.scrollWidth - scrollLeft > rect.width;\n const canScrollBottom = el.scrollHeight - scrollTop > rect.height;\n\n let left = scrollLeft;\n if (canScrollLeft && leftScrollStep > 0) {\n left = Math.max(scrollLeft - leftScrollStep, 0);\n } else if (canScrollRight && rightScrollStep > 0) {\n left = Math.min(\n scrollLeft + rightScrollStep,\n el.scrollWidth - rect.width\n );\n }\n\n let top = scrollTop;\n if (canScrollTop && topScrollStep > 0) {\n top = Math.max(scrollTop - topScrollStep, 0);\n } else if (canScrollBottom && bottomScrollStep > 0) {\n top = Math.min(\n scrollTop + bottomScrollStep,\n el.scrollHeight - rect.height\n );\n }\n\n if (left !== scrollLeft || top !== scrollTop) {\n scrollTo(el, { left, top });\n timeoutRef.current = setTimeout(scroll, FRAME_TIMEOUT);\n return;\n }\n }\n\n isScrollingRef.current = false;\n }, [getMaxDist, getScrollStep, scrollTo]);\n\n // Start auto scrolling when the cursor position changes only if it is not already running\n useEffect(() => {\n if (!isScrollingRef.current && props.enabled) scroll();\n }, [scroll, cursorPosition, props.enabled]);\n};\n\nexport default useAutoScroll;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@os-design/use-auto-scroll",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"repository": "git@gitlab.com:os-team/libs/os-design.git",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@os-design/use-cursor-position": "^1.0.
|
|
32
|
+
"@os-design/use-cursor-position": "^1.0.7"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"react": ">=18"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "8cb28f6719d699c014fbce91d832a9ff06abe515"
|
|
38
38
|
}
|