Skip to content

Commit da51292

Browse files
committed
feat(pickerheader): Arrow keys on prev/up/next buttons
1 parent 7c26eb3 commit da51292

File tree

9 files changed

+279
-17
lines changed

9 files changed

+279
-17
lines changed

src/components/Datepicker.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
:first-day-of-week="firstDayOfWeek"
8080
:highlighted="highlighted"
8181
:is-rtl="isRtl"
82+
:is-typeable="typeable"
8283
:is-up-disabled="isUpDisabled"
8384
:is-minimum-view="isMinimumView"
8485
:open-date="computedOpenDate"
@@ -95,6 +96,7 @@
9596
:year-range="yearPickerRange"
9697
@page-change="handlePageChange"
9798
@select="handleSelect"
99+
@set-focus="setFocus($event)"
98100
@set-transition-name="setTransitionName($event)"
99101
@set-view="setView"
100102
>

src/components/PickerDay.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99
:is-next-disabled="isNextDisabled"
1010
:is-previous-disabled="isPreviousDisabled"
1111
:is-rtl="isRtl"
12+
@focus-input="focusInput"
1213
@page-change="changePage($event)"
14+
@set-focus="$emit('set-focus', $event)"
1315
>
1416
<slot slot="prevIntervalBtn" name="prevIntervalBtn" />
1517
<UpButton
1618
ref="up"
1719
:class="{ btn: bootstrapStyling }"
1820
:is-disabled="isUpDisabled"
21+
:is-rtl="isRtl"
22+
@focus-input="focusInput"
1923
@select="$emit('set-view', 'month')"
24+
@set-focus="$emit('set-focus', $event)"
2025
>
2126
{{ pageTitleDay }}
2227
</UpButton>

src/components/PickerHeader.vue

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
:disabled="isPreviousDisabled"
99
type="button"
1010
@click="$emit('page-change', previousPage)"
11+
@keydown.down.prevent="focusTabbableCell"
12+
@keydown.up.prevent="$emit('focus-input')"
13+
@keydown.left.prevent="arrowLeftPrev"
14+
@keydown.right.prevent="arrowRightPrev"
1115
>
1216
<slot name="prevIntervalBtn">
1317
<span class="default">&lt;</span>
@@ -22,6 +26,10 @@
2226
:disabled="isNextDisabled"
2327
type="button"
2428
@click="$emit('page-change', nextPage)"
29+
@keydown.down.prevent="focusTabbableCell"
30+
@keydown.up.prevent="$emit('focus-input')"
31+
@keydown.left.prevent="arrowLeftNext"
32+
@keydown.right.prevent="arrowRightNext"
2533
>
2634
<slot name="nextIntervalBtn">
2735
<span class="default">&gt;</span>
@@ -57,5 +65,50 @@ export default {
5765
nextPage: { incrementBy: 1, focusRefs: ['next'] },
5866
}
5967
},
68+
methods: {
69+
/**
70+
* Changes the page, or sets focus to the adjacent button
71+
*/
72+
arrowLeftPrev() {
73+
if (this.isRtl) {
74+
this.$emit('set-focus', ['up', 'next', 'tabbableCell'])
75+
return
76+
}
77+
this.$emit('page-change', this.previousPage)
78+
},
79+
/**
80+
* Changes the page, or sets focus to the adjacent button
81+
*/
82+
arrowRightPrev() {
83+
if (this.isRtl) {
84+
this.$emit('page-change', this.previousPage)
85+
return
86+
}
87+
this.$emit('set-focus', ['up', 'next', 'tabbableCell'])
88+
},
89+
/**
90+
* Changes the page, or sets focus to the adjacent button
91+
*/
92+
arrowLeftNext() {
93+
if (this.isRtl) {
94+
this.$emit('page-change', this.nextPage)
95+
return
96+
}
97+
this.$emit('set-focus', ['up', 'prev', 'tabbableCell'])
98+
},
99+
/**
100+
* Changes the page, or sets focus to the adjacent button
101+
*/
102+
arrowRightNext() {
103+
if (this.isRtl) {
104+
this.$emit('set-focus', ['up', 'prev', 'tabbableCell'])
105+
return
106+
}
107+
this.$emit('page-change', this.nextPage)
108+
},
109+
focusTabbableCell() {
110+
this.$emit('set-focus', ['tabbableCell'])
111+
},
112+
},
60113
}
61114
</script>

