@gitlab/ui 33.0.0 → 33.1.2

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/base/accordion/accordion.js +6 -2
  3. package/dist/components/base/accordion/accordion_item.js +2 -2
  4. package/dist/components/base/datepicker/datepicker.js +4 -1
  5. package/dist/components/base/dropdown/dropdown.js +4 -4
  6. package/dist/components/base/filtered_search/filtered_search.js +5 -2
  7. package/dist/components/base/filtered_search/filtered_search_token.js +12 -8
  8. package/dist/components/base/filtered_search/filtered_search_token_segment.js +6 -5
  9. package/dist/components/base/form/form_checkbox_tree/models/node.js +9 -8
  10. package/dist/components/base/form/form_checkbox_tree/models/tree.js +21 -10
  11. package/dist/components/base/form/form_input/form_input.js +14 -4
  12. package/dist/components/base/form/form_textarea/form_textarea.js +14 -4
  13. package/dist/components/base/infinite_scroll/infinite_scroll.documentation.js +2 -33
  14. package/dist/components/base/infinite_scroll/infinite_scroll.js +21 -3
  15. package/dist/components/base/pagination/pagination.js +2 -1
  16. package/dist/components/base/path/path.js +6 -5
  17. package/dist/components/base/popover/popover.js +25 -2
  18. package/dist/components/base/segmented_control/segmented_control.js +9 -4
  19. package/dist/components/base/skeleton_loader/skeleton_loader.js +6 -4
  20. package/dist/components/base/sorting/sorting_item.js +6 -5
  21. package/dist/components/base/table/table.js +5 -4
  22. package/dist/components/base/tabs/tabs/scrollable_tabs.js +6 -5
  23. package/dist/components/base/toast/toast.js +2 -1
  24. package/dist/components/base/token_selector/token_container.js +2 -1
  25. package/dist/components/base/token_selector/token_selector.js +2 -1
  26. package/dist/components/charts/bar/bar.js +2 -1
  27. package/dist/components/charts/column/column.documentation.js +1 -7
  28. package/dist/components/charts/column/column.js +17 -14
  29. package/dist/components/charts/gauge/gauge.js +45 -42
  30. package/dist/components/charts/sparkline/sparkline.js +6 -4
  31. package/dist/components/charts/stacked_column/stacked_column.js +17 -14
  32. package/dist/components/utilities/friendly_wrap/friendly_wrap.js +4 -3
  33. package/dist/components/utilities/sprintf/sprintf.js +4 -2
  34. package/dist/directives/hover_load/hover_load.js +5 -3
  35. package/dist/directives/outside/outside.js +12 -8
  36. package/dist/directives/resize_observer/examples/resize_observer.basic.example.js +7 -6
  37. package/dist/directives/resize_observer/resize_observer.js +12 -8
  38. package/dist/directives/safe_link/safe_link.js +12 -6
  39. package/dist/index.css +1 -1
  40. package/dist/index.css.map +1 -1
  41. package/dist/utility_classes.css +1 -1
  42. package/dist/utility_classes.css.map +1 -1
  43. package/dist/utils/charts/config.js +95 -72
  44. package/dist/utils/charts/story_config.js +4 -2
  45. package/dist/utils/charts/theme.js +106 -103
  46. package/dist/utils/charts/utils.js +14 -6
  47. package/dist/utils/number_utils.js +14 -5
  48. package/dist/utils/use_mock_intersection_observer.js +31 -11
  49. package/dist/utils/utils.js +15 -4
  50. package/dist/utils/validation_utils.js +3 -1
  51. package/documentation/documented_stories.js +2 -0
  52. package/package.json +16 -13
  53. package/src/components/base/accordion/accordion.vue +5 -2
  54. package/src/components/base/accordion/accordion_item.spec.js +2 -2
  55. package/src/components/base/accordion/accordion_item.stories.js +2 -2
  56. package/src/components/base/accordion/accordion_item.vue +2 -2
  57. package/src/components/base/infinite_scroll/infinite_scroll.documentation.js +0 -38
  58. package/src/components/base/infinite_scroll/infinite_scroll.md +0 -4
  59. package/src/components/base/infinite_scroll/infinite_scroll.stories.js +49 -24
  60. package/src/components/base/infinite_scroll/infinite_scroll.vue +18 -0
  61. package/src/components/base/popover/popover.scss +0 -5
  62. package/src/components/base/popover/popover.spec.js +42 -1
  63. package/src/components/base/popover/popover.stories.js +18 -0
  64. package/src/components/base/popover/popover.vue +32 -2
  65. package/src/components/base/search_box_by_click/search_box_by_click.scss +4 -0
  66. package/src/components/base/search_box_by_type/search_box_by_type.scss +4 -0
  67. package/src/components/charts/column/column.documentation.js +0 -5
  68. package/src/components/charts/column/column.stories.js +61 -88
  69. package/src/scss/utilities.scss +8 -0
  70. package/src/scss/utility-mixins/sizing.scss +4 -0
  71. package/dist/components/charts/column/examples/column.basic.example.js +0 -49
  72. package/dist/components/charts/column/examples/index.js +0 -13
  73. package/src/components/charts/column/column.md +0 -1
  74. package/src/components/charts/column/examples/column.basic.example.vue +0 -22
  75. package/src/components/charts/column/examples/index.js +0 -15
