Skip to content

Commit c6dd70a

Browse files
authored
feat: add headerTag and footerTag props to all componets with header and footer (#6375)
1 parent bc02fb8 commit c6dd70a

File tree

15 files changed

+237
-40
lines changed

15 files changed

+237
-40
lines changed

src/components/calendar/calendar.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export const props = makePropsConfigurable(
114114
// 'ltr', 'rtl', or `null` (for auto detect)
115115
direction: makeProp(PROP_TYPE_STRING),
116116
disabled: makeProp(PROP_TYPE_BOOLEAN, false),
117+
headerTag: makeProp(PROP_TYPE_STRING, 'header'),
117118
// When `true`, renders a comment node, but keeps the component instance active
118119
// Mainly for <b-form-date>, so that we can get the component's value and locale
119120
// But we might just use separate date formatters, using the resolved locale
@@ -806,7 +807,7 @@ export const BCalendar = Vue.extend({
806807
: this.labelNoDateSelected || '\u00a0' // '&nbsp;'
807808
)
808809
$header = h(
809-
'header',
810+
this.headerTag,
810811
{
811812
staticClass: 'b-calendar-header',
812813
class: { 'sr-only': this.hideHeader },
@@ -936,7 +937,7 @@ export const BCalendar = Vue.extend({
936937

937938
// Caption for calendar grid
938939
const $gridCaption = h(
939-
'header',
940+
'div',
940941
{
941942
staticClass: 'b-calendar-grid-caption text-center font-weight-bold',
942943
class: { 'text-muted': disabled },
@@ -1065,7 +1066,7 @@ export const BCalendar = Vue.extend({
10651066
)
10661067

10671068
const $gridHelp = h(
1068-
'footer',
1069+
'div',
10691070
{
10701071
staticClass: 'b-calendar-grid-help border-top small text-muted text-center bg-light',
10711072
attrs: {

src/components/calendar/calendar.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,26 @@ describe('calendar', () => {
244244
wrapper.destroy()
245245
})
246246

247+
it('has correct header tag when "header-tag" prop is set', async () => {
248+
const wrapper = mount(BCalendar, {
249+
attachTo: createContainer(),
250+
propsData: {
251+
value: '2020-02-15', // Leap year,
252+
headerTag: 'div'
253+
}
254+
})
255+
256+
expect(wrapper.vm).toBeDefined()
257+
await waitNT(wrapper.vm)
258+
await waitRAF()
259+
260+
const $header = wrapper.find('.b-calendar-header')
261+
expect($header.exists()).toBe(true)
262+
expect($header.element.tagName).toBe('DIV')
263+
264+
wrapper.destroy()
265+
})
266+
247267
it('keyboard navigation works', async () => {
248268
const wrapper = mount(BCalendar, {
249269
attachTo: createContainer(),

src/components/calendar/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
"prop": "disabled",
3737
"description": "Places the calendar in a non-interactive disabled state"
3838
},
39+
{
40+
"prop": "headerTag",
41+
"version": "2.22.0",
42+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
43+
},
3944
{
4045
"prop": "hidden",
4146
"description": "When `true`, renders a comment node instead of the calendar widget while keeping the Vue instance active. Mainly used when implementing a custom date picker"

src/components/modal/modal.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,15 @@ export const props = makePropsConfigurable(
128128
footerBgVariant: makeProp(PROP_TYPE_STRING),
129129
footerBorderVariant: makeProp(PROP_TYPE_STRING),
130130
footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
131+
footerTag: makeProp(PROP_TYPE_STRING, 'footer'),
131132
footerTextVariant: makeProp(PROP_TYPE_STRING),
132133
headerBgVariant: makeProp(PROP_TYPE_STRING),
133134
headerBorderVariant: makeProp(PROP_TYPE_STRING),
134135
headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
135136
headerCloseContent: makeProp(PROP_TYPE_STRING, '&times;'),
136137
headerCloseLabel: makeProp(PROP_TYPE_STRING, 'Close'),
137138
headerCloseVariant: makeProp(PROP_TYPE_STRING),
139+
headerTag: makeProp(PROP_TYPE_STRING, 'header'),
138140
headerTextVariant: makeProp(PROP_TYPE_STRING),
139141
// TODO: Rename to `noBackdrop` and deprecate `hideBackdrop`
140142
hideBackdrop: makeProp(PROP_TYPE_BOOLEAN, false),
@@ -813,7 +815,7 @@ export const BModal = /*#__PURE__*/ Vue.extend({
813815
}
814816

815817
$header = h(
816-
'header',
818+
this.headerTag,
817819
{
818820
staticClass: 'modal-header',
819821
class: this.headerClasses,
@@ -887,7 +889,7 @@ export const BModal = /*#__PURE__*/ Vue.extend({
887889
}
888890

889891
$footer = h(
890-
'footer',
892+
this.footerTag,
891893
{
892894
staticClass: 'modal-footer',
893895
class: this.footerClasses,

src/components/modal/modal.spec.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,48 @@ describe('modal', () => {
262262

263263
wrapper.destroy()
264264
})
265+
266+
it('has correct header tag when "header-tag" prop is set', async () => {
267+
const wrapper = mount(BModal, {
268+
attachTo: createContainer(),
269+
propsData: {
270+
static: true,
271+
id: 'test',
272+
headerTag: 'div'
273+
}
274+
})
275+
276+
expect(wrapper.vm).toBeDefined()
277+
await waitNT(wrapper.vm)
278+
await waitRAF()
279+
280+
const $header = wrapper.find('.modal-header')
281+
expect($header.exists()).toBe(true)
282+
expect($header.element.tagName).toBe('DIV')
283+
284+
wrapper.destroy()
285+
})
286+
287+
it('has correct footer tag when "footer-tag" prop is set', async () => {
288+
const wrapper = mount(BModal, {
289+
attachTo: createContainer(),
290+
propsData: {
291+
static: true,
292+
id: 'test',
293+
footerTag: 'div'
294+
}
295+
})
296+
297+
expect(wrapper.vm).toBeDefined()
298+
await waitNT(wrapper.vm)
299+
await waitRAF()
300+
301+
const $footer = wrapper.find('.modal-footer')
302+
expect($footer.exists()).toBe(true)
303+
expect($footer.element.tagName).toBe('DIV')
304+
305+
wrapper.destroy()
306+
})
265307
})
266308

267309
describe('default button content, classes and attributes', () => {

src/components/modal/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@
104104
"prop": "footerTextVariant",
105105
"description": "Applies one of the Bootstrap theme color variants to the footer text"
106106
},
107+
{
108+
"prop": "footerTag",
109+
"version": "2.22.0",
110+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
111+
},
107112
{
108113
"prop": "headerBgVariant",
109114
"description": "Applies one of the Bootstrap theme color variants to the header background"
@@ -133,6 +138,11 @@
133138
"prop": "headerTextVariant",
134139
"description": "Applies one of the Bootstrap theme color variants to the header text"
135140
},
141+
{
142+
"prop": "headerTag",
143+
"version": "2.22.0",
144+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
145+
},
136146
{
137147
"prop": "hideBackdrop",
138148
"description": "Disables rendering of the modal backdrop"

src/components/sidebar/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,20 @@
3939
"prop": "footerClass",
4040
"description": "Class, or classes, to apply to the optional `footer` slot"
4141
},
42+
{
43+
"prop": "footerTag",
44+
"version": "2.22.0",
45+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
46+
},
4247
{
4348
"prop": "headerClass",
4449
"description": "Class, or classes, to apply to the built in header. Has no effect if prop `no-header` is set"
4550
},
51+
{
52+
"prop": "headerTag",
53+
"version": "2.22.0",
54+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
55+
},
4656
{
4757
"prop": "lazy",
4858
"description": "When set to `true`, the content of the sidebar will only be rendered while the sidebar is open"

src/components/sidebar/sidebar.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ export const props = makePropsConfigurable(
6767
// `aria-label` for close button
6868
closeLabel: makeProp(PROP_TYPE_STRING),
6969
footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
70+
footerTag: makeProp(PROP_TYPE_STRING, 'footer'),
7071
headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
72+
headerTag: makeProp(PROP_TYPE_STRING, 'header'),
7173
lazy: makeProp(PROP_TYPE_BOOLEAN, false),
7274
noCloseOnBackdrop: makeProp(PROP_TYPE_BOOLEAN, false),
7375
noCloseOnEsc: makeProp(PROP_TYPE_BOOLEAN, false),
@@ -131,7 +133,7 @@ const renderHeader = (h, ctx) => {
131133
}
132134

133135
return h(
134-
'header',
136+
ctx.headerTag,
135137
{
136138
staticClass: `${CLASS_NAME}-header`,
137139
class: ctx.headerClass,
@@ -160,7 +162,7 @@ const renderFooter = (h, ctx) => {
160162
}
161163

162164
return h(
163-
'footer',
165+
ctx.footerTag,
164166
{
165167
staticClass: `${CLASS_NAME}-footer`,
166168
class: ctx.footerClass,

src/components/sidebar/sidebar.spec.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ describe('sidebar', () => {
331331
propsData: {
332332
id: 'sidebar-header-slot',
333333
visible: true,
334-
title: 'TITLE'
334+
title: 'TITLE',
335+
headerTag: 'div'
335336
},
336337
slots: {
337338
header: 'Custom header'
@@ -343,6 +344,7 @@ describe('sidebar', () => {
343344

344345
const $header = wrapper.find('.b-sidebar-header')
345346
expect($header.exists()).toBe(true)
347+
expect($header.element.tagName).toBe('DIV')
346348
expect($header.find('strong').exists()).toBe(false)
347349
expect($header.find('button').exists()).toBe(false)
348350
expect($header.text()).toContain('Custom header')
@@ -358,7 +360,8 @@ describe('sidebar', () => {
358360
attachTo: createContainer(),
359361
propsData: {
360362
id: 'test-5',
361-
visible: true
363+
visible: true,
364+
footerTag: 'div'
362365
},
363366
slots: {
364367
footer: '<span>FOOTER</span>'
@@ -367,10 +370,14 @@ describe('sidebar', () => {
367370

368371
expect(wrapper.vm).toBeDefined()
369372
expect(wrapper.element.tagName).toBe('DIV')
373+
370374
expect(wrapper.find('.b-sidebar-header').exists()).toBe(true)
371375
expect(wrapper.find('.b-sidebar-body').exists()).toBe(true)
372-
expect(wrapper.find('.b-sidebar-footer').exists()).toBe(true)
373-
expect(wrapper.find('.b-sidebar-footer').text()).toEqual('FOOTER')
376+
377+
const $footer = wrapper.find('.b-sidebar-footer')
378+
expect($footer.exists()).toBe(true)
379+
expect($footer.element.tagName).toBe('DIV')
380+
expect($footer.text()).toEqual('FOOTER')
374381

375382
wrapper.destroy()
376383
})

src/components/time/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@
1010
"component": "BTime",
1111
"version": "2.6.0",
1212
"props": [
13+
{
14+
"prop": "footerTag",
15+
"version": "2.22.0",
16+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
17+
},
18+
{
19+
"prop": "headerTag",
20+
"version": "2.22.0",
21+
"description": "Specify the HTML tag to render instead of the default tag for the footer"
22+
},
1323
{
1424
"prop": "hideHeader",
1525
"description": "When set, visually hides the selected time header"

0 commit comments

Comments
 (0)