Skip to content

Commit fa64025

Browse files
authored
Merge pull request #2 from github/composition
Fix keyboard event handling during composition
2 parents 17e8281 + 895f19b commit fa64025

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

combobox-nav.js

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
/* @flow strict */
22

33
export function install(input: HTMLTextAreaElement | HTMLInputElement, list: HTMLElement): void {
4+
input.addEventListener('compositionstart', trackComposition)
5+
input.addEventListener('compositionend', trackComposition)
46
input.addEventListener('keydown', keyboardBindings)
57
list.addEventListener('click', commitWithElement)
68
}
79

810
export function uninstall(input: HTMLTextAreaElement | HTMLInputElement, list: HTMLElement): void {
911
input.removeAttribute('aria-activedescendant')
12+
input.removeEventListener('compositionstart', trackComposition)
13+
input.removeEventListener('compositionend', trackComposition)
1014
input.removeEventListener('keydown', keyboardBindings)
1115
list.removeEventListener('click', commitWithElement)
1216
}
1317

18+
let isComposing = false
1419
const ctrlBindings = !!navigator.userAgent.match(/Macintosh/)
1520

1621
function keyboardBindings(event: KeyboardEvent) {
1722
if (event.shiftKey || event.metaKey || event.altKey) return
1823
const input = event.currentTarget
1924
if (!(input instanceof HTMLTextAreaElement || input instanceof HTMLInputElement)) return
25+
if (isComposing) return
2026
const list = document.getElementById(input.getAttribute('aria-owns') || '')
2127
if (!list) return
2228

2329
switch (event.key) {
2430
case 'Enter':
2531
case 'Tab':
26-
commit(input, list)
27-
event.preventDefault()
32+
if (commit(input, list)) {
33+
event.preventDefault()
34+
}
35+
break
36+
case 'Escape':
37+
clearSelection(list)
2838
break
2939
case 'ArrowDown':
3040
navigate(input, list, 1)
@@ -57,10 +67,11 @@ function commitWithElement(event: MouseEvent) {
5767
event.preventDefault()
5868
}
5969

60-
function commit(input: HTMLTextAreaElement | HTMLInputElement, list: HTMLElement): void {
70+
function commit(input: HTMLTextAreaElement | HTMLInputElement, list: HTMLElement): boolean {
6171
const target = list.querySelector('[aria-selected="true"]')
62-
if (!target) return
72+
if (!target) return false
6373
fireCommitEvent(target)
74+
return true
6475
}
6576

6677
function fireCommitEvent(target: Element): void {
@@ -96,3 +107,20 @@ export function navigate(
96107
}
97108
}
98109
}
110+
111+
function clearSelection(list): void {
112+
const target = list.querySelector('[aria-selected="true"]')
113+
if (!target) return
114+
target.setAttribute('aria-selected', 'false')
115+
}
116+
117+
function trackComposition(event: Event): void {
118+
const input = event.currentTarget
119+
if (!(input instanceof HTMLTextAreaElement || input instanceof HTMLInputElement)) return
120+
isComposing = event.type === 'compositionstart'
121+
122+
const list = document.getElementById(input.getAttribute('aria-owns') || '')
123+
if (!list) return
124+
125+
clearSelection(list)
126+
}

examples/index.html

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@
88
<style>[aria-selected="true"] { font-weight: bold; }</style>
99
</head>
1010
<body>
11-
<label>
12-
Least favorite robot
13-
<input aria-owns="list-id" role="combobox" type="text">
14-
</label>
15-
<ul role="listbox" id="list-id">
16-
<li id="baymax" role="option">Baymax</li>
17-
<li><del>BB-8</del></li>
18-
<li id="hubot" role="option">Hubot</li>
19-
<li id="r2-d2" role="option">R2-D2</li>
20-
</ul>
11+
<form>
12+
<label>
13+
Least favorite robot
14+
<input aria-owns="list-id" role="combobox" type="text">
15+
</label>
16+
<ul role="listbox" id="list-id">
17+
<li id="baymax" role="option">Baymax</li>
18+
<li><del>BB-8</del></li>
19+
<li id="hubot" role="option">Hubot</li>
20+
<li id="r2-d2" role="option">R2-D2</li>
21+
</ul>
22+
</form>
2123
<pre class="events"></pre>
2224
<script type="text/javascript">
2325
comboboxNav.install(document.querySelector('input'), document.querySelector('ul'))

0 commit comments

Comments
 (0)