@gitlab/ui 32.25.0 → 32.29.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 +28 -0
- package/dist/components/base/banner/banner.js +10 -1
- package/dist/components/base/breadcrumb/breadcrumb.js +10 -2
- package/dist/components/base/toggle/toggle.js +14 -10
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/package.json +2 -2
- package/scss_to_js/scss_variables.js +5 -4
- package/scss_to_js/scss_variables.json +40 -8
- package/src/components/base/banner/banner.stories.js +8 -0
- package/src/components/base/banner/banner.vue +9 -1
- package/src/components/base/breadcrumb/breadcrumb.scss +18 -2
- package/src/components/base/breadcrumb/breadcrumb.stories.js +1 -4
- package/src/components/base/breadcrumb/breadcrumb.vue +22 -11
- package/src/components/base/dropdown/dropdown.scss +2 -0
- package/src/components/base/form/form_select/form_select.scss +1 -0
- package/src/components/base/label/label.scss +4 -0
- package/src/components/base/pagination/pagination.scss +1 -1
- package/src/components/base/search_box_by_click/search_box_by_click.scss +1 -0
- package/src/components/base/segmented_control/segmented_control.scss +1 -0
- package/src/components/base/table/table.scss +1 -0
- package/src/components/base/toast/toast.scss +1 -0
- package/src/components/base/toggle/toggle.spec.js +14 -9
- package/src/components/base/toggle/toggle.stories.js +3 -0
- package/src/components/base/toggle/toggle.vue +38 -31
- package/src/components/base/tooltip/tooltip.scss +1 -0
- package/src/scss/mixins.scss +49 -1
- package/src/scss/mixins.spec.scss +103 -0
- package/src/scss/utilities.scss +168 -168
- package/src/scss/utility-mixins/border.scss +1 -1
- package/src/scss/utility-mixins/color.scss +1 -1
- package/src/scss/utility-mixins/display.scss +17 -17
- package/src/scss/utility-mixins/flex.scss +26 -26
- package/src/scss/utility-mixins/sizing.scss +5 -5
- package/src/scss/utility-mixins/spacing.scss +33 -33
- package/src/scss/utility-mixins/typography.scss +1 -1
- package/src/scss/variables.scss +13 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.29.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"sass-true": "^5.0.0",
|
|
143
143
|
"start-server-and-test": "^1.10.6",
|
|
144
144
|
"storybook-readme": "5.0.9",
|
|
145
|
-
"stylelint-config-prettier": "
|
|
145
|
+
"stylelint-config-prettier": "9.0.3",
|
|
146
146
|
"stylelint-prettier": "1.2.0",
|
|
147
147
|
"vue": "^2.6.11",
|
|
148
148
|
"vue-jest": "4.0.0-rc.0",
|
|
@@ -15,10 +15,11 @@ export const glSpacingScale12 = '5rem'
|
|
|
15
15
|
export const glSpacingScale13 = '6rem'
|
|
16
16
|
export const glSpacingScale15 = '7.5rem'
|
|
17
17
|
export const glSpacingScale20 = '10rem'
|
|
18
|
-
export const breakpointSm = '
|
|
19
|
-
export const breakpointMd = '
|
|
20
|
-
export const breakpointLg = '
|
|
21
|
-
export const breakpointXl = '
|
|
18
|
+
export const breakpointSm = '576px'
|
|
19
|
+
export const breakpointMd = '768px'
|
|
20
|
+
export const breakpointLg = '992px'
|
|
21
|
+
export const breakpointXl = '1200px'
|
|
22
|
+
export const breakpoints = '(xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)'
|
|
22
23
|
export const limitedLayoutWidth = '990px'
|
|
23
24
|
export const black = '#000'
|
|
24
25
|
export const blackNormal = '#333'
|
|
@@ -87,23 +87,55 @@
|
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
"name": "$breakpoint-sm",
|
|
90
|
-
"value": "
|
|
91
|
-
"compiledValue": "
|
|
90
|
+
"value": "576px",
|
|
91
|
+
"compiledValue": "576px"
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"name": "$breakpoint-md",
|
|
95
|
-
"value": "
|
|
96
|
-
"compiledValue": "
|
|
95
|
+
"value": "768px",
|
|
96
|
+
"compiledValue": "768px"
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"name": "$breakpoint-lg",
|
|
100
|
-
"value": "
|
|
101
|
-
"compiledValue": "
|
|
100
|
+
"value": "992px",
|
|
101
|
+
"compiledValue": "992px"
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
"name": "$breakpoint-xl",
|
|
105
|
-
"value": "
|
|
106
|
-
"compiledValue": "
|
|
105
|
+
"value": "1200px",
|
|
106
|
+
"compiledValue": "1200px"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "$breakpoints",
|
|
110
|
+
"value": "( xs: 0, sm: $breakpoint-sm, md: $breakpoint-md, lg: $breakpoint-lg, xl: $breakpoint-xl, )",
|
|
111
|
+
"mapValue": [
|
|
112
|
+
{
|
|
113
|
+
"name": "xs",
|
|
114
|
+
"value": "0",
|
|
115
|
+
"compiledValue": "0"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "sm",
|
|
119
|
+
"value": "$breakpoint-sm",
|
|
120
|
+
"compiledValue": "576px"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "md",
|
|
124
|
+
"value": "$breakpoint-md",
|
|
125
|
+
"compiledValue": "768px"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "lg",
|
|
129
|
+
"value": "$breakpoint-lg",
|
|
130
|
+
"compiledValue": "992px"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "xl",
|
|
134
|
+
"value": "$breakpoint-xl",
|
|
135
|
+
"compiledValue": "1200px"
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
"compiledValue": "(xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)"
|
|
107
139
|
},
|
|
108
140
|
{
|
|
109
141
|
"name": "$limited-layout-width",
|
|
@@ -11,6 +11,7 @@ const template = `
|
|
|
11
11
|
:button-link="buttonLink"
|
|
12
12
|
:svg-path="svgPath"
|
|
13
13
|
:variant="variant"
|
|
14
|
+
:embedded="embedded"
|
|
14
15
|
>
|
|
15
16
|
<p>GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either though the GitLab interface or by email. End users will only see the thread though email.</p>
|
|
16
17
|
</gl-banner>
|
|
@@ -22,12 +23,14 @@ const generateProps = ({
|
|
|
22
23
|
buttonLink = 'https://gitlab.com',
|
|
23
24
|
svgPath = serviceDeskCalloutSvg,
|
|
24
25
|
variant = GlBanner.props.variant.default,
|
|
26
|
+
embedded = false,
|
|
25
27
|
} = {}) => ({
|
|
26
28
|
title,
|
|
27
29
|
buttonText,
|
|
28
30
|
buttonLink,
|
|
29
31
|
svgPath,
|
|
30
32
|
variant,
|
|
33
|
+
embedded,
|
|
31
34
|
});
|
|
32
35
|
|
|
33
36
|
const Template = (args, { argTypes }) => ({
|
|
@@ -51,6 +54,11 @@ Introduction.args = generateProps({
|
|
|
51
54
|
variant: bannerVariants[1],
|
|
52
55
|
});
|
|
53
56
|
|
|
57
|
+
export const Embedded = Template.bind({});
|
|
58
|
+
Embedded.args = generateProps({
|
|
59
|
+
embedded: true,
|
|
60
|
+
});
|
|
61
|
+
|
|
54
62
|
export const WithActions = (args, { argTypes }) => ({
|
|
55
63
|
components: {
|
|
56
64
|
GlBanner,
|
|
@@ -51,6 +51,14 @@ export default {
|
|
|
51
51
|
return bannerVariants.includes(value);
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
|
+
/**
|
|
55
|
+
* Removes the border for banners embedded in content.
|
|
56
|
+
*/
|
|
57
|
+
embedded: {
|
|
58
|
+
type: Boolean,
|
|
59
|
+
required: false,
|
|
60
|
+
default: null,
|
|
61
|
+
},
|
|
54
62
|
},
|
|
55
63
|
computed: {
|
|
56
64
|
isIntroducing() {
|
|
@@ -83,7 +91,7 @@ export default {
|
|
|
83
91
|
<template>
|
|
84
92
|
<gl-card
|
|
85
93
|
class="gl-px-8 gl-py-6 gl-line-height-20"
|
|
86
|
-
:class="{ 'gl-banner-introduction': isIntroducing }"
|
|
94
|
+
:class="{ 'gl-banner-introduction': isIntroducing, 'gl-border-none!': embedded }"
|
|
87
95
|
body-class="gl-display-flex gl-p-0!"
|
|
88
96
|
>
|
|
89
97
|
<div v-if="svgPath" class="gl-banner-illustration">
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
$breadcrumb-max-width: $grid-size * 16;
|
|
3
3
|
|
|
4
4
|
.gl-breadcrumbs {
|
|
5
|
+
@include gl-display-flex;
|
|
5
6
|
@include gl-border-0;
|
|
6
7
|
@include gl-inset-border-b-1-gray-200;
|
|
7
8
|
@include gl-py-5;
|
|
@@ -20,10 +21,12 @@ $breadcrumb-max-width: $grid-size * 16;
|
|
|
20
21
|
|
|
21
22
|
.gl-breadcrumb-separator {
|
|
22
23
|
@include gl-display-inline-flex;
|
|
24
|
+
@include gl-absolute;
|
|
25
|
+
right: 0;
|
|
23
26
|
|
|
24
27
|
> svg {
|
|
25
28
|
@include gl-my-auto;
|
|
26
|
-
@include gl-mx-
|
|
29
|
+
@include gl-mx-2;
|
|
27
30
|
@include gl-w-3;
|
|
28
31
|
@include gl-text-gray-500;
|
|
29
32
|
@include gl-fill-current-color;
|
|
@@ -31,7 +34,7 @@ $breadcrumb-max-width: $grid-size * 16;
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
.gl-breadcrumb-avatar-tile {
|
|
34
|
-
@include gl-mr-
|
|
37
|
+
@include gl-mr-3;
|
|
35
38
|
@include gl-border-1;
|
|
36
39
|
@include gl-border-solid;
|
|
37
40
|
@include gl-border-gray-200;
|
|
@@ -42,8 +45,21 @@ $breadcrumb-max-width: $grid-size * 16;
|
|
|
42
45
|
.gl-breadcrumb-item {
|
|
43
46
|
@include gl-font-sm;
|
|
44
47
|
@include gl-line-height-normal;
|
|
48
|
+
@include gl-relative;
|
|
49
|
+
@include gl-pr-6;
|
|
50
|
+
|
|
51
|
+
+ .gl-breadcrumb-item {
|
|
52
|
+
@include gl-pl-0;
|
|
53
|
+
|
|
54
|
+
&::before {
|
|
55
|
+
content: '';
|
|
56
|
+
@include gl-display-none;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
45
59
|
|
|
46
60
|
> a {
|
|
61
|
+
@include gl-display-flex;
|
|
62
|
+
@include gl-align-items-center;
|
|
47
63
|
@include gl-text-gray-500;
|
|
48
64
|
@include media-breakpoint-down(xs) {
|
|
49
65
|
@include str-truncated($breadcrumb-max-width);
|
|
@@ -6,10 +6,7 @@ const template = `
|
|
|
6
6
|
:items="items"
|
|
7
7
|
>
|
|
8
8
|
<template #avatar>
|
|
9
|
-
<img class="gl-breadcrumb-avatar-tile" src="https://assets.gitlab-static.net/uploads/-/system/group/avatar/9970/logo-extra-whitespace.png?width=
|
|
10
|
-
</template>
|
|
11
|
-
<template #separator>
|
|
12
|
-
<gl-icon name="angle-right" />
|
|
9
|
+
<img class="gl-breadcrumb-avatar-tile" src="https://assets.gitlab-static.net/uploads/-/system/group/avatar/9970/logo-extra-whitespace.png?width=16" width="16" height="16" />
|
|
13
10
|
</template>
|
|
14
11
|
</gl-breadcrumb>
|
|
15
12
|
`;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { BBreadcrumb, BBreadcrumbItem } from 'bootstrap-vue';
|
|
3
|
+
import GlIcon from '../icon/icon.vue';
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
components: {
|
|
6
7
|
BBreadcrumb,
|
|
7
8
|
BBreadcrumbItem,
|
|
9
|
+
GlIcon,
|
|
8
10
|
},
|
|
9
11
|
inheritAttrs: false,
|
|
10
12
|
props: {
|
|
@@ -23,13 +25,18 @@ export default {
|
|
|
23
25
|
},
|
|
24
26
|
},
|
|
25
27
|
},
|
|
28
|
+
methods: {
|
|
29
|
+
isLastItem(items, index) {
|
|
30
|
+
return index === items.length - 1;
|
|
31
|
+
},
|
|
32
|
+
},
|
|
26
33
|
};
|
|
27
34
|
</script>
|
|
28
35
|
<template>
|
|
29
36
|
<div class="gl-breadcrumbs">
|
|
37
|
+
<!-- @slot The avatar to display. -->
|
|
38
|
+
<slot name="avatar"></slot>
|
|
30
39
|
<b-breadcrumb class="gl-breadcrumb-list" v-bind="$attrs" v-on="$listeners">
|
|
31
|
-
<!-- @slot The avatar to display. -->
|
|
32
|
-
<slot name="avatar"></slot>
|
|
33
40
|
<template v-for="(item, index) in items">
|
|
34
41
|
<b-breadcrumb-item
|
|
35
42
|
:key="index"
|
|
@@ -37,16 +44,20 @@ export default {
|
|
|
37
44
|
:text="item.text"
|
|
38
45
|
:href="item.href"
|
|
39
46
|
:to="item.to"
|
|
40
|
-
/>
|
|
41
|
-
<span
|
|
42
|
-
v-if="index != items.length - 1"
|
|
43
|
-
:key="`index ${item.text}`"
|
|
44
|
-
class="gl-breadcrumb-separator"
|
|
45
|
-
data-testid="separator"
|
|
46
47
|
>
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
48
|
+
<span>{{ item.text }}</span>
|
|
49
|
+
<span
|
|
50
|
+
v-if="!isLastItem(items, index)"
|
|
51
|
+
:key="`${index} ${item.text}`"
|
|
52
|
+
class="gl-breadcrumb-separator"
|
|
53
|
+
data-testid="separator"
|
|
54
|
+
>
|
|
55
|
+
<!-- @slot The separator to display. -->
|
|
56
|
+
<slot name="separator">
|
|
57
|
+
<gl-icon name="chevron-right" />
|
|
58
|
+
</slot>
|
|
59
|
+
</span>
|
|
60
|
+
</b-breadcrumb-item>
|
|
50
61
|
</template>
|
|
51
62
|
</b-breadcrumb>
|
|
52
63
|
</div>
|
|
@@ -33,6 +33,7 @@ $label-close-button: '.gl-label-close.gl-button';
|
|
|
33
33
|
&:hover {
|
|
34
34
|
@include gl-reset-color;
|
|
35
35
|
@include gl-shadow-none;
|
|
36
|
+
|
|
36
37
|
.gl-label-text-scoped {
|
|
37
38
|
@include gl-text-decoration-underline;
|
|
38
39
|
}
|
|
@@ -62,6 +63,7 @@ $label-close-button: '.gl-label-close.gl-button';
|
|
|
62
63
|
@include gl-opacity-5;
|
|
63
64
|
@include gl-reset-bg;
|
|
64
65
|
@include gl-shadow-none;
|
|
66
|
+
|
|
65
67
|
.gl-icon {
|
|
66
68
|
@include gl-fill-current-color;
|
|
67
69
|
}
|
|
@@ -92,6 +94,7 @@ $label-close-button: '.gl-label-close.gl-button';
|
|
|
92
94
|
&:focus,
|
|
93
95
|
&:hover {
|
|
94
96
|
@include gl-bg-black;
|
|
97
|
+
|
|
95
98
|
.gl-icon {
|
|
96
99
|
color: var(--label-background-color);
|
|
97
100
|
}
|
|
@@ -113,6 +116,7 @@ $label-close-button: '.gl-label-close.gl-button';
|
|
|
113
116
|
&:focus,
|
|
114
117
|
&:hover {
|
|
115
118
|
@include gl-bg-white;
|
|
119
|
+
|
|
116
120
|
.gl-icon {
|
|
117
121
|
color: var(--label-background-color);
|
|
118
122
|
}
|
|
@@ -8,12 +8,14 @@ describe('toggle', () => {
|
|
|
8
8
|
let wrapper;
|
|
9
9
|
|
|
10
10
|
const label = 'toggle label';
|
|
11
|
+
const labelId = 'toggle-label-id';
|
|
11
12
|
const helpText = 'help text';
|
|
12
13
|
|
|
13
14
|
const createWrapper = (props = {}) => {
|
|
14
15
|
wrapper = shallowMount(Toggle, {
|
|
15
16
|
propsData: {
|
|
16
17
|
label,
|
|
18
|
+
labelId,
|
|
17
19
|
...props,
|
|
18
20
|
},
|
|
19
21
|
});
|
|
@@ -24,7 +26,6 @@ describe('toggle', () => {
|
|
|
24
26
|
|
|
25
27
|
afterEach(() => {
|
|
26
28
|
wrapper.destroy();
|
|
27
|
-
wrapper = null;
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
it('has role=switch', () => {
|
|
@@ -112,21 +113,25 @@ describe('toggle', () => {
|
|
|
112
113
|
|
|
113
114
|
describe('label position', () => {
|
|
114
115
|
describe.each`
|
|
115
|
-
state | labelPosition |
|
|
116
|
-
${'top'} | ${toggleLabelPosition.top} | ${
|
|
117
|
-
${'left'} | ${toggleLabelPosition.left} | ${
|
|
118
|
-
${'hidden'} | ${toggleLabelPosition.hidden} | ${
|
|
119
|
-
`('when $state', ({ labelPosition,
|
|
116
|
+
state | labelPosition | hasGlSrOnlyClass
|
|
117
|
+
${'top'} | ${toggleLabelPosition.top} | ${false}
|
|
118
|
+
${'left'} | ${toggleLabelPosition.left} | ${false}
|
|
119
|
+
${'hidden'} | ${toggleLabelPosition.hidden} | ${true}
|
|
120
|
+
`('when $state', ({ labelPosition, hasGlSrOnlyClass }) => {
|
|
120
121
|
beforeEach(() => {
|
|
121
122
|
createWrapper({ labelPosition });
|
|
122
123
|
});
|
|
123
124
|
|
|
124
|
-
it(`${
|
|
125
|
-
|
|
125
|
+
it(`${hasGlSrOnlyClass ? 'adds' : 'does not add'} 'gl-sr-only' class to the label`, () => {
|
|
126
|
+
const cssClasses = wrapper.find('[data-testid="toggle-label"]').classes();
|
|
127
|
+
|
|
128
|
+
return hasGlSrOnlyClass
|
|
129
|
+
? expect(cssClasses).toContain('gl-sr-only')
|
|
130
|
+
: expect(cssClasses).not.toContain('gl-sr-only');
|
|
126
131
|
});
|
|
127
132
|
|
|
128
133
|
it('has accessible name for the button', () => {
|
|
129
|
-
expect(findButton().attributes('aria-
|
|
134
|
+
expect(findButton().attributes('aria-labelledby')).toBe(labelId);
|
|
130
135
|
});
|
|
131
136
|
});
|
|
132
137
|
});
|
|
@@ -9,6 +9,7 @@ const generateProps = ({
|
|
|
9
9
|
disabled = defaultValue('disabled'),
|
|
10
10
|
isLoading = defaultValue('isLoading'),
|
|
11
11
|
label = 'Dark mode',
|
|
12
|
+
labelId = 'dark-mode-toggle',
|
|
12
13
|
help = 'Toggle dark mode for the website',
|
|
13
14
|
labelPosition = defaultValue('labelPosition'),
|
|
14
15
|
} = {}) => ({
|
|
@@ -16,6 +17,7 @@ const generateProps = ({
|
|
|
16
17
|
disabled,
|
|
17
18
|
isLoading,
|
|
18
19
|
label,
|
|
20
|
+
labelId,
|
|
19
21
|
help,
|
|
20
22
|
labelPosition,
|
|
21
23
|
});
|
|
@@ -29,6 +31,7 @@ const Template = (args, { argTypes }) => ({
|
|
|
29
31
|
v-model="value"
|
|
30
32
|
:disabled="disabled"
|
|
31
33
|
:help="help"
|
|
34
|
+
:label-id="labelId"
|
|
32
35
|
:is-loading="isLoading"
|
|
33
36
|
:label="label"
|
|
34
37
|
:label-position="labelPosition"
|
|
@@ -61,7 +61,14 @@ export default {
|
|
|
61
61
|
default: undefined,
|
|
62
62
|
},
|
|
63
63
|
/**
|
|
64
|
-
* The label
|
|
64
|
+
* The id for the label. This id is used by the aria-labelledby attribute on the toggle button.
|
|
65
|
+
*/
|
|
66
|
+
labelId: {
|
|
67
|
+
type: String,
|
|
68
|
+
required: true,
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* The label's position relative to the toggle. If 'hidden', the toggle will add the .gl-sr-only class so the label is still accessible to screen readers.
|
|
65
72
|
*/
|
|
66
73
|
labelPosition: {
|
|
67
74
|
type: String,
|
|
@@ -77,9 +84,6 @@ export default {
|
|
|
77
84
|
icon() {
|
|
78
85
|
return this.value ? 'mobile-issue-close' : 'close';
|
|
79
86
|
},
|
|
80
|
-
shouldShowLabel() {
|
|
81
|
-
return this.label && this.labelPosition !== 'hidden';
|
|
82
|
-
},
|
|
83
87
|
helpId() {
|
|
84
88
|
return this.help ? `toggle-help-${this.uuid}` : undefined;
|
|
85
89
|
},
|
|
@@ -110,38 +114,41 @@ export default {
|
|
|
110
114
|
</script>
|
|
111
115
|
|
|
112
116
|
<template>
|
|
113
|
-
<
|
|
117
|
+
<div
|
|
118
|
+
class="gl-toggle-wrapper gl-display-flex gl-flex-direction-column gl-mb-0 gl-w-max-content"
|
|
119
|
+
:class="{ 'gl-toggle-label-inline': labelPosition === 'left', 'is-disabled': disabled }"
|
|
120
|
+
>
|
|
114
121
|
<span
|
|
115
|
-
|
|
116
|
-
:class="{ 'gl-
|
|
122
|
+
:id="labelId"
|
|
123
|
+
:class="{ 'gl-sr-only': labelPosition === 'hidden' }"
|
|
124
|
+
class="gl-toggle-label"
|
|
125
|
+
data-testid="toggle-label"
|
|
117
126
|
>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<slot name="label">{{ label }}</slot>
|
|
121
|
-
</span>
|
|
122
|
-
<input v-if="name" :name="name" :value="value" type="hidden" />
|
|
123
|
-
<button
|
|
124
|
-
role="switch"
|
|
125
|
-
:aria-checked="isChecked"
|
|
126
|
-
:aria-label="label"
|
|
127
|
-
:aria-describedby="helpId"
|
|
128
|
-
:class="{
|
|
129
|
-
'gl-toggle': true,
|
|
130
|
-
'is-checked': value,
|
|
131
|
-
'is-disabled': disabled,
|
|
132
|
-
}"
|
|
133
|
-
type="button"
|
|
134
|
-
@click.prevent="toggleFeature"
|
|
135
|
-
>
|
|
136
|
-
<gl-loading-icon v-if="isLoading" color="light" class="toggle-loading" />
|
|
137
|
-
<span v-else :class="{ 'toggle-icon': true, disabled: disabled }">
|
|
138
|
-
<gl-icon :name="icon" :size="16" />
|
|
139
|
-
</span>
|
|
140
|
-
</button>
|
|
127
|
+
<!-- @slot The toggle's label. -->
|
|
128
|
+
<slot name="label">{{ label }}</slot>
|
|
141
129
|
</span>
|
|
130
|
+
<input v-if="name" :name="name" :value="value" type="hidden" />
|
|
131
|
+
<button
|
|
132
|
+
role="switch"
|
|
133
|
+
:aria-checked="isChecked"
|
|
134
|
+
:aria-labelledby="labelId"
|
|
135
|
+
:aria-describedby="helpId"
|
|
136
|
+
:class="{
|
|
137
|
+
'gl-toggle': true,
|
|
138
|
+
'is-checked': value,
|
|
139
|
+
'is-disabled': disabled,
|
|
140
|
+
}"
|
|
141
|
+
type="button"
|
|
142
|
+
@click.prevent="toggleFeature"
|
|
143
|
+
>
|
|
144
|
+
<gl-loading-icon v-if="isLoading" color="light" class="toggle-loading" />
|
|
145
|
+
<span v-else :class="{ 'toggle-icon': true, disabled: disabled }">
|
|
146
|
+
<gl-icon :name="icon" :size="16" />
|
|
147
|
+
</span>
|
|
148
|
+
</button>
|
|
142
149
|
<span v-if="help" :id="helpId" class="gl-help-label" data-testid="toggle-help">
|
|
143
150
|
<!-- @slot A help text to be shown below the toggle. -->
|
|
144
151
|
<slot name="help">{{ help }}</slot>
|
|
145
152
|
</span>
|
|
146
|
-
</
|
|
153
|
+
</div>
|
|
147
154
|
</template>
|
package/src/scss/mixins.scss
CHANGED
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
$breakpoint-min: $breakpoint-md,
|
|
34
34
|
$breakpoint-max: $breakpoint-xl
|
|
35
35
|
) {
|
|
36
|
-
$breakpoint-range: ($breakpoint-max - $breakpoint-min) / 1rem;
|
|
37
36
|
$property-range: ($property-max - $property-min) / 1rem;
|
|
37
|
+
$breakpoint-range: px-to-rem($breakpoint-max - $breakpoint-min) / 1rem;
|
|
38
38
|
|
|
39
39
|
@media (min-width: $breakpoint-min) {
|
|
40
40
|
#{$property}: calc(
|
|
@@ -68,3 +68,51 @@
|
|
|
68
68
|
@mixin gl-bg-gradient-blur($direction, $color) {
|
|
69
69
|
background-image: linear-gradient(to $direction, $transparent-rgba, $color 33%);
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Helper function for @media of at least the minimum
|
|
74
|
+
* breakpoint width.
|
|
75
|
+
*
|
|
76
|
+
* @param $name Breakpoint name, such as `sm` or `md`.
|
|
77
|
+
*/
|
|
78
|
+
@mixin gl-media-breakpoint-up($name) {
|
|
79
|
+
$min: map-get($breakpoints, $name);
|
|
80
|
+
@if $min == null {
|
|
81
|
+
@error;
|
|
82
|
+
}
|
|
83
|
+
@if $min != 0 {
|
|
84
|
+
@media (min-width: $min) {
|
|
85
|
+
@content;
|
|
86
|
+
}
|
|
87
|
+
} @else {
|
|
88
|
+
@content;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Helper function for @media of at most the maximum
|
|
94
|
+
* breakpoint width.
|
|
95
|
+
*
|
|
96
|
+
* Note: Before using, consider using a mobile-first
|
|
97
|
+
* approach, and define @media for larger breakpoints
|
|
98
|
+
* using `gl-media-breakpoint-up` while using this rule as
|
|
99
|
+
* the starting point instead.
|
|
100
|
+
*
|
|
101
|
+
* @param $name Breakpoint, such as `sm` or `md`. `xs` is not valid
|
|
102
|
+
*/
|
|
103
|
+
@mixin gl-media-breakpoint-down($name) {
|
|
104
|
+
$max: map-get($breakpoints, $name);
|
|
105
|
+
@if ($max == null or $max == 0) {
|
|
106
|
+
@error;
|
|
107
|
+
}
|
|
108
|
+
// The maximum value is reduced by 0.02px to work around the limitations of
|
|
109
|
+
// `min-` and `max-` prefixes and with fractional viewport sizes.
|
|
110
|
+
// See: https://www.w3.org/TR/mediaqueries-4/#mq-min-max
|
|
111
|
+
// Use 0.02px rather than 0.01px to work around a current rounding bug in Safari.
|
|
112
|
+
// See https://bugs.webkit.org/show_bug.cgi?id=178261
|
|
113
|
+
$breakpoint-max-range-precision: 0.02px;
|
|
114
|
+
|
|
115
|
+
@media (max-width: $max - $breakpoint-max-range-precision) {
|
|
116
|
+
@content;
|
|
117
|
+
}
|
|
118
|
+
}
|