Improve experimental select control accessibility (#34510)
* Use downshift built in methods to handle selection of items * Fix menu styling * Fix removal a11y announcement * Don't show menu without results * Fix async example a11y * Add changelog entry * Deselect item in state on remove * Fix formatting issues * Update lock file * Update lock file after pnpm7 * Skip lib check breaking oclif build in package-release * Rebase again and fix up lock file * Skip lib check in monorepo-merge * Fix the lock * Ignore lint Co-authored-by: Sam Seay <samueljseay@gmail.com> Co-authored-by: Jonathan Sadowski <sadowski@automattic.com>
This commit is contained in:
parent
d2b20dc993
commit
f39d8b6b39
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: enhancement
|
||||
|
||||
Improve experimental SelectControl accessibility
|
|
@ -4,14 +4,11 @@
|
|||
top: 100%;
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
background: $studio-white;
|
||||
border: 1px solid $studio-gray-5;
|
||||
border-radius: 3px;
|
||||
|
||||
&.is-open {
|
||||
&.is-open.has-results {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.woocommerce-experimental-select-control__menu-inner {
|
||||
background: $studio-white;
|
||||
border: 1px solid $studio-gray-5;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
|
@ -17,21 +17,19 @@ type MenuProps = {
|
|||
|
||||
export const Menu = ( { children, getMenuProps, isOpen }: MenuProps ) => {
|
||||
return (
|
||||
<div
|
||||
<ul
|
||||
{ ...getMenuProps() }
|
||||
className={ classnames(
|
||||
'woocommerce-experimental-select-control__menu',
|
||||
{
|
||||
'is-open': isOpen,
|
||||
'has-results': Array.isArray( children )
|
||||
? children.length
|
||||
: Boolean( children ),
|
||||
}
|
||||
) }
|
||||
>
|
||||
{ isOpen &&
|
||||
( ! Array.isArray( children ) || !! children.length ) && (
|
||||
<ul className="woocommerce-experimental-select-control__menu-inner">
|
||||
{ children }
|
||||
</ul>
|
||||
) }
|
||||
</div>
|
||||
{ isOpen && children }
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -84,7 +84,14 @@ function SelectControl< ItemType = DefaultItemType >( {
|
|||
}: SelectControlProps< ItemType > ) {
|
||||
const [ isFocused, setIsFocused ] = useState( false );
|
||||
const [ inputValue, setInputValue ] = useState( '' );
|
||||
const { getSelectedItemProps, getDropdownProps } = useMultipleSelection();
|
||||
const {
|
||||
addSelectedItem,
|
||||
getSelectedItemProps,
|
||||
getDropdownProps,
|
||||
removeSelectedItem,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
} = useMultipleSelection( { itemToString } );
|
||||
let selectedItems = selected === null ? [] : selected;
|
||||
selectedItems = Array.isArray( selectedItems )
|
||||
? selectedItems
|
||||
|
@ -104,11 +111,14 @@ function SelectControl< ItemType = DefaultItemType >( {
|
|||
getComboboxProps,
|
||||
highlightedIndex,
|
||||
getItemProps,
|
||||
} = useCombobox( {
|
||||
selectItem,
|
||||
selectedItem: singleSelectedItem,
|
||||
} = useCombobox< ItemType | null >( {
|
||||
inputValue,
|
||||
items: filteredItems,
|
||||
itemToString: getItemLabel,
|
||||
selectedItem: null,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
onStateChange: ( { inputValue: value, type, selectedItem } ) => {
|
||||
switch ( type ) {
|
||||
case useCombobox.stateChangeTypes.InputChange:
|
||||
|
@ -121,9 +131,18 @@ function SelectControl< ItemType = DefaultItemType >( {
|
|||
case useCombobox.stateChangeTypes.InputBlur:
|
||||
if ( selectedItem ) {
|
||||
onSelect( selectedItem );
|
||||
setInputValue(
|
||||
multiple ? '' : getItemLabel( selectedItem )
|
||||
);
|
||||
if ( multiple ) {
|
||||
addSelectedItem( selectedItem );
|
||||
setInputValue( '' );
|
||||
break;
|
||||
}
|
||||
|
||||
selectItem( selectedItem );
|
||||
setInputValue( getItemLabel( selectedItem ) );
|
||||
}
|
||||
|
||||
if ( ! selectedItem && ! multiple ) {
|
||||
setInputValue( getItemLabel( singleSelectedItem ) );
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -133,6 +152,12 @@ function SelectControl< ItemType = DefaultItemType >( {
|
|||
},
|
||||
} );
|
||||
|
||||
const onRemoveItem = ( item: ItemType ) => {
|
||||
selectItem( null );
|
||||
removeSelectedItem( item );
|
||||
onRemove( item );
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ classnames( 'woocommerce-experimental-select-control', {
|
||||
|
@ -150,7 +175,7 @@ function SelectControl< ItemType = DefaultItemType >( {
|
|||
getItemLabel={ getItemLabel }
|
||||
getItemValue={ getItemValue }
|
||||
getSelectedItemProps={ getSelectedItemProps }
|
||||
onRemove={ onRemove }
|
||||
onRemove={ onRemoveItem }
|
||||
/>
|
||||
) }
|
||||
<ComboBox
|
||||
|
|
|
@ -106,6 +106,7 @@ export const Async: React.FC = () => {
|
|||
|
||||
const fetchItems = ( value: string | undefined ) => {
|
||||
setIsFetching( true );
|
||||
setFetchedItems( [] );
|
||||
setTimeout( () => {
|
||||
const results = sampleItems.sort( () => 0.5 - Math.random() );
|
||||
setFetchedItems( results );
|
||||
|
@ -117,6 +118,9 @@ export const Async: React.FC = () => {
|
|||
<>
|
||||
<SelectControl
|
||||
label="Async"
|
||||
getFilteredItems={ ( allItems ) => {
|
||||
return allItems;
|
||||
} }
|
||||
items={ fetchedItems }
|
||||
onInputChange={ fetchItems }
|
||||
selected={ selectedItem }
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
|
|
Loading…
Reference in New Issue