@gitlab/ui 72.6.0 → 72.8.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +2 -14
  3. package/dist/components/base/dropdown/dropdown.js +2 -6
  4. package/dist/components/base/filtered_search/filtered_search_term.js +2 -0
  5. package/dist/components/base/filtered_search/filtered_search_token.js +3 -1
  6. package/dist/components/base/filtered_search/filtered_search_token_segment.js +4 -1
  7. package/dist/components/base/new_dropdowns/disclosure/utils.js +5 -1
  8. package/dist/components/base/new_dropdowns/listbox/utils.js +6 -0
  9. package/dist/components/base/sorting/sorting.js +1 -0
  10. package/dist/components/charts/column/column.js +1 -1
  11. package/dist/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.js +2 -0
  12. package/dist/components/experimental/duo/chat/duo_chat.js +2 -0
  13. package/dist/components/regions/empty_state/empty_state.js +1 -1
  14. package/dist/components/utilities/sprintf/sprintf.js +3 -1
  15. package/dist/tokens/css/tokens.css +1 -1
  16. package/dist/tokens/css/tokens.dark.css +1 -1
  17. package/dist/tokens/js/tokens.dark.js +1 -1
  18. package/dist/tokens/js/tokens.js +1 -1
  19. package/dist/tokens/scss/_tokens.dark.scss +1 -1
  20. package/dist/tokens/scss/_tokens.scss +1 -1
  21. package/dist/utility_classes.css +1 -1
  22. package/dist/utility_classes.css.map +1 -1
  23. package/dist/utils/is_slot_empty.js +4 -0
  24. package/dist/utils/number_utils.js +1 -1
  25. package/dist/utils/utils.js +1 -1
  26. package/package.json +14 -12
  27. package/src/components/base/accordion/accordion_item.stories.js +1 -1
  28. package/src/components/base/alert/alert.stories.js +4 -12
  29. package/src/components/base/badge/badge.stories.js +2 -6
  30. package/src/components/base/broadcast_message/broadcast_message.stories.js +2 -3
  31. package/src/components/base/drawer/drawer.spec.js +1 -0
  32. package/src/components/base/dropdown/dropdown.vue +2 -6
  33. package/src/components/base/filtered_search/filtered_search.spec.js +11 -0
  34. package/src/components/base/filtered_search/filtered_search_term.vue +1 -0
  35. package/src/components/base/filtered_search/filtered_search_token.vue +1 -0
  36. package/src/components/base/filtered_search/filtered_search_token_segment.vue +3 -1
  37. package/src/components/base/form/form_fields/form_fields.spec.js +1 -0
  38. package/src/components/base/icon/icon.stories.js +1 -1
  39. package/src/components/base/new_dropdowns/disclosure/utils.js +2 -0
  40. package/src/components/base/new_dropdowns/listbox/listbox.spec.js +2 -0
  41. package/src/components/base/new_dropdowns/listbox/listbox.stories.js +5 -3
  42. package/src/components/base/new_dropdowns/listbox/utils.js +3 -0
  43. package/src/components/base/popover/popover.stories.js +1 -3
  44. package/src/components/base/sorting/sorting.vue +1 -0
  45. package/src/components/base/tabs/tabs/tabs.stories.js +1 -3
  46. package/src/components/base/token_selector/token_selector.stories.js +1 -1
  47. package/src/components/charts/area/area.stories.js +1 -3
  48. package/src/components/charts/chart/chart.stories.js +1 -3
  49. package/src/components/charts/column/__snapshots__/column_chart.spec.js.snap +1 -1
  50. package/src/components/charts/column/column.stories.js +18 -3
  51. package/src/components/charts/column/column.vue +16 -1
  52. package/src/components/charts/column/column_chart.spec.js +106 -20
  53. package/src/components/charts/line/line.stories.js +1 -3
  54. package/src/components/charts/sparkline/sparkline.stories.js +2 -2
  55. package/src/components/experimental/duo/chat/components/duo_chat_conversation/duo_chat_conversation.vue +1 -0
  56. package/src/components/experimental/duo/chat/duo_chat.vue +1 -0
  57. package/src/components/experimental/duo/user_feedback/user_feedback.stories.js +1 -1
  58. package/src/components/experimental/experiment_badge/experiment_badge.stories.js +1 -1
  59. package/src/components/regions/empty_state/empty_state.vue +0 -1
  60. package/src/components/utilities/animated_number/animated_number.stories.js +1 -0
  61. package/src/components/utilities/intersection_observer/intersection_observer.spec.js +1 -0
  62. package/src/components/utilities/intersection_observer/intersection_observer.stories.js +1 -1
  63. package/src/components/utilities/intersperse/intersperse.spec.js +1 -0
  64. package/src/components/utilities/sprintf/sprintf.stories.js +4 -4
  65. package/src/components/utilities/sprintf/sprintf.vue +1 -0
  66. package/src/components/utilities/truncate/truncate.stories.js +1 -1
  67. package/src/components/utilities/truncate_text/truncate_text.stories.js +1 -1
  68. package/src/directives/hover_load/hover_load.stories.js +1 -1
  69. package/src/directives/outside/outside.stories.js +1 -3
  70. package/src/directives/resize_observer/resize_observer.stories.js +1 -1
  71. package/src/directives/safe_html/safe_html.stories.js +1 -1
  72. package/src/directives/safe_link/safe_link.stories.js +1 -1
  73. package/src/scss/utilities.scss +8 -0
  74. package/src/scss/utility-mixins/sizing.scss +4 -0
  75. package/src/utils/is_slot_empty.js +3 -0
  76. package/src/utils/number_utils.js +1 -1
  77. package/src/utils/utils.js +1 -1
