import { useResizeObserver } from '@planview/pv-utilities' import * as React from 'react' import { RovingTabIndexProvider } from '../react-roving-tabindex' import { defineMessages, useIntl } from 'react-intl' import { ToolbarSeparator } from '..' import { getBreakPoint, shouldDisplayAtBreakpoint } from '../utils' import type { ResizeContextType, UserMenuConfig } from '../utils/context' import ResizeContext, { MainNavigationContext, UserMenuContext, } from '../utils/context' import { LeftWrap, NavigationBarStaticWrap, RightWrap, StyledNavigationBar, } from './styles' import { UserMenuInternal as UserMenu } from './user-menu' import { useMergeRefs } from '../utils/refs' const messages = defineMessages({ userMenu: { id: 'pvds.toolbar.navigation.userMenu', defaultMessage: 'User menu', description: 'Label for user menu (tooltip and label in dropdown)', }, }) export type NavigationBarProps = { /** * Product logo: Can be one of the logos shipped in this library or custom element. If using custom logo make sure to hook logo up to navigation using `ToolbarItem` */ logo?: React.JSX.Element /** * Customizable content of the navigation (between product logo and user menu). * * The content should be grouped in one `ToolbarSectionLeft` (wrapping content to the left) and one `ToolbarSectionRight` (wrapping content to the right) * */ children: React.ReactNode /** * Element to inject ApplicationSwitcher to the correct place in the navigation bar */ productSwitcher?: React.JSX.Element /** * If the left most separator should be displayed, defaults to true. * * it is [best practice](https://design.planview.com/components/navigation/navigation-bar#left-section) to remove the separator when there is nothing to display in the left content of the main navigation. */ showLogoSeparator?: boolean } & React.HTMLAttributes const NavigationBarImpl: React.ForwardRefRenderFunction< HTMLElement | undefined, NavigationBarProps > = ( { logo, children, productSwitcher, showLogoSeparator = true, ...rest }, ref ) => { const { formatMessage } = useIntl() const wrapperRef = React.useRef(undefined) const { width } = useResizeObserver({ ref: wrapperRef }) const initialized = !!width const { breakpoint, showLabels, showSeparators } = getBreakPoint(width) const [userMenu, setUserMenu] = React.useState(null) const userMenuState = React.useMemo( () => ({ add: (config: UserMenuConfig) => setUserMenu(config), remove: () => setUserMenu(null), }), [] ) const resizeContext = React.useMemo( () => ({ initialized, breakpoint, showLabels, showSeparators, shouldDisplay: (displayOn) => shouldDisplayAtBreakpoint(breakpoint, displayOn), }), [breakpoint, showLabels, showSeparators, initialized] ) const mergedRefs = useMergeRefs([ref, wrapperRef]) return ( {!!logo || !!productSwitcher ? ( {productSwitcher} {logo} {showLogoSeparator && ( )} ) : null} {children} {userMenu ? ( {userMenu.children} ) : null} ) } /** * The NavigationBar implements the [design system specification](https://design.planview.com/components/navigation/navigation-bar/anatomy) * * `import { NavigationBar } from '@planview/pv-toolbar'` * * ### Accessibility * This component will add a [navigation landmark](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/navigation.html) to your application which will serve as a single tab-stop for easy keyboard navigation. * Having [landmarks](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/) will help user using assistive technology jump quicker between the different landmarks on the page. * * If you have more than one navigation on your page at the same time it is considered good practice to add `aria-label` attributes on the navigation landmarks * * */ export const NavigationBar = React.forwardRef(NavigationBarImpl)