@@ -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(...args) {
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 (...args) => {
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, opacity = 1) {
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(message = '') {
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 = (validation = {}) => {
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}`;
@@ -120,6 +120,8 @@ export const setupStorybookReadme = () =>
120
120
  'GlToast',
121
121
  'GlPaginatedList',
122
122
  'GlIntersectionObserver',
123
+ 'GlInfiniteScroll',
124
+ 'GlColumnChart',
123
125
  ],
124
126
  components: {
125
127
  GlComponentDocumentation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "33.0.0",
3
+ "version": "33.1.2",
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.4",
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",
@@ -72,8 +73,8 @@
72
73
  },
73
74
  "peerDependencies": {
74
75
  "@gitlab/svgs": "^1.116.0 || ^2.0.0",
75
- "emoji-regex": ">=10.0.0",
76
76
  "bootstrap": "4.5.3",
77
+ "emoji-regex": ">=10.0.0",
77
78
  "pikaday": "^1.8.0",
78
79
  "vue": "^2.6.10"
79
80
  },
@@ -85,20 +86,20 @@
85
86
  "@babel/core": "^7.10.2",
86
87
  "@babel/preset-env": "^7.10.2",
87
88
  "@gitlab/eslint-plugin": "10.0.1",
88
- "@gitlab/stylelint-config": "2.6.0",
89
+ "@gitlab/stylelint-config": "3.0.0",
89
90
  "@gitlab/svgs": "2.2.0",
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.13",
94
- "@storybook/addon-docs": "6.4.13",
95
- "@storybook/addon-essentials": "6.4.13",
94
+ "@storybook/addon-a11y": "6.4.14",
95
+ "@storybook/addon-docs": "6.4.14",
96
+ "@storybook/addon-essentials": "6.4.14",
96
97
  "@storybook/addon-knobs": "6.4.0",
97
- "@storybook/addon-storyshots": "6.4.13",
98
- "@storybook/addon-storyshots-puppeteer": "6.4.13",
99
- "@storybook/addon-viewport": "6.4.13",
100
- "@storybook/theming": "6.4.13",
101
- "@storybook/vue": "6.4.13",
98
+ "@storybook/addon-storyshots": "6.4.14",
99
+ "@storybook/addon-storyshots-puppeteer": "6.4.14",
100
+ "@storybook/addon-viewport": "6.4.14",
101
+ "@storybook/theming": "6.4.14",
102
+ "@storybook/vue": "6.4.14",
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",
@@ -145,8 +147,9 @@
145
147
  "sass-true": "^5.0.0",
146
148
  "start-server-and-test": "^1.10.6",
147
149
  "storybook-readme": "5.0.9",
150
+ "stylelint": "13.9.0",
148
151
  "stylelint-config-prettier": "9.0.3",
149
- "stylelint-prettier": "1.2.0",
152
+ "stylelint-prettier": "2.0.0",
150
153
  "vue": "^2.6.11",
151
154
  "vue-jest": "4.0.0-rc.0",
152
155
  "vue-loader": "^15.8.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 && uniqueId('accordion-set-'),
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';
@@ -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,7 +1,3 @@
1
- # Infinite Scroll
2
-
3
- <!-- STORY -->
4
-
5
1
  ## Usage
6
2
 
7
3
  The infinite scroll component wraps around a results list and emits a message
@@ -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
- documentedStoriesOf('base/infinite-scroll', readme).add('default', () => ({
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
- <gl-infinite-scroll
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
- <template #default>
38
- <div class="gl-mt-3">
39
- <gl-loading-icon v-if="isLoading" />
40
- <span v-else>{{ fetchedItems }} items loaded</span>
41
- </div>
42
- </template>
43
- </gl-infinite-scroll>
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>
@@ -67,11 +67,6 @@ $gl-popover-max-width: $grid-size * 35;
67
67
  @include gl-font-sm;
68
68
  @include gl-font-weight-bold;
69
69
  @include gl-m-0;
70
-
71
- .gl-button.close {
72
- margin-top: -$gl-spacing-scale-3;
73
- margin-right: -$gl-spacing-scale-4;
74
- }
75
70
  }
76
71
 
77
72
  .popover-body {
@@ -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="$scopedSlots.title" #title>
43
- <slot name="title"></slot>
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>
@@ -56,6 +56,10 @@
56
56
 
57
57
  .gl-search-box-by-click-input {
58
58
  @include gl-pr-7;
59
+
60
+ &::-webkit-search-cancel-button {
61
+ @include gl-display-none;
62
+ }
59
63
  }
60
64
 
61
65
  .gl-search-box-by-click-clear-button {
@@ -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 {
@@ -1,8 +1,3 @@
1
- import description from './column.md';
2
- import examples from './examples';
3
-
4
1
  export default {
5
2
  followsDesignSystem: true,
6
- description,
7
- examples,
8
3
  };