@@ -13,10 +13,12 @@ function isEmpty(vnode) {
13
13
  return true;
14
14
  }
15
15
  if (Array.isArray(vnode)) {
16
+ // eslint-disable-next-line unicorn/no-array-callback-reference
16
17
  return vnode.every(isEmpty);
17
18
  }
18
19
  if (Fragment && vnode.type === Fragment) {
19
20
  // Vue.js 3 fragment, check children
21
+ // eslint-disable-next-line unicorn/no-array-callback-reference
20
22
  return vnode.children.every(isEmpty);
21
23
  }
22
24
  return false;
@@ -28,6 +30,8 @@ function isSlotEmpty(vueInstance, slot, slotArgs) {
28
30
  // we need to check both $slots and $scopedSlots due to https://github.com/vuejs/core/issues/8869
29
31
  // additionally, in @vue/compat $slot might be a function instead of array of vnodes (sigh)
30
32
  callIfNeeded(vueInstance.$slots[slot] || vueInstance.$scopedSlots[slot], slotArgs) : (_vueInstance$$scopedS = (_vueInstance$$scopedS2 = vueInstance.$scopedSlots)[slot]) === null || _vueInstance$$scopedS === void 0 ? void 0 : _vueInstance$$scopedS.call(_vueInstance$$scopedS2, slotArgs);
33
+
34
+ // eslint-disable-next-line unicorn/no-array-callback-reference
31
35
  return isEmpty(slotContent);
32
36
  }
33
37
 
@@ -14,7 +14,7 @@ const sum = function () {
14
14
  numbers[_key] = arguments[_key];
15
15
  }
16
16
  return numbers.reduce(addition);
17
- };
17
+ }; // eslint-disable-line unicorn/no-array-callback-reference
18
18
 
19
19
  /**
20
20
  * Returns the average of all arguments
@@ -171,7 +171,7 @@ function stopEvent(event) {
171
171
  * Return an Array of visible items
172
172
  */
173
173
  function filterVisible(els) {
174
- return (els || []).filter(isVisible);
174
+ return (els || []).filter(el => isVisible(el));
175
175
  }
176
176
 
177
177
  export { colorFromBackground, debounceByAnimationFrame, filterVisible, focusFirstFocusableElement, hexToRgba, isDev, isElementFocusable, isElementTabbable, logWarning, relativeLuminance, rgbFromHex, rgbFromString, stopEvent, throttle, toSrgb, uid };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "72.6.0",
3
+ "version": "72.8.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -38,15 +38,15 @@
38
38
  "pretest:unit": "yarn build-tokens",
39
39
  "test": "run-s test:unit test:visual",
40
40
  "test:integration": "NODE_ENV=test start-server-and-test start http://${STORYBOOK_HOST:-localhost}:9001/iframe.html 'yarn cy:run && yarn cy:edge && yarn cy:a11y'",
41
- "test:unit": "NODE_ENV=test jest --testPathIgnorePatterns storyshots.spec.js",
41
+ "test:unit": "NODE_ENV=test jest",
42
42
  "test:unit:watch": "yarn test:unit --watch",
43
43
  "test:unit:debug": "NODE_ENV=test node --inspect node_modules/.bin/jest --testPathIgnorePatterns storyshot.spec.js --watch --runInBand",
