@gitlab/ui 32.67.0 → 33.1.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 +42 -0
- package/dist/components/base/datepicker/datepicker.js +4 -1
- package/dist/components/base/dropdown/dropdown.js +4 -4
- package/dist/components/base/filtered_search/filtered_search.js +5 -2
- package/dist/components/base/filtered_search/filtered_search_token.js +12 -8
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +6 -5
- package/dist/components/base/form/form_checkbox_tree/models/node.js +9 -8
- package/dist/components/base/form/form_checkbox_tree/models/tree.js +21 -10
- package/dist/components/base/form/form_input/form_input.js +14 -4
- package/dist/components/base/form/form_textarea/form_textarea.js +14 -4
- package/dist/components/base/infinite_scroll/infinite_scroll.documentation.js +2 -33
- package/dist/components/base/infinite_scroll/infinite_scroll.js +21 -3
- package/dist/components/base/pagination/pagination.js +2 -1
- package/dist/components/base/path/path.js +6 -5
- package/dist/components/base/popover/popover.js +25 -2
- package/dist/components/base/segmented_control/segmented_control.js +9 -4
- package/dist/components/base/skeleton_loader/skeleton_loader.js +6 -4
- package/dist/components/base/sorting/sorting_item.js +6 -5
- package/dist/components/base/table/table.js +5 -4
- package/dist/components/base/tabs/tabs/scrollable_tabs.js +6 -5
- package/dist/components/base/toast/toast.js +2 -1
- package/dist/components/base/token_selector/token_container.js +2 -1
- package/dist/components/base/token_selector/token_selector.js +2 -1
- package/dist/components/charts/bar/bar.js +2 -1
- package/dist/components/charts/column/column.documentation.js +1 -7
- package/dist/components/charts/column/column.js +17 -14
- package/dist/components/charts/gauge/gauge.js +45 -42
- package/dist/components/charts/sparkline/sparkline.js +6 -4
- package/dist/components/charts/stacked_column/stacked_column.js +17 -14
- package/dist/components/utilities/friendly_wrap/friendly_wrap.js +4 -3
- package/dist/components/utilities/sprintf/sprintf.js +4 -2
- package/dist/directives/hover_load/hover_load.js +5 -3
- package/dist/directives/outside/outside.js +12 -8
- package/dist/directives/resize_observer/examples/resize_observer.basic.example.js +7 -6
- package/dist/directives/resize_observer/resize_observer.js +12 -8
- package/dist/directives/safe_link/safe_link.js +12 -6
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/dist/utils/charts/config.js +95 -72
- package/dist/utils/charts/story_config.js +4 -2
- package/dist/utils/charts/theme.js +106 -103
- package/dist/utils/charts/utils.js +14 -6
- package/dist/utils/number_utils.js +14 -5
- package/dist/utils/use_mock_intersection_observer.js +31 -11
- package/dist/utils/utils.js +15 -4
- package/dist/utils/validation_utils.js +3 -1
- package/documentation/documented_stories.js +2 -0
- package/package.json +14 -13
- package/scss_to_js/scss_variables.js +1 -0
- package/scss_to_js/scss_variables.json +5 -0
- package/src/components/base/infinite_scroll/infinite_scroll.documentation.js +0 -38
- package/src/components/base/infinite_scroll/infinite_scroll.md +0 -4
- package/src/components/base/infinite_scroll/infinite_scroll.stories.js +49 -24
- package/src/components/base/infinite_scroll/infinite_scroll.vue +18 -0
- 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/src/components/base/search_box_by_click/search_box_by_click.scss +4 -0
- package/src/components/base/search_box_by_type/search_box_by_type.scss +4 -0
- package/src/components/charts/column/column.documentation.js +0 -5
- package/src/components/charts/column/column.stories.js +61 -88
- package/src/scss/utilities.scss +20 -26
- package/src/scss/utility-mixins/flex.scss +1 -8
- package/src/scss/utility-mixins/sizing.scss +8 -0
- package/src/scss/utility-mixins/spacing.scss +1 -7
- package/src/scss/variables.scss +1 -0
- package/dist/components/charts/column/examples/column.basic.example.js +0 -49
- package/dist/components/charts/column/examples/index.js +0 -13
- package/src/components/charts/column/column.md +0 -1
- package/src/components/charts/column/examples/column.basic.example.vue +0 -22
- package/src/components/charts/column/examples/index.js +0 -15
package/dist/utils/utils.js
CHANGED
|
@@ -2,7 +2,11 @@ import { COMMA, labelColorOptions, focusableTags } from './constants';
|
|
|
2
2
|
|
|
3
3
|
function debounceByAnimationFrame(fn) {
|
|
4
4
|
let requestId;
|
|
5
|
-
return function debounced(
|
|
5
|
+
return function debounced() {
|
|
6
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
7
|
+
args[_key] = arguments[_key];
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
if (requestId) {
|
|
7
11
|
window.cancelAnimationFrame(requestId);
|
|
8
12
|
}
|
|
@@ -12,7 +16,11 @@ function debounceByAnimationFrame(fn) {
|
|
|
12
16
|
}
|
|
13
17
|
function throttle(fn) {
|
|
14
18
|
let frameId = null;
|
|
15
|
-
return (
|
|
19
|
+
return function () {
|
|
20
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
21
|
+
args[_key2] = arguments[_key2];
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
if (frameId) {
|
|
17
25
|
return;
|
|
18
26
|
}
|
|
@@ -34,7 +42,8 @@ function rgbFromString(color, sub) {
|
|
|
34
42
|
const [r, g, b] = rgb.map(i => parseInt(i, 10));
|
|
35
43
|
return [r, g, b];
|
|
36
44
|
}
|
|
37
|
-
function hexToRgba(hex
|
|
45
|
+
function hexToRgba(hex) {
|
|
46
|
+
let opacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
38
47
|
const [r, g, b] = rgbFromHex(hex);
|
|
39
48
|
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
40
49
|
}
|
|
@@ -103,7 +112,9 @@ function isDev() {
|
|
|
103
112
|
* @param {string} message message to print to the console
|
|
104
113
|
*/
|
|
105
114
|
|
|
106
|
-
function logWarning(
|
|
115
|
+
function logWarning() {
|
|
116
|
+
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
117
|
+
|
|
107
118
|
if (message.length && isDev()) {
|
|
108
119
|
console.warn(message); // eslint-disable-line no-console
|
|
109
120
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Creates out of validation configurations from .documentation.js files and creates a readable string out of it
|
|
2
|
-
const getValidationInfoText = (
|
|
2
|
+
const getValidationInfoText = function () {
|
|
3
|
+
let validation = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
4
|
+
|
|
3
5
|
switch (validation.type) {
|
|
4
6
|
case 'range':
|
|
5
7
|
return `${validation.min}-${validation.max}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "33.1.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -41,7 +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:update": "NODE_ENV=test IS_VISUAL_TEST=true start-test http-get://localhost:9001 'jest ./tests/storyshots.spec.js --updateSnapshot'",
|
|
44
|
+
"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
45
|
"prettier": "prettier --check '**/*.{js,vue}'",
|
|
46
46
|
"prettier:fix": "prettier --write '**/*.{js,vue}'",
|
|
47
47
|
"eslint": "eslint --max-warnings 0 --ext .js,.vue .",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@gitlab/svgs": "^1.116.0 || ^2.0.0",
|
|
75
|
-
"emoji-regex": ">=10.0.0",
|
|
76
75
|
"bootstrap": "4.5.3",
|
|
76
|
+
"emoji-regex": ">=10.0.0",
|
|
77
77
|
"pikaday": "^1.8.0",
|
|
78
78
|
"vue": "^2.6.10"
|
|
79
79
|
},
|
|
@@ -85,20 +85,20 @@
|
|
|
85
85
|
"@babel/core": "^7.10.2",
|
|
86
86
|
"@babel/preset-env": "^7.10.2",
|
|
87
87
|
"@gitlab/eslint-plugin": "10.0.1",
|
|
88
|
-
"@gitlab/stylelint-config": "
|
|
88
|
+
"@gitlab/stylelint-config": "3.0.0",
|
|
89
89
|
"@gitlab/svgs": "2.2.0",
|
|
90
90
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
91
91
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
92
92
|
"@rollup/plugin-replace": "^2.3.2",
|
|
93
|
-
"@storybook/addon-a11y": "6.4.
|
|
94
|
-
"@storybook/addon-docs": "6.4.
|
|
95
|
-
"@storybook/addon-essentials": "6.4.
|
|
93
|
+
"@storybook/addon-a11y": "6.4.14",
|
|
94
|
+
"@storybook/addon-docs": "6.4.14",
|
|
95
|
+
"@storybook/addon-essentials": "6.4.14",
|
|
96
96
|
"@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.
|
|
97
|
+
"@storybook/addon-storyshots": "6.4.14",
|
|
98
|
+
"@storybook/addon-storyshots-puppeteer": "6.4.14",
|
|
99
|
+
"@storybook/addon-viewport": "6.4.14",
|
|
100
|
+
"@storybook/theming": "6.4.14",
|
|
101
|
+
"@storybook/vue": "6.4.14",
|
|
102
102
|
"@vue/test-utils": "1.3.0",
|
|
103
103
|
"autoprefixer": "^9.7.6",
|
|
104
104
|
"babel-jest": "^26.6.3",
|
|
@@ -145,8 +145,9 @@
|
|
|
145
145
|
"sass-true": "^5.0.0",
|
|
146
146
|
"start-server-and-test": "^1.10.6",
|
|
147
147
|
"storybook-readme": "5.0.9",
|
|
148
|
+
"stylelint": "13.9.0",
|
|
148
149
|
"stylelint-config-prettier": "9.0.3",
|
|
149
|
-
"stylelint-prettier": "
|
|
150
|
+
"stylelint-prettier": "2.0.0",
|
|
150
151
|
"vue": "^2.6.11",
|
|
151
152
|
"vue-jest": "4.0.0-rc.0",
|
|
152
153
|
"vue-loader": "^15.8.3",
|
|
@@ -16,6 +16,7 @@ export const glSpacingScale13 = '6rem'
|
|
|
16
16
|
export const glSpacingScale15 = '7.5rem'
|
|
17
17
|
export const glSpacingScale20 = '10rem'
|
|
18
18
|
export const glSpacingScale26 = '13rem'
|
|
19
|
+
export const glSpacingScale28 = '14rem'
|
|
19
20
|
export const glSpacingScale62 = '31rem'
|
|
20
21
|
export const breakpointSm = '576px'
|
|
21
22
|
export const breakpointMd = '768px'
|
|
@@ -1,44 +1,6 @@
|
|
|
1
|
-
import examples from './examples';
|
|
2
1
|
import description from './infinite_scroll.md';
|
|
3
2
|
|
|
4
3
|
export default {
|
|
5
4
|
followsDesignSystem: true,
|
|
6
5
|
description,
|
|
7
|
-
examples,
|
|
8
|
-
propsInfo: {
|
|
9
|
-
totalItems: {
|
|
10
|
-
additionalInfo: 'Total number of items available',
|
|
11
|
-
},
|
|
12
|
-
fetchedItems: {
|
|
13
|
-
additionalInfo: 'Numbers of items fetched before scrolling',
|
|
14
|
-
},
|
|
15
|
-
maxListHeight: {
|
|
16
|
-
additionalInfo: 'Max height of the list before the scrollbar appears',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
events: [
|
|
20
|
-
{
|
|
21
|
-
event: '@topReached',
|
|
22
|
-
description: 'Emitted when item container is scrolled to the top',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
event: '@bottomReached',
|
|
26
|
-
description: 'Emitted when item container is scrolled to the bottom',
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
slots: [
|
|
30
|
-
{
|
|
31
|
-
name: 'default',
|
|
32
|
-
description: 'Footer of the list, appears below the items',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: 'header',
|
|
36
|
-
description: 'Header of the list, appears above the items',
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
{
|
|
40
|
-
name: 'items',
|
|
41
|
-
description: 'List of items',
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
6
|
};
|
|
@@ -1,14 +1,42 @@
|
|
|
1
|
-
import { documentedStoriesOf } from '../../../../documentation/documented_stories';
|
|
2
1
|
import { setStoryTimeout } from '../../../utils/test_utils';
|
|
2
|
+
import { GlInfiniteScroll } from '../../../../index';
|
|
3
3
|
import readme from './infinite_scroll.md';
|
|
4
4
|
|
|
5
5
|
const ITEMS_BATCH_SIZE = 20;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const template = `
|
|
8
|
+
<gl-infinite-scroll
|
|
9
|
+
:max-list-height="285"
|
|
10
|
+
:fetched-items="fetchedItems"
|
|
11
|
+
@bottomReached="bottomReached"
|
|
12
|
+
>
|
|
13
|
+
<template #items>
|
|
14
|
+
<ul class="list-group list-group-flushed list-unstyled">
|
|
15
|
+
<li v-for="item in fetchedItems" :key="item" class="list-group-item">Item #{{ item }}</li>
|
|
16
|
+
</ul>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<template #default>
|
|
20
|
+
<div class="gl-mt-3">
|
|
21
|
+
<gl-loading-icon v-if="isLoading" />
|
|
22
|
+
<span v-else>{{ fetchedItems }} items loaded</span>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
</gl-infinite-scroll>
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const generateProps = ({ isLoading = false, fetchedItems = ITEMS_BATCH_SIZE } = {}) => ({
|
|
29
|
+
isLoading,
|
|
30
|
+
fetchedItems,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const Template = (args, { argTypes }) => ({
|
|
34
|
+
components: {
|
|
35
|
+
GlInfiniteScroll,
|
|
36
|
+
},
|
|
37
|
+
props: Object.keys(argTypes),
|
|
8
38
|
data() {
|
|
9
39
|
return {
|
|
10
|
-
isLoading: false,
|
|
11
|
-
fetchedItems: ITEMS_BATCH_SIZE,
|
|
12
40
|
loadTimer: null,
|
|
13
41
|
};
|
|
14
42
|
},
|
|
@@ -22,24 +50,21 @@ documentedStoriesOf('base/infinite-scroll', readme).add('default', () => ({
|
|
|
22
50
|
}, 500);
|
|
23
51
|
},
|
|
24
52
|
},
|
|
25
|
-
template
|
|
26
|
-
|
|
27
|
-
:max-list-height="285"
|
|
28
|
-
:fetched-items="fetchedItems"
|
|
29
|
-
@bottomReached="bottomReached"
|
|
30
|
-
>
|
|
31
|
-
<template #items>
|
|
32
|
-
<ul class="list-group list-group-flushed list-unstyled">
|
|
33
|
-
<li v-for="item in fetchedItems" :key="item" class="list-group-item">Item #{{ item }}</li>
|
|
34
|
-
</ul>
|
|
35
|
-
</template>
|
|
53
|
+
template,
|
|
54
|
+
});
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
export const Default = Template.bind({});
|
|
57
|
+
Default.args = generateProps();
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
title: 'base/infinite-scroll',
|
|
61
|
+
component: GlInfiniteScroll,
|
|
62
|
+
parameters: {
|
|
63
|
+
knobs: { disable: true },
|
|
64
|
+
docs: {
|
|
65
|
+
description: {
|
|
66
|
+
component: readme,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
@@ -10,15 +10,24 @@ export const adjustScrollGap = 5;
|
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
props: {
|
|
13
|
+
/**
|
|
14
|
+
* Total number of items available
|
|
15
|
+
*/
|
|
13
16
|
totalItems: {
|
|
14
17
|
type: Number,
|
|
15
18
|
required: false,
|
|
16
19
|
default: 0,
|
|
17
20
|
},
|
|
21
|
+
/**
|
|
22
|
+
* Numbers of items fetched before scrolling
|
|
23
|
+
*/
|
|
18
24
|
fetchedItems: {
|
|
19
25
|
type: Number,
|
|
20
26
|
required: true,
|
|
21
27
|
},
|
|
28
|
+
/**
|
|
29
|
+
* Max height of the list before the scrollbar appears
|
|
30
|
+
*/
|
|
22
31
|
maxListHeight: {
|
|
23
32
|
type: Number,
|
|
24
33
|
required: false,
|
|
@@ -111,9 +120,15 @@ export default {
|
|
|
111
120
|
},
|
|
112
121
|
|
|
113
122
|
topReached: throttle(function topReachedThrottled() {
|
|
123
|
+
/**
|
|
124
|
+
* Emitted when item container is scrolled to the top
|
|
125
|
+
*/
|
|
114
126
|
this.$emit('topReached');
|
|
115
127
|
}, throttleDuration),
|
|
116
128
|
bottomReached: throttle(function bottomReachedThrottled() {
|
|
129
|
+
/**
|
|
130
|
+
* Emitted when item container is scrolled to the bottom
|
|
131
|
+
*/
|
|
117
132
|
this.$emit('bottomReached');
|
|
118
133
|
}, throttleDuration),
|
|
119
134
|
itemsListHeight() {
|
|
@@ -135,6 +150,7 @@ export default {
|
|
|
135
150
|
|
|
136
151
|
<template>
|
|
137
152
|
<div>
|
|
153
|
+
<!-- @slot Header of the list, appears above the items -->
|
|
138
154
|
<slot name="header"></slot>
|
|
139
155
|
<div
|
|
140
156
|
ref="infiniteContainer"
|
|
@@ -144,9 +160,11 @@ export default {
|
|
|
144
160
|
@scroll="handleScroll"
|
|
145
161
|
v-on="$listeners"
|
|
146
162
|
>
|
|
163
|
+
<!-- @slot List of items -->
|
|
147
164
|
<slot name="items"></slot>
|
|
148
165
|
</div>
|
|
149
166
|
<p class="gl-infinite-scroll-legend">
|
|
167
|
+
<!-- @slot Footer of the list, appears below the items -->
|
|
150
168
|
<slot :fetched-items="fetchedItems" :total-items="totalItems">
|
|
151
169
|
{{ legendText }}
|
|
152
170
|
</slot>
|
|
@@ -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>
|
|
@@ -27,6 +27,10 @@ $gl-search-box-by-type-input-padding: 3.5 * $grid-size;
|
|
|
27
27
|
@include gl-h-7;
|
|
28
28
|
@include gl-pr-7;
|
|
29
29
|
padding-left: $gl-search-box-by-type-input-padding;
|
|
30
|
+
|
|
31
|
+
&::-webkit-search-cancel-button {
|
|
32
|
+
@include gl-display-none;
|
|
33
|
+
}
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
.gl-search-box-by-type-right-icons {
|