@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,142 +0,0 @@
|
|
|
1
|
-
import { Wormhole, PortalTarget } from 'portal-vue';
|
|
2
|
-
import { extend } from '../../vue';
|
|
3
|
-
import { NAME_TOASTER } from '../../constants/components';
|
|
4
|
-
import { EVENT_NAME_DESTROYED } from '../../constants/events';
|
|
5
|
-
import { PROP_TYPE_STRING } from '../../constants/props';
|
|
6
|
-
import { requestAF, removeClass } from '../../utils/dom';
|
|
7
|
-
import { getRootEventName } from '../../utils/events';
|
|
8
|
-
import { makeProp } from '../../utils/props';
|
|
9
|
-
import { warn } from '../../utils/warn';
|
|
10
|
-
import { listenOnRootMixin } from '../../mixins/listen-on-root';
|
|
11
|
-
import { normalizeSlotMixin } from '../../mixins/normalize-slot';
|
|
12
|
-
|
|
13
|
-
// --- Helper components ---
|
|
14
|
-
|
|
15
|
-
// @vue/component
|
|
16
|
-
const DefaultTransition = /*#__PURE__*/extend({
|
|
17
|
-
mixins: [normalizeSlotMixin],
|
|
18
|
-
data() {
|
|
19
|
-
return {
|
|
20
|
-
// Transition classes base name
|
|
21
|
-
name: 'b-toaster'
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
methods: {
|
|
25
|
-
onAfterEnter(el) {
|
|
26
|
-
// Work around a Vue.js bug where `*-enter-to` class is not removed
|
|
27
|
-
// See: https://github.com/vuejs/vue/pull/7901
|
|
28
|
-
// The `*-move` class is also stuck on elements that moved,
|
|
29
|
-
// but there are no JavaScript hooks to handle after move
|
|
30
|
-
// See: https://github.com/vuejs/vue/pull/7906
|
|
31
|
-
requestAF(() => {
|
|
32
|
-
removeClass(el, `${this.name}-enter-to`);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
render(h) {
|
|
37
|
-
return h('transition-group', {
|
|
38
|
-
props: {
|
|
39
|
-
tag: 'div',
|
|
40
|
-
name: this.name
|
|
41
|
-
},
|
|
42
|
-
on: {
|
|
43
|
-
afterEnter: this.onAfterEnter
|
|
44
|
-
}
|
|
45
|
-
}, this.normalizeSlot());
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// --- Props ---
|
|
50
|
-
|
|
51
|
-
const props = {
|
|
52
|
-
// Allowed: 'true' or 'false' or `null`
|
|
53
|
-
ariaAtomic: makeProp(PROP_TYPE_STRING),
|
|
54
|
-
ariaLive: makeProp(PROP_TYPE_STRING),
|
|
55
|
-
name: makeProp(PROP_TYPE_STRING, undefined, true),
|
|
56
|
-
// Required
|
|
57
|
-
// Aria role
|
|
58
|
-
role: makeProp(PROP_TYPE_STRING)
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// --- Main component ---
|
|
62
|
-
|
|
63
|
-
// @vue/component
|
|
64
|
-
const BToaster = /*#__PURE__*/extend({
|
|
65
|
-
name: NAME_TOASTER,
|
|
66
|
-
mixins: [listenOnRootMixin],
|
|
67
|
-
props,
|
|
68
|
-
data() {
|
|
69
|
-
return {
|
|
70
|
-
// We don't render on SSR or if a an existing target found
|
|
71
|
-
doRender: false,
|
|
72
|
-
dead: false,
|
|
73
|
-
// Toaster names cannot change once created
|
|
74
|
-
staticName: this.name
|
|
75
|
-
};
|
|
76
|
-
},
|
|
77
|
-
beforeMount() {
|
|
78
|
-
const {
|
|
79
|
-
name
|
|
80
|
-
} = this;
|
|
81
|
-
this.staticName = name;
|
|
82
|
-
|
|
83
|
-
/* istanbul ignore if */
|
|
84
|
-
if (Wormhole.hasTarget(name)) {
|
|
85
|
-
warn(`A "<portal-target>" with name "${name}" already exists in the document.`, NAME_TOASTER);
|
|
86
|
-
this.dead = true;
|
|
87
|
-
} else {
|
|
88
|
-
this.doRender = true;
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
beforeDestroy() {
|
|
92
|
-
// Let toasts made with `this.$bvToast.toast()` know that this toaster
|
|
93
|
-
// is being destroyed and should should also destroy/hide themselves
|
|
94
|
-
if (this.doRender) {
|
|
95
|
-
this.emitOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), this.name);
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
destroyed() {
|
|
99
|
-
// Remove from DOM if needed
|
|
100
|
-
const {
|
|
101
|
-
$el
|
|
102
|
-
} = this;
|
|
103
|
-
/* istanbul ignore next: difficult to test */
|
|
104
|
-
if ($el && $el.parentNode) {
|
|
105
|
-
$el.parentNode.removeChild($el);
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
render(h) {
|
|
109
|
-
let $toaster = h('div', {
|
|
110
|
-
class: ['gl-hidden', {
|
|
111
|
-
'b-dead-toaster': this.dead
|
|
112
|
-
}]
|
|
113
|
-
});
|
|
114
|
-
if (this.doRender) {
|
|
115
|
-
const $target = h(PortalTarget, {
|
|
116
|
-
staticClass: 'b-toaster-slot',
|
|
117
|
-
props: {
|
|
118
|
-
name: this.staticName,
|
|
119
|
-
multiple: true,
|
|
120
|
-
tag: 'div',
|
|
121
|
-
slim: false,
|
|
122
|
-
// transition: this.transition || DefaultTransition
|
|
123
|
-
transition: DefaultTransition
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
$toaster = h('div', {
|
|
127
|
-
staticClass: 'b-toaster',
|
|
128
|
-
class: [this.staticName],
|
|
129
|
-
attrs: {
|
|
130
|
-
id: this.staticName,
|
|
131
|
-
// Fallback to null to make sure attribute doesn't exist
|
|
132
|
-
role: this.role || null,
|
|
133
|
-
'aria-live': this.ariaLive,
|
|
134
|
-
'aria-atomic': this.ariaAtomic
|
|
135
|
-
}
|
|
136
|
-
}, [$target]);
|
|
137
|
-
}
|
|
138
|
-
return $toaster;
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
export { BToaster, DefaultTransition, props };
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/* eslint-disable import/no-default-export */
|
|
2
|
-
import { isFunction } from 'lodash-es';
|
|
3
|
-
// eslint-disable-next-line no-restricted-imports
|
|
4
|
-
import { ToastPlugin } from '../../../vendor/bootstrap-vue/src/components/toast/index';
|
|
5
|
-
import CloseButton from '../../shared_components/close_button/close_button.vue';
|
|
6
|
-
|
|
7
|
-
const DEFAULT_OPTIONS = {
|
|
8
|
-
autoHideDelay: 5000,
|
|
9
|
-
toastClass: 'gl-toast',
|
|
10
|
-
isStatus: true,
|
|
11
|
-
toaster: 'b-toaster-bottom-left',
|
|
12
|
-
appendToast: true,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
let toastsCount = 0;
|
|
16
|
-
|
|
17
|
-
function renderTitle(toast, options) {
|
|
18
|
-
return (h) => {
|
|
19
|
-
const nodes = [
|
|
20
|
-
h(CloseButton, {
|
|
21
|
-
class: ['gl-toast-close-button'],
|
|
22
|
-
on: {
|
|
23
|
-
click: toast.hide,
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
|
-
];
|
|
27
|
-
if (options.action) {
|
|
28
|
-
const { onClick, text, href } = options.action;
|
|
29
|
-
nodes.unshift(
|
|
30
|
-
h(
|
|
31
|
-
'a',
|
|
32
|
-
{
|
|
33
|
-
attrs: {
|
|
34
|
-
role: href ? undefined : 'button',
|
|
35
|
-
href,
|
|
36
|
-
},
|
|
37
|
-
class: ['gl-toast-action'],
|
|
38
|
-
on: {
|
|
39
|
-
click: (e) => onClick(e, toast),
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
text,
|
|
43
|
-
),
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
return nodes;
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function showToast(message, options = {}) {
|
|
51
|
-
// eslint-disable-next-line @gitlab/tailwind-no-interpolation -- Not a CSS utility
|
|
52
|
-
const id = `gl-toast-${toastsCount}`;
|
|
53
|
-
toastsCount += 1;
|
|
54
|
-
const hide = () => {
|
|
55
|
-
this.$bvToast.hide(id);
|
|
56
|
-
};
|
|
57
|
-
const toast = { id, hide };
|
|
58
|
-
|
|
59
|
-
if (isFunction(options.onComplete)) {
|
|
60
|
-
const toastHiddenCallback = (e) => {
|
|
61
|
-
if (e.componentId === id) {
|
|
62
|
-
this.$root.$off('bv::toast:hidden', toastHiddenCallback);
|
|
63
|
-
options.onComplete(e);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
this.$root.$on('bv::toast:hidden', toastHiddenCallback);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const updatedAutoHideDelay = !Number.isNaN(options?.autoHideDelay)
|
|
71
|
-
? { autoHideDelay: options.autoHideDelay }
|
|
72
|
-
: null;
|
|
73
|
-
|
|
74
|
-
this.$bvToast.toast(message, {
|
|
75
|
-
...DEFAULT_OPTIONS,
|
|
76
|
-
...updatedAutoHideDelay,
|
|
77
|
-
id,
|
|
78
|
-
title: renderTitle(toast, options),
|
|
79
|
-
});
|
|
80
|
-
return toast;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Note: This is not a typical Vue component and needs to be registered before instantiating a Vue app.
|
|
85
|
-
* Once registered, the toast will be globally available throughout your app.
|
|
86
|
-
*
|
|
87
|
-
* See https://design.gitlab.com/storybook for detailed documentation.
|
|
88
|
-
*/
|
|
89
|
-
export default {
|
|
90
|
-
install(Vue) {
|
|
91
|
-
Vue.use(ToastPlugin);
|
|
92
|
-
|
|
93
|
-
Vue.mixin({
|
|
94
|
-
beforeCreate() {
|
|
95
|
-
if (this.$toast) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.$toast = { show: showToast.bind(this) };
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
},
|
|
102
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
@use 'sass:color';
|
|
2
|
-
|
|
3
|
-
// --- <b-toast> custom SCSS ---
|
|
4
|
-
|
|
5
|
-
// Toast wrapper element class (needed for list transition in toasters)
|
|
6
|
-
.b-toast {
|
|
7
|
-
display: block;
|
|
8
|
-
position: relative;
|
|
9
|
-
max-width: $toast-max-width;
|
|
10
|
-
backface-visibility: hidden;
|
|
11
|
-
background-clip: padding-box;
|
|
12
|
-
|
|
13
|
-
z-index: 1;
|
|
14
|
-
@include border-radius($toast-border-radius);
|
|
15
|
-
|
|
16
|
-
.toast {
|
|
17
|
-
// Allow us to override Bootstrap's default toast opacity
|
|
18
|
-
// As they do not provide it as a variable
|
|
19
|
-
background-color: rgba($toast-background-color, $b-toast-background-opacity);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
&.b-toast-solid {
|
|
23
|
-
.toast {
|
|
24
|
-
background-color: rgba($toast-background-color, 1);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.toast {
|
|
29
|
-
// Override default Bootstrap v4.x opacity of 0
|
|
30
|
-
// Needed for re-usable fade transition
|
|
31
|
-
opacity: 1;
|
|
32
|
-
|
|
33
|
-
&.fade:not(.show) {
|
|
34
|
-
opacity: 0;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.toast-body {
|
|
38
|
-
display: block; // Needed when we use a link as the body element
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@mixin b-toast-variant($background, $border, $color) {
|
|
44
|
-
// Based on alert-variant mixin
|
|
45
|
-
.toast {
|
|
46
|
-
background-color: rgba(color.adjust($background, $lightness: 5%), $b-toast-background-opacity);
|
|
47
|
-
border-color: rgba($border, $b-toast-background-opacity);
|
|
48
|
-
color: $color;
|
|
49
|
-
|
|
50
|
-
.toast-header {
|
|
51
|
-
color: $color;
|
|
52
|
-
background-color: rgba($background, $b-toast-background-opacity);
|
|
53
|
-
border-bottom-color: rgba($border, $b-toast-background-opacity);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// .toast-body[href] {
|
|
57
|
-
// color: darken($color, 10%);
|
|
58
|
-
// }
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&.b-toast-solid {
|
|
62
|
-
.toast {
|
|
63
|
-
background-color: rgba(color.adjust($background, $lightness: 5%), 1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Toast variants
|
|
69
|
-
@each $color, $value in $theme-colors {
|
|
70
|
-
.b-toast-#{$color} {
|
|
71
|
-
@include b-toast-variant(
|
|
72
|
-
theme-color-level($color, $b-toast-bg-level),
|
|
73
|
-
theme-color-level($color, $b-toast-border-level),
|
|
74
|
-
theme-color-level($color, $b-toast-color-level)
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// --- <b-toaster> custom SCSS ---
|
|
2
|
-
|
|
3
|
-
// Base toaster styling
|
|
4
|
-
.b-toaster {
|
|
5
|
-
z-index: $b-toaster-zindex;
|
|
6
|
-
|
|
7
|
-
.b-toaster-slot {
|
|
8
|
-
position: relative;
|
|
9
|
-
display: block;
|
|
10
|
-
|
|
11
|
-
&:empty {
|
|
12
|
-
display: none !important;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Built-in toaster styling
|
|
18
|
-
// - b-toaster-top-right
|
|
19
|
-
// - b-toaster-top-left
|
|
20
|
-
// - b-toaster-top-center
|
|
21
|
-
// - b-toaster-top-full
|
|
22
|
-
// - b-toaster-bottom-right
|
|
23
|
-
// - b-toaster-bottom-left
|
|
24
|
-
// - b-toaster-bottom-center
|
|
25
|
-
// - b-toaster-bottom-full
|
|
26
|
-
.b-toaster {
|
|
27
|
-
&.b-toaster-top-right,
|
|
28
|
-
&.b-toaster-top-left,
|
|
29
|
-
&.b-toaster-top-center,
|
|
30
|
-
&.b-toaster-top-full,
|
|
31
|
-
&.b-toaster-bottom-right,
|
|
32
|
-
&.b-toaster-bottom-left,
|
|
33
|
-
&.b-toaster-bottom-center,
|
|
34
|
-
&.b-toaster-bottom-full {
|
|
35
|
-
position: fixed;
|
|
36
|
-
left: $b-toaster-offset-left;
|
|
37
|
-
right: $b-toaster-offset-right;
|
|
38
|
-
margin: 0;
|
|
39
|
-
padding: 0;
|
|
40
|
-
height: 0;
|
|
41
|
-
overflow: visible;
|
|
42
|
-
|
|
43
|
-
.b-toaster-slot {
|
|
44
|
-
position: absolute;
|
|
45
|
-
max-width: $toast-max-width;
|
|
46
|
-
width: 100%; /* IE 11 fix */
|
|
47
|
-
left: 0;
|
|
48
|
-
right: 0;
|
|
49
|
-
padding: 0;
|
|
50
|
-
margin: 0;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
&.b-toaster-top-full,
|
|
55
|
-
&.b-toaster-bottom-full {
|
|
56
|
-
.b-toaster-slot {
|
|
57
|
-
width: 100%;
|
|
58
|
-
max-width: 100%;
|
|
59
|
-
|
|
60
|
-
.b-toast,
|
|
61
|
-
.toast {
|
|
62
|
-
// Override Bootstrap toast max-width
|
|
63
|
-
width: 100%;
|
|
64
|
-
max-width: 100%;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
&.b-toaster-top-right,
|
|
70
|
-
&.b-toaster-top-left,
|
|
71
|
-
&.b-toaster-top-center,
|
|
72
|
-
&.b-toaster-top-full {
|
|
73
|
-
top: 0;
|
|
74
|
-
|
|
75
|
-
.b-toaster-slot {
|
|
76
|
-
top: $b-toaster-offset-top;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
&.b-toaster-bottom-right,
|
|
81
|
-
&.b-toaster-bottom-left,
|
|
82
|
-
&.b-toaster-bottom-center,
|
|
83
|
-
&.b-toaster-bottom-full {
|
|
84
|
-
bottom: 0;
|
|
85
|
-
|
|
86
|
-
.b-toaster-slot {
|
|
87
|
-
bottom: $b-toaster-offset-bottom;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
&.b-toaster-top-right,
|
|
92
|
-
&.b-toaster-bottom-right,
|
|
93
|
-
&.b-toaster-top-center,
|
|
94
|
-
&.b-toaster-bottom-center {
|
|
95
|
-
.b-toaster-slot {
|
|
96
|
-
margin-left: auto;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
&.b-toaster-top-left,
|
|
101
|
-
&.b-toaster-bottom-left,
|
|
102
|
-
&.b-toaster-top-center,
|
|
103
|
-
&.b-toaster-bottom-center {
|
|
104
|
-
.b-toaster-slot {
|
|
105
|
-
margin-right: auto;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin for adding `$bvToast` property to all Vue instances
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { NAME_TOAST, NAME_TOASTER, NAME_TOAST_POP } from '../../../constants/components'
|
|
6
|
-
import { EVENT_NAME_DESTROYED, EVENT_NAME_HIDE, EVENT_NAME_SHOW } from '../../../constants/events'
|
|
7
|
-
import { onInstanceDestroy } from '../../../utils/on-instance-destroy'
|
|
8
|
-
import { useParentMixin } from '../../../mixins/use-parent'
|
|
9
|
-
import { concat } from '../../../utils/array'
|
|
10
|
-
import { getComponentConfig } from '../../../utils/config'
|
|
11
|
-
import { requestAF } from '../../../utils/dom'
|
|
12
|
-
import { getRootEventName, getRootActionEventName } from '../../../utils/events'
|
|
13
|
-
import { isUndefined, isFunction } from '../../../utils/inspect'
|
|
14
|
-
import {
|
|
15
|
-
assign,
|
|
16
|
-
defineProperties,
|
|
17
|
-
defineProperty,
|
|
18
|
-
hasOwnProperty,
|
|
19
|
-
keys,
|
|
20
|
-
omit,
|
|
21
|
-
readonlyDescriptor
|
|
22
|
-
} from '../../../utils/object'
|
|
23
|
-
import { pluginFactory } from '../../../utils/plugins'
|
|
24
|
-
import { warn, warnNotClient } from '../../../utils/warn'
|
|
25
|
-
import { createNewChildComponent } from '../../../utils/create-new-child-component'
|
|
26
|
-
import { getEventRoot } from '../../../utils/get-event-root'
|
|
27
|
-
import { isVue3 } from '../../../vue'
|
|
28
|
-
import { BToast, props as toastProps } from '../toast'
|
|
29
|
-
|
|
30
|
-
// --- Constants ---
|
|
31
|
-
|
|
32
|
-
const PROP_NAME = '$bvToast'
|
|
33
|
-
const PROP_NAME_PRIV = '_bv__toast'
|
|
34
|
-
|
|
35
|
-
// Base toast props that are allowed
|
|
36
|
-
// Some may be ignored or overridden on some message boxes
|
|
37
|
-
// Prop ID is allowed, but really only should be used for testing
|
|
38
|
-
// We need to add it in explicitly as it comes from the `idMixin`
|
|
39
|
-
const BASE_PROPS = ['id', ...keys(omit(toastProps, ['static', 'visible']))]
|
|
40
|
-
|
|
41
|
-
// Map prop names to toast slot names
|
|
42
|
-
const propsToSlots = {
|
|
43
|
-
toastContent: 'default',
|
|
44
|
-
title: 'toast-title'
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// --- Helper methods ---
|
|
48
|
-
|
|
49
|
-
// Method to filter only recognized props that are not undefined
|
|
50
|
-
const filterOptions = options => {
|
|
51
|
-
return BASE_PROPS.reduce((memo, key) => {
|
|
52
|
-
if (!isUndefined(options[key])) {
|
|
53
|
-
memo[key] = options[key]
|
|
54
|
-
}
|
|
55
|
-
return memo
|
|
56
|
-
}, {})
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Method to install `$bvToast` VM injection
|
|
60
|
-
const plugin = Vue => {
|
|
61
|
-
// Create a private sub-component constructor that
|
|
62
|
-
// extends BToast and self-destructs after hidden
|
|
63
|
-
// @vue/component
|
|
64
|
-
const BVToastPop = Vue.extend({
|
|
65
|
-
name: NAME_TOAST_POP,
|
|
66
|
-
extends: BToast,
|
|
67
|
-
mixins: [useParentMixin],
|
|
68
|
-
destroyed() {
|
|
69
|
-
// Make sure we not in document any more
|
|
70
|
-
const { $el } = this
|
|
71
|
-
if ($el && $el.parentNode) {
|
|
72
|
-
$el.parentNode.removeChild($el)
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
mounted() {
|
|
76
|
-
// Self destruct handler (stored as instance property for use in onAfterLeave)
|
|
77
|
-
this.$_handleDestroy = () => {
|
|
78
|
-
// Ensure the toast has been force hidden
|
|
79
|
-
this.localShow = false
|
|
80
|
-
this.doRender = false
|
|
81
|
-
this.$nextTick(() => {
|
|
82
|
-
this.$nextTick(() => {
|
|
83
|
-
// In a `requestAF()` to release control back to application
|
|
84
|
-
// and to allow the portal-target time to remove the content
|
|
85
|
-
requestAF(() => {
|
|
86
|
-
this.$destroy()
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
}
|
|
91
|
-
// Self destruct if parent destroyed
|
|
92
|
-
onInstanceDestroy(this.bvParent, this.$_handleDestroy)
|
|
93
|
-
// Self destruct when toaster is destroyed
|
|
94
|
-
this.listenOnRoot(getRootEventName(NAME_TOASTER, EVENT_NAME_DESTROYED), toaster => {
|
|
95
|
-
/* istanbul ignore next: hard to test */
|
|
96
|
-
if (toaster === this.toaster) {
|
|
97
|
-
this.$_handleDestroy()
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
},
|
|
101
|
-
methods: {
|
|
102
|
-
// Override parent's onAfterLeave to self-destruct after hidden
|
|
103
|
-
onAfterLeave() {
|
|
104
|
-
// Call parent's implementation
|
|
105
|
-
BToast.options.methods.onAfterLeave.call(this)
|
|
106
|
-
// Self destruct after hidden
|
|
107
|
-
this.$_handleDestroy()
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Private method to generate the on-demand toast
|
|
113
|
-
const makeToast = (props, parent) => {
|
|
114
|
-
if (warnNotClient(PROP_NAME)) {
|
|
115
|
-
/* istanbul ignore next */
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
// Create an instance of `BVToastPop` component
|
|
119
|
-
const toast = createNewChildComponent(parent, BVToastPop, {
|
|
120
|
-
// We set parent as the local VM so these toasts can emit events on the
|
|
121
|
-
// app `$root`, and it ensures `BToast` is destroyed when parent is destroyed
|
|
122
|
-
propsData: {
|
|
123
|
-
...filterOptions(getComponentConfig(NAME_TOAST)),
|
|
124
|
-
// Add in (filtered) user supplied props
|
|
125
|
-
...omit(props, keys(propsToSlots)),
|
|
126
|
-
// Props that can't be overridden
|
|
127
|
-
static: false,
|
|
128
|
-
visible: true
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
// Convert certain props to slots
|
|
132
|
-
keys(propsToSlots).forEach(prop => {
|
|
133
|
-
let value = props[prop]
|
|
134
|
-
if (!isUndefined(value)) {
|
|
135
|
-
if (isVue3(toast)) {
|
|
136
|
-
// In Vue 3 compat, $slots is readonly. Set slots on the internal
|
|
137
|
-
// instance as functions so VNodes are available during the
|
|
138
|
-
// component's render cycle. When the value is a render function,
|
|
139
|
-
// defer calling it until the slot is evaluated during render so
|
|
140
|
-
// that $createElement runs within an active component context.
|
|
141
|
-
const slotFn = isFunction(value)
|
|
142
|
-
? () => concat(value(toast.$createElement))
|
|
143
|
-
: () => concat(value)
|
|
144
|
-
toast.$.slots[propsToSlots[prop]] = slotFn
|
|
145
|
-
} else {
|
|
146
|
-
if (isFunction(value)) {
|
|
147
|
-
value = value(toast.$createElement)
|
|
148
|
-
}
|
|
149
|
-
toast.$slots[propsToSlots[prop]] = concat(value)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
// Create a mount point (a DIV) and mount it (which triggers the show)
|
|
154
|
-
function createMountPoint() {
|
|
155
|
-
const div = document.createElement('div')
|
|
156
|
-
document.body.appendChild(div)
|
|
157
|
-
toast.$mount(div)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// ViewTransition fallback
|
|
161
|
-
if (!document.startViewTransition) {
|
|
162
|
-
createMountPoint()
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
document.startViewTransition(createMountPoint)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Declare BvToast instance property class
|
|
170
|
-
class BvToast {
|
|
171
|
-
constructor(vm) {
|
|
172
|
-
// Assign the new properties to this instance
|
|
173
|
-
assign(this, { _vm: vm, _root: getEventRoot(vm) })
|
|
174
|
-
// Set these properties as read-only and non-enumerable
|
|
175
|
-
defineProperties(this, {
|
|
176
|
-
_vm: readonlyDescriptor(),
|
|
177
|
-
_root: readonlyDescriptor()
|
|
178
|
-
})
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// --- Public Instance methods ---
|
|
182
|
-
|
|
183
|
-
// Opens a user defined toast and returns immediately
|
|
184
|
-
toast(content, options = {}) {
|
|
185
|
-
if (!content || warnNotClient(PROP_NAME)) {
|
|
186
|
-
/* istanbul ignore next */
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
makeToast({ ...filterOptions(options), toastContent: content }, this._vm)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// shows a `<b-toast>` component with the specified ID
|
|
193
|
-
show(id) {
|
|
194
|
-
if (id) {
|
|
195
|
-
this._root.$emit(getRootActionEventName(NAME_TOAST, EVENT_NAME_SHOW), id)
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Hide a toast with specified ID, or if not ID all toasts
|
|
200
|
-
hide(id = 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
|
-
|
|
229
|
-
export const BVToastPlugin = /*#__PURE__*/ pluginFactory({
|
|
230
|
-
plugins: { plugin }
|
|
231
|
-
})
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { BVToastPlugin } from './helpers/bv-toast'
|
|
2
|
-
import { BToast } from './toast'
|
|
3
|
-
import { BToaster } from './toaster'
|
|
4
|
-
import { pluginFactory } from '../../utils/plugins'
|
|
5
|
-
|
|
6
|
-
const ToastPlugin = /*#__PURE__*/ pluginFactory({
|
|
7
|
-
components: { BToast, BToaster },
|
|
8
|
-
// $bvToast injection
|
|
9
|
-
plugins: { BVToastPlugin }
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
export { ToastPlugin, BToast, BToaster }
|