@gitlab/ui 52.10.0 → 52.12.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 (39) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +23 -5
  3. package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +291 -0
  4. package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.js +90 -0
  5. package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.js +107 -0
  6. package/dist/components/base/new_dropdowns/disclosure/mock_data.js +128 -0
  7. package/dist/components/base/new_dropdowns/disclosure/utils.js +15 -0
  8. package/dist/components/base/new_dropdowns/listbox/listbox.js +4 -4
  9. package/dist/components/base/new_dropdowns/listbox/listbox_group.js +1 -1
  10. package/dist/components/base/new_dropdowns/listbox/listbox_item.js +1 -1
  11. package/dist/components/regions/empty_state/empty_state.js +12 -1
  12. package/dist/index.css +2 -2
  13. package/dist/index.css.map +1 -1
  14. package/dist/index.js +3 -0
  15. package/package.json +3 -3
  16. package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.spec.js +3 -3
  17. package/src/components/base/new_dropdowns/base_dropdown/base_dropdown.vue +21 -3
  18. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.md +114 -0
  19. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.scss +7 -0
  20. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.spec.js +210 -0
  21. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.stories.js +306 -0
  22. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +342 -0
  23. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.spec.js +82 -0
  24. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.vue +77 -0
  25. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.spec.js +94 -0
  26. package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.vue +98 -0
  27. package/src/components/base/new_dropdowns/disclosure/mock_data.js +156 -0
  28. package/src/components/base/new_dropdowns/disclosure/utils.js +18 -0
  29. package/src/components/base/new_dropdowns/disclosure/utils.spec.js +73 -0
  30. package/src/components/base/new_dropdowns/dropdown.scss +6 -0
  31. package/src/components/base/new_dropdowns/listbox/listbox.scss +0 -6
  32. package/src/components/base/new_dropdowns/listbox/listbox.vue +4 -4
  33. package/src/components/base/new_dropdowns/listbox/listbox_group.vue +1 -1
  34. package/src/components/base/new_dropdowns/listbox/listbox_item.vue +1 -1
  35. package/src/components/regions/empty_state/empty_state.spec.js +35 -0
  36. package/src/components/regions/empty_state/empty_state.stories.js +5 -0
  37. package/src/components/regions/empty_state/empty_state.vue +15 -1
  38. package/src/index.js +3 -0
  39. package/src/scss/components.scss +2 -0
