diff --git a/dev/components/components/button.vue b/dev/components/components/button.vue
index 7a33bbb92453..13c2b780fbc6 100644
--- a/dev/components/components/button.vue
+++ b/dev/components/components/button.vue
@@ -50,10 +50,17 @@
@@ -480,7 +487,9 @@ export default {
loading2: false,
percentage: 0,
clickTimes: 0,
- test: 'Initial value'
+ test: 'Initial value',
+ testN: 0,
+ tag: 'button'
}
},
methods: {
@@ -517,9 +526,11 @@ export default {
},
submit () {
this.$q.notify('Submit called')
+ console.log('test', this.test, 'testN', this.testN)
},
reset () {
this.test = 'Initial value'
+ this.testN = 0
this.$q.notify('Reset called')
}
},
diff --git a/dev/components/components/fab.vue b/dev/components/components/fab.vue
index 5ff865d56119..9a3c26209ee8 100644
--- a/dev/components/components/fab.vue
+++ b/dev/components/components/fab.vue
@@ -19,7 +19,6 @@
-
@@ -52,6 +51,8 @@
+
+
There's also the absolute positioned one on bottom
right of screen which maintains position on Page scroll.
diff --git a/dev/components/components/popover.vue b/dev/components/components/popover.vue
index 720bcfcddbff..311bc97c97ad 100644
--- a/dev/components/components/popover.vue
+++ b/dev/components/components/popover.vue
@@ -17,6 +17,8 @@
:key="n"
v-close-overlay
@click.native="showNotify()"
+ @keyup.native.13.32="showNotify()"
+ :tabindex="0"
>
@@ -32,6 +34,8 @@
:key="n"
v-close-overlay
@click.native="showNotify()"
+ @keyup.native.13.32="showNotify()"
+ :tabindex="0"
>
@@ -57,7 +61,9 @@
v-for="n in 3"
:key="n"
v-close-overlay
- @click="showNotify()"
+ @click.native="showNotify()"
+ @keyup.native.13.32="showNotify()"
+ :tabindex="0"
>
@@ -118,6 +124,8 @@
src="~assets/map.png"
style="height: 150px; width: 200px;"
@click="showNotify(), $refs.popover3.hide()"
+ @keyup.13.32="showNotify(), $refs.popover3.hide()"
+ :tabindex="0"
>
@@ -140,6 +148,8 @@
v-for="n in 20"
:key="n"
@click.native="showNotify(), $refs.popover5.hide()"
+ @keyup.native.13.32="showNotify(), $refs.popover5.hide()"
+ :tabindex="0"
>
diff --git a/dev/components/form/select.vue b/dev/components/form/select.vue
index a48946c239e1..1a6d18f823b2 100644
--- a/dev/components/form/select.vue
+++ b/dev/components/form/select.vue
@@ -58,11 +58,11 @@
With Filter
-
-
-
-
-
+
+
+
+
+
With Static Label
diff --git a/src/components/action-sheet/QActionSheet.js b/src/components/action-sheet/QActionSheet.js
index 2dadd7c63a11..4b8e48735e72 100644
--- a/src/components/action-sheet/QActionSheet.js
+++ b/src/components/action-sheet/QActionSheet.js
@@ -59,7 +59,7 @@ export default {
},
nativeOn: {
click: this.__onCancel,
- keydown: this.__onKeyCancel
+ keyup: this.__onKeyCancel
}
}, [
h(QItemMain, { staticClass: 'text-center text-primary' }, [
@@ -116,7 +116,7 @@ export default {
},
[this.grid ? 'on' : 'nativeOn']: {
click: () => this.__onOk(action),
- keydown: e => {
+ keyup: e => {
if (getEventKey(e) === /* Enter */ 13) {
this.__onOk(action)
}
diff --git a/src/components/autocomplete/QAutocomplete.js b/src/components/autocomplete/QAutocomplete.js
index fb55c630eee0..e488b754dd42 100644
--- a/src/components/autocomplete/QAutocomplete.js
+++ b/src/components/autocomplete/QAutocomplete.js
@@ -218,7 +218,8 @@ export default {
'class': dark ? 'bg-dark' : null,
props: {
fit: true,
- anchorClick: false
+ anchorClick: false,
+ noFocus: true
},
on: {
show: () => {
diff --git a/src/components/color/QColorPicker.js b/src/components/color/QColorPicker.js
index 066b33a102a2..4458ee93365e 100644
--- a/src/components/color/QColorPicker.js
+++ b/src/components/color/QColorPicker.js
@@ -127,8 +127,7 @@ export default {
? [{
name: 'touch-pan',
modifiers: {
- prevent: true,
- stop: true
+ mightPrevent: true
},
value: this.__saturationPan
}]
diff --git a/src/components/datetime/QDatetimePicker.mat.vue b/src/components/datetime/QDatetimePicker.mat.vue
index 5d11bff476bc..e19022a0c142 100644
--- a/src/components/datetime/QDatetimePicker.mat.vue
+++ b/src/components/datetime/QDatetimePicker.mat.vue
@@ -7,23 +7,35 @@
- {{ monthString }}
+
+ {{ monthString }}
+
- {{ day }}
+
+ {{ day }}
+
- {{ year }}
+
+ {{ year }}
+
@@ -31,34 +43,52 @@
v-if="typeHasTime"
class="q-datetime-time row flex-center"
>
-
+
- {{ __pad(hour, ' ') }}
+
+ {{ hour }}
+
:
- {{ __pad(minute) }}
+
+ {{ __pad(minute) }}
+
AM
+ @keyup.13.32="toggleAmPm()"
+ :tabindex="0"
+ >
+
+ AM
+
+
PM
+ @keyup.13.32="toggleAmPm()"
+ :tabindex="0"
+ >
+
+ PM
+
+
@@ -76,6 +106,7 @@
:class="{active: n + yearMin === year}"
:disable="!editable"
@click="setYear(n + yearMin)"
+ :tabindex="-1"
>
{{ n + yearMin }}
@@ -93,6 +124,7 @@
:class="{active: month === index + monthMin}"
:disable="!editable"
@click="setMonth(index + monthMin, true)"
+ :tabindex="-1"
>
{{ $q.i18n.date.months[index + monthMin - 1] }}
@@ -112,6 +144,7 @@
:repeat-timeout="__repeatTimeout"
:disable="beforeMinDays > 0 || disable || readonly"
@click="setMonth(month - 1)"
+ :tabindex="-1"
/>
{{ monthStamp }}
@@ -125,6 +158,7 @@
:repeat-timeout="__repeatTimeout"
:disable="afterMaxDays > 0 || disable || readonly"
@click="setMonth(month + 1)"
+ :tabindex="-1"
/>
@@ -392,25 +426,29 @@ export default {
},
methods: {
/* date */
- setYear (value) {
+ setYear (value, skipView) {
if (this.editable) {
- this.view = 'day'
+ if (!skipView) {
+ this.view = 'day'
+ }
this.model = new Date(this.model.setFullYear(this.__parseTypeValue('year', value)))
}
},
- setMonth (value) {
+ setMonth (value, skipView) {
if (this.editable) {
- this.view = 'day'
+ if (!skipView) {
+ this.view = 'day'
+ }
this.model = adjustDate(this.model, {month: value})
}
},
- setDay (value) {
+ setDay (value, skipView) {
if (this.editable) {
this.model = new Date(this.model.setDate(this.__parseTypeValue('date', value)))
if (this.type === 'date') {
this.$emit('canClose')
}
- else {
+ else if (!skipView) {
this.view = 'hour'
}
}
diff --git a/src/components/datetime/datetime.mat.styl b/src/components/datetime/datetime.mat.styl
index 443f3e0cc278..cfdbb0db4673 100644
--- a/src/components/datetime/datetime.mat.styl
+++ b/src/components/datetime/datetime.mat.styl
@@ -39,6 +39,10 @@ div + .q-datetime-time
.q-datetime-link
cursor pointer
opacity .6
+ > span
+ display inline-block
+ width 100%
+ outline none
&.active
opacity 1
@@ -168,10 +172,11 @@ div + .q-datetime-time
&.q-datetime-day-active > span, &:not(.q-datetime-fillerday):not(.disabled):not(.q-datetime-day-active):hover
color black
-body.desktop .q-datetime-clock-position:not(.active):hover
- background $grey-2 !important
-body.desktop .q-datetime-dark .q-datetime-clock-position:not(.active):hover
- color black
+body.desktop
+ .q-datetime-clock-position:not(.active):hover
+ background $grey-2 !important
+ .q-datetime-dark .q-datetime-clock-position:not(.active):hover
+ color black
.q-datetime-clock-position
position absolute
diff --git a/src/components/dialog/QDialog.js b/src/components/dialog/QDialog.js
index bdea517220a3..77834c75a8fc 100644
--- a/src/components/dialog/QDialog.js
+++ b/src/components/dialog/QDialog.js
@@ -23,6 +23,7 @@ export default {
preventClose: Boolean,
noBackdropDismiss: Boolean,
noEscDismiss: Boolean,
+ noRefocus: Boolean,
position: String,
color: {
type: String,
@@ -86,6 +87,7 @@ export default {
minimized: true,
noBackdropDismiss: this.noBackdropDismiss || this.preventClose,
noEscDismiss: this.noEscDismiss || this.preventClose,
+ noRefocus: this.noRefocus,
position: this.position
},
on: {
@@ -95,7 +97,7 @@ export default {
show: () => {
this.$emit('show')
- if (!this.$q.platform.is.desktop || (!this.prompt && !this.options)) {
+ if (!this.$q.platform.is.desktop) {
return
}
@@ -108,7 +110,7 @@ export default {
return
}
- node = this.$refs.modal.$el.getElementsByTagName('BUTTON')
+ node = this.$refs.modal.$el.getElementsByClassName('q-btn')
if (node.length) {
node[node.length - 1].focus()
}
diff --git a/src/components/fab/QFab.js b/src/components/fab/QFab.js
index 7911518ccc70..54a64b3aa2bc 100644
--- a/src/components/fab/QFab.js
+++ b/src/components/fab/QFab.js
@@ -8,7 +8,10 @@ export default {
mixins: [FabMixin, ModelToggleMixin],
provide () {
return {
- __qFabClose: this.hide
+ __qFabClose: evt => this.hide(evt).then(() => {
+ this.$refs.trigger && this.$refs.trigger.$el && this.$refs.trigger.$el.focus()
+ return evt
+ })
}
},
props: {
@@ -37,6 +40,7 @@ export default {
}
}, [
h(QBtn, {
+ ref: 'trigger',
props: {
fab: true,
outline: this.outline,
@@ -64,7 +68,7 @@ export default {
h('div', {
staticClass: 'q-fab-actions flex no-wrap inline items-center',
'class': `q-fab-${this.direction}`
- }, this.$slots.default)
+ }, this.showing ? this.$slots.default : null)
])
}
}
diff --git a/src/components/knob/QKnob.js b/src/components/knob/QKnob.js
index 9e912d834636..d19ca2440260 100644
--- a/src/components/knob/QKnob.js
+++ b/src/components/knob/QKnob.js
@@ -66,6 +66,9 @@ export default {
},
computedDecimals () {
return this.decimals !== void 0 ? this.decimals || 0 : (String(this.step).trim('0').split('.')[1] || '').length
+ },
+ computedStep () {
+ return this.decimals !== void 0 ? 1 / Math.pow(10, this.decimals || 0) : this.step
}
},
data () {
@@ -142,18 +145,35 @@ export default {
}, 100)
this.__onInput(ev, this.centerPosition, true)
},
+ __onKeyDown (ev) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ const step = ev.ctrlKey ? 10 * this.computedStep : this.computedStep
+ const offset = [37, 40].includes(keyCode) ? -step : step
+ this.__onInputValue(between(this.model + offset, this.min, this.max))
+ },
+ __onKeyUp (ev) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ this.__emitChange()
+ },
__onInput (ev, center = this.__getCenter(), emitChange) {
if (!this.editable) {
return
}
- let
+ const
pos = position(ev),
height = Math.abs(pos.top - center.top),
distance = Math.sqrt(
Math.pow(Math.abs(pos.top - center.top), 2) +
Math.pow(Math.abs(pos.left - center.left), 2)
- ),
- angle = Math.asin(height / distance) * (180 / Math.PI)
+ )
+
+ let angle = Math.asin(height / distance) * (180 / Math.PI)
if (pos.top < center.top) {
angle = center.left < pos.left ? 90 - angle : 270 + angle
@@ -166,16 +186,18 @@ export default {
angle = 360 - angle
}
- let
+ const
model = this.min + (angle / 360) * (this.max - this.min),
modulo = model % this.step
- let value = between(
+ const value = between(
model - modulo + (Math.abs(modulo) >= this.step / 2 ? (modulo < 0 ? -1 : 1) * this.step : 0),
this.min,
this.max
)
-
+ this.__onInputValue(value, emitChange)
+ },
+ __onInputValue (value, emitChange) {
if (this.computedDecimals) {
value = parseFloat(value.toFixed(this.computedDecimals))
}
@@ -192,13 +214,16 @@ export default {
this.$emit('input', value)
if (emitChange) {
- this.$nextTick(() => {
- if (JSON.stringify(value) !== JSON.stringify(this.value)) {
- this.$emit('change', value)
- }
- })
+ this.__emitChange(value)
}
},
+ __emitChange (value = this.model) {
+ this.$nextTick(() => {
+ if (JSON.stringify(value) !== JSON.stringify(this.value)) {
+ this.$emit('change', value)
+ }
+ })
+ },
__getCenter () {
let knobOffset = offset(this.$el)
return {
@@ -255,7 +280,16 @@ export default {
h(
'div',
- { staticClass: 'q-knob-label row flex-center content-center' },
+ {
+ staticClass: 'q-knob-label row flex-center content-center',
+ attrs: {
+ tabindex: this.editable ? 0 : -1
+ },
+ on: {
+ keydown: this.__onKeyDown,
+ keyup: this.__onKeyUp
+ }
+ },
this.$slots.default || [
h('span', [ this.model ])
]
diff --git a/src/components/modal/QModal.js b/src/components/modal/QModal.js
index 83698c95142f..921aad1bb1fb 100644
--- a/src/components/modal/QModal.js
+++ b/src/components/modal/QModal.js
@@ -83,6 +83,7 @@ export default {
default: false
},
noRouteDismiss: Boolean,
+ noRefocus: Boolean,
minimized: Boolean,
maximized: Boolean
},
@@ -146,6 +147,9 @@ export default {
})
},
__show () {
+ if (!this.noRefocus) {
+ this.__refocusTarget = document.activeElement
+ }
const body = document.body
body.appendChild(this.$el)
@@ -156,6 +160,7 @@ export default {
if (!this.noEscDismiss) {
this.hide().then(() => {
this.$emit('escape-key')
+ this.$emit('dismiss')
})
}
})
@@ -171,11 +176,15 @@ export default {
el.scrollTop = 0
})
})
+ this.$nextTick(() => content.focus())
},
__hide () {
EscapeKey.pop()
this.__preventScroll(false)
this.__register(false)
+ if (!this.noRefocus && this.__refocusTarget) {
+ this.__refocusTarget.focus()
+ }
},
__stopPropagation (e) {
e.stopPropagation()
@@ -245,6 +254,7 @@ export default {
staticClass: 'modal-content scroll',
style: this.modalCss,
'class': this.contentClasses,
+ attrs: { tabindex: -1 },
on: {
click: this.__stopPropagation,
touchstart: this.__stopPropagation
diff --git a/src/components/modal/modal.ios.styl b/src/components/modal/modal.ios.styl
index e5122fe40340..da33e9d6f172 100644
--- a/src/components/modal/modal.ios.styl
+++ b/src/components/modal/modal.ios.styl
@@ -18,6 +18,7 @@ maximized-modal()
max-height 80vh
border-radius $modal-border-radius
-webkit-backface-visibility hidden
+ outline none
.modal
z-index $z-modal
diff --git a/src/components/modal/modal.mat.styl b/src/components/modal/modal.mat.styl
index 78171570ea48..dd821d5335e5 100644
--- a/src/components/modal/modal.mat.styl
+++ b/src/components/modal/modal.mat.styl
@@ -16,6 +16,7 @@ maximized-modal()
min-width 280px
max-height 80vh
-webkit-backface-visibility hidden
+ outline none
.modal
z-index $z-modal
diff --git a/src/components/popover/QPopover.js b/src/components/popover/QPopover.js
index c739380ab9a4..66c36c87e740 100644
--- a/src/components/popover/QPopover.js
+++ b/src/components/popover/QPopover.js
@@ -39,6 +39,8 @@ export default {
type: Array,
validator: offsetValidator
},
+ noFocus: Boolean,
+ noRefocus: Boolean,
disable: Boolean
},
watch: {
@@ -59,6 +61,8 @@ export default {
return h('div', {
staticClass: 'q-popover scroll',
+ ref: 'content',
+ attrs: { tabindex: -1 },
on: {
click (e) { e.stopPropagation() }
}
@@ -75,6 +79,7 @@ export default {
if (this.anchorClick) {
this.anchorEl.classList.add('cursor-pointer')
this.anchorEl.addEventListener('click', this.toggle)
+ this.anchorEl.addEventListener('keyup', this.__toggleKey)
}
})
if (this.value) {
@@ -84,10 +89,14 @@ export default {
beforeDestroy () {
if (this.anchorClick && this.anchorEl) {
this.anchorEl.removeEventListener('click', this.toggle)
+ this.anchorEl.removeEventListener('keyup', this.__toggleKey)
}
},
methods: {
__show (evt) {
+ if (!this.noRefocus) {
+ this.__refocusTarget = document.activeElement
+ }
document.body.appendChild(this.$el)
EscapeKey.register(() => { this.hide() })
this.scrollTarget = getScrollTarget(this.anchorEl)
@@ -96,12 +105,20 @@ export default {
this.__updatePosition(0, evt, true)
clearTimeout(this.timer)
+ if (!this.noFocus && this.$refs.content) {
+ this.$refs.content.focus()
+ }
this.timer = setTimeout(() => {
document.body.addEventListener('click', this.__bodyHide, true)
document.body.addEventListener('touchstart', this.__bodyHide, true)
this.showPromise && this.showPromiseResolve()
}, 0)
},
+ __toggleKey (evt) {
+ if (evt.keyCode === 13) {
+ this.toggle(evt)
+ }
+ },
__bodyHide (evt) {
if (
evt && evt.target &&
@@ -123,6 +140,9 @@ export default {
document.body.removeChild(this.$el)
this.hidePromise && this.hidePromiseResolve()
+ if (!this.noRefocus && this.__refocusTarget) {
+ this.__refocusTarget.focus()
+ }
},
reposition (event, animate) {
if (this.fit) {
diff --git a/src/components/popover/popover.ios.styl b/src/components/popover/popover.ios.styl
index 4c7634b9cce6..15e9877e34af 100644
--- a/src/components/popover/popover.ios.styl
+++ b/src/components/popover/popover.ios.styl
@@ -6,6 +6,7 @@
overflow-y auto
overflow-x hidden
max-width $popover-max-width
+ outline none
> .q-list:only-child
border none
diff --git a/src/components/popover/popover.mat.styl b/src/components/popover/popover.mat.styl
index 4c7634b9cce6..15e9877e34af 100644
--- a/src/components/popover/popover.mat.styl
+++ b/src/components/popover/popover.mat.styl
@@ -6,6 +6,7 @@
overflow-y auto
overflow-x hidden
max-width $popover-max-width
+ outline none
> .q-list:only-child
border none
diff --git a/src/components/range/QRange.js b/src/components/range/QRange.js
index f20418e2bea7..2116de40c322 100644
--- a/src/components/range/QRange.js
+++ b/src/components/range/QRange.js
@@ -240,6 +240,29 @@ export default {
this.currentMinPercentage = (this.model.min - this.min) / (this.max - this.min)
this.currentMaxPercentage = (this.model.max - this.min) / (this.max - this.min)
},
+ __onKeyDown (ev, type) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ const
+ decimals = this.computedDecimals,
+ step = ev.ctrlKey ? 10 * this.computedStep : this.computedStep,
+ offset = [37, 40].includes(keyCode) ? -step : step,
+ model = decimals ? parseFloat((this.model[type] + offset).toFixed(decimals)) : (this.model[type] + offset)
+
+ this.model[type] = between(model, type === 'min' ? this.min : this.model.min, type === 'max' ? this.max : this.model.max)
+ this.currentMinPercentage = (this.model.min - this.min) / (this.max - this.min)
+ this.currentMaxPercentage = (this.model.max - this.min) / (this.max - this.min)
+ this.__update()
+ },
+ __onKeyUp (ev, type) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ this.__update(true)
+ },
__validateProps () {
if (this.min >= this.max) {
console.error('Range error: min >= max', this.$el, this.min, this.max)
@@ -266,7 +289,12 @@ export default {
'class': [
edge ? 'handle-at-minimum' : null,
{ dragging: this.dragging }
- ]
+ ],
+ attrs: { tabindex: this.editable ? 0 : -1 },
+ on: {
+ keydown: ev => this.__onKeyDown(ev, lower),
+ keyup: ev => this.__onKeyUp(ev, lower)
+ }
}, [
this.label || this.labelAlways
? h(QChip, {
diff --git a/src/components/select/QSelect.vue b/src/components/select/QSelect.vue
index 5331a0f08677..62f3fefd84ab 100644
--- a/src/components/select/QSelect.vue
+++ b/src/components/select/QSelect.vue
@@ -77,13 +77,13 @@
:class="dark ? 'bg-dark' : null"
@show="__onShow"
@hide="__onClose(true)"
+ @keydown.native="__keyboardHandleKey"
>
popover.reposition())
}
},
@@ -388,7 +387,7 @@ export default {
return
}
this.__onFocus()
- if (this.filter && this.autofocusFilter) {
+ if (this.filter) {
this.$refs.filter.focus()
}
},
diff --git a/src/components/slider/QSlider.js b/src/components/slider/QSlider.js
index 0f8ee4ebb457..6d66bba450c3 100644
--- a/src/components/slider/QSlider.js
+++ b/src/components/slider/QSlider.js
@@ -4,6 +4,7 @@ import {
notDivides,
SliderMixin
} from './slider-utils'
+import { between } from '../../utils/format'
import { QChip } from '../chip'
export default {
@@ -94,6 +95,28 @@ export default {
this.model = getModel(percentage, this.min, this.max, this.step, this.computedDecimals)
this.currentPercentage = (this.model - this.min) / (this.max - this.min)
},
+ __onKeyDown (ev) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ const
+ decimals = this.computedDecimals,
+ step = ev.ctrlKey ? 10 * this.computedStep : this.computedStep,
+ offset = [37, 40].includes(keyCode) ? -step : step,
+ model = decimals ? parseFloat((this.model + offset).toFixed(decimals)) : (this.model + offset)
+
+ this.model = between(model, this.min, this.max)
+ this.currentPercentage = (this.model - this.min) / (this.max - this.min)
+ this.__update()
+ },
+ __onKeyUp (ev) {
+ const keyCode = ev.keyCode
+ if (!this.editable || ![37, 40, 39, 38].includes(keyCode)) {
+ return
+ }
+ this.__update(true)
+ },
__validateProps () {
if (this.min >= this.max) {
console.error('Range error: min >= max', this.$el, this.min, this.max)
@@ -121,6 +144,11 @@ export default {
'class': {
dragging: this.dragging,
'handle-at-minimum': !this.fillHandleAlways && this.model === this.min
+ },
+ attrs: { tabindex: this.editable ? 0 : -1 },
+ on: {
+ keydown: this.__onKeyDown,
+ keyup: this.__onKeyUp
}
}, [
this.label || this.labelAlways
diff --git a/src/components/slider/slider-utils.js b/src/components/slider/slider-utils.js
index 41b3c075a970..426fa46e0d68 100644
--- a/src/components/slider/slider-utils.js
+++ b/src/components/slider/slider-utils.js
@@ -88,6 +88,9 @@ export let SliderMixin = {
},
computedDecimals () {
return this.decimals !== void 0 ? this.decimals || 0 : (String(this.step).trim('0').split('.')[1] || '').length
+ },
+ computedStep () {
+ return this.decimals !== void 0 ? 1 / Math.pow(10, this.decimals || 0) : this.step
}
},
methods: {
diff --git a/src/components/tab/QRouteTab.js b/src/components/tab/QRouteTab.js
index d9eca693f2ea..1fcd371107bd 100644
--- a/src/components/tab/QRouteTab.js
+++ b/src/components/tab/QRouteTab.js
@@ -51,7 +51,8 @@ export default {
exactActiveClass: 'q-router-link-exact-active'
},
nativeOn: {
- click: this.select
+ click: this.select,
+ keyup: e => e.keyCode === 13 && this.select(e)
},
staticClass: 'q-tab column flex-center relative-position',
'class': this.classes,
diff --git a/src/components/tab/QTab.js b/src/components/tab/QTab.js
index f7100733e6d2..881fbe3758f4 100644
--- a/src/components/tab/QTab.js
+++ b/src/components/tab/QTab.js
@@ -24,7 +24,8 @@ export default {
staticClass: 'q-tab column flex-center relative-position',
'class': this.classes,
on: {
- click: this.select
+ click: this.select,
+ keyup: e => e.keyCode === 13 && this.select(e)
},
directives: process.env.THEME === 'mat'
? [{ name: 'ripple' }]
diff --git a/src/components/tab/tab-mixin.js b/src/components/tab/tab-mixin.js
index 7f739856e042..a0bbd8ea99a6 100644
--- a/src/components/tab/tab-mixin.js
+++ b/src/components/tab/tab-mixin.js
@@ -24,7 +24,8 @@ export default {
},
alert: Boolean,
count: [Number, String],
- color: String
+ color: String,
+ tabindex: Number
},
inject: {
data: {
@@ -71,6 +72,9 @@ export default {
if (!this.active || !this.data.highlight) {
return 'display: none;'
}
+ },
+ computedTabIndex () {
+ return this.disable || this.active ? -1 : this.tabindex || 0
}
},
methods: {
@@ -123,6 +127,11 @@ export default {
}))
}
+ child.push(h('div', {
+ staticClass: 'q-tab-focus-helper absolute-full',
+ attrs: { tabindex: this.computedTabIndex }
+ }))
+
return child
}
}
diff --git a/src/components/tab/tabs.ios.styl b/src/components/tab/tabs.ios.styl
index c81ee31ecc5c..73049f809cb6 100644
--- a/src/components/tab/tabs.ios.styl
+++ b/src/components/tab/tabs.ios.styl
@@ -55,6 +55,14 @@
.q-tab-icon
font-size $tabs-icon-font-size
+.q-tab-focus-helper
+ z-index -1
+ outline none
+ &:focus
+ z-index unset
+ background currentColor
+ opacity .1
+
@media (max-width $breakpoint-sm-max)
.q-tab
&.hide-icon .q-tab-icon-parent,
diff --git a/src/components/tab/tabs.mat.styl b/src/components/tab/tabs.mat.styl
index c05abdbe234d..92cea9945bc5 100644
--- a/src/components/tab/tabs.mat.styl
+++ b/src/components/tab/tabs.mat.styl
@@ -48,6 +48,14 @@
.q-tab-icon
font-size $tabs-icon-font-size
+.q-tab-focus-helper
+ z-index -1
+ outline none
+ &:focus
+ z-index unset
+ background currentColor
+ opacity .1
+
@media (max-width $breakpoint-sm-max)
.q-tab
&.hide-icon .q-tab-icon-parent,
diff --git a/src/directives/back-to-top.js b/src/directives/back-to-top.js
index a24cbd92bb94..a70de915e73f 100644
--- a/src/directives/back-to-top.js
+++ b/src/directives/back-to-top.js
@@ -54,6 +54,11 @@ export default {
},
goToTop () {
setScrollPosition(ctx.scrollTarget, 0, ctx.animate ? ctx.duration : 0)
+ },
+ goToTopKey (evt) {
+ if (evt.keyCode === 13) {
+ setScrollPosition(ctx.scrollTarget, 0, ctx.animate ? ctx.duration : 0)
+ }
}
}
ctx.update = debounce(ctx.updateNow, 25)
@@ -68,6 +73,7 @@ export default {
ctx.scrollTarget.addEventListener('scroll', ctx.update, listenOpts.passive)
window.addEventListener('resize', ctx.update, listenOpts.passive)
el.addEventListener('click', ctx.goToTop)
+ el.addEventListener('keyup', ctx.goToTopKey)
},
update (el, binding) {
if (JSON.stringify(binding.oldValue) !== JSON.stringify(binding.value)) {
@@ -85,6 +91,7 @@ export default {
ctx.scrollTarget.removeEventListener('scroll', ctx.update, listenOpts.passive)
window.removeEventListener('resize', ctx.update, listenOpts.passive)
el.removeEventListener('click', ctx.goToTop)
+ el.removeEventListener('keyup', ctx.goToTopKey)
delete el.__qbacktotop
}
}
diff --git a/src/directives/close-overlay.js b/src/directives/close-overlay.js
index ecba2208fb54..15784df558f6 100644
--- a/src/directives/close-overlay.js
+++ b/src/directives/close-overlay.js
@@ -1,23 +1,31 @@
export default {
name: 'close-overlay',
bind (el, binding, vnode) {
- const handler = ev => {
- let vm = vnode.componentInstance
- while ((vm = vm.$parent)) {
- const name = vm.$options.name
- if (name === 'QPopover' || name === 'QModal') {
- vm.hide(ev)
- break
+ const
+ handler = ev => {
+ let vm = vnode.componentInstance
+ while ((vm = vm.$parent)) {
+ const name = vm.$options.name
+ if (name === 'QPopover' || name === 'QModal') {
+ vm.hide(ev)
+ break
+ }
+ }
+ },
+ handlerKey = ev => {
+ if (ev.keyCode === 13) {
+ handler(ev)
}
}
- }
- el.__qclose = { handler }
+ el.__qclose = { handler, handlerKey }
el.addEventListener('click', handler)
+ el.addEventListener('keyup', handlerKey)
},
unbind (el) {
const ctx = el.__qclose
if (!ctx) { return }
el.removeEventListener('click', ctx.handler)
+ el.removeEventListener('keyup', ctx.handlerKey)
delete el.__qclose
}
}
diff --git a/src/directives/go-back.js b/src/directives/go-back.js
index d7e4449ddbf9..7c015832435e 100644
--- a/src/directives/go-back.js
+++ b/src/directives/go-back.js
@@ -15,9 +15,15 @@ export default {
vnode.context.$router.replace(ctx.value)
}
}
+ ctx.goBackKey = ev => {
+ if (ev.keyCode === 13) {
+ ctx.goBack(ev)
+ }
+ }
el.__qgoback = ctx
el.addEventListener('click', ctx.goBack)
+ el.addEventListener('keyup', ctx.goBackKey)
},
update (el, binding) {
if (binding.oldValue !== binding.value) {
@@ -28,6 +34,7 @@ export default {
const ctx = el.__qgoback
if (!ctx) { return }
el.removeEventListener('click', ctx.goBack)
+ el.removeEventListener('keyup', ctx.goBackKey)
delete el.__qgoback
}
}
diff --git a/src/directives/ripple.js b/src/directives/ripple.js
index 64eb2f961b8d..305f8efaf378 100644
--- a/src/directives/ripple.js
+++ b/src/directives/ripple.js
@@ -64,11 +64,17 @@ export default {
if (ctx.enabled) {
showRipple(evt, el, modifiers.stop)
}
+ },
+ keyup (evt) {
+ if (ctx.enabled && evt.keyCode === 13) {
+ showRipple(evt, el, modifiers.stop)
+ }
}
}
el.__qripple = ctx
el.addEventListener('click', ctx.click, false)
+ el.addEventListener('keyup', ctx.keyup, false)
},
update (el, { value, oldValue }) {
if (el.__qripple && value !== oldValue) {
@@ -82,6 +88,7 @@ export default {
}
el.removeEventListener('click', ctx.click, false)
+ el.removeEventListener('keyup', ctx.keyup, false)
delete el.__qripple
}
}
diff --git a/src/mixins/input.js b/src/mixins/input.js
index 35d3ed9fb7e5..21660eca5990 100644
--- a/src/mixins/input.js
+++ b/src/mixins/input.js
@@ -55,6 +55,9 @@ export default {
})
},
__onKeydown (e) {
+ if (e.keyCode === 13) {
+ this.__emit()
+ }
this.$emit('keydown', e)
},
__onKeyup (e) {