From 23477bc422a19c7d8775bafdf2192c4b06142bb7 Mon Sep 17 00:00:00 2001 From: Frantz Kati Date: Sun, 26 Jul 2020 02:51:41 +0100 Subject: [PATCH] 03-accessible-keyboard-navigation --- .../react/src/molecules/Select/Select.tsx | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/packages/react/src/molecules/Select/Select.tsx b/packages/react/src/molecules/Select/Select.tsx index 5b2dd81..bd4605d 100644 --- a/packages/react/src/molecules/Select/Select.tsx +++ b/packages/react/src/molecules/Select/Select.tsx @@ -5,7 +5,9 @@ import Text from '../../atoms/Text' const KEY_CODES = { ENTER: 13, SPACE: 32, - DOWN_ARROW: 40 + DOWN_ARROW: 40, + ESC: 27, + UP_ARROW: 38 } interface SelectOption { @@ -26,6 +28,30 @@ interface SelectProps { renderOption?: (props: RenderOptionProps) => React.ReactNode } +const getPreviousOptionIndex = (currentIndex: number|null, options: Array) => { + if (currentIndex === null) { + return 0 + } + + if (currentIndex === 0) { + return options.length - 1 + } + + return currentIndex - 1 +} + +const getNextOptionIndex = (currentIndex: number|null, options: Array) => { + if (currentIndex === null) { + return 0 + } + + if (currentIndex === options.length - 1) { + return 0 + } + + return currentIndex + 1 +} + const Select: React.FunctionComponent = ({ options = [], label = 'Please select an option ...', onOptionSelected: handler, renderOption }) => { const [isOpen, setIsOpen] = useState(false) const [selectedIndex, setSelectedIndex] = useState(null) @@ -59,7 +85,7 @@ const Select: React.FunctionComponent = ({ options = [], label = 'P selectedOption = options[selectedIndex] } - const highlightItem = (optionIndex: number|null) => { + const highlightOption = (optionIndex: number|null) => { setHighlightedIndex(optionIndex) } @@ -70,7 +96,7 @@ const Select: React.FunctionComponent = ({ options = [], label = 'P setIsOpen(true) // set focus on the list item - highlightItem(0) + highlightOption(0) } } @@ -86,7 +112,29 @@ const Select: React.FunctionComponent = ({ options = [], label = 'P ref.current.focus() } } - }, [isOpen]) + }, [isOpen, highlightedIndex]) + + const onOptionKeyDown: KeyboardEventHandler = (event) => { + if (event.keyCode === KEY_CODES.ESC) { + setIsOpen(false) + + return + } + + if (event.keyCode === KEY_CODES.DOWN_ARROW) { + highlightOption(getNextOptionIndex(highlightedIndex, options)) + } + + if (event.keyCode === KEY_CODES.UP_ARROW) { + highlightOption( + getPreviousOptionIndex(highlightedIndex, options) + ) + } + + if (event.keyCode === KEY_CODES.ENTER) { + onOptionSelected(options[highlightedIndex!], highlightedIndex!) + } + } return