diff --git a/packages/components/src/circular-option-picker/README.md b/packages/components/src/circular-option-picker/README.md index b6db6f06daf456..8a4d5ac3cf5ca3 100644 --- a/packages/components/src/circular-option-picker/README.md +++ b/packages/components/src/circular-option-picker/README.md @@ -93,6 +93,19 @@ Prevents keyboard interaction from wrapping around. Only used when `asButtons` i - Required: No - Default: `true` +### `aria-labelledby`: `string` + +The ID reference list of one or more elements that label the wrapper element. + +- Required: No + +### `aria-label`: `string` + +The label for the wrapper element. Not used if an 'aria-labelledby' is provided. + +- Required: No +- Default: `Custom color picker` + ## Subcomponents ### `CircularOptionPicker.ButtonAction` diff --git a/packages/components/src/circular-option-picker/index.tsx b/packages/components/src/circular-option-picker/index.tsx index ef975c21ee6545..0eca8b025d92c6 100644 --- a/packages/components/src/circular-option-picker/index.tsx +++ b/packages/components/src/circular-option-picker/index.tsx @@ -9,5 +9,6 @@ export { ButtonAction, DropdownLinkAction, } from './circular-option-picker-actions'; +export { useComputeCircularOptionPickerCommonProps } from './utils'; export default CircularOptionPicker; diff --git a/packages/components/src/circular-option-picker/test/index.tsx b/packages/components/src/circular-option-picker/test/index.tsx index a6e9f2c45a05ce..7d58ed3920f9bd 100644 --- a/packages/components/src/circular-option-picker/test/index.tsx +++ b/packages/components/src/circular-option-picker/test/index.tsx @@ -57,6 +57,7 @@ describe( 'CircularOptionPicker', () => { expect( screen.queryByRole( 'listbox' ) ).not.toBeInTheDocument(); expect( screen.queryByRole( 'option' ) ).not.toBeInTheDocument(); + expect( screen.getByRole( 'group' ) ).toBeInTheDocument(); expect( screen.getByRole( 'button' ) ).toBeInTheDocument(); } ); } ); diff --git a/packages/components/src/circular-option-picker/types.ts b/packages/components/src/circular-option-picker/types.ts index 65760092220999..54fae3ab2e798a 100644 --- a/packages/components/src/circular-option-picker/types.ts +++ b/packages/components/src/circular-option-picker/types.ts @@ -40,16 +40,17 @@ type CommonCircularOptionPickerProps = { * The child elements. */ children?: ReactNode; -} & ( - | { - 'aria-label': string; - 'aria-labelledby'?: never; - } - | { - 'aria-label'?: never; - 'aria-labelledby': string; - } -); + /** + * The ID reference list of one or more elements that label the wrapper + * element. + */ + 'aria-labelledby'?: string; + /** + * The label for the wrapper element. Defaults to 'Custom color picker'. Not + * used if an 'aria-labelledby' is provided. + */ + 'aria-label'?: string; +}; type WithBaseId = { baseId: string; diff --git a/packages/components/src/circular-option-picker/utils.tsx b/packages/components/src/circular-option-picker/utils.tsx new file mode 100644 index 00000000000000..2496ee6478ef0f --- /dev/null +++ b/packages/components/src/circular-option-picker/utils.tsx @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Computes the common props for the CircularOptionPicker. + */ +export function useComputeCircularOptionPickerCommonProps( + asButtons?: boolean, + loop?: boolean, + ariaLabel?: string, + ariaLabelledby?: string +) { + const metaProps = asButtons + ? { asButtons: true } + : { asButtons: false, loop }; + + const labelProps = { + 'aria-labelledby': ariaLabelledby, + 'aria-label': ariaLabelledby + ? undefined + : ariaLabel || __( 'Custom color picker' ), + }; + + return { metaProps, labelProps }; +} diff --git a/packages/components/src/color-palette/index.tsx b/packages/components/src/color-palette/index.tsx index 68c4d339120a31..39a143c7c8bf07 100644 --- a/packages/components/src/color-palette/index.tsx +++ b/packages/components/src/color-palette/index.tsx @@ -19,7 +19,9 @@ import { useCallback, useMemo, useState, forwardRef } from '@wordpress/element'; */ import Dropdown from '../dropdown'; import { ColorPicker } from '../color-picker'; -import CircularOptionPicker from '../circular-option-picker'; +import CircularOptionPicker, { + useComputeCircularOptionPickerCommonProps, +} from '../circular-option-picker'; import { VStack } from '../v-stack'; import { Truncate } from '../truncate'; import { ColorHeading } from './styles'; @@ -251,50 +253,12 @@ function UnforwardedColorPalette( ); - let metaProps: - | { asButtons: false; loop?: boolean; 'aria-label': string } - | { asButtons: false; loop?: boolean; 'aria-labelledby': string } - | { asButtons: true; 'aria-label': string } - | { asButtons: true; 'aria-labelledby': string }; - - if ( asButtons ) { - const _metaProps: { asButtons: true } = { - asButtons: true, - }; - - if ( ariaLabel ) { - metaProps = { ..._metaProps, 'aria-label': ariaLabel }; - } else if ( ariaLabelledby ) { - metaProps = { - ..._metaProps, - 'aria-labelledby': ariaLabelledby, - }; - } else { - metaProps = { - ..._metaProps, - 'aria-label': __( 'Custom color picker.' ), - }; - } - } else { - const _metaProps: { asButtons: false; loop?: boolean } = { - asButtons: false, - loop, - }; - - if ( ariaLabel ) { - metaProps = { ..._metaProps, 'aria-label': ariaLabel }; - } else if ( ariaLabelledby ) { - metaProps = { - ..._metaProps, - 'aria-labelledby': ariaLabelledby, - }; - } else { - metaProps = { - ..._metaProps, - 'aria-label': __( 'Custom color picker.' ), - }; - } - } + const { metaProps, labelProps } = useComputeCircularOptionPickerCommonProps( + asButtons, + loop, + ariaLabel, + ariaLabelledby + ); return ( @@ -352,6 +316,7 @@ function UnforwardedColorPalette( { ( colors.length > 0 || actions ) && ( ) { ); - let metaProps: - | { asButtons: false; loop?: boolean; 'aria-label': string } - | { asButtons: false; loop?: boolean; 'aria-labelledby': string } - | { asButtons: true; 'aria-label': string } - | { asButtons: true; 'aria-labelledby': string }; - - if ( asButtons ) { - const _metaProps: { asButtons: true } = { - asButtons: true, - }; - - if ( ariaLabel ) { - metaProps = { ..._metaProps, 'aria-label': ariaLabel }; - } else if ( ariaLabelledby ) { - metaProps = { - ..._metaProps, - 'aria-labelledby': ariaLabelledby, - }; - } else { - metaProps = { - ..._metaProps, - 'aria-label': __( 'Custom color picker.' ), - }; - } - } else { - const _metaProps: { asButtons: false; loop?: boolean } = { - asButtons: false, - loop, - }; - - if ( ariaLabel ) { - metaProps = { ..._metaProps, 'aria-label': ariaLabel }; - } else if ( ariaLabelledby ) { - metaProps = { - ..._metaProps, - 'aria-labelledby': ariaLabelledby, - }; - } else { - metaProps = { - ..._metaProps, - 'aria-label': __( 'Custom color picker.' ), - }; - } - } + const { metaProps, labelProps } = useComputeCircularOptionPickerCommonProps( + asButtons, + loop, + ariaLabel, + ariaLabelledby + ); return (