@@ -27,6 +27,7 @@ import { isLocaleRTL } from '../../utils/locale'
27
27
import { mathMax } from '../../utils/math'
28
28
import { toInteger } from '../../utils/number'
29
29
import { toString } from '../../utils/string'
30
+ import attrsMixin from '../../mixins/attrs'
30
31
import idMixin from '../../mixins/id'
31
32
import normalizeSlotMixin from '../../mixins/normalize-slot'
32
33
import {
@@ -56,7 +57,8 @@ export const STR_NARROW = 'narrow'
56
57
// @vue /component
57
58
export const BCalendar = Vue . extend ( {
58
59
name : NAME ,
59
- mixins : [ idMixin , normalizeSlotMixin ] ,
60
+ // Mixin order is important!
61
+ mixins : [ attrsMixin , idMixin , normalizeSlotMixin ] ,
60
62
model : {
61
63
// Even though this is the default that Vue assumes, we need
62
64
// to add it for the docs to reflect that this is the model
@@ -271,6 +273,27 @@ export const BCalendar = Vue.extend({
271
273
}
272
274
} ,
273
275
computed : {
276
+ valueId ( ) {
277
+ return this . safeId ( )
278
+ } ,
279
+ widgetId ( ) {
280
+ return this . safeId ( '_calendar-wrapper_' )
281
+ } ,
282
+ navId ( ) {
283
+ return this . safeId ( '_calendar-nav_' )
284
+ } ,
285
+ gridId ( ) {
286
+ return this . safeId ( '_calendar-grid_' )
287
+ } ,
288
+ gridCaptionId ( ) {
289
+ return this . safeId ( '_calendar-grid-caption_' )
290
+ } ,
291
+ gridHelpId ( ) {
292
+ return this . safeId ( '_calendar-grid-help_' )
293
+ } ,
294
+ activeId ( ) {
295
+ return this . activeYMD ? this . safeId ( `_cell-${ this . activeYMD } _` ) : null
296
+ } ,
274
297
// TODO: Use computed props to convert `YYYY-MM-DD` to `Date` object
275
298
selectedDate ( ) {
276
299
// Selected as a `Date` object
@@ -771,24 +794,28 @@ export const BCalendar = Vue.extend({
771
794
}
772
795
} ,
773
796
render ( h ) {
774
- // If hidden prop is set, render just a placeholder node
797
+ // If ` hidden` prop is set, render just a placeholder node
775
798
if ( this . hidden ) {
776
799
return h ( )
777
800
}
778
801
779
- const { isLive, isRTL, activeYMD, selectedYMD, safeId } = this
802
+ const {
803
+ valueId,
804
+ widgetId,
805
+ navId,
806
+ gridId,
807
+ gridCaptionId,
808
+ gridHelpId,
809
+ activeId,
810
+ isLive,
811
+ isRTL,
812
+ activeYMD,
813
+ selectedYMD,
814
+ safeId
815
+ } = this
780
816
const hideDecadeNav = ! this . showDecadeNav
781
817
const todayYMD = formatYMD ( this . getToday ( ) )
782
818
const highlightToday = ! this . noHighlightToday
783
- // Pre-compute some IDs
784
- // This should be computed props
785
- const idValue = safeId ( )
786
- const idWidget = safeId ( '_calendar-wrapper_' )
787
- const idNav = safeId ( '_calendar-nav_' )
788
- const idGrid = safeId ( '_calendar-grid_' )
789
- const idGridCaption = safeId ( '_calendar-grid-caption_' )
790
- const idGridHelp = safeId ( '_calendar-grid-help_' )
791
- const idActive = activeYMD ? safeId ( `_cell-${ activeYMD } _` ) : null
792
819
793
820
// Header showing current selected date
794
821
let $header = h (
@@ -797,8 +824,8 @@ export const BCalendar = Vue.extend({
797
824
staticClass : 'form-control form-control-sm text-center' ,
798
825
class : { 'text-muted' : this . disabled , readonly : this . readonly || this . disabled } ,
799
826
attrs : {
800
- id : idValue ,
801
- for : idGrid ,
827
+ id : valueId ,
828
+ for : gridId ,
802
829
role : 'status' ,
803
830
tabindex : this . disabled ? null : '-1' ,
804
831
// Mainly for testing purposes, as we do not know
@@ -885,11 +912,11 @@ export const BCalendar = Vue.extend({
885
912
{
886
913
staticClass : 'b-calendar-nav d-flex' ,
887
914
attrs : {
888
- id : idNav ,
915
+ id : navId ,
889
916
role : 'group' ,
890
917
'aria-hidden' : this . disabled ? 'true' : null ,
891
918
'aria-label' : this . labelNav || null ,
892
- 'aria-controls' : idGrid
919
+ 'aria-controls' : gridId
893
920
}
894
921
} ,
895
922
[
@@ -957,7 +984,7 @@ export const BCalendar = Vue.extend({
957
984
staticClass : 'b-calendar-grid-caption text-center font-weight-bold' ,
958
985
class : { 'text-muted' : this . disabled } ,
959
986
attrs : {
960
- id : idGridCaption ,
987
+ id : gridCaptionId ,
961
988
'aria-live' : isLive ? 'polite' : null ,
962
989
'aria-atomic' : isLive ? 'true' : null
963
990
}
@@ -1077,7 +1104,7 @@ export const BCalendar = Vue.extend({
1077
1104
{
1078
1105
staticClass : 'b-calendar-grid-help border-top small text-muted text-center bg-light' ,
1079
1106
attrs : {
1080
- id : idGridHelp
1107
+ id : gridHelpId
1081
1108
}
1082
1109
} ,
1083
1110
[ h ( 'div' , { staticClass : 'small' } , this . labelHelp ) ]
@@ -1089,18 +1116,18 @@ export const BCalendar = Vue.extend({
1089
1116
ref : 'grid' ,
1090
1117
staticClass : 'b-calendar-grid form-control h-auto text-center' ,
1091
1118
attrs : {
1092
- id : idGrid ,
1119
+ id : gridId ,
1093
1120
role : 'application' ,
1094
1121
tabindex : this . disabled ? null : '0' ,
1095
1122
'data-month' : activeYMD . slice ( 0 , - 3 ) , // `YYYY-MM`, mainly for testing
1096
1123
'aria-roledescription' : this . labelCalendar || null ,
1097
- 'aria-labelledby' : idGridCaption ,
1098
- 'aria-describedby' : idGridHelp ,
1124
+ 'aria-labelledby' : gridCaptionId ,
1125
+ 'aria-describedby' : gridHelpId ,
1099
1126
// `aria-readonly` is not considered valid on `role="application"`
1100
1127
// https://www.w3.org/TR/wai-aria-1.1/#aria-readonly
1101
1128
// 'aria-readonly': this.readonly && !this.disabled ? 'true' : null,
1102
1129
'aria-disabled' : this . disabled ? 'true' : null ,
1103
- 'aria-activedescendant' : idActive
1130
+ 'aria-activedescendant' : activeId
1104
1131
} ,
1105
1132
on : {
1106
1133
keydown : this . onKeydownGrid ,
@@ -1121,7 +1148,7 @@ export const BCalendar = Vue.extend({
1121
1148
staticClass : 'b-calendar-inner' ,
1122
1149
style : this . block ? { } : { width : this . width } ,
1123
1150
attrs : {
1124
- id : idWidget ,
1151
+ id : widgetId ,
1125
1152
dir : isRTL ? 'rtl' : 'ltr' ,
1126
1153
lang : this . computedLocale || null ,
1127
1154
role : 'group' ,
@@ -1133,9 +1160,9 @@ export const BCalendar = Vue.extend({
1133
1160
'aria-describedby' : [
1134
1161
// Should the attr (if present) go last?
1135
1162
// Or should this attr be a prop?
1136
- this . $attrs [ 'aria-describedby' ] ,
1137
- idValue ,
1138
- idGridHelp
1163
+ this . bvAttrs [ 'aria-describedby' ] ,
1164
+ valueId ,
1165
+ gridHelpId
1139
1166
]
1140
1167
. filter ( identity )
1141
1168
. join ( ' ' )
0 commit comments