@gitlab/ui 58.4.0 → 58.5.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 (86) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/base/filtered_search/filtered_search_token_segment.js +1 -1
  3. package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.js +9 -1
  4. package/dist/components/base/new_dropdowns/listbox/listbox.js +17 -12
  5. package/dist/components/charts/chart/chart.js +5 -1
  6. package/dist/index.css +1 -1
  7. package/dist/index.css.map +1 -1
  8. package/package.json +8 -4
  9. package/src/components/base/alert/alert.stories.js +2 -1
  10. package/src/components/base/avatar/avatar.stories.js +1 -1
  11. package/src/components/base/avatar_labeled/avatar_labeled.stories.js +3 -1
  12. package/src/components/base/avatar_link/avatar_link.stories.js +3 -1
  13. package/src/components/base/avatars_inline/avatars_inline.stories.js +4 -1
  14. package/src/components/base/badge/badge.stories.js +1 -1
  15. package/src/components/base/banner/banner.stories.js +2 -1
  16. package/src/components/base/breadcrumb/breadcrumb.stories.js +1 -1
  17. package/src/components/base/broadcast_message/broadcast_message.stories.js +1 -1
  18. package/src/components/base/button/button.stories.js +7 -9
  19. package/src/components/base/button_group/button_group.stories.js +4 -1
  20. package/src/components/base/collapse/collapse.stories.js +3 -1
  21. package/src/components/base/datepicker/datepicker.stories.js +2 -1
  22. package/src/components/base/drawer/drawer.stories.js +3 -1
  23. package/src/components/base/dropdown/dropdown.stories.js +10 -12
  24. package/src/components/base/dropdown/dropdown_item.stories.js +1 -1
  25. package/src/components/base/filtered_search/filtered_search.stories.js +15 -13
  26. package/src/components/base/filtered_search/filtered_search_suggestion.stories.js +1 -1
  27. package/src/components/base/filtered_search/filtered_search_suggestion_list.stories.js +2 -1
  28. package/src/components/base/filtered_search/filtered_search_token.stories.js +1 -1
  29. package/src/components/base/filtered_search/filtered_search_token_segment.stories.js +1 -1
  30. package/src/components/base/filtered_search/filtered_search_token_segment.vue +1 -0
  31. package/src/components/base/form/form.stories.js +7 -9
  32. package/src/components/base/form/form_checkbox/form_checkbox.stories.js +2 -1
  33. package/src/components/base/form/form_group/form_group.stories.js +3 -1
  34. package/src/components/base/form/form_input/form_input.stories.js +1 -1
  35. package/src/components/base/form/form_input_group/form_input_group.stories.js +2 -1
  36. package/src/components/base/form/form_radio/form_radio.stories.js +1 -1
  37. package/src/components/base/form/form_radio_group/form_radio_group.stories.js +2 -1
  38. package/src/components/base/form/form_select/form_select.stories.js +2 -2
  39. package/src/components/base/form/form_textarea/form_textarea.stories.js +1 -1
  40. package/src/components/base/icon/icon.stories.js +1 -1
  41. package/src/components/base/infinite_scroll/infinite_scroll.stories.js +2 -1
  42. package/src/components/base/label/label.stories.js +1 -1
  43. package/src/components/base/link/link.stories.js +1 -1
  44. package/src/components/base/loading_icon/loading_icon.stories.js +1 -1
  45. package/src/components/base/modal/modal.stories.js +3 -1
  46. package/src/components/base/nav/nav.stories.js +6 -8
  47. package/src/components/base/navbar/navbar.stories.js +1 -1
  48. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.scss +10 -0
  49. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.stories.js +9 -11
  50. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.spec.js +33 -0
  51. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.vue +8 -2
  52. package/src/components/base/new_dropdowns/listbox/listbox.stories.js +7 -9
  53. package/src/components/base/new_dropdowns/listbox/listbox.vue +24 -21
  54. package/src/components/base/paginated_list/paginated_list.stories.js +2 -1
  55. package/src/components/base/pagination/pagination.stories.js +7 -10
  56. package/src/components/base/path/path.stories.js +2 -1
  57. package/src/components/base/popover/popover.stories.js +2 -1
  58. package/src/components/base/progress_bar/progress_bar.stories.js +1 -1
  59. package/src/components/base/search_box_by_click/search_box_by_click.stories.js +1 -1
  60. package/src/components/base/search_box_by_type/search_box_by_type.stories.js +1 -1
  61. package/src/components/base/segmented_control/segmented_control.stories.js +1 -1
  62. package/src/components/base/skeleton_loader/skeleton_loader.stories.js +1 -1
  63. package/src/components/base/skeleton_loading/skeleton_loading.stories.js +1 -1
  64. package/src/components/base/sorting/sorting.stories.js +2 -1
  65. package/src/components/base/sorting/sorting_item.stories.js +2 -1
  66. package/src/components/base/table/table.stories.js +2 -1
  67. package/src/components/base/tabs/tabs/tabs.stories.js +5 -2
  68. package/src/components/base/toast/toast.stories.js +2 -1
  69. package/src/components/base/toggle/toggle.stories.js +1 -1
  70. package/src/components/base/token/token.stories.js +2 -1
  71. package/src/components/base/tooltip/tooltip.stories.js +3 -1
  72. package/src/components/charts/chart/chart.stories.js +3 -2
  73. package/src/components/charts/chart/chart.vue +5 -1
  74. package/src/components/regions/dashboard_skeleton/dashboard_skeleton.stories.js +1 -1
  75. package/src/components/regions/empty_state/empty_state.stories.js +2 -1
  76. package/src/components/utilities/friendly_wrap/friendly_wrap.stories.js +1 -1
  77. package/src/components/utilities/intersection_observer/intersection_observer.stories.js +1 -1
  78. package/src/components/utilities/intersperse/intersperse.stories.js +1 -1
  79. package/src/components/utilities/sprintf/sprintf.stories.js +3 -1
  80. package/src/components/utilities/truncate/truncate.spec.js +16 -1
  81. package/src/components/utilities/truncate/truncate.stories.js +1 -1
  82. package/src/components/utilities/truncate/truncate.vue +0 -3
  83. package/src/directives/hover_load/hover_load.stories.js +1 -1
  84. package/src/directives/outside/outside.stories.js +1 -1
  85. package/src/directives/resize_observer/resize_observer.stories.js +1 -1
  86. package/src/directives/safe_html/safe_html.stories.js +1 -1