src/components/PickerMonth.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99
:is-next-disabled="isNextDisabled"
1010
:is-previous-disabled="isPreviousDisabled"
1111
:is-rtl="isRtl"
12+
@focus-input="focusInput"
1213
@page-change="changePage($event)"
14+
@set-focus="$emit('set-focus', $event)"
1315
>
1416
<slot slot="prevIntervalBtn" name="prevIntervalBtn" />
1517
<UpButton
1618
ref="up"
1719
:class="{ btn: bootstrapStyling }"
1820
:is-disabled="isUpDisabled"
21+
:is-rtl="isRtl"
22+
@focus-input="focusInput"
1923
@select="$emit('set-view', 'year')"
24+
@set-focus="$emit('set-focus', $event)"
2025
>
2126
{{ pageTitleMonth }}
2227
</UpButton>

src/components/PickerYear.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,17 @@
99
:is-next-disabled="isNextDisabled"
1010
:is-previous-disabled="isPreviousDisabled"
1111
:is-rtl="isRtl"
12+
@focus-input="focusInput"
1213
@page-change="changePage($event)"
14+
@set-focus="$emit('set-focus', $event)"
1315
>
1416
<slot slot="prevIntervalBtn" name="prevIntervalBtn" />
15-
<UpButton ref="up" :class="{ btn: bootstrapStyling }" :is-disabled="true">
17+
<UpButton
18+
ref="up"
19+
:class="{ btn: bootstrapStyling }"
20+
:is-disabled="true"
21+
:is-rtl="isRtl"
22+
>
1623
{{ pageTitleYear }}
1724
</UpButton>
1825
<slot slot="nextIntervalBtn" name="nextIntervalBtn" />

src/components/UpButton.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
:disabled="isDisabled"
66
type="button"
77
@click="$emit('select')"
8+
@keydown.down.prevent="$emit('set-focus', ['tabbableCell'])"
9+
@keydown.up.prevent="$emit('focus-input')"
10+
@keydown.left.prevent="$emit('set-focus', [isRtl ? 'next' : 'prev'])"
11+
@keydown.right.prevent="$emit('set-focus', [isRtl ? 'prev' : 'next'])"
812
>
913
<slot />
1014
</button>
@@ -18,6 +22,10 @@ export default {
1822
type: Boolean,
1923
default: false,
2024
},
25+
isRtl: {
26+
type: Boolean,
27+
required: true,
28+
},
2129
},
2230
}
2331
</script>

src/mixins/pickerMixin.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export default {
2121
type: Boolean,
2222
default: false,
2323
},
24+
isTypeable: {
25+
type: Boolean,
26+
default: false,
27+
},
2428
isUpDisabled: {
2529
type: Boolean,
2630
default: false,
@@ -115,6 +119,14 @@ export default {
115119
116120
this.$emit('page-change', { focusRefs, pageDate })
117121
},
122+
/**
123+
* Focuses the input field, if typeable
124+
*/
125+
focusInput() {
126+
if (this.isTypeable) {
127+
this.$emit('set-focus', ['input'])
128+
}
129+
},
118130
/**
119131
* Determines which transition to use (for edge dates) and emits a 'select' event
120132
* @param {Object} cell

test/unit/specs/DateInput/typedDates.spec.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,56 @@ describe('Datepicker mount', () => {
235235
expect(wrapper.vm.selectedDate).toEqual(new Date(2016, 1, 15))
236236
})
237237
})
238+
239+
describe('Datepicker mounted to document body', () => {
240+
let wrapper
241+
242+
beforeEach(() => {
243+
wrapper = mount(Datepicker, {
244+
attachTo: document.body,
245+
propsData: {
246+
typeable: true,
247+
},
248+
})
249+
})
250+
251+
afterEach(() => {
252+
wrapper.destroy()
253+
})
254+
255+
it('arrows up from the previous button to the input field', async () => {
256+
const input = wrapper.find('input')
257+
258+
await input.trigger('click')
259+
await wrapper.vm.$nextTick()
260+
261+
const prevButton = wrapper.find('button.prev')
262+
await prevButton.trigger('keydown.up')
263+
264+
expect(document.activeElement).toBe(input.element)
265+
})
266+
267+
it('arrows up from the next button to the input field', async () => {
268+
const input = wrapper.find('input')
269+
270+
await input.trigger('click')
271+
await wrapper.vm.$nextTick()
272+
273+
const nextButton = wrapper.find('button.next')
274+
await nextButton.trigger('keydown.up')
275+
276+
expect(document.activeElement).toBe(input.element)
277+
})
278+
279+
it('arrows up from the up button to the input field', async () => {
280+
const input = wrapper.find('input')
281+
282+
await input.trigger('click')
283+
await wrapper.vm.$nextTick()
284+
285+
const upButton = wrapper.find('button.vdp-datepicker__up')
286+
await upButton.trigger('keydown.up')
287+
288+
expect(document.activeElement).toBe(input.element)
289+
})
290+
})

0 commit comments

Comments
 (0)