diff --git a/src/hooks/useCombobox/__tests__/props.test.js b/src/hooks/useCombobox/__tests__/props.test.js index a93a95ae..8d4c671c 100644 --- a/src/hooks/useCombobox/__tests__/props.test.js +++ b/src/hooks/useCombobox/__tests__/props.test.js @@ -334,6 +334,71 @@ describe('props', () => { expect(input).toHaveAttribute('aria-activedescendant', expectedItemId) }) + test('initialHighlightedIndex is ignored if item is disabled', async () => { + const initialHighlightedIndex = 2 + renderCombobox({ + initialHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === initialHighlightedIndex + }, + }) + + await clickOnInput() + + expect(getInput()).toHaveAttribute('aria-activedescendant', '') + }) + + test('initialHighlightedIndex is ignored and defaultHighlightedIndex is chosen if enabled', async () => { + const initialHighlightedIndex = 0 + const defaultHighlightedIndex = 2 + renderCombobox({ + initialHighlightedIndex, + defaultHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === initialHighlightedIndex + }, + }) + + await clickOnInput() + + expect(getInput()).toHaveAttribute( + 'aria-activedescendant', + defaultIds.getItemId(defaultHighlightedIndex), + ) + }) + + test('defaultHighlightedIndex is ignored if item is disabled', async () => { + const defaultHighlightedIndex = 2 + renderCombobox({ + defaultHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === defaultHighlightedIndex + }, + }) + + await clickOnInput() + + expect(getInput()).toHaveAttribute('aria-activedescendant', '') + }) + + test('both defaultHighlightedIndex and initialHighlightedIndex are ignored if items are disabled', async () => { + const initialHighlightedIndex = 0 + const defaultHighlightedIndex = 2 + renderCombobox({ + initialHighlightedIndex, + defaultHighlightedIndex, + isItemDisabled(item) { + return [initialHighlightedIndex, defaultHighlightedIndex].includes( + items.indexOf(item), + ) + }, + }) + + await clickOnInput() + + expect(getInput()).toHaveAttribute('aria-activedescendant', '') + }) + describe('inputValue', () => { test('controls the state property if passed', async () => { renderCombobox({isOpen: true, inputValue: 'Dohn Joe'}) diff --git a/src/hooks/useSelect/__tests__/props.test.js b/src/hooks/useSelect/__tests__/props.test.js index 111dbf66..f83a8982 100644 --- a/src/hooks/useSelect/__tests__/props.test.js +++ b/src/hooks/useSelect/__tests__/props.test.js @@ -99,7 +99,7 @@ describe('props', () => { inputValue: 'h', highlightedIndex: 15, isOpen: true, - selectedItem: null + selectedItem: null, }) expect(getA11yStatusMessage).toHaveBeenCalledTimes(1) @@ -234,7 +234,72 @@ describe('props', () => { } }) - test('controls the state property if passed', async () => { + test('initialHighlightedIndex is ignored if item is disabled', async () => { + const initialHighlightedIndex = 2 + renderSelect({ + initialHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === initialHighlightedIndex + }, + }) + + await clickOnToggleButton() + + expect(getToggleButton()).toHaveAttribute('aria-activedescendant', '') + }) + + test('initialHighlightedIndex is ignored and defaultHighlightedIndex is chosen if enabled', async () => { + const initialHighlightedIndex = 0 + const defaultHighlightedIndex = 2 + renderSelect({ + initialHighlightedIndex, + defaultHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === initialHighlightedIndex + }, + }) + + await clickOnToggleButton() + + expect(getToggleButton()).toHaveAttribute( + 'aria-activedescendant', + defaultIds.getItemId(defaultHighlightedIndex), + ) + }) + + test('defaultHighlightedIndex is ignored if item is disabled', async () => { + const defaultHighlightedIndex = 2 + renderSelect({ + defaultHighlightedIndex, + isItemDisabled(item) { + return items.indexOf(item) === defaultHighlightedIndex + }, + }) + + await clickOnToggleButton() + + expect(getToggleButton()).toHaveAttribute('aria-activedescendant', '') + }) + + test('both defaultHighlightedIndex and initialHighlightedIndex are ignored if items are disabled', async () => { + const initialHighlightedIndex = 0 + const defaultHighlightedIndex = 2 + renderSelect({ + initialHighlightedIndex, + defaultHighlightedIndex, + isItemDisabled(item) { + return [initialHighlightedIndex, defaultHighlightedIndex].includes( + items.indexOf(item), + ) + }, + }) + + await clickOnToggleButton() + + expect(getToggleButton()).toHaveAttribute('aria-activedescendant', '') + }) + + test('isOpen controls the state property if passed', async () => { renderSelect({isOpen: true}) expect(getItems()).toHaveLength(items.length) await tab() // focus toggle button diff --git a/src/hooks/utils.js b/src/hooks/utils.js index 746ef658..9e0c4c7f 100644 --- a/src/hooks/utils.js +++ b/src/hooks/utils.js @@ -310,8 +310,13 @@ function getInitialState(props) { } function getHighlightedIndexOnOpen(props, state, offset) { - const {items, initialHighlightedIndex, defaultHighlightedIndex, itemToKey} = - props + const { + items, + initialHighlightedIndex, + defaultHighlightedIndex, + isItemDisabled, + itemToKey, + } = props const {selectedItem, highlightedIndex} = state if (items.length === 0) { @@ -321,11 +326,15 @@ function getHighlightedIndexOnOpen(props, state, offset) { // initialHighlightedIndex will give value to highlightedIndex on initial state only. if ( initialHighlightedIndex !== undefined && - highlightedIndex === initialHighlightedIndex + highlightedIndex === initialHighlightedIndex && + !isItemDisabled(items[initialHighlightedIndex]) ) { return initialHighlightedIndex } - if (defaultHighlightedIndex !== undefined) { + if ( + defaultHighlightedIndex !== undefined && + !isItemDisabled(items[defaultHighlightedIndex]) + ) { return defaultHighlightedIndex } if (selectedItem) {