@gitlab/ui 33.0.1 → 34.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/CHANGELOG.md +38 -0
- package/dist/components/base/accordion/accordion.js +6 -2
- package/dist/components/base/accordion/accordion_item.js +2 -2
- package/dist/components/base/avatars_inline/avatars_inline.documentation.js +1 -1
- package/dist/components/base/avatars_inline/avatars_inline.js +5 -1
- package/dist/components/base/popover/popover.js +25 -2
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/package.json +12 -10
- package/src/components/base/accordion/accordion.vue +5 -2
- package/src/components/base/accordion/accordion_item.spec.js +2 -2
- package/src/components/base/accordion/accordion_item.stories.js +2 -2
- package/src/components/base/accordion/accordion_item.vue +2 -2
- package/src/components/base/avatars_inline/avatars_inline.md +5 -0
- package/src/components/base/avatars_inline/avatars_inline.spec.js +21 -1
- package/src/components/base/avatars_inline/avatars_inline.stories.js +23 -9
- package/src/components/base/avatars_inline/avatars_inline.vue +11 -1
- package/src/components/base/popover/popover.scss +0 -5
- package/src/components/base/popover/popover.spec.js +42 -1
- package/src/components/base/popover/popover.stories.js +18 -0
- package/src/components/base/popover/popover.vue +32 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "34.0.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"test:unit:watch": "yarn test:unit --watch --notify",
|
|
42
42
|
"test:unit:debug": "NODE_ENV=test node --inspect node_modules/.bin/jest --testPathIgnorePatterns storyshot.spec.js --watch --runInBand",
|
|
43
43
|
"test:visual": "NODE_ENV=test IS_VISUAL_TEST=true start-test http-get://localhost:9001 'jest ./tests/storyshots.spec.js'",
|
|
44
|
+
"test:visual:minimal": "node ./bin/run_minimal_visual_tests.js",
|
|
44
45
|
"test:visual:update": "NODE_ENV=test IS_VISUAL_TEST=true JEST_IMAGE_SNAPSHOT_TRACK_OBSOLETE=1 start-test http-get://localhost:9001 'jest ./tests/storyshots.spec.js --updateSnapshot'",
|
|
45
46
|
"prettier": "prettier --check '**/*.{js,vue}'",
|
|
46
47
|
"prettier:fix": "prettier --write '**/*.{js,vue}'",
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"@babel/standalone": "^7.0.0",
|
|
61
62
|
"bootstrap-vue": "2.20.1",
|
|
62
63
|
"copy-to-clipboard": "^3.0.8",
|
|
63
|
-
"dompurify": "^2.3.
|
|
64
|
+
"dompurify": "^2.3.5",
|
|
64
65
|
"echarts": "^5.2.1",
|
|
65
66
|
"highlight.js": "^10.6.0",
|
|
66
67
|
"iframe-resizer": "^4.3.2",
|
|
@@ -90,15 +91,15 @@
|
|
|
90
91
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
91
92
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
92
93
|
"@rollup/plugin-replace": "^2.3.2",
|
|
93
|
-
"@storybook/addon-a11y": "6.4.
|
|
94
|
-
"@storybook/addon-docs": "6.4.
|
|
95
|
-
"@storybook/addon-essentials": "6.4.
|
|
94
|
+
"@storybook/addon-a11y": "6.4.15",
|
|
95
|
+
"@storybook/addon-docs": "6.4.15",
|
|
96
|
+
"@storybook/addon-essentials": "6.4.15",
|
|
96
97
|
"@storybook/addon-knobs": "6.4.0",
|
|
97
|
-
"@storybook/addon-storyshots": "6.4.
|
|
98
|
-
"@storybook/addon-storyshots-puppeteer": "6.4.
|
|
99
|
-
"@storybook/addon-viewport": "6.4.
|
|
100
|
-
"@storybook/theming": "6.4.
|
|
101
|
-
"@storybook/vue": "6.4.
|
|
98
|
+
"@storybook/addon-storyshots": "6.4.15",
|
|
99
|
+
"@storybook/addon-storyshots-puppeteer": "6.4.15",
|
|
100
|
+
"@storybook/addon-viewport": "6.4.15",
|
|
101
|
+
"@storybook/theming": "6.4.15",
|
|
102
|
+
"@storybook/vue": "6.4.15",
|
|
102
103
|
"@vue/test-utils": "1.3.0",
|
|
103
104
|
"autoprefixer": "^9.7.6",
|
|
104
105
|
"babel-jest": "^26.6.3",
|
|
@@ -113,6 +114,7 @@
|
|
|
113
114
|
"eslint-import-resolver-jest": "3.0.2",
|
|
114
115
|
"eslint-plugin-cypress": "2.12.1",
|
|
115
116
|
"file-loader": "^4.2.0",
|
|
117
|
+
"glob": "^7.2.0",
|
|
116
118
|
"identity-obj-proxy": "^3.0.0",
|
|
117
119
|
"inquirer-select-directory": "^1.2.0",
|
|
118
120
|
"jest": "^26.6.3",
|
|
@@ -4,9 +4,12 @@ import { uniqueId } from 'lodash';
|
|
|
4
4
|
export default {
|
|
5
5
|
name: 'GlAccordion',
|
|
6
6
|
provide() {
|
|
7
|
+
const accordionId = uniqueId('accordion-set-');
|
|
8
|
+
// temporary fix for this issue: https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2019#note_514671251
|
|
9
|
+
// MR for the upstream pending: https://github.com/vuejs/apollo/pull/1153
|
|
7
10
|
return {
|
|
8
|
-
defaultHeaderLevel: this.headerLevel,
|
|
9
|
-
accordionSetId: this.autoCollapse &&
|
|
11
|
+
defaultHeaderLevel: () => this.headerLevel,
|
|
12
|
+
accordionSetId: () => this.autoCollapse && accordionId,
|
|
10
13
|
};
|
|
11
14
|
},
|
|
12
15
|
props: {
|
|
@@ -16,8 +16,8 @@ describe('GlAccordionItem', () => {
|
|
|
16
16
|
GlCollapseToggle: GlCollapseToggleDirective,
|
|
17
17
|
},
|
|
18
18
|
provide: {
|
|
19
|
-
defaultHeaderLevel,
|
|
20
|
-
accordionSetId,
|
|
19
|
+
defaultHeaderLevel: () => defaultHeaderLevel,
|
|
20
|
+
accordionSetId: () => accordionSetId,
|
|
21
21
|
},
|
|
22
22
|
propsData: {
|
|
23
23
|
title: defaultTitle,
|
|
@@ -26,8 +26,8 @@ const Template = (args) => ({
|
|
|
26
26
|
props: Object.keys(args),
|
|
27
27
|
template,
|
|
28
28
|
provide: {
|
|
29
|
-
defaultHeaderLevel: defaultValue('headerLevel'),
|
|
30
|
-
accordionSetId: '1',
|
|
29
|
+
defaultHeaderLevel: () => defaultValue('headerLevel'),
|
|
30
|
+
accordionSetId: () => '1',
|
|
31
31
|
},
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -51,11 +51,11 @@ When set, it will ensure the accordion item is initially visible
|
|
|
51
51
|
},
|
|
52
52
|
computed: {
|
|
53
53
|
headerComponent() {
|
|
54
|
-
const level = this.headerLevel || this.defaultHeaderLevel;
|
|
54
|
+
const level = this.headerLevel || this.defaultHeaderLevel();
|
|
55
55
|
return `h${level}`;
|
|
56
56
|
},
|
|
57
57
|
accordion() {
|
|
58
|
-
return this.accordionSetId || undefined;
|
|
58
|
+
return this.accordionSetId() || undefined;
|
|
59
59
|
},
|
|
60
60
|
icon() {
|
|
61
61
|
return this.isVisible ? 'chevron-down' : 'chevron-right';
|
|
@@ -28,6 +28,11 @@ When the `collapse` property value is `true` and the `maxVisible` property value
|
|
|
28
28
|
than the length of the `avatars` property array, `<avatars-inline>` will hide the overflown avatars
|
|
29
29
|
and display a badge instead.
|
|
30
30
|
|
|
31
|
+
### Badge description in screen readers
|
|
32
|
+
|
|
33
|
+
The `badgeSrOnlyText` property provides a meaningful description of the badge that appears
|
|
34
|
+
when avatars are collapsed for screen reader users.
|
|
35
|
+
|
|
31
36
|
### Supported sizes
|
|
32
37
|
|
|
33
38
|
`<avatars-inline>` only supports avatars with `24` or `32` size.
|
|
@@ -11,10 +11,14 @@ describe('avatars inline', () => {
|
|
|
11
11
|
{ src: 'avatar 2', tooltip: 'Avatar 2' },
|
|
12
12
|
{ src: 'avatar 3', tooltip: 'Avatar 3' },
|
|
13
13
|
];
|
|
14
|
+
const badgeSrOnlyText = 'additional users';
|
|
14
15
|
|
|
15
16
|
const buildWrapper = (propsData = {}) => {
|
|
16
17
|
wrapper = shallowMount(AvatarsInline, {
|
|
17
|
-
propsData
|
|
18
|
+
propsData: {
|
|
19
|
+
badgeSrOnlyText,
|
|
20
|
+
...propsData,
|
|
21
|
+
},
|
|
18
22
|
stubs: {
|
|
19
23
|
GlTooltip,
|
|
20
24
|
},
|
|
@@ -107,4 +111,20 @@ describe('avatars inline', () => {
|
|
|
107
111
|
});
|
|
108
112
|
});
|
|
109
113
|
});
|
|
114
|
+
|
|
115
|
+
describe('a11y', () => {
|
|
116
|
+
it('renders screen reader only text for the collapse badge', () => {
|
|
117
|
+
buildWrapper({ avatars, maxVisible: 1, collapsed: true, avatarSize: 32 });
|
|
118
|
+
|
|
119
|
+
expect(wrapper.find('[data-testid="badge-sr-only-text"]').text()).toBe(badgeSrOnlyText);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('hides badge text for screen readers', () => {
|
|
123
|
+
buildWrapper({ avatars, maxVisible: 1, collapsed: true, avatarSize: 32 });
|
|
124
|
+
|
|
125
|
+
expect(
|
|
126
|
+
wrapper.find('[data-testid="collapsed-avatars-badge"]').attributes('aria-hidden')
|
|
127
|
+
).toBe('true');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
110
130
|
});
|
|
@@ -1,37 +1,49 @@
|
|
|
1
|
+
import { GlAvatarsInline, GlAvatar, GlAvatarLink, GlTooltipDirective } from '../../../../index';
|
|
1
2
|
import { avatarsInlineSizeOptions } from '../../../utils/constants';
|
|
2
3
|
import readme from './avatars_inline.md';
|
|
3
4
|
|
|
4
5
|
const defaultAvatars = [
|
|
5
|
-
{ src: 'https://picsum.photos/id/1005/32' },
|
|
6
|
-
{ src: 'https://picsum.photos/id/1006/32' },
|
|
7
|
-
{ src: 'https://picsum.photos/id/1009/32' },
|
|
8
|
-
{ src: 'https://picsum.photos/id/1011/32' },
|
|
9
|
-
{ src: 'https://picsum.photos/id/1012/32' },
|
|
6
|
+
{ src: 'https://picsum.photos/id/1005/32', alt: 'Administrator’s user avatar' },
|
|
7
|
+
{ src: 'https://picsum.photos/id/1006/32', alt: 'Ops Manager’s user avatar' },
|
|
8
|
+
{ src: 'https://picsum.photos/id/1009/32', alt: 'Developer’s user avatar' },
|
|
9
|
+
{ src: 'https://picsum.photos/id/1011/32', alt: 'Business Admin’s user avatar' },
|
|
10
|
+
{ src: 'https://picsum.photos/id/1012/32', alt: 'Product designer’s user avatar' },
|
|
10
11
|
];
|
|
11
12
|
|
|
12
13
|
const generateProps = (
|
|
13
14
|
avatars = defaultAvatars,
|
|
14
|
-
{
|
|
15
|
+
{
|
|
16
|
+
maxVisible = 2,
|
|
17
|
+
collapsed = true,
|
|
18
|
+
avatarSize = 24,
|
|
19
|
+
badgeTooltipProp = '',
|
|
20
|
+
badgeSrOnlyText = `${avatars.length - maxVisible} additional users`,
|
|
21
|
+
} = {}
|
|
15
22
|
) => ({
|
|
16
23
|
maxVisible,
|
|
17
24
|
collapsed,
|
|
18
25
|
avatarSize,
|
|
19
26
|
avatars,
|
|
27
|
+
badgeTooltipProp,
|
|
28
|
+
badgeSrOnlyText,
|
|
20
29
|
});
|
|
21
30
|
|
|
22
31
|
export const Default = (args, { argTypes }) => ({
|
|
32
|
+
components: { GlAvatarsInline },
|
|
23
33
|
props: Object.keys(argTypes),
|
|
24
34
|
template: `
|
|
25
|
-
<gl-avatars-inline :avatars="avatars" :collapsed="collapsed" :avatar-size="avatarSize" :max-visible="maxVisible">
|
|
35
|
+
<gl-avatars-inline :avatars="avatars" :collapsed="collapsed" :avatar-size="avatarSize" :max-visible="maxVisible" :badgeTooltipProp="badgeTooltipProp" :badgeSrOnlyText="badgeSrOnlyText">
|
|
26
36
|
</gl-avatars-inline>
|
|
27
37
|
`,
|
|
28
38
|
});
|
|
29
39
|
Default.args = generateProps();
|
|
30
40
|
|
|
31
41
|
export const WithLinksAndTooltips = (args, { argTypes }) => ({
|
|
42
|
+
components: { GlAvatarsInline, GlAvatar, GlAvatarLink },
|
|
43
|
+
directives: { GlTooltip: GlTooltipDirective },
|
|
32
44
|
props: Object.keys(argTypes),
|
|
33
45
|
template: `
|
|
34
|
-
<gl-avatars-inline :avatars="avatars" :collapsed="collapsed" :avatar-size="avatarSize" :max-visible="maxVisible">
|
|
46
|
+
<gl-avatars-inline :avatars="avatars" :collapsed="collapsed" :avatar-size="avatarSize" :max-visible="maxVisible" :badgeTooltipProp="badgeTooltipProp" :badgeSrOnlyText="badgeSrOnlyText">
|
|
35
47
|
<template #avatar="{ avatar }">
|
|
36
48
|
<gl-avatar-link target="blank" :href="avatar.href" v-gl-tooltip :title="avatar.tooltip">
|
|
37
49
|
<gl-avatar :src="avatar.src" :size="avatarSize" />
|
|
@@ -45,11 +57,13 @@ WithLinksAndTooltips.args = generateProps(
|
|
|
45
57
|
...avatar,
|
|
46
58
|
href: '//gitlab.com',
|
|
47
59
|
tooltip: `Avatar ${index}`,
|
|
48
|
-
}))
|
|
60
|
+
})),
|
|
61
|
+
{ badgeTooltipProp: 'tooltip' }
|
|
49
62
|
);
|
|
50
63
|
|
|
51
64
|
export default {
|
|
52
65
|
title: 'base/avatar/avatars-inline',
|
|
66
|
+
component: GlAvatarsInline,
|
|
53
67
|
parameters: {
|
|
54
68
|
knobs: { disable: true },
|
|
55
69
|
docs: {
|
|
@@ -29,6 +29,10 @@ export default {
|
|
|
29
29
|
required: false,
|
|
30
30
|
default: false,
|
|
31
31
|
},
|
|
32
|
+
badgeSrOnlyText: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
32
36
|
badgeTooltipProp: {
|
|
33
37
|
type: String,
|
|
34
38
|
required: false,
|
|
@@ -111,9 +115,15 @@ export default {
|
|
|
111
115
|
<gl-tooltip v-if="badgeTooltipProp" :target="() => $refs.badge">
|
|
112
116
|
{{ badgeTooltipTitle }}
|
|
113
117
|
</gl-tooltip>
|
|
114
|
-
<span
|
|
118
|
+
<span
|
|
119
|
+
ref="badge"
|
|
120
|
+
data-testid="collapsed-avatars-badge"
|
|
121
|
+
:class="['gl-avatars-inline-badge', badgeSize]"
|
|
122
|
+
aria-hidden="true"
|
|
123
|
+
>
|
|
115
124
|
{{ badgeLabel }}
|
|
116
125
|
</span>
|
|
126
|
+
<span data-testid="badge-sr-only-text" class="sr-only">{{ badgeSrOnlyText }}</span>
|
|
117
127
|
</div>
|
|
118
128
|
</div>
|
|
119
129
|
</template>
|
|
@@ -5,16 +5,18 @@ import GlPopover from './popover.vue';
|
|
|
5
5
|
describe('GlPopover', () => {
|
|
6
6
|
let wrapper;
|
|
7
7
|
|
|
8
|
-
const createWrapper = (props) => {
|
|
8
|
+
const createWrapper = (props, stubs = {}) => {
|
|
9
9
|
wrapper = shallowMount(GlPopover, {
|
|
10
10
|
propsData: {
|
|
11
11
|
target: document.body,
|
|
12
12
|
...props,
|
|
13
13
|
},
|
|
14
|
+
stubs,
|
|
14
15
|
});
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
const findBVPopover = () => wrapper.findComponent({ ref: 'bPopover' });
|
|
19
|
+
const findCloseButton = () => findBVPopover().find('[data-testid="close-button"]');
|
|
18
20
|
|
|
19
21
|
it.each(tooltipActionEvents)('passes through the %s event to the bvPopover instance', (event) => {
|
|
20
22
|
createWrapper();
|
|
@@ -46,4 +48,43 @@ describe('GlPopover', () => {
|
|
|
46
48
|
expect(findBVPopover().props('title')).toBe(title);
|
|
47
49
|
});
|
|
48
50
|
});
|
|
51
|
+
|
|
52
|
+
describe('close button', () => {
|
|
53
|
+
let doCloseMock;
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
doCloseMock = jest.fn();
|
|
57
|
+
createWrapper(
|
|
58
|
+
{ showCloseButton: true },
|
|
59
|
+
{
|
|
60
|
+
BPopover: {
|
|
61
|
+
template: `
|
|
62
|
+
<div>
|
|
63
|
+
<slot name="title" />
|
|
64
|
+
</div>
|
|
65
|
+
`,
|
|
66
|
+
methods: {
|
|
67
|
+
doClose: doCloseMock,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('renders a close button', () => {
|
|
75
|
+
expect(findCloseButton().exists()).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("calls BPopover's doClose method when clicking on the close button", () => {
|
|
79
|
+
findCloseButton().vm.$emit('click');
|
|
80
|
+
|
|
81
|
+
expect(doCloseMock).toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('emits close-button-clicked event when clicking on the close button', () => {
|
|
85
|
+
findCloseButton().vm.$emit('click');
|
|
86
|
+
|
|
87
|
+
expect(wrapper.emitted('close-button-clicked')).toHaveLength(1);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
49
90
|
});
|
|
@@ -60,6 +60,24 @@ documentedStoriesOf('base/popover', '')
|
|
|
60
60
|
template,
|
|
61
61
|
props: generateProps(),
|
|
62
62
|
}))
|
|
63
|
+
.add('with close button', () => ({
|
|
64
|
+
template: `
|
|
65
|
+
<div class="gl-display-flex gl-justify-content-center gl-p-6">
|
|
66
|
+
<gl-button id="pop-with-close-button">{{placement}}</gl-button>
|
|
67
|
+
<gl-popover
|
|
68
|
+
target="pop-with-close-button"
|
|
69
|
+
data-testid="popover-with-close-button"
|
|
70
|
+
triggers="hover focus"
|
|
71
|
+
:title="title"
|
|
72
|
+
:placement="placement"
|
|
73
|
+
content="${contentString}"
|
|
74
|
+
show
|
|
75
|
+
show-close-button
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
78
|
+
`,
|
|
79
|
+
props: generateProps(),
|
|
80
|
+
}))
|
|
63
81
|
.add(
|
|
64
82
|
'on click',
|
|
65
83
|
() => ({
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { BPopover } from 'bootstrap-vue';
|
|
3
3
|
import tooltipMixin from '../../mixins/tooltip_mixin';
|
|
4
|
+
import CloseButton from '../../shared_components/close_button/close_button.vue';
|
|
4
5
|
|
|
5
6
|
const popoverRefName = 'bPopover';
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
9
|
components: {
|
|
9
10
|
BPopover,
|
|
11
|
+
CloseButton,
|
|
10
12
|
},
|
|
11
13
|
mixins: [tooltipMixin(popoverRefName)],
|
|
12
14
|
inheritAttrs: false,
|
|
@@ -21,11 +23,30 @@ export default {
|
|
|
21
23
|
required: false,
|
|
22
24
|
default: 'hover focus',
|
|
23
25
|
},
|
|
26
|
+
title: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: false,
|
|
29
|
+
default: '',
|
|
30
|
+
},
|
|
31
|
+
showCloseButton: {
|
|
32
|
+
type: Boolean,
|
|
33
|
+
required: false,
|
|
34
|
+
default: false,
|
|
35
|
+
},
|
|
24
36
|
},
|
|
25
37
|
computed: {
|
|
26
38
|
customClass() {
|
|
27
39
|
return ['gl-popover', ...this.cssClasses].join(' ');
|
|
28
40
|
},
|
|
41
|
+
shouldShowTitle() {
|
|
42
|
+
return this.$scopedSlots.title || this.title || this.showCloseButton;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
methods: {
|
|
46
|
+
close(e) {
|
|
47
|
+
this.$refs[popoverRefName].doClose();
|
|
48
|
+
this.$emit('close-button-clicked', e);
|
|
49
|
+
},
|
|
29
50
|
},
|
|
30
51
|
popoverRefName,
|
|
31
52
|
};
|
|
@@ -36,11 +57,20 @@ export default {
|
|
|
36
57
|
:ref="$options.popoverRefName"
|
|
37
58
|
:custom-class="customClass"
|
|
38
59
|
:triggers="triggers"
|
|
60
|
+
:title="title"
|
|
39
61
|
v-bind="$attrs"
|
|
40
62
|
v-on="$listeners"
|
|
41
63
|
>
|
|
42
|
-
<template v-if="
|
|
43
|
-
<slot name="title"
|
|
64
|
+
<template v-if="shouldShowTitle" #title>
|
|
65
|
+
<slot name="title">
|
|
66
|
+
{{ title }}
|
|
67
|
+
</slot>
|
|
68
|
+
<close-button
|
|
69
|
+
v-if="showCloseButton"
|
|
70
|
+
class="gl-float-right gl-mt-n2 gl-mr-n3"
|
|
71
|
+
data-testid="close-button"
|
|
72
|
+
@click="close"
|
|
73
|
+
/>
|
|
44
74
|
</template>
|
|
45
75
|
<slot></slot>
|
|
46
76
|
</b-popover>
|