@gitlab/ui 55.3.0 → 55.3.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [55.3.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v55.3.0...v55.3.1) (2023-02-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **GlDisclosureDropdown:** Improve markup semantics of dropdown wrapper ([79b1922](https://gitlab.com/gitlab-org/gitlab-ui/commit/79b19229c617904cc300a58d54c6ff04b742bb53))
7
+
1
8
  # [55.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v55.2.1...v55.3.0) (2023-02-16)
2
9
 
3
10
 
@@ -0,0 +1,4 @@
1
+ const DISCLOSURE_DROPDOWN_ITEM_NAME = 'GlDisclosureDropdownItem';
2
+ const DISCLOSURE_DROPDOWN_GROUP_NAME = 'GlDisclosureDropdownGroup';
3
+
4
+ export { DISCLOSURE_DROPDOWN_GROUP_NAME, DISCLOSURE_DROPDOWN_ITEM_NAME };
@@ -6,7 +6,7 @@ import { buttonCategoryOptions, dropdownVariantOptions, buttonSizeOptions, dropd
6
6
  import GlBaseDropdown from '../base_dropdown/base_dropdown';
7
7
  import GlDisclosureDropdownItem, { ITEM_CLASS } from './disclosure_dropdown_item';
8
8
  import GlDisclosureDropdownGroup from './disclosure_dropdown_group';
9
- import { itemsValidator, isAllItems, isAllGroups, isItem } from './utils';
9
+ import { itemsValidator, hasOnlyListItems, isItem } from './utils';
10
10
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
11
11
 
12
12
  var script = {
@@ -157,21 +157,12 @@ var script = {
157
157
  };
158
158
  },
159
159
  computed: {
160
- disclosureOptions() {
161
- if (this.items) {
162
- if (isAllItems(this.items)) {
163
- return {
164
- tag: 'ul'
165
- };
166
- }
167
- if (isAllGroups(this.items)) return {
168
- tag: 'div',
169
- role: 'group'
170
- };
160
+ disclosureTag() {
161
+ var _this$items;
162
+ if ((_this$items = this.items) !== null && _this$items !== void 0 && _this$items.length || hasOnlyListItems(this.$scopedSlots)) {
163
+ return 'ul';
171
164
  }
172
- return {
173
- tag: 'div'
174
- };
165
+ return 'div';
175
166
  },
176
167
  hasCustomToggle() {
177
168
  return Boolean(this.$scopedSlots.toggle);
@@ -265,7 +256,7 @@ var script = {
265
256
  const __vue_script__ = script;
266
257
 
267
258
  /* template */
268
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureOptions.tag,{ref:"content",tag:"component",staticClass:"gl-new-dropdown-contents",attrs:{"id":_vm.disclosureId,"role":_vm.disclosureOptions.role,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:item.text,attrs:{"item":item},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":item})],2)]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:groupItem.text,attrs:{"item":groupItem},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":groupItem})],2)}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
259
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureTag,{ref:"content",tag:"component",staticClass:"gl-new-dropdown-contents",attrs:{"id":_vm.disclosureId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:item.text,attrs:{"item":item},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":item})],2)]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:groupItem.text,attrs:{"item":groupItem},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":groupItem})],2)}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
269
260
  var __vue_staticRenderFns__ = [];
270
261
 
271
262
  /* style */
@@ -1,10 +1,12 @@
1
1
  import _uniqueId from 'lodash/uniqueId';
2
2
  import GlDisclosureDropdownItem from './disclosure_dropdown_item';
3
3
  import { isGroup } from './utils';
4
+ import { DISCLOSURE_DROPDOWN_GROUP_NAME } from './constants';
4
5
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
5
6
 
6
7
  const GROUP_TOP_BORDER_CLASSES = 'gl-border-t gl-pt-2 gl-mt-2';
7
8
  var script = {
9
+ name: DISCLOSURE_DROPDOWN_GROUP_NAME,
8
10
  components: {
9
11
  GlDisclosureDropdownItem
10
12
  },
@@ -54,7 +56,7 @@ var script = {
54
56
  const __vue_script__ = script;
55
57
 
56
58
  /* template */
57
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:_vm.borderClass},[(_vm.showHeader)?_c('div',{staticClass:"gl-pl-4 gl-py-2 gl-font-sm gl-font-weight-bold",attrs:{"id":_vm.nameId,"aria-hidden":"true"}},[_vm._t("group-label",function(){return [_vm._v(_vm._s(_vm.group.name))]})],2):_vm._e(),_vm._v(" "),_c('ul',{staticClass:"gl-mb-0 gl-pl-0 gl-list-style-none",attrs:{"role":"group","aria-labelledby":_vm.groupLabeledBy}},[_vm._t("default",function(){return _vm._l((_vm.group.items),function(item){return _c('gl-disclosure-dropdown-item',{key:item.text,attrs:{"item":item},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":item})],2)})})],2)])};
59
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('li',{class:_vm.borderClass},[(_vm.showHeader)?_c('div',{staticClass:"gl-pl-4 gl-py-2 gl-font-sm gl-font-weight-bold",attrs:{"id":_vm.nameId,"aria-hidden":"true"}},[_vm._t("group-label",function(){return [_vm._v(_vm._s(_vm.group.name))]})],2):_vm._e(),_vm._v(" "),_c('ul',{staticClass:"gl-mb-0 gl-pl-0 gl-list-style-none",attrs:{"role":"group","aria-labelledby":_vm.groupLabeledBy}},[_vm._t("default",function(){return _vm._l((_vm.group.items),function(item){return _c('gl-disclosure-dropdown-item',{key:item.text,attrs:{"item":item},on:{"action":_vm.handleAction}},[_vm._t("list-item",null,{"item":item})],2)})})],2)])};
58
60
  var __vue_staticRenderFns__ = [];
59
61
 
60
62
  /* style */
@@ -1,10 +1,12 @@
1
1
  import { ENTER, SPACE } from '../constants';
2
2
  import { stopEvent } from '../../../../utils/utils';
3
3
  import { isItem } from './utils';
4
+ import { DISCLOSURE_DROPDOWN_ITEM_NAME } from './constants';
4
5
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
5
6
 
6
7
  const ITEM_CLASS = 'gl-new-dropdown-item';
7
8
  var script = {
9
+ name: DISCLOSURE_DROPDOWN_ITEM_NAME,
8
10
  ITEM_CLASS,
9
11
  props: {
10
12
  item: {
@@ -1,3 +1,6 @@
1
+ import _isFunction from 'lodash/isFunction';
2
+ import { DISCLOSURE_DROPDOWN_ITEM_NAME, DISCLOSURE_DROPDOWN_GROUP_NAME } from './constants';
3
+
1
4
  const itemValidator = item => {
2
5
  var _item$text;
3
6
  return (item === null || item === void 0 ? void 0 : (_item$text = item.text) === null || _item$text === void 0 ? void 0 : _item$text.length) > 0 && !Array.isArray(item === null || item === void 0 ? void 0 : item.items);
@@ -5,7 +8,24 @@ const itemValidator = item => {
5
8
  const isItem = item => Boolean(item) && itemValidator(item);
6
9
  const isGroup = group => Boolean(group) && Array.isArray(group.items) && Boolean(group.items.length) && group.items.every(isItem);
7
10
  const itemsValidator = items => items.every(isItem) || items.every(isGroup);
8
- const isAllItems = items => items.every(isItem);
9
- const isAllGroups = items => items.every(isGroup);
11
+ const isListItem = tag => ['gl-disclosure-dropdown-group', 'gl-disclosure-dropdown-item', 'li'].includes(tag);
12
+ const isValidSlotTagVue2 = vNode => {
13
+ var _vNode$componentOptio;
14
+ return Boolean(vNode) && isListItem(((_vNode$componentOptio = vNode.componentOptions) === null || _vNode$componentOptio === void 0 ? void 0 : _vNode$componentOptio.tag) || vNode.tag);
15
+ };
16
+ const isValidSlotTag = vNode => {
17
+ var _vNode$type;
18
+ return [DISCLOSURE_DROPDOWN_ITEM_NAME, DISCLOSURE_DROPDOWN_GROUP_NAME].includes((_vNode$type = vNode.type) === null || _vNode$type === void 0 ? void 0 : _vNode$type.name) || vNode.type === 'li';
19
+ };
20
+ const hasOnlyListItems = _ref => {
21
+ let {
22
+ default: defaultSlot
23
+ } = _ref;
24
+ if (!_isFunction(defaultSlot)) {
25
+ return false;
26
+ }
27
+ const nodes = defaultSlot();
28
+ return Array.isArray(nodes) && nodes.filter(vNode => vNode.tag).length && (nodes.filter(vNode => vNode.tag).every(isValidSlotTagVue2) || nodes.filter(vNode => vNode.tag).every(isValidSlotTag));
29
+ };
10
30
 
11
- export { isAllGroups, isAllItems, isGroup, isItem, itemsValidator };
31
+ export { hasOnlyListItems, isGroup, isItem, itemsValidator };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "55.3.0",
3
+ "version": "55.3.1",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,2 @@
1
+ export const DISCLOSURE_DROPDOWN_ITEM_NAME = 'GlDisclosureDropdownItem';
2
+ export const DISCLOSURE_DROPDOWN_GROUP_NAME = 'GlDisclosureDropdownGroup';
@@ -22,6 +22,7 @@ describe('GlDisclosureDropdown', () => {
22
22
  const buildWrapper = (propsData, slots = {}) => {
23
23
  wrapper = mount(GlDisclosureDropdown, {
24
24
  propsData,
25
+ components: { GlDisclosureDropdownItem, GlDisclosureDropdownGroup },
25
26
  slots,
26
27
  attachTo: document.body,
27
28
  });
@@ -216,23 +217,65 @@ describe('GlDisclosureDropdown', () => {
216
217
  });
217
218
  });
218
219
 
219
- describe('disclosure options', () => {
220
- it('should render the `ul` as content tag and not add `role` attribute when it is a list of items only', () => {
220
+ describe('disclosure tag', () => {
221
+ it('should render `ul` as content tag when items is a list of items', () => {
221
222
  buildWrapper({ items: mockItems });
222
223
  expect(findDisclosureContent().element.tagName).toBe('UL');
223
- expect(findDisclosureContent().attributes('role')).toBeUndefined();
224
224
  });
225
225
 
226
- it('should render the `div` as content tag and add `role` attribute when it is a list of groups', () => {
226
+ it('should render `ul` as content tag when items is a list of groups', () => {
227
227
  buildWrapper({ items: mockGroups });
228
+ expect(findDisclosureContent().element.tagName).toBe('UL');
229
+ });
230
+
231
+ it('should render `ul` as content tag when default slot contains only groups', () => {
232
+ const slots = {
233
+ default: `
234
+ <gl-disclosure-dropdown-group>
235
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
236
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
237
+ </gl-disclosure-dropdown-group>
238
+ <gl-disclosure-dropdown-group>
239
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
240
+ </gl-disclosure-dropdown-group>
241
+ `,
242
+ };
243
+
244
+ buildWrapper({}, slots);
245
+ expect(findDisclosureContent().element.tagName).toBe('UL');
246
+ });
247
+
248
+ it('should render `ul` as content tag when default slot contains only items', () => {
249
+ const slots = {
250
+ default: `
251
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
252
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
253
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
254
+ `,
255
+ };
256
+
257
+ buildWrapper({}, slots);
258
+ expect(findDisclosureContent().element.tagName).toBe('UL');
259
+ });
260
+
261
+ it('should render `div` as content tag when default slot does not contain valid list item', () => {
262
+ const slots = {
263
+ default: `
264
+ <div>Item</div>
265
+ <gl-disclosure-dropdown-group>
266
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
267
+ <gl-disclosure-dropdown-item>Item</gl-disclosure-dropdown-item>
268
+ </gl-disclosure-dropdown-group>
269
+ `,
270
+ };
271
+
272
+ buildWrapper({}, slots);
228
273
  expect(findDisclosureContent().element.tagName).toBe('DIV');
229
- expect(findDisclosureContent().attributes('role')).toBe('group');
230
274
  });
231
275
 
232
- it('should render the `div` as content tag and NOT add `role` otherwise', () => {
233
- buildWrapper({ items: null }, { default: 'Some other content' });
276
+ it('should render `div` as content tag when slot is not a list item', () => {
277
+ buildWrapper({}, { default: 'Some other content' });
234
278
  expect(findDisclosureContent().element.tagName).toBe('DIV');
235
- expect(findDisclosureContent().attributes('role')).toBeUndefined();
236
279
  });
237
280
  });
238
281
  });
@@ -52,13 +52,16 @@ function openDisclosure(component) {
52
52
  });
53
53
  }
54
54
 
55
- const template = (content, { bindingOverrides = {} } = {}) => `
55
+ const template = (content, { bindingOverrides = {} } = {}, after) => `
56
+ <div>
56
57
  <gl-disclosure-dropdown
57
58
  ref="disclosure"
58
59
  ${makeBindings(bindingOverrides)}
59
60
  >
60
61
  ${content || ''}
61
62
  </gl-disclosure-dropdown>
63
+ ${after || ''}
64
+ </div>
62
65
  `;
63
66
 
64
67
  const TOGGLE_ID = 'custom-toggle-id';
@@ -217,15 +220,14 @@ CustomGroupsAndItems.args = {
217
220
  CustomGroupsAndItems.decorators = [makeContainer({ height: '200px' })];
218
221
 
219
222
  export const CustomGroupsItemsAndToggle = makeGroupedExample({
220
- template: template(`
221
- <template #toggle>
222
- <span class="gl-sr-only">
223
- Orange Fox user's menu
224
- </span>
225
- <gl-avatar :size="32" entity-name="Orange Fox" aria-hidden="true"></gl-avatar>
226
- </template>
227
-
228
- <div role="group">
223
+ template: template(
224
+ `
225
+ <template #toggle>
226
+ <span class="gl-sr-only">
227
+ Orange Fox user's menu
228
+ </span>
229
+ <gl-avatar :size="32" entity-name="Orange Fox" aria-hidden="true"></gl-avatar>
230
+ </template>
229
231
  <gl-disclosure-dropdown-group>
230
232
  <gl-disclosure-dropdown-item>
231
233
  <span class="gl-display-flex gl-flex-direction-column">
@@ -256,15 +258,18 @@ export const CustomGroupsItemsAndToggle = makeGroupedExample({
256
258
  <gl-toggle label="New navigation" label-position="left" v-model="newNavigation"/>
257
259
  </gl-disclosure-dropdown-item>
258
260
  <gl-disclosure-dropdown-item @action="toggleModalVisibility(true)">
259
- <a>Provide feedback</a>
261
+ Provide feedback
260
262
  </gl-disclosure-dropdown-item>
261
263
  </gl-disclosure-dropdown-group>
262
264
  <gl-disclosure-dropdown-group bordered :group="$options.groups[1]"> </gl-disclosure-dropdown-group>
265
+ `,
266
+ {},
267
+ `
263
268
  <gl-modal :visible="feedBackModalVisible" @change="toggleModalVisibility" modal-id="feedbackModal" size="sm">
264
269
  <textarea class="gl-w-full">Tell us what you think!</textarea>
265
270
  </gl-modal>
266
- </div>
267
- `),
271
+ `
272
+ ),
268
273
  data() {
269
274
  return {
270
275
  newNavigation: true,
@@ -19,7 +19,7 @@ import {
19
19
  import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
20
20
  import GlDisclosureDropdownItem, { ITEM_CLASS } from './disclosure_dropdown_item.vue';
21
21
  import GlDisclosureDropdownGroup from './disclosure_dropdown_group.vue';
22
- import { itemsValidator, isItem, isAllItems, isAllGroups } from './utils';
22
+ import { itemsValidator, isItem, hasOnlyListItems } from './utils';
23
23
 
24
24
  export default {
25
25
  events: {
@@ -169,22 +169,11 @@ export default {
169
169
  };
170
170
  },
171
171
  computed: {
172
- disclosureOptions() {
173
- if (this.items) {
174
- if (isAllItems(this.items)) {
175
- return {
176
- tag: 'ul',
177
- };
178
- }
179
-
180
- if (isAllGroups(this.items))
181
- return {
182
- tag: 'div',
183
- role: 'group',
184
- };
172
+ disclosureTag() {
173
+ if (this.items?.length || hasOnlyListItems(this.$scopedSlots)) {
174
+ return 'ul';
185
175
  }
186
-
187
- return { tag: 'div' };
176
+ return 'div';
188
177
  },
189
178
  hasCustomToggle() {
190
179
  return Boolean(this.$scopedSlots.toggle);
@@ -305,10 +294,9 @@ export default {
305
294
  <slot name="header"></slot>
306
295
 
307
296
  <component
308
- :is="disclosureOptions.tag"
297
+ :is="disclosureTag"
309
298
  :id="disclosureId"
310
299
  ref="content"
311
- :role="disclosureOptions.role"
312
300
  :aria-labelledby="listAriaLabelledBy || toggleId"
313
301
  data-testid="disclosure-content"
314
302
  class="gl-new-dropdown-contents"
@@ -2,10 +2,12 @@
2
2
  import { uniqueId } from 'lodash';
3
3
  import GlDisclosureDropdownItem from './disclosure_dropdown_item.vue';
4
4
  import { isGroup } from './utils';
5
+ import { DISCLOSURE_DROPDOWN_GROUP_NAME } from './constants';
5
6
 
6
7
  export const GROUP_TOP_BORDER_CLASSES = 'gl-border-t gl-pt-2 gl-mt-2';
7
8
 
8
9
  export default {
10
+ name: DISCLOSURE_DROPDOWN_GROUP_NAME,
9
11
  components: {
10
12
  GlDisclosureDropdownItem,
11
13
  },
@@ -52,7 +54,7 @@ export default {
52
54
  </script>
53
55
 
54
56
  <template>
55
- <div :class="borderClass">
57
+ <li :class="borderClass">
56
58
  <div
57
59
  v-if="showHeader"
58
60
  :id="nameId"
@@ -73,5 +75,5 @@ export default {
73
75
  </gl-disclosure-dropdown-item>
74
76
  </slot>
75
77
  </ul>
76
- </div>
78
+ </li>
77
79
  </template>
@@ -2,10 +2,12 @@
2
2
  import { ENTER, SPACE } from '../constants';
3
3
  import { stopEvent } from '../../../../utils/utils';
4
4
  import { isItem } from './utils';
5
+ import { DISCLOSURE_DROPDOWN_ITEM_NAME } from './constants';
5
6
 
6
7
  export const ITEM_CLASS = 'gl-new-dropdown-item';
7
8
 
8
9
  export default {
10
+ name: DISCLOSURE_DROPDOWN_ITEM_NAME,
9
11
  ITEM_CLASS,
10
12
  props: {
11
13
  item: {
@@ -1,3 +1,6 @@
1
+ import { isFunction } from 'lodash';
2
+ import { DISCLOSURE_DROPDOWN_ITEM_NAME, DISCLOSURE_DROPDOWN_GROUP_NAME } from './constants';
3
+
1
4
  const itemValidator = (item) => item?.text?.length > 0 && !Array.isArray(item?.items);
2
5
 
3
6
  const isItem = (item) => Boolean(item) && itemValidator(item);
@@ -10,8 +13,30 @@ const isGroup = (group) =>
10
13
 
11
14
  const itemsValidator = (items) => items.every(isItem) || items.every(isGroup);
12
15
 
13
- const isAllItems = (items) => items.every(isItem);
16
+ const isListItem = (tag) =>
17
+ ['gl-disclosure-dropdown-group', 'gl-disclosure-dropdown-item', 'li'].includes(tag);
18
+
19
+ const isValidSlotTagVue2 = (vNode) =>
20
+ Boolean(vNode) && isListItem(vNode.componentOptions?.tag || vNode.tag);
21
+
22
+ const isValidSlotTag = (vNode) => {
23
+ return (
24
+ [DISCLOSURE_DROPDOWN_ITEM_NAME, DISCLOSURE_DROPDOWN_GROUP_NAME].includes(vNode.type?.name) ||
25
+ vNode.type === 'li'
26
+ );
27
+ };
14
28
 
15
- const isAllGroups = (items) => items.every(isGroup);
29
+ const hasOnlyListItems = ({ default: defaultSlot }) => {
30
+ if (!isFunction(defaultSlot)) {
31
+ return false;
32
+ }
33
+ const nodes = defaultSlot();
34
+ return (
35
+ Array.isArray(nodes) &&
36
+ nodes.filter((vNode) => vNode.tag).length &&
37
+ (nodes.filter((vNode) => vNode.tag).every(isValidSlotTagVue2) ||
38
+ nodes.filter((vNode) => vNode.tag).every(isValidSlotTag))
39
+ );
40
+ };
16
41
 
17
- export { itemsValidator, isItem, isGroup, isAllItems, isAllGroups };
42
+ export { itemsValidator, isItem, isGroup, hasOnlyListItems };