forked from drownbes/react-use-sync-scroll
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.js
More file actions
62 lines (50 loc) · 1.74 KB
/
Copy pathindex.js
File metadata and controls
62 lines (50 loc) · 1.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import React, { useCallback } from 'react'
function syncScroll(target, others, TopLeft, WidthHeight) {
const percentage =
target[`scroll${TopLeft}`] / (target[`scroll${WidthHeight}`] - target[`offset${WidthHeight}`])
// eslint-disable-next-line no-undef
window.requestAnimationFrame(() => {
others.forEach(el => {
el[`scroll${TopLeft}`] = Math.round(
percentage * (el[`scroll${WidthHeight}`] - el[`offset${WidthHeight}`]),
)
})
})
}
function syncVerticalScroll(target, others) {
syncScroll(target, others, 'Top', 'Height')
}
function syncHorizontalScroll(target, others) {
syncScroll(target, others, 'Left', 'Width')
}
function useSyncScroll({ vertical, horizontal }) {
const elementsRef = React.useRef([])
const locksRef = React.useRef(0)
const refCallback = useCallback(
element => {
const currentElements = elementsRef.current
if (element) {
// eslint-disable-next-line
element.addEventListener('scroll', handleScroll)
currentElements.push(element)
} else {
// eslint-disable-next-line
currentElements.forEach(el => el.removeEventListener('scroll', handleScroll))
currentElements.splice(0, currentElements.length)
}
function handleScroll({ target }) {
if (locksRef.current > 0) {
locksRef.current -= 1 // Release lock by 1
return
}
locksRef.current = elementsRef.current.length - 1 // Acquire lock
const others = elementsRef.current.filter(ref => ref !== target)
if (vertical) syncVerticalScroll(target, others)
if (horizontal) syncHorizontalScroll(target, others)
}
},
[horizontal, vertical],
)
return refCallback
}
export default useSyncScroll