Skip to content

Commit ed66237

Browse files
committed
fix: keyboard naviagation UX improvement
1 parent 4692e36 commit ed66237

File tree

1 file changed

+45
-2
lines changed

1 file changed

+45
-2
lines changed

packages/webui/src/client/lib/Components/BreadCrumbTextInput.tsx

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ type ReducerActions =
5555
index: number
5656
value: string
5757
}
58+
| {
59+
type: 'focus'
60+
index: number
61+
position: 'begin' | 'end'
62+
}
5863
| {
5964
type: 'clearEdit'
6065
}
@@ -63,6 +68,7 @@ type InputState = {
6368
value: string[]
6469
editingValue: string[] | null
6570
selectIndex: number | null
71+
selectIndexPosition: 'begin' | 'end' | null
6672
}
6773

6874
export function BreadCrumbTextInput({
@@ -89,9 +95,11 @@ export function BreadCrumbTextInput({
8995
newState.editingValue ??= newState.value ?? []
9096
if (action.index === undefined) {
9197
newState.selectIndex = newState.editingValue.push('') - 1
98+
newState.selectIndexPosition = 'end'
9299
} else {
93100
newState.editingValue.splice(action.index, 0, '')
94101
newState.selectIndex = action.index
102+
newState.selectIndexPosition = 'end'
95103
}
96104
break
97105
}
@@ -100,8 +108,10 @@ export function BreadCrumbTextInput({
100108
newState.editingValue.splice(action.index, 1)
101109
if (action.selectPrevious) {
102110
newState.selectIndex = Math.max(0, action.index - 1)
111+
newState.selectIndexPosition = 'end'
103112
} else {
104113
newState.selectIndex = null
114+
newState.selectIndexPosition = 'end'
105115
}
106116
break
107117
}
@@ -112,6 +122,11 @@ export function BreadCrumbTextInput({
112122
}
113123
case 'clearEdit': {
114124
newState.editingValue = null
125+
break
126+
}
127+
case 'focus': {
128+
newState.selectIndex = action.index
129+
newState.selectIndexPosition = action.position
115130
}
116131
}
117132

@@ -120,14 +135,15 @@ export function BreadCrumbTextInput({
120135
{
121136
editingValue: null,
122137
selectIndex: null,
138+
selectIndexPosition: null,
123139
value,
124140
}
125141
)
126142

127143
useEffect(() => {
128144
dispatch({
129145
type: 'setValue',
130-
value
146+
value,
131147
})
132148
}, [dispatch, value])
133149

@@ -185,6 +201,8 @@ export function BreadCrumbTextInput({
185201
index: index + 1,
186202
})
187203
event.stopPropagation()
204+
205+
delete event.currentTarget.dataset['backspace']
188206
} else if (event.key === 'Backspace') {
189207
if (!event.currentTarget.value) {
190208
if (!event.currentTarget.dataset['backspace']) {
@@ -202,6 +220,22 @@ export function BreadCrumbTextInput({
202220
}
203221
}
204222
}
223+
} else if (event.key === 'ArrowLeft' && event.currentTarget.selectionStart === 0) {
224+
dispatch({
225+
type: 'focus',
226+
index: index - 1,
227+
position: 'end'
228+
})
229+
event.preventDefault()
230+
delete event.currentTarget.dataset['backspace']
231+
} else if (event.key === 'ArrowRight' && event.currentTarget.selectionEnd === event.currentTarget.value.length) {
232+
dispatch({
233+
type: 'focus',
234+
index: index + 1,
235+
position: 'begin',
236+
})
237+
event.preventDefault()
238+
delete event.currentTarget.dataset['backspace']
205239
} else {
206240
delete event.currentTarget.dataset['backspace']
207241
}
@@ -250,7 +284,16 @@ export function BreadCrumbTextInput({
250284
if (!inputToFocus || !(inputToFocus instanceof HTMLInputElement)) return
251285

252286
inputToFocus.focus()
253-
}, [inputState.selectIndex])
287+
288+
if (inputState.selectIndexPosition === null) return
289+
if (inputState.selectIndexPosition === 'end') {
290+
inputToFocus.selectionStart = inputToFocus.value.length
291+
inputToFocus.selectionEnd = inputToFocus.selectionStart
292+
} else if (inputState.selectIndexPosition === 'begin') {
293+
inputToFocus.selectionStart = 0
294+
inputToFocus.selectionEnd = 0
295+
}
296+
}, [inputState.selectIndex, inputState.selectIndexPosition])
254297

255298
return (
256299
<div className="input-breadcrumbtext" ref={inputRef} tabIndex={0} onBlur={handleBlur}>

0 commit comments

Comments
 (0)