@gitlab/ui 113.6.0 → 114.0.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 +25 -0
- package/dist/components/base/button/button.js +251 -8
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
- package/src/components/base/button/button.md +61 -3
- package/src/components/base/button/button.vue +248 -13
- package/src/scss/typography.scss +10 -0
- package/src/vendor/bootstrap/scss/_code.scss +0 -17
- package/src/vendor/bootstrap/scss/_variables.scss +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
# [114.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v113.7.0...v114.0.0) (2025-05-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **GlButton:** remove BButton from GlButton ([fcdca4e](https://gitlab.com/gitlab-org/gitlab-ui/commit/fcdca4ee51ed98d71d93a94a2ffa741cf720c4db))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* **GlButton:** support for following props have been dropped:
|
|
12
|
+
- pressed
|
|
13
|
+
- router-component-name
|
|
14
|
+
- exact
|
|
15
|
+
- exact-path
|
|
16
|
+
- exact-path-active-class (replaced with exact-active-class)
|
|
17
|
+
- no-prefetch (use prefetch instead)
|
|
18
|
+
|
|
19
|
+
# [113.7.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v113.6.0...v113.7.0) (2025-05-15)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* **CSS:** define basic styles for <kbd> element ([730ddb2](https://gitlab.com/gitlab-org/gitlab-ui/commit/730ddb2dc1a5912c1fa33fbb1db16aa70b044828))
|
|
25
|
+
|
|
1
26
|
# [113.6.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v113.5.2...v113.6.0) (2025-05-14)
|
|
2
27
|
|
|
3
28
|
|
|
@@ -1,74 +1,213 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { buttonCategoryOptions, buttonVariantOptions, buttonSizeOptions } from '../../../utils/constants';
|
|
3
|
-
import { logWarning } from '../../../utils/utils';
|
|
1
|
+
import GlLink from '../link/link';
|
|
2
|
+
import { buttonCategoryOptions, buttonVariantOptions, buttonSizeOptions, linkVariantUnstyled } from '../../../utils/constants';
|
|
3
|
+
import { logWarning, stopEvent } from '../../../utils/utils';
|
|
4
4
|
import { isSlotEmpty } from '../../../utils/is_slot_empty';
|
|
5
5
|
import { SafeLinkMixin } from '../../mixins/safe_link_mixin';
|
|
6
|
+
import { isEvent } from '../../../vendor/bootstrap-vue/src/utils/inspect';
|
|
6
7
|
import GlIcon from '../icon/icon';
|
|
7
8
|
import GlLoadingIcon from '../loading_icon/loading_icon';
|
|
9
|
+
import { SPACE, ENTER } from '../new_dropdowns/constants';
|
|
8
10
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
9
11
|
|
|
10
12
|
//
|
|
11
13
|
var script = {
|
|
12
14
|
name: 'GlButton',
|
|
13
15
|
components: {
|
|
14
|
-
BButton,
|
|
15
16
|
GlIcon,
|
|
16
17
|
GlLoadingIcon
|
|
17
18
|
},
|
|
18
19
|
mixins: [SafeLinkMixin],
|
|
19
20
|
props: {
|
|
21
|
+
/**
|
|
22
|
+
* Set the category of the button.
|
|
23
|
+
*/
|
|
20
24
|
category: {
|
|
21
25
|
type: String,
|
|
22
26
|
required: false,
|
|
23
27
|
default: buttonCategoryOptions.primary,
|
|
24
28
|
validator: value => Object.keys(buttonCategoryOptions).includes(value)
|
|
25
29
|
},
|
|
30
|
+
/**
|
|
31
|
+
* Set the variant of the button.
|
|
32
|
+
*/
|
|
26
33
|
variant: {
|
|
27
34
|
type: String,
|
|
28
35
|
required: false,
|
|
29
36
|
default: buttonVariantOptions.default,
|
|
30
37
|
validator: value => Object.keys(buttonVariantOptions).includes(value)
|
|
31
38
|
},
|
|
39
|
+
/**
|
|
40
|
+
* Specify the size of the button. Options are `small` and `medium`.
|
|
41
|
+
*/
|
|
32
42
|
size: {
|
|
33
43
|
type: String,
|
|
34
44
|
required: false,
|
|
35
45
|
default: 'medium',
|
|
36
46
|
validator: value => Object.keys(buttonSizeOptions).includes(value)
|
|
37
47
|
},
|
|
48
|
+
/**
|
|
49
|
+
* Style the button as selected.
|
|
50
|
+
*/
|
|
38
51
|
selected: {
|
|
39
52
|
type: Boolean,
|
|
40
53
|
required: false,
|
|
41
54
|
default: false
|
|
42
55
|
},
|
|
56
|
+
/**
|
|
57
|
+
* Specify an icon to render in the button.
|
|
58
|
+
*/
|
|
43
59
|
icon: {
|
|
44
60
|
type: String,
|
|
45
61
|
required: false,
|
|
46
62
|
default: ''
|
|
47
63
|
},
|
|
64
|
+
/**
|
|
65
|
+
* Render a non-interactive label button, a `span` styled as a button.
|
|
66
|
+
*/
|
|
48
67
|
label: {
|
|
49
68
|
type: Boolean,
|
|
50
69
|
required: false,
|
|
51
70
|
default: false
|
|
52
71
|
},
|
|
72
|
+
/**
|
|
73
|
+
* Set the loading state of the button.
|
|
74
|
+
*/
|
|
53
75
|
loading: {
|
|
54
76
|
type: Boolean,
|
|
55
77
|
required: false,
|
|
56
78
|
default: false
|
|
57
79
|
},
|
|
80
|
+
/**
|
|
81
|
+
* CSS classes to add to the button text.
|
|
82
|
+
*/
|
|
58
83
|
buttonTextClasses: {
|
|
59
84
|
type: String,
|
|
60
85
|
required: false,
|
|
61
86
|
default: ''
|
|
62
87
|
},
|
|
88
|
+
/**
|
|
89
|
+
* Renders a 100% width button (expands to the width of its parent container).
|
|
90
|
+
*/
|
|
63
91
|
block: {
|
|
64
92
|
type: Boolean,
|
|
65
93
|
required: false,
|
|
66
94
|
default: false
|
|
67
95
|
},
|
|
96
|
+
/**
|
|
97
|
+
* Specify the HTML tag to render instead of the default tag.
|
|
98
|
+
*/
|
|
99
|
+
tag: {
|
|
100
|
+
type: String,
|
|
101
|
+
required: false,
|
|
102
|
+
default: 'button'
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* The value to set the button's `type` attribute to. Can be one of `button`, `submit`, or `reset`.
|
|
106
|
+
*/
|
|
107
|
+
type: {
|
|
108
|
+
type: String,
|
|
109
|
+
required: false,
|
|
110
|
+
default: 'button',
|
|
111
|
+
validator: value => ['button', 'submit', 'reset'].includes(value)
|
|
112
|
+
},
|
|
113
|
+
/**
|
|
114
|
+
* Disables the component's functionality and places it in a disabled state.
|
|
115
|
+
*/
|
|
68
116
|
disabled: {
|
|
69
117
|
type: Boolean,
|
|
70
118
|
required: false,
|
|
71
119
|
default: false
|
|
120
|
+
},
|
|
121
|
+
/**
|
|
122
|
+
* Denotes the target URL of the link for standard links.
|
|
123
|
+
*/
|
|
124
|
+
href: {
|
|
125
|
+
type: String,
|
|
126
|
+
required: false,
|
|
127
|
+
default: undefined
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Skips sanitization of href if true. This should be used sparingly.
|
|
131
|
+
* Consult security team before setting to true.
|
|
132
|
+
*/
|
|
133
|
+
isUnsafeLink: {
|
|
134
|
+
type: Boolean,
|
|
135
|
+
required: false,
|
|
136
|
+
default: false
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* Sets the 'rel' attribute on the rendered link.
|
|
140
|
+
*/
|
|
141
|
+
rel: {
|
|
142
|
+
type: String,
|
|
143
|
+
required: false,
|
|
144
|
+
default: null
|
|
145
|
+
},
|
|
146
|
+
/**
|
|
147
|
+
* Sets the 'target' attribute on the rendered link.
|
|
148
|
+
*/
|
|
149
|
+
target: {
|
|
150
|
+
type: String,
|
|
151
|
+
required: false,
|
|
152
|
+
default: null
|
|
153
|
+
},
|
|
154
|
+
/**
|
|
155
|
+
* Places the component in the active state with active styling
|
|
156
|
+
*/
|
|
157
|
+
active: {
|
|
158
|
+
type: Boolean,
|
|
159
|
+
required: false,
|
|
160
|
+
default: false
|
|
161
|
+
},
|
|
162
|
+
/**
|
|
163
|
+
* <router-link> prop: Denotes the target route of the link.
|
|
164
|
+
* When clicked, the value of the to prop will be passed to `router.push()` internally,
|
|
165
|
+
* so the value can be either a string or a Location descriptor object.
|
|
166
|
+
*/
|
|
167
|
+
to: {
|
|
168
|
+
type: [Object, String],
|
|
169
|
+
required: false,
|
|
170
|
+
default: undefined
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* <router-link> prop: Configure the active CSS class applied when the link is active.
|
|
174
|
+
*/
|
|
175
|
+
activeClass: {
|
|
176
|
+
type: String,
|
|
177
|
+
required: false,
|
|
178
|
+
default: undefined
|
|
179
|
+
},
|
|
180
|
+
/**
|
|
181
|
+
* <router-link> prop: Configure the active CSS class applied when the link is active with exact match.
|
|
182
|
+
*/
|
|
183
|
+
exactActiveClass: {
|
|
184
|
+
type: String,
|
|
185
|
+
required: false,
|
|
186
|
+
default: undefined
|
|
187
|
+
},
|
|
188
|
+
/**
|
|
189
|
+
* <router-link> prop: Setting the replace prop will call `router.replace()` instead of `router.push()`
|
|
190
|
+
* when clicked, so the navigation will not leave a history record.
|
|
191
|
+
*/
|
|
192
|
+
replace: {
|
|
193
|
+
type: Boolean,
|
|
194
|
+
required: false,
|
|
195
|
+
default: false
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* <nuxt-link> prop: To improve the responsiveness of your Nuxt.js applications, when the link will be displayed within the viewport,
|
|
199
|
+
* Nuxt.js will automatically prefetch the code splitted page. Setting `prefetch` to `true` or `false` will overwrite the default value of `router.prefetchLinks`
|
|
200
|
+
*/
|
|
201
|
+
prefetch: {
|
|
202
|
+
type: Boolean,
|
|
203
|
+
required: false,
|
|
204
|
+
// Must be `null` to fall back to the value defined in the
|
|
205
|
+
// `nuxt.config.js` configuration file for `router.prefetchLinks`
|
|
206
|
+
// We convert `null` to `undefined`, so that Nuxt.js will use the
|
|
207
|
+
// compiled default
|
|
208
|
+
// Vue treats `undefined` as default of `false` for Boolean props,
|
|
209
|
+
// so we must set it as `null` here to be a true tri-state prop
|
|
210
|
+
default: null
|
|
72
211
|
}
|
|
73
212
|
},
|
|
74
213
|
computed: {
|
|
@@ -82,17 +221,19 @@ var script = {
|
|
|
82
221
|
return this.disabled || this.loading;
|
|
83
222
|
},
|
|
84
223
|
buttonClasses() {
|
|
85
|
-
const classes = ['gl-button'];
|
|
224
|
+
const classes = ['btn', 'gl-button', `btn-${this.variant}`, `btn-${this.buttonSize}`];
|
|
86
225
|
if (this.category !== buttonCategoryOptions.primary) {
|
|
87
226
|
classes.push(`btn-${this.variant}-${this.category}`);
|
|
88
227
|
}
|
|
89
228
|
classes.push({
|
|
90
229
|
'btn-icon': this.hasIconOnly,
|
|
91
230
|
'button-ellipsis-horizontal': this.hasIconOnly && this.icon === 'ellipsis_h',
|
|
92
|
-
selected: this.selected
|
|
231
|
+
selected: this.selected,
|
|
232
|
+
'btn-block': this.displayBlock,
|
|
233
|
+
disabled: this.disabled
|
|
93
234
|
});
|
|
94
235
|
if (this.label) {
|
|
95
|
-
classes.push('btn', 'btn-label'
|
|
236
|
+
classes.push('btn', 'btn-label');
|
|
96
237
|
}
|
|
97
238
|
return classes;
|
|
98
239
|
},
|
|
@@ -101,6 +242,84 @@ var script = {
|
|
|
101
242
|
},
|
|
102
243
|
displayBlock() {
|
|
103
244
|
return !this.label && this.block;
|
|
245
|
+
},
|
|
246
|
+
isLink() {
|
|
247
|
+
return this.href || this.to;
|
|
248
|
+
},
|
|
249
|
+
isHashLink() {
|
|
250
|
+
return this.isLink && this.href === '#';
|
|
251
|
+
},
|
|
252
|
+
isButton() {
|
|
253
|
+
return this.componentIs === 'button';
|
|
254
|
+
},
|
|
255
|
+
isNonStandardTag() {
|
|
256
|
+
if (this.label) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
return !this.isLink && !this.isButton;
|
|
260
|
+
},
|
|
261
|
+
tabindex() {
|
|
262
|
+
// When disabled remove links and non-standard tags from tab order
|
|
263
|
+
if (this.disabled) {
|
|
264
|
+
return this.isLink || this.isNonStandardTag ? '-1' : this.$attrs.tabindex;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Add hash links and non-standard tags to tab order
|
|
268
|
+
return this.isNonStandardTag || this.isHashLink ? '0' : this.$attrs.tabindex;
|
|
269
|
+
},
|
|
270
|
+
computedPropsAndAttributes() {
|
|
271
|
+
var _this$$attrs;
|
|
272
|
+
const base = {
|
|
273
|
+
// Type only used for "real" buttons
|
|
274
|
+
type: this.isButton ? this.type : null,
|
|
275
|
+
// Disabled only set on "real" buttons
|
|
276
|
+
disabled: this.isButton ? this.isButtonDisabled : null,
|
|
277
|
+
// We add a role of button when the tag is not a link or button or when link has `href` of `#`
|
|
278
|
+
role: this.isNonStandardTag || this.isHashLink ? 'button' : (_this$$attrs = this.$attrs) === null || _this$$attrs === void 0 ? void 0 : _this$$attrs.role,
|
|
279
|
+
// We set the `aria-disabled` state for non-standard tags
|
|
280
|
+
...(this.isNonStandardTag ? {
|
|
281
|
+
'aria-disabled': String(this.disabled)
|
|
282
|
+
} : {}),
|
|
283
|
+
tabindex: this.tabindex
|
|
284
|
+
};
|
|
285
|
+
if (this.isLink) {
|
|
286
|
+
return {
|
|
287
|
+
...this.$attrs,
|
|
288
|
+
...base,
|
|
289
|
+
variant: linkVariantUnstyled,
|
|
290
|
+
disabled: this.disabled,
|
|
291
|
+
href: this.href,
|
|
292
|
+
isUnsafeLink: this.isUnsafeLink,
|
|
293
|
+
rel: this.rel,
|
|
294
|
+
target: this.target,
|
|
295
|
+
active: this.active,
|
|
296
|
+
to: this.to,
|
|
297
|
+
activeClass: this.activeClass,
|
|
298
|
+
exactActiveClass: this.exactActiveClass,
|
|
299
|
+
replace: this.replace,
|
|
300
|
+
prefetch: this.prefetch
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
...this.$attrs,
|
|
305
|
+
...base
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
computedListeners() {
|
|
309
|
+
return {
|
|
310
|
+
click: this.onClick,
|
|
311
|
+
keydown: this.onKeydown,
|
|
312
|
+
...this.$listeners
|
|
313
|
+
};
|
|
314
|
+
},
|
|
315
|
+
componentIs() {
|
|
316
|
+
if (this.label) {
|
|
317
|
+
return 'span';
|
|
318
|
+
}
|
|
319
|
+
if (this.isLink) {
|
|
320
|
+
return GlLink;
|
|
321
|
+
}
|
|
322
|
+
return this.tag;
|
|
104
323
|
}
|
|
105
324
|
},
|
|
106
325
|
mounted() {
|
|
@@ -108,6 +327,30 @@ var script = {
|
|
|
108
327
|
if (!this.$slots.default && !this.$attrs['aria-label'] && !this.$props.label) {
|
|
109
328
|
logWarning('[gl-button]: Accessible name missing. Please add inner text or aria-label.', this.$el);
|
|
110
329
|
}
|
|
330
|
+
},
|
|
331
|
+
methods: {
|
|
332
|
+
onKeydown(event) {
|
|
333
|
+
// Skip if disabled
|
|
334
|
+
// Add SPACE keydown handler for link has `href` of `#`
|
|
335
|
+
// Add ENTER handler for non-standard tags
|
|
336
|
+
if (!this.disabled && (this.isNonStandardTag || this.isHashLink)) {
|
|
337
|
+
const {
|
|
338
|
+
code
|
|
339
|
+
} = event;
|
|
340
|
+
if (code === SPACE || code === ENTER && this.isNonStandardTag) {
|
|
341
|
+
const target = event.currentTarget || event.target;
|
|
342
|
+
stopEvent(event, {
|
|
343
|
+
propagation: false
|
|
344
|
+
});
|
|
345
|
+
target.click();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
onClick(event) {
|
|
350
|
+
if (this.disabled && isEvent(event)) {
|
|
351
|
+
stopEvent(event);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
111
354
|
}
|
|
112
355
|
};
|
|
113
356
|
|
|
@@ -115,7 +358,7 @@ var script = {
|
|
|
115
358
|
const __vue_script__ = script;
|
|
116
359
|
|
|
117
360
|
/* template */
|
|
118
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c(_vm.
|
|
361
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c(_vm.componentIs,_vm._g(_vm._b({directives:[{name:"safe-link",rawName:"v-safe-link:[safeLinkConfig]",arg:_vm.safeLinkConfig}],tag:"component",class:_vm.buttonClasses},'component',_vm.computedPropsAndAttributes,false),_vm.computedListeners),[(_vm.loading)?_c('gl-loading-icon',{staticClass:"gl-button-icon gl-button-loading-indicator",attrs:{"inline":""}}):_vm._e(),_vm._v(" "),(_vm.hasIcon && !(_vm.hasIconOnly && _vm.loading))?_c('gl-icon',{staticClass:"gl-button-icon",attrs:{"name":_vm.icon}}):_vm._e(),_vm._v(" "),_vm._t("emoji"),_vm._v(" "),(!_vm.hasIconOnly)?_c('span',{staticClass:"gl-button-text",class:_vm.buttonTextClasses},[_vm._t("default")],2):_vm._e()],2)};
|
|
119
362
|
var __vue_staticRenderFns__ = [];
|
|
120
363
|
|
|
121
364
|
/* style */
|