@gitlab/ui 55.3.1 → 56.0.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 +22 -0
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +1 -1
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.js +1 -1
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.js +30 -16
- package/package.json +3 -3
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.md +4 -15
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.stories.js +24 -34
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +8 -4
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.spec.js +5 -2
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_group.vue +3 -1
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.spec.js +44 -42
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown_item.vue +37 -25
- package/src/components/charts/chart/chart.md +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## [56.0.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v56.0.0...v56.0.1) (2023-02-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** update dependency dompurify to ^2.4.4 ([c90c17b](https://gitlab.com/gitlab-org/gitlab-ui/commit/c90c17b307da010cacb566800f9cf5922124f28e))
|
|
7
|
+
|
|
8
|
+
# [56.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v55.3.1...v56.0.0) (2023-02-16)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **GlDisclosureDropdown:** wrap custom item content in `button` or `link` ([684386d](https://gitlab.com/gitlab-org/gitlab-ui/commit/684386d4dd66c4ce85538faec1b35b9c5c370926))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### BREAKING CHANGES
|
|
17
|
+
|
|
18
|
+
* **GlDisclosureDropdown:** It will cause styling and semantic issues
|
|
19
|
+
in the downstream project.
|
|
20
|
+
Wherever the `list-item` slot is used with a `button` or `a` inside
|
|
21
|
+
it wrapping the content, this wrapper `button/a` needs to be removed.
|
|
22
|
+
|
|
1
23
|
## [55.3.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v55.3.0...v55.3.1) (2023-02-16)
|
|
2
24
|
|
|
3
25
|
|
|
@@ -256,7 +256,7 @@ var script = {
|
|
|
256
256
|
const __vue_script__ = script;
|
|
257
257
|
|
|
258
258
|
/* template */
|
|
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}
|
|
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},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}],null,true)})]:[_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},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":groupItem})]},proxy:true}],null,true)})}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
|
|
260
260
|
var __vue_staticRenderFns__ = [];
|
|
261
261
|
|
|
262
262
|
/* style */
|
|
@@ -56,7 +56,7 @@ var script = {
|
|
|
56
56
|
const __vue_script__ = script;
|
|
57
57
|
|
|
58
58
|
/* template */
|
|
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}
|
|
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},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}],null,true)})})})],2)])};
|
|
60
60
|
var __vue_staticRenderFns__ = [];
|
|
61
61
|
|
|
62
62
|
/* style */
|
|
@@ -28,7 +28,6 @@ var script = {
|
|
|
28
28
|
const {
|
|
29
29
|
item
|
|
30
30
|
} = this;
|
|
31
|
-
if (!item) return null;
|
|
32
31
|
if (this.isLink) return {
|
|
33
32
|
is: 'a',
|
|
34
33
|
attrs: {
|
|
@@ -36,22 +35,34 @@ var script = {
|
|
|
36
35
|
...item.extraAttrs
|
|
37
36
|
},
|
|
38
37
|
wrapperClass: item.wrapperClass,
|
|
39
|
-
listeners: {
|
|
38
|
+
listeners: {
|
|
39
|
+
click: this.action
|
|
40
|
+
}
|
|
40
41
|
};
|
|
41
42
|
return {
|
|
42
43
|
is: 'button',
|
|
43
44
|
attrs: {
|
|
44
|
-
...item.extraAttrs,
|
|
45
|
+
...(item === null || item === void 0 ? void 0 : item.extraAttrs),
|
|
45
46
|
type: 'button'
|
|
46
47
|
},
|
|
47
48
|
listeners: {
|
|
48
49
|
click: () => {
|
|
49
50
|
var _item$action;
|
|
50
|
-
|
|
51
|
+
item === null || item === void 0 ? void 0 : (_item$action = item.action) === null || _item$action === void 0 ? void 0 : _item$action.call(undefined, item);
|
|
52
|
+
this.action();
|
|
51
53
|
}
|
|
52
54
|
},
|
|
53
|
-
wrapperClass: item.wrapperClass
|
|
55
|
+
wrapperClass: item === null || item === void 0 ? void 0 : item.wrapperClass
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
wrapperListeners() {
|
|
59
|
+
const listeners = {
|
|
60
|
+
keydown: this.onKeydown
|
|
54
61
|
};
|
|
62
|
+
if (this.isCustomContent) {
|
|
63
|
+
listeners.click = this.action;
|
|
64
|
+
}
|
|
65
|
+
return listeners;
|
|
55
66
|
}
|
|
56
67
|
},
|
|
57
68
|
methods: {
|
|
@@ -60,17 +71,20 @@ var script = {
|
|
|
60
71
|
code
|
|
61
72
|
} = event;
|
|
62
73
|
if (code === ENTER || code === SPACE) {
|
|
63
|
-
var _this$$refs$item;
|
|
64
74
|
stopEvent(event);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
if (this.isCustomContent) {
|
|
76
|
+
this.action();
|
|
77
|
+
} else {
|
|
78
|
+
var _this$$refs$item;
|
|
79
|
+
/** Instead of simply navigating or calling the action, we want
|
|
80
|
+
* the `a/button` to be the target of the event as it might have additional attributes.
|
|
81
|
+
* E.g. `a` might have `target` attribute.
|
|
82
|
+
*/
|
|
83
|
+
(_this$$refs$item = this.$refs.item) === null || _this$$refs$item === void 0 ? void 0 : _this$$refs$item.dispatchEvent(new MouseEvent('click', {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
cancelable: true
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
74
88
|
}
|
|
75
89
|
},
|
|
76
90
|
action() {
|
|
@@ -83,7 +97,7 @@ var script = {
|
|
|
83
97
|
const __vue_script__ = script;
|
|
84
98
|
|
|
85
99
|
/* template */
|
|
86
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('li',{class:[_vm.$options.ITEM_CLASS, _vm.itemComponent
|
|
100
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('li',_vm._g({class:[_vm.$options.ITEM_CLASS, _vm.itemComponent.wrapperClass],attrs:{"tabindex":"0","data-testid":"disclosure-dropdown-item"}},_vm.wrapperListeners),[_vm._t("default",function(){return [_c(_vm.itemComponent.is,_vm._g(_vm._b({ref:"item",tag:"component",staticClass:"gl-new-dropdown-item-content",attrs:{"tabindex":"-1"}},'component',_vm.itemComponent.attrs,false),_vm.itemComponent.listeners),[_c('span',{staticClass:"gl-new-dropdown-item-text-wrapper"},[_vm._t("list-item",function(){return [_vm._v("\n "+_vm._s(_vm.item.text)+"\n ")]})],2)])]})],2)};
|
|
87
101
|
var __vue_staticRenderFns__ = [];
|
|
88
102
|
|
|
89
103
|
/* style */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "56.0.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@popperjs/core": "^2.11.2",
|
|
64
64
|
"bootstrap-vue": "2.20.1",
|
|
65
|
-
"dompurify": "^2.4.
|
|
65
|
+
"dompurify": "^2.4.4",
|
|
66
66
|
"echarts": "^5.3.2",
|
|
67
67
|
"iframe-resizer": "^4.3.2",
|
|
68
68
|
"lodash": "^4.17.20",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"bootstrap-vue-vue3": "npm:bootstrap-vue@2.23.1",
|
|
116
116
|
"cypress": "^11.2.0",
|
|
117
117
|
"emoji-regex": "^10.0.0",
|
|
118
|
-
"eslint": "8.
|
|
118
|
+
"eslint": "8.34.0",
|
|
119
119
|
"eslint-import-resolver-jest": "3.0.2",
|
|
120
120
|
"eslint-plugin-cypress": "2.12.1",
|
|
121
121
|
"eslint-plugin-storybook": "0.6.10",
|
|
@@ -88,25 +88,14 @@ template. If you want to render a custom template for items, use the
|
|
|
88
88
|
```html
|
|
89
89
|
<gl-disclosure-dropdown :items="items">
|
|
90
90
|
<template #list-item="{ item }">
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
v-bind="item.extraAttrs"
|
|
96
|
-
>
|
|
97
|
-
{{ item.text }}
|
|
98
|
-
<gl-badge v-if="item.count" pill variant="info">{{ item.count }}</gl-badge>
|
|
99
|
-
</a>
|
|
91
|
+
<span class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
|
|
92
|
+
{{item.text}}
|
|
93
|
+
<gl-icon v-if="item.icon" :name="item.icon"/>
|
|
94
|
+
</span>
|
|
100
95
|
</template>
|
|
101
96
|
</gl-disclosure-dropdown>
|
|
102
97
|
```
|
|
103
98
|
|
|
104
|
-
**Note:** when providing custom content to the item, user should
|
|
105
|
-
define the correct tab order inside the disclosure dropdown by setting
|
|
106
|
-
the `tabindex` attribute on the elements.
|
|
107
|
-
The `li` item will get the focus so you might want elements inside it
|
|
108
|
-
not to be focused - this can be done by setting `tabindex="-1"` on them.
|
|
109
|
-
|
|
110
99
|
#### Groups
|
|
111
100
|
|
|
112
101
|
Actions/links can be contained within groups. A group can have a `name`
|
|
@@ -107,23 +107,17 @@ export const CustomListItem = (args, { argTypes }) => ({
|
|
|
107
107
|
openDisclosure(this);
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
|
-
methods: {
|
|
111
|
-
navigate() {
|
|
112
|
-
this.$refs.link.click();
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
110
|
template: template(
|
|
116
111
|
`
|
|
117
112
|
<template #list-item="{ item }">
|
|
118
|
-
<
|
|
113
|
+
<span class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
|
|
119
114
|
{{ item.text }}
|
|
120
115
|
<gl-badge pill size="sm" variant="neutral">{{ item.count }}</gl-badge>
|
|
121
|
-
</
|
|
116
|
+
</span>
|
|
122
117
|
</template>
|
|
123
118
|
`,
|
|
124
119
|
{
|
|
125
120
|
bindingOverrides: {
|
|
126
|
-
'@action': 'navigate',
|
|
127
121
|
class: 'gl-display-block! gl-text-center',
|
|
128
122
|
},
|
|
129
123
|
}
|
|
@@ -186,9 +180,6 @@ export const CustomGroupsAndItems = (args, { argTypes }) => ({
|
|
|
186
180
|
}
|
|
187
181
|
},
|
|
188
182
|
methods: {
|
|
189
|
-
navigate() {
|
|
190
|
-
this.$refs.link.click();
|
|
191
|
-
},
|
|
192
183
|
getTotalMrs(items) {
|
|
193
184
|
return items.reduce((acc, item) => acc + item.count, 0);
|
|
194
185
|
},
|
|
@@ -199,17 +190,12 @@ export const CustomGroupsAndItems = (args, { argTypes }) => ({
|
|
|
199
190
|
{{ group.name }} <gl-badge pill size="sm" variant="neutral">{{ getTotalMrs(group.items) }}</gl-badge>
|
|
200
191
|
</template>
|
|
201
192
|
<template #list-item="{ item }">
|
|
202
|
-
<
|
|
193
|
+
<span class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
|
|
203
194
|
{{ item.text }}
|
|
204
195
|
<gl-badge pill size="sm" variant="neutral">{{ item.count }}</gl-badge>
|
|
205
|
-
</
|
|
196
|
+
</span>
|
|
206
197
|
</template>
|
|
207
|
-
|
|
208
|
-
{
|
|
209
|
-
bindingOverrides: {
|
|
210
|
-
'@action': 'navigate',
|
|
211
|
-
},
|
|
212
|
-
}
|
|
198
|
+
`
|
|
213
199
|
),
|
|
214
200
|
});
|
|
215
201
|
|
|
@@ -230,23 +216,20 @@ export const CustomGroupsItemsAndToggle = makeGroupedExample({
|
|
|
230
216
|
</template>
|
|
231
217
|
<gl-disclosure-dropdown-group>
|
|
232
218
|
<gl-disclosure-dropdown-item>
|
|
233
|
-
<
|
|
234
|
-
<span class="gl-
|
|
235
|
-
|
|
236
|
-
|
|
219
|
+
<template #list-item>
|
|
220
|
+
<span class="gl-display-flex gl-flex-direction-column">
|
|
221
|
+
<span class="gl-font-weight-bold gl-white-space-nowrap">Orange Fox</span>
|
|
222
|
+
<span class="gl-text-gray-400">@thefox</span>
|
|
223
|
+
</span>
|
|
224
|
+
</template>
|
|
237
225
|
</gl-disclosure-dropdown-item>
|
|
238
226
|
</gl-disclosure-dropdown-group>
|
|
239
227
|
<gl-disclosure-dropdown-group bordered :group="$options.groups[0]">
|
|
240
228
|
<template #list-item="{ item }">
|
|
241
|
-
<
|
|
242
|
-
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"
|
|
243
|
-
:href="item.href"
|
|
244
|
-
tabindex="-1"
|
|
245
|
-
v-bind="item.extraAttrs"
|
|
246
|
-
>
|
|
229
|
+
<span class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
|
|
247
230
|
{{item.text}}
|
|
248
231
|
<gl-icon v-if="item.icon" :name="item.icon"/>
|
|
249
|
-
</
|
|
232
|
+
</span>
|
|
250
233
|
</template>
|
|
251
234
|
</gl-disclosure-dropdown-group>
|
|
252
235
|
<gl-disclosure-dropdown-group bordered>
|
|
@@ -254,14 +237,18 @@ export const CustomGroupsItemsAndToggle = makeGroupedExample({
|
|
|
254
237
|
<span class="gl-font-sm">Navigation redesign</span>
|
|
255
238
|
<gl-badge size="sm" variant="info">Beta</gl-badge>
|
|
256
239
|
</template>
|
|
257
|
-
<gl-disclosure-dropdown-item>
|
|
258
|
-
<
|
|
240
|
+
<gl-disclosure-dropdown-item @action="toggleNewNavigation">
|
|
241
|
+
<div class="gl-new-dropdown-item-content">
|
|
242
|
+
<div class="gl-new-dropdown-item-text-wrapper">
|
|
243
|
+
<gl-toggle label="New navigation" label-position="left" :value="newNavigation"/>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
259
246
|
</gl-disclosure-dropdown-item>
|
|
260
247
|
<gl-disclosure-dropdown-item @action="toggleModalVisibility(true)">
|
|
261
|
-
Provide feedback
|
|
248
|
+
<template #list-item>Provide feedback</template>
|
|
262
249
|
</gl-disclosure-dropdown-item>
|
|
263
250
|
</gl-disclosure-dropdown-group>
|
|
264
|
-
<gl-disclosure-dropdown-group bordered :group="$options.groups[1]"
|
|
251
|
+
<gl-disclosure-dropdown-group bordered :group="$options.groups[1]"/>
|
|
265
252
|
`,
|
|
266
253
|
{},
|
|
267
254
|
`
|
|
@@ -280,6 +267,9 @@ export const CustomGroupsItemsAndToggle = makeGroupedExample({
|
|
|
280
267
|
toggleModalVisibility(value) {
|
|
281
268
|
this.feedBackModalVisible = value;
|
|
282
269
|
},
|
|
270
|
+
toggleNewNavigation() {
|
|
271
|
+
this.newNavigation = !this.newNavigation;
|
|
272
|
+
},
|
|
283
273
|
},
|
|
284
274
|
groups: mockProfileGroups,
|
|
285
275
|
});
|
|
@@ -307,8 +307,10 @@ export default {
|
|
|
307
307
|
<template v-for="(item, index) in items">
|
|
308
308
|
<template v-if="isItem(item)">
|
|
309
309
|
<gl-disclosure-dropdown-item :key="item.text" :item="item" @action="handleAction">
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
<template #list-item>
|
|
311
|
+
<!-- @slot Custom template of the disclosure dropdown item -->
|
|
312
|
+
<slot name="list-item" :item="item"></slot>
|
|
313
|
+
</template>
|
|
312
314
|
</gl-disclosure-dropdown-item>
|
|
313
315
|
</template>
|
|
314
316
|
|
|
@@ -331,8 +333,10 @@ export default {
|
|
|
331
333
|
:item="groupItem"
|
|
332
334
|
@action="handleAction"
|
|
333
335
|
>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
+
<template #list-item>
|
|
337
|
+
<!-- @slot Custom template of the disclosure dropdown item -->
|
|
338
|
+
<slot name="list-item" :item="groupItem"></slot>
|
|
339
|
+
</template>
|
|
336
340
|
</gl-disclosure-dropdown-item>
|
|
337
341
|
</template>
|
|
338
342
|
</gl-disclosure-dropdown-group>
|
|
@@ -14,6 +14,9 @@ describe('GlDisclosureDropdownGroup', () => {
|
|
|
14
14
|
group: mockGroups[0],
|
|
15
15
|
...propsData,
|
|
16
16
|
},
|
|
17
|
+
stubs: {
|
|
18
|
+
GlDisclosureDropdownItem,
|
|
19
|
+
},
|
|
17
20
|
slots,
|
|
18
21
|
});
|
|
19
22
|
};
|
|
@@ -38,9 +41,9 @@ describe('GlDisclosureDropdownGroup', () => {
|
|
|
38
41
|
expect(findItems()).toHaveLength(mockGroups[0].items.length);
|
|
39
42
|
});
|
|
40
43
|
|
|
41
|
-
it('renders `list-item` content in a
|
|
44
|
+
it('renders `list-item` content in a `list-item` slot of `GlDisclosureDropdownItem`', () => {
|
|
42
45
|
buildWrapper({
|
|
43
|
-
slots: { 'list-item': '<
|
|
46
|
+
slots: { 'list-item': '<span data-testid="list-item-content"></span>' },
|
|
44
47
|
});
|
|
45
48
|
|
|
46
49
|
expect(findItems()).toHaveLength(mockGroups[0].items.length);
|
|
@@ -37,13 +37,17 @@ describe('GlDisclosureDropdownItem', () => {
|
|
|
37
37
|
${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
|
|
38
38
|
`(`$event should emit 'action' event`, ({ trigger }) => {
|
|
39
39
|
trigger();
|
|
40
|
-
|
|
40
|
+
const emittedAction = wrapper.emitted('action');
|
|
41
|
+
expect(emittedAction).toHaveLength(1);
|
|
42
|
+
expect(emittedAction).toEqual([[item]]);
|
|
41
43
|
});
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
describe('when item has a `href`', () => {
|
|
47
|
+
const item = mockItems[0];
|
|
48
|
+
|
|
45
49
|
beforeEach(() => {
|
|
46
|
-
buildWrapper({ item
|
|
50
|
+
buildWrapper({ item });
|
|
47
51
|
});
|
|
48
52
|
|
|
49
53
|
const findLink = () => wrapper.find('a.gl-new-dropdown-item-content');
|
|
@@ -53,28 +57,30 @@ describe('GlDisclosureDropdownItem', () => {
|
|
|
53
57
|
});
|
|
54
58
|
|
|
55
59
|
it('should set correct attributes', () => {
|
|
56
|
-
expect(findLink().attributes('href')).toBe(
|
|
57
|
-
expect(findLink().attributes()).
|
|
60
|
+
expect(findLink().attributes('href')).toBe(item.href);
|
|
61
|
+
expect(findLink().attributes()).toEqual(expect.objectContaining(item.extraAttrs));
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
it('should apply the default classes to the item wrapper', () => {
|
|
61
65
|
expect(findItem().classes()).toEqual(['gl-new-dropdown-item']);
|
|
62
66
|
});
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
wrapperClass: TEST_CLASS,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
});
|
|
68
|
+
it('should emit `action` on `click`', () => {
|
|
69
|
+
findLink().trigger('click');
|
|
70
|
+
const emittedAction = wrapper.emitted('action');
|
|
71
|
+
expect(emittedAction).toHaveLength(1);
|
|
72
|
+
expect(emittedAction).toEqual([[item]]);
|
|
73
|
+
});
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})
|
|
75
|
+
it.each`
|
|
76
|
+
trigger | event
|
|
77
|
+
${() => findItem().trigger('keydown', { code: ENTER })} | ${'ENTER'}
|
|
78
|
+
${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
|
|
79
|
+
`(`$event on parent will execute 'action' event`, ({ trigger }) => {
|
|
80
|
+
trigger();
|
|
81
|
+
const emittedAction = wrapper.emitted('action');
|
|
82
|
+
expect(emittedAction).toHaveLength(1);
|
|
83
|
+
expect(emittedAction).toEqual([[item]]);
|
|
78
84
|
});
|
|
79
85
|
});
|
|
80
86
|
|
|
@@ -100,7 +106,7 @@ describe('GlDisclosureDropdownItem', () => {
|
|
|
100
106
|
expect(findButton().attributes()).toMatchObject(attrs);
|
|
101
107
|
});
|
|
102
108
|
|
|
103
|
-
it('should call `action` on `click`', () => {
|
|
109
|
+
it('should call `action` on `click` and emit `action` event', () => {
|
|
104
110
|
findButton().trigger('click');
|
|
105
111
|
expect(action).toHaveBeenCalledTimes(1);
|
|
106
112
|
|
|
@@ -110,47 +116,43 @@ describe('GlDisclosureDropdownItem', () => {
|
|
|
110
116
|
const actionArgs = action.mock.calls[0];
|
|
111
117
|
expect(actionArgs).toEqual([item]);
|
|
112
118
|
|
|
113
|
-
|
|
119
|
+
const emittedAction = wrapper.emitted('action');
|
|
120
|
+
expect(emittedAction).toHaveLength(1);
|
|
121
|
+
expect(emittedAction).toEqual([[item]]);
|
|
114
122
|
});
|
|
115
123
|
|
|
116
124
|
it.each`
|
|
117
125
|
trigger | event
|
|
118
|
-
${() => findItem().trigger('click')} | ${'click'}
|
|
119
126
|
${() => findItem().trigger('keydown', { code: ENTER })} | ${'ENTER'}
|
|
120
127
|
${() => findItem().trigger('keydown', { code: SPACE })} | ${'SPACE'}
|
|
121
|
-
`(`$event will execute action and emit 'action' event`, ({ trigger }) => {
|
|
128
|
+
`(`$event on parent will execute action and emit 'action' event`, ({ trigger }) => {
|
|
122
129
|
trigger();
|
|
123
|
-
expect(
|
|
130
|
+
expect(action).toHaveBeenCalledTimes(1);
|
|
131
|
+
expect(action.mock.calls[0]).toEqual([item]);
|
|
132
|
+
|
|
133
|
+
const emittedAction = wrapper.emitted('action');
|
|
134
|
+
expect(emittedAction).toHaveLength(1);
|
|
135
|
+
expect(emittedAction).toEqual([[item]]);
|
|
124
136
|
});
|
|
125
137
|
|
|
126
138
|
it('should apply the default classes to the item wrapper', () => {
|
|
127
139
|
expect(findItem().classes()).toEqual(['gl-new-dropdown-item']);
|
|
128
140
|
});
|
|
129
|
-
|
|
130
|
-
describe('when item has wrapperClass', () => {
|
|
131
|
-
const TEST_CLASS = 'just-a-test-class';
|
|
132
|
-
beforeEach(() => {
|
|
133
|
-
buildWrapper({
|
|
134
|
-
item: {
|
|
135
|
-
...mockItems[1],
|
|
136
|
-
wrapperClass: TEST_CLASS,
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('should add the extra class to the item wrapper', () => {
|
|
142
|
-
expect(findItem().classes()).toContain(TEST_CLASS);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
141
|
});
|
|
146
142
|
|
|
147
|
-
describe('when item
|
|
143
|
+
describe('when item has wrapperClass', () => {
|
|
144
|
+
const TEST_CLASS = 'just-a-test-class';
|
|
148
145
|
beforeEach(() => {
|
|
149
|
-
buildWrapper({
|
|
146
|
+
buildWrapper({
|
|
147
|
+
item: {
|
|
148
|
+
...mockItems[0],
|
|
149
|
+
wrapperClass: TEST_CLASS,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
150
152
|
});
|
|
151
153
|
|
|
152
|
-
it('should
|
|
153
|
-
expect(
|
|
154
|
+
it('should add the extra class to the item wrapper', () => {
|
|
155
|
+
expect(findItem().classes()).toContain(TEST_CLASS);
|
|
154
156
|
});
|
|
155
157
|
});
|
|
156
158
|
});
|
|
@@ -27,8 +27,6 @@ export default {
|
|
|
27
27
|
itemComponent() {
|
|
28
28
|
const { item } = this;
|
|
29
29
|
|
|
30
|
-
if (!item) return null;
|
|
31
|
-
|
|
32
30
|
if (this.isLink)
|
|
33
31
|
return {
|
|
34
32
|
is: 'a',
|
|
@@ -37,20 +35,34 @@ export default {
|
|
|
37
35
|
...item.extraAttrs,
|
|
38
36
|
},
|
|
39
37
|
wrapperClass: item.wrapperClass,
|
|
40
|
-
listeners: {
|
|
38
|
+
listeners: {
|
|
39
|
+
click: this.action,
|
|
40
|
+
},
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
return {
|
|
44
44
|
is: 'button',
|
|
45
45
|
attrs: {
|
|
46
|
-
...item
|
|
46
|
+
...item?.extraAttrs,
|
|
47
47
|
type: 'button',
|
|
48
48
|
},
|
|
49
49
|
listeners: {
|
|
50
|
-
click: () =>
|
|
50
|
+
click: () => {
|
|
51
|
+
item?.action?.call(undefined, item);
|
|
52
|
+
this.action();
|
|
53
|
+
},
|
|
51
54
|
},
|
|
52
|
-
wrapperClass: item
|
|
55
|
+
wrapperClass: item?.wrapperClass,
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
wrapperListeners() {
|
|
59
|
+
const listeners = {
|
|
60
|
+
keydown: this.onKeydown,
|
|
53
61
|
};
|
|
62
|
+
if (this.isCustomContent) {
|
|
63
|
+
listeners.click = this.action;
|
|
64
|
+
}
|
|
65
|
+
return listeners;
|
|
54
66
|
},
|
|
55
67
|
},
|
|
56
68
|
methods: {
|
|
@@ -59,13 +71,18 @@ export default {
|
|
|
59
71
|
|
|
60
72
|
if (code === ENTER || code === SPACE) {
|
|
61
73
|
stopEvent(event);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
|
|
75
|
+
if (this.isCustomContent) {
|
|
76
|
+
this.action();
|
|
77
|
+
} else {
|
|
78
|
+
/** Instead of simply navigating or calling the action, we want
|
|
79
|
+
* the `a/button` to be the target of the event as it might have additional attributes.
|
|
80
|
+
* E.g. `a` might have `target` attribute.
|
|
81
|
+
*/
|
|
82
|
+
this.$refs.item?.dispatchEvent(
|
|
83
|
+
new MouseEvent('click', { bubbles: true, cancelable: true })
|
|
84
|
+
);
|
|
85
|
+
}
|
|
69
86
|
}
|
|
70
87
|
},
|
|
71
88
|
action() {
|
|
@@ -78,18 +95,11 @@ export default {
|
|
|
78
95
|
<template>
|
|
79
96
|
<li
|
|
80
97
|
tabindex="0"
|
|
81
|
-
:class="[$options.ITEM_CLASS, itemComponent
|
|
98
|
+
:class="[$options.ITEM_CLASS, itemComponent.wrapperClass]"
|
|
82
99
|
data-testid="disclosure-dropdown-item"
|
|
83
|
-
|
|
84
|
-
@keydown="onKeydown"
|
|
100
|
+
v-on="wrapperListeners"
|
|
85
101
|
>
|
|
86
|
-
<
|
|
87
|
-
<div class="gl-new-dropdown-item-text-wrapper">
|
|
88
|
-
<slot></slot>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<template v-else-if="itemComponent && item">
|
|
102
|
+
<slot>
|
|
93
103
|
<component
|
|
94
104
|
:is="itemComponent.is"
|
|
95
105
|
v-bind="itemComponent.attrs"
|
|
@@ -99,9 +109,11 @@ export default {
|
|
|
99
109
|
v-on="itemComponent.listeners"
|
|
100
110
|
>
|
|
101
111
|
<span class="gl-new-dropdown-item-text-wrapper">
|
|
102
|
-
|
|
112
|
+
<slot name="list-item">
|
|
113
|
+
{{ item.text }}
|
|
114
|
+
</slot>
|
|
103
115
|
</span>
|
|
104
116
|
</component>
|
|
105
|
-
</
|
|
117
|
+
</slot>
|
|
106
118
|
</li>
|
|
107
119
|
</template>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
### ECharts Wrapper
|
|
2
2
|
|
|
3
|
-
The chart component is a Vue component wrapper around
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
by default.
|
|
3
|
+
The chart component is a Vue component wrapper around [Apache ECharts](https://echarts.apache.org/en/api.html#echarts).
|
|
4
|
+
The chart component accepts width and height props in order to allow the user to make it responsive,
|
|
5
|
+
but it is not responsive by default.
|
|
7
6
|
|
|
8
|
-
> Note:
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
> Note: When implementing a chart type that does not already have a GitLab UI component, you can use
|
|
8
|
+
> this component alonside the [ECharts options](https://echarts.apache.org/en/api.html#echarts) to
|
|
9
|
+
> build your chart. Each type of chart should still follow the general guidelines in the
|
|
10
|
+
> [pajamas documentation](https://design.gitlab.com/data-visualization/charts).
|
|
11
11
|
|
|
12
12
|
### EChart Lifecycle
|
|
13
13
|
|