@gitlab/ui 64.18.3 → 64.20.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 +14 -0
- package/dist/components/base/filtered_search/filtered_search_token.js +1 -1
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +1 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/dist/utility_classes.css +1 -1
- package/dist/utility_classes.css.map +1 -1
- package/package.json +21 -21
- package/src/components/base/filtered_search/filtered_search.stories.js +63 -0
- package/src/components/base/filtered_search/filtered_search_token.spec.js +45 -1
- package/src/components/base/filtered_search/filtered_search_token.vue +3 -0
- package/src/components/base/filtered_search/filtered_search_token_segment.vue +1 -1
- package/src/scss/utilities.scss +8 -0
- package/src/scss/utility-mixins/border.scss +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/ui",
|
|
3
|
-
"version": "64.
|
|
3
|
+
"version": "64.20.0",
|
|
4
4
|
"description": "GitLab UI Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -85,28 +85,28 @@
|
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@arkweid/lefthook": "0.7.7",
|
|
88
|
-
"@babel/core": "^7.22.
|
|
89
|
-
"@babel/preset-env": "^7.22.
|
|
88
|
+
"@babel/core": "^7.22.8",
|
|
89
|
+
"@babel/preset-env": "^7.22.7",
|
|
90
90
|
"@babel/preset-react": "^7.22.5",
|
|
91
91
|
"@gitlab/eslint-plugin": "19.0.0",
|
|
92
92
|
"@gitlab/fonts": "^1.2.0",
|
|
93
93
|
"@gitlab/stylelint-config": "4.1.0",
|
|
94
|
-
"@gitlab/svgs": "3.
|
|
94
|
+
"@gitlab/svgs": "3.54.0",
|
|
95
95
|
"@rollup/plugin-commonjs": "^11.1.0",
|
|
96
96
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
|
97
97
|
"@rollup/plugin-replace": "^2.3.2",
|
|
98
|
-
"@storybook/addon-a11y": "7.0.
|
|
99
|
-
"@storybook/addon-docs": "7.0.
|
|
100
|
-
"@storybook/addon-essentials": "7.0.
|
|
101
|
-
"@storybook/addon-storyshots": "7.0.
|
|
102
|
-
"@storybook/addon-storyshots-puppeteer": "7.0.
|
|
103
|
-
"@storybook/addon-viewport": "7.0.
|
|
104
|
-
"@storybook/builder-webpack5": "7.0.
|
|
105
|
-
"@storybook/theming": "7.0.
|
|
106
|
-
"@storybook/vue": "7.0.
|
|
107
|
-
"@storybook/vue-webpack5": "7.0.
|
|
108
|
-
"@storybook/vue3": "7.0.
|
|
109
|
-
"@storybook/vue3-webpack5": "7.0.
|
|
98
|
+
"@storybook/addon-a11y": "7.0.26",
|
|
99
|
+
"@storybook/addon-docs": "7.0.26",
|
|
100
|
+
"@storybook/addon-essentials": "7.0.26",
|
|
101
|
+
"@storybook/addon-storyshots": "7.0.26",
|
|
102
|
+
"@storybook/addon-storyshots-puppeteer": "7.0.26",
|
|
103
|
+
"@storybook/addon-viewport": "7.0.26",
|
|
104
|
+
"@storybook/builder-webpack5": "7.0.26",
|
|
105
|
+
"@storybook/theming": "7.0.26",
|
|
106
|
+
"@storybook/vue": "7.0.26",
|
|
107
|
+
"@storybook/vue-webpack5": "7.0.26",
|
|
108
|
+
"@storybook/vue3": "7.0.26",
|
|
109
|
+
"@storybook/vue3-webpack5": "7.0.26",
|
|
110
110
|
"@vue/compat": "^3.2.40",
|
|
111
111
|
"@vue/compiler-sfc": "^3.2.40",
|
|
112
112
|
"@vue/test-utils": "1.3.0",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"babel-loader": "^8.0.5",
|
|
119
119
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
120
120
|
"bootstrap": "4.6.2",
|
|
121
|
-
"cypress": "12.
|
|
121
|
+
"cypress": "12.17.0",
|
|
122
122
|
"emoji-regex": "^10.0.0",
|
|
123
123
|
"eslint": "8.44.0",
|
|
124
124
|
"eslint-import-resolver-jest": "3.0.2",
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"glob": "^7.2.0",
|
|
128
128
|
"identity-obj-proxy": "^3.0.0",
|
|
129
129
|
"inquirer-select-directory": "^1.2.0",
|
|
130
|
-
"jest": "^29.
|
|
131
|
-
"jest-circus": "29.
|
|
132
|
-
"jest-environment-jsdom": "29.
|
|
130
|
+
"jest": "^29.6.1",
|
|
131
|
+
"jest-circus": "29.6.1",
|
|
132
|
+
"jest-environment-jsdom": "29.6.1",
|
|
133
133
|
"markdownlint-cli": "^0.29.0",
|
|
134
134
|
"mockdate": "^2.0.5",
|
|
135
135
|
"module-alias": "^2.2.2",
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"sass-loader": "^10.2.0",
|
|
155
155
|
"sass-true": "^6.1.0",
|
|
156
156
|
"start-server-and-test": "^1.10.6",
|
|
157
|
-
"storybook": "7.0.
|
|
157
|
+
"storybook": "7.0.26",
|
|
158
158
|
"storybook-dark-mode": "3.0.0",
|
|
159
159
|
"style-dictionary": "^3.8.0",
|
|
160
160
|
"stylelint": "14.9.1",
|
|
@@ -2,6 +2,7 @@ import GlLoadingIcon from '../loading_icon/loading_icon.vue';
|
|
|
2
2
|
import GlIcon from '../icon/icon.vue';
|
|
3
3
|
import GlToken from '../token/token.vue';
|
|
4
4
|
import GlAvatar from '../avatar/avatar.vue';
|
|
5
|
+
import GlDatepicker from '../datepicker/datepicker.vue';
|
|
5
6
|
import GlDropdownDivider from '../dropdown/dropdown_divider.vue';
|
|
6
7
|
import { setStoryTimeout } from '../../../utils/test_utils';
|
|
7
8
|
import { makeContainer } from '../../../utils/story_decorators/container';
|
|
@@ -284,6 +285,58 @@ const LabelToken = {
|
|
|
284
285
|
`,
|
|
285
286
|
};
|
|
286
287
|
|
|
288
|
+
const DateToken = {
|
|
289
|
+
name: 'DateToken',
|
|
290
|
+
__v_skip: true /* temporary workaround for @vue/compat */,
|
|
291
|
+
components: {
|
|
292
|
+
GlIcon,
|
|
293
|
+
GlDatepicker,
|
|
294
|
+
GlFilteredSearchToken,
|
|
295
|
+
},
|
|
296
|
+
props: ['value', 'active', 'viewOnly'],
|
|
297
|
+
inheritAttrs: false,
|
|
298
|
+
data() {
|
|
299
|
+
return {
|
|
300
|
+
dataSegmentInputAttributes: {
|
|
301
|
+
id: 'this-id',
|
|
302
|
+
placeholder: 'YYYY-MM-DD',
|
|
303
|
+
style: 'padding-left: 23px;',
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
},
|
|
307
|
+
methods: {
|
|
308
|
+
selectValue(value, submitValue) {
|
|
309
|
+
const date = new Date(value);
|
|
310
|
+
const offset = date.getTimezoneOffset();
|
|
311
|
+
const offsetDdate = new Date(date.getTime() - offset * 60 * 1000);
|
|
312
|
+
const dateString = offsetDdate.toISOString().split('T')[0];
|
|
313
|
+
submitValue(dateString);
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
template: `
|
|
317
|
+
<div>
|
|
318
|
+
<gl-filtered-search-token
|
|
319
|
+
:data-segment-input-attributes="dataSegmentInputAttributes"
|
|
320
|
+
v-bind="{ ...this.$props, ...this.$attrs }"
|
|
321
|
+
v-on="$listeners"
|
|
322
|
+
>
|
|
323
|
+
<template #before-data-segment-input="{ submitValue }">
|
|
324
|
+
<gl-icon
|
|
325
|
+
class="gl-text-gray-500"
|
|
326
|
+
name="calendar"
|
|
327
|
+
style="margin-right: -20px; z-index: 1; pointer-events: none;"
|
|
328
|
+
/>
|
|
329
|
+
<gl-datepicker
|
|
330
|
+
class="gl-display-none!"
|
|
331
|
+
target='#this-id'
|
|
332
|
+
:container="null"
|
|
333
|
+
@input="selectValue($event, submitValue)" />
|
|
334
|
+
</template>
|
|
335
|
+
</gl-filtered-search-token>
|
|
336
|
+
</div>
|
|
337
|
+
`,
|
|
338
|
+
};
|
|
339
|
+
|
|
287
340
|
const tokens = [
|
|
288
341
|
{
|
|
289
342
|
type: 'author',
|
|
@@ -308,6 +361,16 @@ const tokens = [
|
|
|
308
361
|
{ icon: 'eye', value: 'false', title: 'No' },
|
|
309
362
|
],
|
|
310
363
|
},
|
|
364
|
+
{
|
|
365
|
+
type: 'date',
|
|
366
|
+
icon: 'history',
|
|
367
|
+
title: 'Created',
|
|
368
|
+
token: DateToken,
|
|
369
|
+
operators: [
|
|
370
|
+
{ value: '<', description: 'before' },
|
|
371
|
+
{ value: '>', description: 'after' },
|
|
372
|
+
],
|
|
373
|
+
},
|
|
311
374
|
];
|
|
312
375
|
|
|
313
376
|
const components = {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import * as Vue from 'vue';
|
|
1
2
|
import { shallowMount, mount } from '@vue/test-utils';
|
|
2
|
-
import { observable, nextTick } from 'vue';
|
|
3
|
+
import { observable, nextTick, h } from 'vue';
|
|
3
4
|
import GlFilteredSearchToken from './filtered_search_token.vue';
|
|
4
5
|
import GlFilteredSearchTokenSegment from './filtered_search_token_segment.vue';
|
|
5
6
|
|
|
7
|
+
const TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON = 'before-data-input-button';
|
|
8
|
+
const TEST_APPLY_VALUE = 'Lorem-ipsum-apply';
|
|
9
|
+
|
|
6
10
|
describe('Filtered search token', () => {
|
|
7
11
|
let wrapper;
|
|
8
12
|
|
|
@@ -39,6 +43,23 @@ describe('Filtered search token', () => {
|
|
|
39
43
|
});
|
|
40
44
|
};
|
|
41
45
|
|
|
46
|
+
const createSlot = (testId, onClick) => {
|
|
47
|
+
// why: Vue3 has a different format for creating VNodes
|
|
48
|
+
return Vue.version.startsWith('3')
|
|
49
|
+
? h('button', {
|
|
50
|
+
'data-testid': testId,
|
|
51
|
+
onClick,
|
|
52
|
+
})
|
|
53
|
+
: h('button', {
|
|
54
|
+
attrs: {
|
|
55
|
+
'data-testid': testId,
|
|
56
|
+
},
|
|
57
|
+
on: {
|
|
58
|
+
click: onClick,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
42
63
|
const mountComponent = (props) => {
|
|
43
64
|
wrapper = mount(GlFilteredSearchToken, {
|
|
44
65
|
provide: {
|
|
@@ -58,6 +79,10 @@ describe('Filtered search token', () => {
|
|
|
58
79
|
},
|
|
59
80
|
},
|
|
60
81
|
propsData: { ...defaultProps, ...props },
|
|
82
|
+
scopedSlots: {
|
|
83
|
+
'before-data-segment-input': ({ submitValue }) =>
|
|
84
|
+
createSlot(TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON, () => submitValue(TEST_APPLY_VALUE)),
|
|
85
|
+
},
|
|
61
86
|
});
|
|
62
87
|
};
|
|
63
88
|
|
|
@@ -282,6 +307,25 @@ describe('Filtered search token', () => {
|
|
|
282
307
|
|
|
283
308
|
expect(value).toEqual(originalValue());
|
|
284
309
|
});
|
|
310
|
+
|
|
311
|
+
it('renders before-data-segment-input scoped slot which can submitValue', async () => {
|
|
312
|
+
mountComponent({ active: true, value: observable({ operator: '=', data: '' }) });
|
|
313
|
+
|
|
314
|
+
// what: Activate data segment
|
|
315
|
+
await wrapper.find('input').trigger('keydown', { key: ' ' });
|
|
316
|
+
|
|
317
|
+
expect(wrapper.emitted()).toEqual({});
|
|
318
|
+
|
|
319
|
+
const beforeDataInputButton = wrapper.find(
|
|
320
|
+
`[data-testid="${TEST_ID_BEFORE_DATA_SEGMENT_INPUT_BUTTON}"]`
|
|
321
|
+
);
|
|
322
|
+
beforeDataInputButton.trigger('click');
|
|
323
|
+
|
|
324
|
+
expect(wrapper.emitted()).toEqual({
|
|
325
|
+
complete: [[]],
|
|
326
|
+
select: [[TEST_APPLY_VALUE]],
|
|
327
|
+
});
|
|
328
|
+
});
|
|
285
329
|
});
|
|
286
330
|
|
|
287
331
|
describe('when multi select', () => {
|
|
@@ -421,6 +421,9 @@ export default {
|
|
|
421
421
|
@previous="activatePreviousOperatorSegment"
|
|
422
422
|
@next="$emit('next')"
|
|
423
423
|
>
|
|
424
|
+
<template #before-input="scope">
|
|
425
|
+
<slot name="before-data-segment-input" v-bind="scope"></slot>
|
|
426
|
+
</template>
|
|
424
427
|
<template #suggestions>
|
|
425
428
|
<!-- @slot The suggestions (implemented with GlFilteredSearchSuggestion). -->
|
|
426
429
|
|
|
@@ -416,6 +416,7 @@ export default {
|
|
|
416
416
|
v-on="viewOnly ? {} : { mousedown: emitIfInactive }"
|
|
417
417
|
>
|
|
418
418
|
<template v-if="active">
|
|
419
|
+
<slot name="before-input" v-bind="{ submitValue: applySuggestion }"></slot>
|
|
419
420
|
<input
|
|
420
421
|
ref="input"
|
|
421
422
|
v-bind="searchInputAttributes"
|
|
@@ -427,7 +428,6 @@ export default {
|
|
|
427
428
|
@keydown="handleInputKeydown"
|
|
428
429
|
@blur="handleBlur"
|
|
429
430
|
/>
|
|
430
|
-
|
|
431
431
|
<portal :key="`operator-${_uid}`" :to="portalName">
|
|
432
432
|
<gl-filtered-search-suggestion-list
|
|
433
433
|
v-if="hasOptionsOrSuggestions"
|
package/src/scss/utilities.scss
CHANGED
|
@@ -1301,6 +1301,14 @@
|
|
|
1301
1301
|
border-color: $blue-700 !important;
|
|
1302
1302
|
}
|
|
1303
1303
|
|
|
1304
|
+
.gl-border-purple-300 {
|
|
1305
|
+
border-color: $purple-300;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
.gl-border-purple-300\! {
|
|
1309
|
+
border-color: $purple-300 !important;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1304
1312
|
.gl-border-purple-700 {
|
|
1305
1313
|
border-color: $purple-700;
|
|
1306
1314
|
}
|