UNPKG

bootstrap-vue

Version:

BootstrapVue, with more than 85 custom components, over 45 plugins, several custom directives, and over 300 icons, provides one of the most comprehensive implementations of Bootstrap v4 components and grid system for Vue.js. With extensive and automated W

224 lines (220 loc) 5.8 kB
import Vue from '../../utils/vue' import { arrayIncludes } from '../../utils/array' import { stripTags } from '../../utils/html' import { getComponentConfig } from '../../utils/config' import idMixin from '../../mixins/id' import dropdownMixin from '../../mixins/dropdown' import normalizeSlotMixin from '../../mixins/normalize-slot' import { BButton } from '../button/button' const NAME = 'BDropdown' export const props = { text: { // Button label type: String, default: '' }, html: { // Button label type: String // default: undefined }, size: { type: String, default: () => getComponentConfig(NAME, 'size') }, variant: { type: String, default: () => getComponentConfig(NAME, 'variant') }, block: { type: Boolean, default: false }, menuClass: { type: [String, Array, Object] // default: null }, toggleTag: { type: String, default: 'button' }, toggleText: { // This really should be toggleLabel type: String, default: () => getComponentConfig(NAME, 'toggleText') }, toggleClass: { type: [String, Array, Object] // default: null }, noCaret: { type: Boolean, default: false }, split: { type: Boolean, default: false }, splitHref: { type: String // default: undefined }, splitTo: { type: [String, Object] // default: undefined }, splitVariant: { type: String, default: () => getComponentConfig(NAME, 'splitVariant') }, splitClass: { type: [String, Array, Object] // default: null }, splitButtonType: { type: String, default: 'button', validator: value => arrayIncludes(['button', 'submit', 'reset'], value) }, lazy: { // If true, only render menu contents when open type: Boolean, default: false }, role: { type: String, default: 'menu' } } // @vue/component export const BDropdown = /*#__PURE__*/ Vue.extend({ name: NAME, mixins: [idMixin, dropdownMixin, normalizeSlotMixin], props, computed: { dropdownClasses() { return [ this.directionClass, { show: this.visible, // The 'btn-group' class is required in `split` mode for button alignment // It needs also to be applied when `block` is disabled to allow multiple // dropdowns to be aligned one line 'btn-group': this.split || !this.block, // When `block` is enabled and we are in `split` mode the 'd-flex' class // needs to be applied to allow the buttons to stretch to full width 'd-flex': this.block && this.split, // Position `static` is needed to allow menu to "breakout" of the `scrollParent` // boundaries when boundary is anything other than `scrollParent` // See: https://github.com/twbs/bootstrap/issues/24251#issuecomment-341413786 'position-static': this.boundary !== 'scrollParent' || !this.boundary } ] }, menuClasses() { return [ this.menuClass, { 'dropdown-menu-right': this.right, show: this.visible } ] }, toggleClasses() { return [ this.toggleClass, { 'dropdown-toggle-split': this.split, 'dropdown-toggle-no-caret': this.noCaret && !this.split } ] } }, render(h) { let split = h() const buttonContent = this.normalizeSlot('button-content') || this.html || stripTags(this.text) if (this.split) { const btnProps = { variant: this.splitVariant || this.variant, size: this.size, block: this.block, disabled: this.disabled } // We add these as needed due to router-link issues with defined property with undefined/null values if (this.splitTo) { btnProps.to = this.splitTo } else if (this.splitHref) { btnProps.href = this.splitHref } else if (this.splitButtonType) { btnProps.type = this.splitButtonType } split = h( BButton, { ref: 'button', props: btnProps, class: this.splitClass, attrs: { id: this.safeId('_BV_button_') }, on: { click: this.onSplitClick } }, [buttonContent] ) } const toggle = h( BButton, { ref: 'toggle', staticClass: 'dropdown-toggle', class: this.toggleClasses, props: { tag: this.toggleTag, variant: this.variant, size: this.size, block: this.block && !this.split, disabled: this.disabled }, attrs: { id: this.safeId('_BV_toggle_'), 'aria-haspopup': 'true', 'aria-expanded': this.visible ? 'true' : 'false' }, on: { mousedown: this.onMousedown, click: this.toggle, keydown: this.toggle // Handle ENTER, SPACE and DOWN } }, [this.split ? h('span', { class: ['sr-only'] }, [this.toggleText]) : buttonContent] ) const menu = h( 'ul', { ref: 'menu', staticClass: 'dropdown-menu', class: this.menuClasses, attrs: { role: this.role, tabindex: '-1', 'aria-labelledby': this.safeId(this.split ? '_BV_button_' : '_BV_toggle_') }, on: { keydown: this.onKeydown // Handle UP, DOWN and ESC } }, !this.lazy || this.visible ? this.normalizeSlot('default', { hide: this.hide }) : [h()] ) return h( 'div', { staticClass: 'dropdown b-dropdown', class: this.dropdownClasses, attrs: { id: this.safeId() } }, [split, toggle, menu] ) } })