forked from nodejs/nodejs.dev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnavigation.tsx
More file actions
78 lines (69 loc) · 2.31 KB
/
navigation.tsx
File metadata and controls
78 lines (69 loc) · 2.31 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
73
74
75
76
77
78
import React, { useState, useRef } from 'react';
import NavigationSection from './navigation-section';
import { NavigationSectionData, NavigationSectionItem } from '../types';
import { isSmallScreen } from '../util/isScreenWithinWidth';
import { scrollTo, calcNavScrollParams } from '../util/scrollTo';
type Props = {
sections: NavigationSectionData;
currentSlug: string;
};
const Navigation = ({ sections, currentSlug }: Props) => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [hasScrolled, setHasScrolled] = useState<boolean>(false);
const navElement = useRef<HTMLElement | null>(null);
const toggle = () => setIsOpen(!isOpen);
const onItemClick = () => {
if (isSmallScreen()) {
toggle();
}
};
const autoScroll = async (height: number) => {
if (isOpen && !hasScrolled && navElement.current) {
const { newScrollPos, scrollWindow, scrollTime } = calcNavScrollParams(
height,
navElement.current
);
try {
await scrollTo(newScrollPos, scrollWindow, scrollTime);
setHasScrolled(true);
} catch (e) {
// TODO: follow up with appropriate error logging if any
setHasScrolled(false);
}
}
};
const className = isOpen ? 'side-nav side-nav--open' : 'side-nav';
const readSections: Set<NavigationSectionItem['slug']> = new Set();
// Assume section items up to the one currently open have been read. Track
// their unique slugs in `readSections` set.
Object.keys(sections).some(sectionKey => {
let isCurrentSlug: boolean = false;
sections[sectionKey].some(sectionItem => {
isCurrentSlug = sectionItem.slug === currentSlug;
if (!isCurrentSlug) {
readSections.add(sectionItem.slug);
}
return isCurrentSlug;
});
return isCurrentSlug;
});
return (
<nav className={className} ref={navElement}>
<button className="side-nav__open" onClick={toggle}>
Menu
</button>
{Object.keys(sections).map((sectionKey: string) => (
<NavigationSection
key={sectionKey}
title={sectionKey}
section={sections[sectionKey]}
currentSlug={currentSlug}
onItemClick={onItemClick}
readSections={readSections}
autoScroll={autoScroll}
/>
))}
</nav>
);
};
export default Navigation;