@gitlab/ui 32.31.0 → 32.34.1

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 (45) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/base/filtered_search/filtered_search_suggestion_list.js +7 -2
  3. package/dist/components/base/icon/icon.js +2 -19
  4. package/dist/components/charts/area/area.js +3 -0
  5. package/dist/components/charts/bar/bar.js +2 -2
  6. package/dist/components/charts/chart/chart.js +20 -21
  7. package/dist/components/charts/legend/legend.js +1 -1
  8. package/dist/components/charts/tooltip/tooltip.js +1 -1
  9. package/dist/components/utilities/truncate/truncate.documentation.js +3 -0
  10. package/dist/components/utilities/truncate/truncate.js +34 -2
  11. package/dist/directives/resize_observer/resize_observer.documentation.js +1 -1
  12. package/dist/directives/resize_observer/resize_observer.js +43 -23
  13. package/dist/index.css +1 -1
  14. package/dist/index.css.map +1 -1
  15. package/dist/utils/charts/config.js +4 -3
  16. package/dist/utils/charts/mock_data.js +6 -3
  17. package/dist/utils/charts/theme.js +15 -9
  18. package/package.json +3 -3
  19. package/scss_to_js/scss_variables.js +0 -1
  20. package/scss_to_js/scss_variables.json +0 -5
  21. package/src/components/base/filtered_search/filtered_search_suggestion_list.spec.js +15 -8
  22. package/src/components/base/filtered_search/filtered_search_suggestion_list.vue +11 -2
  23. package/src/components/base/icon/icon.scss +1 -1
  24. package/src/components/base/icon/icon.spec.js +4 -24
  25. package/src/components/base/icon/icon.vue +1 -16
  26. package/src/components/charts/area/area.vue +3 -0
  27. package/src/components/charts/bar/__snapshots__/bar.spec.js.snap +2 -2
  28. package/src/components/charts/bar/bar.vue +2 -2
  29. package/src/components/charts/chart/chart.spec.js +3 -1
  30. package/src/components/charts/chart/chart.vue +22 -20
  31. package/src/components/charts/column/__snapshots__/column_chart.spec.js.snap +6 -6
  32. package/src/components/charts/legend/legend.vue +1 -1
  33. package/src/components/charts/stacked_column/__snapshots__/stacked_column.spec.js.snap +26 -26
  34. package/src/components/charts/tooltip/tooltip.vue +1 -1
  35. package/src/components/utilities/truncate/truncate.documentation.js +3 -0
  36. package/src/components/utilities/truncate/truncate.spec.js +8 -0
  37. package/src/components/utilities/truncate/truncate.stories.js +6 -2
  38. package/src/components/utilities/truncate/truncate.vue +57 -7
  39. package/src/directives/resize_observer/resize_observer.js +34 -19
  40. package/src/directives/resize_observer/resize_observer.md +20 -0
  41. package/src/directives/resize_observer/resize_observer.spec.js +33 -1
  42. package/src/scss/variables.scss +0 -5
  43. package/src/utils/charts/config.js +3 -2
  44. package/src/utils/charts/mock_data.js +5 -2
  45. package/src/utils/charts/theme.js +14 -9
@@ -1,6 +1,7 @@
1
1
  import { shallowMount } from '@vue/test-utils';
2
2
  import { POSITION } from './constants';
3
3
  import Truncate from './truncate.vue';
4
+ import { createMockDirective, getBinding } from '~helpers/vue_mock_directive';
4
5
 
