@@ -20,6 +20,7 @@ import {
2020} from '../../utils/date'
2121import { requestAF } from '../../utils/dom'
2222import { isArray , isFunction , isPlainObject , isString } from '../../utils/inspect'
23+ import { isLocaleRTL } from '../../utils/locale'
2324import { toInteger } from '../../utils/number'
2425import { toString } from '../../utils/string'
2526import idMixin from '../../mixins/id'
@@ -34,37 +35,6 @@ const NAME = 'BCalendar'
3435// Key Codes
3536const { UP , DOWN , LEFT , RIGHT , PAGEUP , PAGEDOWN , HOME , END , ENTER , SPACE } = KeyCodes
3637
37- // Languages that are RTL
38- const RTL_LANGS = [
39- 'ar' ,
40- 'az' ,
41- 'ckb' ,
42- 'fa' ,
43- 'he' ,
44- 'ks' ,
45- 'lrc' ,
46- 'mzn' ,
47- 'ps' ,
48- 'sd' ,
49- 'te' ,
50- 'ug' ,
51- 'ur' ,
52- 'yi'
53- ] . map ( locale => locale . toLowerCase ( ) )
54-
55- // --- Helper utilities ---
56-
57- export const isLocaleRTL = locale => {
58- // Determines if the locale is RTL (only single locale supported)
59- const parts = toString ( locale )
60- . toLowerCase ( )
61- . replace ( / - u - .+ / , '' )
62- . split ( '-' )
63- const locale1 = parts . slice ( 0 , 2 ) . join ( '-' )
64- const locale2 = parts [ 0 ]
65- return arrayIncludes ( RTL_LANGS , locale1 ) || arrayIncludes ( RTL_LANGS , locale2 )
66- }
67-
6838// --- BCalendar component ---
6939
7040// @vue /component
@@ -667,7 +637,6 @@ export const BCalendar = Vue.extend({
667637 } ,
668638 onClickDay ( day ) {
669639 // Clicking on a date "button" to select it
670- // TODO: Change to lookup the `data-data` attribute
671640 const selectedDate = this . selectedDate
672641 const activeDate = this . activeDate
673642 const clickedDate = parseYMD ( day . ymd )
@@ -702,6 +671,12 @@ export const BCalendar = Vue.extend({
702671 } ,
703672 gotoNextYear ( ) {
704673 this . activeYMD = formatYMD ( this . constrainDate ( oneYearAhead ( this . activeDate ) ) )
674+ } ,
675+ onHeaderClick ( ) {
676+ if ( ! this . disabled ) {
677+ this . activeYMD = this . selectedYMD || formatYMD ( this . getToday ( ) )
678+ this . focus ( )
679+ }
705680 }
706681 } ,
707682 render ( h ) {
@@ -719,8 +694,9 @@ export const BCalendar = Vue.extend({
719694 // Flag for making the `aria-live` regions live
720695 const isLive = this . isLive
721696 // Pre-compute some IDs
722- const idWidget = safeId ( )
723- const idValue = safeId ( '_calendar-value_' )
697+ // Thes should be computed props
698+ const idValue = safeId ( )
699+ const idWidget = safeId ( '_calendar-wrapper_' )
724700 const idNav = safeId ( '_calendar-nav_' )
725701 const idGrid = safeId ( '_calendar-grid_' )
726702 const idGridCaption = safeId ( '_calendar-grid-caption_' )
@@ -737,13 +713,20 @@ export const BCalendar = Vue.extend({
737713 id : idValue ,
738714 for : idGrid ,
739715 role : 'status' ,
716+ tabindex : this . disabled ? null : '-1' ,
740717 // Mainly for testing purposes, as we do not know
741718 // the exact format `Intl` will format the date string
742719 'data-selected' : toString ( selectedYMD ) ,
743720 // We wait until after mount to enable `aria-live`
744721 // to prevent initial announcement on page render
745722 'aria-live' : isLive ? 'polite' : 'off' ,
746723 'aria-atomic' : isLive ? 'true' : null
724+ } ,
725+ on : {
726+ // Transfer focus/click to focus grid
727+ // and focus active date (or today if no selection)
728+ click : this . onHeaderClick ,
729+ focus : this . onHeaderClick
747730 }
748731 } ,
749732 this . selectedDate
0 commit comments