@@ -41,6 +41,10 @@ describe('GlDisclosureDropdownItem', () => {
41
41
  expect(emittedAction).toHaveLength(1);
42
42
  expect(emittedAction).toEqual([[item]]);
43
43
  });
44
+
45
+ it('sets tabIndex on li element', () => {
46
+ expect(findItem().attributes('tabindex')).toBe('0');
47
+ });
44
48
  });
45
49
 
46
50
  describe('when item has a `href`', () => {
@@ -82,6 +86,10 @@ describe('GlDisclosureDropdownItem', () => {
82
86
  expect(emittedAction).toHaveLength(1);
83
87
  expect(emittedAction).toEqual([[item]]);
84
88
  });
89
+
90
+ it('sets tabIndex on link element', () => {
91
+ expect(findLink().attributes('tabindex')).toBe('-1');
92
+ });
85
93
  });
86
94
 
87
95
  describe('when item has an `action`', () => {
@@ -138,6 +146,10 @@ describe('GlDisclosureDropdownItem', () => {
138
146
  it('should apply the default classes to the item wrapper', () => {
139
147
  expect(findItem().classes()).toEqual(['gl-new-dropdown-item']);
140
148
  });
149
+
150
+ it('sets tabIndex on link element', () => {
151
+ expect(findButton().attributes('tabindex')).toBe('-1');
152
+ });
141
153
  });
142
154
 
143
155
  describe('when item has wrapperClass', () => {
@@ -155,4 +167,25 @@ describe('GlDisclosureDropdownItem', () => {
155
167
  expect(findItem().classes()).toContain(TEST_CLASS);
156
168
  });
157
169
  });
170
+
171
+ describe('when item has disabled attribute', () => {
172
+ const extraAttrs = {
173
+ disabled: true,
174
+ };
175
+ beforeEach(() => {
176
+ buildWrapper({
177
+ item: {
178
+ ...mockItems[1],
179
+ extraAttrs,
180
+ },
181
+ });
182
+ });
183
+
184
+ it('should not set tabIndex to elements', () => {
185
+ const findButton = () => wrapper.find('button[type="button"].gl-new-dropdown-item-content');
186
+
187
+ expect(findItem().attributes('tabindex')).toBeUndefined();
188
+ expect(findButton().attributes('tabindex')).toBeUndefined();
189
+ });
190
+ });
158
191
  });
