diff --git a/packages/components/src/navigation/README.md b/packages/components/src/navigation/README.md index 2ef74b122d314d..4ebaf1172bb810 100644 --- a/packages/components/src/navigation/README.md +++ b/packages/components/src/navigation/README.md @@ -99,7 +99,7 @@ Optional className for the `NavigationMenu` component. - Required: No - Default: "root" -The menu slug. +The unique identifier of the menu. The root menu can omit this, and it will default to "root"; all other menus need to specify it. ### `parentMenu` @@ -158,6 +158,13 @@ Optional className for the `NavigationItem` component. If provided, renders `a` instead of `button`. +### `item` + +- Type: `string` +- Required: Yes + +The unique identifier of the item. + ### `navigateToMenu` - Type: `string` diff --git a/packages/components/src/navigation/context.js b/packages/components/src/navigation/context.js index ac057888a81802..c283c3899a89fe 100644 --- a/packages/components/src/navigation/context.js +++ b/packages/components/src/navigation/context.js @@ -17,5 +17,17 @@ export const NavigationContext = createContext( { activeItem: undefined, activeMenu: ROOT_MENU, setActiveMenu: noop, + + navigationTree: { + items: {}, + getItem: noop, + addItem: noop, + removeItem: noop, + + menus: {}, + getMenu: noop, + addMenu: noop, + removeMenu: noop, + }, } ); export const useNavigationContext = () => useContext( NavigationContext ); diff --git a/packages/components/src/navigation/group.js b/packages/components/src/navigation/group/index.js similarity index 61% rename from packages/components/src/navigation/group.js rename to packages/components/src/navigation/group/index.js index a1293d0c65a077..ba2b3a2ad13b91 100644 --- a/packages/components/src/navigation/group.js +++ b/packages/components/src/navigation/group/index.js @@ -6,9 +6,17 @@ import classnames from 'classnames'; /** * Internal dependencies */ -import { GroupTitleUI } from './styles/navigation-styles'; +import { GroupTitleUI } from '../styles/navigation-styles'; +import { useNavigationMenuContext } from '../menu/context'; export default function NavigationGroup( { children, className, title } ) { + const { isActive } = useNavigationMenuContext(); + + // Keep the children rendered to make sure inactive items are included in the navigation tree + if ( ! isActive ) { + return children; + } + const classes = classnames( 'components-navigation__group', className ); return ( diff --git a/packages/components/src/navigation/index.js b/packages/components/src/navigation/index.js index f5742def52763f..4919eca4861d67 100644 --- a/packages/components/src/navigation/index.js +++ b/packages/components/src/navigation/index.js @@ -16,6 +16,7 @@ import Animate from '../animate'; import { ROOT_MENU } from './constants'; import { NavigationContext } from './context'; import { NavigationUI } from './styles/navigation-styles'; +import { useCreateNavigationTree } from './use-create-navigation-tree'; export default function Navigation( { activeItem, @@ -26,6 +27,7 @@ export default function Navigation( { } ) { const [ menu, setMenu ] = useState( activeMenu ); const [ slideOrigin, setSlideOrigin ] = useState(); + const navigationTree = useCreateNavigationTree(); const setActiveMenu = ( menuId, slideInOrigin = 'left' ) => { setSlideOrigin( slideInOrigin ); @@ -51,6 +53,7 @@ export default function Navigation( { activeItem, activeMenu: menu, setActiveMenu, + navigationTree, }; const classes = classnames( 'components-navigation', className ); diff --git a/packages/components/src/navigation/item.js b/packages/components/src/navigation/item/index.js similarity index 54% rename from packages/components/src/navigation/item.js rename to packages/components/src/navigation/item/index.js index 33cb7ae48c48bc..53aab5ff75acb0 100644 --- a/packages/components/src/navigation/item.js +++ b/packages/components/src/navigation/item/index.js @@ -12,22 +12,34 @@ import { Icon, chevronRight } from '@wordpress/icons'; /** * Internal dependencies */ -import Button from '../button'; -import { useNavigationContext } from './context'; -import { ItemBadgeUI, ItemTitleUI, ItemUI } from './styles/navigation-styles'; +import Button from '../../button'; +import { useNavigationContext } from '../context'; +import { ItemBadgeUI, ItemTitleUI, ItemUI } from '../styles/navigation-styles'; +import { useNavigationTreeItem } from './use-navigation-tree-item'; +import { useNavigationMenuContext } from '../menu/context'; -export default function NavigationItem( { - badge, - children, - className, - href, - item, - navigateToMenu, - onClick = noop, - title, - ...props -} ) { +export default function NavigationItem( props ) { + const { + badge, + children, + className, + href, + item, + navigateToMenu, + onClick = noop, + title, + ...restProps + } = props; + useNavigationTreeItem( props ); const { activeItem, setActiveMenu } = useNavigationContext(); + const { isActive } = useNavigationMenuContext(); + + // If this item is in an inactive menu, then we skip rendering + // We need to make sure this component gets mounted though + // To make sure inactive items are included in the navigation tree + if ( ! isActive ) { + return null; + } const classes = classnames( 'components-navigation__item', className, { 'is-active': item && activeItem === item, @@ -44,7 +56,7 @@ export default function NavigationItem( { return ( { children || ( -