Skip to content

Commit db20047

Browse files
committed
refactor(Calendar): improve keyboard support
1 parent 5ddb035 commit db20047

File tree

1 file changed

+64
-53
lines changed

1 file changed

+64
-53
lines changed

js/src/calendar.js

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -169,33 +169,12 @@ class Calendar extends BaseComponent {
169169
}
170170

171171
// Private
172-
_initializeDates() {
173-
// Convert dates to date objects based on the selection type
174-
this._calendarDate = convertToDateObject(
175-
this._config.calendarDate || this._config.startDate || this._config.endDate || new Date(), this._config.selectionType
176-
)
177-
this._startDate = convertToDateObject(this._config.startDate, this._config.selectionType)
178-
this._endDate = convertToDateObject(this._config.endDate, this._config.selectionType)
179-
this._hoverDate = null
180-
this._selectEndDate = this._config.selectEndDate
181-
}
172+
_focusOnFirstAvailableCell() {
173+
const cell = SelectorEngine.findOne(SELECTOR_CALENDAR_CELL_CLICKABLE, this._element)
182174

183-
_initializeView() {
184-
const viewMap = {
185-
day: 'days',
186-
week: 'days',
187-
month: 'months',
188-
year: 'years'
175+
if (cell) {
176+
cell.focus()
189177
}
190-
191-
this._view = viewMap[this._config.selectionType] || 'days'
192-
}
193-
194-
_classNames(classNames) {
195-
return Object.entries(classNames)
196-
.filter(([_, value]) => Boolean(value))
197-
.map(([key]) => key)
198-
.join(' ')
199178
}
200179

201180
_getDate(target) {
@@ -220,14 +199,14 @@ class Calendar extends BaseComponent {
220199
if (this._view === 'months' && this._config.selectionType !== 'month') {
221200
this._setCalendarDate(index ? new Date(cloneDate.setMonth(cloneDate.getMonth() - index)) : date)
222201
this._view = 'days'
223-
this._updateCalendar()
202+
this._updateCalendar(this._focusOnFirstAvailableCell.bind(this))
224203
return
225204
}
226205

227206
if (this._view === 'years' && this._config.selectionType !== 'year') {
228207
this._setCalendarDate(index ? new Date(cloneDate.setFullYear(cloneDate.getFullYear() - index)) : date)
229208
this._view = 'months'
230-
this._updateCalendar()
209+
this._updateCalendar(this._focusOnFirstAvailableCell.bind(this))
231210
return
232211
}
233212

@@ -307,40 +286,35 @@ class Calendar extends BaseComponent {
307286
(event.key === ARROW_UP_KEY && toBoundary.start < Math.abs(gap.ArrowUp))
308287
) {
309288
const callback = key => {
310-
setTimeout(() => {
311-
const _list = SelectorEngine.find(
312-
`${SELECTOR_CALENDAR_CELL_CLICKABLE}, ${SELECTOR_CALENDAR_ROW_CLICKABLE}`,
313-
SelectorEngine.find('.calendar', this._element).pop()
314-
)
315-
316-
if (_list.length && key === ARROW_RIGHT_KEY) {
317-
_list[0].focus()
318-
}
319-
320-
if (_list.length && key === ARROW_LEFT_KEY) {
321-
_list[_list.length - 1].focus()
322-
}
323-
324-
if (_list.length && key === ARROW_DOWN_KEY) {
325-
_list[gap.ArrowDown - (list.length - index)].focus()
326-
}
327-
328-
if (_list.length && key === ARROW_UP_KEY) {
329-
_list[_list.length - (Math.abs(gap.ArrowUp) + 1 - (index + 1))].focus()
330-
}
331-
}, 0)
289+
const _list = SelectorEngine.find(`${SELECTOR_CALENDAR_CELL_CLICKABLE}, ${SELECTOR_CALENDAR_ROW_CLICKABLE}`, this._element)
290+
291+
if (_list.length && key === ARROW_RIGHT_KEY) {
292+
_list[0].focus()
293+
}
294+
295+
if (_list.length && key === ARROW_LEFT_KEY) {
296+
_list[_list.length - 1].focus()
297+
}
298+
299+
if (_list.length && key === ARROW_DOWN_KEY) {
300+
_list[gap.ArrowDown - (list.length - index)].focus()
301+
}
302+
303+
if (_list.length && key === ARROW_UP_KEY) {
304+
_list[_list.length - (Math.abs(gap.ArrowUp) + 1 - (index + 1))].focus()
305+
}
332306
}
333307

334308
if (this._view === 'days') {
335-
this._modifyCalendarDate(0, event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 1 : -1, callback(event.key))
309+
this._modifyCalendarDate(0, event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 1 : -1, callback.bind(this, event.key))
336310
}
337311

338312
if (this._view === 'months') {
339-
this._modifyCalendarDate(event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 1 : -1, callback(event.key))
313+
this._modifyCalendarDate(event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 1 : -1, 0, callback.bind(this, event.key))
340314
}
341315

342316
if (this._view === 'years') {
343-
this._modifyCalendarDate(event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 10 : -10, callback(event.key))
317+
this._modifyCalendarDate(event.key === ARROW_RIGHT_KEY || event.key === ARROW_DOWN_KEY ? 10 : -10, 0, callback.bind(this, event.key))
344318
}
345319

346320
return
@@ -463,7 +437,15 @@ class Calendar extends BaseComponent {
463437
for (const [selector, handler] of Object.entries(navigationSelectors)) {
464438
EventHandler.on(this._element, EVENT_CLICK_DATA_API, selector, event => {
465439
event.preventDefault()
440+
const selectors = SelectorEngine.find(selector, this._element)
441+
const selectorIndex = selectors.indexOf(event.target.closest(selector))
466442
handler()
443+
444+
// Retrieve focus to the navigation element
445+
const _selectors = SelectorEngine.find(selector, this._element)
446+
if (_selectors && _selectors[selectorIndex]) {
447+
_selectors[selectorIndex].focus()
448+
}
467449
})
468450
}
469451
}
@@ -735,12 +717,34 @@ class Calendar extends BaseComponent {
735717
this._element.classList.add(CLASS_NAME_CALENDARS)
736718
}
737719

720+
_initializeDates() {
721+
// Convert dates to date objects based on the selection type
722+
this._calendarDate = convertToDateObject(
723+
this._config.calendarDate || this._config.startDate || this._config.endDate || new Date(), this._config.selectionType
724+
)
725+
this._startDate = convertToDateObject(this._config.startDate, this._config.selectionType)
726+
this._endDate = convertToDateObject(this._config.endDate, this._config.selectionType)
727+
this._hoverDate = null
728+
this._selectEndDate = this._config.selectEndDate
729+
}
730+
731+
_initializeView() {
732+
const viewMap = {
733+
day: 'days',
734+
week: 'days',
735+
month: 'months',
736+
year: 'years'
737+
}
738+
739+
this._view = viewMap[this._config.selectionType] || 'days'
740+
}
741+
738742
_updateCalendar(callback) {
739743
this._element.innerHTML = ''
740744
this._createCalendar()
741745

742746
if (callback) {
743-
callback()
747+
setTimeout(callback, 1)
744748
}
745749
}
746750

@@ -791,6 +795,13 @@ class Calendar extends BaseComponent {
791795
}
792796
}
793797

798+
_classNames(classNames) {
799+
return Object.entries(classNames)
800+
.filter(([_, value]) => Boolean(value))
801+
.map(([key]) => key)
802+
.join(' ')
803+
}
804+
794805
_cellDayAttributes(date, month) {
795806
const isCurrentMonth = month === 'current'
796807
const isDisabled = isDateDisabled(date, this._config.minDate, this._config.maxDate, this._config.disabledDates)

0 commit comments

Comments
 (0)