fix: improve autosuggest a11y (#1630)

* fix: improve autosuggest a11y

some progress on #1629

- works in Chrome on NVDA now
- works in Chrome on VoiceOver now
- shorter aria-labels, don't repeat information like "1 of 3", because
it causes the screen reader to speak too frequently, e.g. when the
selected result hasn't changed but the number of results has. Also both
NVDA and VoiceOver already speak this information
- stop doing a fancy fade animation, just show and hide the input
instantly. I worry it confuses screen readers to have the aria-hidden
attribute in there at all
- stop using a single id to identify the active descendant - give
immutable IDs and then update the aria-activedescendant instead. I think
this is what fixed Chrome.

* fix test
This commit is contained in:
Nolan Lawson 2019-11-09 20:38:29 -05:00 committed by GitHub
parent c5a005186c
commit 07facea505
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 21 additions and 21 deletions

View file

@ -1,6 +1,4 @@
<div class="compose-autosuggest {shown ? 'shown' : ''} {realm === 'dialog' ? 'is-dialog' : ''}"
aria-hidden={!shown}
>
<div class="compose-autosuggest {shown ? '' : 'not-shown'} {realm === 'dialog' ? 'is-dialog' : ''}">
<ComposeAutosuggestionList
items={autosuggestSearchResults}
on:click="onClick(event)"
@ -15,17 +13,13 @@
position: absolute;
left: 5px;
top: 0;
pointer-events: none;
opacity: 0;
transition: opacity 0.1s linear;
z-index: 7000;
}
.compose-autosuggest.is-dialog {
z-index: 11000;
}
.compose-autosuggest.shown {
pointer-events: auto;
opacity: 1;
.compose-autosuggest.not-shown {
display: none;
}
@media (min-width: 480px) {

View file

@ -4,7 +4,7 @@
role="listbox"
>
{#each items as item, i (item.shortcode || item.id || item.name)}
<li id="{i === selected ? `compose-autosuggest-active-item-${realm}` : ''}"
<li id="compose-autosuggest-active-item-{realm}-{i}"
class="compose-autosuggest-list-item {i === selected ? 'selected' : ''}"
role="option"
aria-selected="{i === selected}"

View file

@ -3,10 +3,10 @@
class="compose-box-input compose-box-input-realm-{realm}"
placeholder="What's on your mind?"
aria-describedby="compose-box-input-description-{realm}"
aria-owns="{autosuggestShownForThisInput ? `compose-autosuggest-list-${realm}` : undefined}"
aria-owns="compose-autosuggest-list-{realm}"
aria-expanded={autosuggestShownForThisInput}
aria-autocomplete="both"
aria-activedescendant="{autosuggestShownForThisInput ? `compose-autosuggest-active-item-${realm}` : undefined}"
aria-activedescendant={activeDescendant}
ref:textarea
bind:value=rawText
on:blur="onBlur()"
@ -268,10 +268,17 @@
composeFocused: ({ $autosuggestData_composeFocused, $currentInstance, realm }) => (
get($autosuggestData_composeFocused, [$currentInstance, realm], false)
),
/* eslint-enable camelcase */
autosuggestShownForThisInput: ({ realm, $autosuggestShown, composeFocused }) => (
autosuggestShownForThisInput: ({ $autosuggestShown, composeFocused }) => (
!!($autosuggestShown && composeFocused)
),
autosuggestSelected: ({ $autosuggestData_autosuggestSelected, $currentInstance, realm }) => (
get($autosuggestData_autosuggestSelected, [$currentInstance, realm], 0)
),
activeDescendant: ({ autosuggestSelected, autosuggestShownForThisInput, realm }) => (
autosuggestShownForThisInput ? `compose-autosuggest-active-item-${realm}-${autosuggestSelected}` : undefined
)
/* eslint-enable camelcase */
},
events: {
selectionChange

View file

@ -17,6 +17,5 @@ export function createAutosuggestAccessibleLabel (
: displayName
label = `${displayName} @${selected.acct}`
}
return `${label} (${selectedIndex + 1} of ${searchResults.length}). ` +
'Press up and down arrows to review and enter to select.'
return label
}

View file

@ -110,7 +110,7 @@ test('autosuggest only shows for one input', async t => {
.selectText(getNthComposeReplyInput(1))
.pressKey('delete')
.typeText(getNthComposeReplyInput(1), 'uu')
.expect($('.compose-autosuggest.shown').exists).notOk()
.expect($('.compose-autosuggest').visible).notOk()
})
test('autosuggest only shows for one input part 2', async t => {
@ -118,7 +118,7 @@ test('autosuggest only shows for one input part 2', async t => {
await t
.hover(composeInput)
.typeText(composeInput, '@adm')
.expect($('.compose-autosuggest.shown').exists).ok({ timeout })
.expect($('.compose-autosuggest').visible).ok({ timeout })
.expect(getNthAutosuggestionResult(1).innerText).contains('@admin')
.hover(getNthStatus(1))
.click(getNthReplyButton(1))
@ -127,7 +127,7 @@ test('autosuggest only shows for one input part 2', async t => {
.typeText(getNthComposeReplyInput(1), '@dd')
await sleep(1000)
await t.pressKey('backspace')
.expect($('.compose-autosuggest.shown').exists).notOk()
.expect($('.compose-autosuggest').visible).notOk()
})
test('autocomplete disappears on blur', async t => {
@ -135,7 +135,7 @@ test('autocomplete disappears on blur', async t => {
await t
.hover(composeInput)
.typeText(composeInput, '@adm')
.expect($('.compose-autosuggest.shown').exists).ok({ timeout })
.expect($('.compose-autosuggest').visible).ok({ timeout })
.click(composeLengthIndicator)
.expect($('.compose-autosuggest.shown').exists).notOk()
.expect($('.compose-autosuggest').visible).notOk()
})