UNPKG

bootstrap-vue

Version:

With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens

138 lines (133 loc) 3.65 kB
import { PortalTarget, Wormhole } from 'portal-vue' import Vue from '../../vue' import { NAME_TOASTER } from '../../constants/components' import { getComponentConfig } from '../../utils/config' import { removeClass, requestAF } from '../../utils/dom' import { warn } from '../../utils/warn' // --- Props --- export const props = { name: { type: String, required: true }, ariaLive: { type: String, default: () => getComponentConfig(NAME_TOASTER, 'ariaLive') }, ariaAtomic: { type: String, default: () => getComponentConfig(NAME_TOASTER, 'ariaAtomic') // Allowed: 'true' or 'false' or null }, role: { // Aria role type: String, default: () => getComponentConfig(NAME_TOASTER, 'role') } /* transition: { type: [Boolean, String, Object], default: false } */ } // @vue/component export const DefaultTransition = /*#__PURE__*/ Vue.extend({ data() { return { // Transition classes base name name: 'b-toaster' } }, methods: { onAfterEnter(el) { // Work around a Vue.js bug where `*-enter-to` class is not removed // See: https://github.com/vuejs/vue/pull/7901 // The `*-move` class is also stuck on elements that moved, // but there are no JavaScript hooks to handle after move // See: https://github.com/vuejs/vue/pull/7906 requestAF(() => { removeClass(el, `${this.name}-enter-to`) }) } }, render(h) { return h( 'transition-group', { props: { tag: 'div', name: this.name }, on: { afterEnter: this.onAfterEnter } }, this.$slots.default ) } }) // @vue/component export const BToaster = /*#__PURE__*/ Vue.extend({ name: NAME_TOASTER, props, data() { return { // We don't render on SSR or if a an existing target found doRender: false, dead: false, // Toaster names cannot change once created staticName: this.name } }, beforeMount() { this.staticName = this.name /* istanbul ignore if */ if (Wormhole.hasTarget(this.staticName)) { warn( `A "<portal-target>" with name "${this.name}" already exists in the document.`, NAME_TOASTER ) this.dead = true } else { this.doRender = true this.$once('hook:beforeDestroy', () => { // Let toasts made with `this.$bvToast.toast()` know that this toaster // is being destroyed and should should also destroy/hide themselves this.$root.$emit('bv::toaster::destroyed', this.staticName) }) } }, destroyed() { // Remove from DOM if needed /* istanbul ignore next: difficult to test */ if (this.$el && this.$el.parentNode) { this.$el.parentNode.removeChild(this.$el) } }, render(h) { let $toaster = h('div', { class: ['d-none', { 'b-dead-toaster': this.dead }] }) if (this.doRender) { const $target = h(PortalTarget, { staticClass: 'b-toaster-slot', props: { name: this.staticName, multiple: true, tag: 'div', slim: false, // transition: this.transition || DefaultTransition transition: DefaultTransition } }) $toaster = h( 'div', { staticClass: 'b-toaster', class: [this.staticName], attrs: { id: this.staticName, role: this.role || null, // Fallback to null to make sure attribute doesn't exist 'aria-live': this.ariaLive, 'aria-atomic': this.ariaAtomic } }, [$target] ) } return $toaster } })