@gitlab/ui 124.1.1 → 124.3.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/dist/components/base/breadcrumb/breadcrumb.js +33 -2
- package/dist/components/base/form/form_combobox/form_combobox.js +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/shared_components/clipboard_button/clipboard_button.js +100 -0
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tailwind.css.map +1 -1
- package/dist/tokens/tailwind/tokens.cjs +110 -547
- package/package.json +4 -4
- package/src/components/base/breadcrumb/breadcrumb.scss +6 -1
- package/src/components/base/breadcrumb/breadcrumb.vue +53 -9
- package/src/components/base/form/form_combobox/form_combobox.scss +120 -0
- package/src/components/base/form/form_combobox/form_combobox.vue +1 -1
- package/src/components/index.js +3 -0
- package/src/components/shared_components/clipboard_button/clipboard_button.vue +78 -0
- package/translations.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "124.
|
|
3
|
+
"version": "124.3.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"@jest/test-sequencer": "30.2.0",
|
|
106
106
|
"@rollup/plugin-commonjs": "^28.0.9",
|
|
107
107
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
108
|
-
"@rollup/plugin-replace": "^6.0.
|
|
108
|
+
"@rollup/plugin-replace": "^6.0.3",
|
|
109
109
|
"@storybook/addon-a11y": "^7.6.20",
|
|
110
110
|
"@storybook/addon-docs": "^7.6.20",
|
|
111
111
|
"@storybook/addon-essentials": "^7.6.20",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"cypress-real-events": "^1.15.0",
|
|
138
138
|
"dompurify": "^3.1.2",
|
|
139
139
|
"emoji-regex": "^10.6.0",
|
|
140
|
-
"esbuild": "^0.25.
|
|
140
|
+
"esbuild": "^0.25.12",
|
|
141
141
|
"gitlab-api-async-iterator": "^1.3.1",
|
|
142
142
|
"glob": "11.0.3",
|
|
143
143
|
"globby": "^14.1.0",
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
"rollup-plugin-string": "^3.0.0",
|
|
164
164
|
"rollup-plugin-svg": "^2.0.0",
|
|
165
165
|
"rollup-plugin-vue": "^5.1.9",
|
|
166
|
-
"sass": "^1.93.
|
|
166
|
+
"sass": "^1.93.3",
|
|
167
167
|
"sass-loader": "^10.5.2",
|
|
168
168
|
"sass-true": "^9",
|
|
169
169
|
"start-server-and-test": "^2.1.2",
|
|
@@ -20,7 +20,7 @@ $breadcrumb-max-width: $grid-size * 16;
|
|
|
20
20
|
@apply gl-leading-normal;
|
|
21
21
|
@apply gl-shrink-0;
|
|
22
22
|
|
|
23
|
-
&:not(:last-child)::after {
|
|
23
|
+
&:not(:last-child, :has(+ .gl-breadcrumb-clipboard-button))::after {
|
|
24
24
|
color: var(--gl-breadcrumb-separator-color);
|
|
25
25
|
@apply gl-px-3;
|
|
26
26
|
content: '/';
|
|
@@ -75,3 +75,8 @@ $breadcrumb-max-width: $grid-size * 16;
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
.gl-breadcrumb-clipboard-button {
|
|
80
|
+
@apply gl-leading-normal;
|
|
81
|
+
@apply gl-shrink-0;
|
|
82
|
+
}
|
|
@@ -6,6 +6,7 @@ import GlAvatar from '../avatar/avatar.vue';
|
|
|
6
6
|
import GlDisclosureDropdown from '../new_dropdowns/disclosure/disclosure_dropdown.vue';
|
|
7
7
|
import { GlTooltipDirective } from '../../../directives/tooltip/tooltip';
|
|
8
8
|
import { breadCrumbSizeOptions } from '../../../utils/constants';
|
|
9
|
+
import ClipboardButton from '../../shared_components/clipboard_button/clipboard_button.vue';
|
|
9
10
|
import GlBreadcrumbItem from './breadcrumb_item.vue';
|
|
10
11
|
|
|
11
12
|
export default {
|
|
@@ -14,6 +15,7 @@ export default {
|
|
|
14
15
|
GlBreadcrumbItem,
|
|
15
16
|
GlAvatar,
|
|
16
17
|
GlDisclosureDropdown,
|
|
18
|
+
ClipboardButton,
|
|
17
19
|
},
|
|
18
20
|
directives: {
|
|
19
21
|
GlTooltip: GlTooltipDirective,
|
|
@@ -64,6 +66,30 @@ export default {
|
|
|
64
66
|
default: breadCrumbSizeOptions.sm,
|
|
65
67
|
validator: (value) => Object.keys(breadCrumbSizeOptions).includes(value),
|
|
66
68
|
},
|
|
69
|
+
/**
|
|
70
|
+
* Copy to clipboard button for breadcrumbs path.
|
|
71
|
+
*/
|
|
72
|
+
showClipboardButton: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
required: false,
|
|
75
|
+
default: false,
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* Custom path for copy to clipboard button. By default, it resolves to all items text values with `/` separator.
|
|
79
|
+
*/
|
|
80
|
+
pathToCopy: {
|
|
81
|
+
type: String,
|
|
82
|
+
required: false,
|
|
83
|
+
default: null,
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* Custom tooltip text for clipboard button.
|
|
87
|
+
*/
|
|
88
|
+
clipboardTooltipText: {
|
|
89
|
+
type: String,
|
|
90
|
+
required: false,
|
|
91
|
+
default: null,
|
|
92
|
+
},
|
|
67
93
|
},
|
|
68
94
|
data() {
|
|
69
95
|
return {
|
|
@@ -94,6 +120,12 @@ export default {
|
|
|
94
120
|
avatarSize() {
|
|
95
121
|
return this.size === 'sm' ? 16 : 24;
|
|
96
122
|
},
|
|
123
|
+
clipboardButtonText() {
|
|
124
|
+
if (this.pathToCopy) return this.pathToCopy;
|
|
125
|
+
|
|
126
|
+
const items = Array.from(this.items, (item) => item.text);
|
|
127
|
+
return items.join('/');
|
|
128
|
+
},
|
|
97
129
|
},
|
|
98
130
|
watch: {
|
|
99
131
|
items: {
|
|
@@ -230,16 +262,28 @@ export default {
|
|
|
230
262
|
:size="size"
|
|
231
263
|
:aria-current="getAriaCurrentAttr(index)"
|
|
232
264
|
:class="[hideItemClass(item), itemClass]"
|
|
233
|
-
><
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
><template #default>
|
|
266
|
+
<gl-avatar
|
|
267
|
+
v-if="item.avatarPath"
|
|
268
|
+
:src="item.avatarPath"
|
|
269
|
+
:size="avatarSize"
|
|
270
|
+
aria-hidden="true"
|
|
271
|
+
class="gl-breadcrumb-avatar-tile gl-border gl-mr-2 !gl-rounded-default"
|
|
272
|
+
shape="rect"
|
|
273
|
+
data-testid="avatar"
|
|
274
|
+
/><span class="gl-align-middle">{{ item.text }}</span>
|
|
275
|
+
</template>
|
|
242
276
|
</gl-breadcrumb-item>
|
|
277
|
+
|
|
278
|
+
<li v-if="showClipboardButton" class="gl-breadcrumb-clipboard-button">
|
|
279
|
+
<clipboard-button
|
|
280
|
+
data-testid="copy-to-clipboard-button"
|
|
281
|
+
class="gl-ml-2"
|
|
282
|
+
:text="clipboardButtonText"
|
|
283
|
+
v-bind="clipboardTooltipText ? { title: clipboardTooltipText } : {}"
|
|
284
|
+
:size="dropdownSize"
|
|
285
|
+
/>
|
|
286
|
+
</li>
|
|
243
287
|
</ol>
|
|
244
288
|
</nav>
|
|
245
289
|
</template>
|
|
@@ -1,5 +1,125 @@
|
|
|
1
1
|
.gl-form-combobox {
|
|
2
2
|
.gl-form-combobox-inner {
|
|
3
3
|
max-height: $gl-max-dropdown-max-height;
|
|
4
|
+
position: relative;
|
|
5
|
+
@apply gl-grow;
|
|
6
|
+
@apply gl-overflow-y-auto;
|
|
7
|
+
@apply gl-pl-0;
|
|
8
|
+
@apply gl-mb-0;
|
|
9
|
+
@apply gl-py-2;
|
|
10
|
+
@apply gl-list-none;
|
|
11
|
+
border-radius: var(--gl-dropdown-border-radius);
|
|
12
|
+
|
|
13
|
+
&:focus-visible {
|
|
14
|
+
@apply gl-focus;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ul {
|
|
18
|
+
@apply gl-list-none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Update dropdown items to match new listbox styling exactly
|
|
22
|
+
.gl-dropdown-item {
|
|
23
|
+
@apply gl-cursor-pointer;
|
|
24
|
+
@apply gl-px-2;
|
|
25
|
+
@apply gl-my-1;
|
|
26
|
+
|
|
27
|
+
&:first-child {
|
|
28
|
+
@apply gl-mt-0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&:last-child {
|
|
32
|
+
@apply gl-mb-0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Target the actual Bootstrap dropdown item element
|
|
36
|
+
.dropdown-item {
|
|
37
|
+
transition: background-color $gl-transition-duration-fast $gl-easing-out-cubic,
|
|
38
|
+
box-shadow $gl-transition-duration-medium $gl-easing-out-cubic;
|
|
39
|
+
@apply gl-rounded-default;
|
|
40
|
+
@apply gl-border-0;
|
|
41
|
+
@apply gl-w-full;
|
|
42
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-default);
|
|
43
|
+
@apply gl-items-center;
|
|
44
|
+
@apply gl-flex;
|
|
45
|
+
@apply gl-text-base;
|
|
46
|
+
@apply gl-font-normal;
|
|
47
|
+
@apply gl-leading-normal;
|
|
48
|
+
@apply gl-px-3;
|
|
49
|
+
@apply gl-py-0;
|
|
50
|
+
position: relative;
|
|
51
|
+
@apply gl-no-underline;
|
|
52
|
+
color: var(--gl-dropdown-option-text-color-default);
|
|
53
|
+
@apply gl-text-left;
|
|
54
|
+
@apply gl-whitespace-normal;
|
|
55
|
+
@include gl-prefers-reduced-motion-transition;
|
|
56
|
+
|
|
57
|
+
.gl-dropdown-item-text-wrapper {
|
|
58
|
+
@apply gl-min-w-0;
|
|
59
|
+
@apply gl-grow;
|
|
60
|
+
@apply gl-py-3;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Hover state
|
|
64
|
+
&:not(.disable-hover):hover {
|
|
65
|
+
color: var(--gl-dropdown-option-text-color-hover);
|
|
66
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-hover);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Focus state (when item receives actual focus)
|
|
70
|
+
&:focus {
|
|
71
|
+
color: var(--gl-dropdown-option-text-color-focus);
|
|
72
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-focus);
|
|
73
|
+
@include gl-focus($inset: true);
|
|
74
|
+
z-index: 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Active state (when item is clicked)
|
|
78
|
+
&:active,
|
|
79
|
+
&:focus:active {
|
|
80
|
+
color: var(--gl-dropdown-option-text-color-active);
|
|
81
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-active);
|
|
82
|
+
@include gl-focus($inset: true);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Keyboard navigation highlight (Bootstrap active class when :active prop is true)
|
|
86
|
+
&.active {
|
|
87
|
+
color: var(--gl-dropdown-option-text-color-focus) !important;
|
|
88
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-focus) !important;
|
|
89
|
+
@include gl-focus($inset: true);
|
|
90
|
+
z-index: 1;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Also handle the is-focused class for compatibility
|
|
94
|
+
&.is-focused {
|
|
95
|
+
color: var(--gl-dropdown-option-text-color-focus) !important;
|
|
96
|
+
background-color: var(--gl-dropdown-option-background-color-unselected-focus) !important;
|
|
97
|
+
@include gl-focus($inset: true);
|
|
98
|
+
z-index: 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&:focus-visible {
|
|
102
|
+
outline: none;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Selected state (if needed for multi-select scenarios)
|
|
107
|
+
&[aria-selected="true"] .dropdown-item {
|
|
108
|
+
background-color: var(--gl-dropdown-option-background-color-selected-default);
|
|
109
|
+
|
|
110
|
+
&:hover {
|
|
111
|
+
background-color: var(--gl-dropdown-option-background-color-selected-hover);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&:focus {
|
|
115
|
+
background-color: var(--gl-dropdown-option-background-color-selected-focus);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&:active,
|
|
119
|
+
&:focus:active {
|
|
120
|
+
background-color: var(--gl-dropdown-option-background-color-selected-active);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
4
124
|
}
|
|
5
125
|
}
|
|
@@ -248,7 +248,7 @@ export default {
|
|
|
248
248
|
ref="suggestionsMenu"
|
|
249
249
|
data-testid="combobox-dropdown"
|
|
250
250
|
role="listbox"
|
|
251
|
-
class="
|
|
251
|
+
class="gl-form-combobox-inner -gl-mt-3 gl-mb-0 gl-flex gl-w-full gl-list-none gl-flex-col gl-bg-dropdown gl-pl-0 gl-drop-shadow-md"
|
|
252
252
|
@keydown.down="onArrowDown"
|
|
253
253
|
@keydown.up="onArrowUp"
|
|
254
254
|
@keydown.left="onArrowLeft"
|
package/src/components/index.js
CHANGED
|
@@ -102,6 +102,9 @@ export { default as GlDashboardPanel } from './dashboards/dashboard_panel/dashbo
|
|
|
102
102
|
// Experimental
|
|
103
103
|
export { default as GlExperimentBadge } from './experimental/experiment_badge/experiment_badge.vue';
|
|
104
104
|
|
|
105
|
+
// Shared components
|
|
106
|
+
export { default as GlClipboardButton } from './shared_components/clipboard_button/clipboard_button.vue';
|
|
107
|
+
|
|
105
108
|
// Utilities
|
|
106
109
|
export { default as GlAnimatedNumber } from './utilities/animated_number/animated_number.vue';
|
|
107
110
|
export { default as GlFriendlyWrap } from './utilities/friendly_wrap/friendly_wrap.vue';
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { GlTooltipDirective } from '../../../directives/tooltip/tooltip';
|
|
3
|
+
import GlButton from '../../base/button/button.vue';
|
|
4
|
+
import { translate } from '../../../utils/i18n';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
name: 'ClipboardButton',
|
|
8
|
+
components: {
|
|
9
|
+
GlButton,
|
|
10
|
+
},
|
|
11
|
+
directives: {
|
|
12
|
+
GlTooltip: GlTooltipDirective,
|
|
13
|
+
},
|
|
14
|
+
props: {
|
|
15
|
+
/**
|
|
16
|
+
* The text to copy to clipboard
|
|
17
|
+
*/
|
|
18
|
+
text: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* The tooltip text shown on hover
|
|
24
|
+
*/
|
|
25
|
+
title: {
|
|
26
|
+
type: String,
|
|
27
|
+
required: false,
|
|
28
|
+
default: () => translate('ClipboardButton.title', 'Copy to clipboard'),
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Button size
|
|
32
|
+
*/
|
|
33
|
+
size: {
|
|
34
|
+
type: String,
|
|
35
|
+
required: false,
|
|
36
|
+
default: 'medium',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
data() {
|
|
40
|
+
return {
|
|
41
|
+
localTitle: this.title,
|
|
42
|
+
titleTimeout: null,
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
methods: {
|
|
46
|
+
updateTooltip(title) {
|
|
47
|
+
this.localTitle = title;
|
|
48
|
+
|
|
49
|
+
clearTimeout(this.titleTimeout);
|
|
50
|
+
|
|
51
|
+
this.titleTimeout = setTimeout(() => {
|
|
52
|
+
this.localTitle = this.title;
|
|
53
|
+
}, 1000);
|
|
54
|
+
},
|
|
55
|
+
async handleClick() {
|
|
56
|
+
try {
|
|
57
|
+
await navigator.clipboard.writeText(this.text);
|
|
58
|
+
this.updateTooltip(translate('ClipboardButton.copied', 'Copied'));
|
|
59
|
+
} catch {
|
|
60
|
+
this.updateTooltip(translate('ClipboardButton.error', 'Copy failed'));
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<gl-button
|
|
69
|
+
v-gl-tooltip.hover.focus.top
|
|
70
|
+
variant="default"
|
|
71
|
+
category="tertiary"
|
|
72
|
+
icon="copy-to-clipboard"
|
|
73
|
+
:size="size"
|
|
74
|
+
:title="localTitle"
|
|
75
|
+
:aria-label="localTitle"
|
|
76
|
+
@click="handleClick"
|
|
77
|
+
/>
|
|
78
|
+
</template>
|
package/translations.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* eslint-disable import/no-default-export */
|
|
2
2
|
export default {
|
|
3
3
|
'ClearIconButton.title': 'Clear',
|
|
4
|
+
'ClipboardButton.copied': 'Copied',
|
|
5
|
+
'ClipboardButton.error': 'Copy failed',
|
|
6
|
+
'ClipboardButton.title': 'Copy to clipboard',
|
|
4
7
|
'CloseButton.title': 'Close',
|
|
5
8
|
'GlAlert.closeButtonTitle': 'Dismiss',
|
|
6
9
|
'GlBanner.closeButtonTitle': 'Dismiss',
|