@@ -55,6 +55,12 @@ export default {
55
55
  wrapperClass: item?.wrapperClass,
56
56
  };
57
57
  },
58
+ listIndex() {
59
+ return this.item?.extraAttrs?.disabled ? null : 0;
60
+ },
61
+ componentIndex() {
62
+ return this.item?.extraAttrs?.disabled ? null : -1;
63
+ },
58
64
  wrapperListeners() {
59
65
  const listeners = {
60
66
  keydown: this.onKeydown,
@@ -94,7 +100,7 @@ export default {
94
100
 
95
101
  <template>
96
102
  <li
97
- tabindex="0"
103
+ :tabindex="listIndex"
98
104
  :class="[$options.ITEM_CLASS, itemComponent.wrapperClass]"
99
105
  data-testid="disclosure-dropdown-item"
100
106
  v-on="wrapperListeners"
@@ -105,7 +111,7 @@ export default {
105
111
  v-bind="itemComponent.attrs"
106
112
  ref="item"
107
113
  class="gl-new-dropdown-item-content"
108
- tabindex="-1"
114
+ :tabindex="componentIndex"
109
115
  v-on="itemComponent.listeners"
110
116
  >
111
117
  <span class="gl-new-dropdown-item-text-wrapper">
@@ -4,15 +4,12 @@ import {
4
4
  buttonVariantOptions,
5
5
  dropdownPlacements,
6
6
  } from '../../../../utils/constants';
7
- import {
8
- GlIcon,
9
- GlCollapsibleListbox,
10
- GlSearchBoxByType,
11
- GlButtonGroup,
12
- GlButton,
13
- GlBadge,
14
- GlAvatar,
15
- } from '../../../../index';
7
+ import GlIcon from '../../icon/icon.vue';
8
+ import GlSearchBoxByType from '../../search_box_by_type/search_box_by_type.vue';
9
+ import GlButtonGroup from '../../button_group/button_group.vue';
10
+ import GlButton from '../../button/button.vue';
11
+ import GlBadge from '../../badge/badge.vue';
12
+ import GlAvatar from '../../avatar/avatar.vue';
16
13
  import { makeContainer } from '../../../../utils/story_decorators/container';
17
14
  import { setStoryTimeout } from '../../../../utils/test_utils';
18
15
  import { disableControls } from '../../../../utils/stories_utils';
@@ -26,6 +23,7 @@ import {
26
23
  import readme from './listbox.md';
27
24
  import { mockOptions, mockGroups, mockUsers } from './mock_data';
28
25
  import { flattenedOptions } from './utils';
26
+ import GlCollapsibleListbox from './listbox.vue';
29
27
 
30
28
  const defaultValue = (prop) => GlCollapsibleListbox.props[prop].default;
31
29
 
@@ -366,7 +366,7 @@ export default {
366
366
  immediate: true,
367
367
  handler(newSelected) {
368
368
  if (Array.isArray(newSelected)) {
369
- if (!this.multiple && newSelected.length) {
369
+ if (process.env.NODE_ENV !== 'production' && !this.multiple && newSelected.length) {
370
370
  throw new Error('To allow multi-selection, please, set "multiple" property to "true"');
371
371
  }
372
372
  this.selectedValues = [...newSelected];
@@ -375,27 +375,30 @@ export default {
375
375
  }
376
376
  },
377
377
  },
378
- resetButtonLabel: {
379
- immediate: true,
380
- handler(newResetButtonLabel) {
381
- if (process.env.NODE_ENV !== 'production' && newResetButtonLabel && !this.headerText) {
382
- throw new Error(
383
- 'The reset button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the resetButtonLabel prop.'
384
- );
378
+ ...(process.env.NODE_ENV !== 'production'
379
+ ? {
380
+ resetButtonLabel: {
381
+ immediate: true,
382
+ handler(newResetButtonLabel) {
383
+ if (newResetButtonLabel && !this.headerText) {
384
+ throw new Error(
385
+ 'The reset button cannot be rendered without a header. Either provide a header via the headerText prop, or do not provide the resetButtonLabel prop.'
386
+ );
387
+ }
388
+ },
389
+ },
390
+ infiniteScroll: {
391
+ immediate: true,
392
+ handler(newValue) {
393
+ if (newValue && this.items.some((item) => !isOption(item))) {
394
+ throw new Error(
395
+ 'Infinite scroll does not support groups. Please set the "infiniteScroll" prop to "false"'
396
+ );
397
+ }
398
+ },
399
+ },
385
400
  }
386
- },
387
- },
388
- },
389
- created() {
390
- if (
391
- process.env.NODE_ENV !== 'production' &&
392
- this.infiniteScroll &&
393
- this.items.some((item) => !isOption(item))
394
- ) {
395
- throw new Error(
396
- 'Infinite scroll does not support groups. Please set the "infiniteScroll" prop to "false"'
397
- );
398
- }
401
+ : {}),
399
402
  },
400
403
  methods: {
401
404
  open() {
@@ -1,4 +1,5 @@
1
- import { GlPaginatedList, GlButton } from '../../../index';
1
+ import GlButton from '../button/button.vue';
2
+ import GlPaginatedList from './paginated_list.vue';
2
3
  import readme from './paginated_list.md';
3
4
 
4
5
  const sampleList = [
@@ -71,15 +71,6 @@ export const Compact = (args, { argTypes }) => ({
71
71
  components,
72
72
  props: Object.keys(argTypes),
73
73
  ...defaults(args),
74
- computed: {
75
- prevPage() {
76
- return Math.max(this.page - 1, 0);
77
- },
78
- nextPage() {
79
- const nextPage = this.page + 1;
80
- return nextPage > 3 ? 0 : nextPage;
81
- },
82
- },
83
74
  template: `
84
75
  <div class="text-center gl-font-base">
85
76
  ${template}
@@ -87,7 +78,13 @@ export const Compact = (args, { argTypes }) => ({
87
78
  </div>
88
79
  `,
89
80
  });
90
- Compact.args = generateProps({ page: 1, totalItems: 0, align: alignOptions.center });
81
+ Compact.args = generateProps({
82
+ page: 1,
83
+ prevPage: 0,
84
+ nextPage: 2,
85
+ totalItems: 0,
86
+ align: alignOptions.center,
87
+ });
91
88
 
92
89
  export const LinkBased = (args, { argTypes }) => ({
93
90
  components,
@@ -1,5 +1,6 @@
1
- import { GlPath, GlPopover } from '../../../index';
1
+ import GlPopover from '../popover/popover.vue';
2
2
  import { glThemes } from '../../../utils/constants';
3
+ import GlPath from './path.vue';
3
4
  import { mockPathItems } from './data';
4
5
  import readme from './path.md';
5
6
 
@@ -1,5 +1,6 @@
1
- import { GlPopover, GlButton } from '../../../index';
1
+ import GlButton from '../button/button.vue';
2
2
  import { popoverPlacements } from '../../../utils/constants';
3
+ import GlPopover from './popover.vue';
3
4
 
4
5
  const defaultValue = (prop) => GlPopover.props[prop].default;
5
6
 
@@ -1,5 +1,5 @@
1
- import { GlProgressBar } from '../../../index';
2
1
  import { variantOptions } from '../../../utils/constants';
2
+ import GlProgressBar from './progress_bar.vue';
3
3
 
4
4
  const generateProps = ({ value = 30, variant = variantOptions.primary } = {}) => ({
5
5
  value,
@@ -1,5 +1,5 @@
1
- import { GlSearchBoxByClick } from '../../../index';
2
1
  import { disableControls } from '../../../utils/stories_utils';
2
+ import GlSearchBoxByClick from './search_box_by_click.vue';
3
3
  import readme from './search_box_by_click.md';
4
4
 
5
5
  const template = `
@@ -1,5 +1,5 @@
1
- import { GlSearchBoxByType } from '../../../index';
2
1
  import { disableControls } from '../../../utils/stories_utils';
2
+ import GlSearchBoxByType from './search_box_by_type.vue';
3
3
  import readme from './search_box_by_type.md';
4
4
 
5
5
  const template = `
@@ -1,4 +1,4 @@
1
- import { GlSegmentedControl } from '../../../index';
1
+ import GlSegmentedControl from './segmented_control.vue';
2
2
  import readme from './segmented_control.md';
3
3
 
4
4
  const defaultOptions = [
@@ -1,5 +1,5 @@
1
- import { GlSkeletonLoader } from '../../../index';
2
1
  import { makeContainer } from '../../../utils/story_decorators/container';
2
+ import GlSkeletonLoader from './skeleton_loader.vue';
3
3
  import readme from './skeleton_loader.md';
4
4
 
5
5
  const defaultValue = (prop) => GlSkeletonLoader.props[prop].default;
@@ -1,4 +1,4 @@
1
- import { GlDeprecatedSkeletonLoading } from '../../../index';
1
+ import GlDeprecatedSkeletonLoading from './skeleton_loading.vue';
2
2
  import readme from './skeleton_loading.md';
3
3
 
4
4
  const components = {
@@ -1,5 +1,6 @@
1
- import { GlSorting, GlSortingItem } from '../../../index';
2
1
  import { makeContainer } from '../../../utils/story_decorators/container';
2
+ import GlSortingItem from './sorting_item.vue';
3
+ import GlSorting from './sorting.vue';
3
4
  import readme from './sorting.md';
4
5
 
5
6
  const components = {
@@ -1,5 +1,6 @@
1
- import { GlSorting, GlSortingItem } from '../../../index';
2
1
  import { makeContainer } from '../../../utils/story_decorators/container';
2
+ import GlSortingItem from './sorting_item.vue';
3
+ import GlSorting from './sorting.vue';
3
4
  import readme from './sorting_item.md';
4
5
 
5
6
  const components = {
@@ -1,4 +1,5 @@
1
- import { GlTable, GlFormInput } from '../../../index';
1
+ import GlFormInput from '../form/form_input/form_input.vue';
2
+ import GlTable from './table.vue';
2
3
  import readme from './table.md';
3
4
 
4
5
  const components = { GlTable };
@@ -1,6 +1,9 @@
1
1
  import range from 'lodash/range';
2
- import { GlTabs, GlTab, GlScrollableTabs, GlBadge } from '../../../../index';
2
+ import GlBadge from '../../badge/badge.vue';
3
3
  import { badgeVariantOptions } from '../../../../utils/constants';
4
+ import GlTab from '../tab/tab.vue';
5
+ import GlScrollableTabs from './scrollable_tabs.vue';
6
+ import GlTabs from './tabs.vue';
4
7
  import readme from './tabs.md';
5
8
 
6
9
  const components = {
@@ -153,7 +156,7 @@ export const WithCounterBadges = (_args, { argTypes }) => ({
153
156
  props: Object.keys(argTypes),
154
157
  components: { ...components, GlBadge },
155
158
  template: wrap(`
156
- <gl-tab
159
+ <gl-tab
157
160
  v-for="variant in $options.badgeVariantOptions"
158
161
  :key="variant"
159
162
  >
@@ -1,5 +1,6 @@
1
1
  import Vue from 'vue';
2
- import { GlToast, GlButton } from '../../../index';
2
+ import GlButton from '../button/button.vue';
3
+ import GlToast from './toast';
3
4
  import readme from './toast.md';
4
5
 
5
6
  Vue.use(GlToast);
@@ -1,6 +1,6 @@
1
- import { GlToggle } from '../../../index';
2
1
  import { toggleLabelPosition } from '../../../utils/constants';
3
2
  import { disableControls } from '../../../utils/stories_utils';
3
+ import GlToggle from './toggle.vue';
4
4
  import readme from './toggle.md';
5
5
 
6
6
  const defaultValue = (prop) => GlToggle.props[prop].default;
@@ -1,5 +1,6 @@
1
- import { GlToken, GlAvatar } from '../../../index';
1
+ import GlAvatar from '../avatar/avatar.vue';
2
2
  import { tokenVariants } from '../../../utils/constants';
3
+ import GlToken from './token.vue';
3
4
 
4
5
  import readme from './token.md';
5
6
 
@@ -1,4 +1,6 @@
1
- import { GlTooltip, GlTooltipDirective, GlButton } from '../../../index';
1
+ import { GlTooltipDirective } from '../../../directives/tooltip';
2
+ import GlButton from '../button/button.vue';
3
+ import GlTooltip from './tooltip.vue';
2
4
  import readme from './tooltip.md';
3
5
 
4
6
  function makeTooltip(modifier = '') {
@@ -1,5 +1,6 @@
1
- import { GlChart } from '../../../charts';
2
- import { GlTabs, GlTab } from '../../../index';
1
+ import GlTabs from '../../base/tabs/tabs/tabs.vue';
2
+ import GlTab from '../../base/tabs/tab/tab.vue';
3
+ import GlChart from './chart.vue';
3
4
  import readme from './chart.md';
4
5
 
5
6
  const Template = (args, { argTypes = {} }) => ({
@@ -124,11 +124,15 @@ export default {
124
124
  async mounted() {
125
125
  await this.$nextTick();
126
126
 
127
- this.chart = echarts.init(this.$refs.chart, this.disableTheme ? null : themeName, {
127
+ const chart = echarts.init(this.$refs.chart, this.disableTheme ? null : themeName, {
128
128
  renderer: this.renderer,
129
129
  width: defaultWidth,
130
130
  height: defaultHeight,
131
131
  });
132
+ // FIXME: temporary workaround to ensure compatibility with @vue/compat
133
+ // eslint-disable-next-line no-underscore-dangle
134
+ chart.__v_skip = true;
135
+ this.chart = chart;
132
136
 
133
137
  if (this.groupId.length) {
134
138
  this.chart.group = this.groupId;
@@ -1,4 +1,4 @@
1
- import { GlDashboardSkeleton } from '../../../index';
1
+ import GlDashboardSkeleton from './dashboard_skeleton.vue';
2
2
  import readme from './dashboard_skeleton.md';
3
3
 
4
4
  const defaultValue = (prop) => GlDashboardSkeleton.props[prop].default;
@@ -1,6 +1,7 @@
1
1
  import securityDashboardEmptyStateSvg from '@gitlab/svgs/dist/illustrations/security-dashboard-empty-state.svg';
2
2
  import issuesSvg from '@gitlab/svgs/dist/illustrations/issues.svg';
3
- import { GlButton, GlEmptyState } from '../../../index';
3
+ import GlButton from '../../base/button/button.vue';
4
+ import GlEmptyState from './empty_state.vue';
4
5
  import readme from './empty_state.md';
5
6
 
6
7
  const template = `
@@ -1,4 +1,4 @@
1
- import { GlFriendlyWrap } from '../../../index';
1
+ import GlFriendlyWrap from './friendly_wrap.vue';
2
2
  import readme from './friendly_wrap.md';
3
3
 
4
4
  const components = {
@@ -1,4 +1,4 @@
1
- import { GlIntersectionObserver } from '../../../index';
1
+ import GlIntersectionObserver from './intersection_observer.vue';
2
2
  import readme from './intersection_observer.md';
3
3
 
4
4
  const components = {
@@ -1,4 +1,4 @@
1
- import { GlIntersperse } from '../../../index';
1
+ import GlIntersperse from './intersperse.vue';
2
2
  import readme from './intersperse.md';
3
3
 
4
4
  const template = `
@@ -1,4 +1,6 @@
1
- import { GlSprintf, GlButton, GlLink } from '../../../index';
1
+ import GlButton from '../../base/button/button.vue';
2
+ import GlLink from '../../base/link/link.vue';
3
+ import GlSprintf from './sprintf.vue';
2
4
  import readme from './sprintf.md';
3
5
 
4
6
  const generateProps = ({ message = 'Written by %{author}', placeholders } = {}) => ({
@@ -16,9 +16,12 @@ describe('Truncate component', () => {
16
16
  text: 'ee/app/assets/javascripts/vue_shared/src/utils_reports/components/utils/index.js',
17
17
  };
18
18
 
19
- const createComponent = (props) => {
19
+ const createComponent = ({ classes, ...props } = {}) => {
20
20
  wrapper = shallowMount(Truncate, {
21
21
  propsData: { ...defaultProps, ...props },
22
+ attrs: {
23
+ class: classes,
24
+ },
22
25
  });
23
26
  };
24
27
 
@@ -107,4 +110,16 @@ describe('Truncate component', () => {
107
110
  expect(wrapper.find('.gl-truncate-end').exists()).toBe(true);
108
111
  });
109
112
  });
113
+
114
+ // This tests a workaround for a subtle Vue 2/3 compiler difference.
115
+ // See https://github.com/vuejs/core/issues/7909.
116
+ describe('parent classes', () => {
117
+ beforeEach(() => {
118
+ createComponent({ classes: 'test-class' });
119
+ });
120
+
121
+ it('applies classes from parent', () => {
122
+ expect(wrapper.classes()).toContain('test-class');
123
+ });
124
+ });
110
125
  });
@@ -1,4 +1,4 @@
1
- import { GlTruncate } from '../../../index';
1
+ import GlTruncate from './truncate.vue';
2
2
  import { POSITION } from './constants';
3
3
  import readme from './truncate.md';
4
4
 
@@ -74,7 +74,6 @@ export default {
74
74
  </script>
75
75
 
76
76
  <template>
77
- <!-- START -->
78
77
  <span
79
78
  v-if="position === $options.POSITION.START"
80
79
  v-gl-tooltip="{ disabled: isTooltipDisabled }"
@@ -87,7 +86,6 @@ export default {
87
86
  >
88
87
  </span>
89
88
 
90
- <!-- MIDDLE -->
91
89
  <span
92
90
  v-else-if="position === $options.POSITION.MIDDLE"
93
91
  v-gl-tooltip="{ disabled: isTooltipDisabled }"
@@ -99,7 +97,6 @@ export default {
99
97
  ><span class="gl-truncate-start">&lrm;{{ last }}&lrm;</span>
100
98
  </span>
101
99
 
102
- <!-- END -->
103
100
  <span
104
101
  v-else
105
102
  v-gl-tooltip="{ disabled: isTooltipDisabled }"
@@ -1,4 +1,4 @@
1
- import { GlHoverLoadDirective } from '../../index';
1
+ import GlHoverLoadDirective from './hover_load';
2
2
  import readme from './hover_load.md';
3
3
 
4
4
  const directives = {
@@ -1,5 +1,5 @@
1
- import { GlOutsideDirective } from '../../index';
2
1
  import GlButton from '../../components/base/button/button.vue';
2
+ import GlOutsideDirective from './outside';
3
3
  import readme from './outside.md';
4
4
 
5
5
  export const Default = () => ({
@@ -1,4 +1,4 @@
1
- import { GlResizeObserverDirective as GlResizeObserver } from '../../index';
1
+ import GlResizeObserver from './resize_observer';
2
2
  import readme from './resize_observer.md';
3
3
 
4
4
  const generateProps = ({ elementWidth = '100%', elementHeight = '100%' } = {}) => ({
@@ -1,5 +1,5 @@
1
1
  import DOMPurify from 'dompurify';
2
- import { GlSafeHtmlDirective as GlSafeHtml } from '../../index';
2
+ import GlSafeHtml from './safe_html';
3
3
  import readme from './safe_html.md';
4
4
 
5
5
  const { sanitize } = DOMPurify;