@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,306 @@
1
+ import {
2
+ buttonCategoryOptions,
3
+ buttonSizeOptions,
4
+ buttonVariantOptions,
5
+ } from '../../../../utils/constants';
6
+ import {
7
+ GlDisclosureDropdown,
8
+ GlBadge,
9
+ GlDisclosureDropdownGroup,
10
+ GlDisclosureDropdownItem,
11
+ GlToggle,
12
+ GlAvatar,
13
+ GlModal,
14
+ GlIcon,
15
+ } from '../../../../index';
16
+ import { makeContainer } from '../../../../utils/story_decorators/container';
17
+ import readme from './disclosure_dropdown.md';
18
+ import { mockItems, mockItemsCustomItem, mockGroups, mockProfileGroups } from './mock_data';
19
+
20
+ const defaultValue = (prop) => GlDisclosureDropdown.props[prop].default;
21
+
22
+ const generateProps = ({
23
+ items = mockItems,
24
+ category = defaultValue('category'),
25
+ variant = defaultValue('variant'),
26
+ size = defaultValue('size'),
27
+ disabled = defaultValue('disabled'),
28
+ loading = defaultValue('loading'),
29
+ noCaret = defaultValue('noCaret'),
30
+ right = defaultValue('right'),
31
+ toggleText,
32
+ textSrOnly = defaultValue('textSrOnly'),
33
+ icon = '',
34
+ toggleAriaLabelledBy,
35
+ listAriaLabelledBy,
36
+ startOpened = true,
37
+ } = {}) => ({
38
+ items,
39
+ category,
40
+ variant,
41
+ size,
42
+ disabled,
43
+ loading,
44
+ noCaret,
45
+ right,
46
+ toggleText,
47
+ textSrOnly,
48
+ icon,
49
+ toggleAriaLabelledBy,
50
+ listAriaLabelledBy,
51
+ startOpened,
52
+ });
53
+
54
+ const makeBindings = (overrides = {}) =>
55
+ Object.entries({
56
+ ':items': 'items',
57
+ ':category': 'category',
58
+ ':variant': 'variant',
59
+ ':size': 'size',
60
+ ':disabled': 'disabled',
61
+ ':loading': 'loading',
62
+ ':no-caret': 'noCaret',
63
+ ':right': 'right',
64
+ ':toggle-text': 'toggleText',
65
+ ':text-sr-only': 'textSrOnly',
66
+ ':icon': 'icon',
67
+ ':toggle-aria-labelled-by': 'toggleAriaLabelledBy',
68
+ ':list-aria-labelled-by': 'listAriaLabelledBy',
69
+ ...overrides,
70
+ })
71
+ .map(([key, value]) => `${key}="${value}"`)
72
+ .join('\n');
73
+
74
+ function openDisclosure(component) {
75
+ component.$nextTick(() => {
76
+ component.$refs.disclosure.open();
77
+ });
78
+ }
79
+
80
+ const template = (content, { bindingOverrides = {} } = {}) => `
81
+ <gl-disclosure-dropdown
82
+ ref="disclosure"
83
+ ${makeBindings(bindingOverrides)}
84
+ >
85
+ ${content || ''}
86
+ </gl-disclosure-dropdown>
87
+ `;
88
+
89
+ export const Default = (args, { argTypes }) => ({
90
+ props: Object.keys(argTypes),
91
+ components: {
92
+ GlDisclosureDropdown,
93
+ },
94
+ mounted() {
95
+ if (this.startOpened) {
96
+ openDisclosure(this);
97
+ }
98
+ },
99
+ template: template(),
100
+ });
101
+ Default.args = generateProps({
102
+ icon: 'ellipsis_v',
103
+ noCaret: true,
104
+ toggleText: 'Disclosure',
105
+ textSrOnly: true,
106
+ });
107
+ Default.decorators = [makeContainer({ height: '200px' })];
108
+
109
+ export const CustomListItem = (args, { argTypes }) => ({
110
+ props: Object.keys(argTypes),
111
+ components: {
112
+ GlDisclosureDropdown,
113
+ GlBadge,
114
+ },
115
+ mounted() {
116
+ if (this.startOpened) {
117
+ openDisclosure(this);
118
+ }
119
+ },
120
+ methods: {
121
+ navigate() {
122
+ this.$refs.link.click();
123
+ },
124
+ },
125
+ template: template(
126
+ `
127
+ <template #list-item="{ item }">
128
+ <a ref="link" class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-hover-text-gray-900 gl-hover-text-decoration-none gl-text-gray-900" :href="item.href" v-bind="item.extraAttrs">
129
+ {{item.text}}
130
+ <gl-badge pill variant="info" v-if="item.count">{{item.count}}</gl-badge>
131
+ </a>
132
+ </template>
133
+ `,
134
+ {
135
+ bindingOverrides: {
136
+ '@action': 'navigate',
137
+ },
138
+ }
139
+ ),
140
+ });
141
+
142
+ CustomListItem.args = generateProps({ items: mockItemsCustomItem, toggleText: 'Merge requests' });
143
+ CustomListItem.decorators = [makeContainer({ height: '200px' })];
144
+
145
+ const makeGroupedExample = (changes) => {
146
+ const story = (args, { argTypes }) => ({
147
+ props: Object.keys(argTypes),
148
+ components: {
149
+ GlBadge,
150
+ GlDisclosureDropdown,
151
+ GlDisclosureDropdownGroup,
152
+ GlDisclosureDropdownItem,
153
+ GlToggle,
154
+ GlAvatar,
155
+ GlModal,
156
+ GlIcon,
157
+ },
158
+ mounted() {
159
+ if (this.startOpened) {
160
+ openDisclosure(this);
161
+ }
162
+ },
163
+ ...changes,
164
+ });
165
+
166
+ story.args = generateProps({ items: mockGroups });
167
+ story.decorators = [makeContainer({ height: '340px' })];
168
+
169
+ return story;
170
+ };
171
+
172
+ export const Groups = makeGroupedExample({
173
+ template: template(''),
174
+ });
175
+ Groups.args = generateProps({
176
+ icon: 'plus-square',
177
+ items: mockGroups,
178
+ toggleText: 'Create new',
179
+ textSrOnly: true,
180
+ });
181
+
182
+ export const CustomGroupsItemsAndToggle = makeGroupedExample({
183
+ template: template(`
184
+ <template #toggle>
185
+ <span class="gl-sr-only">
186
+ Orange Fox user's menu
187
+ </span>
188
+ <gl-avatar :size="32" entity-name="Orange Fox" aria-hidden="true"></gl-avatar>
189
+ </template>
190
+
191
+ <div role="group">
192
+ <gl-disclosure-dropdown-group>
193
+ <gl-disclosure-dropdown-item>
194
+ <span class="gl-display-flex gl-flex-direction-column">
195
+ <span class="gl-font-weight-bold gl-white-space-nowrap">Orange Fox</span>
196
+ <span class="gl-text-gray-400">@thefox</span>
197
+ </span>
198
+ </gl-disclosure-dropdown-item>
199
+ </gl-disclosure-dropdown-group>
200
+ <gl-disclosure-dropdown-group bordered :group="$options.groups[0]">
201
+ <template #list-item="{ item }">
202
+ <a
203
+ class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-hover-text-gray-900 gl-hover-text-decoration-none gl-text-gray-900"
204
+ :href="item.href"
205
+ v-bind="item.extraAttrs"
206
+ >
207
+ {{item.text}}
208
+ <gl-icon v-if="item.icon" :name="item.icon"/>
209
+ </a>
210
+ </template>
211
+ </gl-disclosure-dropdown-group>
212
+ <gl-disclosure-dropdown-group bordered>
213
+ <template #group-label>
214
+ <span class="gl-font-sm">Navigation redesign</span>
215
+ <gl-badge size="sm" variant="info">Beta</gl-badge>
216
+ </template>
217
+ <gl-disclosure-dropdown-item>
218
+ <gl-toggle label="New navigation" label-position="left" v-model="newNavigation"/>
219
+ </gl-disclosure-dropdown-item>
220
+ <gl-disclosure-dropdown-item @action="toggleModalVisibility(true)">
221
+ <a>Provide feedback</a>
222
+ </gl-disclosure-dropdown-item>
223
+ </gl-disclosure-dropdown-group>
224
+ <gl-disclosure-dropdown-group bordered :group="$options.groups[1]"> </gl-disclosure-dropdown-group>
225
+ <gl-modal :visible="feedBackModalVisible" @change="toggleModalVisibility" modal-id="feedbackModal" size="sm">
226
+ <textarea class="gl-w-full">Tell us what you think!</textarea>
227
+ </gl-modal>
228
+ </div>
229
+ `),
230
+ data() {
231
+ return {
232
+ newNavigation: true,
233
+ feedBackModalVisible: false,
234
+ };
235
+ },
236
+ methods: {
237
+ toggleModalVisibility(value) {
238
+ this.feedBackModalVisible = value;
239
+ },
240
+ },
241
+ groups: mockProfileGroups,
242
+ });
243
+ CustomGroupsItemsAndToggle.args = generateProps({
244
+ icon: 'plus-square',
245
+ toggleText: 'User profile menu',
246
+ textSrOnly: true,
247
+ items: null,
248
+ });
249
+ CustomGroupsItemsAndToggle.decorators = [makeContainer({ height: '400px' })];
250
+
251
+ export const MiscellaneousContent = (args, { argTypes }) => ({
252
+ props: Object.keys(argTypes),
253
+ components: {
254
+ GlDisclosureDropdown,
255
+ },
256
+ mounted() {
257
+ if (this.startOpened) {
258
+ openDisclosure(this);
259
+ }
260
+ },
261
+ template: template(
262
+ `
263
+ <div class="gl-p-3">A disclosure dropdown is a button that toggles a panel containing a list of items and/or links.</div>
264
+ `
265
+ ),
266
+ });
267
+
268
+ MiscellaneousContent.args = generateProps({
269
+ icon: 'doc-text',
270
+ toggleText: 'Miscellaneous content',
271
+ textSrOnly: true,
272
+ items: null,
273
+ });
274
+ MiscellaneousContent.decorators = [makeContainer({ height: '200px' })];
275
+
276
+ export default {
277
+ title: 'base/new-dropdowns/disclosure',
278
+ component: GlDisclosureDropdown,
279
+ parameters: {
280
+ docs: {
281
+ description: {
282
+ component: readme,
283
+ },
284
+ },
285
+ },
286
+ argTypes: {
287
+ category: {
288
+ control: {
289
+ type: 'select',
290
+ options: buttonCategoryOptions,
291
+ },
292
+ },
293
+ variant: {
294
+ control: {
295
+ type: 'select',
296
+ options: buttonVariantOptions,
297
+ },
298
+ },
299
+ size: {
300
+ control: {
301
+ type: 'select',
302
+ options: Object.keys(buttonSizeOptions),
303
+ },
304
+ },
305
+ },
306
+ };
@@ -0,0 +1,342 @@
1
+ <!-- eslint-disable vue/multi-word-component-names -->
2
+ <script>
3
+ import { clamp, uniqueId } from 'lodash';
4
+ import { stopEvent } from '../../../../utils/utils';
5
+ import {
6
+ GL_DROPDOWN_SHOWN,
7
+ GL_DROPDOWN_HIDDEN,
8
+ HOME,
9
+ END,
10
+ ARROW_DOWN,
11
+ ARROW_UP,
12
+ } from '../constants';
13
+ import {
14
+ buttonCategoryOptions,
15
+ buttonSizeOptions,
16
+ dropdownVariantOptions,
17
+ } from '../../../../utils/constants';
18
+ import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
19
+ import GlDisclosureDropdownItem, { ITEM_CLASS } from './disclosure_dropdown_item.vue';
20
+ import GlDisclosureDropdownGroup from './disclosure_dropdown_group.vue';
21
+ import { itemsValidator, isItem, isAllItems, isAllGroups } from './utils';
22
+
23
+ export default {
24
+ events: {
25
+ GL_DROPDOWN_SHOWN,
26
+ GL_DROPDOWN_HIDDEN,
27
+ },
28
+ components: {
29
+ GlBaseDropdown,
30
+ GlDisclosureDropdownItem,
31
+ GlDisclosureDropdownGroup,
32
+ },
33
+ props: {
34
+ /**
35
+ * Items to display in the dropdown
36
+ */
37
+ items: {
38
+ type: Array,
39
+ required: false,
40
+ default: () => [],
41
+ validator: itemsValidator,
42
+ },
43
+ /**
44
+ * Toggle button text
45
+ */
46
+ toggleText: {
47
+ type: String,
48
+ required: false,
49
+ default: '',
50
+ },
51
+ /**
52
+ * Toggle text to be read by screen readers only
53
+ */
54
+ textSrOnly: {
55
+ type: Boolean,
56
+ required: false,
57
+ default: false,
58
+ },
59
+ /**
60
+ * Styling option - dropdown's toggle category
61
+ */
62
+ category: {
63
+ type: String,
64
+ required: false,
65
+ default: buttonCategoryOptions.primary,
66
+ validator: (value) => value in buttonCategoryOptions,
67
+ },
68
+ /**
69
+ * Styling option - dropdown's toggle variant
70
+ */
71
+ variant: {
72
+ type: String,
73
+ required: false,
74
+ default: dropdownVariantOptions.default,
75
+ validator: (value) => value in dropdownVariantOptions,
76
+ },
77
+ /**
78
+ * The size of the dropdown toggle
79
+ */
80
+ size: {
81
+ type: String,
82
+ required: false,
83
+ default: 'medium',
84
+ validator: (value) => value in buttonSizeOptions,
85
+ },
86
+ /**
87
+ * Icon name that will be rendered in the toggle button
88
+ */
89
+ icon: {
90
+ type: String,
91
+ required: false,
92
+ default: '',
93
+ },
94
+ /**
95
+ * Set to "true" to disable the dropdown
96
+ */
97
+ disabled: {
98
+ type: Boolean,
99
+ required: false,
100
+ default: false,
101
+ },
102
+ /**
103
+ * Set to "true" when dropdown content (items) is loading
104
+ * It will render a small loader in the dropdown toggle and make it disabled
105
+ */
106
+ loading: {
107
+ type: Boolean,
108
+ required: false,
109
+ default: false,
110
+ },
111
+ /**
112
+ * Additional CSS classes to customize toggle appearance
113
+ */
114
+ toggleClass: {
115
+ type: [String, Array, Object],
116
+ required: false,
117
+ default: null,
118
+ },
119
+ /**
120
+ * Set to "true" to hide the caret
121
+ */
122
+ noCaret: {
123
+ type: Boolean,
124
+ required: false,
125
+ default: false,
126
+ },
127
+ /**
128
+ * Right align disclosure dropdown with respect to the toggle button
129
+ */
130
+ right: {
131
+ type: Boolean,
132
+ required: false,
133
+ default: false,
134
+ },
135
+ /**
136
+ * The `aria-labelledby` attribute value for the toggle button
137
+ * Provide the string of ids seperated by space
138
+ */
139
+ toggleAriaLabelledBy: {
140
+ type: String,
141
+ required: false,
142
+ default: null,
143
+ },
144
+ /**
145
+ * The `aria-labelledby` attribute value for the list of options
146
+ * Provide the string of ids seperated by space
147
+ */
148
+ listAriaLabelledBy: {
149
+ type: String,
150
+ required: false,
151
+ default: null,
152
+ },
153
+ },
154
+ data() {
155
+ return {
156
+ toggleId: uniqueId('dropdown-toggle-btn-'),
157
+ disclosureId: uniqueId('disclosure-'),
158
+ nextFocusedItemIndex: null,
159
+ };
160
+ },
161
+ computed: {
162
+ disclosureOptions() {
163
+ if (this.items) {
164
+ if (isAllItems(this.items)) {
165
+ return {
166
+ tag: 'ul',
167
+ };
168
+ }
169
+
170
+ if (isAllGroups(this.items))
171
+ return {
172
+ tag: 'div',
173
+ role: 'group',
174
+ };
175
+ }
176
+
177
+ return { tag: 'div' };
178
+ },
179
+ hasCustomToggle() {
180
+ return Boolean(this.$scopedSlots.toggle);
181
+ },
182
+ },
183
+ methods: {
184
+ open() {
185
+ this.$refs.baseDropdown.open();
186
+ },
187
+ close() {
188
+ this.$refs.baseDropdown.close();
189
+ },
190
+ onShow() {
191
+ const items = this.getFocusableListItemElements();
192
+
193
+ if (items.length) {
194
+ this.focusItem(0, items);
195
+ }
196
+
197
+ /**
198
+ * Emitted when dropdown is shown
199
+ *
200
+ * @event shown
201
+ */
202
+ this.$emit(GL_DROPDOWN_SHOWN);
203
+ },
204
+ onHide() {
205
+ /**
206
+ * Emitted when dropdown is hidden
207
+ *
208
+ * @event hidden
209
+ */
210
+ this.$emit(GL_DROPDOWN_HIDDEN);
211
+ this.nextFocusedItemIndex = null;
212
+ },
213
+ onKeydown(event) {
214
+ const { code } = event;
215
+ const elements = this.getFocusableListItemElements();
216
+
217
+ if (elements.length < 1) return;
218
+
219
+ let stop = true;
220
+
221
+ if (code === HOME) {
222
+ this.focusItem(0, elements);
223
+ } else if (code === END) {
224
+ this.focusItem(elements.length - 1, elements);
225
+ } else if (code === ARROW_UP) {
226
+ this.focusNextItem(event, elements, -1);
227
+ } else if (code === ARROW_DOWN) {
228
+ this.focusNextItem(event, elements, 1);
229
+ } else {
230
+ stop = false;
231
+ }
232
+
233
+ if (stop) {
234
+ stopEvent(event);
235
+ }
236
+ },
237
+ getFocusableListItemElements() {
238
+ const items = this.$refs.content?.querySelectorAll(`.${ITEM_CLASS}`);
239
+ return Array.from(items || []);
240
+ },
241
+ focusNextItem(event, elements, offset) {
242
+ const { target } = event;
243
+ const currentIndex = elements.indexOf(target);
244
+ const nextIndex = clamp(currentIndex + offset, 0, elements.length - 1);
245
+
246
+ this.focusItem(nextIndex, elements);
247
+ },
248
+ focusItem(index, elements) {
249
+ this.nextFocusedItemIndex = index;
250
+
251
+ elements[index]?.focus();
252
+ },
253
+ closeAndFocus() {
254
+ this.$refs.baseDropdown.closeAndFocus();
255
+ },
256
+ handleAction(action) {
257
+ /**
258
+ * Emitted when one of disclosure dropdown items is clicked
259
+ *
260
+ * @event action
261
+ */
262
+ this.$emit('action', action);
263
+ },
264
+ isItem,
265
+ },
266
+ };
267
+ </script>
268
+
269
+ <template>
270
+ <gl-base-dropdown
271
+ ref="baseDropdown"
272
+ :aria-labelledby="toggleAriaLabelledBy"
273
+ :toggle-id="toggleId"
274
+ :toggle-text="toggleText"
275
+ :toggle-class="toggleClass"
276
+ :text-sr-only="textSrOnly"
277
+ :category="category"
278
+ :variant="variant"
279
+ :size="size"
280
+ :icon="icon"
281
+ :disabled="disabled"
282
+ :loading="loading"
283
+ :no-caret="noCaret"
284
+ :right="right"
285
+ class="gl-disclosure-dropdown"
286
+ @[$options.events.GL_DROPDOWN_SHOWN]="onShow"
287
+ @[$options.events.GL_DROPDOWN_HIDDEN]="onHide"
288
+ >
289
+ <template v-if="hasCustomToggle" #toggle>
290
+ <!-- @slot Custom toggle content -->
291
+ <slot name="toggle"></slot>
292
+ </template>
293
+
294
+ <!-- @slot Content to display in dropdown header -->
295
+ <slot name="header"></slot>
296
+
297
+ <component
298
+ :is="disclosureOptions.tag"
299
+ :id="disclosureId"
300
+ ref="content"
301
+ :role="disclosureOptions.role"
302
+ :aria-labelledby="listAriaLabelledBy || toggleId"
303
+ data-testid="disclosure-content"
304
+ class="gl-dropdown-contents gl-list-style-none gl-pl-0 gl-mb-0"
305
+ tabindex="-1"
306
+ @keydown="onKeydown"
307
+ >
308
+ <slot>
309
+ <template v-for="(item, index) in items">
310
+ <template v-if="isItem(item)">
311
+ <gl-disclosure-dropdown-item :key="item.text" :item="item" @action="handleAction">
312
+ <!-- @slot Custom template of the disclosure dropdown item -->
313
+ <slot name="list-item" :item="item"></slot>
314
+ </gl-disclosure-dropdown-item>
315
+ </template>
316
+
317
+ <template v-else>
318
+ <gl-disclosure-dropdown-group
319
+ :key="item.name"
320
+ :bordered="index !== 0"
321
+ :group="item"
322
+ @action="handleAction"
323
+ >
324
+ <template v-if="$scopedSlots['group-label']" #group-label>
325
+ <!-- @slot Custom template for group names -->
326
+ <slot name="group-label" :group="item"></slot>
327
+ </template>
328
+
329
+ <template #list-item>
330
+ <!-- @slot Custom template of the disclosure dropdown item -->
331
+ <slot name="list-item"></slot>
332
+ </template>
333
+ </gl-disclosure-dropdown-group>
334
+ </template>
335
+ </template>
336
+ </slot>
337
+ </component>
338
+
339
+ <!-- @slot Content to display in dropdown footer -->
340
+ <slot name="footer"></slot>
341
+ </gl-base-dropdown>
342
+ </template>