@@ -27,6 +27,7 @@ import { isLocaleRTL } from '../../utils/locale'
2727import { mathMax } from '../../utils/math'
2828import { toInteger } from '../../utils/number'
2929import { toString } from '../../utils/string'
30+ import attrsMixin from '../../mixins/attrs'
3031import idMixin from '../../mixins/id'
3132import normalizeSlotMixin from '../../mixins/normalize-slot'
3233import {
@@ -56,7 +57,8 @@ export const STR_NARROW = 'narrow'
5657// @vue /component
5758export const BCalendar = Vue . extend ( {
5859 name : NAME ,
59- mixins : [ idMixin , normalizeSlotMixin ] ,
60+ // Mixin order is important!
61+ mixins : [ attrsMixin , idMixin , normalizeSlotMixin ] ,
6062 model : {
6163 // Even though this is the default that Vue assumes, we need
6264 // to add it for the docs to reflect that this is the model
@@ -271,6 +273,27 @@ export const BCalendar = Vue.extend({
271273 }
272274 } ,
273275 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+ } ,
274297 // TODO: Use computed props to convert `YYYY-MM-DD` to `Date` object
275298 selectedDate ( ) {
276299 // Selected as a `Date` object
@@ -771,24 +794,28 @@ export const BCalendar = Vue.extend({
771794 }
772795 } ,
773796 render ( h ) {
774- // If hidden prop is set, render just a placeholder node
797+ // If ` hidden` prop is set, render just a placeholder node
775798 if ( this . hidden ) {
776799 return h ( )
777800 }
778801
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
780816 const hideDecadeNav = ! this . showDecadeNav
781817 const todayYMD = formatYMD ( this . getToday ( ) )
782818 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
792819
793820 // Header showing current selected date
794821 let $header = h (
@@ -797,8 +824,8 @@ export const BCalendar = Vue.extend({
797824 staticClass : 'form-control form-control-sm text-center' ,
798825 class : { 'text-muted' : this . disabled , readonly : this . readonly || this . disabled } ,
799826 attrs : {
800- id : idValue ,
801- for : idGrid ,
827+ id : valueId ,
828+ for : gridId ,
802829 role : 'status' ,
803830 tabindex : this . disabled ? null : '-1' ,
804831 // Mainly for testing purposes, as we do not know
@@ -885,11 +912,11 @@ export const BCalendar = Vue.extend({
885912 {
886913 staticClass : 'b-calendar-nav d-flex' ,
887914 attrs : {
888- id : idNav ,
915+ id : navId ,
889916 role : 'group' ,
890917 'aria-hidden' : this . disabled ? 'true' : null ,
891918 'aria-label' : this . labelNav || null ,
892- 'aria-controls' : idGrid
919+ 'aria-controls' : gridId
893920 }
894921 } ,
895922 [
@@ -957,7 +984,7 @@ export const BCalendar = Vue.extend({
957984 staticClass : 'b-calendar-grid-caption text-center font-weight-bold' ,
958985 class : { 'text-muted' : this . disabled } ,
959986 attrs : {
960- id : idGridCaption ,
987+ id : gridCaptionId ,
961988 'aria-live' : isLive ? 'polite' : null ,
962989 'aria-atomic' : isLive ? 'true' : null
963990 }
@@ -1077,7 +1104,7 @@ export const BCalendar = Vue.extend({
10771104 {
10781105 staticClass : 'b-calendar-grid-help border-top small text-muted text-center bg-light' ,
10791106 attrs : {
1080- id : idGridHelp
1107+ id : gridHelpId
10811108 }
10821109 } ,
10831110 [ h ( 'div' , { staticClass : 'small' } , this . labelHelp ) ]
@@ -1089,18 +1116,18 @@ export const BCalendar = Vue.extend({
10891116 ref : 'grid' ,
10901117 staticClass : 'b-calendar-grid form-control h-auto text-center' ,
10911118 attrs : {
1092- id : idGrid ,
1119+ id : gridId ,
10931120 role : 'application' ,
10941121 tabindex : this . disabled ? null : '0' ,
10951122 'data-month' : activeYMD . slice ( 0 , - 3 ) , // `YYYY-MM`, mainly for testing
10961123 'aria-roledescription' : this . labelCalendar || null ,
1097- 'aria-labelledby' : idGridCaption ,
1098- 'aria-describedby' : idGridHelp ,
1124+ 'aria-labelledby' : gridCaptionId ,
1125+ 'aria-describedby' : gridHelpId ,
10991126 // `aria-readonly` is not considered valid on `role="application"`
11001127 // https://www.w3.org/TR/wai-aria-1.1/#aria-readonly
11011128 // 'aria-readonly': this.readonly && !this.disabled ? 'true' : null,
11021129 'aria-disabled' : this . disabled ? 'true' : null ,
1103- 'aria-activedescendant' : idActive
1130+ 'aria-activedescendant' : activeId
11041131 } ,
11051132 on : {
11061133 keydown : this . onKeydownGrid ,
@@ -1121,7 +1148,7 @@ export const BCalendar = Vue.extend({
11211148 staticClass : 'b-calendar-inner' ,
11221149 style : this . block ? { } : { width : this . width } ,
11231150 attrs : {
1124- id : idWidget ,
1151+ id : widgetId ,
11251152 dir : isRTL ? 'rtl' : 'ltr' ,
11261153 lang : this . computedLocale || null ,
11271154 role : 'group' ,
@@ -1133,9 +1160,9 @@ export const BCalendar = Vue.extend({
11331160 'aria-describedby' : [
11341161 // Should the attr (if present) go last?
11351162 // 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
11391166 ]
11401167 . filter ( identity )
11411168 . join ( ' ' )
0 commit comments