All files / src/views/Package SecondaryDocNavigation.tsx

0% Statements 0/19
0% Branches 0/8
0% Functions 0/5
0% Lines 0/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                                                                                             
import {
  FunctionComponent,
  useCallback,
  useEffect,
  useRef,
  useState,
} from "react";
import { useLocation } from "react-router-dom";
import { PACKAGE_ANALYTICS } from "./constants";
import { normalizeId, useIntersectingHeader } from "./useIntersectingHeader";
import { useSectionItems } from "./useSectionItems";
import { GetIsActiveItemFunction, NavTree } from "../../components/NavTree";
 
export const SecondaryDocNavigation: FunctionComponent = () => {
  const intersectingHeader = useIntersectingHeader();
  const sectionItems = useSectionItems();
  const { hash } = useLocation();
 
  // This ref is used to direct control over highlight state between
  // recentlyClickedItem and intersectingHeader
  const allowIntersectTakeover = useRef(false);
 
  // Tracks the link which was clicked, is set to undefined when the intersectingHeader state takes over
  const [recentlyClickedItem, setRecentlyClickedItem] = useState<
    string | undefined
  >(hash);
 
  // When a user clicks a link, we give control of highlights to the recentlyClickedItem state for 500ms
  // Afterwards, intersectingHeader state via intersection observer takes control of state
  useEffect(() => {
    setRecentlyClickedItem(hash);
    allowIntersectTakeover.current = false;
 
    setTimeout(() => {
      allowIntersectTakeover.current = true;
    }, 500);
  }, [hash]);
 
  // When intersectingHeader changes from scroll and allowIntersectTakeover is true,
  // we set the recentlyClickedItem state to undefined so link highlight state will be dictated
  // by the intersectingHeader state
  useEffect(() => {
    if (recentlyClickedItem && allowIntersectTakeover.current) {
      setRecentlyClickedItem(undefined);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [intersectingHeader]);
 
  // If recentlyClickedItem is defined, use it to compare for highlight state
  // Otherwise compare item id against intersectingHeader
  const getIsLinkActive: GetIsActiveItemFunction = useCallback(
    ({ path, id }) => {
      if (recentlyClickedItem) {
        return new URL(path ?? "", window.origin).hash === recentlyClickedItem;
      }
 
      return normalizeId(id) === intersectingHeader;
    },
    [intersectingHeader, recentlyClickedItem]
  );
 
  return (
    <NavTree
      data-event={PACKAGE_ANALYTICS.SCOPE}
      getIsActiveItem={getIsLinkActive}
      items={sectionItems}
      variant="sm"
    />
  );
};