@gitlab/ui 69.0.0 → 70.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/charts/area/area.js +3 -30
  3. package/dist/components/charts/bar/bar.js +2 -2
  4. package/dist/components/charts/column/column.js +2 -2
  5. package/dist/components/charts/discrete_scatter/discrete_scatter.js +1 -0
  6. package/dist/components/charts/heatmap/heatmap.js +2 -2
  7. package/dist/components/charts/line/line.js +3 -3
  8. package/dist/components/charts/stacked_column/stacked_column.js +2 -2
  9. package/dist/components/charts/tooltip/tooltip.js +121 -12
  10. package/dist/tokens/css/tokens.css +1 -1
  11. package/dist/tokens/css/tokens.dark.css +1 -1
  12. package/dist/tokens/js/tokens.dark.js +1 -1
  13. package/dist/tokens/js/tokens.js +1 -1
  14. package/dist/tokens/scss/_tokens.dark.scss +1 -1
  15. package/dist/tokens/scss/_tokens.scss +1 -1
  16. package/dist/utility_classes.css +1 -1
  17. package/dist/utility_classes.css.map +1 -1
  18. package/dist/utils/charts/constants.js +4 -12
  19. package/dist/utils/charts/theme.js +2 -3
  20. package/dist/utils/constants.js +1 -3
  21. package/package.json +8 -10
  22. package/src/components/charts/area/area.spec.js +2 -19
  23. package/src/components/charts/area/area.vue +3 -40
  24. package/src/components/charts/bar/bar.vue +2 -2
  25. package/src/components/charts/column/column.vue +2 -6
  26. package/src/components/charts/discrete_scatter/discrete_scatter.vue +1 -0
  27. package/src/components/charts/heatmap/heatmap.spec.js +1 -2
  28. package/src/components/charts/heatmap/heatmap.vue +2 -2
  29. package/src/components/charts/line/line.vue +2 -4
  30. package/src/components/charts/sparkline/sparkline.spec.js +6 -6
  31. package/src/components/charts/stacked_column/stacked_column.vue +1 -2
  32. package/src/components/charts/tooltip/tooltip.spec.js +158 -11
  33. package/src/components/charts/tooltip/tooltip.vue +117 -23
  34. package/src/scss/utilities.scss +20 -0
  35. package/src/scss/utility-mixins/spacing.scss +12 -0
  36. package/src/utils/charts/constants.js +3 -11
  37. package/src/utils/charts/theme.js +3 -2
  38. package/src/utils/constants.js +1 -3
  39. package/scss_to_js/scss_variables.js +0 -386
  40. package/scss_to_js/scss_variables.json +0 -2192
@@ -17,13 +17,6 @@ const ANNOTATIONS_SERIES_NAME = 'annotations';
17
17
  */
18
18
  const ANNOTATIONS_COMPONENT_TYPE = 'markPoint';
19
19
 
20
- /**
21
- * This is so that the mouse doesn't go over the
22
- * tooltip and call mouseout which will hide the
23
- * tooltip.
24
- */
25
- const ANNOTATION_TOOLTIP_TOP_OFFSET = 10;
26
-
27
20
  /**
28
21
  * This is a slight offset that gets applied to the left
29
22
  * of the chart tooltips to ensure a correct position.
@@ -31,11 +24,10 @@ const ANNOTATION_TOOLTIP_TOP_OFFSET = 10;
31
24
  const TOOLTIP_LEFT_OFFSET = 2;
32
25
 
33
26
  /**
34
- * This is an offset that gets applied between the mouse
35
- * cursor and the left of the chart data tooltips to provide
36
- * some spacing.
27
+ * This is a slight offset that gets applied to the left
28
+ * of the chart tooltips to ensure a correct position.
37
29
  */
38
- const DATA_TOOLTIP_LEFT_OFFSET = 10;
30
+ const TOOLTIP_TOP_OFFSET = 10;
39
31
 
