diff --git a/packages/menu/README.md b/packages/menu/README.md index 8c64ee2de..7e12bd282 100644 --- a/packages/menu/README.md +++ b/packages/menu/README.md @@ -18,6 +18,8 @@ Check out [storybook](https://zendeskgarden.github.io/react-containers) for live ### useMenu +#### Menu items + ```jsx import { useMenu } from '@zendeskgarden/container-menu'; @@ -50,6 +52,40 @@ const Menu = () => { }; ``` +#### Menu links + +```jsx +import { useMenu } from '@zendeskgarden/container-menu'; + +const Menu = () => { + const triggerRef = useRef(); + const menuRef = useRef(); + const items = [ + { value: 'home', label: 'Home', href="#", selected: true }, + { value: 'about', label: 'About', href="www.example.com/about" }, + { value: 'support', label: 'Support', href="www.support.example.com", external: true } + ]; + const { isExpanded, getTriggerProps, getMenuProps, getItemProps, getAnchorProps } = useMenu({ + triggerRef, + menuRef, + items + }); + + return ( + <> + + + + ); +}; +``` + ### MenuContainer ```jsx @@ -61,27 +97,20 @@ const Menu = () => { const items = [ { value: 'value-1', label: 'One' }, { value: 'value-2', label: 'Two' }, - { value: 'value-3', label: 'Three', href: '#0' }, - { value: 'value-4', label: 'Four' } + { value: 'value-3', label: 'Three' } ]; return ( - {({ isExpanded, getTriggerProps, getMenuProps, getItemProps, getSeparatorProps }) => ( + {({ isExpanded, getTriggerProps, getMenuProps, getItemProps }) => ( <> )} diff --git a/packages/menu/demo/menu.stories.tsx b/packages/menu/demo/menu.stories.tsx index 76723ddab..ddd81132d 100644 --- a/packages/menu/demo/menu.stories.tsx +++ b/packages/menu/demo/menu.stories.tsx @@ -48,6 +48,8 @@ export const Controlled: Story = { return ( { updateArgs(rest); diff --git a/packages/menu/demo/stories/MenuStory.tsx b/packages/menu/demo/stories/MenuStory.tsx index a60b8ecf8..4fc2a225e 100644 --- a/packages/menu/demo/stories/MenuStory.tsx +++ b/packages/menu/demo/stories/MenuStory.tsx @@ -5,7 +5,7 @@ * found at http://www.apache.org/licenses/LICENSE-2.0. */ -import React, { AnchorHTMLAttributes, LiHTMLAttributes, useRef } from 'react'; +import React, { useEffect, useRef } from 'react'; import { StoryFn } from '@storybook/react'; import classNames from 'classnames'; import { @@ -29,18 +29,20 @@ interface IUseMenuComponentProps extends MenuReturnValue { type MenuItemProps = { item: IMenuItemBase; getItemProps: IUseMenuComponentProps['getItemProps']; + getAnchorProps: IUseMenuComponentProps['getAnchorProps']; focusedValue: IUseMenuComponentProps['focusedValue']; isSelected?: boolean; }; -const Item = ({ item, getItemProps, focusedValue, isSelected }: MenuItemProps) => { - const itemProps = getItemProps({ item }); +const Item = ({ item, getAnchorProps, getItemProps, focusedValue, isSelected }: MenuItemProps) => { + const itemProps = getItemProps({ item }); + const anchorProps = getAnchorProps({ item }); const itemChildren = ( <> - {item?.type === 'radio' && !!isSelected && '•'} - {item?.type === 'checkbox' && !!isSelected && '✓'} + {!!isSelected && item.type === 'radio' && '•'} + {!!isSelected && (item.type === 'checkbox' || !!item.href) && '✓'} {item.label || item.value} @@ -54,16 +56,21 @@ const Item = ({ item, getItemProps, focusedValue, isSelected }: MenuItemProps) = 'cursor-pointer': !item.disabled, 'cursor-default': item.disabled })} - role={itemProps.href ? 'none' : undefined} - {...(!itemProps.href && (itemProps as LiHTMLAttributes))} + {...itemProps} > - {itemProps.href ? ( + {anchorProps ? ( )} - className="w-full rounded-sm outline-offset-0 transition-none border-width-none" + {...anchorProps} + className={classNames( + ' w-full rounded-sm outline-offset-0 transition-none border-width-none', + { + 'text-grey-400': item.disabled, + 'cursor-default': item.disabled + } + )} > {itemChildren} - {!!item.isExternal && ( + {anchorProps.target === '_blank' && ( <> (opens in new window) @@ -85,11 +92,20 @@ const Component = ({ getTriggerProps, getMenuProps, getItemProps, + getAnchorProps, getItemGroupProps, getSeparatorProps }: MenuReturnValue & UseMenuProps) => { const selectedValues = selection.map(item => item.value); + useEffect(() => { + const originalWindowOpen = window.open; + window.open = () => null; + return () => { + window.open = originalWindowOpen; + }; + }, []); + return (