Skip to content

Commit

Permalink
feat(header): L3-4484 added close menu functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
constantinehuzenko committed Nov 8, 2024
1 parent 7a0ff41 commit 4d26986
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 13 deletions.
15 changes: 14 additions & 1 deletion src/components/Navigation/NavigationItem/NavigationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import classNames from 'classnames';
import Link, { LinkProps } from '../../Link/Link';
import { LinkVariants } from '../../Link/types';
import { ComponentProps, ElementType, forwardRef, ReactNode } from 'react';
import React from 'react';
import { HeaderContext } from '../../../site-furniture/Header/Header';

export interface NavigationItemProps extends ComponentProps<'li'> {
/**
Expand Down Expand Up @@ -33,6 +35,10 @@ export interface NavigationItemProps extends ComponentProps<'li'> {
* Element to render within the navigation item, renders <Link> by default
*/
element?: ElementType<LinkProps>;
/**
* Function to close the submenu
*/
closeSubmenu?: () => void;
}

/**
Expand All @@ -55,15 +61,22 @@ const NavigationItem = forwardRef<HTMLLIElement, NavigationItemProps>(
navGroup,
navType,
onClick,
closeSubmenu,
element: Component = Link,
...props
},
ref,
) => {
const { closeMenu } = React.useContext(HeaderContext);

return (
<li
{...props}
onClick={onClick}
onClick={(e) => {
closeMenu?.();
closeSubmenu?.();
onClick?.(e);
}}
data-testid={`nav-item-${label}`}
className={classNames(`${px}-nav__item`, navGroup, className, {
[`view-all`]: isViewAllLink,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const NavigationItemTrigger = forwardRef<HTMLLIElement, NavigationItemTriggerPro
const { className: baseClassName, ...commonProps } = getCommonProps({ id }, 'NavigationItemTrigger');
const [isSubmenuOpened, setIsSubmenuOpened] = useState(false);
const navListElement = findChildrenOfType<NavigationListProps>(children, NavigationList);
const closeSubmenu = () => setIsSubmenuOpened(false);

return (
<>
Expand Down Expand Up @@ -74,7 +75,7 @@ const NavigationItemTrigger = forwardRef<HTMLLIElement, NavigationItemTriggerPro
<Text variant={TextVariants.snwHeaderLink}>{label}</Text>
</button>
{navListElement
? React.cloneElement(navListElement[0], { className: `${baseClassName}__submenu` })
? React.cloneElement(navListElement[0], { className: `${baseClassName}__submenu`, closeSubmenu })
: undefined}
</li>
</SSRMediaQuery.Media>
Expand Down
38 changes: 27 additions & 11 deletions src/components/Navigation/NavigationList/NavigationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,36 @@ export interface NavigationListProps extends React.ComponentProps<'ul'> {
* Optional right section heading
*/
rightSectionHeading?: string;
/**
* Function to close the submenu
*/
closeSubmenu?: () => void;
}

const NavigationList = React.forwardRef<HTMLUListElement, NavigationListProps>(
({ id, children, className, isOffScreen, leftSectionHeading, rightSectionHeading }, ref) => {
const leftSectionItems = React.Children.toArray(children).filter((child) => {
if (child && (child as React.ReactElement<NavigationItemProps>).props.navGroup === 'nav-link-start') {
return child;
}
});
const rightSectionItems = React.Children.toArray(children).filter((child) => {
if (child && (child as React.ReactElement<NavigationItemProps>).props.navGroup === 'nav-link-end') {
return child;
}
});
({ id, children, className, isOffScreen, leftSectionHeading, rightSectionHeading, closeSubmenu }, ref) => {
const leftSectionItems = React.Children.toArray(children)
.map((child) => {
if (
React.isValidElement(child) &&
(child as React.ReactElement<NavigationItemProps>).props.navGroup === 'nav-link-start'
) {
return React.cloneElement(child as React.ReactElement<NavigationItemProps>, { closeSubmenu });
}
})
.filter(Boolean);

const rightSectionItems = React.Children.toArray(children)
.map((child) => {
if (
React.isValidElement(child) &&
(child as React.ReactElement<NavigationItemProps>).props.navGroup === 'nav-link-end'
) {
return React.cloneElement(child as React.ReactElement<NavigationItemProps>, { closeSubmenu });
}
})
.filter(Boolean);

return (
<ul
aria-hidden={isOffScreen}
Expand Down
6 changes: 6 additions & 0 deletions src/site-furniture/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export type HeaderContextType = {
* Set the search expanded state
*/
setIsSearchExpanded: React.Dispatch<React.SetStateAction<boolean>>;
/**
* Close the mobile menu
* */
closeMenu?: () => void;
};

export const HeaderContext = createContext<HeaderContextType>(defaultHeaderContext);
Expand Down Expand Up @@ -83,6 +87,7 @@ const Header = forwardRef<HTMLElement, HeaderProps>(
const handleMenuToggle = function () {
setIsMenuOpen((prev) => !prev);
};
const closeMenu = () => setIsMenuOpen(false);

return (
<header {...props} className={classnames(`${px}-header`, className)} ref={ref}>
Expand Down Expand Up @@ -118,6 +123,7 @@ const Header = forwardRef<HTMLElement, HeaderProps>(
isMenuOpen,
isSearchExpanded,
setIsSearchExpanded,
closeMenu,
} as HeaderContextType
}
>
Expand Down

0 comments on commit 4d26986

Please sign in to comment.