40
32
  /**
41
33
  * These are the accepted values for the layout prop
@@ -68,4 +60,4 @@ const CHART_TYPE_LINE = 'line';
68
60
  const HEIGHT_AUTO_CLASSES = 'gl-chart-h-auto gl-display-flex gl-flex-direction-column gl-h-full';
69
61
  const HEIGHT_AUTO_HORIZONTAL_LAYOUT_CLASSES = 'gl-display-flex gl-h-full';
70
62
 
71
- export { ANNOTATIONS_COMPONENT_TYPE, ANNOTATIONS_SERIES_NAME, ANNOTATION_TOOLTIP_TOP_OFFSET, CHART_TYPE_BAR, CHART_TYPE_LINE, DATA_TOOLTIP_LEFT_OFFSET, HEIGHT_AUTO_CLASSES, HEIGHT_AUTO_HORIZONTAL_LAYOUT_CLASSES, LEGEND_AVERAGE_TEXT, LEGEND_CURRENT_TEXT, LEGEND_LAYOUT_INLINE, LEGEND_LAYOUT_TABLE, LEGEND_MAX_TEXT, LEGEND_MIN_TEXT, TOOLTIP_LEFT_OFFSET, arrowSymbol };
63
+ export { ANNOTATIONS_COMPONENT_TYPE, ANNOTATIONS_SERIES_NAME, CHART_TYPE_BAR, CHART_TYPE_LINE, HEIGHT_AUTO_CLASSES, HEIGHT_AUTO_HORIZONTAL_LAYOUT_CLASSES, LEGEND_AVERAGE_TEXT, LEGEND_CURRENT_TEXT, LEGEND_LAYOUT_INLINE, LEGEND_LAYOUT_TABLE, LEGEND_MAX_TEXT, LEGEND_MIN_TEXT, TOOLTIP_LEFT_OFFSET, TOOLTIP_TOP_OFFSET, arrowSymbol };
@@ -2,8 +2,7 @@ import { GRAY_600, GRAY_200, GRAY_50, GRAY_300, GRAY_100, DATA_VIZ_BLUE_200, DAT
2
2
  import { scrollHandleSvgPath } from '../svgs/svg_paths';
3
3
  import { hexToRgba } from '../utils';
4
4
 
5
- const glBorderRadiusBase = '0.25rem';
6
-
5
+ const GL_BORDER_RADIUS_BASE = '0.25rem';
7
6
  const themeName = 'gitlab';
8
7
  const heatmapHues = [GRAY_100, DATA_VIZ_BLUE_200, DATA_VIZ_BLUE_400, DATA_VIZ_BLUE_600, DATA_VIZ_BLUE_800];
9
8
  const gaugeNeutralHues = [GRAY_900, GRAY_500];
@@ -128,7 +127,7 @@ const createTheme = function () {
128
127
  borderWidth: 0,
129
128
  color: GRAY_900,
130
129
  textBackgroundColor: WHITE,
131
- textBorderRadius: glBorderRadiusBase,
130
+ textBorderRadius: GL_BORDER_RADIUS_BASE,
132
131
  textPadding: [8, 12]
133
132
  }
134
133
  },
@@ -1,7 +1,5 @@
1
1
  import { POSITION } from '../components/utilities/truncate/constants';
2
2
 
3
- const glIconSizes = '8 12 14 16 24 32 48 72';
4
-
5
3
  function appendDefaultOption(options) {
6
4
  return {
7
5
  ...options,
@@ -131,7 +129,7 @@ const datepickerWidthOptionsMap = {
131
129
  };
132
130
 
133
131
  // size options all have corresponding styles (e.g. .s12 defined in icon.scss)
134
- const iconSizeOptions = glIconSizes.split(' ').map(Number);
132
+ const iconSizeOptions = [8, 12, 14, 16, 24, 32, 48, 72];
135
133
  const triggerVariantOptions = {
136
134
  click: 'click',
137
135
  hover: 'hover',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "69.0.0",
3
+ "version": "70.0.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -17,27 +17,25 @@
17
17
  "files": [
18
18
  "src",
19
19
  "dist",
20
- "scss_to_js",
21
20
  "translations.json"
22
21
  ],
23
22
  "scripts": {
24
23
  "build": "NODE_ENV=production rollup -c",
25
- "prebuild": "run-s build-tokens build-scss-variables generate-utilities",
26
- "prepare": "run-s build-tokens build-scss-variables generate-utilities",
24
+ "prebuild": "run-s build-tokens generate-utilities",
25
+ "prepare": "run-s build-tokens generate-utilities",
27
26
  "generate-utilities": "make src/scss/utilities.scss",
28
27
  "copy-fonts": "make copy-fonts",
29
- "build-scss-variables": "make scss_to_js/scss_variables.js",
30
28
  "build-tokens": "node ./bin/build_tokens.js",
31
- "clean": "rm -r dist storybook scss_to_js/scss_variables.* src/scss/utilities.scss",
29
+ "clean": "rm -r dist storybook src/scss/utilities.scss",
32
30
  "cy:a11y": "cypress run --browser chrome --env grepTags=@a11y",
33
31
  "cy:edge": "cypress run --browser edge --env grepTags=-@a11y",
34
32
  "cy:run": "cypress run --browser firefox --env grepTags=-@a11y",
35
33
  "start": "yarn storybook",
36
34
  "storybook": "yarn storybook-prep && storybook dev --ci --host ${STORYBOOK_HOST:-localhost} --port 9001 -c .storybook",
37
35
  "storybook-vue3": "yarn storybook-prep && VUE_VERSION=3 storybook dev --ci --host ${STORYBOOK_HOST:-localhost} --port 9001 -c .storybook",
38
- "storybook-prep": "run-s copy-fonts build-tokens generate-utilities build-scss-variables",
36
+ "storybook-prep": "run-s copy-fonts build-tokens generate-utilities",
39
37
  "storybook-static": "yarn storybook-prep && storybook build -c .storybook -o storybook",
40
- "pretest:unit": "yarn build-tokens build-scss-variables",
38
+ "pretest:unit": "yarn build-tokens",
41
39
  "test": "run-s test:unit test:visual",
42
40
  "test:integration": "NODE_ENV=test start-server-and-test start http://${STORYBOOK_HOST:-localhost}:9001/iframe.html 'yarn cy:run && yarn cy:a11y'",
43
41
  "test:unit": "NODE_ENV=test jest --testPathIgnorePatterns storyshots.spec.js",
@@ -124,12 +122,12 @@
124
122
  "babel-loader": "^8.0.5",
125
123
  "babel-plugin-require-context-hook": "^1.0.0",
126
124
  "bootstrap": "4.6.2",
127
- "cypress": "13.5.0",
125
+ "cypress": "13.5.1",
128
126
  "cypress-axe": "^1.4.0",
129
127
  "cypress-real-events": "^1.11.0",
130
128
  "dompurify": "^3.0.0",
131
129
  "emoji-regex": "^10.0.0",
132
- "eslint": "8.53.0",
130
+ "eslint": "8.54.0",
133
131
  "eslint-import-resolver-jest": "3.0.2",
134
132
  "eslint-plugin-cypress": "2.15.1",
135
133
  "eslint-plugin-storybook": "0.6.15",
@@ -136,30 +136,13 @@ describe('area component', () => {
136
136
  });
137
137
  });
138
138
 
139
- describe('tooltip position', () => {
140
- const dataTooltipTitle = 'FooBar';
141
-
139
+ describe('data tooltip is set', () => {
142
140
  beforeEach(() => {
143
141
  createShallowWrapper();
144
142
  });
145
143
 
146
144
  it('is initialized', () => {
147
- expect(findDataTooltip().props('left')).toBe('0');
148
- expect(findDataTooltip().props('top')).toBe('0');
149
- expect(findDataTooltip().text()).not.toContain(dataTooltipTitle);
150
- });
151
-
152
- it('is reset when mouse moves', async () => {
153
- const left = '10px';
154
- const top = '30px';
155
-
156
- wrapper.setData({ dataTooltipPosition: { left, top }, dataTooltipTitle });
157
-
158
- await nextTick();
159
-
160
- expect(findDataTooltip().props('left')).toBe(`${left}`);
161
- expect(findDataTooltip().props('top')).toBe(`${top}`);
162
- expect(findDataTooltip().text()).toContain(dataTooltipTitle);
145
+ expect(findDataTooltip().exists()).toBe(true);
163
146
  });
164
147
  });
165
148
 
@@ -30,8 +30,6 @@ import {
30
30
  getDefaultTooltipContent,
31
31
  } from '../../../utils/charts/config';
32
32
  import {
33
- ANNOTATION_TOOLTIP_TOP_OFFSET,
34
- DATA_TOOLTIP_LEFT_OFFSET,
35
33
  LEGEND_LAYOUT_INLINE,
36
34
  LEGEND_LAYOUT_TABLE,
37
35
  LEGEND_AVERAGE_TEXT,
@@ -42,7 +40,6 @@ import {
42
40
  } from '../../../utils/charts/constants';
43
41
  import { colorFromDefaultPalette } from '../../../utils/charts/theme';
44
42
  import { seriesHasAnnotations, isDataPointAnnotation } from '../../../utils/charts/utils';
45
- import { debounceByAnimationFrame } from '../../../utils/utils';
46
43
  import TooltipDefaultFormat from '../../shared_components/charts/tooltip_default_format.vue';
47
44
  import Chart from '../chart/chart.vue';
48
45
  import ChartLegend from '../legend/legend.vue';
@@ -141,13 +138,8 @@ export default {
141
138
  // https://gitlab.com/gitlab-org/gitlab-ui/-/issues/618
142
139
  return {
143
140
  chart: null,
144
- showDataTooltip: false,
145
141
  dataTooltipTitle: '',
146
142
  dataTooltipContent: {},
147
- dataTooltipPosition: {
148
- left: '0',
149
- top: '0',
150
- },
151
143
  showAnnotationsTooltip: false,
152
144
  annotationsTooltipTitle: '',
153
145
  annotationsTooltipContent: '',
@@ -155,7 +147,6 @@ export default {
155
147
  left: '0',
156
148
  top: '0',
157
149
  },
158
- debouncedShowHideTooltip: debounceByAnimationFrame(this.showHideTooltip),
159
150
  selectedFormatTooltipText: this.formatTooltipText || this.defaultFormatTooltipText,
160
151
  };
161
152
  },
@@ -269,9 +260,6 @@ export default {
269
260
  },
270
261
  },
271
262
  beforeDestroy() {
272
- this.chart.getZr().off('mousemove', this.debouncedShowHideTooltip);
273
- this.chart.getZr().off('mouseout', this.debouncedShowHideTooltip);
274
-
275
263
  this.chart.off('mouseout', this.hideAnnotationsTooltip);
276
264
  this.chart.off('mouseover', this.onChartMouseOver);
277
265
  },
@@ -289,13 +277,6 @@ export default {
289
277
  };
290
278
  },
291
279
  onCreated(chart) {
292
- // These listeners are used to show/hide data tooltips
293
- // when the mouse is hovered over the parent container
294
- // of echarts' svg element. This works only for data points
295
- // and not markPoints.
296
- chart.getZr().on('mousemove', this.debouncedShowHideTooltip);
297
- chart.getZr().on('mouseout', this.debouncedShowHideTooltip);
298
-
299
280
  // eCharts inbuild mouse events
300
281
  // https://echarts.apache.org/en/api.html#events.Mouse%20events
301
282
  // is used to attach listeners to markPoints. These listeners
@@ -305,7 +286,6 @@ export default {
305
286
  // sections of the charts with their own mouseovers and mouseouts,
306
287
  // there shouldn't be an overlapping situation where both tooltips
307
288
  // are visible.
308
-
309
289
  if (this.hasAnnotations) {
310
290
  chart.on('mouseout', this.onChartDataPointMouseOut);
311
291
  chart.on('mouseover', this.onChartDataPointMouseOver);
@@ -314,14 +294,6 @@ export default {
314
294
  this.chart = chart;
315
295
  this.$emit('created', chart);
316
296
  },
317
- showHideTooltip({ event: mouseEvent }) {
318
- this.showDataTooltip = this.chart.containPixel('grid', [mouseEvent.zrX, mouseEvent.zrY]);
319
-
320
- this.dataTooltipPosition = {
321
- left: `${mouseEvent.zrX + DATA_TOOLTIP_LEFT_OFFSET}px`,
322
- top: `${mouseEvent.zrY}px`,
323
- };
324
- },
325
297
  onChartDataPointMouseOut() {
326
298
  this.showAnnotationsTooltip = false;
327
299
  },
@@ -340,7 +312,7 @@ export default {
340
312
  this.annotationsTooltipContent = content;
341
313
  this.annotationsTooltipPosition = {
342
314
  left: `${event.event.zrX}px`,
343
- top: `${event.event.zrY + ANNOTATION_TOOLTIP_TOP_OFFSET}px`,
315
+ top: `${event.event.zrY}px`,
344
316
  };
345
317
  }
346
318
  },
@@ -367,9 +339,9 @@ export default {
367
339
  id="annotationsTooltip"
368
340
  ref="annotationsTooltip"
369
341
  :show="showAnnotationsTooltip"
370
- :chart="chart"
371
342
  :top="annotationsTooltipPosition.top"
372
343
  :left="annotationsTooltipPosition.left"
344
+ :chart="chart"
373
345
  placement="bottom"
374
346
  >
375
347
  <template #title>
@@ -377,16 +349,7 @@ export default {
377
349
  </template>
378
350
  <div>{{ annotationsTooltipContent }}</div>
379
351
  </chart-tooltip>
380
- <chart-tooltip
381
- v-if="chart"
382
- id="dataTooltip"
383
- ref="dataTooltip"
384
- class="gl-pointer-events-none"
385
- :show="showDataTooltip"
386
- :chart="chart"
387
- :top="dataTooltipPosition.top"
388
- :left="dataTooltipPosition.left"
389
- >
352
+ <chart-tooltip v-if="chart" ref="dataTooltip" :chart="chart">
390
353
  <template #title>
391
354
  <slot v-if="formatTooltipText" name="tooltip-title"></slot>
392
355
  <template v-else>
@@ -3,7 +3,7 @@
3
3
  import merge from 'lodash/merge';
4
4
  import truncate from 'lodash/truncate';
5
5
  import { grid, dataZoomAdjustments, mergeSeriesToOptions } from '../../../utils/charts/config';
6
- import { TOOLTIP_LEFT_OFFSET, HEIGHT_AUTO_CLASSES } from '../../../utils/charts/constants';
6
+ import { HEIGHT_AUTO_CLASSES } from '../../../utils/charts/constants';
7
7
  import { colorFromDefaultPalette } from '../../../utils/charts/theme';
8
8
  import { engineeringNotation } from '../../../utils/number_utils';
9
9
  import { hexToRgba, debounceByAnimationFrame } from '../../../utils/utils';
@@ -182,7 +182,7 @@ export default {
182
182
  methods: {
183
183
  moveShowTooltip({ event: mouseEvent }) {
184
184
  this.tooltipPosition = {
185
- left: `${mouseEvent.zrX + TOOLTIP_LEFT_OFFSET}px`,
185
+ left: `${mouseEvent.zrX}px`,
186
186
  top: `${mouseEvent.zrY}px`,
187
187
  };
188
188
  this.showTooltip = this.chart.containPixel('grid', [mouseEvent.zrX, mouseEvent.zrY]);
@@ -12,11 +12,7 @@ import {
12
12
  generateBarSeries,
13
13
  generateLineSeries,
14
14
  } from '../../../utils/charts/config';
15
- import {
16
- TOOLTIP_LEFT_OFFSET,
17
- CHART_TYPE_LINE,
18
- HEIGHT_AUTO_CLASSES,
19
- } from '../../../utils/charts/constants';
15
+ import { CHART_TYPE_LINE, HEIGHT_AUTO_CLASSES } from '../../../utils/charts/constants';
20
16
  import { colorFromDefaultPalette } from '../../../utils/charts/theme';
21
17
  import { columnOptions } from '../../../utils/constants';
22
18
  import { debounceByAnimationFrame } from '../../../utils/utils';
@@ -192,7 +188,7 @@ export default {
192
188
  methods: {
193
189
  moveShowTooltip(mouseEvent) {
194
190
  this.tooltipPosition = {
195
- left: `${mouseEvent.zrX + TOOLTIP_LEFT_OFFSET}px`,
191
+ left: `${mouseEvent.zrX}px`,
196
192
  top: `${mouseEvent.zrY}px`,
197
193
  };
198
194
  this.showTooltip = this.chart.containPixel('grid', [mouseEvent.zrX, mouseEvent.zrY]);
@@ -173,6 +173,7 @@ export default {
173
173
  if (data.length) {
174
174
  const [left, top] = this.chart.convertToPixel('grid', data);
175
175
 
176
+ this.showTooltip = true;
176
177
  this.tooltipPosition = {
177
178
  left: `${left}px`,
178
179
  top: `${top}px`,
@@ -1,6 +1,5 @@
1
1
  import { shallowMount } from '@vue/test-utils';
2
2
 
3
- import { TOOLTIP_LEFT_OFFSET } from '~/utils/charts/constants';
4
3
  import { createMockChartInstance } from '~helpers/chart_stubs';
5
4
  import { expectHeightAutoClasses } from '~helpers/chart_height';
6
5
  import Chart from '../chart/chart.vue';
@@ -71,7 +70,7 @@ describe('heatmap component', () => {
71
70
  return wrapper.vm.$nextTick(() => {
72
71
  expect(mockChartInstance.convertToPixel).toHaveBeenCalledWith({ seriesId }, value);
73
72
 
74
- expect(findChartTooltip().props('left')).toBe(`${pixel[0] + TOOLTIP_LEFT_OFFSET}px`);
73
+ expect(findChartTooltip().props('left')).toBe(`${pixel[0]}px`);
75
74
  expect(findChartTooltip().props('top')).toBe(`${pixel[1]}px`);
76
75
  });
77
76
  });
@@ -3,7 +3,7 @@
3
3
  import merge from 'lodash/merge';
4
4
  import { WHITE, GRAY_100 } from '../../../../dist/tokens/js/tokens';
5
5
  import { getDefaultTooltipContent } from '../../../utils/charts/config';
6
- import { TOOLTIP_LEFT_OFFSET, HEIGHT_AUTO_CLASSES } from '../../../utils/charts/constants';
6
+ import { HEIGHT_AUTO_CLASSES } from '../../../utils/charts/constants';
7
7
  import { heatmapHues } from '../../../utils/charts/theme';
8
8
  import { engineeringNotation } from '../../../utils/number_utils';
9
9
  import { debounceByAnimationFrame } from '../../../utils/utils';
@@ -255,7 +255,7 @@ export default {
255
255
 
256
256
  this.tooltip = {
257
257
  ...this.tooltip,
258
- left: `${left + TOOLTIP_LEFT_OFFSET}px`,
258
+ left: `${left}px`,
259
259
  top: `${top}px`,
260
260
  };
261
261
  }
@@ -33,8 +33,6 @@ import {
33
33
  getDefaultTooltipContent,
34
34
  } from '../../../utils/charts/config';
35
35
  import {
36
- ANNOTATION_TOOLTIP_TOP_OFFSET,
37
- DATA_TOOLTIP_LEFT_OFFSET,
38
36
  LEGEND_LAYOUT_INLINE,
39
37
  LEGEND_LAYOUT_TABLE,
40
38
  LEGEND_AVERAGE_TEXT,
@@ -313,7 +311,7 @@ export default {
313
311
  this.showDataTooltip = this.chart.containPixel('grid', [mouseEvent.zrX, mouseEvent.zrY]);
314
312
 
315
313
  this.dataTooltipPosition = {
316
- left: `${mouseEvent.zrX + DATA_TOOLTIP_LEFT_OFFSET}px`,
314
+ left: `${mouseEvent.zrX}px`,
317
315
  top: `${mouseEvent.zrY}px`,
318
316
  };
319
317
  },
@@ -335,7 +333,7 @@ export default {
335
333
  this.annotationsTooltipContent = content;
336
334
  this.annotationsTooltipPosition = {
337
335
  left: `${event.event.zrX}px`,
338
- top: `${event.event.zrY + ANNOTATION_TOOLTIP_TOP_OFFSET}px`,
336
+ top: `${event.event.zrY}px`,
339
337
  };
340
338
  }
341
339
  },
@@ -128,25 +128,25 @@ describe('sparkline chart component', () => {
128
128
  });
129
129
 
130
130
  it('shows the tooltip when mousing over an axis point in the component', async () => {
131
- expect(getTooltip().attributes('show')).toBe(undefined);
131
+ expect(getTooltip().props('show')).toBe(false);
132
132
 
133
133
  const mockData = { seriesData: [{ data: [5, 8] }] };
134
134
  getXAxisLabelFormatter()(mockData);
135
135
 
136
136
  await wrapper.vm.$nextTick();
137
- expect(getTooltip().attributes('show')).toBe('true');
137
+ expect(getTooltip().props('show')).toBe(true);
138
138
  });
139
139
 
140
140
  it('hides the tooltip when the mouse leaves the component', async () => {
141
141
  wrapper.setData({ tooltip: { show: true } });
142
142
  await wrapper.vm.$nextTick();
143
143
 
144
- expect(getTooltip().attributes('show')).toBe('true');
144
+ expect(getTooltip().props('show')).toBe(true);
145
145
 
146
146
  wrapper.trigger('mouseleave');
147
147
  await wrapper.vm.$nextTick();
148
148
 
149
- expect(getTooltip().attributes('show')).toBe(undefined);
149
+ expect(getTooltip().props('show')).toBe(false);
150
150
  });
151
151
 
152
152
  it.each`
@@ -156,13 +156,13 @@ describe('sparkline chart component', () => {
156
156
  ${undefined} | ${0}
157
157
  ${-10} | ${undefined}
158
158
  `(`hides the tooltip when seriesData = ($label, $content)`, async ({ label, content }) => {
159
- expect(getTooltip().attributes('show')).toBe(undefined);
159
+ expect(getTooltip().props('show')).toBe(false);
160
160
 
161
161
  const mockData = { seriesData: [{ data: [label, content] }] };
162
162
  getXAxisLabelFormatter()(mockData);
163
163
 
164
164
  await wrapper.vm.$nextTick();
165
- expect(getTooltip().attributes('show')).toBe(undefined);
165
+ expect(getTooltip().props('show')).toBe(false);
166
166
  });
167
167
 
168
168
  it('adds the right content to the tooltip', async () => {
@@ -18,7 +18,6 @@ import {
18
18
  LEGEND_MIN_TEXT,
19
19
  LEGEND_MAX_TEXT,
20
20
  CHART_TYPE_LINE,
21
- ANNOTATION_TOOLTIP_TOP_OFFSET,
22
21
  HEIGHT_AUTO_CLASSES,
23
22
  } from '../../../utils/charts/constants';
24
23
  import { colorFromDefaultPalette } from '../../../utils/charts/theme';
@@ -271,7 +270,7 @@ export default {
271
270
  moveShowTooltip({ event: mouseEvent }) {
272
271
  this.tooltipPosition = {
273
272
  left: `${mouseEvent.zrX}px`,
274
- top: `${mouseEvent.zrY + ANNOTATION_TOOLTIP_TOP_OFFSET}px`,
273
+ top: `${mouseEvent.zrY}px`,
275
274
  };
276
275
  this.showTooltip = this.chart.containPixel('grid', [mouseEvent.zrX, mouseEvent.zrY]);
277
276
  },
@@ -2,6 +2,8 @@ import { shallowMount } from '@vue/test-utils';
2
2
  import { createMockChartInstance } from '~helpers/chart_stubs';
3
3
  import GlPopover from '../../base/popover/popover.vue';
4
4
  import { popoverPlacements } from '../../../utils/constants';
5
+ import { waitForAnimationFrame } from '../../../utils/test_utils';
6
+
5
7
  import ChartTooltip from './tooltip.vue';
6
8
 
7
9
  let mockChartInstance;
@@ -12,31 +14,176 @@ jest.mock('echarts', () => ({
12
14
 
13
15
  describe('ChartTooltip', () => {
14
16
  let wrapper;
17
+ let mockContainPixel;
18
+
19
+ const findPopover = () => wrapper.findComponent(GlPopover);
20
+ const findPopoverTarget = () => wrapper.find(`#${findPopover().attributes('target')}`);
21
+ const getPopoverTargetStyle = (name) => findPopoverTarget().element.style.getPropertyValue(name);
15
22
 
16
- const findGlPopover = () => wrapper.findComponent(GlPopover);
23
+ const getMouseHandler = () => mockChartInstance.getZr().on.mock.calls[0][1];
24
+ const triggerMouseHandler = async (event) => {
25
+ getMouseHandler()({ event });
26
+ await waitForAnimationFrame();
27
+ };
17
28
 
18
- const createWrapper = (props = {}) => {
19
- mockChartInstance = createMockChartInstance();
29
+ const createWrapper = (props = {}, ...options) => {
30
+ mockChartInstance = {
31
+ ...createMockChartInstance(),
32
+ containPixel: mockContainPixel,
33
+ };
20
34
  wrapper = shallowMount(ChartTooltip, {
21
35
  propsData: {
22
36
  chart: mockChartInstance,
23
37
  ...props,
24
38
  },
39
+ ...options,
25
40
  });
26
41
  };
27
42
 
28
- describe('GlPopover', () => {
29
- it('is right-positioned by default', () => {
30
- createWrapper();
43
+ beforeEach(() => {
44
+ mockContainPixel = jest.fn();
45
+ });
46
+
47
+ it('sets target as container instead of a trigger', () => {
48
+ createWrapper();
49
+
50
+ expect(findPopover().props('triggers')).toBe('');
51
+ expect(findPopover().props('container')).toEqual(findPopover().props('target'));
52
+
53
+ expect(findPopoverTarget().exists()).toBe(true);
54
+ });
55
+
56
+ it('is right-positioned by default', () => {
57
+ createWrapper();
58
+
59
+ expect(findPopover().props('placement')).toBe(popoverPlacements.right);
60
+ });
61
+
62
+ it('applies placement if any', () => {
63
+ createWrapper({ placement: popoverPlacements.bottom });
64
+
65
+ expect(findPopover().props('placement')).toBe(popoverPlacements.bottom);
66
+ });
67
+
68
+ it('applies initial position and updates it', async () => {
69
+ createWrapper({ show: true, left: '0', top: '50%' });
70
+
71
+ expect(findPopover().attributes('show')).toBe('true');
72
+ expect(getPopoverTargetStyle('left')).toBe('0px');
73
+ expect(getPopoverTargetStyle('top')).toBe('50%');
74
+
75
+ wrapper.setProps({ left: '100px', top: '200px' });
76
+
77
+ await waitForAnimationFrame();
78
+
79
+ expect(findPopover().attributes('show')).toBe('true');
80
+ expect(getPopoverTargetStyle('left')).toBe('100px');
81
+ expect(getPopoverTargetStyle('top')).toBe('200px');
82
+ });
83
+
84
+ it('reacts to `mousemove` and `mouseout` in chart dom', () => {
85
+ createWrapper();
86
+
87
+ const zr = mockChartInstance.getZr();
88
+ const handler = getMouseHandler();
89
+
90
+ expect(zr.on).toHaveBeenCalledWith('mousemove', handler);
91
+ expect(zr.on).toHaveBeenCalledWith('mouseout', handler);
92
+ });
93
+
94
+ it('tooltip target has default offset', () => {
95
+ createWrapper();
96
+
97
+ expect(getPopoverTargetStyle('margin-top')).toBe('-10px');
98
+ expect(getPopoverTargetStyle('height')).toBe('20px');
31
99
 
32
- expect(findGlPopover().props('placement')).toBe(popoverPlacements.right);
100
+ expect(getPopoverTargetStyle('margin-left')).toBe('-2px');
101
+ expect(getPopoverTargetStyle('width')).toBe('4px');
102
+ });
103
+
104
+ it('tooltip target defines offsets', () => {
105
+ const xOffset = 7;
106
+ const yOffset = 12;
107
+
108
+ createWrapper({
109
+ xOffset,
110
+ yOffset,
111
+ });
112
+
113
+ expect(getPopoverTargetStyle('margin-top')).toBe('-12px');
114
+ expect(getPopoverTargetStyle('height')).toBe('24px');
115
+
116
+ expect(getPopoverTargetStyle('margin-left')).toBe('-7px');
117
+ expect(getPopoverTargetStyle('width')).toBe('14px');
118
+ });
119
+
120
+ describe('when setting a `show` value', () => {
121
+ it('applies initial `show` value and updates it', async () => {
122
+ createWrapper({ show: true });
123
+
124
+ expect(findPopover().attributes('show')).toBe('true');
125
+
126
+ wrapper.setProps({ show: false });
127
+ await waitForAnimationFrame();
128
+
129
+ expect(findPopover().attributes('show')).toBe(undefined);
130
+ });
131
+ });
132
+
133
+ describe('when not setting a `show` value', () => {
134
+ describe('with no position defined', () => {
135
+ beforeEach(() => {
136
+ createWrapper();
137
+ });
138
+
139
+ it('when mouse moves outside of chart', async () => {
140
+ mockContainPixel.mockReturnValueOnce(false);
141
+
142
+ await triggerMouseHandler({ zrX: 1, zrY: 2.3 });
143
+
144
+ expect(mockContainPixel).toHaveBeenCalledWith('grid', [1, 2]);
145
+
146
+ expect(findPopover().attributes('show')).toBe(undefined);
147
+ });
148
+
149
+ it('when mouse moves inside chart', async () => {
150
+ mockContainPixel.mockReturnValueOnce(true);
151
+
152
+ await triggerMouseHandler({ zrX: 3, zrY: 4.3 });
153
+
154
+ expect(mockContainPixel).toHaveBeenCalledWith('grid', [3, 4]);
155
+
156
+ expect(findPopover().attributes('show')).toBe('true');
157
+ expect(getPopoverTargetStyle('left')).toBe('3px');
158
+ expect(getPopoverTargetStyle('top')).toBe('4px');
159
+ });
33
160
  });
34
161
 
35
- it('applies passed placement if any', () => {
36
- const placement = popoverPlacements.bottom;
37
- createWrapper({ placement });
162
+ describe('with position defined', () => {
163
+ beforeEach(() => {
164
+ createWrapper({ right: '50px', bottom: '100px' });
165
+ });
166
+
167
+ it('when mouse moves outside of chart', async () => {
168
+ mockContainPixel.mockReturnValueOnce(false);
169
+ await triggerMouseHandler({ zrX: 1, zrY: 2.3 });
170
+
171
+ expect(mockContainPixel).toHaveBeenCalledWith('grid', [1, 2]);
172
+ expect(findPopover().attributes('show')).toBe(undefined);
173
+ });
174
+
175
+ it('when mouse moves inside chart', async () => {
176
+ mockContainPixel.mockReturnValueOnce(true);
177
+ await triggerMouseHandler({ zrX: 3, zrY: 4.3 });
178
+
179
+ expect(mockContainPixel).toHaveBeenCalledWith('grid', [3, 4]);
180
+ expect(findPopover().attributes('show')).toBe('true');
38
181
 
39
- expect(findGlPopover().props('placement')).toBe(placement);
182
+ expect(getPopoverTargetStyle('left')).toBe('');
183
+ expect(getPopoverTargetStyle('top')).toBe('');
184
+ expect(getPopoverTargetStyle('right')).toBe('50px');
185
+ expect(getPopoverTargetStyle('bottom')).toBe('100px');
186
+ });
40
187
  });
41
188
  });
42
189
  });