Skip to content

Commit

Permalink
[NavigationMenu] Add Portal
Browse files Browse the repository at this point in the history
  • Loading branch information
zephyr-dassouli committed Dec 4, 2024
1 parent 4584a37 commit 4f29a01
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
49 changes: 49 additions & 0 deletions packages/react/navigation-menu/src/NavigationMenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,55 @@ export const Submenus = () => {
);
};

export const WithPortalContainer = () => {
const [portalContainer, setPortalContainer] = React.useState<HTMLDivElement | null>(null);

return (
<StoryFrame>
<NavigationMenu.Root>
<div data-portal-container="" ref={setPortalContainer} />
<NavigationMenu.List className={mainListClass()}>
<NavigationMenu.Item className={expandableItemClass()}>
<TriggerWithIndicator>Portaled Products</TriggerWithIndicator>
<NavigationMenu.Portal container={portalContainer}>
<NavigationMenu.Content className={basicContentClass()}>
<LinkGroup
bordered={false}
items={[
'Fusce pellentesque',
'Aliquam porttitor',
'Pellentesque',
'Fusce pellentesque',
'Aliquam porttitor',
'Pellentesque',
]}
/>
</NavigationMenu.Content>
</NavigationMenu.Portal>
</NavigationMenu.Item>

<NavigationMenu.Item className={expandableItemClass()}>
<TriggerWithIndicator>Not Portaled Products</TriggerWithIndicator>
<NavigationMenu.Content className={basicContentClass()}>
<LinkGroup
bordered={false}
items={[
'Fusce pellentesque',
'Aliquam porttitor',
'Pellentesque',
'Fusce pellentesque',
'Aliquam porttitor',
'Pellentesque',
]}
/>
</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu.Root>
</StoryFrame>
);
};

/* -----------------------------------------------------------------------------------------------*/

const StoryFrame: React.FC<{ children: React.ReactNode }> = ({ children }) => {
Expand Down
48 changes: 48 additions & 0 deletions packages/react/navigation-menu/src/NavigationMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { usePrevious } from '@radix-ui/react-use-previous';
import { useLayoutEffect } from '@radix-ui/react-use-layout-effect';
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
import * as VisuallyHiddenPrimitive from '@radix-ui/react-visually-hidden';
import { Portal as PortalPrimitive } from '@radix-ui/react-portal';

import type { Scope } from '@radix-ui/react-context';

Expand Down Expand Up @@ -1100,6 +1101,49 @@ const FocusGroup = React.forwardRef<FocusGroupElement, FocusGroupProps>(
}
);

/* -------------------------------------------------------------------------------------------------
* NaviationMenuPortal
* -----------------------------------------------------------------------------------------------*/

const PORTAL_NAME = 'NavigationMenuPortal';

type PortalContextValue = { forceMount?: true };
const [PortalProvider] = createNavigationMenuContext<PortalContextValue>(PORTAL_NAME, {
forceMount: undefined,
});

type PortalProps = React.ComponentPropsWithoutRef<typeof PortalPrimitive>;
interface NavigationMenuPortalProps {
children?: React.ReactNode;
/**
* Specify a container element to portal the content into.
*/
container?: PortalProps['container'];
/**
* Used to force mounting when more control is needed. Useful when
* controlling animation with React animation libraries.
*/
forceMount?: true;
}

const NavigationMenuPortal: React.FC<NavigationMenuPortalProps> = (
props: ScopedProps<NavigationMenuContentProps>
) => {
const { __scopeNavigationMenu, forceMount, children } = props;
const context = useNavigationMenuContext(PORTAL_NAME, __scopeNavigationMenu);
return (
<PortalProvider scope={__scopeNavigationMenu} forceMount={forceMount}>
{React.Children.map(children, (child) => (
<Presence present={forceMount || context.isRootMenu}>
<PortalPrimitive asChild>{child}</PortalPrimitive>
</Presence>
))}
</PortalProvider>
);
};

NavigationMenuPortal.displayName = PORTAL_NAME;

/* -----------------------------------------------------------------------------------------------*/

const ARROW_KEYS = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'];
Expand Down Expand Up @@ -1249,6 +1293,7 @@ const Link = NavigationMenuLink;
const Indicator = NavigationMenuIndicator;
const Content = NavigationMenuContent;
const Viewport = NavigationMenuViewport;
const Portal = NavigationMenuPortal;

export {
createNavigationMenuScope,
Expand All @@ -1262,6 +1307,7 @@ export {
NavigationMenuIndicator,
NavigationMenuContent,
NavigationMenuViewport,
NavigationMenuPortal,
//
Root,
Sub,
Expand All @@ -1272,6 +1318,7 @@ export {
Indicator,
Content,
Viewport,
Portal,
};
export type {
NavigationMenuProps,
Expand All @@ -1283,4 +1330,5 @@ export type {
NavigationMenuIndicatorProps,
NavigationMenuContentProps,
NavigationMenuViewportProps,
NavigationMenuPortalProps,
};
3 changes: 3 additions & 0 deletions packages/react/navigation-menu/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export {
NavigationMenuIndicator,
NavigationMenuContent,
NavigationMenuViewport,
NavigationMenuPortal,
//
Root,
Sub,
Expand All @@ -21,6 +22,7 @@ export {
Indicator,
Content,
Viewport,
Portal,
} from './NavigationMenu';
export type {
NavigationMenuProps,
Expand All @@ -32,4 +34,5 @@ export type {
NavigationMenuIndicatorProps,
NavigationMenuContentProps,
NavigationMenuViewportProps,
NavigationMenuPortalProps,
} from './NavigationMenu';

0 comments on commit 4f29a01

Please sign in to comment.