Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit 8cc235d

Browse files
scharingerTigge
authored andcommitted
feat(selectList): change value with keyboard up/down
When the select list has focus, the key up and down key will change the selected vaue instead of scrolling the list.
1 parent 58c58be commit 8cc235d

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

packages/core/src/SelectList/__snapshots__/index.test.tsx.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ exports[`SelectList SelectList 1`] = `
136136
>
137137
<ul
138138
className="c2"
139+
onKeyDown={[Function]}
139140
onKeyUp={[Function]}
140141
tabIndex={0}
141142
>
@@ -333,6 +334,7 @@ exports[`SelectList SelectList 2`] = `
333334
>
334335
<ul
335336
className="c2"
337+
onKeyDown={[Function]}
336338
onKeyUp={[Function]}
337339
tabIndex={0}
338340
>

packages/core/src/SelectList/index.tsx

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useRef, useEffect } from 'react'
1+
import React, { useCallback, useRef, useEffect, useMemo } from 'react'
22
import styled, { css } from 'styled-components'
33
import { shape, spacing } from '../designparams'
44
import { Typography } from '../Typography'
@@ -126,11 +126,15 @@ export const SelectList: React.FC<SelectListProps> = ({
126126
[onSelect]
127127
)
128128

129+
const selectedValueIndex: number = useMemo(
130+
() => options.findIndex(o => o.value === value),
131+
[options, value]
132+
)
133+
129134
// At first render _only_, scroll to the position of the selected item.
130135
useEffect(() => {
131-
const index = options.findIndex(o => o.value === value)
132-
if (listRef.current !== null && index !== -1) {
133-
listRef.current.scrollTo(0, index * LIST_ITEM_HEIGHT)
136+
if (listRef.current !== null && selectedValueIndex !== -1) {
137+
listRef.current.scrollTo(0, selectedValueIndex * LIST_ITEM_HEIGHT)
134138
}
135139
}, []) // eslint-disable-line react-hooks/exhaustive-deps
136140

@@ -152,10 +156,53 @@ export const SelectList: React.FC<SelectListProps> = ({
152156
[options, listRef]
153157
)
154158

159+
// traversingKeys
160+
enum TraversingKey {
161+
ArrowUp = 'ArrowUp',
162+
ArrowDown = 'ArrowDown',
163+
}
164+
165+
const halfway = Math.round(maxHeight / LIST_ITEM_HEIGHT / 2)
166+
167+
const traverseSelection = useCallback(
168+
(e: React.KeyboardEvent<HTMLUListElement>) => {
169+
if (!(e.key in TraversingKey)) {
170+
return
171+
}
172+
173+
e.preventDefault()
174+
175+
let nextSelectedValueIndex = selectedValueIndex
176+
let nextScrollTopCount = selectedValueIndex
177+
switch (e.key) {
178+
case TraversingKey.ArrowUp:
179+
if (selectedValueIndex === 0) {
180+
return
181+
}
182+
nextSelectedValueIndex--
183+
nextScrollTopCount = nextSelectedValueIndex - halfway
184+
break
185+
case TraversingKey.ArrowDown:
186+
if (selectedValueIndex + 1 === options.length) {
187+
return
188+
}
189+
nextSelectedValueIndex++
190+
nextScrollTopCount = nextSelectedValueIndex - halfway
191+
break
192+
}
193+
onSelect(options[nextSelectedValueIndex].value)
194+
if (listRef.current !== null && selectedValueIndex !== -1) {
195+
listRef.current.scrollTo(0, nextScrollTopCount * LIST_ITEM_HEIGHT)
196+
}
197+
},
198+
[options, value, selectedValueIndex]
199+
)
200+
155201
return (
156202
<SelectListNative
157203
tabIndex={0}
158204
onKeyUp={searchForOption}
205+
onKeyDown={traverseSelection}
159206
maxHeight={`${maxHeight}px`}
160207
ref={listRef}
161208
{...props}

0 commit comments

Comments
 (0)