aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/TrackActiveSection.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/TrackActiveSection.tsx')
-rw-r--r--src/components/TrackActiveSection.tsx47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/components/TrackActiveSection.tsx b/src/components/TrackActiveSection.tsx
new file mode 100644
index 0000000..bb1b2ee
--- /dev/null
+++ b/src/components/TrackActiveSection.tsx
@@ -0,0 +1,47 @@
1/*
2 * SPDX-FileCopyrightText: 2023 Kristóf Marussy
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7import { type ReactNode, useEffect, useCallback, useRef } from 'react';
8
9import { useActiveSection } from './ActiveSectionProvider';
10
11export default function TrackActiveSection({
12 children,
13}: {
14 children: ReactNode;
15}) {
16 const { setHash } = useActiveSection();
17 const elementRef = useRef<HTMLDivElement | null>(null);
18 const callback = useCallback(() => {
19 const { current: element } = elementRef;
20 if (!element) {
21 return;
22 }
23 const currentID = Array.from(element.children)
24 .reverse()
25 .find((child) => child.getBoundingClientRect().top <= 60)?.id;
26 const currentHash =
27 currentID === undefined || currentID === '' ? '' : `#${currentID}`;
28 setHash(currentHash);
29 }, [setHash]);
30 const setElement = useCallback(
31 (element: HTMLDivElement | null) => {
32 elementRef.current = element;
33 if (element) {
34 callback();
35 } else {
36 setHash(undefined);
37 }
38 },
39 [setHash],
40 );
41 useEffect(() => {
42 window.addEventListener('scroll', callback);
43 return () => window.removeEventListener('scroll', callback);
44 });
45
46 return <div ref={setElement}>{children}</div>;
47}