@dnanpm/styleguide
Version:
DNA Styleguide repository provides the set of components and theme object used in various DNA projects.
189 lines (182 loc) • 10.7 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var icons = require('@dnanpm/icons');
var React = require('react');
var reactSpring = require('react-spring');
var styledComponents = require('styled-components');
var theme = require('../../../themes/theme.js');
var navigation = require('../../../themes/themeComponents/navigation.js');
var styledUtils = require('../../../utils/styledUtils.js');
var NavContext = require('../context/NavContext.js');
var globalNavStyles = require('../globalNavStyles.js');
var LinkModifier = require('./LinkModifier.js');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
var React__default = /*#__PURE__*/_interopDefaultCompat(React);
const MobileMenuWrapper = styledComponents.styled(reactSpring.animated.div) `
width: ${100 * navigation.menuLevelsAmount}%;
display: flex;
button {
border: 0;
background: transparent;
}
`;
const mobileMenu = `calc(100vh - ${navigation.headerMaxHeight})`;
const MenuLinkBackLink = styledComponents.styled(globalNavStyles.MenuLink) ``;
const MobileMenuContainer = styledComponents.styled.nav `
width: 100%;
position: absolute;
top: ${navigation.navMaxHeight};
right: 0;
overflow: hidden;
overflow-y: auto;
transition: max-height 0.2s ease-in-out;
background-color: ${theme.default.color.background.sand.default};
max-height: ${mobileMenu};
height: ${mobileMenu};
max-width: ${navigation.mobileNavMaxWidth};
${globalNavStyles.MenuList} {
display: block;
width: ${100 / navigation.menuLevelsAmount}%;
position: relative;
border-top: 4px solid ${theme.default.color.background.white.default};
&:first-of-type {
background: ${theme.default.color.background.white.default};
> ${globalNavStyles.MenuItem} > ${globalNavStyles.MenuLink} {
font-weight: ${theme.default.fontWeight.bold};
height: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 6)};
}
}
&:not(:first-of-type) {
background: ${theme.default.color.background.sand.default};
}
${globalNavStyles.MenuItem} {
border-bottom: 1px solid ${theme.default.color.line.L04};
}
margin-bottom: ${navigation.headerMaxHeight}; // make sure items are visible in different devices which might calculate vh differently
}
${globalNavStyles.MenuLink}, ${globalNavStyles.MenuLinkWithChildren} {
line-height: ${theme.default.lineHeight.default};
padding: ${styledUtils.getMultipliedSize(theme.default.base.baseWidth, 2)};
font-size: ${theme.default.fontSize.default};
display: flex;
flex-grow: 1;
align-items: center;
height: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 5)};
&:hover {
cursor: pointer;
text-decoration: none;
}
}
${MenuLinkBackLink} {
font-weight: ${theme.default.fontWeight.bold};
background: ${theme.default.color.background.white.default};
color: ${theme.default.color.text.pink};
justify-content: flex-start;
gap: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 1)};
height: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 6)};
}
${globalNavStyles.FeaturedBlock} {
border-bottom: 1px solid ${theme.default.color.line.L04};
section > a {
font-size: ${theme.default.fontSize.s};
line-height: ${theme.default.lineHeight.s};
padding: ${styledUtils.getMultipliedSize(theme.default.base.baseHeight, 1)};
height: auto;
}
}
`;
const MenuItemBackLink = ({ currentLevel, backRef, }) => {
const { backToPreviousCategoryLabel, handleNavMenuClick, lang, menuLevel: { scrollPosition }, level1Items, level2Items, getBackLink, } = React.useContext(NavContext.default);
const menuElements = currentLevel === 2 ? level1Items : level2Items;
const tabNavigationDisabled = scrollPosition !== currentLevel - 1;
const backLink = getBackLink(menuElements, currentLevel - 1);
const mobileMenuBackClick = () => {
handleNavMenuClick(null, `level${currentLevel - 1}Mobile`);
};
return (React__default.default.createElement(globalNavStyles.MenuItem, { "data-testid": `mobile-nav-menu-backlink-level-${currentLevel}` },
React__default.default.createElement(MenuLinkBackLink, { as: "button", ref: backRef, onClick: mobileMenuBackClick, tabIndex: tabNavigationDisabled ? -1 : undefined, "aria-label": `${backToPreviousCategoryLabel} ${backLink.titles[lang]}` },
React__default.default.createElement(icons.ChevronLeft, { size: "1.5rem" }),
backLink.titles[lang])));
};
const SubMenuItem = ({ menuItem, currentLevel, itemIndex, mobileMenuRef, firstItemRef, }) => {
const { handleNavMenuClick, menuLevel, lang, currentUrl } = React.useContext(NavContext.default);
const hasChildren = !!menuItem.pages.length;
const indexLevel = currentLevel - 1;
const tabNavigationDisabled = menuLevel.scrollPosition !== indexLevel;
const menuUrl = menuItem.urls[lang];
const mobileMenuClick = (element) => (e) => {
var _a, _b;
(_b = (_a = mobileMenuRef === null || mobileMenuRef === void 0 ? void 0 : mobileMenuRef.current) === null || _a === void 0 ? void 0 : _a.scroll) === null || _b === void 0 ? void 0 : _b.call(_a, {
top: 0,
left: 0,
behavior: 'smooth',
});
e.preventDefault();
handleNavMenuClick(element.id, `level${currentLevel}Mobile`);
};
const renderMenuItem = (children) => (React__default.default.createElement(globalNavStyles.MenuItem, { key: menuItem.id, "data-testid": `mobile-menu-level-${currentLevel}-link-${itemIndex + 1}`, "$isActive": LinkModifier.isSelected(currentUrl, menuUrl, true) }, children));
if (hasChildren && currentLevel < 3) {
return renderMenuItem(React__default.default.createElement(globalNavStyles.MenuLink, { as: "button", ref: firstItemRef, onClick: mobileMenuClick(menuItem), tabIndex: tabNavigationDisabled ? -1 : undefined },
menuItem.titles[lang],
React__default.default.createElement(icons.ChevronRight, { color: theme.default.color.default.pink })));
}
return renderMenuItem(React__default.default.createElement(LinkModifier.default, { menuItem: menuItem, disabledTabIndex: tabNavigationDisabled }));
};
const SubMenuMobile = ({ currentLevel, menuItem, mobileMenuRef }) => {
const { collapseSize, featuredItemsAriaLabel, menuLevel } = React.useContext(NavContext.default);
const indexLevel = currentLevel - 1;
const tabNavigationDisabled = menuLevel.scrollPosition !== indexLevel;
const backRef = React.useRef(null);
const firstItemRef = React.useRef(null);
React.useEffect(() => {
// Delay focus to allow animation to finish
const timer = setTimeout(() => {
if (currentLevel === 1 && firstItemRef.current) {
firstItemRef.current.focus();
}
if (currentLevel > 1 && backRef.current) {
backRef.current.focus();
}
}, 300);
return () => clearTimeout(timer);
}, [menuItem, currentLevel]);
if (!(menuItem === null || menuItem === void 0 ? void 0 : menuItem.pages.length)) {
return null;
}
const featuredItems = currentLevel === 2 ? menuItem.pages.filter(subMenuItem => !subMenuItem.pages.length) : [];
const menuItems = menuItem.pages.filter(subMenuItem => !featuredItems.includes(subMenuItem));
return (React__default.default.createElement(React__default.default.Fragment, null,
currentLevel > 1 && React__default.default.createElement(MenuItemBackLink, { backRef: backRef, currentLevel: currentLevel }),
featuredItems.length > 0 && (React__default.default.createElement(globalNavStyles.FeaturedBlock, { "$collapseSize": collapseSize },
React__default.default.createElement("section", { "aria-label": featuredItemsAriaLabel }, featuredItems.map(subMenuItem => (React__default.default.createElement(LinkModifier.default, { key: subMenuItem.id, menuItem: subMenuItem, showIcon: true, disabledTabIndex: tabNavigationDisabled })))))),
menuItems.map((subMenuItem, index) => (React__default.default.createElement(SubMenuItem, { currentLevel: currentLevel, itemIndex: index, key: subMenuItem.id, menuItem: subMenuItem, mobileMenuRef: mobileMenuRef, firstItemRef: index === 0 ? firstItemRef : undefined })))));
};
const NavigationMenuMobile = ({ mobileMenuRef }) => {
const { items, menuLevel, level1Items, level2Items } = React.useContext(NavContext.default);
const { mainNavigation } = items;
if (!(mainNavigation === null || mainNavigation === void 0 ? void 0 : mainNavigation.pages.length)) {
return null;
}
const renderMenuList = (scrollPosition, level, menuItem) => (React__default.default.createElement(globalNavStyles.MenuList, { "aria-hidden": menuLevel.scrollPosition !== scrollPosition, "aria-disabled": menuLevel.scrollPosition !== scrollPosition, "data-testid": `mobile-nav-menu-level-${level}`, "$isInView": menuLevel.scrollPosition === scrollPosition }, menuLevel.scrollPosition === scrollPosition && (React__default.default.createElement(SubMenuMobile, { currentLevel: level, menuItem: menuItem, mobileMenuRef: mobileMenuRef }))));
return (React__default.default.createElement(React__default.default.Fragment, null,
renderMenuList(0, 1, mainNavigation),
menuLevel.level1Mobile !== null &&
renderMenuList(1, 2, level1Items[menuLevel.level1Mobile]),
menuLevel.level2Mobile !== null &&
renderMenuList(2, 3, level2Items[menuLevel.level2Mobile])));
};
const RenderMobileMenu = () => {
const { menuLevel, isMobileMenuOpen } = React.useContext(NavContext.default);
const mobileMenuRef = React.useRef(null);
const slidingMenuAnimation = reactSpring.useSpring({
transform: `translateX(${(menuLevel.scrollPosition / navigation.menuLevelsAmount) * -100}%)`,
});
if (!isMobileMenuOpen) {
return null;
}
return (React__default.default.createElement(MobileMenuContainer, { ref: mobileMenuRef, role: "dialog", "aria-modal": "true" },
React__default.default.createElement(MobileMenuWrapper, { style: slidingMenuAnimation },
React__default.default.createElement(NavigationMenuMobile, { mobileMenuRef: mobileMenuRef }))));
};
exports.MenuItemBackLink = MenuItemBackLink;
exports.default = RenderMobileMenu;