UNPKG

@massds/mayflower-react

Version:

React versions of Mayflower design system UI components

300 lines (295 loc) 12.7 kB
import React from "react"; import propTypes from "prop-types"; import GoogleTranslateElement from "../GoogleTranslateElement/index.mjs"; import DecorativeLink from "../DecorativeLink/index.mjs"; import IconBuilding from "../Icon/IconBuilding.mjs"; import IconLogin from "../Icon/IconLogin.mjs"; import useWindowWidth from "../hooks/use-window-width.mjs"; import nanoid from "nanoid"; import UtilityNavData from "./UtilityNav.data"; const PanelItem = _ref => { let narrow = _ref.narrow, _ref$title = _ref.title, title = _ref$title === void 0 ? '' : _ref$title, CustomIcon = _ref.CustomIcon, _ref$description = _ref.description, description = _ref$description === void 0 ? '' : _ref$description, _ref$ariaLabel = _ref.ariaLabel, ariaLabel = _ref$ariaLabel === void 0 ? '' : _ref$ariaLabel, _ref$links = _ref.links, links = _ref$links === void 0 ? [] : _ref$links; const windowWidth = useWindowWidth(); const isMobileWindow = windowWidth !== null && windowWidth < 860; const loginToggleRef = React.useRef(); const loginContentRef = React.useRef(); const loginCloseRef = React.useRef(); const loginContainerRef = React.useRef(); React.useEffect(() => { const utilButton = loginToggleRef.current; const utilCloseButton = loginCloseRef.current; const utilContent = loginContentRef.current; const utilContainer = utilContent ? loginContainerRef.current : null; let narrowUtilContentOpen = false; const closeUtilWideContent = () => { // Content state utilContent.style.height = '0'; utilContent.style.opacity = '0'; utilContent.classList.add('is-closed'); utilContent.setAttribute('aria-hidden', 'true'); // Close button state utilCloseButton.setAttribute('aria-expanded', 'false'); // Utility button state utilButton.setAttribute('aria-expanded', 'false'); utilButton.setAttribute('aria-pressed', 'false'); const closestHamburgerNav = utilButton.closest('.ma__header__hamburger__nav'); if (closestHamburgerNav) { closestHamburgerNav.classList.toggle('util-nav-content-open'); } }; const closeNarrowUtilContent = () => { utilButton.setAttribute('aria-expanded', 'false'); utilContent.setAttribute('aria-hidden', 'true'); utilContainer.style.pointerEvents = 'none'; utilContent.style.maxHeight = '0'; utilContainer.style.opacity = '0'; setTimeout(() => { utilContainer.removeAttribute('style'); utilContent.classList.add('is-closed'); }, 500); narrowUtilContentOpen = false; }; const openNarrowUtilContent = () => { closeSubMenu(); utilButton.setAttribute('aria-expanded', 'true'); utilContent.removeAttribute('aria-hidden'); utilContainer.style.pointerEvents = 'none'; /** Slide down. */ utilContainer.removeAttribute('style'); /** Show the content. */ utilContent.classList.remove('is-closed'); utilContent.style.maxHeight = 'auto'; /** Get the computed height of the content. */ const contentHeight = utilContent.querySelector('.ma__utility-nav__content-body').clientHeight + "px"; /** Set the height of the submenu as 0px, */ /** so we can trigger the slide down animation. */ utilContent.style.maxHeight = '0'; utilContent.style.Height = '0'; // These height settings display the bottom border of the parent li at the correct spot. utilContent.style.height = contentHeight; utilContainer.style.height = contentHeight; utilContent.style.maxHeight = contentHeight; utilContainer.style.opacity = '1'; narrowUtilContentOpen = true; }; const utilButtonNarrowKeyDown = e => { const isUtilClosed = utilContent.classList.contains('is-closed'); if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { openNarrowUtilContent(); const utilItems = utilContent.querySelectorAll('.ma__utility-panel__item a'); const focusedElement = document.activeElement; let focusIndexInDropdown = Array.from(utilItems).findIndex(link => link === focusedElement); const utilItemsCount = utilItems.length; if (e.key === 'ArrowDown') { if (!narrowUtilContentOpen) { focusIndexInDropdown = 0; } else { focusIndexInDropdown += 1; } } else if (!narrowUtilContentOpen) { focusIndexInDropdown = utilItemsCount - 1; } else { focusIndexInDropdown -= 1; } focusIndexInDropdown = (focusIndexInDropdown + utilItemsCount) % utilItemsCount; utilItems[focusIndexInDropdown].focus(); } if (e.key === 'Escape' && !isUtilClosed) { // If the utility accordion is open, escape key closes the utility accordion and sets focus on the utility toggle button // Hamburger menu escape is handled in useHamburgerNavKeydown hook closeNarrowUtilContent(); utilButton.focus(); } }; const utilButtonNarrowClick = () => { if (utilContent.classList.contains('is-closed')) { openNarrowUtilContent(); } else { closeNarrowUtilContent(); } }; const utilButtonWideClick = e => { const thisWideButton = e.target.closest('.js-util-nav-toggle'); const thisWideContent = thisWideButton.nextElementSibling; if (thisWideContent.classList.contains('is-closed')) { const closestHamburgerNav = thisWideButton.closest('.ma__header__hamburger__nav'); if (closestHamburgerNav) { closestHamburgerNav.classList.add('util-nav-content-open'); } thisWideContent.classList.remove('is-closed'); thisWideContent.removeAttribute('aria-hidden'); thisWideContent.removeAttribute('style'); thisWideContent.style.height = 'auto'; thisWideContent.style.opacity = '1'; // Button State thisWideButton.setAttribute('aria-expanded', 'true'); thisWideButton.setAttribute('aria-pressed', 'true'); } thisWideButton.setAttribute('aria-expanded', 'true'); thisWideButton.setAttribute('aria-pressed', 'true'); }; function closeSubMenu() { const openSubMenu = document.querySelector('.submenu-open'); if (openSubMenu) { const openSubMenuButton = openSubMenu.querySelector('.js-main-nav-hamburger__top-link'); const openSubMenuContent = openSubMenu.querySelector('.js-main-nav-hamburger-content'); const openSubMenuContainer = openSubMenu.querySelector('.js-main-nav-hamburger__container'); openSubMenuButton.setAttribute('aria-expanded', 'false'); openSubMenuContent.style.height = '0'; openSubMenuContainer.style.opacity = '0'; openSubMenuContent.classList.add('is-closed'); openSubMenu.removeAttribute('style'); openSubMenu.classList.remove('submenu-open'); } } if (utilButton && utilCloseButton && utilContent && utilContainer) { // Open if (!isMobileWindow) { utilContent.removeAttribute('style'); utilContainer.removeAttribute('style'); utilButton.addEventListener('click', utilButtonWideClick); utilCloseButton.addEventListener('click', closeUtilWideContent); } else { utilContent.style.maxHeight = '0'; utilContainer.style.opacity = '0'; utilButton.addEventListener('click', utilButtonNarrowClick); utilButton.addEventListener('keydown', utilButtonNarrowKeyDown); utilContent.addEventListener('keydown', utilButtonNarrowKeyDown); } } return () => { utilButton.removeEventListener('click', utilButtonWideClick); utilCloseButton.removeEventListener('click', closeUtilWideContent); utilButton.removeEventListener('click', utilButtonNarrowClick); utilButton.removeEventListener('keydown', utilButtonNarrowKeyDown); utilContent.removeEventListener('keydown', utilButtonNarrowKeyDown); }; }, [isMobileWindow, narrow, loginToggleRef, loginCloseRef, loginContentRef, loginContainerRef]); return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", { ref: loginToggleRef, type: "button", className: "ma__utility-nav__link js-util-nav-toggle", "aria-haspopup": "true", "aria-label": ariaLabel, "aria-expanded": "false" }, CustomIcon && /*#__PURE__*/React.createElement(CustomIcon, { height: 20, width: 18 }), title && title.length > 0 && /*#__PURE__*/React.createElement("span", null, title), /*#__PURE__*/React.createElement("span", { className: "toggle-indicator", "aria-hidden": "true" })), /*#__PURE__*/React.createElement("div", { ref: loginContentRef, "aria-hidden": "true", className: "ma__utility-nav__content js-util-nav-content is-closed" }, /*#__PURE__*/React.createElement("div", { ref: loginContainerRef, className: "ma__utility-nav__container" }, /*#__PURE__*/React.createElement("div", { className: "ma__utility-nav__content-title" }, /*#__PURE__*/React.createElement("button", { ref: loginCloseRef, type: "button", className: "ma__utility-nav__close js-close-util-nav" }, /*#__PURE__*/React.createElement("span", null, "Close"), /*#__PURE__*/React.createElement("span", { className: "ma__utility-nav__close-icon", "aria-hidden": "true" }, "+")), CustomIcon && /*#__PURE__*/React.createElement(CustomIcon, { height: 20, width: 18 }), title && title.length > 0 && /*#__PURE__*/React.createElement("h2", null, title)), /*#__PURE__*/React.createElement("div", { className: "ma__utility-nav__content-body" }, /*#__PURE__*/React.createElement("div", { className: "ma__utility-panel" }, description && description.length > 0 && /*#__PURE__*/React.createElement("div", { className: "ma__utility-panel__description ma__utility-panel__description--full" }, /*#__PURE__*/React.createElement("div", { className: "ma__rich-text" }, /*#__PURE__*/React.createElement("p", null, description))), /*#__PURE__*/React.createElement("ul", { className: "ma__utility-panel__items" }, links.length > 0 && links.map(link => /*#__PURE__*/React.createElement("li", { className: "ma__utility-panel__item js-clickable", key: "util_panel_item_" + nanoid() }, /*#__PURE__*/React.createElement(DecorativeLink, link))))))))); }; PanelItem.propTypes = process.env.NODE_ENV !== "production" ? { narrow: propTypes.bool, title: propTypes.string, CustomIcon: propTypes.elementType, description: propTypes.string, ariaLabel: propTypes.string, links: propTypes.arrayOf(propTypes.shape({ text: propTypes.string, href: propTypes.string, type: propTypes.string })) } : {}; export const LoginItem = _ref2 => { let _ref2$data = _ref2.data, data = _ref2$data === void 0 ? UtilityNavData.loginItem : _ref2$data; const _data$panel = data.panel, links = _data$panel.links, description = _data$panel.description, text = data.text, ariaLabel = data.ariaLabel; return /*#__PURE__*/React.createElement(PanelItem, { links: links, title: text, CustomIcon: IconLogin, description: description, ariaLabel: ariaLabel }); }; LoginItem.propTypes = process.env.NODE_ENV !== "production" ? { data: propTypes.shape({ panel: propTypes.shape({ description: propTypes.string, links: propTypes.arrayOf(propTypes.shape({ href: propTypes.string, text: propTypes.string, type: propTypes.string })) }), text: propTypes.string, ariaLabel: propTypes.string }) } : {}; export const TranslateItem = () => { const windowWidth = useWindowWidth(); return /*#__PURE__*/React.createElement(React.Fragment, null, windowWidth && windowWidth > 840 && /*#__PURE__*/React.createElement("div", { className: "ma__utility-nav__translate" }, /*#__PURE__*/React.createElement(GoogleTranslateElement, { id: "google-translate-id" }))); }; export const StateItem = _ref3 => { let _ref3$data = _ref3.data, data = _ref3$data === void 0 ? UtilityNavData.stateItem : _ref3$data; const link = data.link, ariaLabel = data.ariaLabel, text = data.text; return /*#__PURE__*/React.createElement("a", { className: "ma__utility-nav__link direct-link", href: link, "aria-label": ariaLabel }, /*#__PURE__*/React.createElement(IconBuilding, { height: 20, width: 18 }), /*#__PURE__*/React.createElement("span", null, text)); }; StateItem.propTypes = process.env.NODE_ENV !== "production" ? { data: propTypes.shape({ link: propTypes.string, text: propTypes.string, ariaLabel: propTypes.string }) } : {};