5
6
  const removeSpecialChar = (text) => {
6
7
  return text.replace(/‎|\u200E/gi, '');
@@ -18,6 +19,9 @@ describe('Truncate component', () => {
18
19
  const createComponent = (props) => {
19
20
  wrapper = shallowMount(Truncate, {
20
21
  propsData: { ...defaultProps, ...props },
22
+ directives: {
23
+ GlTooltip: createMockDirective(),
24
+ },
21
25
  });
22
26
  };
23
27
 
@@ -45,6 +49,10 @@ describe('Truncate component', () => {
45
49
  it('should have the default position', () => {
46
50
  expect(wrapper.props('position')).toBe('end');
47
51
  });
52
+
53
+ it('disables the tooltip by default', () => {
54
+ expect(getBinding(wrapper.element, 'gl-tooltip').value.disabled).toBe(true);
55
+ });
48
56
  });
49
57
 
50
58
  describe('start truncation', () => {
@@ -1,4 +1,4 @@
1
- import { withKnobs, text, select } from '@storybook/addon-knobs';
1
+ import { withKnobs, text, select, boolean } from '@storybook/addon-knobs';
2
2
  import { documentedStoriesOf } from '../../../../documentation/documented_stories';
3
3
  import { GlTruncate } from '../../../../index';
4
4
  import { POSITION } from './constants';
@@ -8,11 +8,12 @@ const components = {
8
8
  GlTruncate,
9
9
  };
10
10
 
11
- const template = '<gl-truncate :text="text" :position="position" />';
11
+ const template = '<gl-truncate :text="text" :position="position" :with-tooltip="withTooltip" />';
12
12
 
13
13
  function generateProps({
14
14
  longText = 'src/thisIs/AVeryLongFilePath/that/needs/to/be/smartly/truncated/from/the/middle/so/we/dont/lose/important/information/here.vue',
15
15
  position = 'middle',
16
+ withTooltip = false,
16
17
  } = {}) {
17
18
  return {
18
19
  text: {
@@ -23,6 +24,9 @@ function generateProps({
23
24
  type: String,
24
25
  default: select('position', Object.values(POSITION), position),
25
26
  },
27
+ withTooltip: {
28
+ default: boolean('withTooltip', withTooltip),
29
+ },
26
30
  };
27
31
  }
28
32
 
@@ -1,7 +1,14 @@
1
1
  <script>
2
+ import { GlTooltipDirective } from '../../../directives/tooltip';
3
+ import { GlResizeObserverDirective } from '../../../directives/resize_observer/resize_observer';
2
4
  import { POSITION } from './constants';
3
5
 
4
6
  export default {
7
+ POSITION,
8
+ directives: {
9
+ GlTooltip: GlTooltipDirective,
10
+ GlResizeObserver: GlResizeObserverDirective,
11
+ },
5
12
  props: {
6
13
  text: {
7
14
  type: String,
@@ -13,10 +20,15 @@ export default {
13
20
  default: POSITION.END,
14
21
  validator: (value) => Object.values(POSITION).includes(value),
15
22
  },
23
+ withTooltip: {
24
+ type: Boolean,
25
+ required: false,
26
+ default: false,
27
+ },
16
28
  },
17
29
  data() {
18
30
  return {
19
- POSITION,
31
+ isTruncated: false,
20
32
  };
21
33
  },
22
34
  computed: {
@@ -30,24 +42,62 @@ export default {
30
42
  last() {
31
43
  return this.text.slice(this.middleIndex);
32
44
  },
45
+ isTooltipDisabled() {
46
+ return !this.withTooltip || !this.isTruncated;
47
+ },
48
+ },
49
+ watch: {
50
+ withTooltip(withTooltip) {
51
+ if (withTooltip) {
52
+ this.checkTruncationState();
53
+ }
54
+ },
55
+ },
56
+ methods: {
57
+ checkTruncationState() {
58
+ if (this.withTooltip) {
59
+ this.isTruncated = this.$refs.text.scrollWidth > this.$refs.text.offsetWidth;
60
+ }
61
+ },
33
62
  },
34
63
  };
35
64
  </script>
36
65
 
37
66
  <template>
38
67
  <!-- START -->
39
- <span v-if="position === POSITION.START" class="gl-truncate" :title="text">
40
- <span class="gl-truncate-start gl-text-overflow-ellipsis!">&lrm;{{ text }}&lrm;</span>
68
+ <span
69
+ v-if="position === $options.POSITION.START"
70
+ v-gl-tooltip="{ disabled: isTooltipDisabled }"
71
+ v-gl-resize-observer:[withTooltip]="checkTruncationState"
72
+ class="gl-truncate"
73
+ :title="text"
74
+ >
75
+ <span ref="text" class="gl-truncate-start gl-text-overflow-ellipsis!"
76
+ >&lrm;{{ text }}&lrm;</span
77
+ >
41
78
  </span>
42
79
 
43
80
  <!-- MIDDLE -->
44
- <span v-else-if="position === POSITION.MIDDLE" class="gl-truncate" :title="text">
45
- <span class="gl-truncate-end">{{ first }}</span
81
+ <span
82
+ v-else-if="position === $options.POSITION.MIDDLE"
83
+ v-gl-tooltip="{ disabled: isTooltipDisabled }"
84
+ v-gl-resize-observer:[withTooltip]="checkTruncationState"
85
+ class="gl-truncate"
86
+ :title="text"
87
+ >
88
+ <span ref="text" class="gl-truncate-end">{{ first }}</span
46
89
  ><span class="gl-truncate-start">&lrm;{{ last }}&lrm;</span>
47
90
  </span>
48
91
 
49
92
  <!-- END -->
50
- <span v-else class="gl-truncate" :title="text">
51
- <span class="gl-truncate-end">{{ text }}</span>
93
+ <span
94
+ v-else
95
+ v-gl-tooltip="{ disabled: isTooltipDisabled }"
96
+ v-gl-resize-observer:[withTooltip]="checkTruncationState"
97
+ class="gl-truncate"
98
+ data-testid="truncate-end-container"
99
+ :title="text"
100
+ >
101
+ <span ref="text" class="gl-truncate-end">{{ text }}</span>
52
102
  </span>
53
103
  </template>
@@ -2,29 +2,44 @@ import isFunction from 'lodash/isFunction';
2
2
 
3
3
  let observer = null;
4
4
 
5
- export const GlResizeObserverDirective = {
6
- bind(el, { value: resizeHandler }) {
7
- if (!isFunction(resizeHandler)) {
8
- throw TypeError('directive value must be a function');
9
- }
5
+ const attachObserver = (el, resizeHandler) => {
6
+ if (!isFunction(resizeHandler)) {
7
+ throw TypeError('directive value must be a function');
8
+ }
10
9
 
11
- if (!observer) {
12
- // the observer instance is shared for performance reasons
13
- // more information: https://github.com/WICG/ResizeObserver/issues/59
14
- observer = new ResizeObserver((entries) => {
15
- entries.forEach((event) => {
16
- event.target.glResizeHandler(event);
17
- });
10
+ if (!observer) {
11
+ // the observer instance is shared for performance reasons
12
+ // more information: https://github.com/WICG/ResizeObserver/issues/59
13
+ observer = new ResizeObserver((entries) => {
14
+ entries.forEach((event) => {
15
+ event.target.glResizeHandler(event);
18
16
  });
19
- }
17
+ });
18
+ }
19
+
20
+ el.glResizeHandler = resizeHandler;
21
+ observer.observe(el);
22
+ };
20
23
 
21
- el.glResizeHandler = resizeHandler;
22
- observer.observe(el);
24
+ const detachObserver = (el) => {
25
+ if (el.glResizeHandler) {
26
+ delete el.glResizeHandler;
27
+ observer?.unobserve(el);
28
+ }
29
+ };
30
+
31
+ export const GlResizeObserverDirective = {
32
+ bind(el, { value: resizeHandler, arg: enabled = true }) {
33
+ if (enabled) {
34
+ attachObserver(el, resizeHandler);
35
+ }
23
36
  },
24
- unbind(el) {
25
- if (el.glResizeHandler) {
26
- delete el.glResizeHandler;
27
- observer?.unobserve(el);
37
+ update(el, { value: resizeHandler, arg: enabled = true }) {
38
+ if (enabled) {
39
+ attachObserver(el, resizeHandler);
40
+ } else {
41
+ detachObserver(el);
28
42
  }
29
43
  },
44
+ unbind: detachObserver,
30
45
  };
@@ -38,3 +38,23 @@ export default {
38
38
  </div>
39
39
  </template>
40
40
  ```
41
+
42
+ The observer can be toggled on or off by passing a boolean argument to the directive:
43
+
44
+ ```html
45
+ <script>
46
+ export default {
47
+ data() {
48
+ return {
49
+ shouldObserve: true,
50
+ };
51
+ },
52
+ methods: {
53
+ handleResize() {},
54
+ },
55
+ };
56
+ </script>
57
+ <template>
58
+ <div v-gl-resize-observer-directive[shouldObserve]="handleResize"></div>
59
+ </template>
60
+ ```
@@ -10,7 +10,7 @@ describe('resize observer directive', () => {
10
10
  const localVue = createLocalVue();
11
11
  let wrapper;
12
12
 
13
- const createComponent = ({ template } = {}) => {
13
+ const createComponent = ({ template, data = {} } = {}) => {
14
14
  const defaultTemplate = `<div v-resize-observer="handleResize"></div>`;
15
15
 
16
16
  const component = {
@@ -21,6 +21,9 @@ describe('resize observer directive', () => {
21
21
  handleResize: mockHandleResize,
22
22
  },
23
23
  template: template || defaultTemplate,
24
+ data() {
25
+ return data;
26
+ },
24
27
  };
25
28
 
26
29
  wrapper = shallowMount(component, { localVue });
@@ -52,6 +55,13 @@ describe('resize observer directive', () => {
52
55
  expect(observesElement(wrapper.element)).toBe(true);
53
56
  });
54
57
 
58
+ it('does not subscribe if the argument is false', () => {
59
+ createComponent({ template: '<div v-resize-observer:[false]="handleResize"></div>' });
60
+
61
+ expect(observersCount()).toBe(0);
62
+ expect(observesElement(wrapper.element)).toBe(false);
63
+ });
64
+
55
65
  it('passes the first entries "contentRect" and "target" to the given handler', () => {
56
66
  createComponent();
57
67
 
@@ -61,6 +71,28 @@ describe('resize observer directive', () => {
61
71
  expect(mockHandleResize).toHaveBeenCalledWith({ contentRect: {}, target: wrapper.element });
62
72
  });
63
73
 
74
+ it("detaches then reattaches observer based on argument's value", async () => {
75
+ expect(observersCount()).toBe(0);
76
+
77
+ createComponent({
78
+ template: '<div v-resize-observer:[isEnabled]="handleResize"></div>',
79
+ data: {
80
+ isEnabled: true,
81
+ },
82
+ });
83
+
84
+ expect(observersCount()).toBe(1);
85
+ expect(wrapper.element.glResizeHandler).not.toBeFalsy();
86
+
87
+ await wrapper.setData({ isEnabled: false });
88
+
89
+ expect(wrapper.element.glResizeHandler).toBeFalsy();
90
+
91
+ await wrapper.setData({ isEnabled: true });
92
+
93
+ expect(wrapper.element.glResizeHandler).not.toBeFalsy();
94
+ });
95
+
64
96
  it('does a clean up when the component is destroyed', () => {
65
97
  createComponent();
66
98
 
@@ -427,12 +427,7 @@ $gl-icon-chevron-down: 'data:image/svg+xml;utf8,<svg viewBox="0 0 16 16" xmlns="
427
427
 
428
428
  // Icons
429
429
  $default-icon-size: px-to-rem(16px);
430
- // $gl-deprecated-icon-sizes is used for css classes generation as there are still instances around codebase
431
- // where $gl-icon-sizes is a new list of supported icon sizes and will be used for icon size validation
432
- // $gl-deprecated-icon-sizes should be replaced with $gl-icon-sizes in scope
433
- // of this issue https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1232
434
430
  $gl-icon-sizes: 8 12 14 16 24 32 48 72;
435
- $gl-deprecated-icon-sizes: join($gl-icon-sizes, 10 18);
436
431
 
437
432
  // Dropdowns
438
433
  $gl-dropdown-width: px-to-rem(240px);
@@ -12,6 +12,7 @@ import { ANNOTATIONS_SERIES_NAME, arrowSymbol, CHART_TYPE_BAR, CHART_TYPE_LINE }
12
12
  export const defaultAreaOpacity = 0.2;
13
13
  export const defaultFontSize = 12;
14
14
  export const defaultHeight = 400;
15
+ export const defaultWidth = 300;
15
16
  export const validRenderers = ['canvas', 'svg'];
16
17
 
17
18
  export const axes = {
@@ -433,8 +434,8 @@ export const generateBarSeries = ({
433
434
  yAxisIndex,
434
435
  itemStyle: {
435
436
  color: hexToRgba(color, 0.2),
436
- barBorderColor: color,
437
- barBorderWidth: 1,
437
+ borderColor: color,
438
+ borderWidth: 1,
438
439
  },
439
440
  emphasis: {
440
441
  itemStyle: {
@@ -43,6 +43,9 @@ export const mockDefaultChartOptions = {
43
43
  axisPointer: {
44
44
  show: true,
45
45
  label: {},
46
+ lineStyle: {
47
+ type: 'solid',
48
+ },
46
49
  },
47
50
  },
48
51
  yAxis: {
@@ -204,8 +207,8 @@ export const mockDefaultBarChartConfig = {
204
207
  yAxisIndex: 0,
205
208
  itemStyle: {
206
209
  color: hexToRgba(color, 0.2),
207
- barBorderColor: color,
208
- barBorderWidth: 1,
210
+ borderColor: color,
211
+ borderWidth: 1,
209
212
  },
210
213
  emphasis: {
211
214
  itemStyle: {
@@ -105,15 +105,14 @@ const axes = {
105
105
  margin: 8,
106
106
  show: true,
107
107
  color: gray600,
108
- textStyle: {
109
- color: gray600,
110
- },
108
+ hideOverlap: true,
111
109
  },
112
110
  axisLine: {
113
111
  show: false,
114
112
  },
115
113
  axisPointer: {
116
114
  lineStyle: {
115
+ type: 'solid',
117
116
  color: gray600,
118
117
  },
119
118
  label: {
@@ -175,6 +174,7 @@ const createTheme = (options = {}) => ({
175
174
  dataZoom: {
176
175
  borderColor: 'transparent',
177
176
  filterMode: 'none',
177
+ brushSelect: false,
178
178
  dataBackground: {
179
179
  lineStyle: {
180
180
  width: 2,
@@ -184,7 +184,7 @@ const createTheme = (options = {}) => ({
184
184
  // render unfilled zoom-graph if the series is a line chart without area styles
185
185
  // more details: https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2364#note_666637306
186
186
  areaStyle: isLineChartWithoutArea(options)
187
- ? null
187
+ ? {} // Use empty object instead of null, see https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2185#note_707711029 for more context
188
188
  : {
189
189
  color: gray50,
190
190
  opacity: 1,
@@ -192,7 +192,10 @@ const createTheme = (options = {}) => ({
192
192
  },
193
193
  fillerColor: hexToRgba(gray200, 0.23),
194
194
  handleIcon: scrollHandleSvgPath,
195
- handleColor: gray500,
195
+ handleStyle: {
196
+ borderColor: 'transparent',
197
+ color: gray500,
198
+ },
196
199
  handleSize: '50%',
197
200
  labelFormatter: () => null,
198
201
  textStyle: {
@@ -203,14 +206,16 @@ const createTheme = (options = {}) => ({
203
206
  top: '-5',
204
207
  left: 'center',
205
208
  itemSize: 14,
206
- iconStyle: {
207
- color: gray200,
208
- borderWidth: 0,
209
- emphasis: {
209
+ emphasis: {
210
+ iconStyle: {
210
211
  borderWidth: 0,
211
212
  color: gray700,
212
213
  },
213
214
  },
215
+ iconStyle: {
216
+ color: gray200,
217
+ borderWidth: 0,
218
+ },
214
219
  itemGap: 8,
215
220
  feature: {
216
221
  dataZoom: {