Skip to content

Commit

Permalink
fix(VSelect): expose clickable icons to screen readers (vuetifyjs#10489)
Browse files Browse the repository at this point in the history
* fix(VSelect): allow clickable append/prepend icons to be focused

* refactor(VTextField): always render a named icon when clearable

* refactor(VInput): use default argument instead of or operator
  • Loading branch information
KaelWD authored and epicpants64 committed Feb 7, 2020
1 parent 0f0c05e commit 1119810
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,14 @@ exports[`VFileInput.ts should render 1`] = `
>
</div>
<div class="v-input__append-inner">
<div class="v-input__icon">
<i aria-hidden="true"
class="v-icon notranslate material-icons theme--light"
<div class="v-input__icon v-input__icon--clear">
<button disabled="disabled"
type="button"
aria-label="clear icon"
class="v-icon notranslate v-icon--disabled v-icon--link material-icons theme--light"
>
</i>
$clear
</button>
</div>
</div>
</div>
Expand Down Expand Up @@ -429,11 +432,14 @@ exports[`VFileInput.ts should render without icon 1`] = `
>
</div>
<div class="v-input__append-inner">
<div class="v-input__icon">
<i aria-hidden="true"
class="v-icon notranslate material-icons theme--light"
<div class="v-input__icon v-input__icon--clear">
<button disabled="disabled"
type="button"
aria-label="clear icon"
class="v-icon notranslate v-icon--disabled v-icon--link material-icons theme--light"
>
</i>
$clear
</button>
</div>
</div>
</div>
Expand Down
3 changes: 3 additions & 0 deletions packages/vuetify/src/components/VInput/VInput.sass
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@
&--clear
border-radius: 50%

.v-icon--disabled
visibility: hidden

&__slot
align-items: center
color: inherit
Expand Down
10 changes: 5 additions & 5 deletions packages/vuetify/src/components/VInput/VInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
getSlot,
kebabCase,
} from '../../util/helpers'
import mergeData from '../../util/mergeData'

// Types
import { VNode, VNodeData, PropType } from 'vue'
Expand Down Expand Up @@ -165,17 +166,16 @@ export default baseMixins.extend<options>().extend({
},
genIcon (
type: string,
cb?: (e: Event) => void
cb?: (e: Event) => void,
extraData: VNodeData = {}
) {
const icon = (this as any)[`${type}Icon`]
const eventName = `click:${kebabCase(type)}`
const hasListener = !!(this.listeners$[eventName] || cb)

const data: VNodeData = {
const data = mergeData({
attrs: {
'aria-label': hasListener ? kebabCase(type).split('-')[0] + ' icon' : undefined,
},
props: {
color: this.validationState,
dark: this.dark,
disabled: this.disabled,
Expand All @@ -198,7 +198,7 @@ export default baseMixins.extend<options>().extend({
e.stopPropagation()
},
},
}
}, extraData)

return this.$createElement('div', {
staticClass: `v-input__icon`,
Expand Down
28 changes: 15 additions & 13 deletions packages/vuetify/src/components/VSelect/VSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import mergeData from '../../util/mergeData'

// Types
import mixins from '../../util/mixins'
import { VNode, VNodeDirective, PropType } from 'vue'
import { VNode, VNodeDirective, PropType, VNodeData } from 'vue'
import { SelectItemKey } from 'types'

export const defaultMenuProps = {
Expand Down Expand Up @@ -416,19 +416,21 @@ export default baseMixins.extend<options>().extend({
},
genIcon (
type: string,
cb?: (e: Event) => void
cb?: (e: Event) => void,
extraData?: VNodeData
) {
const icon = VInput.options.methods.genIcon.call(this, type, cb)

icon.children![0].data = mergeData(icon.children![0].data!, {
attrs: {
tabindex: type !== 'append'
? undefined
: (icon.children![0].componentOptions!.listeners && '-1'),
'aria-hidden': 'true',
'aria-label': undefined,
},
})
const icon = VInput.options.methods.genIcon.call(this, type, cb, extraData)

if (type === 'append') {
// Don't allow the dropdown icon to be focused
icon.children![0].data = mergeData(icon.children![0].data!, {
attrs: {
tabindex: icon.children![0].componentOptions!.listeners && '-1',
'aria-hidden': 'true',
'aria-label': undefined,
},
})
}

return icon
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ exports[`VSelect.ts should be clearable with prop, dirty and multi select 1`] =
</div>
<div class="v-input__append-inner">
<div class="v-input__icon v-input__icon--clear">
<button aria-hidden="true"
type="button"
<button type="button"
aria-label="clear icon"
class="v-icon notranslate v-icon--link material-icons theme--light"
>
$clear
Expand Down Expand Up @@ -83,8 +83,8 @@ exports[`VSelect.ts should be clearable with prop, dirty and single select 1`] =
</div>
<div class="v-input__append-inner">
<div class="v-input__icon v-input__icon--clear">
<button aria-hidden="true"
type="button"
<button type="button"
aria-label="clear icon"
class="v-icon notranslate v-icon--link material-icons theme--light"
>
$clear
Expand Down
8 changes: 2 additions & 6 deletions packages/vuetify/src/components/VTextField/VTextField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,10 @@ export default baseMixins.extend<options>().extend({
genClearIcon () {
if (!this.clearable) return null

const icon = this.isDirty ? 'clear' : ''
const cb = this.isDirty ? this.clearableCallback : undefined
const data = this.isDirty ? undefined : { attrs: { disabled: true } }

return this.genSlot('append', 'inner', [
this.genIcon(
icon,
cb
),
this.genIcon('clear', this.clearableCallback, data),
])
},
genCounter () {
Expand Down
9 changes: 9 additions & 0 deletions packages/vuetify/src/util/mergeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export default function mergeData (): VNodeData {
case 'class':
case 'style':
case 'directives':
if (!arguments[i][prop]) {
break
}
if (!Array.isArray(mergeTarget[prop])) {
mergeTarget[prop] = []
}
Expand Down Expand Up @@ -98,6 +101,9 @@ export default function mergeData (): VNodeData {
// uses the last given value to assign.
case 'on':
case 'nativeOn':
if (!arguments[i][prop]) {
break
}
if (!mergeTarget[prop]) {
mergeTarget[prop] = {}
}
Expand All @@ -124,6 +130,9 @@ export default function mergeData (): VNodeData {
case 'staticStyle':
case 'hook':
case 'transition':
if (!arguments[i][prop]) {
break
}
if (!mergeTarget[prop]) {
mergeTarget[prop] = {}
}
Expand Down

0 comments on commit 1119810

Please sign in to comment.