Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(highlightedIndex): do not highlight disabled items #1601

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/hooks/reducer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {getHighlightedIndexOnOpen, getDefaultValue} from './utils'
import {
getHighlightedIndexOnOpen,
getDefaultValue,
getDefaultHighlightedIndex,
} from './utils'

export default function downshiftCommonReducer(
state,
Expand Down Expand Up @@ -46,7 +50,12 @@ export default function downshiftCommonReducer(
break
case stateChangeTypes.FunctionSetHighlightedIndex:
changes = {
highlightedIndex: action.highlightedIndex,
highlightedIndex: props.isItemDisabled(
props.items[action.highlightedIndex],
action.highlightedIndex,
)
? -1
: action.highlightedIndex,
}

break
Expand All @@ -58,7 +67,7 @@ export default function downshiftCommonReducer(
break
case stateChangeTypes.FunctionReset:
changes = {
highlightedIndex: getDefaultValue(props, 'highlightedIndex'),
highlightedIndex: getDefaultHighlightedIndex(props),
isOpen: getDefaultValue(props, 'isOpen'),
selectedItem: getDefaultValue(props, 'selectedItem'),
inputValue: getDefaultValue(props, 'inputValue'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getInputProps event handlers on key down arrow down defaultHighlightedIndex is ignored if item is disabled 1`] = `
[
[
Americium,
2,
],
[
Americium,
2,
],
[
Neptunium,
0,
],
]
`;

exports[`getInputProps event handlers on key down arrow down initialHighlightedIndex is ignored if item is disabled 1`] = `
[
[
Americium,
2,
],
[
Neptunium,
0,
],
]
`;

exports[`getInputProps event handlers on key down arrow up defaultHighlightedIndex is ignored if item is disabled 1`] = `
[
[
Americium,
2,
],
[
Americium,
2,
],
[
Oganesson,
25,
],
]
`;

exports[`getInputProps event handlers on key down arrow up initialHighlightedIndex is ignored if item is disabled 1`] = `
[
[
Americium,
2,
],
[
Oganesson,
25,
],
]
`;
147 changes: 97 additions & 50 deletions src/hooks/useCombobox/__tests__/getInputProps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,47 +436,64 @@ describe('getInputProps', () => {
})

describe('event handlers', () => {
test('on change should open the menu and keep the input value', async () => {
renderCombobox()
describe('on change', () => {
test('should open the menu and keep the input value', async () => {
renderCombobox()

await changeInputValue('california')
await changeInputValue('california')

expect(getItems()).toHaveLength(items.length)
expect(getInput()).toHaveValue('california')
})
expect(getItems()).toHaveLength(items.length)
expect(getInput()).toHaveValue('california')
})

test('on change should remove the highlightedIndex', async () => {
renderCombobox({initialHighlightedIndex: 2})
test('should remove the highlightedIndex', async () => {
renderCombobox({initialHighlightedIndex: 2})

await changeInputValue('california')
await changeInputValue('california')

expect(getInput()).toHaveAttribute('aria-activedescendant', '')
})
expect(getInput()).toHaveAttribute('aria-activedescendant', '')
})

test('on change should reset to defaultHighlightedIndex', async () => {
const defaultHighlightedIndex = 2
renderCombobox({defaultHighlightedIndex})
test('should reset to defaultHighlightedIndex', async () => {
const defaultHighlightedIndex = 2
renderCombobox({defaultHighlightedIndex})

await changeInputValue('a')
await changeInputValue('a')

expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex),
)
expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex),
)

await keyDownOnInput('{ArrowDown}')
await keyDownOnInput('{ArrowDown}')

expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex + 1),
)
expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex + 1),
)

await changeInputValue('a')
await changeInputValue('a')

expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex),
)
expect(getInput()).toHaveAttribute(
'aria-activedescendant',
defaultIds.getItemId(defaultHighlightedIndex),
)
})

test('should not reset to defaultHighlightedIndex if disabled', async () => {
const defaultHighlightedIndex = 2
renderCombobox({
defaultHighlightedIndex,
isItemDisabled(_item, index) {
return index === defaultHighlightedIndex
},
})

await keyDownOnInput('{ArrowDown}')
await changeInputValue('a')

expect(getInput()).toHaveAttribute('aria-activedescendant', '')
})
})

describe('on key down', () => {
Expand Down Expand Up @@ -579,11 +596,14 @@ describe('getInputProps', () => {

test('initialHighlightedIndex is ignored if item is disabled', async () => {
const initialHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === initialHighlightedIndex,
)
renderCombobox({
initialHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === initialHighlightedIndex
},
isItemDisabled,
})

await keyDownOnInput('{ArrowUp}')
Expand All @@ -592,6 +612,7 @@ describe('getInputProps', () => {
'aria-activedescendant',
defaultIds.getItemId(items.length - 1),
)
expect(isItemDisabled.mock.calls.slice(0, 2)).toMatchSnapshot()
})

test('initialHighlightedIndex is ignored and defaultHighlightedIndex is chosen if enabled', async () => {
Expand All @@ -615,11 +636,14 @@ describe('getInputProps', () => {

test('defaultHighlightedIndex is ignored if item is disabled', async () => {
const defaultHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === defaultHighlightedIndex,
)
renderCombobox({
defaultHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === defaultHighlightedIndex
},
isItemDisabled,
})

await keyDownOnInput('{ArrowUp}')
Expand All @@ -628,6 +652,7 @@ describe('getInputProps', () => {
'aria-activedescendant',
defaultIds.getItemId(items.length - 1),
)
expect(isItemDisabled.mock.calls.slice(0, 3)).toMatchSnapshot()
})

test('both defaultHighlightedIndex and initialHighlightedIndex are ignored if items are disabled', async () => {
Expand Down Expand Up @@ -901,11 +926,14 @@ describe('getInputProps', () => {

test('initialHighlightedIndex is ignored if item is disabled', async () => {
const initialHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === initialHighlightedIndex,
)
renderCombobox({
initialHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === initialHighlightedIndex
},
isItemDisabled,
})

await keyDownOnInput('{ArrowDown}')
Expand All @@ -914,6 +942,7 @@ describe('getInputProps', () => {
'aria-activedescendant',
defaultIds.getItemId(0),
)
expect(isItemDisabled.mock.calls.slice(0, 2)).toMatchSnapshot()
})

test('initialHighlightedIndex is ignored and defaultHighlightedIndex is chosen if enabled', async () => {
Expand All @@ -937,11 +966,14 @@ describe('getInputProps', () => {

test('defaultHighlightedIndex is ignored if item is disabled', async () => {
const defaultHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === defaultHighlightedIndex,
)
renderCombobox({
defaultHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === defaultHighlightedIndex
},
isItemDisabled,
})

await keyDownOnInput('{ArrowDown}')
Expand All @@ -950,6 +982,7 @@ describe('getInputProps', () => {
'aria-activedescendant',
defaultIds.getItemId(0),
)
expect(isItemDisabled.mock.calls.slice(0, 3)).toMatchSnapshot()
})

test('both defaultHighlightedIndex and initialHighlightedIndex are ignored if items are disabled', async () => {
Expand Down Expand Up @@ -1859,7 +1892,7 @@ describe('getInputProps', () => {
renderCombobox({
initialIsOpen: true,
initialHighlightedIndex,
environment: undefined
environment: undefined,
})

await tab()
Expand Down Expand Up @@ -1967,19 +2000,26 @@ describe('getInputProps', () => {
)
})


test('initialHighlightedIndex is ignored if item is disabled', async () => {
const initialHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === initialHighlightedIndex,
)
renderCombobox({
initialHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === initialHighlightedIndex
},
isItemDisabled,
})

await clickOnInput()

expect(getInput()).toHaveAttribute('aria-activedescendant', '')
expect(isItemDisabled).toHaveBeenNthCalledWith(
1,
items[initialHighlightedIndex],
initialHighlightedIndex,
)
})

test('initialHighlightedIndex is ignored and defaultHighlightedIndex is chosen if enabled', async () => {
Expand All @@ -2003,16 +2043,24 @@ describe('getInputProps', () => {

test('defaultHighlightedIndex is ignored if item is disabled', async () => {
const defaultHighlightedIndex = 2
const isItemDisabled = jest
.fn()
.mockImplementation(
item => items.indexOf(item) === defaultHighlightedIndex,
)
renderCombobox({
defaultHighlightedIndex,
isItemDisabled(item) {
return items.indexOf(item) === defaultHighlightedIndex
},
isItemDisabled,
})

await clickOnInput()

expect(getInput()).toHaveAttribute('aria-activedescendant', '')
expect(isItemDisabled).toHaveBeenNthCalledWith(
1,
items[defaultHighlightedIndex],
defaultHighlightedIndex,
)
})

test('both defaultHighlightedIndex and initialHighlightedIndex are ignored if items are disabled', async () => {
Expand All @@ -2032,7 +2080,6 @@ describe('getInputProps', () => {

expect(getInput()).toHaveAttribute('aria-activedescendant', '')
})

})
})

Expand Down
19 changes: 19 additions & 0 deletions src/hooks/useCombobox/__tests__/getItemProps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,25 @@ describe('getItemProps', () => {
defaultIds.getItemId(defaultHighlightedIndex),
)
})

test('it selects the item and resets to user defined defaults, but considers disabled status for an item', async () => {
const index = 1
const defaultHighlightedIndex = 2
renderCombobox({
defaultIsOpen: true,
defaultHighlightedIndex,
isItemDisabled(_item, idx) {
return idx === defaultHighlightedIndex
},
})
const input = getInput()

await clickOnItemAtIndex(index)

expect(input).toHaveValue(items[index])
expect(getItems()).toHaveLength(items.length)
expect(input).toHaveAttribute('aria-activedescendant', '')
})
})
})

Expand Down
Loading
Loading