@gitlab/ui 43.11.0 → 43.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/components/base/new_dropdowns/listbox/listbox.js +43 -19
- package/dist/components/base/new_dropdowns/listbox/listbox_group.js +54 -0
- package/dist/components/base/new_dropdowns/listbox/listbox_item.js +19 -1
- package/dist/components/base/new_dropdowns/listbox/mock_data.js +61 -0
- package/dist/components/base/new_dropdowns/listbox/utils.js +34 -0
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/package.json +5 -5
- package/scss_to_js/scss_variables.js +1 -0
- package/scss_to_js/scss_variables.json +5 -0
- package/src/components/base/new_dropdowns/listbox/listbox.md +56 -13
- package/src/components/base/new_dropdowns/listbox/listbox.spec.js +60 -33
- package/src/components/base/new_dropdowns/listbox/listbox.stories.js +94 -92
- package/src/components/base/new_dropdowns/listbox/listbox.vue +71 -19
- package/src/components/base/new_dropdowns/listbox/listbox_group.spec.js +47 -0
- package/src/components/base/new_dropdowns/listbox/listbox_group.vue +24 -0
- package/src/components/base/new_dropdowns/listbox/listbox_item.spec.js +25 -0
- package/src/components/base/new_dropdowns/listbox/listbox_item.vue +19 -2
- package/src/components/base/new_dropdowns/listbox/mock_data.js +68 -0
- package/src/components/base/new_dropdowns/listbox/utils.js +21 -0
- package/src/components/base/new_dropdowns/listbox/utils.spec.js +56 -0
- package/src/components/base/toggle/toggle.md +0 -2
- package/src/scss/utilities.scss +20 -0
- package/src/scss/utility-mixins/flex.scss +6 -0
- package/src/scss/utility-mixins/sizing.scss +4 -0
- package/src/scss/variables.scss +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "43.
|
|
3
|
+
"version": "43.14.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
103
103
|
"babel-preset-vue": "^2.0.2",
|
|
104
104
|
"bootstrap": "4.5.3",
|
|
105
|
-
"cypress": "^10.
|
|
105
|
+
"cypress": "^10.7.0",
|
|
106
106
|
"emoji-regex": "^10.0.0",
|
|
107
107
|
"eslint": "8.22.0",
|
|
108
108
|
"eslint-import-resolver-jest": "3.0.2",
|
|
@@ -112,9 +112,9 @@
|
|
|
112
112
|
"glob": "^7.2.0",
|
|
113
113
|
"identity-obj-proxy": "^3.0.0",
|
|
114
114
|
"inquirer-select-directory": "^1.2.0",
|
|
115
|
-
"jest": "^29.0.
|
|
116
|
-
"jest-circus": "29.0.
|
|
117
|
-
"jest-environment-jsdom": "29.0.
|
|
115
|
+
"jest": "^29.0.2",
|
|
116
|
+
"jest-circus": "29.0.2",
|
|
117
|
+
"jest-environment-jsdom": "29.0.2",
|
|
118
118
|
"jest-serializer-vue": "^2.0.2",
|
|
119
119
|
"markdownlint-cli": "^0.29.0",
|
|
120
120
|
"mockdate": "^2.0.5",
|
|
@@ -26,6 +26,7 @@ export const breakpointLg = '992px'
|
|
|
26
26
|
export const breakpointXl = '1200px'
|
|
27
27
|
export const breakpoints = '(xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)'
|
|
28
28
|
export const limitedLayoutWidth = '990px'
|
|
29
|
+
export const containerXl = '1280px'
|
|
29
30
|
export const black = '#000'
|
|
30
31
|
export const blackNormal = '#333'
|
|
31
32
|
export const white = '#fff'
|
|
@@ -51,21 +51,64 @@ On selection the listbox will emit the `select` event with the selected values.
|
|
|
51
51
|
|
|
52
52
|
### Setting listbox options
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
Use the `items` prop to provide options to the listbox. Each item can be
|
|
55
|
+
either an option or a group. Below are the expected shapes of these
|
|
56
|
+
objects:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
type Option = {
|
|
60
|
+
value: string
|
|
61
|
+
text?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
type Group = {
|
|
65
|
+
text: string
|
|
66
|
+
options: Array<Option>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type ItemsProp = Array<Option> | Array<Group>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Options
|
|
73
|
+
|
|
74
|
+
The `value` property of options must be unique across all options
|
|
75
|
+
provided to the listbox, as it's used as a primary key.
|
|
76
|
+
|
|
77
|
+
The optional `text` property is used to render the default listbox item
|
|
78
|
+
template. If you want to render a custom template for items, use the
|
|
79
|
+
`list-item` scoped slot:
|
|
58
80
|
|
|
59
81
|
```html
|
|
60
82
|
<gl-listbox :items="items">
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
<template #list-item="{ item }">
|
|
84
|
+
<span class="gl-display-flex gl-align-items-center">
|
|
85
|
+
<gl-avatar :size="32" class-="gl-mr-3"/>
|
|
86
|
+
<span class="gl-display-flex gl-flex-direction-column">
|
|
87
|
+
<span class="gl-font-weight-bold gl-white-space-nowrap">{{ item.text }}</span>
|
|
88
|
+
<span class="gl-text-gray-400"> {{ item.secondaryText }}</span>
|
|
89
|
+
</span>
|
|
90
|
+
</span>
|
|
91
|
+
</template>
|
|
92
|
+
</gl-listbox>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Groups
|
|
96
|
+
|
|
97
|
+
Options can be contained within groups. A group has a required `text`
|
|
98
|
+
property, which must be unique across all groups within the listbox, as
|
|
99
|
+
it's used as a primary key. It also has a required property `items` that
|
|
100
|
+
must be an array of options.
|
|
101
|
+
|
|
102
|
+
Groups can be at most one level deep: a group can only contain options.
|
|
103
|
+
Options and groups _cannot_ be siblings. Either all items are options,
|
|
104
|
+
or they are all groups.
|
|
105
|
+
|
|
106
|
+
To render custom group labels, use the `group-label` scoped slot:
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<gl-listbox :items="groups">
|
|
110
|
+
<template #group-label="{ group }">
|
|
111
|
+
{{ group.text }} <gl-badge size="sm">{{ group.options.length }}</gl-badge>
|
|
112
|
+
</template>
|
|
70
113
|
</gl-listbox>
|
|
71
114
|
```
|
|
@@ -11,21 +11,8 @@ import {
|
|
|
11
11
|
} from '../constants';
|
|
12
12
|
import GlListbox, { ITEM_SELECTOR } from './listbox.vue';
|
|
13
13
|
import GlListboxItem from './listbox_item.vue';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
value: 'eng',
|
|
18
|
-
text: 'Engineering',
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
value: 'sales',
|
|
22
|
-
text: 'Sales',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
value: 'marketing',
|
|
26
|
-
text: 'Marketing',
|
|
27
|
-
},
|
|
28
|
-
];
|
|
14
|
+
import GlListboxGroup from './listbox_group.vue';
|
|
15
|
+
import { mockOptions, mockGroups } from './mock_data';
|
|
29
16
|
|
|
30
17
|
describe('GlListbox', () => {
|
|
31
18
|
let wrapper;
|
|
@@ -40,19 +27,20 @@ describe('GlListbox', () => {
|
|
|
40
27
|
|
|
41
28
|
const findBaseDropdown = () => wrapper.findComponent(GlBaseDropdown);
|
|
42
29
|
const findListContainer = () => wrapper.find('[role="listbox"]');
|
|
43
|
-
const findListboxItems = () =>
|
|
30
|
+
const findListboxItems = (root = wrapper) => root.findAllComponents(GlListboxItem);
|
|
31
|
+
const findListboxGroups = () => wrapper.findAllComponents(GlListboxGroup);
|
|
44
32
|
const findListItem = (index) => findListboxItems().at(index).find(ITEM_SELECTOR);
|
|
45
33
|
|
|
46
34
|
describe('toggle text', () => {
|
|
47
35
|
describe.each`
|
|
48
|
-
toggleText | multiple | selected
|
|
49
|
-
${'Toggle caption'} | ${true} | ${[
|
|
50
|
-
${''} | ${true} | ${[
|
|
51
|
-
${''} | ${false} | ${
|
|
52
|
-
${''} | ${false} | ${''}
|
|
36
|
+
toggleText | multiple | selected | expectedToggleText
|
|
37
|
+
${'Toggle caption'} | ${true} | ${[mockOptions[0].value]} | ${'Toggle caption'}
|
|
38
|
+
${''} | ${true} | ${[mockOptions[0]].value} | ${''}
|
|
39
|
+
${''} | ${false} | ${mockOptions[0].value} | ${mockOptions[0].text}
|
|
40
|
+
${''} | ${false} | ${''} | ${''}
|
|
53
41
|
`('when listbox', ({ toggleText, multiple, selected, expectedToggleText }) => {
|
|
54
42
|
beforeEach(() => {
|
|
55
|
-
buildWrapper({ items:
|
|
43
|
+
buildWrapper({ items: mockOptions, toggleText, multiple, selected });
|
|
56
44
|
});
|
|
57
45
|
|
|
58
46
|
it(`is ${multiple ? 'multi' : 'single'}-select, toggleText is ${
|
|
@@ -77,8 +65,8 @@ describe('GlListbox', () => {
|
|
|
77
65
|
beforeEach(() => {
|
|
78
66
|
buildWrapper({
|
|
79
67
|
multiple: true,
|
|
80
|
-
selected: [
|
|
81
|
-
items:
|
|
68
|
+
selected: [mockOptions[1].value, mockOptions[2].value],
|
|
69
|
+
items: mockOptions,
|
|
82
70
|
});
|
|
83
71
|
});
|
|
84
72
|
|
|
@@ -90,28 +78,29 @@ describe('GlListbox', () => {
|
|
|
90
78
|
it('should deselect previously selected', async () => {
|
|
91
79
|
findListboxItems().at(1).vm.$emit('select', false);
|
|
92
80
|
await nextTick();
|
|
93
|
-
expect(wrapper.emitted('select')[0][0]).toEqual([
|
|
81
|
+
expect(wrapper.emitted('select')[0][0]).toEqual([mockOptions[2].value]);
|
|
94
82
|
});
|
|
95
83
|
|
|
96
84
|
it('should add to selection', async () => {
|
|
97
85
|
findListboxItems().at(0).vm.$emit('select', true);
|
|
98
86
|
await nextTick();
|
|
99
87
|
expect(wrapper.emitted('select')[0][0]).toEqual(
|
|
100
|
-
|
|
88
|
+
// The first three items should now be selected.
|
|
89
|
+
expect.arrayContaining(mockOptions.slice(0, 3).map(({ value }) => value))
|
|
101
90
|
);
|
|
102
91
|
});
|
|
103
92
|
});
|
|
104
93
|
|
|
105
94
|
describe('single-select', () => {
|
|
106
95
|
beforeEach(() => {
|
|
107
|
-
buildWrapper({ selected:
|
|
96
|
+
buildWrapper({ selected: mockOptions[1].value, items: mockOptions });
|
|
108
97
|
});
|
|
109
98
|
|
|
110
99
|
it('should throw an error when array of selections is provided', () => {
|
|
111
100
|
expect(() => {
|
|
112
101
|
buildWrapper({
|
|
113
|
-
selected: [
|
|
114
|
-
items:
|
|
102
|
+
selected: [mockOptions[1].value, mockOptions[2].value],
|
|
103
|
+
items: mockOptions,
|
|
115
104
|
});
|
|
116
105
|
}).toThrowError('To allow multi-selection, please, set "multiple" property to "true"');
|
|
117
106
|
expect(wrapper).toHaveLoggedVueErrors();
|
|
@@ -124,7 +113,25 @@ describe('GlListbox', () => {
|
|
|
124
113
|
it('should deselect previously selected and select a new item', async () => {
|
|
125
114
|
findListboxItems().at(2).vm.$emit('select', true);
|
|
126
115
|
await nextTick();
|
|
127
|
-
expect(wrapper.emitted('select')[0][0]).toEqual(
|
|
116
|
+
expect(wrapper.emitted('select')[0][0]).toEqual(mockOptions[2].value);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('with groups', () => {
|
|
121
|
+
const selected = mockGroups[1].options[1].value;
|
|
122
|
+
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
buildWrapper({ selected, items: mockGroups });
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should render item as selected when `selected` provided ', () => {
|
|
128
|
+
expect(findListboxItems().at(3).props('isSelected')).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should deselect previously selected and select a new item', async () => {
|
|
132
|
+
findListboxItems().at(0).vm.$emit('select', true);
|
|
133
|
+
await nextTick();
|
|
134
|
+
expect(wrapper.emitted('select')[0][0]).toEqual(mockGroups[0].options[0].value);
|
|
128
135
|
});
|
|
129
136
|
});
|
|
130
137
|
});
|
|
@@ -133,8 +140,8 @@ describe('GlListbox', () => {
|
|
|
133
140
|
beforeEach(async () => {
|
|
134
141
|
buildWrapper({
|
|
135
142
|
multiple: true,
|
|
136
|
-
items:
|
|
137
|
-
selected: [
|
|
143
|
+
items: mockOptions,
|
|
144
|
+
selected: [mockOptions[2].value, mockOptions[1].value],
|
|
138
145
|
});
|
|
139
146
|
findBaseDropdown().vm.$emit(GL_DROPDOWN_SHOWN);
|
|
140
147
|
await nextTick();
|
|
@@ -166,7 +173,8 @@ describe('GlListbox', () => {
|
|
|
166
173
|
let thirdItem;
|
|
167
174
|
|
|
168
175
|
beforeEach(() => {
|
|
169
|
-
|
|
176
|
+
// These tests are more easily written with a small list of items.
|
|
177
|
+
buildWrapper({ items: mockOptions.slice(0, 3) });
|
|
170
178
|
findBaseDropdown().vm.$emit(GL_DROPDOWN_SHOWN);
|
|
171
179
|
firstItem = findListItem(0);
|
|
172
180
|
secondItem = findListItem(1);
|
|
@@ -233,4 +241,23 @@ describe('GlListbox', () => {
|
|
|
233
241
|
expect(wrapper.text()).toContain(footerContent);
|
|
234
242
|
});
|
|
235
243
|
});
|
|
244
|
+
|
|
245
|
+
describe('with groups', () => {
|
|
246
|
+
it('renders groups of items', () => {
|
|
247
|
+
buildWrapper({ items: mockGroups });
|
|
248
|
+
|
|
249
|
+
const groups = findListboxGroups();
|
|
250
|
+
|
|
251
|
+
expect(groups.length).toBe(mockGroups.length);
|
|
252
|
+
|
|
253
|
+
const expectedNameProps = mockGroups.map((group) => group.text);
|
|
254
|
+
const actualNameProps = groups.wrappers.map((group) => group.props('name'));
|
|
255
|
+
|
|
256
|
+
expect(actualNameProps).toEqual(expectedNameProps);
|
|
257
|
+
|
|
258
|
+
mockGroups.forEach((group, i) => {
|
|
259
|
+
expect(findListboxItems(groups.at(i))).toHaveLength(group.options.length);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
236
263
|
});
|
|
@@ -9,65 +9,17 @@ import {
|
|
|
9
9
|
GlSearchBoxByType,
|
|
10
10
|
GlButtonGroup,
|
|
11
11
|
GlButton,
|
|
12
|
+
GlBadge,
|
|
12
13
|
GlAvatar,
|
|
13
14
|
} from '../../../../index';
|
|
14
15
|
import { makeContainer } from '../../../../utils/story_decorators/container';
|
|
15
16
|
import readme from './listbox.md';
|
|
17
|
+
import { mockOptions, mockGroups } from './mock_data';
|
|
16
18
|
|
|
17
19
|
const defaultValue = (prop) => GlListbox.props[prop].default;
|
|
18
20
|
|
|
19
|
-
const defaultItems = [
|
|
20
|
-
{
|
|
21
|
-
value: 'prod',
|
|
22
|
-
text: 'Product',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
value: 'ppl',
|
|
26
|
-
text: 'People',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
value: 'fin',
|
|
30
|
-
text: 'Finance',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
value: 'leg',
|
|
34
|
-
text: 'Legal',
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
value: 'eng',
|
|
38
|
-
text: 'Engineering',
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
value: 'sales',
|
|
42
|
-
text: 'Sales',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
value: 'marketing',
|
|
46
|
-
text: 'Marketing',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
value: 'acc',
|
|
50
|
-
text: 'Accounting',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
value: 'hr',
|
|
54
|
-
text: 'Human Resource Management',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
value: 'rnd',
|
|
58
|
-
text: 'Research and Development',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
value: 'cust',
|
|
62
|
-
text: 'Customer Service',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
value: 'sup',
|
|
66
|
-
text: 'Support',
|
|
67
|
-
},
|
|
68
|
-
];
|
|
69
21
|
const generateProps = ({
|
|
70
|
-
items =
|
|
22
|
+
items = mockOptions,
|
|
71
23
|
category = defaultValue('category'),
|
|
72
24
|
variant = defaultValue('variant'),
|
|
73
25
|
size = defaultValue('size'),
|
|
@@ -79,6 +31,7 @@ const generateProps = ({
|
|
|
79
31
|
textSrOnly = defaultValue('textSrOnly'),
|
|
80
32
|
icon = '',
|
|
81
33
|
multiple = defaultValue('multiple'),
|
|
34
|
+
isCheckCentered = defaultValue('isCheckCentered'),
|
|
82
35
|
ariaLabelledby,
|
|
83
36
|
startOpened = true,
|
|
84
37
|
} = {}) => ({
|
|
@@ -94,6 +47,7 @@ const generateProps = ({
|
|
|
94
47
|
textSrOnly,
|
|
95
48
|
icon,
|
|
96
49
|
multiple,
|
|
50
|
+
isCheckCentered,
|
|
97
51
|
ariaLabelledby,
|
|
98
52
|
startOpened,
|
|
99
53
|
});
|
|
@@ -120,6 +74,7 @@ const template = (content, label = '') => `
|
|
|
120
74
|
:text-sr-only="textSrOnly"
|
|
121
75
|
:icon="icon"
|
|
122
76
|
:multiple="multiple"
|
|
77
|
+
:is-check-centered="isCheckCentered"
|
|
123
78
|
:aria-labelledby="ariaLabelledby"
|
|
124
79
|
>
|
|
125
80
|
${content}
|
|
@@ -134,7 +89,7 @@ export const Default = (args, { argTypes }) => ({
|
|
|
134
89
|
},
|
|
135
90
|
data() {
|
|
136
91
|
return {
|
|
137
|
-
selected:
|
|
92
|
+
selected: mockOptions[1].value,
|
|
138
93
|
};
|
|
139
94
|
},
|
|
140
95
|
mounted() {
|
|
@@ -167,23 +122,28 @@ export const HeaderAndFooter = (args, { argTypes }) => ({
|
|
|
167
122
|
},
|
|
168
123
|
methods: {
|
|
169
124
|
selectItem(index) {
|
|
170
|
-
this.selected.push(
|
|
125
|
+
this.selected.push(mockOptions[index].value);
|
|
171
126
|
},
|
|
172
127
|
},
|
|
173
|
-
template: template(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
128
|
+
template: template(`
|
|
129
|
+
<template #header>
|
|
130
|
+
<gl-search-box-by-type/>
|
|
131
|
+
</template>
|
|
132
|
+
<template #footer>
|
|
133
|
+
<div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-100 gl-display-flex gl-justify-content-center gl-p-3">
|
|
134
|
+
<gl-button-group :vertical="false">
|
|
135
|
+
<gl-button @click="selectItem(0)">1st</gl-button>
|
|
136
|
+
<gl-button @click="selectItem(1)">2nd</gl-button>
|
|
137
|
+
<gl-button @click="selectItem(2)">3rd</gl-button>
|
|
138
|
+
</gl-button-group>
|
|
139
|
+
</div>
|
|
140
|
+
</template>
|
|
141
|
+
`),
|
|
142
|
+
});
|
|
143
|
+
HeaderAndFooter.args = generateProps({
|
|
144
|
+
toggleText: 'Header and Footer',
|
|
145
|
+
multiple: true,
|
|
185
146
|
});
|
|
186
|
-
HeaderAndFooter.args = generateProps({ toggleText: 'Header and Footer', multiple: true });
|
|
187
147
|
HeaderAndFooter.decorators = [makeContainer({ height: '370px' })];
|
|
188
148
|
|
|
189
149
|
export const CustomListItem = (args, { argTypes }) => ({
|
|
@@ -211,32 +171,33 @@ export const CustomListItem = (args, { argTypes }) => ({
|
|
|
211
171
|
},
|
|
212
172
|
},
|
|
213
173
|
template: `
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
</span>
|
|
237
|
-
|
|
238
|
-
</
|
|
239
|
-
</
|
|
174
|
+
<gl-listbox
|
|
175
|
+
v-model="selected"
|
|
176
|
+
:items="items"
|
|
177
|
+
:category="category"
|
|
178
|
+
:variant="variant"
|
|
179
|
+
:size="size"
|
|
180
|
+
:disabled="disabled"
|
|
181
|
+
:loading="loading"
|
|
182
|
+
:no-caret="noCaret"
|
|
183
|
+
:right="right"
|
|
184
|
+
:toggle-text="headerText"
|
|
185
|
+
:text-sr-only="textSrOnly"
|
|
186
|
+
:icon="icon"
|
|
187
|
+
:multiple="multiple"
|
|
188
|
+
:is-check-centered="isCheckCentered"
|
|
189
|
+
:aria-labelledby="ariaLabelledby"
|
|
190
|
+
>
|
|
191
|
+
<template #list-item="{ item }">
|
|
192
|
+
<span class="gl-display-flex gl-align-items-center">
|
|
193
|
+
<gl-avatar :size="32" class-="gl-mr-3"/>
|
|
194
|
+
<span class="gl-display-flex gl-flex-direction-column">
|
|
195
|
+
<span class="gl-font-weight-bold gl-white-space-nowrap">{{ item.text }}</span>
|
|
196
|
+
<span class="gl-text-gray-400"> {{ item.secondaryText }}</span>
|
|
197
|
+
</span>
|
|
198
|
+
</span>
|
|
199
|
+
</template>
|
|
200
|
+
</gl-listbox>
|
|
240
201
|
`,
|
|
241
202
|
});
|
|
242
203
|
|
|
@@ -247,9 +208,50 @@ CustomListItem.args = generateProps({
|
|
|
247
208
|
{ value: 'markian', text: 'Mark Florian', secondaryText: '@markian', icon: 'bin' },
|
|
248
209
|
],
|
|
249
210
|
multiple: true,
|
|
211
|
+
isCheckCentered: true,
|
|
250
212
|
});
|
|
251
213
|
CustomListItem.decorators = [makeContainer({ height: '200px' })];
|
|
252
214
|
|
|
215
|
+
const makeGroupedExample = (changes) => {
|
|
216
|
+
const story = (args, { argTypes }) => ({
|
|
217
|
+
props: Object.keys(argTypes),
|
|
218
|
+
components: {
|
|
219
|
+
GlBadge,
|
|
220
|
+
GlListbox,
|
|
221
|
+
},
|
|
222
|
+
data() {
|
|
223
|
+
return {
|
|
224
|
+
selected: 'v1.0',
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
mounted() {
|
|
228
|
+
if (this.startOpened) {
|
|
229
|
+
openListbox(this);
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
template: template(''),
|
|
233
|
+
...changes,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
story.args = generateProps({ items: mockGroups });
|
|
237
|
+
story.decorators = [makeContainer({ height: '280px' })];
|
|
238
|
+
|
|
239
|
+
return story;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export const Groups = makeGroupedExample();
|
|
243
|
+
|
|
244
|
+
export const CustomGroupsAndItems = makeGroupedExample({
|
|
245
|
+
template: template(`
|
|
246
|
+
<template #group-label="{ group }">
|
|
247
|
+
{{ group.text }} <gl-badge size="sm">{{ group.options.length }}</gl-badge>
|
|
248
|
+
</template>
|
|
249
|
+
<template #list-item="{ item }">
|
|
250
|
+
{{ item.text }} <gl-badge v-if="item.value === 'main'" size="sm">default</gl-badge>
|
|
251
|
+
</template>
|
|
252
|
+
`),
|
|
253
|
+
});
|
|
254
|
+
|
|
253
255
|
export default {
|
|
254
256
|
title: 'base/new-dropdowns/listbox',
|
|
255
257
|
component: GlListbox,
|