diff --git a/src/components/tabs/README.md b/src/components/tabs/README.md index 4ccbbc5b636..89ff57b80d8 100644 --- a/src/components/tabs/README.md +++ b/src/components/tabs/README.md @@ -572,4 +572,28 @@ It is recommended to use the `disabled` attribute on the `` component ins ``` +### Card title using tabs-before slot + +```html + + + +``` + diff --git a/src/components/tabs/package.json b/src/components/tabs/package.json index 3f8c8b82636..00a324e6677 100644 --- a/src/components/tabs/package.json +++ b/src/components/tabs/package.json @@ -141,6 +141,14 @@ "name": "empty", "description": "Renders this slot if no tabs are present" }, + { + "name": "tabs-after", + "description": "Content to place after the content tab buttons" + }, + { + "name": "tabs-before", + "description": "Content to place before the content tab buttons" + }, { "name": "tabs-end", "description": "Additional tab buttons without tab content placed after content tab buttons" diff --git a/src/components/tabs/tabs.js b/src/components/tabs/tabs.js index 3e5f9a47e19..9c3e4567d5d 100644 --- a/src/components/tabs/tabs.js +++ b/src/components/tabs/tabs.js @@ -27,6 +27,8 @@ import { } from '../../constants/props' import { SLOT_NAME_EMPTY, + SLOT_NAME_TABS_AFTER, + SLOT_NAME_TABS_BEFORE, SLOT_NAME_TABS_END, SLOT_NAME_TABS_START, SLOT_NAME_TITLE @@ -635,7 +637,11 @@ export const BTabs = /*#__PURE__*/ Vue.extend({ ], key: 'bv-tabs-nav' }, - [$nav] + [ + this.normalizeSlot(SLOT_NAME_TABS_BEFORE) || h(), + $nav, + this.normalizeSlot(SLOT_NAME_TABS_AFTER) || h() + ] ) const $children = this.normalizeSlot() || [] diff --git a/src/components/tabs/tabs.spec.js b/src/components/tabs/tabs.spec.js index 74a0ad3776c..250a88670a5 100644 --- a/src/components/tabs/tabs.spec.js +++ b/src/components/tabs/tabs.spec.js @@ -687,6 +687,60 @@ describe('tabs', () => { wrapper.destroy() }) + it('tabs-before slot is injected at the right place', async () => { + const wrapper = mount(BTabs, { + slots: { + default: [BTab, BTab], + 'tabs-before': 'foobar' + } + }) + expect(wrapper).toBeDefined() + expect(wrapper.findAllComponents(BTab).length).toBe(2) + + // check existance + const spans = wrapper.findAll('span.test-tabs-before') + expect(spans).toBeDefined() + expect(spans.length).toBe(1) + expect(spans.at(0).text()).toBe('foobar') + + // check order + const childs = wrapper.findAll('div.tabs > div:first-of-type > *') + expect(childs.length).toBe(2) + expect(childs.at(0).classes().length).toBe(1) + expect(childs.at(0).classes()).toContain('test-tabs-before') + expect(childs.at(0).text()).toBe('foobar') + expect(childs.at(1).classes().length).toBe(2) + expect(childs.at(1).classes()).toContain('nav') + expect(childs.at(1).classes()).toContain('nav-tabs') + }) + + it('tabs-after slot is injected at the right place', async () => { + const wrapper = mount(BTabs, { + slots: { + default: [BTab, BTab], + 'tabs-after': 'foobar' + } + }) + expect(wrapper).toBeDefined() + expect(wrapper.findAllComponents(BTab).length).toBe(2) + + // check existance + const spans = wrapper.findAll('span.test-tabs-after') + expect(spans).toBeDefined() + expect(spans.length).toBe(1) + expect(spans.at(0).text()).toBe('foobar') + + // check order + const childs = wrapper.findAll('div.tabs > div:first-of-type > *') + expect(childs.length).toBe(2) + expect(childs.at(0).classes().length).toBe(2) + expect(childs.at(0).classes()).toContain('nav') + expect(childs.at(0).classes()).toContain('nav-tabs') + expect(childs.at(1).classes().length).toBe(1) + expect(childs.at(1).classes()).toContain('test-tabs-after') + expect(childs.at(1).text()).toBe('foobar') + }) + it('"active-nav-item-class" is applied to active nav item', async () => { const activeNavItemClass = 'text-success' const App = { diff --git a/src/constants/slots.js b/src/constants/slots.js index 270994c9799..486c254be3d 100644 --- a/src/constants/slots.js +++ b/src/constants/slots.js @@ -54,6 +54,8 @@ export const SLOT_NAME_ROW_DETAILS = 'row-details' export const SLOT_NAME_TABLE_BUSY = 'table-busy' export const SLOT_NAME_TABLE_CAPTION = 'table-caption' export const SLOT_NAME_TABLE_COLGROUP = 'table-colgroup' +export const SLOT_NAME_TABS_AFTER = 'tabs-after' +export const SLOT_NAME_TABS_BEFORE = 'tabs-before' export const SLOT_NAME_TABS_END = 'tabs-end' export const SLOT_NAME_TABS_START = 'tabs-start' export const SLOT_NAME_TEXT = 'text'