diff --git a/packages/block-editor/src/components/color-palette/test/control.js b/packages/block-editor/src/components/color-palette/test/control.js index 3a5dcc657a94c4..e1a5529544f791 100644 --- a/packages/block-editor/src/components/color-palette/test/control.js +++ b/packages/block-editor/src/components/color-palette/test/control.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { render } from '@testing-library/react'; +import { render, waitFor, queryByAttribute } from '@testing-library/react'; /** * Internal dependencies @@ -10,9 +10,22 @@ import ColorPaletteControl from '../control'; const noop = () => {}; +async function renderAndValidate( ...renderArgs ) { + const view = render( ...renderArgs ); + await waitFor( () => { + const activeButton = queryByAttribute( + 'data-active-item', + view.baseElement, + 'true' + ); + expect( activeButton ).not.toBeNull(); + } ); + return view; +} + describe( 'ColorPaletteControl', () => { it( 'matches the snapshot', async () => { - const { container } = render( + const { container } = await renderAndValidate( [ 'store' ] - >; }, forwardedRef: ForwardedRef< any > ) { - const { id, isSelected, compositeStore, ...additionalProps } = props; - const activeId = useStoreState( compositeStore, 'activeId' ); + const { id, isSelected, ...additionalProps } = props; - if ( isSelected && ! activeId ) { - compositeStore.setActiveId( id ); - } + const { setActiveId, activeId } = useContext( CircularOptionPickerContext ); + + useEffect( () => { + if ( isSelected && ! activeId ) { + // The setTimeout call is necessary to make sure that this update + // doesn't get overridden by `Composite`'s internal logic, which picks + // an initial active item if one is not specifically set. + window.setTimeout( () => setActiveId?.( id ), 0 ); + } + }, [ isSelected, setActiveId, activeId, id ] ); return ( + const isListbox = setActiveId !== undefined; + const optionControl = isListbox ? ( + ) : ( ); diff --git a/packages/components/src/circular-option-picker/circular-option-picker.tsx b/packages/components/src/circular-option-picker/circular-option-picker.tsx index c878000aff84b8..adf2b386e5cbec 100644 --- a/packages/components/src/circular-option-picker/circular-option-picker.tsx +++ b/packages/components/src/circular-option-picker/circular-option-picker.tsx @@ -8,13 +8,13 @@ import clsx from 'clsx'; */ import { useInstanceId } from '@wordpress/compose'; import { isRTL } from '@wordpress/i18n'; +import { useMemo, useState } from '@wordpress/element'; /** * Internal dependencies */ import { CircularOptionPickerContext } from './circular-option-picker-context'; import { Composite } from '../composite'; -import { useCompositeStore } from '../composite/store'; import type { CircularOptionPickerProps, ListboxCircularOptionPickerProps, @@ -86,24 +86,30 @@ function ListboxCircularOptionPicker( ...additionalProps } = props; - const compositeStore = useCompositeStore( { - focusLoop: loop, - rtl: isRTL(), - } ); + const [ activeId, setActiveId ] = useState< string | null | undefined >( + undefined + ); - const compositeContext = { - baseId, - compositeStore, - }; + const contextValue = useMemo( + () => ( { + baseId, + activeId, + setActiveId, + } ), + [ baseId, activeId, setActiveId ] + ); return (
- + { options } @@ -119,9 +125,16 @@ function ButtonsCircularOptionPicker( ) { const { actions, options, children, baseId, ...additionalProps } = props; + const contextValue = useMemo( + () => ( { + baseId, + } ), + [ baseId ] + ); + return (
- + { options } { children } { actions } diff --git a/packages/components/src/circular-option-picker/types.ts b/packages/components/src/circular-option-picker/types.ts index e23ff4165f0580..411782aed575b1 100644 --- a/packages/components/src/circular-option-picker/types.ts +++ b/packages/components/src/circular-option-picker/types.ts @@ -14,7 +14,6 @@ import type { Icon } from '@wordpress/icons'; import type { ButtonAsButtonProps } from '../button/types'; import type { DropdownProps } from '../dropdown/types'; import type { WordPressComponentProps } from '../context'; -import type { Composite } from '../composite'; type CommonCircularOptionPickerProps = { /** @@ -125,5 +124,6 @@ export type OptionProps = Omit< export type CircularOptionPickerContextProps = { baseId?: string; - compositeStore?: React.ComponentProps< typeof Composite >[ 'store' ]; + activeId?: string | null | undefined; + setActiveId?: ( newId: string | null | undefined ) => void; };