44
- "test:unit-vue3": "VUE_VERSION=3 NODE_ENV=test jest --testPathIgnorePatterns storyshots.spec.js",
44
+ "test:unit-vue3": "VUE_VERSION=3 NODE_ENV=test jest",
45
45
  "test:unit-vue3:watch": "VUE_VERSION=3 yarn test:unit --watch",
46
46
  "test:unit-vue3:debug": "VUE_VERSION=3 NODE_ENV=test node --inspect node_modules/.bin/jest --testPathIgnorePatterns storyshot.spec.js --watch --runInBand",
47
- "test:visual": "./bin/run-visual-tests.sh 'jest ./tests/storyshots.spec.js'",
47
+ "test:visual": "./bin/run-visual-tests.sh 'test-storybook --browsers firefox --verbose --url http://localhost:9001'",
48
48
  "test:visual:minimal": "node ./bin/run_minimal_visual_tests.js",
49
- "test:visual:update": "./bin/run-visual-tests.sh 'JEST_IMAGE_SNAPSHOT_TRACK_OBSOLETE=1 jest ./tests/storyshots.spec.js --updateSnapshot'",
49
+ "test:visual:update": "./bin/run-visual-tests.sh 'test-storybook -u --browsers firefox --verbose --url http://localhost:9001'",
50
50
  "test:visual:internal": "NODE_ENV=test IS_VISUAL_TEST=true start-test http-get://${STORYBOOK_HOST:-localhost}:9001/iframe.html",
51
51
  "prettier": "prettier --check '**/*.{js,vue}'",
52
52
  "prettier:fix": "prettier --write '**/*.{js,vue}'",
