import { Component, createContext, createRef } from 'react'; import styles from '@patternfly/react-styles/css/components/Nav/nav'; import { css } from '@patternfly/react-styles'; import { getOUIAProps, OUIAProps } from '../../helpers'; import { SSRSafeIds } from '../../helpers/SSRSafeIds/SSRSafeIds'; export type NavSelectClickHandler = ( event: React.FormEvent, itemId: number | string, groupId: number | string, to: string ) => void; export interface NavProps extends Omit, HTMLElement>, 'onSelect' | 'onToggle'>, OUIAProps { /** Anything that can be rendered inside of the nav */ children?: React.ReactNode; /** Additional classes added to the container */ className?: string; /** Callback for updating when item selection changes */ onSelect?: ( event: React.FormEvent, selectedItem: { groupId: number | string; itemId: number | string; to: string; } ) => void; /** Callback for when a list is expanded or collapsed */ onToggle?: ( event: React.MouseEvent, toggledItem: { groupId: number | string; isExpanded: boolean; } ) => void; /** Accessible label for the nav when there are multiple navs on the page */ 'aria-label'?: string; /** The nav variant to use. Docked is in beta. */ variant?: 'default' | 'horizontal' | 'horizontal-subnav' | 'docked'; /** @beta Flag indicating the docked nav should display text. Only applies when variant is docked. */ isTextExpanded?: boolean; /** Value to overwrite the randomly generated data-ouia-component-id.*/ ouiaId?: number | string; /** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */ ouiaSafe?: boolean; } export interface NavContextProps { onSelect?: ( event: React.FormEvent, groupId: number | string, itemId: number | string, to: string, preventDefault: boolean, onClick: NavSelectClickHandler ) => void; onToggle?: (event: React.MouseEvent, groupId: number | string, expanded: boolean) => void; updateIsScrollable?: (isScrollable: boolean) => void; isHorizontal?: boolean; flyoutRef?: React.Ref; setFlyoutRef?: (ref: React.Ref) => void; navRef?: React.RefObject; } export const navContextDefaults = {}; export const NavContext = createContext(navContextDefaults); class Nav extends Component | null }> { static displayName = 'Nav'; static defaultProps: NavProps = { onSelect: () => undefined, onToggle: () => undefined, ouiaSafe: true }; state = { isScrollable: false, flyoutRef: null as React.Ref }; navRef = createRef(); // Callback from NavItem onSelect( event: React.FormEvent, groupId: number | string, itemId: number | string, to: string, preventDefault: boolean, onClick: NavSelectClickHandler ) { if (preventDefault) { event.preventDefault(); } this.props.onSelect(event, { groupId, itemId, to }); if (onClick) { onClick(event, itemId, groupId, to); } } // Callback from NavExpandable onToggle(event: React.MouseEvent, groupId: number | string, toggleValue: boolean) { this.props.onToggle(event, { groupId, isExpanded: toggleValue }); } render() { const { 'aria-label': ariaLabel, children, className, // eslint-disable-next-line @typescript-eslint/no-unused-vars onSelect, // eslint-disable-next-line @typescript-eslint/no-unused-vars onToggle, ouiaId, ouiaSafe, variant, isTextExpanded = false, ...props } = this.props; const isHorizontal = ['horizontal', 'horizontal-subnav'].includes(variant); const isDocked = variant === 'docked'; return ( {(_, generatedOuiaId) => ( , groupId: number | string, itemId: number | string, to: string, preventDefault: boolean, onClick: ( e: React.FormEvent, itemId: number | string, groupId: number | string, to: string ) => void ) => this.onSelect(event, groupId, itemId, to, preventDefault, onClick), onToggle: (event: React.MouseEvent, groupId: number | string, expanded: boolean) => this.onToggle(event, groupId, expanded), updateIsScrollable: (isScrollable: boolean) => this.setState({ isScrollable }), isHorizontal: ['horizontal', 'horizontal-subnav'].includes(variant), flyoutRef: this.state.flyoutRef, setFlyoutRef: (flyoutRef) => this.setState({ flyoutRef }), navRef: this.navRef }} > )} ); } } export { Nav };