From 52832f5bc8ff4dcbe9e5116dc3a47438b7460b13 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Mon, 2 Sep 2024 14:20:03 +0200 Subject: [PATCH] DropdownMenuV2: fix active and focus-visible item glitches (#64942) * Remove previous workaround * Implement flushSync-based workaround * Update CHANGELOG --- Co-authored-by: ciampo Co-authored-by: tyxla Co-authored-by: diegohaz --- packages/components/CHANGELOG.md | 2 +- .../src/dropdown-menu-v2/checkbox-item.tsx | 6 ++++- .../components/src/dropdown-menu-v2/item.tsx | 6 ++++- .../src/dropdown-menu-v2/radio-item.tsx | 6 ++++- .../components/src/dropdown-menu-v2/styles.ts | 15 ++++--------- .../use-temporary-focus-visible-fix.ts | 22 +++++++++++++++++++ 6 files changed, 42 insertions(+), 15 deletions(-) create mode 100644 packages/components/src/dropdown-menu-v2/use-temporary-focus-visible-fix.ts diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0021df7a36110..48bdc1e9cbdcf 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -64,7 +64,7 @@ ### Internal -- `DropdownMenu` v2: fix flashing menu item styles when using keyboard ([#64873](https://github.com/WordPress/gutenberg/pull/64873)). +- `DropdownMenu` v2: fix flashing menu item styles when using keyboard ([#64873](https://github.com/WordPress/gutenberg/pull/64873), [#64942](https://github.com/WordPress/gutenberg/pull/64942)). - `DropdownMenu` v2: refactor to overloaded naming convention ([#64654](https://github.com/WordPress/gutenberg/pull/64654)). - `DropdownMenu` v2: add `GroupLabel` subcomponent ([#64854](https://github.com/WordPress/gutenberg/pull/64854)). - `Composite` V2: fix Storybook docgen ([#64682](https://github.com/WordPress/gutenberg/pull/64682)). diff --git a/packages/components/src/dropdown-menu-v2/checkbox-item.tsx b/packages/components/src/dropdown-menu-v2/checkbox-item.tsx index 2f0d15557bb5e..bcbc920cbb720 100644 --- a/packages/components/src/dropdown-menu-v2/checkbox-item.tsx +++ b/packages/components/src/dropdown-menu-v2/checkbox-item.tsx @@ -16,20 +16,24 @@ import type { WordPressComponentProps } from '../context'; import { DropdownMenuContext } from './context'; import type { DropdownMenuCheckboxItemProps } from './types'; import * as Styled from './styles'; +import { useTemporaryFocusVisibleFix } from './use-temporary-focus-visible-fix'; export const DropdownMenuCheckboxItem = forwardRef< HTMLDivElement, WordPressComponentProps< DropdownMenuCheckboxItemProps, 'div', false > >( function DropdownMenuCheckboxItem( - { suffix, children, hideOnClick = false, ...props }, + { suffix, children, onBlur, hideOnClick = false, ...props }, ref ) { + // TODO: Remove when https://github.com/ariakit/ariakit/issues/4083 is fixed + const focusVisibleFixProps = useTemporaryFocusVisibleFix( { onBlur } ); const dropdownMenuContext = useContext( DropdownMenuContext ); return ( >( function DropdownMenuItem( - { prefix, suffix, children, hideOnClick = true, ...props }, + { prefix, suffix, children, onBlur, hideOnClick = true, ...props }, ref ) { + // TODO: Remove when https://github.com/ariakit/ariakit/issues/4083 is fixed + const focusVisibleFixProps = useTemporaryFocusVisibleFix( { onBlur } ); const dropdownMenuContext = useContext( DropdownMenuContext ); return ( @@ -28,15 +29,18 @@ export const DropdownMenuRadioItem = forwardRef< HTMLDivElement, WordPressComponentProps< DropdownMenuRadioItemProps, 'div', false > >( function DropdownMenuRadioItem( - { suffix, children, hideOnClick = false, ...props }, + { suffix, children, onBlur, hideOnClick = false, ...props }, ref ) { + // TODO: Remove when https://github.com/ariakit/ariakit/issues/4083 is fixed + const focusVisibleFixProps = useTemporaryFocusVisibleFix( { onBlur } ); const dropdownMenuContext = useContext( DropdownMenuContext ); return ( ; +} ) { + const [ focusVisible, setFocusVisible ] = useState( false ); + return { + 'data-focus-visible': focusVisible || undefined, + onFocusVisible: () => { + flushSync( () => setFocusVisible( true ) ); + }, + onBlur: ( ( event ) => { + onBlurProp?.( event ); + setFocusVisible( false ); + } ) as React.FocusEventHandler< HTMLDivElement >, + }; +}