design-comuni-plone-theme
Version:
Volto Theme for Italia design guidelines
230 lines (204 loc) • 6.71 kB
JSX
/**
* Navigation components.
* @module components/theme/Navigation/Navigation
*/
import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { UniversalLink } from '@plone/volto/components';
import { Header, HeaderContent, HeaderToggler, Nav } from 'design-react-kit';
import { flattenToAppURL } from '@plone/volto/helpers';
import { Collapse } from 'design-comuni-plone-theme/components';
import {
MegaMenu,
MenuSecondary,
ParentSiteMenu,
TertiaryMenu,
Logo,
Icon,
SocialHeader,
BrandText,
} from 'design-comuni-plone-theme/components/ItaliaTheme';
import { getDropdownMenuNavitems, getItemsByPath } from 'volto-dropdownmenu';
import FocusLock from 'react-focus-lock';
const Navigation = ({ pathname }) => {
const intl = useIntl();
const [collapseOpen, setCollapseOpen] = useState(false);
const [focusTrapActive, setFocusTrapActive] = useState(false);
const dispatch = useDispatch();
const subsite = useSelector((state) => state.subsite?.data);
const logoSubsite = subsite?.subsite_logo && (
<figure className="icon">
<Logo />
</figure>
);
const items = useSelector((state) => state.dropdownMenuNavItems?.result);
useEffect(() => {
dispatch(getDropdownMenuNavitems());
}, [dispatch]);
const menu = getItemsByPath(items, pathname);
const getAnchorTarget = (nodeElement) => {
if (nodeElement.nodeName === 'A') {
return nodeElement;
} else if (nodeElement.parentElement?.nodeName === 'A') {
return nodeElement.parentElement;
} else {
return null;
}
};
useEffect(() => {
const blocksClickListener = (e) => {
const menuLinks = [
...(document?.querySelectorAll(
'.menu-wrapper a:not([aria-haspopup]), .menu-wrapper .it-brand-wrapper a',
) ?? []),
];
if (
menuLinks?.length === 0 ||
menuLinks?.indexOf(getAnchorTarget(e.target)) < 0
) {
return;
}
setCollapseOpen(false);
setFocusTrapActive(false);
};
document.body.addEventListener('click', blocksClickListener);
return () =>
document.body.removeEventListener('click', blocksClickListener);
}, []);
const closeButtonStyle = collapseOpen
? {
display: 'block',
}
: { display: 'none' };
return (
<Header theme="" type="navbar">
{menu?.length > 0 ? (
<HeaderContent
expand="lg"
megamenu
id="navigation"
aria-label={intl.formatMessage(messages.mainMenu)}
>
<HeaderToggler
aria-controls="it-navigation-collapse"
aria-expanded={collapseOpen}
aria-label={intl.formatMessage(messages.toggleMenu, {
action: collapseOpen
? intl.formatMessage(messages.toggleMenu_close)
: intl.formatMessage(messages.toggleMenu_open),
})}
onClick={() => {
setCollapseOpen(!collapseOpen);
setFocusTrapActive(!focusTrapActive);
}}
>
<Icon
icon="it-burger"
title={intl.formatMessage(messages.toggleMenu, {
action: collapseOpen
? intl.formatMessage(messages.toggleMenu_close)
: intl.formatMessage(messages.toggleMenu_open),
})}
/>
</HeaderToggler>
<Collapse
header
isOpen={collapseOpen}
navbar
onOverlayClick={() => setCollapseOpen(!collapseOpen)}
id="it-navigation-collapse"
showCloseButton={false}
>
<FocusLock disabled={!focusTrapActive}>
<div className="menu-wrapper">
<div className="it-brand-wrapper" role="navigation">
<UniversalLink
href={
subsite?.['@id'] ? flattenToAppURL(subsite['@id']) : '/'
}
onClick={() => setCollapseOpen(false)}
>
{subsite?.subsite_logo ? (
logoSubsite
) : (
<Logo className="icon" />
)}
<BrandText mobile={true} subsite={subsite} />
</UniversalLink>
</div>
{/* Main Menu */}
<Nav
data-element="main-navigation"
navbar
role="menubar"
aria-label={intl.formatMessage(messages.mainMenu)}
>
{menu
?.filter((item) => item.visible)
?.map((item, index) => (
<MegaMenu
item={item}
pathname={pathname}
key={index + 'mm'}
/>
))}
</Nav>
{/* Secondary Menu */}
<MenuSecondary pathname={pathname} />
{/* Headerslim Menu - main site */}
{!subsite && <TertiaryMenu />}
{/* Social Links */}
<SocialHeader />
{/* Headerslim Menu - parent site (if subsite) */}
{subsite && <ParentSiteMenu />}
</div>
<div className="close-div" style={closeButtonStyle}>
<button
className="btn close-menu"
type="button"
title={intl.formatMessage(messages.CloseMenu)}
onClick={() => setCollapseOpen(!collapseOpen)}
>
<Icon
color="white"
icon="it-close-big"
padding={false}
title={intl.formatMessage(messages.CloseMenu)}
/>
</button>
</div>
</FocusLock>
</Collapse>
</HeaderContent>
) : null}
</Header>
);
};
const messages = defineMessages({
CloseMenu: {
id: 'close-menu',
defaultMessage: 'Chiudi menu',
},
toggleMenu: {
id: 'toggle-menu',
defaultMessage: '{action} il menu',
},
toggleMenu_open: {
id: 'toggleMenu_open',
defaultMessage: 'Apri',
},
toggleMenu_close: {
id: 'toggleMenu_close',
defaultMessage: 'Chiudi',
},
mainMenu: {
id: 'mainMenu',
defaultMessage: 'Menu principale',
},
});
Navigation.propTypes = {
pathname: PropTypes.string.isRequired,
};
export default Navigation;