@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
|
@@ -17,8 +17,11 @@ import {
|
|
|
17
17
|
} from '../../../../utils/constants';
|
|
18
18
|
import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
|
|
19
19
|
import GlListboxItem from './listbox_item.vue';
|
|
20
|
+
import GlListboxGroup from './listbox_group.vue';
|
|
21
|
+
import { isOption, itemsValidator, flattenedOptions } from './utils';
|
|
20
22
|
|
|
21
23
|
export const ITEM_SELECTOR = '[role="option"]';
|
|
24
|
+
const GROUP_TOP_BORDER_CLASSES = ['gl-border-t', 'gl-pt-3', 'gl-mt-3'];
|
|
22
25
|
|
|
23
26
|
export default {
|
|
24
27
|
events: {
|
|
@@ -28,6 +31,7 @@ export default {
|
|
|
28
31
|
components: {
|
|
29
32
|
GlBaseDropdown,
|
|
30
33
|
GlListboxItem,
|
|
34
|
+
GlListboxGroup,
|
|
31
35
|
},
|
|
32
36
|
model: {
|
|
33
37
|
prop: 'selected',
|
|
@@ -41,9 +45,7 @@ export default {
|
|
|
41
45
|
type: Array,
|
|
42
46
|
required: false,
|
|
43
47
|
default: () => [],
|
|
44
|
-
validator:
|
|
45
|
-
return items.every(({ value }) => typeof value === 'string');
|
|
46
|
-
},
|
|
48
|
+
validator: itemsValidator,
|
|
47
49
|
},
|
|
48
50
|
/**
|
|
49
51
|
* array of selected items values for multi-select and selected item value for single-select
|
|
@@ -152,6 +154,14 @@ export default {
|
|
|
152
154
|
required: false,
|
|
153
155
|
default: false,
|
|
154
156
|
},
|
|
157
|
+
/**
|
|
158
|
+
* Center selected item checkmark
|
|
159
|
+
*/
|
|
160
|
+
isCheckCentered: {
|
|
161
|
+
type: Boolean,
|
|
162
|
+
required: false,
|
|
163
|
+
default: false,
|
|
164
|
+
},
|
|
155
165
|
/**
|
|
156
166
|
* The `aria-labelledby` attribute value for the toggle button
|
|
157
167
|
*/
|
|
@@ -169,10 +179,17 @@ export default {
|
|
|
169
179
|
};
|
|
170
180
|
},
|
|
171
181
|
computed: {
|
|
182
|
+
listboxTag() {
|
|
183
|
+
if (this.items.length === 0 || isOption(this.items[0])) return 'ul';
|
|
184
|
+
return 'div';
|
|
185
|
+
},
|
|
186
|
+
flattenedOptions() {
|
|
187
|
+
return flattenedOptions(this.items);
|
|
188
|
+
},
|
|
172
189
|
listboxToggleText() {
|
|
173
190
|
if (!this.toggleText) {
|
|
174
191
|
if (!this.multiple && this.selectedValues.length) {
|
|
175
|
-
return this.
|
|
192
|
+
return this.flattenedOptions.find(({ value }) => value === this.selectedValues[0])?.text;
|
|
176
193
|
}
|
|
177
194
|
return '';
|
|
178
195
|
}
|
|
@@ -181,7 +198,7 @@ export default {
|
|
|
181
198
|
},
|
|
182
199
|
selectedIndices() {
|
|
183
200
|
return this.selectedValues
|
|
184
|
-
.map((selected) => this.
|
|
201
|
+
.map((selected) => this.flattenedOptions.findIndex(({ value }) => value === selected))
|
|
185
202
|
.sort();
|
|
186
203
|
},
|
|
187
204
|
},
|
|
@@ -201,6 +218,9 @@ export default {
|
|
|
201
218
|
},
|
|
202
219
|
},
|
|
203
220
|
methods: {
|
|
221
|
+
groupClasses(index) {
|
|
222
|
+
return index === 0 ? null : GROUP_TOP_BORDER_CLASSES;
|
|
223
|
+
},
|
|
204
224
|
onShow() {
|
|
205
225
|
this.$nextTick(() => {
|
|
206
226
|
this.focusItem(this.selectedIndices[0] ?? 0, this.getFocusableListItemElements());
|
|
@@ -273,6 +293,9 @@ export default {
|
|
|
273
293
|
isSelected(item) {
|
|
274
294
|
return this.selectedValues.some((value) => value === item.value);
|
|
275
295
|
},
|
|
296
|
+
isFocused(item) {
|
|
297
|
+
return this.nextFocusedItemIndex === this.flattenedOptions.indexOf(item);
|
|
298
|
+
},
|
|
276
299
|
onSingleSelect(value, isSelected) {
|
|
277
300
|
if (isSelected) {
|
|
278
301
|
/**
|
|
@@ -295,6 +318,7 @@ export default {
|
|
|
295
318
|
);
|
|
296
319
|
}
|
|
297
320
|
},
|
|
321
|
+
isOption,
|
|
298
322
|
},
|
|
299
323
|
};
|
|
300
324
|
</script>
|
|
@@ -322,7 +346,8 @@ export default {
|
|
|
322
346
|
<!-- @slot Content to display in dropdown header -->
|
|
323
347
|
<slot name="header"></slot>
|
|
324
348
|
|
|
325
|
-
<
|
|
349
|
+
<component
|
|
350
|
+
:is="listboxTag"
|
|
326
351
|
ref="list"
|
|
327
352
|
:aria-labelledby="toggleId"
|
|
328
353
|
role="listbox"
|
|
@@ -330,19 +355,46 @@ export default {
|
|
|
330
355
|
tabindex="-1"
|
|
331
356
|
@keydown="onKeydown"
|
|
332
357
|
>
|
|
333
|
-
<
|
|
334
|
-
v-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
358
|
+
<template v-for="(item, index) in items">
|
|
359
|
+
<template v-if="isOption(item)">
|
|
360
|
+
<gl-listbox-item
|
|
361
|
+
:key="item.value"
|
|
362
|
+
:is-selected="isSelected(item)"
|
|
363
|
+
:is-focused="isFocused(item)"
|
|
364
|
+
:is-check-centered="isCheckCentered"
|
|
365
|
+
@select="onSelect(item, $event)"
|
|
366
|
+
>
|
|
367
|
+
<!-- @slot Custom template of the listbox item -->
|
|
368
|
+
<slot name="list-item" :item="item">
|
|
369
|
+
{{ item.text }}
|
|
370
|
+
</slot>
|
|
371
|
+
</gl-listbox-item>
|
|
372
|
+
</template>
|
|
373
|
+
|
|
374
|
+
<template v-else>
|
|
375
|
+
<gl-listbox-group :key="item.text" :name="item.text" :class="groupClasses(index)">
|
|
376
|
+
<template v-if="$scopedSlots['group-label']" #group-label>
|
|
377
|
+
<!-- @slot Custom template for group names -->
|
|
378
|
+
<slot name="group-label" :group="item"></slot>
|
|
379
|
+
</template>
|
|
380
|
+
|
|
381
|
+
<gl-listbox-item
|
|
382
|
+
v-for="option in item.options"
|
|
383
|
+
:key="option.value"
|
|
384
|
+
:is-selected="isSelected(option)"
|
|
385
|
+
:is-focused="isFocused(option)"
|
|
386
|
+
:is-check-centered="isCheckCentered"
|
|
387
|
+
@select="onSelect(option, $event)"
|
|
388
|
+
>
|
|
389
|
+
<!-- @slot Custom template of the listbox item -->
|
|
390
|
+
<slot name="list-item" :item="option">
|
|
391
|
+
{{ option.text }}
|
|
392
|
+
</slot>
|
|
393
|
+
</gl-listbox-item>
|
|
394
|
+
</gl-listbox-group>
|
|
395
|
+
</template>
|
|
396
|
+
</template>
|
|
397
|
+
</component>
|
|
346
398
|
<!-- @slot Content to display in dropdown footer -->
|
|
347
399
|
<slot name="footer"></slot>
|
|
348
400
|
</gl-base-dropdown>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import GlListboxGroup from './listbox_group.vue';
|
|
3
|
+
|
|
4
|
+
describe('GlListboxGroup', () => {
|
|
5
|
+
let wrapper;
|
|
6
|
+
const name = 'Group name';
|
|
7
|
+
|
|
8
|
+
const buildWrapper = ({ propsData, slots } = {}) => {
|
|
9
|
+
wrapper = shallowMount(GlListboxGroup, {
|
|
10
|
+
propsData: {
|
|
11
|
+
name,
|
|
12
|
+
...propsData,
|
|
13
|
+
},
|
|
14
|
+
slots,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const findByTestId = (testid, root = wrapper) => root.find(`[data-testid="${testid}"]`);
|
|
19
|
+
const findLabelElement = () => {
|
|
20
|
+
const labelElementId = wrapper.attributes('aria-labelledby');
|
|
21
|
+
return wrapper.find(`#${labelElementId}`);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
it('renders a group', () => {
|
|
25
|
+
buildWrapper();
|
|
26
|
+
|
|
27
|
+
expect(wrapper.find('ul[role="group"]').element).toBe(wrapper.element);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders default slot content', () => {
|
|
31
|
+
buildWrapper({ slots: { default: '<li data-testid="default-slot-content"></li>' } });
|
|
32
|
+
|
|
33
|
+
expect(findByTestId('default-slot-content').exists()).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('labels the group', () => {
|
|
37
|
+
buildWrapper();
|
|
38
|
+
|
|
39
|
+
expect(findLabelElement().text()).toBe(name);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('allows arbitrary content for group label', () => {
|
|
43
|
+
buildWrapper({ slots: { 'group-label': '<i data-testid="custom-name"></i>' } });
|
|
44
|
+
|
|
45
|
+
expect(findByTestId('custom-name', findLabelElement()).exists()).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { uniqueId } from 'lodash';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
props: {
|
|
6
|
+
name: {
|
|
7
|
+
type: String,
|
|
8
|
+
required: true,
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
created() {
|
|
12
|
+
this.nameId = uniqueId('gl-listbox-group-');
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<ul role="group" :aria-labelledby="nameId" class="gl-mb-0 gl-pl-0 gl-list-style-none">
|
|
19
|
+
<li :id="nameId" role="presentation" class="gl-pl-5! gl-py-2! gl-font-base gl-font-weight-bold">
|
|
20
|
+
<slot name="group-label">{{ name }}</slot>
|
|
21
|
+
</li>
|
|
22
|
+
<slot></slot>
|
|
23
|
+
</ul>
|
|
24
|
+
</template>
|
|
@@ -80,6 +80,31 @@ describe('GlListboxItem', () => {
|
|
|
80
80
|
});
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
describe('checkbox', () => {
|
|
84
|
+
describe('is NOT centered', () => {
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
buildWrapper({ isSelected: true });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should not center check icon by default', () => {
|
|
90
|
+
expect(findCheckIcon().classes()).toEqual(
|
|
91
|
+
expect.arrayContaining(['gl-mt-3', 'gl-align-self-start'])
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('is centered', () => {
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
buildWrapper({ isSelected: true, isCheckCentered: true });
|
|
99
|
+
});
|
|
100
|
+
it('should center the check icon', () => {
|
|
101
|
+
expect(findCheckIcon().classes()).not.toEqual(
|
|
102
|
+
expect.arrayContaining(['gl-mt-3', 'gl-align-self-start'])
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
83
108
|
describe('tabindex', () => {
|
|
84
109
|
it('should set tabindex to `-1` when item is not focused', () => {
|
|
85
110
|
buildWrapper({ isFocused: false });
|
|
@@ -18,6 +18,20 @@ export default {
|
|
|
18
18
|
default: false,
|
|
19
19
|
required: false,
|
|
20
20
|
},
|
|
21
|
+
isCheckCentered: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
required: false,
|
|
24
|
+
default: false,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
computed: {
|
|
28
|
+
checkedClasses() {
|
|
29
|
+
if (this.isCheckCentered) {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return 'gl-mt-3 gl-align-self-start';
|
|
34
|
+
},
|
|
21
35
|
},
|
|
22
36
|
methods: {
|
|
23
37
|
toggleSelection() {
|
|
@@ -48,8 +62,11 @@ export default {
|
|
|
48
62
|
<gl-icon
|
|
49
63
|
name="mobile-issue-close"
|
|
50
64
|
data-testid="dropdown-item-checkbox"
|
|
51
|
-
class="
|
|
52
|
-
|
|
65
|
+
:class="[
|
|
66
|
+
'gl-new-dropdown-item-check-icon',
|
|
67
|
+
{ 'gl-visibility-hidden': !isSelected },
|
|
68
|
+
checkedClasses,
|
|
69
|
+
]"
|
|
53
70
|
/>
|
|
54
71
|
<span class="gl-new-dropdown-item-text-wrapper">
|
|
55
72
|
<slot></slot>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const mockOptions = [
|
|
2
|
+
{
|
|
3
|
+
value: 'prod',
|
|
4
|
+
text: 'Product',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
value: 'ppl',
|
|
8
|
+
text: 'People',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
value: 'fin',
|
|
12
|
+
text: 'Finance',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
value: 'leg',
|
|
16
|
+
text: 'Legal',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: 'eng',
|
|
20
|
+
text: 'Engineering',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: 'sales',
|
|
24
|
+
text: 'Sales',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: 'marketing',
|
|
28
|
+
text: 'Marketing',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: 'acc',
|
|
32
|
+
text: 'Accounting',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
value: 'hr',
|
|
36
|
+
text: 'Human Resource Management',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: 'rnd',
|
|
40
|
+
text: 'Research and Development',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: 'cust',
|
|
44
|
+
text: 'Customer Service',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: 'sup',
|
|
48
|
+
text: 'Support',
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export const mockGroups = [
|
|
53
|
+
{
|
|
54
|
+
text: 'Branches',
|
|
55
|
+
options: [
|
|
56
|
+
{ text: 'main', value: 'main' },
|
|
57
|
+
{ text: 'feature-123', value: 'feature-123' },
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
text: 'Tags',
|
|
62
|
+
options: [
|
|
63
|
+
{ text: 'v1.0', value: 'v1.0' },
|
|
64
|
+
{ text: 'v2.0', value: 'v2.0' },
|
|
65
|
+
{ text: 'v2.1', value: 'v2.1' },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isString } from 'lodash';
|
|
2
|
+
|
|
3
|
+
const isOption = (item) => Boolean(item) && isString(item.value);
|
|
4
|
+
|
|
5
|
+
const isGroup = ({ options } = {}) => Array.isArray(options) && options.every(isOption);
|
|
6
|
+
|
|
7
|
+
const hasNoDuplicates = (array) => array.length === new Set(array).size;
|
|
8
|
+
|
|
9
|
+
const flattenedOptions = (items) => items.flatMap((item) => (isOption(item) ? item : item.options));
|
|
10
|
+
|
|
11
|
+
const isAllOptionsOrAllGroups = (items) => items.every(isOption) || items.every(isGroup);
|
|
12
|
+
|
|
13
|
+
const hasUniqueValues = (items) =>
|
|
14
|
+
hasNoDuplicates(flattenedOptions(items).map(({ value }) => value));
|
|
15
|
+
|
|
16
|
+
const hasUniqueGroups = (items) => hasNoDuplicates(items.filter(isGroup).map(({ text }) => text));
|
|
17
|
+
|
|
18
|
+
const itemsValidator = (items) =>
|
|
19
|
+
isAllOptionsOrAllGroups(items) && hasUniqueValues(items) && hasUniqueGroups(items);
|
|
20
|
+
|
|
21
|
+
export { isOption, itemsValidator, flattenedOptions };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { isOption, flattenedOptions, itemsValidator } from './utils';
|
|
2
|
+
import { mockOptions, mockGroups } from './mock_data';
|
|
3
|
+
|
|
4
|
+
describe('isOption', () => {
|
|
5
|
+
it.each([null, undefined, {}, { value: null }, { text: 'group', options: [] }])(
|
|
6
|
+
'isOption(%p) === false',
|
|
7
|
+
(notAnOption) => {
|
|
8
|
+
expect(isOption(notAnOption)).toBe(false);
|
|
9
|
+
}
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
it.each([{ value: '' }, { value: 'foo', text: 'bar' }, { value: 'qux', foo: true }])(
|
|
13
|
+
'isOption(%p) === true',
|
|
14
|
+
(option) => {
|
|
15
|
+
expect(isOption(option)).toBe(true);
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('flattenedOptions', () => {
|
|
21
|
+
it('returns flattened items as-is', () => {
|
|
22
|
+
expect(flattenedOptions(mockOptions)).toEqual(mockOptions);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('returns flattened items given groups items', () => {
|
|
26
|
+
expect(flattenedOptions(mockGroups)).toEqual([
|
|
27
|
+
...mockGroups[0].options,
|
|
28
|
+
...mockGroups[1].options,
|
|
29
|
+
]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('returns flattened items given mixed items/groups', () => {
|
|
33
|
+
expect(flattenedOptions([...mockOptions, ...mockGroups])).toEqual([
|
|
34
|
+
...mockOptions,
|
|
35
|
+
...mockGroups[0].options,
|
|
36
|
+
...mockGroups[1].options,
|
|
37
|
+
]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('itemsValidator', () => {
|
|
42
|
+
it.each`
|
|
43
|
+
description | value | expected
|
|
44
|
+
${'valid flat items'} | ${mockOptions} | ${true}
|
|
45
|
+
${'valid grouped items'} | ${mockGroups} | ${true}
|
|
46
|
+
${'empty list'} | ${[]} | ${true}
|
|
47
|
+
${'invalid items'} | ${[{ foo: true }]} | ${false}
|
|
48
|
+
${'group with invalid items'} | ${[{ text: 'foo', options: [{ foo: true }] }]} | ${false}
|
|
49
|
+
${'non-unique items'} | ${[{ value: 'a' }, { value: 'a' }]} | ${false}
|
|
50
|
+
${'non-unique items across groups'} | ${[{ text: 'a', options: [{ value: 'b' }] }, { text: 'z', options: [{ value: 'b' }] }]} | ${false}
|
|
51
|
+
${'non-unique groups'} | ${[{ text: 'a', options: [] }, { text: 'a', options: [] }]} | ${false}
|
|
52
|
+
${'sibling groups and options'} | ${[...mockOptions, ...mockGroups]} | ${false}
|
|
53
|
+
`('returns $expected given $description', ({ value, expected }) => {
|
|
54
|
+
expect(itemsValidator(value)).toBe(expected);
|
|
55
|
+
});
|
|
56
|
+
});
|
package/src/scss/utilities.scss
CHANGED
|
@@ -3112,6 +3112,18 @@
|
|
|
3112
3112
|
}
|
|
3113
3113
|
}
|
|
3114
3114
|
|
|
3115
|
+
.gl-sm-align-items-center {
|
|
3116
|
+
@include gl-media-breakpoint-up(sm) {
|
|
3117
|
+
align-items: center;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
.gl-sm-align-items-center\! {
|
|
3122
|
+
@include gl-media-breakpoint-up(sm) {
|
|
3123
|
+
align-items: center !important;
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3115
3127
|
.gl-md-align-items-center {
|
|
3116
3128
|
@include gl-media-breakpoint-up(md) {
|
|
3117
3129
|
align-items: center;
|
|
@@ -4559,6 +4571,14 @@
|
|
|
4559
4571
|
max-width: $limited-layout-width !important;
|
|
4560
4572
|
}
|
|
4561
4573
|
|
|
4574
|
+
.gl-max-w-container-xl {
|
|
4575
|
+
max-width: $container-xl;
|
|
4576
|
+
}
|
|
4577
|
+
|
|
4578
|
+
.gl-max-w-container-xl\! {
|
|
4579
|
+
max-width: $container-xl !important;
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4562
4582
|
.gl-h-auto {
|
|
4563
4583
|
height: auto;
|
|
4564
4584
|
}
|
|
@@ -36,6 +36,12 @@
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
@mixin gl-sm-align-items-center {
|
|
40
|
+
@include gl-media-breakpoint-up(sm) {
|
|
41
|
+
@include gl-align-items-center;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
@mixin gl-md-align-items-center {
|
|
40
46
|
@include gl-media-breakpoint-up(md) {
|
|
41
47
|
@include gl-align-items-center;
|