Skip to content

Commit 4154a72

Browse files
committed
feat(datepicker): Focus correct element on view change
1 parent 824f711 commit 4154a72

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

src/components/Datepicker.vue

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ export default {
332332
const parsedValue = this.parseValue(value)
333333
this.setValue(parsedValue)
334334
},
335+
view(newView, oldView) {
336+
this.handleViewChange(newView, oldView)
337+
},
335338
},
336339
mounted() {
337340
this.init()
@@ -410,6 +413,26 @@ export default {
410413
handleTypedDate(date) {
411414
this.selectDate(date.valueOf())
412415
},
416+
/**
417+
* Focus the relevant element when the view changes
418+
* @param {String} newView
419+
* @param {String} oldView
420+
*/
421+
handleViewChange(newView, oldView) {
422+
const isClosing = newView === ''
423+
const isOpeningInline = oldView === '' && this.isInline
424+
425+
if (isClosing || isOpeningInline) {
426+
return
427+
}
428+
429+
if (!this.isRevertingToOpenDate) {
430+
this.setViewChangeFocusRefs(newView, oldView)
431+
this.reviewFocus()
432+
}
433+
434+
this.isRevertingToOpenDate = false
435+
},
413436
/**
414437
* Initiate the component
415438
*/
@@ -539,6 +562,28 @@ export default {
539562
this.view = view
540563
}
541564
},
565+
/**
566+
* Sets the array of `refs` that might be focused following a view change
567+
* @param {String} newView The view being changed to
568+
* @param {String} oldView The previous view
569+
*/
570+
setViewChangeFocusRefs(newView, oldView) {
571+
if (oldView === '') {
572+
this.focus.refs = []
573+
return
574+
}
575+
576+
const views = ['day', 'month', 'year']
577+
const isNewView = (view) => view === newView
578+
const isOldView = (view) => view === oldView
579+
const newViewIndex = views.findIndex(isNewView)
580+
const oldViewIndex = views.findIndex(isOldView)
581+
const isViewChangeUp = newViewIndex - oldViewIndex > 0
582+
583+
this.focus.refs = isViewChangeUp
584+
? ['up', 'tabbableCell']
585+
: ['tabbableCell', 'up']
586+
},
542587
/**
543588
* Set the view to the next view down e.g. from `month` to `day`
544589
* @param {Object} cell The currently focused cell

test/unit/specs/Datepicker/Datepicker.spec.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ describe('Datepicker mounted', () => {
9494
await calendarButton.trigger('click')
9595
expect(wrapper.vm.isOpen).toBeFalsy()
9696
})
97+
98+
it('selects an edge date', async () => {
99+
await wrapper.setProps({
100+
value: new Date(2020, 0, 1),
101+
})
102+
103+
const cells = wrapper.findAll('button.cell')
104+
const lastCell = cells.at(cells.length - 1)
105+
106+
await lastCell.trigger('click')
107+
108+
expect(wrapper.vm.selectedDate).toStrictEqual(new Date(2020, 1, 1))
109+
})
97110
})
98111

99112
describe('Datepicker mounted with slots', () => {
@@ -171,6 +184,40 @@ describe('Datepicker mounted to body', () => {
171184
expect(todayCell.text()).toBe(new Date().getDate().toString())
172185
expect(document.activeElement).toStrictEqual(todayCell.element)
173186
})
187+
188+
it('focuses the up button on increasing the view', async () => {
189+
const input = wrapper.find('input')
190+
await input.trigger('click')
191+
192+
jest.advanceTimersByTime(250)
193+
let upButton = wrapper.find('button.vdp-datepicker__up')
194+
195+
await upButton.trigger('click')
196+
jest.advanceTimersByTime(250)
197+
upButton = wrapper.find('button.vdp-datepicker__up')
198+
199+
expect(document.activeElement).toBe(upButton.element)
200+
})
201+
202+
it('focuses the tabbable-cell on decreasing the view', async () => {
203+
const input = wrapper.find('input')
204+
await input.trigger('click')
205+
await wrapper.vm.$nextTick()
206+
jest.advanceTimersByTime(250)
207+
208+
const upButton = wrapper.find('button.vdp-datepicker__up')
209+
210+
await upButton.trigger('click')
211+
jest.advanceTimersByTime(250)
212+
const firstCell = wrapper.find('button.cell')
213+
214+
await firstCell.trigger('click')
215+
await wrapper.vm.$nextTick()
216+
jest.advanceTimersByTime(250)
217+
218+
const tabbableCell = wrapper.find('button.cell[data-test-tabbable-cell]')
219+
expect(document.activeElement).toBe(tabbableCell.element)
220+
})
174221
})
175222

176223
describe('Datepicker shallowMounted', () => {

0 commit comments

Comments
 (0)