import React , { cloneElement , isValidElement , useEffect } from 'react' ; import 'hds-core' ; import styles from './SideNavigation.module.scss' ; import SideNavigationContext from './SideNavigationContext' ; import { FCWithName } from '../../common/types' ; import classNames from '../../utils/classNames' ; import { useMobile } from '../../hooks/useMobile' ; import { Button } from '../button' ; import { IconAngleDown , IconAngleUp } from '../../icons' ; import { MainLevel } from './mainLevel/MainLevel' ; import { SubLevel } from './subLevel/SubLevel' ; import { useTheme } from '../../hooks/useTheme' ; export interface SideNavigationCustomTheme { '--side-navigation-background-color' ? : string ; '--side-navigation-active-indicator-background-color' ? : string ; '--side-navigation-icon-size' ? : string ; '--side-navigation-level-border-color' ? : string ; '--side-navigation-level-border-color-focus' ? : string ; '--side-navigation-level-border-color-hover' ? : string ; '--side-navigation-level-background-color' ? : string ; '--side-navigation-level-background-color-active' ? : string ; '--side-navigation-level-background-color-hover' ? : string ; '--side-navigation-level-color' ? : string ; '--side-navigation-level-color-active' ? : string ; '--side-navigation-level-color-hover' ? : string ; '--side-navigation-mobile-menu-border-color' ? : string ; '--side-navigation-mobile-menu-z-index' ? : number ; } export type SideNavigationProps = React . PropsWithChildren < { /**
     * Additional class names to apply to the side navigation
     */ className ? : string ; /**
     * Default value for open main levels
     */ defaultOpenMainLevels ? : number [ ] ; /**
     * The id of the side navigation.
     */ id : string ; /**
     * Override or extend the styles applied to the component
     */ style ? : React . CSSProperties ; /**
     * Custom theme styles
     */ theme ? : SideNavigationCustomTheme ; /**
     * label for the mobile menu toggle button
     */ toggleButtonLabel : string ; } > ; export const SideNavigation = ( { children , className , defaultOpenMainLevels = [ ] , id , style , theme , toggleButtonLabel , } ) => { const container = React . useRef < HTMLDivElement > ( null ) ; const customThemeClass = useTheme < SideNavigationCustomTheme > ( styles . sideNavigation , theme ) ; const menuId = `${ id }-menu` ; const [ activeParentLevel , setActiveParentLevel ] = React . useState < number > ( ) ; const [ mobileMenuOpen , setMobileMenuOpen ] = React . useState ( false ) ; const isMobile = useMobile ( ) ; const mainLevels = React . Children . map ( children , ( child , index ) => { if ( isValidElement ( child ) && ( child . type as FCWithName ) . componentName === 'MainLevel' ) { return cloneElement ( child , { index } ) ; } return null ; } ) ; const toggleMobileMenu = ( ) => { setMobileMenuOpen ( ! mobileMenuOpen ) ; } ; useEffect ( ( ) => { const handleEscKey = ( event ) => { const key = event . key || event . keyCode ; if ( mobileMenuOpen && ( key === 'Escape' || key === 'Esc' || key === 27 ) ) { setMobileMenuOpen ( false ) ; } } ; const handleOutsideClickOrFocusin = ( event ) => { const target = event . target as Node ; if ( mobileMenuOpen && ! container . current . contains ( target ) ) { setMobileMenuOpen ( false ) ; } } ; document . addEventListener ( 'click' , handleOutsideClickOrFocusin ) ; document . addEventListener ( 'focusin' , handleOutsideClickOrFocusin ) ; document . addEventListener ( 'keyup' , handleEscKey ) ; return ( ) => { document . removeEventListener ( 'click' , handleOutsideClickOrFocusin ) ; document . removeEventListener ( 'focusin' , handleOutsideClickOrFocusin ) ; document . removeEventListener ( 'keyup' , handleEscKey ) ; } ; } ) ; return ( < SideNavigationContext . Provider value = { { mobileMenuOpen , defaultOpenMainLevels , activeParentLevel , setMobileMenuOpen , setActiveParentLevel , } } > < nav className = { classNames ( styles . sideNavigation , customThemeClass , className ) } id = { id } ref = { container } style = { style } > { } < Button aria - controls = { menuId } aria - expanded = { mobileMenuOpen } aria - haspopup className = { styles . toggleButton } fullWidth iconRight = { mobileMenuOpen ? < IconAngleUp aria - hidden / > : < IconAngleDown aria - hidden / > } onClick = { toggleMobileMenu } variant = "secondary" type = "button" > { toggleButtonLabel } < /Button> < ul { ... { className : classNames ( styles . mainLevelList , mobileMenuOpen && styles . open ) , 'aria-label' : toggleButtonLabel , 'aria-hidden' : isMobile && ! mobileMenuOpen , } } id = { menuId } > { mainLevels } < /ul> < /nav> < /SideNavigationContext.Provider>); } ; SideNavigation . MainLevel = MainLevel ; SideNavigation . SubLevel = SubLevel ;