All files / base/navigation dropdownUtils.ts

0% Statements 0/45
0% Branches 0/17
0% Functions 0/10
0% Lines 0/45

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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113                                                                                                                                                                                                                                 
export const setActiveDropdown = (
  dropdownToggleButton: HTMLElement,
  isActive = true
) => {
  // set active state of the dropdown toggle (to slide the panel into view)
  const dropdownToggleEl = dropdownToggleButton.closest(
    ".p-navigation__item--dropdown-toggle"
  );
  if (dropdownToggleEl) {
    dropdownToggleEl.classList.toggle("is-active", isActive);
    dropdownToggleEl.classList.toggle("is-selected", isActive);
    const globalNavButton = dropdownToggleEl.querySelector(
      ":scope > .p-navigation__link"
    );
    // fix some states from global-nav elements in mobile
    if (globalNavButton) {
      globalNavButton.setAttribute("aria-expanded", isActive.toString());
      globalNavButton.classList.toggle("is-selected", isActive);
    }
  }
 
  // set active state of the parent dropdown panel (to fade it out of view)
  const parentLevelDropdown = dropdownToggleEl?.closest(
    ".p-navigation__dropdown"
  );
  if (parentLevelDropdown) {
    parentLevelDropdown.classList.toggle("is-active", isActive);
  }
 
  // set active state of the top navigation list under p-navigation__nav
  // to set the position of the sliding panel properly
  const topLevelNavigation = dropdownToggleButton.closest(".p-navigation__nav");
  if (topLevelNavigation) {
    const topLevelItems = topLevelNavigation.querySelectorAll(
      ":scope > .p-navigation__items"
    );
 
    for (const item of topLevelItems) {
      // in case there are more than one top level navigation lists, we need to
      // mark as active the one that contains the clicked button and hide the rest
      if (item.contains(dropdownToggleButton)) {
        item.classList.toggle("is-active", isActive);
      } else {
        item.classList.toggle("u-hide", isActive);
      }
    }
  }
};
 
export const setListFocusable = (list: Element) => {
  // turn on focusability for all direct children in the target dropdown
  if (list) {
    for (const item of list.children) {
      item.children[0].setAttribute("tabindex", "0");
    }
  }
};
 
export const setFocusable = (target: Element) => {
  // if target dropdown is not a list, find the list in it
  const isList =
    target.classList.contains("p-navigation__dropdown") ||
    target.classList.contains("p-navigation__items");
 
  if (!isList) {
    // find all lists in the target dropdown and make them focusable
    target.querySelectorAll(".p-navigation__dropdown").forEach((element) => {
      setListFocusable(element);
    });
  } else {
    setListFocusable(target);
  }
};
 
export const collapseDropdown = (
  dropdownToggleButton: HTMLElement,
  targetDropdown: HTMLElement
) => {
  targetDropdown.setAttribute("aria-hidden", "true");
  setActiveDropdown(dropdownToggleButton, false);
};
 
export const expandDropdown = (
  dropdownToggleButton: HTMLElement,
  targetDropdown: HTMLElement
) => {
  setActiveDropdown(dropdownToggleButton);
  targetDropdown.setAttribute("aria-hidden", "false");
  setFocusable(targetDropdown);
};
 
const toggleAnimationPlaying = (
  element: Element,
  animationDuration?: number
) => {
  const endAnimation = () => {
    element.classList.toggle("js-animation-playing", false);
  };
  element.classList.toggle("js-animation-playing", true);
  // force browser to flush all pending style and layout calculations immediately
  void (element as HTMLElement).offsetWidth;
  setTimeout(endAnimation, animationDuration);
};
 
export const setupAnimationStart = (
  elements: Element[],
  animationDuration?: number
) => {
  elements.forEach((toggle: Element) => {
    toggleAnimationPlaying(toggle.parentElement!, animationDuration);
  });
};