-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(select a11y): make PageDown keypress respect disabled options
- Loading branch information
Showing
7 changed files
with
250 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
...ect/src/single-select-a11y/use-handle-key-press/use-highlight-last-option-on-next-page.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { useCallback } from 'react' | ||
import { isOptionHidden } from '../is-option-hidden.js' | ||
|
||
export function useHighlightLastOptionOnNextPage({ | ||
options, | ||
focussedOptionIndex, | ||
setFocussedOptionIndex, | ||
listBoxRef, | ||
}) { | ||
return useCallback( | ||
(listBoxParent) => { | ||
const optionElements = Array.from(listBoxRef.current.childNodes) | ||
const visibleOptionsAmount = options.filter( | ||
(_, index) => | ||
!isOptionHidden(optionElements[index], listBoxParent) | ||
).length | ||
|
||
const nextHighlightedOptionIndex = Math.min( | ||
options.length - 1, | ||
focussedOptionIndex + visibleOptionsAmount | ||
) | ||
|
||
// If there's no next option and we already have the last option in the list highlighted | ||
if (!options[nextHighlightedOptionIndex]) { | ||
return | ||
} | ||
|
||
if (!options[nextHighlightedOptionIndex].disabled) { | ||
// This will be the first option in the list | ||
const { offsetTop: scrollPosition } = | ||
optionElements[ | ||
nextHighlightedOptionIndex - visibleOptionsAmount + 1 | ||
] | ||
|
||
listBoxParent.scrollTop = scrollPosition | ||
setFocussedOptionIndex(nextHighlightedOptionIndex) | ||
return | ||
} | ||
|
||
const followingEnabledOptionIndex = | ||
nextHighlightedOptionIndex + | ||
options | ||
.slice(nextHighlightedOptionIndex) | ||
.findIndex((option) => !option.disabled) | ||
|
||
// There is no enabled option after the disabled option that's at the end of the next page | ||
// So we stay where we are | ||
if (followingEnabledOptionIndex === -1) { | ||
return | ||
} | ||
|
||
// There is an enabled option after the disabled option that's at the end of the next page | ||
// So that'll be the new highlighted option and the bottom of the next displayed page | ||
const { offsetTop: adjustedScrollPosition } = | ||
optionElements[ | ||
followingEnabledOptionIndex - visibleOptionsAmount + 1 | ||
] | ||
|
||
listBoxParent.scrollTop = adjustedScrollPosition | ||
setFocussedOptionIndex(followingEnabledOptionIndex) | ||
}, | ||
[options, focussedOptionIndex, setFocussedOptionIndex, listBoxRef] | ||
) | ||
} |
52 changes: 52 additions & 0 deletions
52
...s/select/src/single-select-a11y/use-handle-key-press/use-highlight-last-visible-option.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { useCallback } from 'react' | ||
|
||
export function useHighlightLastVisibleOption({ | ||
options, | ||
focussedOptionIndex, | ||
setFocussedOptionIndex, | ||
}) { | ||
return useCallback( | ||
(highestVisibleIndex) => { | ||
if (!options[highestVisibleIndex].disabled) { | ||
setFocussedOptionIndex(highestVisibleIndex) | ||
return | ||
} | ||
|
||
// Last option on page is disabled, find next option that's not disabled | ||
const followingEnabledOptionIndex = options | ||
.slice(highestVisibleIndex) | ||
.findIndex((option) => !option.disabled) | ||
|
||
if (followingEnabledOptionIndex >= 0) { | ||
// We need to add the highest visible index because the index is lower due to slicing the array | ||
setFocussedOptionIndex( | ||
followingEnabledOptionIndex + highestVisibleIndex | ||
) | ||
return | ||
} | ||
|
||
// No following enabled option, trying to find the closest previous sibling of the last option on the current page | ||
const closestToEndOfPageEnabledOptionIndex = options | ||
.slice( | ||
// We don't include the currently highlighted option | ||
focussedOptionIndex + 1, | ||
highestVisibleIndex | ||
) | ||
.findLastIndex((option) => !option.disabled) | ||
|
||
if (closestToEndOfPageEnabledOptionIndex >= 0) { | ||
setFocussedOptionIndex( | ||
closestToEndOfPageEnabledOptionIndex + | ||
// We need to add the focused index and 1 because the index is lower due to slicing the array | ||
focussedOptionIndex + | ||
1 | ||
) | ||
return | ||
} | ||
|
||
// The currently highlighted option is the last enabled option | ||
return | ||
}, | ||
[options, focussedOptionIndex, setFocussedOptionIndex] | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters