From 7a761563f1287252a77602d258ab9e96c2870fc6 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Tue, 27 Aug 2024 16:00:24 +0200 Subject: [PATCH 1/3] CircularOptionPicker: do not use composite store directly --- .../circular-option-picker-option.tsx | 35 ++++++++---------- .../circular-option-picker.tsx | 37 +++++++++++++------ .../src/circular-option-picker/types.ts | 4 +- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/packages/components/src/circular-option-picker/circular-option-picker-option.tsx b/packages/components/src/circular-option-picker/circular-option-picker-option.tsx index 1ab4fd0d01790..276ab7549781e 100644 --- a/packages/components/src/circular-option-picker/circular-option-picker-option.tsx +++ b/packages/components/src/circular-option-picker/circular-option-picker-option.tsx @@ -2,14 +2,13 @@ * External dependencies */ import clsx from 'clsx'; -import { useStoreState } from '@ariakit/react'; import type { ForwardedRef } from 'react'; /** * WordPress dependencies */ import { useInstanceId } from '@wordpress/compose'; -import { forwardRef, useContext } from '@wordpress/element'; +import { forwardRef, useContext, useEffect } from '@wordpress/element'; import { Icon, check } from '@wordpress/icons'; /** @@ -46,18 +45,21 @@ function UnforwardedOptionAsOption( id: string; className?: string; isSelected?: boolean; - compositeStore: NonNullable< - React.ComponentProps< typeof Composite >[ '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 c878000aff84b..adf2b386e5cbe 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 e23ff4165f058..411782aed575b 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; }; From aae19228d648fbfee905c81127a1e8b611c6726c Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Tue, 27 Aug 2024 17:46:18 +0200 Subject: [PATCH 2/3] Wait for composite to initialize in unit tests --- .../components/color-palette/test/control.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) 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 3a5dcc657a94c..e1a5529544f79 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( Date: Sat, 31 Aug 2024 11:24:20 +0200 Subject: [PATCH 3/3] CHANGELOG --- packages/components/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0021df7a36110..7834015cc8dbf 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -56,6 +56,7 @@ - `TreeSelect` - `UnitControl` - `Modal`: Update animation effect ([#64580](https://github.com/WordPress/gutenberg/pull/64580)). +- `CircularOptionPicker`: do not use composite store directly ([#64833](https://github.com/WordPress/gutenberg/pull/64833)). ### Bug Fixes