@gitlab/ui 134.0.0 → 134.1.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/dist/components/base/avatars_inline/avatars_inline.js +5 -1
- package/dist/components/base/breadcrumb/breadcrumb.js +5 -1
- package/dist/components/base/breadcrumb/breadcrumb_item.js +7 -1
- package/dist/components/base/button/button.js +36 -19
- package/dist/config.js +23 -3
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/utils/string_utils.js +0 -1
- package/package.json +11 -11
- package/src/components/base/avatars_inline/avatars_inline.vue +5 -1
- package/src/components/base/breadcrumb/breadcrumb.vue +5 -5
- package/src/components/base/breadcrumb/breadcrumb_item.vue +7 -1
- package/src/components/base/button/button.vue +37 -16
- package/src/components/base/new_dropdowns/dropdown.scss +4 -2
- package/src/components/utilities/sprintf/sprintf.vue +0 -1
- package/src/config.js +21 -2
- package/src/utils/string_utils.js +0 -1
|
@@ -29,7 +29,6 @@ const splitAfterSymbols = (symbols, string) => {
|
|
|
29
29
|
for (let j = 0; j < symbols.length; j += 1) {
|
|
30
30
|
const symbol = symbols[j];
|
|
31
31
|
if (!symbol) {
|
|
32
|
-
// eslint-disable-next-line no-continue
|
|
33
32
|
continue;
|
|
34
33
|
}
|
|
35
34
|
symbolFound = string.slice(i, i + symbol.length) === symbol;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "134.
|
|
3
|
+
"version": "134.1.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"resolutions": {
|
|
92
92
|
"chokidar": "^4.0.3",
|
|
93
93
|
"sane": "^5.0.1",
|
|
94
|
-
"jackspeak": "2.
|
|
95
|
-
"postcss": "8.5.
|
|
94
|
+
"jackspeak": "2.3.6",
|
|
95
|
+
"postcss": "8.5.14",
|
|
96
96
|
"json5": "2.2.3",
|
|
97
97
|
"rollup-plugin-vue/@vue/component-compiler/postcss-modules-sync/generic-names/loader-utils": "3.3.1"
|
|
98
98
|
},
|
|
@@ -101,14 +101,14 @@
|
|
|
101
101
|
"@babel/core": "^7.29.0",
|
|
102
102
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
|
103
103
|
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
|
|
104
|
-
"@babel/preset-env": "^7.29.
|
|
104
|
+
"@babel/preset-env": "^7.29.5",
|
|
105
105
|
"@babel/preset-react": "^7.28.5",
|
|
106
106
|
"@cypress/grep": "^4.1.1",
|
|
107
|
-
"@figma/code-connect": "^1.4.
|
|
107
|
+
"@figma/code-connect": "^1.4.5",
|
|
108
108
|
"@gitlab/fonts": "^1.3.1",
|
|
109
|
-
"@gitlab/hybrid-vue": "npm:@vue/compat@3.5.
|
|
109
|
+
"@gitlab/hybrid-vue": "npm:@vue/compat@3.5.34",
|
|
110
110
|
"@gitlab/svgs": "*",
|
|
111
|
-
"@jest/test-sequencer": "30.
|
|
111
|
+
"@jest/test-sequencer": "30.4.1",
|
|
112
112
|
"@rollup/plugin-commonjs": "^28.0.9",
|
|
113
113
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
114
114
|
"@rollup/plugin-replace": "^6.0.3",
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
"autoprefixer": "10.5.0",
|
|
140
140
|
"axe-playwright": "^2.2.2",
|
|
141
141
|
"babel-loader": "^9.2.1",
|
|
142
|
-
"cypress": "15.
|
|
142
|
+
"cypress": "15.15.0",
|
|
143
143
|
"cypress-real-events": "^1.15.0",
|
|
144
144
|
"dompurify": "^3.1.2",
|
|
145
145
|
"emoji-regex": "^10.6.0",
|
|
@@ -154,9 +154,9 @@
|
|
|
154
154
|
"mockdate": "^3.0.5",
|
|
155
155
|
"module-alias": "^2.3.4",
|
|
156
156
|
"pikaday": "^1.8.0",
|
|
157
|
-
"playwright": "^1.
|
|
158
|
-
"playwright-core": "^1.
|
|
159
|
-
"postcss": "8.5.
|
|
157
|
+
"playwright": "^1.60.0",
|
|
158
|
+
"playwright-core": "^1.60.0",
|
|
159
|
+
"postcss": "8.5.14",
|
|
160
160
|
"postcss-loader": "8.2.1",
|
|
161
161
|
"postcss-scss": "4.0.9",
|
|
162
162
|
"react": "18.3.1",
|
|
@@ -84,6 +84,10 @@ export default {
|
|
|
84
84
|
}[this.avatarSize] || 'lg'
|
|
85
85
|
);
|
|
86
86
|
},
|
|
87
|
+
rootClass() {
|
|
88
|
+
// eslint-disable-next-line @gitlab/tailwind-no-interpolation
|
|
89
|
+
return ['gl-avatars-inline', `gl-avatars-inline-${this.badgeSize}`];
|
|
90
|
+
},
|
|
87
91
|
badgeLabel() {
|
|
88
92
|
return `+${this.hiddenAvatars.length}`;
|
|
89
93
|
},
|
|
@@ -106,7 +110,7 @@ export default {
|
|
|
106
110
|
};
|
|
107
111
|
</script>
|
|
108
112
|
<template>
|
|
109
|
-
<div
|
|
113
|
+
<div :class="rootClass">
|
|
110
114
|
<div v-for="(avatar, index) in visibleAvatars" :key="index" class="gl-avatars-inline-child">
|
|
111
115
|
<!-- @slot Custom avatar rendering. Provide avatar object as slot prop. -->
|
|
112
116
|
<slot name="avatar" :avatar="avatar">
|
|
@@ -119,6 +119,10 @@ export default {
|
|
|
119
119
|
}
|
|
120
120
|
return '';
|
|
121
121
|
},
|
|
122
|
+
dropdownItemClass() {
|
|
123
|
+
// eslint-disable-next-line @gitlab/tailwind-no-interpolation
|
|
124
|
+
return ['gl-breadcrumb-item', `gl-breadcrumb-item-${this.size}`];
|
|
125
|
+
},
|
|
122
126
|
dropdownSize() {
|
|
123
127
|
return this.size === 'sm' ? 'small' : 'medium';
|
|
124
128
|
},
|
|
@@ -257,11 +261,7 @@ export default {
|
|
|
257
261
|
<template>
|
|
258
262
|
<nav class="gl-breadcrumbs" :aria-label="ariaLabel" :style="breadcrumbStyle">
|
|
259
263
|
<ol class="gl-breadcrumb-list breadcrumb" v-bind="$attrs" v-on="$listeners">
|
|
260
|
-
<li
|
|
261
|
-
v-if="hasCollapsible || !resizeDone"
|
|
262
|
-
ref="dropdown"
|
|
263
|
-
:class="`gl-breadcrumb-item gl-breadcrumb-item-${size}`"
|
|
264
|
-
>
|
|
264
|
+
<li v-if="hasCollapsible || !resizeDone" ref="dropdown" :class="dropdownItemClass">
|
|
265
265
|
<gl-disclosure-dropdown
|
|
266
266
|
:items="overflowingItems"
|
|
267
267
|
:toggle-text="showMoreLabel"
|
|
@@ -54,12 +54,18 @@ export default {
|
|
|
54
54
|
validator: (value) => Object.keys(breadCrumbSizeOptions).includes(value),
|
|
55
55
|
},
|
|
56
56
|
},
|
|
57
|
+
computed: {
|
|
58
|
+
itemClass() {
|
|
59
|
+
// eslint-disable-next-line @gitlab/tailwind-no-interpolation
|
|
60
|
+
return ['gl-breadcrumb-item', `gl-breadcrumb-item-${this.size}`];
|
|
61
|
+
},
|
|
62
|
+
},
|
|
57
63
|
linkVariantUnstyled,
|
|
58
64
|
};
|
|
59
65
|
</script>
|
|
60
66
|
|
|
61
67
|
<template>
|
|
62
|
-
<li :class="
|
|
68
|
+
<li :class="itemClass">
|
|
63
69
|
<gl-link
|
|
64
70
|
:href="href"
|
|
65
71
|
:to="to"
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { logWarning, stopEvent } from '../../../utils/utils';
|
|
10
10
|
import { isSlotEmpty } from '../../../utils/is_slot_empty';
|
|
11
11
|
import { SafeLinkMixin } from '../../mixins/safe_link_mixin';
|
|
12
|
-
import {
|
|
12
|
+
import { glButtonConfig } from '../../../config';
|
|
13
13
|
import GlIcon from '../icon/icon.vue';
|
|
14
14
|
import GlLoadingIcon from '../loading_icon/loading_icon.vue';
|
|
15
15
|
import { ENTER, SPACE } from '../new_dropdowns/constants';
|
|
@@ -122,6 +122,14 @@ export default {
|
|
|
122
122
|
required: false,
|
|
123
123
|
default: false,
|
|
124
124
|
},
|
|
125
|
+
/**
|
|
126
|
+
* Keep the button accessible while `disabled` is `true`. Uses `aria-disabled` so the element remains focusable and is announced by assistive technology.
|
|
127
|
+
*/
|
|
128
|
+
accessibleDisabled: {
|
|
129
|
+
type: Boolean,
|
|
130
|
+
required: false,
|
|
131
|
+
default: () => glButtonConfig.accessibleDisabledButton,
|
|
132
|
+
},
|
|
125
133
|
/**
|
|
126
134
|
* Denotes the target URL of the link for standard links.
|
|
127
135
|
*/
|
|
@@ -237,9 +245,20 @@ export default {
|
|
|
237
245
|
hasIconOnly() {
|
|
238
246
|
return isSlotEmpty(this, 'default') && this.hasIcon && this.count == null;
|
|
239
247
|
},
|
|
240
|
-
|
|
248
|
+
isDisabledOrLoading() {
|
|
249
|
+
if (this.accessibleDisabled) {
|
|
250
|
+
return this.disabled || (this.isButton && this.loading);
|
|
251
|
+
}
|
|
241
252
|
return this.isButton && this.loading;
|
|
242
253
|
},
|
|
254
|
+
ariaDisabled() {
|
|
255
|
+
if (this.isDisabledOrLoading) return 'true';
|
|
256
|
+
// Non-standard tags need an explicit aria-disabled value to convey interactive state.
|
|
257
|
+
if (this.isNonStandardTag) {
|
|
258
|
+
return this.accessibleDisabled ? 'false' : String(this.disabled);
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
},
|
|
243
262
|
buttonClasses() {
|
|
244
263
|
const classes = ['btn', 'gl-button', `btn-${this.variant}`, `btn-${this.buttonSize}`];
|
|
245
264
|
|
|
@@ -252,7 +271,7 @@ export default {
|
|
|
252
271
|
'button-ellipsis-horizontal': this.hasIconOnly && this.icon === 'ellipsis_h',
|
|
253
272
|
selected: this.selected,
|
|
254
273
|
'btn-block': this.displayBlock,
|
|
255
|
-
disabled: this.disabled || this.
|
|
274
|
+
disabled: this.disabled || this.isDisabledOrLoading,
|
|
256
275
|
});
|
|
257
276
|
|
|
258
277
|
if (this.label) {
|
|
@@ -284,27 +303,24 @@ export default {
|
|
|
284
303
|
return !this.isLink && !this.isButton;
|
|
285
304
|
},
|
|
286
305
|
tabindex() {
|
|
287
|
-
//
|
|
288
|
-
if (this.disabled) {
|
|
306
|
+
// Legacy: remove disabled links and non-standard tags from tab order.
|
|
307
|
+
if (!this.accessibleDisabled && this.disabled) {
|
|
289
308
|
return this.isLink || this.isNonStandardTag ? '-1' : this.$attrs.tabindex;
|
|
290
309
|
}
|
|
291
|
-
|
|
292
|
-
//
|
|
310
|
+
// Inactive elements stay in tab order so assistive technology can discover them;
|
|
311
|
+
// aria-disabled communicates the inactive state instead of removing the element.
|
|
293
312
|
return this.isNonStandardTag || this.isHashLink ? '0' : this.$attrs.tabindex;
|
|
294
313
|
},
|
|
295
314
|
computedPropsAndAttributes() {
|
|
296
315
|
const base = {
|
|
297
316
|
// Type only used for "real" buttons
|
|
298
317
|
type: this.isButton ? this.type : null,
|
|
299
|
-
//
|
|
300
|
-
|
|
318
|
+
// Legacy: native disabled attribute on real buttons.
|
|
319
|
+
...(!this.accessibleDisabled && this.isButton ? { disabled: this.disabled } : {}),
|
|
301
320
|
// We add a role of button when the tag is not a link or button or when link has `href` of `#`
|
|
302
321
|
role: this.isNonStandardTag || this.isHashLink ? 'button' : this.$attrs?.role,
|
|
303
|
-
// We set the `aria-disabled` state for non-standard tags
|
|
304
|
-
...(this.isNonStandardTag ? { 'aria-disabled': String(this.disabled) } : {}),
|
|
305
322
|
tabindex: this.tabindex,
|
|
306
|
-
|
|
307
|
-
...(this.isButtonAriaDisabled ? { 'aria-disabled': 'true' } : {}),
|
|
323
|
+
...(this.ariaDisabled !== null ? { 'aria-disabled': this.ariaDisabled } : {}),
|
|
308
324
|
};
|
|
309
325
|
|
|
310
326
|
if (this.isLink) {
|
|
@@ -333,7 +349,7 @@ export default {
|
|
|
333
349
|
...this.$listeners,
|
|
334
350
|
};
|
|
335
351
|
|
|
336
|
-
if (this.
|
|
352
|
+
if (this.isDisabledOrLoading) {
|
|
337
353
|
delete listeners.click;
|
|
338
354
|
}
|
|
339
355
|
return listeners;
|
|
@@ -366,7 +382,11 @@ export default {
|
|
|
366
382
|
// Skip if disabled
|
|
367
383
|
// Add SPACE keydown handler for link has `href` of `#`
|
|
368
384
|
// Add ENTER handler for non-standard tags
|
|
369
|
-
if (
|
|
385
|
+
if (
|
|
386
|
+
!this.disabled &&
|
|
387
|
+
!this.isDisabledOrLoading &&
|
|
388
|
+
(this.isNonStandardTag || this.isHashLink)
|
|
389
|
+
) {
|
|
370
390
|
const { code } = event;
|
|
371
391
|
|
|
372
392
|
if (code === SPACE || (code === ENTER && this.isNonStandardTag)) {
|
|
@@ -377,7 +397,8 @@ export default {
|
|
|
377
397
|
}
|
|
378
398
|
},
|
|
379
399
|
maybeStopEvent(event) {
|
|
380
|
-
|
|
400
|
+
const eventIsEvent = event instanceof Event;
|
|
401
|
+
if (this.isDisabledOrLoading && eventIsEvent) {
|
|
381
402
|
stopEvent(event);
|
|
382
403
|
}
|
|
383
404
|
},
|
package/src/config.js
CHANGED
|
@@ -6,6 +6,8 @@ export const defaultConfig = {
|
|
|
6
6
|
firstDayOfWeek: 0, // Defaults to 0 (Sunday)
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
export const glButtonConfig = {};
|
|
10
|
+
|
|
9
11
|
let configured = false;
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -15,10 +17,10 @@ let configured = false;
|
|
|
15
17
|
* @template TValue=string
|
|
16
18
|
* @property {undefined | Object} translations Generic translations for component labels to fall back to.
|
|
17
19
|
* @property {undefined | Number} firstDayOfWeek Configured first day of the week, from 0 (Sunday) to 6 (Saturday).
|
|
18
|
-
* @property {boolean} [
|
|
20
|
+
* @property {boolean} [accessibleDisabledButton] Temporary flag to enable the accessible disabled button.
|
|
19
21
|
*
|
|
20
22
|
*/
|
|
21
|
-
const setConfigs = ({ translations, firstDayOfWeek } = {}) => {
|
|
23
|
+
const setConfigs = ({ translations, firstDayOfWeek, accessibleDisabledButton = false } = {}) => {
|
|
22
24
|
if (configured) {
|
|
23
25
|
if (process.env.NODE_ENV === 'development') {
|
|
24
26
|
throw new Error('GitLab UI can only be configured once!');
|
|
@@ -52,6 +54,23 @@ const setConfigs = ({ translations, firstDayOfWeek } = {}) => {
|
|
|
52
54
|
|
|
53
55
|
Object.assign(i18n, translations);
|
|
54
56
|
}
|
|
57
|
+
|
|
58
|
+
// Temporary flag to enable the accessible disabled button feature.
|
|
59
|
+
// This flag allows the feature to be opt-in during the rollout phase,
|
|
60
|
+
// giving us the flexibility to test and validate its impact on user experience.
|
|
61
|
+
|
|
62
|
+
// The global variable `accessibleDisabledButton` is set to a boolean value
|
|
63
|
+
// to indicate whether the button should use aria-disabled while disabled.
|
|
64
|
+
|
|
65
|
+
// Future Plan:
|
|
66
|
+
// Once the accessible disabled button feature is validated and stable,
|
|
67
|
+
// we will remove this temporary flag and make the feature the default behavior.
|
|
68
|
+
// At that point, there will be no need for opt-in or opt-out mechanisms for this feature.
|
|
69
|
+
if (typeof accessibleDisabledButton === 'boolean') {
|
|
70
|
+
Object.assign(glButtonConfig, {
|
|
71
|
+
accessibleDisabledButton,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
55
74
|
};
|
|
56
75
|
|
|
57
76
|
export default setConfigs;
|