@gitlab/ui 85.11.0 → 85.12.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/CHANGELOG.md +14 -0
- package/dist/components/base/badge/badge.js +1 -1
- package/dist/components/base/new_dropdowns/listbox/listbox.js +2 -8
- package/dist/components/base/pagination/pagination.js +15 -5
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/utils/i18n.js +49 -1
- package/package.json +3 -3
- package/src/components/base/badge/badge.scss +5 -2
- package/src/components/base/badge/badge.vue +5 -2
- package/src/components/base/new_dropdowns/listbox/listbox.vue +6 -8
- package/src/components/base/pagination/pagination.vue +18 -5
- package/src/utils/i18n.js +52 -0
- package/translations.js +2 -1
package/dist/utils/i18n.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import escape from 'lodash/escape';
|
|
1
2
|
import { i18n } from '../config';
|
|
2
3
|
|
|
4
|
+
const defaultPluralHandler = (n, singleValue, pluralValue) => {
|
|
5
|
+
const value = n === 1 ? singleValue : pluralValue;
|
|
6
|
+
return value.replace(/%d/g, n);
|
|
7
|
+
};
|
|
8
|
+
|
|
3
9
|
/**
|
|
4
10
|
* Mark a label as translatable.
|
|
5
11
|
*
|
|
@@ -12,4 +18,46 @@ const translate = (key, defaultValue) => {
|
|
|
12
18
|
return (_i18n$key = i18n[key]) !== null && _i18n$key !== void 0 ? _i18n$key : defaultValue;
|
|
13
19
|
};
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Marks a label as translatable and pluralized.
|
|
23
|
+
*
|
|
24
|
+
* @param {*} key Translation key to be leveraged by the consumer to provide a generic translation at configuration time.
|
|
25
|
+
* @param {*} singularValue The singular value to be relied on if the consumer doesn't have translation capabilities.
|
|
26
|
+
* @param {*} pluralValue The plural value to be relied on if the consumer doesn't have translation capabilities.
|
|
27
|
+
* @returns {function} A function that takes a number and returns the pluralized translated label.
|
|
28
|
+
*/
|
|
29
|
+
const translatePlural = (key, singularValue, pluralValue) => {
|
|
30
|
+
if (i18n[key]) {
|
|
31
|
+
return i18n[key];
|
|
32
|
+
}
|
|
33
|
+
return x => defaultPluralHandler(x, singularValue, pluralValue);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Very limited implementation of sprintf supporting only named parameters.
|
|
38
|
+
* Copied from the GitLab repo: https://gitlab.com/gitlab-org/gitlab/-/blob/0dff8b02accb3dccbf6cd31236834c37013aad59/app/assets/javascripts/locale/sprintf.js.
|
|
39
|
+
* @param {string} input - (translated) text with parameters (e.g. '%{num_users} users use us')
|
|
40
|
+
* @param {Object.<string, string|number>} [parameters] - object mapping parameter names to values (e.g. { num_users: 5 })
|
|
41
|
+
* @param {boolean} [escapeParameters=true] - whether parameter values should be escaped (see https://lodash.com/docs/4.17.15#escape)
|
|
42
|
+
* @returns {string} the text with parameters replaces (e.g. '5 users use us')
|
|
43
|
+
* @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf
|
|
44
|
+
* @see https://gitlab.com/gitlab-org/gitlab-foss/issues/37992
|
|
45
|
+
*/
|
|
46
|
+
function sprintf(input, parameters) {
|
|
47
|
+
let escapeParameters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
48
|
+
let output = input;
|
|
49
|
+
output = output.replace(/%+/g, '%');
|
|
50
|
+
if (parameters) {
|
|
51
|
+
const mappedParameters = new Map(Object.entries(parameters));
|
|
52
|
+
mappedParameters.forEach((key, parameterName) => {
|
|
53
|
+
const parameterValue = mappedParameters.get(parameterName);
|
|
54
|
+
const escapedParameterValue = escapeParameters ? escape(parameterValue) : parameterValue;
|
|
55
|
+
// Pass the param value as a function to ignore special replacement patterns like $` and $'.
|
|
56
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#syntax
|
|
57
|
+
output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), () => escapedParameterValue);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return output;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { sprintf, translate, translatePlural };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "85.
|
|
3
|
+
"version": "85.12.1",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -167,8 +167,8 @@
|
|
|
167
167
|
"module-alias": "^2.2.2",
|
|
168
168
|
"npm-run-all": "^4.1.5",
|
|
169
169
|
"pikaday": "^1.8.0",
|
|
170
|
-
"playwright": "^1.
|
|
171
|
-
"playwright-core": "^1.
|
|
170
|
+
"playwright": "^1.45.0",
|
|
171
|
+
"playwright-core": "^1.45.0",
|
|
172
172
|
"plop": "^2.5.4",
|
|
173
173
|
"postcss": "8.4.28",
|
|
174
174
|
"postcss-loader": "^7.0.2",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
$badge-padding-horizontal: 0.75 * $grid-size;
|
|
2
|
-
$badge-min-width:
|
|
2
|
+
$badge-min-width: $gl-spacing-scale-3;
|
|
3
3
|
|
|
4
4
|
@mixin gl-badge-variant(
|
|
5
5
|
$variant,
|
|
@@ -74,7 +74,6 @@ $badge-min-width: 2.5 * $grid-size;
|
|
|
74
74
|
@include gl-line-height-normal;
|
|
75
75
|
gap: $gl-spacing-scale-2;
|
|
76
76
|
padding: $gl-spacing-scale-1 $badge-padding-horizontal;
|
|
77
|
-
min-width: $badge-min-width;
|
|
78
77
|
|
|
79
78
|
@media (forced-colors: active) {
|
|
80
79
|
border: 1px solid;
|
|
@@ -86,6 +85,10 @@ $badge-min-width: 2.5 * $grid-size;
|
|
|
86
85
|
@include gl-flex-shrink-0;
|
|
87
86
|
top: auto;
|
|
88
87
|
}
|
|
88
|
+
|
|
89
|
+
.gl-badge-content {
|
|
90
|
+
min-width: $badge-min-width;
|
|
91
|
+
}
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/* Variants */
|
|
@@ -83,7 +83,10 @@ export default {
|
|
|
83
83
|
:class="{ '-gl-ml-2 gl-ml-n2': isCircularIcon }"
|
|
84
84
|
:name="icon"
|
|
85
85
|
/>
|
|
86
|
-
<!-- @
|
|
87
|
-
<
|
|
86
|
+
<!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots -->
|
|
87
|
+
<span v-if="$slots.default" class="gl-badge-content">
|
|
88
|
+
<!-- @slot The badge content to display. -->
|
|
89
|
+
<slot></slot>
|
|
90
|
+
</span>
|
|
88
91
|
</b-badge>
|
|
89
92
|
</template>
|
|
@@ -26,7 +26,7 @@ import GlLoadingIcon from '../../loading_icon/loading_icon.vue';
|
|
|
26
26
|
import GlIntersectionObserver from '../../../utilities/intersection_observer/intersection_observer.vue';
|
|
27
27
|
import GlSearchBoxByType from '../../search_box_by_type/search_box_by_type.vue';
|
|
28
28
|
import GlBaseDropdown from '../base_dropdown/base_dropdown.vue';
|
|
29
|
-
import {
|
|
29
|
+
import { translatePlural } from '../../../../utils/i18n';
|
|
30
30
|
import GlListboxItem from './listbox_item.vue';
|
|
31
31
|
import GlListboxSearchInput from './listbox_search_input.vue';
|
|
32
32
|
import GlListboxGroup from './listbox_group.vue';
|
|
@@ -343,13 +343,11 @@ export default {
|
|
|
343
343
|
srOnlyResultsLabel: {
|
|
344
344
|
type: Function,
|
|
345
345
|
required: false,
|
|
346
|
-
default: (
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return `${count} result${count > 1 ? 's' : ''}`;
|
|
352
|
-
},
|
|
346
|
+
default: translatePlural(
|
|
347
|
+
'GlCollapsibleListbox.srOnlyResultsLabel',
|
|
348
|
+
'%d result',
|
|
349
|
+
'%d results'
|
|
350
|
+
),
|
|
353
351
|
},
|
|
354
352
|
},
|
|
355
353
|
data() {
|
|
@@ -5,6 +5,7 @@ import isFunction from 'lodash/isFunction';
|
|
|
5
5
|
import range from 'lodash/range';
|
|
6
6
|
import { GlBreakpointInstance, breakpoints } from '../../../utils/breakpoints';
|
|
7
7
|
import { alignOptions, resizeDebounceTime } from '../../../utils/constants';
|
|
8
|
+
import { sprintf, translate } from '../../../utils/i18n';
|
|
8
9
|
import GlIcon from '../icon/icon.vue';
|
|
9
10
|
import GlLink from '../link/link.vue';
|
|
10
11
|
|
|
@@ -145,9 +146,10 @@ export default {
|
|
|
145
146
|
* aria-label getter for numbered page items, defaults to "Go to page <page_number>"
|
|
146
147
|
*/
|
|
147
148
|
labelPage: {
|
|
148
|
-
|
|
149
|
+
// note: `Function` support is for legacy reasons
|
|
150
|
+
type: [Function, String],
|
|
149
151
|
required: false,
|
|
150
|
-
default: (
|
|
152
|
+
default: translate('GlPagination.labelPage', 'Go to page %{page}'),
|
|
151
153
|
},
|
|
152
154
|
/**
|
|
153
155
|
* Controls the component\'s horizontal alignment, value should be one of "left", "center", "right" or "fill"
|
|
@@ -263,10 +265,14 @@ export default {
|
|
|
263
265
|
return this.pageIsDisabled(this.value + 1);
|
|
264
266
|
},
|
|
265
267
|
prevPageAriaLabel() {
|
|
266
|
-
return this.prevPageIsDisabled
|
|
268
|
+
return this.prevPageIsDisabled
|
|
269
|
+
? false
|
|
270
|
+
: this.labelPrevPage || this.labelForPage(this.value - 1);
|
|
267
271
|
},
|
|
268
272
|
nextPageAriaLabel() {
|
|
269
|
-
return this.nextPageIsDisabled
|
|
273
|
+
return this.nextPageIsDisabled
|
|
274
|
+
? false
|
|
275
|
+
: this.labelNextPage || this.labelForPage(this.value + 1);
|
|
270
276
|
},
|
|
271
277
|
prevPageHref() {
|
|
272
278
|
if (this.prevPageIsDisabled) return false;
|
|
@@ -286,6 +292,13 @@ export default {
|
|
|
286
292
|
window.removeEventListener('resize', debounce(this.setBreakpoint, resizeDebounceTime));
|
|
287
293
|
},
|
|
288
294
|
methods: {
|
|
295
|
+
labelForPage(page) {
|
|
296
|
+
if (isFunction(this.labelPage)) {
|
|
297
|
+
return this.labelPage(page);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return sprintf(this.labelPage, { page });
|
|
301
|
+
},
|
|
289
302
|
setBreakpoint() {
|
|
290
303
|
this.breakpoint = GlBreakpointInstance.getBreakpointSize();
|
|
291
304
|
},
|
|
@@ -299,7 +312,7 @@ export default {
|
|
|
299
312
|
},
|
|
300
313
|
getPageItem(page, label = null) {
|
|
301
314
|
const commonAttrs = {
|
|
302
|
-
'aria-label': label || this.
|
|
315
|
+
'aria-label': label || this.labelForPage(page),
|
|
303
316
|
href: '#',
|
|
304
317
|
class: [],
|
|
305
318
|
};
|
package/src/utils/i18n.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import escape from 'lodash/escape';
|
|
1
2
|
import { i18n } from '../config';
|
|
2
3
|
|
|
4
|
+
const defaultPluralHandler = (n, singleValue, pluralValue) => {
|
|
5
|
+
const value = n === 1 ? singleValue : pluralValue;
|
|
6
|
+
|
|
7
|
+
return value.replace(/%d/g, n);
|
|
8
|
+
};
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
* Mark a label as translatable.
|
|
5
12
|
*
|
|
@@ -8,3 +15,48 @@ import { i18n } from '../config';
|
|
|
8
15
|
* @returns {string} The translated label.
|
|
9
16
|
*/
|
|
10
17
|
export const translate = (key, defaultValue) => i18n[key] ?? defaultValue;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Marks a label as translatable and pluralized.
|
|
21
|
+
*
|
|
22
|
+
* @param {*} key Translation key to be leveraged by the consumer to provide a generic translation at configuration time.
|
|
23
|
+
* @param {*} singularValue The singular value to be relied on if the consumer doesn't have translation capabilities.
|
|
24
|
+
* @param {*} pluralValue The plural value to be relied on if the consumer doesn't have translation capabilities.
|
|
25
|
+
* @returns {function} A function that takes a number and returns the pluralized translated label.
|
|
26
|
+
*/
|
|
27
|
+
export const translatePlural = (key, singularValue, pluralValue) => {
|
|
28
|
+
if (i18n[key]) {
|
|
29
|
+
return i18n[key];
|
|
30
|
+
}
|
|
31
|
+
return (x) => defaultPluralHandler(x, singularValue, pluralValue);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Very limited implementation of sprintf supporting only named parameters.
|
|
36
|
+
* Copied from the GitLab repo: https://gitlab.com/gitlab-org/gitlab/-/blob/0dff8b02accb3dccbf6cd31236834c37013aad59/app/assets/javascripts/locale/sprintf.js.
|
|
37
|
+
* @param {string} input - (translated) text with parameters (e.g. '%{num_users} users use us')
|
|
38
|
+
* @param {Object.<string, string|number>} [parameters] - object mapping parameter names to values (e.g. { num_users: 5 })
|
|
39
|
+
* @param {boolean} [escapeParameters=true] - whether parameter values should be escaped (see https://lodash.com/docs/4.17.15#escape)
|
|
40
|
+
* @returns {string} the text with parameters replaces (e.g. '5 users use us')
|
|
41
|
+
* @see https://ruby-doc.org/core-2.3.3/Kernel.html#method-i-sprintf
|
|
42
|
+
* @see https://gitlab.com/gitlab-org/gitlab-foss/issues/37992
|
|
43
|
+
*/
|
|
44
|
+
export function sprintf(input, parameters, escapeParameters = true) {
|
|
45
|
+
let output = input;
|
|
46
|
+
|
|
47
|
+
output = output.replace(/%+/g, '%');
|
|
48
|
+
|
|
49
|
+
if (parameters) {
|
|
50
|
+
const mappedParameters = new Map(Object.entries(parameters));
|
|
51
|
+
|
|
52
|
+
mappedParameters.forEach((key, parameterName) => {
|
|
53
|
+
const parameterValue = mappedParameters.get(parameterName);
|
|
54
|
+
const escapedParameterValue = escapeParameters ? escape(parameterValue) : parameterValue;
|
|
55
|
+
// Pass the param value as a function to ignore special replacement patterns like $` and $'.
|
|
56
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#syntax
|
|
57
|
+
output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), () => escapedParameterValue);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return output;
|
|
62
|
+
}
|
package/translations.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
export default {
|
|
3
3
|
'ClearIconButton.title': 'Clear',
|
|
4
4
|
'GlBreadcrumb.showMoreLabel': 'Show more breadcrumbs',
|
|
5
|
-
'GlCollapsibleListbox.srOnlyResultsLabel':
|
|
5
|
+
'GlCollapsibleListbox.srOnlyResultsLabel': null,
|
|
6
6
|
'GlKeysetPagination.navigationLabel': 'Pagination',
|
|
7
7
|
'GlKeysetPagination.nextText': 'Next',
|
|
8
8
|
'GlKeysetPagination.prevText': 'Previous',
|
|
9
|
+
'GlPagination.labelPage': 'Go to page %{page}',
|
|
9
10
|
'GlSearchBoxByType.clearButtonTitle': 'Clear',
|
|
10
11
|
'GlSearchBoxByType.input.placeholder': 'Search',
|
|
11
12
|
'GlSorting.sortAscending': 'Sort direction: ascending',
|