@@ -0,0 +1,82 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import GlDisclosureDropdownGroup, {
3
+ GROUP_TOP_BORDER_CLASSES,
4
+ } from './disclosure_dropdown_group.vue';
5
+ import GlDisclosureDropdownItem from './disclosure_dropdown_item.vue';
6
+ import { mockGroups, mockProfileGroups } from './mock_data';
7
+
8
+ describe('GlDisclosureDropdownGroup', () => {
9
+ let wrapper;
10
+
11
+ const buildWrapper = ({ propsData, slots } = {}) => {
12
+ wrapper = shallowMount(GlDisclosureDropdownGroup, {
13
+ propsData: {
14
+ group: mockGroups[0],
15
+ ...propsData,
16
+ },
17
+ slots,
18
+ });
19
+ };
20
+
21
+ const findGroup = () => wrapper.find('ul[role="group"]');
22
+ const findItems = () => wrapper.findAllComponents(GlDisclosureDropdownItem);
23
+ const findByTestId = (testid, root = wrapper) => root.find(`[data-testid="${testid}"]`);
24
+ const findLabelElement = () => {
25
+ const labelElementId = findGroup().attributes('aria-labelledby');
26
+ return wrapper.find(`#${labelElementId}`);
27
+ };
28
+
29
+ it('renders default slot content', () => {
30
+ buildWrapper({ slots: { default: '<li data-testid="default-slot-content"></li>' } });
31
+
32
+ expect(findByTestId('default-slot-content').exists()).toBe(true);
33
+ });
34
+
35
+ it('renders list of items if default content was not provided', () => {
36
+ buildWrapper();
37
+
38
+ expect(findItems()).toHaveLength(mockGroups[0].items.length);
39
+ });
40
+
41
+ it('renders `list-item` content in a default slot of `GlDisclosureDropdownItem`', () => {
42
+ buildWrapper({
43
+ slots: { 'list-item': '<li data-testid="list-item-content"></li>' },
44
+ });
45
+
46
+ expect(findItems()).toHaveLength(mockGroups[0].items.length);
47
+
48
+ expect(findItems().at(0).find('[data-testid="list-item-content"]').exists()).toBe(true);
49
+ });
50
+
51
+ describe('label', () => {
52
+ it('labels the group when label provided', () => {
53
+ buildWrapper();
54
+ expect(findLabelElement().text()).toBe(mockGroups[0].name);
55
+ });
56
+
57
+ it('does not label the group when label is not provided', () => {
58
+ buildWrapper({ propsData: { group: mockProfileGroups[0] } });
59
+ expect(findLabelElement().exists()).toBe(false);
60
+ });
61
+
62
+ it('allows arbitrary content for group label', () => {
63
+ buildWrapper({ slots: { 'group-label': '<i data-testid="custom-name"></i>' } });
64
+
65
+ expect(findByTestId('custom-name', findLabelElement()).exists()).toBe(true);
66
+ });
67
+ });
68
+
69
+ describe('separator', () => {
70
+ const topBorderClasses = GROUP_TOP_BORDER_CLASSES.split(' ');
71
+
72
+ it('should not add top border by default', () => {
73
+ buildWrapper();
74
+ expect(wrapper.classes()).not.toEqual(expect.arrayContaining(topBorderClasses));
75
+ });
76
+
77
+ it('should add top border classes when `bordered` props is set to `true`', () => {
78
+ buildWrapper({ propsData: { bordered: true } });
79
+ expect(wrapper.classes()).toEqual(expect.arrayContaining(topBorderClasses));
80
+ });
81
+ });
82
+ });
@@ -0,0 +1,77 @@
1
+ <script>
2
+ import { uniqueId } from 'lodash';
3
+ import GlDisclosureDropdownItem from './disclosure_dropdown_item.vue';
4
+ import { isGroup } from './utils';
5
+
6
+ export const GROUP_TOP_BORDER_CLASSES = 'gl-border-t gl-pt-3 gl-mt-3';
7
+
8
+ export default {
9
+ components: {
10
+ GlDisclosureDropdownItem,
11
+ },
12
+ props: {
13
+ /**
14
+ * Group of items
15
+ */
16
+ group: {
17
+ type: Object,
18
+ required: false,
19
+ default: null,
20
+ validator: isGroup,
21
+ },
22
+ /**
23
+ * If 'true', will set top border for the group
24
+ * to separate from other groups
25
+ */
26
+ bordered: {
27
+ type: Boolean,
28
+ required: false,
29
+ default: false,
30
+ },
31
+ },
32
+ computed: {
33
+ borderClass() {
34
+ return this.bordered ? GROUP_TOP_BORDER_CLASSES : null;
35
+ },
36
+ showHeader() {
37
+ return this.$scopedSlots['group-label'] || this.group?.name;
38
+ },
39
+ groupLabeledBy() {
40
+ return this.showHeader ? this.nameId : null;
41
+ },
42
+ },
43
+ created() {
44
+ this.nameId = uniqueId('gl-disclosure-dropdown-group-');
45
+ },
46
+ methods: {
47
+ handleAction(action) {
48
+ this.$emit('action', action);
49
+ },
50
+ },
51
+ };
52
+ </script>
53
+
54
+ <template>
55
+ <div :class="borderClass">
56
+ <div
57
+ v-if="showHeader"
58
+ :id="nameId"
59
+ aria-hidden="true"
60
+ class="gl-pl-5 gl-py-2 gl-font-sm gl-font-weight-bold"
61
+ >
62
+ <slot name="group-label">{{ group.name }}</slot>
63
+ </div>
64
+ <ul role="group" :aria-labelledby="groupLabeledBy" class="gl-mb-0 gl-pl-0 gl-list-style-none">
65
+ <slot>
66
+ <gl-disclosure-dropdown-item
67
+ v-for="item in group.items"
68
+ :key="item.text"
69
+ :item="item"
70
+ @action="handleAction"
71
+ >
72
+ <slot name="list-item" :item="item"> </slot>
73
+ </gl-disclosure-dropdown-item>
74
+ </slot>
75
+ </ul>
76
+ </div>
77
+ </template>
@@ -0,0 +1,94 @@
1
+ import { mount } from '@vue/test-utils';
2
+ import { ENTER, SPACE } from '../constants';
3
+ import { mockItems } from './mock_data';
4
+
5
+ import GlDisclosureDropdownItem from './disclosure_dropdown_item.vue';
6
+
7
+ describe('GlDisclosureDropdownItem', () => {
8
+ let wrapper;
9
+
10
+ const buildWrapper = (propsData, slots = {}) => {
11
+ wrapper = mount(GlDisclosureDropdownItem, {
12
+ propsData,
13
+ slots,
14
+ });
15
+ };
16
+ const findItem = () => wrapper.find('[data-testid="disclosure-dropdown-item"]');
17
+
18
+ describe('when default slot content provided', () => {
19
+ const content = 'This is an item';
20
+ const slots = { default: content };
21
+ beforeEach(() => {
22
+ buildWrapper({}, slots);
23
+ });
24
+
25
+ it('renders it', () => {
26
+ expect(wrapper.text()).toContain(content);
27
+ });
28
+
29
+ it.each`
30
+ trigger | event
31
+ ${() => findItem().trigger('click')} | ${'click'}
32
+ ${() => findItem().trigger('keydown', { code: ENTER })} | ${'ENTER'}
33
+ ${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
34
+ `(`$event should emit 'action' event`, ({ trigger }) => {
35
+ trigger();
36
+ expect(wrapper.emitted('action')).toHaveLength(1);
37
+ });
38
+ });
39
+
40
+ describe('when item has an `href`', () => {
41
+ beforeEach(() => {
42
+ buildWrapper({ item: mockItems[0] });
43
+ });
44
+
45
+ const findLink = () => wrapper.find('a.dropdown-item');
46
+
47
+ it('should render a link', () => {
48
+ expect(findLink().exists()).toBe(true);
49
+ });
50
+
51
+ it('should set correct attributes', () => {
52
+ expect(findLink().attributes('href')).toBe(mockItems[0].href);
53
+ expect(findLink().attributes()).toMatchObject(mockItems[0].extraAttrs);
54
+ });
55
+ });
56
+
57
+ describe('when item has an `action`', () => {
58
+ const action = jest.spyOn(mockItems[1], 'action');
59
+
60
+ beforeEach(() => {
61
+ buildWrapper({ item: mockItems[1] });
62
+ action.mockClear();
63
+ });
64
+
65
+ const findButton = () => wrapper.find('button.dropdown-item');
66
+
67
+ it('should render a button', () => {
68
+ expect(findButton().exists()).toBe(true);
69
+ });
70
+
71
+ it('should set correct attributes', () => {
72
+ const attrs = { ...mockItems[1].extraAttrs };
73
+ delete attrs.class;
74
+ expect(findButton().classes()).toContain(mockItems[1].extraAttrs.class);
75
+ expect(findButton().attributes()).toMatchObject(attrs);
76
+ });
77
+
78
+ it('should call `action` on `click`', () => {
79
+ findButton().trigger('click');
80
+ expect(action).toHaveBeenCalled();
81
+ expect(wrapper.emitted('action')).toHaveLength(1);
82
+ });
83
+
84
+ it.each`
85
+ trigger | event
86
+ ${() => findItem().trigger('click')} | ${'click'}
87
+ ${() => findItem().trigger('keydown', { code: ENTER })} | ${'ENTER'}
88
+ ${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
89
+ `(`$event will execute action and emit 'action' event`, ({ trigger }) => {
90
+ trigger();
91
+ expect(wrapper.emitted('action')).toHaveLength(1);
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,98 @@
1
+ <script>
2
+ import { ENTER, SPACE } from '../constants';
3
+ import { stopEvent } from '../../../../utils/utils';
4
+ import { isItem } from './utils';
5
+
6
+ export const ITEM_CLASS = 'gl-dropdown-item';
7
+
8
+ export default {
9
+ ITEM_CLASS,
10
+ props: {
11
+ item: {
12
+ type: Object,
13
+ required: false,
14
+ default: null,
15
+ validator: isItem,
16
+ },
17
+ },
18
+ computed: {
19
+ isActionItem() {
20
+ return this.item?.action;
21
+ },
22
+ isCustomContent() {
23
+ return Boolean(this.$scopedSlots.default);
24
+ },
25
+ itemComponent() {
26
+ if (this.isActionItem)
27
+ return {
28
+ is: 'button',
29
+ attrs: {
30
+ ...this.item.extraAttrs,
31
+ },
32
+ listeners: {
33
+ click: () => this.item.action(),
34
+ },
35
+ };
36
+ return {
37
+ is: 'a',
38
+ attrs: {
39
+ href: this.item.href,
40
+ ...this.item.extraAttrs,
41
+ },
42
+ listeners: {},
43
+ };
44
+ },
45
+ },
46
+ methods: {
47
+ onKeydown(event) {
48
+ const { code } = event;
49
+
50
+ if (code === ENTER || code === SPACE) {
51
+ stopEvent(event);
52
+ /** Instead of simply navigating or calling the action, we want
53
+ * the `a/button` to be the target of the event as it might have additional attributes.
54
+ * E.g. `a` might have `target` attribute.
55
+ * `bubbles` is set to `true` as the parent `li` item has this event listener and thus we'll get a loop.
56
+ */
57
+ this.$refs.item?.dispatchEvent(new MouseEvent('click', { bubbles: false }));
58
+ this.action();
59
+ }
60
+ },
61
+ action() {
62
+ this.$emit('action', this.item);
63
+ },
64
+ },
65
+ };
66
+ </script>
67
+
68
+ <template>
69
+ <li
70
+ tabindex="0"
71
+ :class="$options.ITEM_CLASS"
72
+ class="gl-dropdown-item gl-focusable-dropdown-item"
73
+ data-testid="disclosure-dropdown-item"
74
+ @click="action"
75
+ @keydown="onKeydown"
76
+ >
77
+ <div v-if="isCustomContent" class="dropdown-item">
78
+ <div class="gl-dropdown-item-text-wrapper">
79
+ <slot></slot>
80
+ </div>
81
+ </div>
82
+
83
+ <template v-else>
84
+ <component
85
+ :is="itemComponent.is"
86
+ v-bind="itemComponent.attrs"
87
+ ref="item"
88
+ class="dropdown-item"
89
+ tabindex="-1"
90
+ v-on="itemComponent.listeners"
91
+ >
92
+ <span class="gl-dropdown-item-text-wrapper">
93
+ {{ item.text }}
94
+ </span>
95
+ </component>
96
+ </template>
97
+ </li>
98
+ </template>
@@ -0,0 +1,156 @@
1
+ export const mockItems = [
2
+ {
3
+ text: 'Mark as draft',
4
+ href: 'https://gitlab.com',
5
+ extraAttrs: {
6
+ target: '_blank',
7
+ rel: 'nofollow',
8
+ 'data-method': 'put',
9
+ },
10
+ },
11
+ {
12
+ text: 'Close merge request',
13
+ action: () => {
14
+ // eslint-disable-next-line no-console
15
+ console.log('CLOSED');
16
+ },
17
+ extraAttrs: {
18
+ class: 'gl-text-red-500!',
19
+ rel: 'nofollow',
20
+ 'data-method': 'put',
21
+ },
22
+ },
23
+ {
24
+ text: 'Create new',
25
+ href: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/new',
26
+ extraAttrs: {
27
+ rel: 'nofollow',
28
+ target: '_blank',
29
+ },
30
+ },
31
+ ];
32
+
33
+ export const mockItemsCustomItem = [
34
+ {
35
+ text: 'Assigned to you',
36
+ href: 'https://gitlab.com/dashboard/merge_requests',
37
+ count: '2',
38
+ extraAttrs: {
39
+ target: '_blank',
40
+ rel: 'nofollow',
41
+ },
42
+ },
43
+ {
44
+ text: 'Review requests from you',
45
+ href: 'https://gitlab.com/dashboard/merge_requests',
46
+ count: 0,
47
+ extraAttrs: {
48
+ target: '_blank',
49
+ rel: 'nofollow',
50
+ },
51
+ },
52
+ ];
53
+
54
+ export const mockGroups = [
55
+ {
56
+ name: 'This project',
57
+ items: [
58
+ {
59
+ text: 'New issue',
60
+ href: 'https://gitlab.com/gitlab-org/gitlab/-/issues/new',
61
+ extraAttrs: {
62
+ target: '_blank',
63
+ rel: 'nofollow',
64
+ },
65
+ },
66
+ {
67
+ text: 'New merge request',
68
+ href: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/new',
69
+ extraAttrs: {
70
+ target: '_blank',
71
+ rel: 'nofollow',
72
+ },
73
+ },
74
+ {
75
+ text: 'New snippet',
76
+ href: 'https://gitlab.com/gitlab-org/gitlab/-/snippets/new',
77
+ extraAttrs: {
78
+ target: '_blank',
79
+ rel: 'nofollow',
80
+ },
81
+ },
82
+ ],
83
+ },
84
+ {
85
+ name: 'GitLab',
86
+ items: [
87
+ {
88
+ text: 'New project',
89
+ href: 'https://gitlab.com/projects/new',
90
+ extraAttrs: {
91
+ target: '_blank',
92
+ rel: 'nofollow',
93
+ },
94
+ },
95
+ {
96
+ text: 'New group',
97
+ href: 'https://gitlab.com/groups/new',
98
+ extraAttrs: {
99
+ target: '_blank',
100
+ rel: 'nofollow',
101
+ },
102
+ },
103
+ {
104
+ text: 'New snippet',
105
+ href: 'https://gitlab.com/snippets/new',
106
+ extraAttrs: {
107
+ target: '_blank',
108
+ rel: 'nofollow',
109
+ },
110
+ },
111
+ ],
112
+ },
113
+ ];
114
+
115
+ export const mockProfileGroups = [
116
+ {
117
+ items: [
118
+ {
119
+ text: 'Set status',
120
+ href: 'https://gitlab.com',
121
+ icon: 'status_success',
122
+ extraAttrs: {
123
+ target: '_blank',
124
+ rel: 'nofollow',
125
+ },
126
+ },
127
+ {
128
+ text: 'Edit profile',
129
+ href: '#',
130
+ extraAttrs: {
131
+ target: '_blank',
132
+ rel: 'nofollow',
133
+ },
134
+ },
135
+ {
136
+ text: 'Preferences',
137
+ href: '#',
138
+ extraAttrs: {
139
+ target: '_blank',
140
+ rel: 'nofollow',
141
+ },
142
+ },
143
+ ],
144
+ },
145
+ {
146
+ items: [
147
+ {
148
+ text: 'Sign out',
149
+ action: () => {
150
+ // eslint-disable-next-line no-alert
151
+ window.confirm('Are you sure?');
152
+ },
153
+ },
154
+ ],
155
+ },
156
+ ];
@@ -0,0 +1,18 @@
1
+ const itemValidator = ({ text, href, action }) =>
2
+ Boolean(text?.length && (href?.length || typeof action === 'function'));
3
+
4
+ const isItem = (item) => Boolean(item) && itemValidator(item);
5
+
6
+ const isGroup = (group) =>
7
+ Boolean(group) &&
8
+ Array.isArray(group.items) &&
9
+ Boolean(group.items.length) &&
10
+ group.items.every(isItem);
11
+
12
+ const itemsValidator = (items) => items.every(isItem) || items.every(isGroup);
13
+
14
+ const isAllItems = (items) => items.every(isItem);
15
+
16
+ const isAllGroups = (items) => items.every(isGroup);
17
+
18
+ export { itemsValidator, isItem, isGroup, isAllItems, isAllGroups };
@@ -0,0 +1,73 @@
1
+ import { itemsValidator, isItem, isGroup } from './utils';
2
+ import { mockItems, mockGroups } from './mock_data';
3
+
4
+ describe('isItem', () => {
5
+ it.each([null, undefined, {}, { text: null }, { text: 'group', items: [] }])(
6
+ 'isItem(%p) === false',
7
+ (notAnItem) => {
8
+ expect(isItem(notAnItem)).toBe(false);
9
+ }
10
+ );
11
+
12
+ it.each([
13
+ { text: 'Action', href: 'gitlab.com' },
14
+ {
15
+ text: 'Action',
16
+ action: () => {},
17
+ },
18
+ {
19
+ text: 'Action',
20
+ href: 'gitlab.com',
21
+ action: () => {},
22
+ },
23
+ ])('isItem(%p) === true', (item) => {
24
+ expect(isItem(item)).toBe(true);
25
+ });
26
+ });
27
+
28
+ describe('isGroup', () => {
29
+ it.each([null, undefined, {}, { name: null }, { name: 'group', items: [] }])(
30
+ 'isGroup(%p) === false',
31
+ (notAGroup) => {
32
+ expect(isGroup(notAGroup)).toBe(false);
33
+ }
34
+ );
35
+
36
+ it.each([
37
+ {
38
+ name: 'group',
39
+ items: [
40
+ { text: 'Action', href: 'gitlab.com' },
41
+ {
42
+ text: 'Action',
43
+ action: () => {},
44
+ },
45
+ ],
46
+ },
47
+ {
48
+ items: [
49
+ { text: 'Action', href: 'gitlab.com' },
50
+ {
51
+ text: 'Action',
52
+ action: () => {},
53
+ },
54
+ ],
55
+ },
56
+ ])('isGroup(%p) === true', (group) => {
57
+ expect(isGroup(group)).toBe(true);
58
+ });
59
+ });
60
+
61
+ describe('itemsValidator', () => {
62
+ it.each`
63
+ description | value | expected
64
+ ${'valid flat items'} | ${mockItems} | ${true}
65
+ ${'valid grouped items'} | ${mockGroups} | ${true}
66
+ ${'empty list'} | ${[]} | ${true}
67
+ ${'invalid items'} | ${[{ foo: true }]} | ${false}
68
+ ${'group with invalid items'} | ${[{ name: 'foo', items: [{ foo: true }] }]} | ${false}
69
+ ${'sibling groups and items'} | ${[...mockItems, ...mockGroups]} | ${false}
70
+ `('returns $expected given $description', ({ value, expected }) => {
71
+ expect(itemsValidator(value)).toBe(expected);
72
+ });
73
+ });
@@ -0,0 +1,6 @@
1
+ // TODO: remove in scope of https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2111
2
+ .gl-focusable-dropdown-item {
3
+ &:focus {
4
+ @include gl-focus($inset: true);
5
+ }
6
+ }
@@ -40,9 +40,3 @@ $clear-button-size: 24px;
40
40
  right: $gl-spacing-scale-2;
41
41
  }
42
42
  }
43
-
44
- .gl-listbox-item {
45
- &:focus {
46
- @include gl-focus($inset: true);
47
- }
48
- }
@@ -105,7 +105,7 @@ export default {
105
105
  type: String,
106
106
  required: false,
107
107
  default: buttonCategoryOptions.primary,
108
- validator: (value) => Object.keys(buttonCategoryOptions).includes(value),
108
+ validator: (value) => value in buttonCategoryOptions,
109
109
  },
110
110
  /**
111
111
  * Styling option - dropdown's toggle variant
@@ -114,7 +114,7 @@ export default {
114
114
  type: String,
115
115
  required: false,
116
116
  default: dropdownVariantOptions.default,
117
- validator: (value) => Object.keys(dropdownVariantOptions).includes(value),
117
+ validator: (value) => value in dropdownVariantOptions,
118
118
  },
119
119
  /**
120
120
  * The size of the dropdown toggle
@@ -123,7 +123,7 @@ export default {
123
123
  type: String,
124
124
  required: false,
125
125
  default: 'medium',
126
- validator: (value) => Object.keys(buttonSizeOptions).includes(value),
126
+ validator: (value) => value in buttonSizeOptions,
127
127
  },
128
128
  /**
129
129
  * Icon name that will be rendered in the toggle button
@@ -610,7 +610,7 @@ export default {
610
610
  <component
611
611
  :is="listboxTag"
612
612
  v-if="showList"
613
- id="listbox"
613
+ :id="listboxId"
614
614
  ref="list"
615
615
  :aria-labelledby="listAriaLabelledBy || headerId || toggleId"
616
616
  role="listbox"
@@ -16,7 +16,7 @@ export default {
16
16
 
17
17
  <template>
18
18
  <ul role="group" :aria-labelledby="nameId" class="gl-mb-0 gl-pl-0 gl-list-style-none">
19
- <li :id="nameId" role="presentation" class="gl-pl-5! gl-py-2! gl-font-base gl-font-weight-bold">
19
+ <li :id="nameId" role="presentation" class="gl-pl-5! gl-py-2! gl-font-sm gl-font-weight-bold">
20
20
  <slot name="group-label">{{ name }}</slot>
21
21
  </li>
22
22
  <slot></slot>
@@ -51,7 +51,7 @@ export default {
51
51
 
52
52
  <template>
53
53
  <li
54
- class="gl-dropdown-item gl-listbox-item"
54
+ class="gl-dropdown-item gl-focusable-dropdown-item"
55
55
  role="option"
56
56
  :tabindex="isFocused ? 0 : -1"
57
57
  :aria-selected="isSelected"