forked from newrelic/docs-website
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseActiveHash.js
More file actions
72 lines (56 loc) · 1.86 KB
/
Copy pathuseActiveHash.js
File metadata and controls
72 lines (56 loc) · 1.86 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
63
64
65
66
67
68
69
70
71
72
import { useEffect, useRef, useState } from 'react';
import getScrollHeight from '../utils/scrollHeight';
import { useWindowSize } from 'react-use';
// global header height + layout content padding
const MIN_THRESHOLD = 68;
const useActiveHash = (ids) => {
const { height } = useWindowSize();
const threshold = Math.max(height * 0.2, MIN_THRESHOLD);
const [activeHash, setActiveHash] = useState(() => {
if (typeof window !== 'undefined') {
return window.location.hash || ids[0];
}
return ids[0];
});
const activeHashRef = useRef(activeHash);
useEffect(() => {
if (ids.length === 0) {
return;
}
const handler = () => {
const elements = ids.map((id) => document.getElementById(id));
const scrollTop = document.documentElement.scrollTop;
const scrolledToBottom = scrollTop + height >= getScrollHeight();
const element = scrolledToBottom
? elements[elements.length - 1]
: findNearestHeading(elements, threshold);
if (element && element.id !== activeHashRef.current) {
setActiveHash(element.id);
activeHashRef.current = element.idj;
}
};
window.addEventListener('scroll', handler, {
capture: false,
passive: true,
});
return () => window.removeEventListener('scroll', handler);
}, [ids, threshold, height]);
return activeHash;
};
const findNearestHeading = (elements, offset) => {
const scrollTop = document.documentElement.scrollTop;
const hasCrossedThreshold = (element) =>
element ? element.offsetTop - scrollTop <= offset : false;
return elements.find((element, idx) => {
if (!element) {
return false;
}
if (idx === 0 && !hasCrossedThreshold(element)) {
return true;
}
return (
hasCrossedThreshold(element) && !hasCrossedThreshold(elements[idx + 1])
);
});
};
export default useActiveHash;