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

499 lines (447 loc) 13.6 kB
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import Vue from '../../utils/vue'; import KeyCodes from '../../utils/key-codes'; import BVTransition from '../../utils/bv-transition'; import { contains, getTabables } from '../../utils/dom'; import { getComponentConfig } from '../../utils/config'; import { toString } from '../../utils/string'; import idMixin from '../../mixins/id'; import listenOnRootMixin from '../../mixins/listen-on-root'; import normalizeSlotMixin from '../../mixins/normalize-slot'; import { EVENT_TOGGLE, EVENT_STATE, EVENT_STATE_REQUEST, EVENT_STATE_SYNC } from '../../directives/toggle/toggle'; import { BButtonClose } from '../button/button-close'; import { BIconX } from '../../icons/icons'; // --- Constants --- var NAME = 'BSidebar'; var CLASS_NAME = 'b-sidebar'; // --- Render methods --- var renderHeaderTitle = function renderHeaderTitle(h, ctx) { var title = ctx.normalizeSlot('title', ctx.slotScope) || toString(ctx.title) || null; // Render a empty `<span>` when to title was provided if (!title) { return h('span'); } return h('strong', { attrs: { id: ctx.safeId('__title__') } }, [title]); }; var renderHeaderClose = function renderHeaderClose(h, ctx) { if (ctx.noHeaderClose) { return h(); } var closeLabel = ctx.closeLabel, textVariant = ctx.textVariant, hide = ctx.hide; return h(BButtonClose, { ref: 'close-button', props: { ariaLabel: closeLabel, textVariant: textVariant }, on: { click: hide } }, [ctx.normalizeSlot('header-close') || h(BIconX)]); }; var renderHeader = function renderHeader(h, ctx) { if (ctx.noHeader) { return h(); } var $title = renderHeaderTitle(h, ctx); var $close = renderHeaderClose(h, ctx); return h('header', { key: 'header', staticClass: "".concat(CLASS_NAME, "-header"), class: ctx.headerClass }, ctx.right ? [$close, $title] : [$title, $close]); }; var renderBody = function renderBody(h, ctx) { return h('div', { key: 'body', staticClass: "".concat(CLASS_NAME, "-body"), class: ctx.bodyClass }, [ctx.normalizeSlot('default', ctx.slotScope)]); }; var renderFooter = function renderFooter(h, ctx) { var $footer = ctx.normalizeSlot('footer', ctx.slotScope); if (!$footer) { return h(); } return h('footer', { key: 'footer', staticClass: "".concat(CLASS_NAME, "-footer"), class: ctx.footerClass }, [$footer]); }; var renderContent = function renderContent(h, ctx) { // We render the header even if `lazy` is enabled as it // acts as the accessible label for the sidebar var $header = renderHeader(h, ctx); if (ctx.lazy && !ctx.isOpen) { return $header; } return [$header, renderBody(h, ctx), renderFooter(h, ctx)]; }; var renderBackdrop = function renderBackdrop(h, ctx) { if (!ctx.backdrop) { return h(); } return h('div', { directives: [{ name: 'show', value: ctx.localShow }], staticClass: 'b-sidebar-backdrop', on: { click: ctx.onBackdropClick } }); }; // --- Main component --- // @vue/component export var BSidebar = /*#__PURE__*/Vue.extend({ name: NAME, mixins: [idMixin, listenOnRootMixin, normalizeSlotMixin], inheritAttrs: false, model: { prop: 'visible', event: 'change' }, props: { title: { type: String // default: null }, right: { type: Boolean, default: false }, bgVariant: { type: String, default: function _default() { return getComponentConfig(NAME, 'bgVariant'); } }, textVariant: { type: String, default: function _default() { return getComponentConfig(NAME, 'textVariant'); } }, shadow: { type: [Boolean, String], default: function _default() { return getComponentConfig(NAME, 'shadow'); } }, width: { type: String, default: function _default() { return getComponentConfig(NAME, 'width'); } }, zIndex: { type: [Number, String] // default: null }, ariaLabel: { type: String // default: null }, ariaLabelledby: { type: String // default: null }, closeLabel: { // `aria-label` for close button // Defaults to 'Close' type: String // default: undefined }, tag: { type: String, default: function _default() { return getComponentConfig(NAME, 'tag'); } }, sidebarClass: { type: [String, Array, Object] // default: null }, headerClass: { type: [String, Array, Object] // default: null }, bodyClass: { type: [String, Array, Object] // default: null }, footerClass: { type: [String, Array, Object] // default: null }, backdrop: { // If true, shows a basic backdrop type: Boolean, default: false }, noSlide: { type: Boolean, default: false }, noHeader: { type: Boolean, default: false }, noHeaderClose: { type: Boolean, default: false }, noCloseOnEsc: { type: Boolean, default: false }, noCloseOnBackdrop: { type: Boolean, default: false }, noCloseOnRouteChange: { type: Boolean, default: false }, lazy: { type: Boolean, default: false }, visible: { type: Boolean, default: false } }, data: function data() { return { // Internal `v-model` state localShow: !!this.visible, // For lazy render triggering isOpen: !!this.visible }; }, computed: { transitionProps: function transitionProps() { return this.noSlide ? /* istanbul ignore next */ { css: true } : { css: true, enterClass: '', enterActiveClass: 'slide', enterToClass: 'show', leaveClass: 'show', leaveActiveClass: 'slide', leaveToClass: '' }; }, slotScope: function slotScope() { return { visible: this.localShow, right: this.right, hide: this.hide }; } }, watch: { visible: function visible(newVal, oldVal) { if (newVal !== oldVal) { this.localShow = newVal; } }, localShow: function localShow(newVal, oldVal) { if (newVal !== oldVal) { this.emitState(newVal); this.$emit('change', newVal); } }, /* istanbul ignore next */ $route: function $route() /* istanbul ignore next: pain to mock */ { var newVal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var oldVal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!this.noCloseOnRouteChange && newVal.fullPath !== oldVal.fullPath) { this.hide(); } } }, created: function created() { // Define non-reactive properties this.$_returnFocusEl = null; }, mounted: function mounted() { var _this = this; // Add `$root` listeners this.listenOnRoot(EVENT_TOGGLE, this.handleToggle); this.listenOnRoot(EVENT_STATE_REQUEST, this.handleSync); // Send out a gratuitous state event to ensure toggle button is synced this.$nextTick(function () { _this.emitState(_this.localShow); }); }, /* istanbul ignore next */ activated: function activated() /* istanbul ignore next */ { this.emitSync(); }, beforeDestroy: function beforeDestroy() { this.localShow = false; this.$_returnFocusEl = null; }, methods: { hide: function hide() { this.localShow = false; }, emitState: function emitState() { var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow; this.emitOnRoot(EVENT_STATE, this.safeId(), state); }, emitSync: function emitSync() { var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.localShow; this.emitOnRoot(EVENT_STATE_SYNC, this.safeId(), state); }, handleToggle: function handleToggle(id) { // Note `safeId()` can be null until after mount if (id && id === this.safeId()) { this.localShow = !this.localShow; } }, handleSync: function handleSync(id) { var _this2 = this; // Note `safeId()` can be null until after mount if (id && id === this.safeId()) { this.$nextTick(function () { _this2.emitSync(_this2.localShow); }); } }, onKeydown: function onKeydown(evt) { var keyCode = evt.keyCode; if (!this.noCloseOnEsc && keyCode === KeyCodes.ESC && this.localShow) { this.hide(); } }, onBackdropClick: function onBackdropClick() { if (this.localShow && !this.noCloseOnBackdrop) { this.hide(); } }, /* istanbul ignore next */ onTopTrapFocus: function onTopTrapFocus() /* istanbul ignore next */ { var tabables = getTabables(this.$refs.content); try { tabables.reverse()[0].focus(); } catch (_unused) {} }, /* istanbul ignore next */ onBottomTrapFocus: function onBottomTrapFocus() /* istanbul ignore next */ { var tabables = getTabables(this.$refs.content); try { tabables[0].focus(); } catch (_unused2) {} }, onBeforeEnter: function onBeforeEnter() { this.$_returnFocusEl = null; try { this.$_returnFocusEl = document.activeElement || null; } catch (_unused3) {} // Trigger lazy render this.isOpen = true; }, onAfterEnter: function onAfterEnter(el) { try { if (!contains(el, document.activeElement)) { el.focus(); } } catch (_unused4) {} this.$emit('shown'); }, onAfterLeave: function onAfterLeave() { try { this.$_returnFocusEl.focus(); } catch (_unused5) {} this.$_returnFocusEl = null; // Trigger lazy render this.isOpen = false; this.$emit('hidden'); } }, render: function render(h) { var _ref; var localShow = this.localShow; var shadow = this.shadow === '' ? true : this.shadow; var title = this.normalizeSlot('title', this.slotScope) || toString(this.title) || null; var titleId = title ? this.safeId('__title__') : null; var ariaLabel = this.ariaLabel || null; // `ariaLabel` takes precedence over `ariaLabelledby` var ariaLabelledby = this.ariaLabelledby || titleId || null; var $sidebar = h(this.tag, { ref: 'content', directives: [{ name: 'show', value: localShow }], staticClass: CLASS_NAME, class: [(_ref = { shadow: shadow === true }, _defineProperty(_ref, "shadow-".concat(shadow), shadow && shadow !== true), _defineProperty(_ref, "".concat(CLASS_NAME, "-right"), this.right), _defineProperty(_ref, "bg-".concat(this.bgVariant), !!this.bgVariant), _defineProperty(_ref, "text-".concat(this.textVariant), !!this.textVariant), _ref), this.sidebarClass], attrs: _objectSpread(_objectSpread({}, this.$attrs), {}, { id: this.safeId(), tabindex: '-1', role: 'dialog', 'aria-modal': this.backdrop ? 'true' : 'false', 'aria-hidden': localShow ? null : 'true', 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby }), style: { width: this.width } }, [renderContent(h, this)]); $sidebar = h('transition', { props: this.transitionProps, on: { beforeEnter: this.onBeforeEnter, afterEnter: this.onAfterEnter, afterLeave: this.onAfterLeave } }, [$sidebar]); var $backdrop = h(BVTransition, { props: { noFade: this.noSlide } }, [renderBackdrop(h, this)]); var $tabTrapTop = h(); var $tabTrapBottom = h(); if (this.backdrop && this.localShow) { $tabTrapTop = h('div', { attrs: { tabindex: '0' }, on: { focus: this.onTopTrapFocus } }); $tabTrapBottom = h('div', { attrs: { tabindex: '0' }, on: { focus: this.onBottomTrapFocus } }); } return h('div', { staticClass: 'b-sidebar-outer', style: { zIndex: this.zIndex }, attrs: { tabindex: '-1' }, on: { keydown: this.onKeydown } }, [$tabTrapTop, $sidebar, $tabTrapBottom, $backdrop]); } });