@gitlab/ui 68.0.0 → 68.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "68.0.0",
3
+ "version": "68.2.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -89,7 +89,7 @@
89
89
  &-text {
90
90
  margin-top: -$gl-spacing-scale-1;
91
91
  margin-bottom: -$gl-spacing-scale-1;
92
- @include gl-overflow-break-word;
92
+ @include gl-overflow-anywhere;
93
93
  }
94
94
 
95
95
  &-dismiss {
@@ -27,8 +27,11 @@ import GlIcon from '../../icon/icon.vue';
27
27
  import { OutsideDirective } from '../../../../directives/outside/outside';
28
28
  import { DEFAULT_OFFSET, FIXED_WIDTH_CLASS } from './constants';
29
29
 
30
+ export const BASE_DROPDOWN_CLASS = 'gl-new-dropdown';
31
+
30
32
  export default {
31
33
  name: 'BaseDropdown',
34
+ BASE_DROPDOWN_CLASS,
32
35
  components: {
33
36
  GlButton,
34
37
  GlIcon,
@@ -429,7 +432,7 @@ export default {
429
432
  </script>
430
433
 
431
434
  <template>
432
- <div v-outside="close" class="gl-new-dropdown" :class="{ 'gl-display-block!': block }">
435
+ <div v-outside="close" :class="[$options.BASE_DROPDOWN_CLASS, { 'gl-display-block!': block }]">
433
436
  <component
434
437
  :is="toggleComponent"
435
438
  v-bind="toggleAttributes"
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
2
2
  import { autoUpdate } from '@floating-ui/dom';
3
3
  import { nextTick } from 'vue';
4
4
  import * as utils from '../../../../utils/utils';
5
+ import { useMockIntersectionObserver } from '../../../../utils/use_mock_intersection_observer';
5
6
  import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
6
7
  import {
7
8
  GL_DROPDOWN_SHOWN,
@@ -15,6 +16,7 @@ import {
15
16
  POSITION_ABSOLUTE,
16
17
  POSITION_FIXED,
17
18
  } from '../constants';
19
+ import GlCollapsibleListbox from '../listbox/listbox.vue';
18
20
  import GlDisclosureDropdown from './disclosure_dropdown.vue';
19
21
  import GlDisclosureDropdownItem from './disclosure_dropdown_item.vue';
20
22
  import GlDisclosureDropdownGroup from './disclosure_dropdown_group.vue';
@@ -33,7 +35,12 @@ describe('GlDisclosureDropdown', () => {
33
35
  const buildWrapper = (propsData, slots = {}) => {
34
36
  wrapper = mount(GlDisclosureDropdown, {
35
37
  propsData,
36
- components: { GlDisclosureDropdownItem, GlDisclosureDropdownGroup },
38
+ components: {
39
+ GlDisclosureDropdown,
40
+ GlDisclosureDropdownItem,
41
+ GlDisclosureDropdownGroup,
42
+ GlCollapsibleListbox,
43
+ },
37
44
  slots,
38
45
  attachTo: document.body,
39
46
  });
@@ -43,8 +50,9 @@ describe('GlDisclosureDropdown', () => {
43
50
  const findDisclosureContent = () => wrapper.find('[data-testid="disclosure-content"]');
44
51
  const findDisclosureItems = (root = wrapper) => root.findAllComponents(GlDisclosureDropdownItem);
45
52
  const findDisclosureGroups = () => wrapper.findAllComponents(GlDisclosureDropdownGroup);
46
- const findListItem = (index) => findDisclosureItems().at(index).findComponent(ITEM_SELECTOR);
47
- const findDropdownMenu = () => wrapper.find("[data-testid='base-dropdown-menu']");
53
+ const findListItem = (index, root = wrapper) =>
54
+ findDisclosureItems(root).at(index).findComponent(ITEM_SELECTOR);
55
+ const findDropdownMenu = (root = wrapper) => root.find("[data-testid='base-dropdown-menu']");
48
56
 
49
57
  jest.spyOn(utils, 'filterVisible').mockImplementation((items) => items);
50
58
 
@@ -402,4 +410,33 @@ describe('GlDisclosureDropdown', () => {
402
410
  expect(findDropdownMenu().classes()).not.toContain('gl-display-block!');
403
411
  });
404
412
  });
413
+
414
+ describe('nested dropdowns', () => {
415
+ useMockIntersectionObserver();
416
+
417
+ it.each`
418
+ dropdown | getClickItem
419
+ ${'gl-disclosure-dropdown'} | ${(nestedWrapper) => findListItem(0, nestedWrapper)}
420
+ ${'gl-collapsible-listbox'} | ${(nestedWrapper) => nestedWrapper.find('[data-testid="listbox-item-1"]')}
421
+ `('should only close the target $dropdown', async ({ dropdown, getClickItem }) => {
422
+ const slots = {
423
+ default: `
424
+ <${dropdown}
425
+ :items="[{ text: 'First', action: () => {}, value: '1' }]"
426
+ start-opened
427
+ data-testid="nested"
428
+ />
429
+ `,
430
+ };
431
+ buildWrapper({ startOpened: true }, slots);
432
+ const isOpened = (root) => findDropdownMenu(root).classes('gl-display-block!');
433
+ const nestedWrapper = wrapper.findComponent("[data-testid='nested']");
434
+
435
+ getClickItem(nestedWrapper).trigger('click');
436
+ await nextTick();
437
+
438
+ expect(isOpened(wrapper)).toBe(true);
439
+ expect(isOpened(nestedWrapper)).toBe(false);
440
+ });
441
+ });
405
442
  });
@@ -24,11 +24,12 @@ import {
24
24
  dropdownPlacements,
25
25
  dropdownVariantOptions,
26
26
  } from '../../../../utils/constants';
27
- import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
27
+ import GlBaseDropdown, { BASE_DROPDOWN_CLASS } from '../base_dropdown/base_dropdown.vue';
28
28
  import GlDisclosureDropdownItem, { ITEM_CLASS } from './disclosure_dropdown_item.vue';
29
29
  import GlDisclosureDropdownGroup from './disclosure_dropdown_group.vue';
30
30
  import { itemsValidator, isItem, hasOnlyListItems } from './utils';
31
31
 
32
+ export const DROPDOWN_SELECTOR = `.${BASE_DROPDOWN_CLASS}`;
32
33
  export const ITEM_SELECTOR = `.${ITEM_CLASS}`;
33
34
 
34
35
  export default {
@@ -336,7 +337,11 @@ export default {
336
337
  this.$emit('action', action);
337
338
  },
338
339
  handleAutoClose(e) {
339
- if (this.autoClose && e.target.closest(ITEM_SELECTOR)) {
340
+ if (
341
+ this.autoClose &&
342
+ e.target.closest(ITEM_SELECTOR) &&
343
+ e.target.closest(DROPDOWN_SELECTOR) === this.$refs.baseDropdown.$el
344
+ ) {
340
345
  this.closeAndFocus();
341
346
  }
342
347
  },
@@ -7504,6 +7504,16 @@ $gl-animate-skeleton-loader-max-width: 64 * $grid-size;
7504
7504
  padding-right: $gl-spacing-scale-2 !important;
7505
7505
  }
7506
7506
  }
7507
+ .gl-sm-pr-4 {
7508
+ @include gl-media-breakpoint-up(sm) {
7509
+ padding-right: $gl-spacing-scale-4;
7510
+ }
7511
+ }
7512
+ .gl-sm-pr-4\! {
7513
+ @include gl-media-breakpoint-up(sm) {
7514
+ padding-right: $gl-spacing-scale-4 !important;
7515
+ }
7516
+ }
7507
7517
  .gl-sm-pl-0 {
7508
7518
  @include gl-media-breakpoint-up(sm) {
7509
7519
  padding-left: 0;
@@ -8368,12 +8378,20 @@ $gl-animate-skeleton-loader-max-width: 64 * $grid-size;
8368
8378
  .gl-overflow-break-word {
8369
8379
  overflow-wrap: break-word;
8370
8380
  hyphens: auto;
8371
- -webkit-hyphens: auto;
8372
8381
  }
8373
8382
  .gl-overflow-break-word\! {
8374
8383
  overflow-wrap: break-word !important;
8375
8384
  hyphens: auto !important;
8376
- -webkit-hyphens: auto !important;
8385
+ }
8386
+ .gl-overflow-anywhere {
8387
+ hyphens: auto;
8388
+ overflow-wrap: anywhere;
8389
+ word-break: normal;
8390
+ }
8391
+ .gl-overflow-anywhere\! {
8392
+ hyphens: auto !important;
8393
+ overflow-wrap: anywhere !important;
8394
+ word-break: normal !important;
8377
8395
  }
8378
8396
  .gl-str-truncated {
8379
8397
  @include str-truncated;
@@ -1226,6 +1226,12 @@
1226
1226
  }
1227
1227
  }
1228
1228
 
1229
+ @mixin gl-sm-pr-4 {
1230
+ @include gl-media-breakpoint-up(sm) {
1231
+ @include gl-pr-4;
1232
+ }
1233
+ }
1234
+
1229
1235
  @mixin gl-sm-pl-0 {
1230
1236
  @include gl-media-breakpoint-up(sm) {
1231
1237
  @include gl-pl-0;
@@ -130,7 +130,12 @@
130
130
  @mixin gl-overflow-break-word {
131
131
  overflow-wrap: break-word;
132
132
  hyphens: auto;
133
- -webkit-hyphens: auto; // stylelint-disable-line
133
+ }
134
+
135
+ @mixin gl-overflow-anywhere {
136
+ hyphens: auto;
137
+ overflow-wrap: anywhere;
138
+ word-break: normal;
134
139
  }
135
140
 
136
141
  // Deprecated, prefer `gl-text-truncate`