@@ -88,28 +88,31 @@
88
88
  "devDependencies": {
89
89
  "@arkweid/lefthook": "0.7.7",
90
90
  "@babel/core": "^7.23.7",
91
- "@babel/preset-env": "^7.23.7",
91
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
92
+ "@babel/plugin-proposal-optional-chaining": "^7.21.0",
93
+ "@babel/preset-env": "^7.23.8",
92
94
  "@babel/preset-react": "^7.23.3",
93
95
  "@cypress/grep": "^4.0.1",
94
- "@gitlab/eslint-plugin": "19.2.0",
96
+ "@gitlab/eslint-plugin": "19.4.0",
95
97
  "@gitlab/fonts": "^1.3.0",
96
98
  "@gitlab/stylelint-config": "5.0.1",
97
- "@gitlab/svgs": "3.74.0",
99
+ "@gitlab/svgs": "3.75.0",
98
100
  "@rollup/plugin-commonjs": "^11.1.0",
99
101
  "@rollup/plugin-node-resolve": "^7.1.3",
100
102
  "@rollup/plugin-replace": "^2.3.2",
101
103
  "@storybook/addon-a11y": "7.6.7",
102
104
  "@storybook/addon-docs": "7.6.7",
103
105
  "@storybook/addon-essentials": "7.6.7",
104
- "@storybook/addon-storyshots": "7.6.7",
105
- "@storybook/addon-storyshots-puppeteer": "7.6.7",
106
106
  "@storybook/addon-viewport": "7.6.7",
107
107
  "@storybook/builder-webpack5": "7.6.7",
108
+ "@storybook/test-runner": "0.16.0",
108
109
  "@storybook/theming": "7.6.7",
109
110
  "@storybook/vue": "7.6.7",
110
111
  "@storybook/vue-webpack5": "7.6.7",
111
112
  "@storybook/vue3": "7.6.7",
112
113
  "@storybook/vue3-webpack5": "7.6.7",
114
+ "@types/jest": "^29.5.11",
115
+ "@types/jest-image-snapshot": "^6.4.0",
113
116
  "@vue/compat": "^3.2.40",
114
117
  "@vue/compiler-sfc": "^3.2.40",
115
118
  "@vue/test-utils": "1.3.0",
@@ -120,7 +123,6 @@
120
123
  "axe-core": "^4.2.3",
121
124
  "babel-jest": "29.0.1",
122
125
  "babel-loader": "^8.0.5",
123
- "babel-plugin-require-context-hook": "^1.0.0",
124
126
  "bootstrap": "4.6.2",
125
127
  "cypress": "13.6.2",
126
128
  "cypress-axe": "^1.4.0",
@@ -137,6 +139,7 @@
137
139
  "jest": "^29.7.0",
138
140
  "jest-circus": "29.7.0",
139
141
  "jest-environment-jsdom": "29.7.0",
142
+ "jest-image-snapshot": "^6.4.0",
140
143
  "markdownlint-cli": "^0.29.0",
141
144
  "mockdate": "^2.0.5",
142
145
  "module-alias": "^2.2.2",
@@ -147,7 +150,6 @@
147
150
  "postcss-loader": "^7.0.2",
148
151
  "postcss-scss": "4.0.4",
149
152
  "prettier": "2.6.2",
150
- "puppeteer": "15.5.0",
151
153
  "react": "^18.2.0",
152
154
  "react-dom": "^18.2.0",
153
155
  "rollup": "^2.53.1",
@@ -40,8 +40,8 @@ export default {
40
40
  title: 'base/accordion/accordion-item',
41
41
  component: GlAccordionItem,
42
42
  bootstrapComponent: 'b-collapse',
43
+ tags: ['skip-visual-test'],
43
44
  parameters: {
44
- storyshots: { disable: true },
45
45
  docs: {
46
46
  description: {
47
47
  component: readme,
@@ -81,9 +81,7 @@ export const CustomActions = () => ({
81
81
  </template>
82
82
  </gl-alert>`,
83
83
  });
84
- CustomActions.parameters = {
85
- storyshots: { disable: true },
86
- };
84
+ CustomActions.tags = ['skip-visual-test'];
87
85
 
88
86
  export const TextLinks = () => ({
89
87
  components: { GlAlert },
@@ -92,9 +90,7 @@ export const TextLinks = () => ({
92
90
  Lorem ipsum dolor sit <a class="gl-link" href="#">text link</a> amet
93
91
  </gl-alert>`,
94
92
  });
95
- TextLinks.parameters = {
96
- storyshots: { disable: true },
97
- };
93
+ TextLinks.tags = ['skip-visual-test'];
98
94
 
99
95
  export const NoIcon = () => ({
100
96
  components: { GlAlert },
@@ -103,9 +99,7 @@ export const NoIcon = () => ({
103
99
  Lorem ipsum dolor sit amet
104
100
  </gl-alert>`,
105
101
  });
106
- NoIcon.parameters = {
107
- storyshots: { disable: true },
108
- };
102
+ NoIcon.tags = ['skip-visual-test'];
109
103
 
110
104
  export const Variants = () => ({
111
105
  components: { GlAlert },
@@ -126,9 +120,7 @@ export const Variants = () => ({
126
120
  </gl-alert>
127
121
  </div>`,
128
122
  });
129
- Variants.parameters = {
130
- storyshots: { disable: true },
131
- };
123
+ Variants.tags = ['skip-visual-test'];
132
124
 
133
125
  export const Sticky = () => ({
134
126
  components: { GlAlert },
@@ -44,9 +44,7 @@ const Template = (args, { argTypes }) => ({
44
44
 
45
45
  export const Default = Template.bind({});
46
46
  Default.args = generateProps();
47
- Default.parameters = {
48
- storyshots: { disable: true },
49
- };
47
+ Default.tags = ['skip-visual-test'];
50
48
 
51
49
  export const Variants = (args, { argTypes }) => ({
52
50
  components: { GlBadge },
@@ -95,9 +93,7 @@ Actionable.args = generateProps({
95
93
  href: '#foo',
96
94
  variant: badgeVariantOptions.warning,
97
95
  });
98
- Actionable.parameters = {
99
- storyshots: { disable: true },
100
- };
96
+ Actionable.tags = ['skip-visual-test'];
101
97
  Actionable.argTypes = disableControls(['content', 'variant']);
102
98
 
103
99
  export const Sizes = (args, { argTypes }) => ({
@@ -69,13 +69,12 @@ const StackedStory = (args, { argTypes }) => ({
69
69
  GlBroadcastMessage,
70
70
  },
71
71
  props: Object.keys(argTypes),
72
+ // eslint-disable-next-line unicorn/no-array-callback-reference
72
73
  template: `<div>${Object.keys(colorThemes).map(templateWithTheme).join('')}</div>`,
73
74
  });
74
75
  export const Stacked = StackedStory.bind({});
75
76
  Stacked.args = generateProps();
76
- Stacked.parameters = {
77
- storyshots: { disable: true },
78
- };
77
+ Stacked.tags = ['skip-visual-test'];
79
78
 
80
79
  export const IncreasedSpacing = (args, { argTypes }) => ({
81
80
  components: {
@@ -98,6 +98,7 @@ describe('drawer component', () => {
98
98
  },
99
99
  });
100
100
 
101
+ // eslint-disable-next-line unicorn/no-array-callback-reference
101
102
  expect(wrapper.find(parentSelector).find(`[data-testid="${slot}"]`).exists()).toBe(true);
102
103
  });
103
104
 
@@ -2,24 +2,20 @@
2
2
  <script>
3
3
  import Vue from 'vue';
4
4
  import { BDropdown } from 'bootstrap-vue';
5
- import { isVisible, selectAll } from 'bootstrap-vue/src/utils/dom';
5
+ import { selectAll } from 'bootstrap-vue/src/utils/dom';
6
6
  import merge from 'lodash/merge';
7
7
  import {
8
8
  buttonCategoryOptions,
9
9
  buttonSizeOptions,
10
10
  dropdownVariantOptions,
11
11
  } from '../../../utils/constants';
12
+ import { filterVisible } from '../../../utils/utils';
12
13
  import { ButtonMixin } from '../../mixins/button_mixin';
13
14
  import GlButton from '../button/button.vue';
14
15
  import GlIcon from '../icon/icon.vue';
15
16
  import GlLoadingIcon from '../loading_icon/loading_icon.vue';
16
17
  import GlDropdownDivider from './dropdown_divider.vue';
17
18
 
18
- // Return an Array of visible items
19
- function filterVisible(els) {
20
- return (els || []).filter(isVisible);
21
- }
22
-
23
19
  const Selector = {
24
20
  ITEM_SELECTOR:
25
21
  '.dropdown-item:not(.disabled):not([disabled]),.form-control:not(.disabled):not([disabled])',
@@ -59,6 +59,7 @@ describe('Filtered search', () => {
59
59
  describe('value manipulation', () => {
60
60
  it('creates term when empty', () => {
61
61
  createComponent();
62
+ // eslint-disable-next-line unicorn/no-array-callback-reference
62
63
  expect(wrapper.emitted().input[0][0].map(stripId)).toStrictEqual([
63
64
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
64
65
  ]);
@@ -202,6 +203,7 @@ describe('Filtered search', () => {
202
203
 
203
204
  await nextTick();
204
205
 
206
+ // eslint-disable-next-line unicorn/no-array-callback-reference
205
207
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
206
208
  { type: 'faketoken', value: { data: '' } },
207
209
  { type: TERM_TOKEN_TYPE, value: { data: 'one' } },
@@ -220,6 +222,7 @@ describe('Filtered search', () => {
220
222
 
221
223
  await nextTick();
222
224
 
225
+ // eslint-disable-next-line unicorn/no-array-callback-reference
223
226
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
224
227
  { type: TERM_TOKEN_TYPE, value: { data: 'one' } },
225
228
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
@@ -335,6 +338,7 @@ describe('Filtered search', () => {
335
338
 
336
339
  await nextTick();
337
340
 
341
+ // eslint-disable-next-line unicorn/no-array-callback-reference
338
342
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
339
343
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
340
344
  ]);
@@ -348,6 +352,7 @@ describe('Filtered search', () => {
348
352
 
349
353
  await nextTick();
350
354
 
355
+ // eslint-disable-next-line unicorn/no-array-callback-reference
351
356
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
352
357
  { type: 'faketoken', value: { data: 'test' } },
353
358
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
@@ -369,6 +374,7 @@ describe('Filtered search', () => {
369
374
 
370
375
  await nextTick();
371
376
 
377
+ // eslint-disable-next-line unicorn/no-array-callback-reference
372
378
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
373
379
  { type: 'faketoken', value: { data: 'test' } },
374
380
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
@@ -382,6 +388,7 @@ describe('Filtered search', () => {
382
388
 
383
389
  await nextTick();
384
390
 
391
+ // eslint-disable-next-line unicorn/no-array-callback-reference
385
392
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
386
393
  { type: TERM_TOKEN_TYPE, value: { data: 'one' } },
387
394
  { type: TERM_TOKEN_TYPE, value: { data: '' } },
@@ -398,6 +405,7 @@ describe('Filtered search', () => {
398
405
  await nextTick();
399
406
 
400
407
  expect(wrapper.findAllComponents(GlFilteredSearchTerm).at(2).props('active')).toBe(true);
408
+ // eslint-disable-next-line unicorn/no-array-callback-reference
401
409
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
402
410
  { type: TERM_TOKEN_TYPE, value: { data: 'one' } },
403
411
  { type: TERM_TOKEN_TYPE, value: { data: 'two' } },
@@ -415,6 +423,7 @@ describe('Filtered search', () => {
415
423
 
416
424
  await nextTick();
417
425
 
426
+ // eslint-disable-next-line unicorn/no-array-callback-reference
418
427
  expect(wrapper.emitted().input.pop()[0].map(stripId)).toStrictEqual([
419
428
  { type: TERM_TOKEN_TYPE, value: { data: 'one' } },
420
429
  { type: TERM_TOKEN_TYPE, value: { data: 'foo' } },
@@ -445,6 +454,7 @@ describe('Filtered search', () => {
445
454
  });
446
455
  wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
447
456
  expect(wrapper.emitted('submit')).toBeDefined();
457
+ // eslint-disable-next-line unicorn/no-array-callback-reference
448
458
  expect(wrapper.emitted().submit[0][0].map(stripId)).toStrictEqual([
449
459
  'one two',
450
460
  { type: 'faketoken', value: { data: 'smth' } },
@@ -505,6 +515,7 @@ describe('Filtered search', () => {
505
515
  });
506
516
  await nextTick();
507
517
 
518
+ // eslint-disable-next-line unicorn/no-array-callback-reference
508
519
  expect(wrapper.findComponent(GlFilteredSearchTerm).props('currentValue').map(stripId)).toEqual([
509
520
  { type: 'filtered-search-term', value: { data: 'one' } },
510
521
  { type: 'filtered-search-term', value: { data: '' } },
@@ -108,6 +108,7 @@ export default {
108
108
  });
109
109
  }
110
110
 
111
+ // eslint-disable-next-line unicorn/no-array-callback-reference
111
112
  return tokens.map(tokenToOption);
112
113
  },
113
114
  internalValue: {
@@ -109,6 +109,7 @@ export default {
109
109
 
110
110
  availableTokensWithSelf() {
111
111
  return [this.config, ...this.availableTokens.filter((token) => token !== this.config)].map(
112
+ // eslint-disable-next-line unicorn/no-array-callback-reference
112
113
  tokenToOption
113
114
  );
114
115
  },
@@ -24,7 +24,8 @@ const isVNodeEmpty = (vnode) => {
24
24
  if (isVue3Fragment(vnode)) {
25
25
  // vnode.children might be an array or single node in edge cases
26
26
  return Array.isArray(vnode.children)
27
- ? vnode.children.every(isVNodeEmpty)
27
+ ? // eslint-disable-next-line unicorn/no-array-callback-reference
28
+ vnode.children.every(isVNodeEmpty)
28
29
  : isVNodeEmpty(vnode.children);
29
30
  }
30
31
 
@@ -41,6 +42,7 @@ const isSlotNotEmpty = (slot) => {
41
42
  }
42
43
 
43
44
  const vnodes = typeof slot === 'function' ? slot() : slot;
45
+ // eslint-disable-next-line unicorn/no-array-callback-reference
44
46
  return !(Array.isArray(vnodes) ? vnodes.every(isVNodeEmpty) : isVNodeEmpty(vnodes));
45
47
  };
46
48
 
@@ -78,6 +78,7 @@ describe('GlFormFields', () => {
78
78
  };
79
79
  };
80
80
  const findFormGroups = () => wrapper.findAllComponents(GlFormGroup).wrappers;
81
+ // eslint-disable-next-line unicorn/no-array-callback-reference
81
82
  const findFormGroupsAsData = () => findFormGroups().map(mapFormGroupToData);
82
83
  const findFormGroupFromLabel = (label) =>
83
84
  wrapper.findAllComponents(GlFormGroup).wrappers.find((x) => x.attributes('label') === label);
@@ -32,13 +32,13 @@ Default.args = generateProps();
32
32
  export default {
33
33
  title: 'base/icon',
34
34
  component: GlIcon,
35
+ tags: ['skip-visual-test'],
35
36
  parameters: {
36
37
  docs: {
37
38
  description: {
38
39
  component: readme,
39
40
  },
40
41
  },
41
- storyshots: { disable: true },
42
42
  },
43
43
  argTypes: {
44
44
  ...disableControls(['useDeprecatedSizes']),
@@ -9,8 +9,10 @@ const isGroup = (group) =>
9
9
  Boolean(group) &&
10
10
  Array.isArray(group.items) &&
11
11
  Boolean(group.items.length) &&
12
+ // eslint-disable-next-line unicorn/no-array-callback-reference
12
13
  group.items.every(isItem);
13
14
 
15
+ // eslint-disable-next-line unicorn/no-array-callback-reference
14
16
  const itemsValidator = (items) => items.every(isItem) || items.every(isGroup);
15
17
 
16
18
  const isListItem = (tag) =>
@@ -48,6 +48,7 @@ describe('GlCollapsibleListbox', () => {
48
48
  const findListContainer = () => wrapper.find('[role="listbox"]');
49
49
  const findListboxItems = (root = wrapper) => root.findAllComponents(GlListboxItem);
50
50
  const findListboxGroups = () => wrapper.findAllComponents(GlListboxGroup);
51
+ // eslint-disable-next-line unicorn/no-array-callback-reference
51
52
  const findListItem = (index) => findListboxItems().at(index).find(ITEM_SELECTOR);
52
53
  const findHeaderText = () => wrapper.find("[data-testid='listbox-header-text']");
53
54
  const findSearchBox = () => wrapper.find("[data-testid='listbox-search-input']");
@@ -241,6 +242,7 @@ describe('GlCollapsibleListbox', () => {
241
242
 
242
243
  it('should focus the first selected item', async () => {
243
244
  await showDropdown();
245
+ // eslint-disable-next-line unicorn/no-array-callback-reference
244
246
  expect(findListboxItems().at(1).find(ITEM_SELECTOR).element).toHaveFocus();
245
247
  });
246
248
 
@@ -388,9 +388,13 @@ export const Groups = makeGroupedExample({
388
388
  const isSelected = (option) => this.selected.includes(option.value);
389
389
  const notSelected = (option) => !isSelected(option);
390
390
 
391
+ // eslint-disable-next-line unicorn/no-array-callback-reference
391
392
  const selectedBranches = mockGroups[0].options.filter(isSelected);
393
+ // eslint-disable-next-line unicorn/no-array-callback-reference
392
394
  const availableBranches = mockGroups[0].options.filter(notSelected);
395
+ // eslint-disable-next-line unicorn/no-array-callback-reference
393
396
  const selectedTags = mockGroups[1].options.filter(isSelected);
397
+ // eslint-disable-next-line unicorn/no-array-callback-reference
394
398
  const availableTags = mockGroups[1].options.filter(notSelected);
395
399
 
396
400
  return [
@@ -788,9 +792,7 @@ export const InfiniteScroll = (
788
792
  InfiniteScroll.argTypes = {
789
793
  ...disableControls(['infiniteScroll', 'infiniteScrollLoading', 'items']),
790
794
  };
791
- InfiniteScroll.parameters = {
792
- storyshots: { disable: true },
793
- };
795
+ InfiniteScroll.tags = ['skip-visual-test'];
794
796
  InfiniteScroll.args = generateProps();
795
797
  InfiniteScroll.decorators = [makeContainer({ height: LISTBOX_CONTAINER_HEIGHT })];
796
798
 
@@ -3,17 +3,20 @@ import isString from 'lodash/isString';
3
3
 
4
4
  const isOption = (item) => Boolean(item) && (isString(item.value) || isNumber(item.value));
5
5
 
6
+ // eslint-disable-next-line unicorn/no-array-callback-reference
6
7
  const isGroup = ({ options } = {}) => Array.isArray(options) && options.every(isOption);
7
8
 
8
9
  const hasNoDuplicates = (array) => array.length === new Set(array).size;
9
10
 
10
11
  const flattenedOptions = (items) => items.flatMap((item) => (isOption(item) ? item : item.options));
11
12
 
13
+ // eslint-disable-next-line unicorn/no-array-callback-reference
12
14
  const isAllOptionsOrAllGroups = (items) => items.every(isOption) || items.every(isGroup);
13
15
 
14
16
  const hasUniqueValues = (items) =>
15
17
  hasNoDuplicates(flattenedOptions(items).map(({ value }) => value));
16
18
 
19
+ // eslint-disable-next-line unicorn/no-array-callback-reference
17
20
  const hasUniqueGroups = (items) => hasNoDuplicates(items.filter(isGroup).map(({ text }) => text));
18
21
 
19
22
  const itemsValidator = (items) =>
@@ -74,9 +74,7 @@ export const OnClick = (_args, { viewMode, argTypes }) => ({
74
74
  OnClick.args = generateProps({
75
75
  triggers: 'click',
76
76
  });
77
- OnClick.parameters = {
78
- storyshots: { disable: true },
79
- };
77
+ OnClick.tags = ['skip-visual-test'];
80
78
 
81
79
  export default {
82
80
  title: 'base/popover',
@@ -34,6 +34,7 @@ export default {
34
34
  type: Array,
35
35
  required: false,
36
36
  default: null,
37
+ // eslint-disable-next-line unicorn/no-array-callback-reference
37
38
  validator: (sortOptions) => sortOptions.every(isOption),
38
39
  },
39
40
  /**
@@ -225,9 +225,7 @@ export const WithScrollAndGrowing = (_args, { argTypes }) => ({
225
225
  },
226
226
  template: '<scrollable-tabs-generator :count="count" />',
227
227
  });
228
- WithScrollAndGrowing.parameters = {
229
- storyshots: { disable: true },
230
- };
228
+ WithScrollAndGrowing.tags = ['skip-visual-test'];
231
229
 
232
230
  export default {
233
231
  title: 'base/tabs',
@@ -88,7 +88,7 @@ const Template = (args, { argTypes }) => ({
88
88
  });
89
89
 
90
90
  export const Default = Template.bind({});
91
- Default.parameters = { storyshots: { disable: true } };
91
+ Default.tags = ['skip-visual-test'];
92
92
  Default.args = generateProps();
93
93
 
94
94
  export default {
@@ -189,9 +189,7 @@ export const WithCustomTooltip = (_args, { argTypes }) => ({
189
189
  `),
190
190
  });
191
191
  WithCustomTooltip.args = generateProps();
192
- WithCustomTooltip.parameters = {
193
- storyshots: { disable: true },
194
- };
192
+ WithCustomTooltip.tags = ['skip-visual-test'];
195
193
 
196
194
  export default {
197
195
  title: 'charts/area-chart',
@@ -95,9 +95,7 @@ export const Connected = Template.bind(
95
95
  `,
96
96
  }
97
97
  );
98
- Connected.parameters = {
99
- storyshots: { disable: true },
100
- };
98
+ Connected.tags = ['skip-visual-test'];
101
99
 
102
100
  export default {
103
101
  title: 'charts/chart',
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`column chart component should correctly render the chart 1`] = `
3
+ exports[`column chart component mounted should correctly render the chart 1`] = `
4
4
  Object {
5
5
  "grid": Object {
6
6
  "bottom": 44,
@@ -7,7 +7,7 @@ import {
7
7
  } from '../../../utils/charts/mock_data';
8
8
  import { toolbox } from '../../../utils/charts/story_config';
9
9
 
10
- const template = `
10
+ const template = (content = '') => `
11
11
  <gl-column-chart
12
12
  :bars="bars"
13
13
  :lines="lines"
@@ -18,7 +18,9 @@ const template = `
18
18
  :x-axis-title="xAxisTitle"
19
19
  :x-axis-type="xAxisType"
20
20
  :height="height"
21
- />
21
+ >
22
+ ${content}
23
+ </gl-column-chart>
22
24
  `;
23
25
 
24
26
  const generateProps = ({
@@ -46,7 +48,7 @@ const generateProps = ({
46
48
  const Template = (args, { argTypes }) => ({
47
49
  components: { GlColumnChart },
48
50
  props: Object.keys(argTypes),
49
- template,
51
+ template: template(),
50
52
  });
51
53
 
52
54
  export const Default = Template.bind({});
@@ -90,6 +92,19 @@ SecondaryYAxisLine.args = generateProps({
90
92
  secondaryDataTitle: 'New line data',
91
93
  });
92
94
 
95
+ export const WithCustomTooltip = (args, { argTypes }) => ({
96
+ components: { GlColumnChart },
97
+ props: Object.keys(argTypes),
98
+ template: template(`
99
+ <template #tooltip-title="{ params }">Custom tooltip title: {{params && params.value}}</template>
100
+ <template #tooltip-content="{ params }">
101
+ <div v-for="p in params && params.seriesData">Wow so custom: {{p.seriesName}}: {{p.value[1]}}</div>
102
+ </template>
103
+ `),
104
+ });
105
+ WithCustomTooltip.args = generateProps();
106
+ WithCustomTooltip.tags = ['skip-visual-test'];
107
+
93
108
  export default {
94
109
  title: 'charts/column-chart',
95
110
  component: GlColumnChart,
@@ -184,6 +184,21 @@ export default {
184
184
  v-on="$listeners"
185
185
  @created="onCreated"
186
186
  />
187
- <chart-tooltip v-if="chart" :chart="chart" :use-default-tooltip-formatter="true" />
187
+ <chart-tooltip
188
+ v-if="chart"
189
+ ref="dataTooltip"
190
+ :chart="chart"
191
+ :use-default-tooltip-formatter="true"
192
+ >
193
+ <template v-if="$scopedSlots['tooltip-title']" #title="scope">
194
+ <slot name="tooltip-title" v-bind="scope"></slot>
195
+ </template>
196
+ <template v-if="$scopedSlots['tooltip-content']" #default="scope">
197
+ <slot name="tooltip-content" v-bind="scope"></slot>
198
+ </template>
199
+ <template v-if="$scopedSlots['tooltip-value']" #tooltip-value="scope">
200
+ <slot name="tooltip-value" v-bind="scope"></slot>
201
+ </template>
202
+ </chart-tooltip>
188
203
  </div>
189
204
  </template>