From 6151d81b8d6129f5a981bc0ecf036d165300c3a5 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Tue, 16 Mar 2021 11:03:01 -0700 Subject: [PATCH] Add onSelect handler and tabindexes when appropriate --- packages/components/src/ui/menu/component.js | 4 +-- packages/components/src/ui/menu/item.js | 34 +++++++++++++++++-- .../components/src/ui/menu/stories/index.js | 3 +- packages/components/src/ui/menu/types.ts | 8 +++++ 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/components/src/ui/menu/component.js b/packages/components/src/ui/menu/component.js index e3fc4257f9ab34..1edfe696981a30 100644 --- a/packages/components/src/ui/menu/component.js +++ b/packages/components/src/ui/menu/component.js @@ -32,7 +32,7 @@ import * as styles from './styles'; * @param {import('react').Ref} forwardedRef */ function Menu( props, forwardedRef ) { - const { children, className, menu, ...otherProps } = useContextSystem( + const { as, children, className, menu, ...otherProps } = useContextSystem( props, 'Menu' ); @@ -47,7 +47,7 @@ function Menu( props, forwardedRef ) { const classes = cx( styles.Menu, className ); const menuProps = menu || {}; - const Component = menu ? ReakitMenu : View; + const Component = as || menu ? ReakitMenu : View; return ( diff --git a/packages/components/src/ui/menu/item.js b/packages/components/src/ui/menu/item.js index ad0134f81a5236..6497cc6cc879e8 100644 --- a/packages/components/src/ui/menu/item.js +++ b/packages/components/src/ui/menu/item.js @@ -30,6 +30,7 @@ import * as styles from './styles'; */ function MenuItem( props, forwardedRef ) { const { + as, children, className, closeOnClick = false, @@ -37,10 +38,13 @@ function MenuItem( props, forwardedRef ) { isOffset = false, isSelected, onClick = noop, + onSelect = noop, + onKeyDown = noop, prefix, showArrow = false, size, suffix, + tabIndex: tabIndexProp, ...otherProps } = useContextSystem( props, 'MenuItem' ); @@ -56,7 +60,7 @@ function MenuItem( props, forwardedRef ) { className ); - const Component = menu ? ReakitMenuItem : View; + const Component = as || ( menu ? ReakitMenuItem : View ); const prevArrow = useMemo( () => @@ -112,15 +116,37 @@ function MenuItem( props, forwardedRef ) { }, [ nextArrow, selectedContent, suffix ] ); const handleOnClick = useCallback( - ( event ) => { + ( /** @type {import('react').MouseEvent} */ event ) => { onClick( event ); if ( menu?.hide && closeOnClick ) { menu.hide(); + } else { + onSelect( event ); } }, - [ closeOnClick, menu, onClick ] + [ closeOnClick, menu, onClick, onSelect ] ); + const handleOnKeyDown = useCallback( + ( + /** @type {import('react').KeyboardEvent} */ event + ) => { + onKeyDown( event ); + switch ( event.key ) { + case 'Enter': + case 'Space': + case ' ': + onSelect( event ); + break; + default: + break; + } + }, + [ onSelect, onKeyDown ] + ); + + const tabIndex = tabIndexProp || ( onSelect !== noop ? 0 : undefined ); + return ( { children } diff --git a/packages/components/src/ui/menu/stories/index.js b/packages/components/src/ui/menu/stories/index.js index f234e97c025c26..4778edda453b04 100644 --- a/packages/components/src/ui/menu/stories/index.js +++ b/packages/components/src/ui/menu/stories/index.js @@ -20,8 +20,7 @@ const Example = () => { WordPress.org setIsSelected( ! isSelected ) } - onKeyDown={ () => setIsSelected( ! isSelected ) } + onSelect={ () => setIsSelected( ! isSelected ) } > Code is Poetry diff --git a/packages/components/src/ui/menu/types.ts b/packages/components/src/ui/menu/types.ts index c7fbce7e5ef88e..546fec988239a3 100644 --- a/packages/components/src/ui/menu/types.ts +++ b/packages/components/src/ui/menu/types.ts @@ -3,6 +3,8 @@ */ // eslint-disable-next-line no-restricted-imports import type { MenuStateReturn } from 'reakit'; +// eslint-disable-next-line no-restricted-imports +import type { MouseEvent, KeyboardEvent } from 'react'; /** * Internal dependencies @@ -13,6 +15,8 @@ export type Props = { menu?: MenuStateReturn; }; +export type SelectEvent = MouseEvent | KeyboardEvent; + export type MenuItemProps = BaseButtonProps & { /** * Whether to close the menu when the item is clicked. @@ -40,4 +44,8 @@ export type MenuItemProps = BaseButtonProps & { * @default false */ showArrow?: boolean; + /** + * Called when the menu item is clicked or when a keyDown event happens that is either Enter or Space. + */ + onSelect?: ( event: SelectEvent ) => void; };