diff --git a/src/components/nav/README.md b/src/components/nav/README.md index ed233b193ea..2e446b254a2 100644 --- a/src/components/nav/README.md +++ b/src/components/nav/README.md @@ -23,6 +23,13 @@ types of navigation components. It includes some style overrides (for working wi padding for larger hit areas, and basic disabled styling. No active states are included in the base nav. +`` supports teh following child components: + +- `` for actionable links (or router-links) +- `` for dropdowns +- `` for plain text content +- `` for inline forms + ## Link appearance Two style variations are supported: `tabs` and `pills`, which support `active` state styling. These @@ -215,6 +222,44 @@ shown. When there are a large number of dropdowns rendered on the same page, per impacted due to larger overall memory utilization. You can instruct `` to render the menu contents only when it is shown by setting the `lazy` prop to true. +## Nav text content + +Use the `` child component to place plain text content into the nav: + +```html +
+ + Link 1 + Link 2 + Plain text + +
+ + +``` + +## Nav inline forms + +Use the `` child component to place an _inline_ form into the nav: + +```html +
+ + Link 1 + Link 2 + + + Ok + + +
+ + +``` + +Refer to the [`` inline](/docs/components/form#inline-form) documentation for additional +details on placing form controls. + ## Tabbed local content support See the [``](/docs/components/tabs) component for creating tabbable panes of local content diff --git a/src/components/nav/nav-form.js b/src/components/nav/nav-form.js index 8f1b2814d65..045d03891c6 100644 --- a/src/components/nav/nav-form.js +++ b/src/components/nav/nav-form.js @@ -3,14 +3,35 @@ import { mergeData } from 'vue-functional-data-merge' import { omit } from '../../utils/object' import { BForm, props as BFormProps } from '../form/form' -export const props = omit(BFormProps, ['inline']) +export const props = { + ...omit(BFormProps, ['inline']), + formClass: { + type: [String, Array, Object], + default: null + } +} // @vue/component export const BNavForm = /*#__PURE__*/ Vue.extend({ name: 'BNavForm', functional: true, props, - render(h, { props, data, children }) { - return h(BForm, mergeData(data, { props: { ...props, inline: true } }), children) + render(h, { props, data, children, listeners = {} }) { + const attrs = data.attrs + // The following data properties are cleared out + // as they will be passed to BForm directly + data.attrs = {} + data.on = {} + const $form = h( + BForm, + { + class: props.formClass, + props: { ...props, inline: true }, + attrs, + on: listeners + }, + children + ) + return h('li', mergeData(data, { staticClass: 'form-inline' }), [$form]) } }) diff --git a/src/components/nav/nav-form.spec.js b/src/components/nav/nav-form.spec.js index d582f6e293b..bedb03b289f 100644 --- a/src/components/nav/nav-form.spec.js +++ b/src/components/nav/nav-form.spec.js @@ -5,9 +5,14 @@ describe('nav > nav-form', () => { it('has expected default structure', async () => { const wrapper = mount(BNavForm) - expect(wrapper.is('form')).toBe(true) + expect(wrapper.is('li')).toBe(true) expect(wrapper.classes()).toContain('form-inline') expect(wrapper.classes().length).toBe(1) + + const $form = wrapper.find('form') + expect($form.exists()).toBe(true) + expect($form.classes()).toContain('form-inline') + expect($form.classes().length).toBe(1) expect(wrapper.text()).toEqual('') }) @@ -18,9 +23,63 @@ describe('nav > nav-form', () => { } }) - expect(wrapper.is('form')).toBe(true) + expect(wrapper.is('li')).toBe(true) + expect(wrapper.classes()).toContain('form-inline') + expect(wrapper.classes().length).toBe(1) + + const $form = wrapper.find('form') + expect($form.exists()).toBe(true) + expect($form.classes()).toContain('form-inline') + expect($form.text()).toEqual('foobar') + }) + + it('applies ID to form when prop ID is set', async () => { + const wrapper = mount(BNavForm, { + propsData: { + id: 'baz' + }, + slots: { + default: 'foobar' + } + }) + + expect(wrapper.is('li')).toBe(true) + expect(wrapper.classes()).toContain('form-inline') + expect(wrapper.classes().length).toBe(1) + + const $form = wrapper.find('form') + expect($form.exists()).toBe(true) + expect($form.classes()).toContain('form-inline') + expect($form.text()).toEqual('foobar') + expect($form.attributes('id')).toEqual('baz') + }) + + it('listeners are bound to form element', async () => { + const onSubmit = jest.fn() + const wrapper = mount(BNavForm, { + propsData: { + id: 'baz' + }, + listeners: { + submit: onSubmit + }, + slots: { + default: 'foobar' + } + }) + + expect(wrapper.is('li')).toBe(true) expect(wrapper.classes()).toContain('form-inline') expect(wrapper.classes().length).toBe(1) - expect(wrapper.text()).toEqual('foobar') + + const $form = wrapper.find('form') + expect($form.exists()).toBe(true) + expect($form.classes()).toContain('form-inline') + expect($form.text()).toEqual('foobar') + + expect(onSubmit).not.toHaveBeenCalled() + + $form.trigger('submit') + expect(onSubmit).toHaveBeenCalled() }) }) diff --git a/src/components/nav/nav-text.js b/src/components/nav/nav-text.js index 5882c482d48..f75aae55aff 100644 --- a/src/components/nav/nav-text.js +++ b/src/components/nav/nav-text.js @@ -1,12 +1,7 @@ import Vue from '../../utils/vue' import { mergeData } from 'vue-functional-data-merge' -export const props = { - tag: { - type: String, - default: 'span' - } -} +export const props = {} // @vue/component export const BNavText = /*#__PURE__*/ Vue.extend({ @@ -14,6 +9,6 @@ export const BNavText = /*#__PURE__*/ Vue.extend({ functional: true, props, render(h, { props, data, children }) { - return h(props.tag, mergeData(data, { staticClass: 'navbar-text' }), children) + return h('li', mergeData(data, { staticClass: 'navbar-text' }), children) } }) diff --git a/src/components/nav/nav-text.spec.js b/src/components/nav/nav-text.spec.js index 576a2a79ff8..ccb916bc5e2 100644 --- a/src/components/nav/nav-text.spec.js +++ b/src/components/nav/nav-text.spec.js @@ -5,20 +5,7 @@ describe('nav > nav-text', () => { it('has expected default structure', async () => { const wrapper = mount(BNavText) - expect(wrapper.is('span')).toBe(true) - expect(wrapper.classes()).toContain('navbar-text') - expect(wrapper.classes().length).toBe(1) - expect(wrapper.text()).toEqual('') - }) - - it('renders custom root element when prop tag is set', async () => { - const wrapper = mount(BNavText, { - propsData: { - tag: 'div' - } - }) - - expect(wrapper.is('div')).toBe(true) + expect(wrapper.is('li')).toBe(true) expect(wrapper.classes()).toContain('navbar-text') expect(wrapper.classes().length).toBe(1) expect(wrapper.text()).toEqual('') @@ -31,7 +18,7 @@ describe('nav > nav-text', () => { } }) - expect(wrapper.is('span')).toBe(true) + expect(wrapper.is('li')).toBe(true) expect(wrapper.classes()).toContain('navbar-text') expect(wrapper.classes().length).toBe(1) expect(wrapper.text()).toEqual('foobar') diff --git a/src/components/navbar/README.md b/src/components/navbar/README.md index f45f0f9faad..1693244e73d 100644 --- a/src/components/navbar/README.md +++ b/src/components/navbar/README.md @@ -80,13 +80,14 @@ Navbars come with built-in support for a handful of sub-components. Choose from needed: - `` for your company, product, or project name. -- `` for a full-height and lightweight navigation (including support for dropdowns). -- `` for link (and router-link) action items -- `` for navbar dropdown menus -- `` for adding vertically centered strings of text. -- `` for any form controls and actions. - `` for use with the `` component. - `` for grouping and hiding navbar contents by a parent breakpoint. +- `` for a full-height and lightweight navigation (including support for dropdowns). + The following sub-components inside `` are supported: + - `` for link (and router-link) action items + - `` for nav dropdown menus + - `` for adding vertically centered strings of text. + - `` for any form controls and actions. ### `` @@ -153,7 +154,7 @@ Navbar navigation links build on the `` parent component and requi navbars will also grow to occupy as much horizontal space as possible to keep your navbar contents securely aligned. -`` supports the following components: +`` supports the following child components: - `` for link (and router-link) action items - `` for adding vertically centered strings of text.