@gitlab/ui 130.1.1 → 131.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +9 -0
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +18 -2
- package/dist/components/base/toast/index.js +66 -0
- package/dist/components/base/toast/toast.js +117 -89
- package/dist/components/base/toast/toaster.js +87 -0
- package/dist/components/charts/single_stat/single_stat.js +13 -1
- package/dist/components/index.js +1 -1
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/package.json +4 -1
- package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +9 -0
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +23 -1
- package/src/components/base/toast/index.js +66 -0
- package/src/components/base/toast/toast.scss +31 -5
- package/src/components/base/toast/toast.vue +131 -0
- package/src/components/base/toast/toaster.vue +70 -0
- package/src/components/charts/single_stat/single_stat.vue +31 -3
- package/src/components/index.js +1 -1
- package/src/scss/bootstrap_vue.scss +0 -1
- package/dist/vendor/bootstrap-vue/src/components/toast/helpers/bv-toast.js +0 -234
- package/dist/vendor/bootstrap-vue/src/components/toast/index.js +0 -19
- package/dist/vendor/bootstrap-vue/src/components/toast/toast.js +0 -407
- package/dist/vendor/bootstrap-vue/src/components/toast/toaster.js +0 -142
- package/src/components/base/toast/toast.js +0 -102
- package/src/vendor/bootstrap-vue/src/components/toast/_toast.scss +0 -77
- package/src/vendor/bootstrap-vue/src/components/toast/_toaster.scss +0 -108
- package/src/vendor/bootstrap-vue/src/components/toast/helpers/bv-toast.js +0 -231
- package/src/vendor/bootstrap-vue/src/components/toast/index.js +0 -12
- package/src/vendor/bootstrap-vue/src/components/toast/index.scss +0 -2
- package/src/vendor/bootstrap-vue/src/components/toast/toast.js +0 -439
- package/src/vendor/bootstrap-vue/src/components/toast/toaster.js +0 -136
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { NAME_TOAST_POP, NAME_TOASTER, NAME_TOAST } from '../../../constants/components';
|
|
2
|
-
import { EVENT_NAME_DESTROYED, EVENT_NAME_SHOW, EVENT_NAME_HIDE } from '../../../constants/events';
|
|
3
|
-
import { onInstanceDestroy } from '../../../utils/on-instance-destroy';
|
|
4
|
-
import { useParentMixin } from '../../../mixins/use-parent';
|
|
5
|
-
import { concat } from '../../../utils/array';
|
|
6
|
-
import { getComponentConfig } from '../../../utils/config';
|
|
7
|
-
import { requestAF } from '../../../utils/dom';
|
|
8
|
-
import { getRootEventName, getRootActionEventName } from '../../../utils/events';
|
|
9
|
-
import { isUndefined, isFunction } from '../../../utils/inspect';
|
|
10
|
-
import { keys, omit, hasOwnProperty, defineProperty, assign, defineProperties, readonlyDescriptor } from '../../../utils/object';
|
|
11
|
-
import { pluginFactory } from '../../../utils/plugins';
|
|
12
|
-
import { warn, warnNotClient } from '../../../utils/warn';
|
|
13
|
-
import { createNewChildComponent } from '../../../utils/create-new-child-component';
|
|
14
|
-
import { getEventRoot } from '../../../utils/get-event-root';
|
|
15
|
-
import { isVue3 } from '../../../vue';
|
|
16
|
-
import { props, BToast } from '../toast';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Plugin for adding `$bvToast` property to all Vue instances
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// --- Constants ---
|
|
24
|
-
|
|
25
|
-
const PROP_NAME = '$bvToast';
|
|
26
|
-
const PROP_NAME_PRIV = '_bv__toast';
|
|
27
|
-
|
|
28
|
-
// Base toast props that are allowed
|
|
29
|
-
// Some may be ignored or overridden on some message boxes
|
|
30
|
-
// Prop ID is allowed, but really only should be used for testing
|
|
31
|
-
// We need to add it in explicitly as it comes from the `idMixin`
|
|
32
|
-
const BASE_PROPS = ['id', ...keys(omit(props, ['static', 'visible']))];
|
|
33
|
-
|
|
34
|
-
// Map prop names to toast slot names
|
|
35
|
-
const propsToSlots = {
|
|
36
|
-
toastContent: 'default',
|
|
37
|
-
title: 'toast-title'
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// --- Helper methods ---
|
|
41
|
-
|
|
42
|
-
// Method to filter only recognized props that are not undefined
|
|
43
|
-
const filterOptions = options => {
|
|
44
|
-
return BASE_PROPS.reduce((memo, key) => {
|
|
45
|
-
if (!isUndefined(options[key])) {
|
|
46
|
-
memo[key] = options[key];
|
|
47
|
-
}
|
|
48
|
-
return memo;
|
|
49
|
-
}, {});
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Method to install `$bvToast` VM injection
|
|
53
|
-
const plugin = Vue => {
|
|
54
|
-
// Create a private sub-component constructor that
|
|
55
|
-
// extends BToast and self-destructs after hidden
|
|
56
|
-
// @vue/component
|
|
57
|
-
const BVToastPop = Vue.extend({
|
|
58
|
-
name: NAME_TOAST_POP,
|
|
59
|
-
extends: BToast,
|
|
60
|
-
mixins: [useParentMixin],
|
|
61
|
-
destroyed() {
|
|
62
|
-
// Make sure we not in document any more
|
|
63
|
-
const {
|
|
64
|
-
$el
|
|
65
|
-
} = this;
|
|
66
|
-
if ($el && $el.parentNode) {
|
|
67
|
-
$el.parentNode.removeChild($el);
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
mounted() {
|
|
71
|
-
// Self destruct handler (stored as instance property for use in onAfterLeave)
|
|
72
|
-
this.$_handleDestroy = () => {
|
|
73
|
-
// Ensure the toast has been force hidden
|
|
74
|
-
this.localShow = false;
|
|
75
|
-
this.doRender = false;
|
|
76
|
-
this.$nextTick(() => {
|
|
77
|
-
this.$nextTick(() => {
|
|
78
|
-
// In a `requestAF()` to release control back to application
|
|
79
|
-
// and to allow the portal-target time to remove the content
|
|
80
|
-
requestAF(() => {
|
|
81
|
-
this.$destroy();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
};
|
|
86
|
-
// Self destruct if parent destroyed
|
|
87
|
-
onInstanceDestroy(this.bvParent, this.$_handleDestroy);
|
|
88
|
-
// Self destruct when toaster is destroyed
|
|
89
|
-
this.listenOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), toaster => {
|
|
90
|
-
/* istanbul ignore next: hard to test */
|
|
91
|
-
if (toaster === this.toaster) {
|
|
92
|
-
this.$_handleDestroy();
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
},
|
|
96
|
-
methods: {
|
|
97
|
-
// Override parent's onAfterLeave to self-destruct after hidden
|
|
98
|
-
onAfterLeave() {
|
|
99
|
-
// Call parent's implementation
|
|
100
|
-
BToast.options.methods.onAfterLeave.call(this);
|
|
101
|
-
// Self destruct after hidden
|
|
102
|
-
this.$_handleDestroy();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Private method to generate the on-demand toast
|
|
108
|
-
const makeToast = (props, parent) => {
|
|
109
|
-
if (warnNotClient(PROP_NAME)) {
|
|
110
|
-
/* istanbul ignore next */
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
// Create an instance of `BVToastPop` component
|
|
114
|
-
const toast = createNewChildComponent(parent, BVToastPop, {
|
|
115
|
-
// We set parent as the local VM so these toasts can emit events on the
|
|
116
|
-
// app `$root`, and it ensures `BToast` is destroyed when parent is destroyed
|
|
117
|
-
propsData: {
|
|
118
|
-
...filterOptions(getComponentConfig(NAME_TOAST)),
|
|
119
|
-
// Add in (filtered) user supplied props
|
|
120
|
-
...omit(props, keys(propsToSlots)),
|
|
121
|
-
// Props that can't be overridden
|
|
122
|
-
static: false,
|
|
123
|
-
visible: true
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
// Convert certain props to slots
|
|
127
|
-
keys(propsToSlots).forEach(prop => {
|
|
128
|
-
let value = props[prop];
|
|
129
|
-
if (!isUndefined(value)) {
|
|
130
|
-
if (isVue3(toast)) {
|
|
131
|
-
// In Vue 3 compat, $slots is readonly. Set slots on the internal
|
|
132
|
-
// instance as functions so VNodes are available during the
|
|
133
|
-
// component's render cycle. When the value is a render function,
|
|
134
|
-
// defer calling it until the slot is evaluated during render so
|
|
135
|
-
// that $createElement runs within an active component context.
|
|
136
|
-
const slotFn = isFunction(value) ? () => concat(value(toast.$createElement)) : () => concat(value);
|
|
137
|
-
toast.$.slots[propsToSlots[prop]] = slotFn;
|
|
138
|
-
} else {
|
|
139
|
-
if (isFunction(value)) {
|
|
140
|
-
value = value(toast.$createElement);
|
|
141
|
-
}
|
|
142
|
-
toast.$slots[propsToSlots[prop]] = concat(value);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
// Create a mount point (a DIV) and mount it (which triggers the show)
|
|
147
|
-
function createMountPoint() {
|
|
148
|
-
const div = document.createElement('div');
|
|
149
|
-
document.body.appendChild(div);
|
|
150
|
-
toast.$mount(div);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// ViewTransition fallback
|
|
154
|
-
if (!document.startViewTransition) {
|
|
155
|
-
createMountPoint();
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
document.startViewTransition(createMountPoint);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// Declare BvToast instance property class
|
|
162
|
-
class BvToast {
|
|
163
|
-
constructor(vm) {
|
|
164
|
-
// Assign the new properties to this instance
|
|
165
|
-
assign(this, {
|
|
166
|
-
_vm: vm,
|
|
167
|
-
_root: getEventRoot(vm)
|
|
168
|
-
});
|
|
169
|
-
// Set these properties as read-only and non-enumerable
|
|
170
|
-
defineProperties(this, {
|
|
171
|
-
_vm: readonlyDescriptor(),
|
|
172
|
-
_root: readonlyDescriptor()
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// --- Public Instance methods ---
|
|
177
|
-
|
|
178
|
-
// Opens a user defined toast and returns immediately
|
|
179
|
-
toast(content) {
|
|
180
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
181
|
-
if (!content || warnNotClient(PROP_NAME)) {
|
|
182
|
-
/* istanbul ignore next */
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
makeToast({
|
|
186
|
-
...filterOptions(options),
|
|
187
|
-
toastContent: content
|
|
188
|
-
}, this._vm);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// shows a `<b-toast>` component with the specified ID
|
|
192
|
-
show(id) {
|
|
193
|
-
if (id) {
|
|
194
|
-
this._root.$emit(getRootActionEventName(NAME_TOAST, EVENT_NAME_SHOW), id);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Hide a toast with specified ID, or if not ID all toasts
|
|
199
|
-
hide() {
|
|
200
|
-
let id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
201
|
-
this._root.$emit(getRootActionEventName(NAME_TOAST, EVENT_NAME_HIDE), id);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Add our instance mixin
|
|
206
|
-
Vue.mixin({
|
|
207
|
-
beforeCreate() {
|
|
208
|
-
// Because we need access to `$root` for `$emits`, and VM for parenting,
|
|
209
|
-
// we have to create a fresh instance of `BvToast` for each VM
|
|
210
|
-
this[PROP_NAME_PRIV] = new BvToast(this);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Define our read-only `$bvToast` instance property
|
|
215
|
-
// Placed in an if just in case in HMR mode
|
|
216
|
-
if (!hasOwnProperty(Vue.prototype, PROP_NAME)) {
|
|
217
|
-
defineProperty(Vue.prototype, PROP_NAME, {
|
|
218
|
-
get() {
|
|
219
|
-
/* istanbul ignore next */
|
|
220
|
-
if (!this || !this[PROP_NAME_PRIV]) {
|
|
221
|
-
warn(`"${PROP_NAME}" must be accessed from a Vue instance "this" context.`, NAME_TOAST);
|
|
222
|
-
}
|
|
223
|
-
return this[PROP_NAME_PRIV];
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
const BVToastPlugin = /*#__PURE__*/pluginFactory({
|
|
229
|
-
plugins: {
|
|
230
|
-
plugin
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
export { BVToastPlugin };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { BVToastPlugin } from './helpers/bv-toast';
|
|
2
|
-
import { BToast } from './toast';
|
|
3
|
-
export { BToast } from './toast';
|
|
4
|
-
import { BToaster } from './toaster';
|
|
5
|
-
export { BToaster } from './toaster';
|
|
6
|
-
import { pluginFactory } from '../../utils/plugins';
|
|
7
|
-
|
|
8
|
-
const ToastPlugin = /*#__PURE__*/pluginFactory({
|
|
9
|
-
components: {
|
|
10
|
-
BToast,
|
|
11
|
-
BToaster
|
|
12
|
-
},
|
|
13
|
-
// $bvToast injection
|
|
14
|
-
plugins: {
|
|
15
|
-
BVToastPlugin
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export { ToastPlugin };
|
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import { Wormhole, Portal } from 'portal-vue';
|
|
2
|
-
import { extend, COMPONENT_UID_KEY } from '../../vue';
|
|
3
|
-
import { NAME_TOAST, NAME_TOASTER } from '../../constants/components';
|
|
4
|
-
import { EVENT_NAME_CHANGE, EVENT_NAME_SHOW, EVENT_NAME_HIDE, EVENT_NAME_DESTROYED, EVENT_OPTIONS_NO_CAPTURE, EVENT_NAME_SHOWN, EVENT_NAME_HIDDEN } from '../../constants/events';
|
|
5
|
-
import { PROP_TYPE_BOOLEAN, PROP_TYPE_NUMBER_STRING, PROP_TYPE_ARRAY_OBJECT_STRING, PROP_TYPE_STRING } from '../../constants/props';
|
|
6
|
-
import { SLOT_NAME_TOAST_TITLE, SLOT_NAME_DEFAULT } from '../../constants/slots';
|
|
7
|
-
import { BvEvent } from '../../utils/bv-event.class';
|
|
8
|
-
import { requestAF } from '../../utils/dom';
|
|
9
|
-
import { getRootActionEventName, getRootEventName, eventOnOff } from '../../utils/events';
|
|
10
|
-
import { mathMax } from '../../utils/math';
|
|
11
|
-
import { makeModelMixin } from '../../utils/model';
|
|
12
|
-
import { toInteger } from '../../utils/number';
|
|
13
|
-
import { pick, sortKeys } from '../../utils/object';
|
|
14
|
-
import { makeProp, pluckProps } from '../../utils/props';
|
|
15
|
-
import { isLink } from '../../utils/router';
|
|
16
|
-
import { createNewChildComponent } from '../../utils/create-new-child-component';
|
|
17
|
-
import { attrsMixin } from '../../mixins/attrs';
|
|
18
|
-
import { props as props$2, idMixin } from '../../mixins/id';
|
|
19
|
-
import { listenOnRootMixin } from '../../mixins/listen-on-root';
|
|
20
|
-
import { normalizeSlotMixin } from '../../mixins/normalize-slot';
|
|
21
|
-
import { scopedStyleMixin } from '../../mixins/scoped-style';
|
|
22
|
-
import { props as props$1, BLink } from '../link/link';
|
|
23
|
-
import { BVTransition } from '../transition/bv-transition';
|
|
24
|
-
import { BToaster } from './toaster';
|
|
25
|
-
|
|
26
|
-
// --- Constants ---
|
|
27
|
-
|
|
28
|
-
const {
|
|
29
|
-
mixin: modelMixin,
|
|
30
|
-
props: modelProps,
|
|
31
|
-
prop: MODEL_PROP_NAME,
|
|
32
|
-
event: MODEL_EVENT_NAME
|
|
33
|
-
} = makeModelMixin('visible', {
|
|
34
|
-
type: PROP_TYPE_BOOLEAN,
|
|
35
|
-
defaultValue: false,
|
|
36
|
-
event: EVENT_NAME_CHANGE
|
|
37
|
-
});
|
|
38
|
-
const MIN_DURATION = 1000;
|
|
39
|
-
|
|
40
|
-
// --- Props ---
|
|
41
|
-
|
|
42
|
-
const linkProps = pick(props$1, ['href', 'to']);
|
|
43
|
-
const props = sortKeys({
|
|
44
|
-
...props$2,
|
|
45
|
-
...modelProps,
|
|
46
|
-
...linkProps,
|
|
47
|
-
appendToast: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
48
|
-
autoHideDelay: makeProp(PROP_TYPE_NUMBER_STRING, 5000),
|
|
49
|
-
bodyClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
|
|
50
|
-
headerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
|
|
51
|
-
headerTag: makeProp(PROP_TYPE_STRING, 'header'),
|
|
52
|
-
// Switches role to 'status' and aria-live to 'polite'
|
|
53
|
-
isStatus: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
54
|
-
noAutoHide: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
55
|
-
noFade: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
56
|
-
noHoverPause: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
57
|
-
solid: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
58
|
-
// Render the toast in place, rather than in a portal-target
|
|
59
|
-
static: makeProp(PROP_TYPE_BOOLEAN, false),
|
|
60
|
-
title: makeProp(PROP_TYPE_STRING),
|
|
61
|
-
toastClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
|
|
62
|
-
toaster: makeProp(PROP_TYPE_STRING, 'b-toaster-top-right'),
|
|
63
|
-
variant: makeProp(PROP_TYPE_STRING)
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// --- Main component ---
|
|
67
|
-
|
|
68
|
-
// @vue/component
|
|
69
|
-
const BToast = /*#__PURE__*/extend({
|
|
70
|
-
name: NAME_TOAST,
|
|
71
|
-
mixins: [attrsMixin, idMixin, modelMixin, listenOnRootMixin, normalizeSlotMixin, scopedStyleMixin],
|
|
72
|
-
inheritAttrs: false,
|
|
73
|
-
props,
|
|
74
|
-
data() {
|
|
75
|
-
return {
|
|
76
|
-
isMounted: false,
|
|
77
|
-
doRender: false,
|
|
78
|
-
localShow: false,
|
|
79
|
-
isTransitioning: false,
|
|
80
|
-
isHiding: false,
|
|
81
|
-
order: 0,
|
|
82
|
-
dismissStarted: 0,
|
|
83
|
-
resumeDismiss: 0
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
computed: {
|
|
87
|
-
toastClasses() {
|
|
88
|
-
const {
|
|
89
|
-
appendToast,
|
|
90
|
-
variant
|
|
91
|
-
} = this;
|
|
92
|
-
return {
|
|
93
|
-
'b-toast-solid': this.solid,
|
|
94
|
-
'b-toast-append': appendToast,
|
|
95
|
-
'b-toast-prepend': !appendToast,
|
|
96
|
-
[`b-toast-${variant}`]: variant
|
|
97
|
-
};
|
|
98
|
-
},
|
|
99
|
-
slotScope() {
|
|
100
|
-
const {
|
|
101
|
-
hide
|
|
102
|
-
} = this;
|
|
103
|
-
return {
|
|
104
|
-
hide
|
|
105
|
-
};
|
|
106
|
-
},
|
|
107
|
-
computedDuration() {
|
|
108
|
-
// Minimum supported duration is 1 second
|
|
109
|
-
return mathMax(toInteger(this.autoHideDelay, 0), MIN_DURATION);
|
|
110
|
-
},
|
|
111
|
-
computedToaster() {
|
|
112
|
-
return String(this.toaster);
|
|
113
|
-
},
|
|
114
|
-
transitionHandlers() {
|
|
115
|
-
return {
|
|
116
|
-
beforeEnter: this.onBeforeEnter,
|
|
117
|
-
afterEnter: this.onAfterEnter,
|
|
118
|
-
beforeLeave: this.onBeforeLeave,
|
|
119
|
-
afterLeave: this.onAfterLeave
|
|
120
|
-
};
|
|
121
|
-
},
|
|
122
|
-
computedAttrs() {
|
|
123
|
-
return {
|
|
124
|
-
...this.bvAttrs,
|
|
125
|
-
id: this.safeId(),
|
|
126
|
-
tabindex: '0'
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
watch: {
|
|
131
|
-
[MODEL_PROP_NAME](newValue) {
|
|
132
|
-
this[newValue ? 'show' : 'hide']();
|
|
133
|
-
},
|
|
134
|
-
localShow(newValue) {
|
|
135
|
-
if (newValue !== this[MODEL_PROP_NAME]) {
|
|
136
|
-
this.$emit(MODEL_EVENT_NAME, newValue);
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
/* istanbul ignore next */
|
|
140
|
-
toaster() {
|
|
141
|
-
// If toaster target changed, make sure toaster exists
|
|
142
|
-
this.$nextTick(this.ensureToaster);
|
|
143
|
-
},
|
|
144
|
-
/* istanbul ignore next */
|
|
145
|
-
static(newValue) {
|
|
146
|
-
// If static changes to true, and the toast is showing,
|
|
147
|
-
// ensure the toaster target exists
|
|
148
|
-
if (newValue && this.localShow) {
|
|
149
|
-
this.ensureToaster();
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
created() {
|
|
154
|
-
// Create private non-reactive props
|
|
155
|
-
this.$_dismissTimer = null;
|
|
156
|
-
},
|
|
157
|
-
mounted() {
|
|
158
|
-
this.isMounted = true;
|
|
159
|
-
this.$nextTick(() => {
|
|
160
|
-
if (this[MODEL_PROP_NAME]) {
|
|
161
|
-
requestAF(() => {
|
|
162
|
-
this.show();
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
// Listen for global $root show events
|
|
167
|
-
this.listenOnRoot(getRootActionEventName(NAME_TOAST, EVENT_NAME_SHOW), id => {
|
|
168
|
-
if (id === this.safeId()) {
|
|
169
|
-
this.show();
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
// Listen for global $root hide events
|
|
173
|
-
this.listenOnRoot(getRootActionEventName(NAME_TOAST, EVENT_NAME_HIDE), id => {
|
|
174
|
-
if (!id || id === this.safeId()) {
|
|
175
|
-
this.hide();
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
// Make sure we hide when toaster is destroyed
|
|
179
|
-
/* istanbul ignore next: difficult to test */
|
|
180
|
-
this.listenOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), toaster => {
|
|
181
|
-
/* istanbul ignore next */
|
|
182
|
-
if (toaster === this.computedToaster) {
|
|
183
|
-
this.hide();
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
beforeDestroy() {
|
|
188
|
-
this.clearDismissTimer();
|
|
189
|
-
},
|
|
190
|
-
methods: {
|
|
191
|
-
show() {
|
|
192
|
-
if (!this.localShow) {
|
|
193
|
-
this.ensureToaster();
|
|
194
|
-
const showEvent = this.buildEvent(EVENT_NAME_SHOW);
|
|
195
|
-
this.emitEvent(showEvent);
|
|
196
|
-
this.dismissStarted = this.resumeDismiss = 0;
|
|
197
|
-
this.order = Date.now() * (this.appendToast ? 1 : -1);
|
|
198
|
-
this.isHiding = false;
|
|
199
|
-
this.doRender = true;
|
|
200
|
-
this.$nextTick(() => {
|
|
201
|
-
// We show the toast after we have rendered the portal and b-toast wrapper
|
|
202
|
-
// so that screen readers will properly announce the toast
|
|
203
|
-
requestAF(() => {
|
|
204
|
-
this.localShow = true;
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
hide() {
|
|
210
|
-
if (this.localShow) {
|
|
211
|
-
const hideEvent = this.buildEvent(EVENT_NAME_HIDE);
|
|
212
|
-
this.emitEvent(hideEvent);
|
|
213
|
-
this.setHoverHandler(false);
|
|
214
|
-
this.dismissStarted = this.resumeDismiss = 0;
|
|
215
|
-
this.clearDismissTimer();
|
|
216
|
-
this.isHiding = true;
|
|
217
|
-
requestAF(() => {
|
|
218
|
-
this.localShow = false;
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
buildEvent(type) {
|
|
223
|
-
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
224
|
-
return new BvEvent(type, {
|
|
225
|
-
cancelable: false,
|
|
226
|
-
target: this.$el || null,
|
|
227
|
-
relatedTarget: null,
|
|
228
|
-
...options,
|
|
229
|
-
vueTarget: this,
|
|
230
|
-
componentId: this.safeId()
|
|
231
|
-
});
|
|
232
|
-
},
|
|
233
|
-
emitEvent(bvEvent) {
|
|
234
|
-
const {
|
|
235
|
-
type
|
|
236
|
-
} = bvEvent;
|
|
237
|
-
this.emitOnRoot(getRootEventName(NAME_TOAST, type), bvEvent);
|
|
238
|
-
this.$emit(type, bvEvent);
|
|
239
|
-
},
|
|
240
|
-
ensureToaster() {
|
|
241
|
-
if (this.static) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const {
|
|
245
|
-
computedToaster
|
|
246
|
-
} = this;
|
|
247
|
-
const hasTarget = Wormhole.hasTarget(computedToaster);
|
|
248
|
-
const hasDOM = document.getElementById(computedToaster);
|
|
249
|
-
if (!hasTarget || !hasDOM) {
|
|
250
|
-
if (hasTarget && !hasDOM) {
|
|
251
|
-
Wormhole.unregisterTarget(computedToaster);
|
|
252
|
-
}
|
|
253
|
-
const div = document.createElement('div');
|
|
254
|
-
document.body.appendChild(div);
|
|
255
|
-
const toaster = createNewChildComponent(this.bvEventRoot, BToaster, {
|
|
256
|
-
propsData: {
|
|
257
|
-
name: computedToaster
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
toaster.$mount(div);
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
startDismissTimer() {
|
|
264
|
-
this.clearDismissTimer();
|
|
265
|
-
if (!this.noAutoHide) {
|
|
266
|
-
this.$_dismissTimer = setTimeout(this.hide, this.resumeDismiss || this.computedDuration);
|
|
267
|
-
this.dismissStarted = Date.now();
|
|
268
|
-
this.resumeDismiss = 0;
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
clearDismissTimer() {
|
|
272
|
-
clearTimeout(this.$_dismissTimer);
|
|
273
|
-
this.$_dismissTimer = null;
|
|
274
|
-
},
|
|
275
|
-
setHoverHandler(on) {
|
|
276
|
-
const el = this.$refs['b-toast'];
|
|
277
|
-
eventOnOff(on, el, 'mouseenter', this.onPause, EVENT_OPTIONS_NO_CAPTURE);
|
|
278
|
-
eventOnOff(on, el, 'mouseleave', this.onUnPause, EVENT_OPTIONS_NO_CAPTURE);
|
|
279
|
-
},
|
|
280
|
-
onPause() {
|
|
281
|
-
// Determine time remaining, and then pause timer
|
|
282
|
-
if (this.noAutoHide || this.noHoverPause || !this.$_dismissTimer || this.resumeDismiss) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
const passed = Date.now() - this.dismissStarted;
|
|
286
|
-
if (passed > 0) {
|
|
287
|
-
this.clearDismissTimer();
|
|
288
|
-
this.resumeDismiss = mathMax(this.computedDuration - passed, MIN_DURATION);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
onUnPause() {
|
|
292
|
-
// Restart timer with max of time remaining or 1 second
|
|
293
|
-
if (this.noAutoHide || this.noHoverPause || !this.resumeDismiss) {
|
|
294
|
-
this.resumeDismiss = this.dismissStarted = 0;
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
this.startDismissTimer();
|
|
298
|
-
},
|
|
299
|
-
onLinkClick() {
|
|
300
|
-
// We delay the close to allow time for the
|
|
301
|
-
// browser to process the link click
|
|
302
|
-
this.$nextTick(() => {
|
|
303
|
-
requestAF(() => {
|
|
304
|
-
this.hide();
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
},
|
|
308
|
-
onBeforeEnter() {
|
|
309
|
-
this.isTransitioning = true;
|
|
310
|
-
},
|
|
311
|
-
onAfterEnter() {
|
|
312
|
-
this.isTransitioning = false;
|
|
313
|
-
const hiddenEvent = this.buildEvent(EVENT_NAME_SHOWN);
|
|
314
|
-
this.emitEvent(hiddenEvent);
|
|
315
|
-
this.startDismissTimer();
|
|
316
|
-
this.setHoverHandler(true);
|
|
317
|
-
},
|
|
318
|
-
onBeforeLeave() {
|
|
319
|
-
this.isTransitioning = true;
|
|
320
|
-
},
|
|
321
|
-
onAfterLeave() {
|
|
322
|
-
this.isTransitioning = false;
|
|
323
|
-
this.order = 0;
|
|
324
|
-
this.resumeDismiss = this.dismissStarted = 0;
|
|
325
|
-
const hiddenEvent = this.buildEvent(EVENT_NAME_HIDDEN);
|
|
326
|
-
this.emitEvent(hiddenEvent);
|
|
327
|
-
this.doRender = false;
|
|
328
|
-
},
|
|
329
|
-
// Render helper for generating the toast
|
|
330
|
-
makeToast(h) {
|
|
331
|
-
const {
|
|
332
|
-
slotScope
|
|
333
|
-
} = this;
|
|
334
|
-
const link = isLink(this);
|
|
335
|
-
const $headerContent = [];
|
|
336
|
-
const $title = this.normalizeSlot(SLOT_NAME_TOAST_TITLE, slotScope);
|
|
337
|
-
if ($title) {
|
|
338
|
-
$headerContent.push($title);
|
|
339
|
-
}
|
|
340
|
-
let $header = h();
|
|
341
|
-
if ($headerContent.length > 0) {
|
|
342
|
-
$header = h(this.headerTag, {
|
|
343
|
-
staticClass: 'toast-header',
|
|
344
|
-
class: this.headerClass
|
|
345
|
-
}, $headerContent);
|
|
346
|
-
}
|
|
347
|
-
const $body = h(link ? BLink : 'div', {
|
|
348
|
-
staticClass: 'toast-body',
|
|
349
|
-
class: this.bodyClass,
|
|
350
|
-
props: link ? pluckProps(linkProps, this) : {},
|
|
351
|
-
on: link ? {
|
|
352
|
-
click: this.onLinkClick
|
|
353
|
-
} : {}
|
|
354
|
-
}, this.normalizeSlot(SLOT_NAME_DEFAULT, slotScope));
|
|
355
|
-
return h('div', {
|
|
356
|
-
staticClass: 'toast',
|
|
357
|
-
class: this.toastClass,
|
|
358
|
-
attrs: this.computedAttrs,
|
|
359
|
-
key: `toast-${this[COMPONENT_UID_KEY]}`,
|
|
360
|
-
ref: 'toast'
|
|
361
|
-
}, [$header, $body]);
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
|
-
render(h) {
|
|
365
|
-
if (!this.doRender || !this.isMounted) {
|
|
366
|
-
return h();
|
|
367
|
-
}
|
|
368
|
-
const {
|
|
369
|
-
order,
|
|
370
|
-
static: isStatic,
|
|
371
|
-
isHiding,
|
|
372
|
-
isStatus
|
|
373
|
-
} = this;
|
|
374
|
-
const name = `b-toast-${this[COMPONENT_UID_KEY]}`;
|
|
375
|
-
const $toast = h('div', {
|
|
376
|
-
staticClass: 'b-toast',
|
|
377
|
-
class: this.toastClasses,
|
|
378
|
-
attrs: {
|
|
379
|
-
// If scoped styles are applied and the toast is not static,
|
|
380
|
-
// make sure the scoped style data attribute is applied
|
|
381
|
-
...(isStatic ? {} : this.scopedStyleAttrs),
|
|
382
|
-
id: this.safeId('_toast_outer'),
|
|
383
|
-
role: isHiding ? null : isStatus ? 'status' : 'alert',
|
|
384
|
-
'aria-live': isHiding ? null : isStatus ? 'polite' : 'assertive',
|
|
385
|
-
'aria-atomic': isHiding ? null : 'true'
|
|
386
|
-
},
|
|
387
|
-
key: name,
|
|
388
|
-
ref: 'b-toast'
|
|
389
|
-
}, [h(BVTransition, {
|
|
390
|
-
props: {
|
|
391
|
-
noFade: this.noFade
|
|
392
|
-
},
|
|
393
|
-
on: this.transitionHandlers
|
|
394
|
-
}, [this.localShow ? this.makeToast(h) : h()])]);
|
|
395
|
-
return h(Portal, {
|
|
396
|
-
props: {
|
|
397
|
-
name,
|
|
398
|
-
to: this.computedToaster,
|
|
399
|
-
order,
|
|
400
|
-
slim: true,
|
|
401
|
-
disabled: isStatic
|
|
402
|
-
}
|
|
403
|
-
}, [$toast]);
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
export { BToast, props };
|