@gitlab/ui 74.5.0 → 74.7.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.
@@ -1,4 +1,4 @@
1
- import { userEvent } from '@storybook/testing-library';
1
+ import { userEvent } from '@storybook/test';
2
2
 
3
3
  const triggerBlurEvent = async () => userEvent.pointer([{
4
4
  keys: '[MouseLeft]',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "74.5.0",
3
+ "version": "74.7.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -61,7 +61,7 @@
61
61
  "markdownlint": "markdownlint '**/*.md' --ignore node_modules --ignore CHANGELOG.md",
62
62
  "markdownlint:fix": "yarn markdownlint --fix",
63
63
  "lint": "run-p prettier eslint stylelint markdownlint",
64
- "lint:fix": "run-s prettier:fix eslint:fix stylelint:fix markdownlint:fix",
64
+ "lint:fix": "run-s eslint:fix prettier:fix stylelint:fix markdownlint:fix",
65
65
  "generate:component": "plop",
66
66
  "translations:collect": "make translations.json",
67
67
  "tailwind-config-viewer": "tailwind-config-viewer -o"
@@ -106,21 +106,19 @@
106
106
  "@rollup/plugin-commonjs": "^11.1.0",
107
107
  "@rollup/plugin-node-resolve": "^7.1.3",
108
108
  "@rollup/plugin-replace": "^2.3.2",
109
- "@storybook/addon-a11y": "7.6.13",
110
- "@storybook/addon-docs": "7.6.13",
111
- "@storybook/addon-essentials": "7.6.13",
112
- "@storybook/addon-interactions": "7.6.13",
113
- "@storybook/addon-viewport": "7.6.13",
114
- "@storybook/builder-webpack5": "7.6.13",
115
- "@storybook/jest": "0.2.3",
109
+ "@storybook/addon-a11y": "7.6.14",
110
+ "@storybook/addon-docs": "7.6.14",
111
+ "@storybook/addon-essentials": "7.6.14",
112
+ "@storybook/addon-interactions": "7.6.14",
113
+ "@storybook/addon-viewport": "7.6.14",
114
+ "@storybook/builder-webpack5": "7.6.14",
115
+ "@storybook/test": "7.6.14",
116
116
  "@storybook/test-runner": "0.16.0",
117
- "@storybook/testing-library": "0.2.2",
118
- "@storybook/theming": "7.6.13",
119
- "@storybook/vue": "7.6.13",
120
- "@storybook/vue-webpack5": "7.6.13",
121
- "@storybook/vue3": "7.6.13",
122
- "@storybook/vue3-webpack5": "7.6.13",
123
- "@types/jest": "^29.5.11",
117
+ "@storybook/theming": "7.6.14",
118
+ "@storybook/vue": "7.6.14",
119
+ "@storybook/vue-webpack5": "7.6.14",
120
+ "@storybook/vue3": "7.6.14",
121
+ "@storybook/vue3-webpack5": "7.6.14",
124
122
  "@types/jest-image-snapshot": "^6.4.0",
125
123
  "@vue/compat": "^3.2.40",
126
124
  "@vue/compiler-sfc": "^3.2.40",
@@ -172,7 +170,7 @@
172
170
  "sass-loader": "^10.2.0",
173
171
  "sass-true": "^6.1.0",
174
172
  "start-server-and-test": "^1.10.6",
175
- "storybook": "7.6.13",
173
+ "storybook": "7.6.14",
176
174
  "storybook-dark-mode": "3.0.3",
177
175
  "style-dictionary": "^3.8.0",
178
176
  "stylelint": "15.10.2",
@@ -1,6 +1,5 @@
1
1
  import last from 'lodash/last';
2
- import { userEvent, within, waitFor } from '@storybook/testing-library';
3
- import { expect } from '@storybook/jest';
2
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
4
3
  import GlLoadingIcon from '../loading_icon/loading_icon.vue';
5
4
  import GlIcon from '../icon/icon.vue';
6
5
  import GlToken from '../token/token.vue';
@@ -1,4 +1,4 @@
1
- import { userEvent, within } from '@storybook/testing-library';
1
+ import { userEvent, within } from '@storybook/test';
2
2
  import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list.vue';
3
3
  import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
4
4
  import { provide } from './common_story_options';
@@ -1,5 +1,4 @@
1
- import { userEvent, within, waitFor } from '@storybook/testing-library';
2
- import { expect } from '@storybook/jest';
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
3
2
  import { makeContainer } from '../../../../utils/story_decorators/container';
4
3
  import { stringTokenList, labelText, objectTokenList, actionsList } from './constants';
5
4
  import readme from './form_combobox.md';
@@ -345,6 +345,22 @@ describe('GlFormFields', () => {
345
345
  });
346
346
  }
347
347
  );
348
+
349
+ describe('when there is a server validation message', () => {
350
+ beforeEach(async () => {
351
+ await submitForm();
352
+
353
+ wrapper.setProps({
354
+ serverValidations: { username: 'Username has already been taken.' },
355
+ });
356
+ });
357
+
358
+ it('renders error message', () => {
359
+ expect(
360
+ findFormGroupFromLabel(TEST_FIELDS.username.label).attributes('invalid-feedback')
361
+ ).toBe('Username has already been taken.');
362
+ });
363
+ });
348
364
  });
349
365
 
350
366
  describe('with scoped slot', () => {
@@ -3,6 +3,7 @@ import omit from 'lodash/omit';
3
3
  import GlModal from '../../modal/modal.vue';
4
4
  import GlButton from '../../button/button.vue';
5
5
  import GlListbox from '../../new_dropdowns/listbox/listbox.vue';
6
+ import { setStoryTimeout } from '../../../../utils/test_utils';
6
7
  import GlFormFields from './form_fields.vue';
7
8
  import readme from './form_fields.md';
8
9
  import { required } from './validators';
@@ -49,6 +50,8 @@ const Template = () => ({
49
50
  },
50
51
  formValues: {},
51
52
  testFormId: uniqueId('form_fields_story_'),
53
+ serverValidations: {},
54
+ loading: false,
52
55
  };
53
56
  },
54
57
  computed: {
@@ -61,7 +64,27 @@ const Template = () => ({
61
64
  },
62
65
  },
63
66
  methods: {
64
- onSubmit() {
67
+ onInputField({ name }) {
68
+ this.$delete(this.serverValidations, name);
69
+ },
70
+ async onSubmit() {
71
+ this.loading = true;
72
+
73
+ // Simulate waiting for API request to resolve
74
+ await new Promise((resolve) => {
75
+ setStoryTimeout(resolve, 1000);
76
+ });
77
+
78
+ this.loading = false;
79
+
80
+ // Manually checking field and validating for this example.
81
+ // In practice this error message would come from the API response.
82
+ if (this.formValues.USERNAME === 'FOO') {
83
+ this.$set(this.serverValidations, 'USERNAME', 'Username has already been taken.');
84
+
85
+ return;
86
+ }
87
+
65
88
  this.$refs.modal.show();
66
89
  },
67
90
  },
@@ -69,7 +92,7 @@ const Template = () => ({
69
92
  <div>
70
93
  <h3>Fields</h3>
71
94
  <form :id="testFormId" @submit.prevent>
72
- <gl-form-fields :fields="fields" v-model="formValues" :form-id="testFormId" @submit="onSubmit">
95
+ <gl-form-fields :fields="fields" v-model="formValues" :form-id="testFormId" :server-validations="serverValidations" @input-field="onInputField" @submit="onSubmit">
73
96
  <template #input(custom)="{ id, value, input, blur }">
74
97
  <button :id="id" @click="input(value + 1)" @blur="blur" type="button">{{value}}</button>
75
98
  </template>
@@ -77,7 +100,7 @@ const Template = () => ({
77
100
  <gl-listbox :id="id" :items="$options.ITEMS" :selected="value" @select="input" @hidden="blur" />
78
101
  </template>
79
102
  </gl-form-fields>
80
- <gl-button type="submit" category="primary">Submit</gl-button>
103
+ <gl-button type="submit" category="primary" :loading="loading">Submit</gl-button>
81
104
  </form>
82
105
  <gl-modal ref="modal" modal-id="submission-modal" title="Form submission"><pre>{{ valuesJSON }}</pre></gl-modal>
83
106
  </div>
@@ -51,6 +51,16 @@ export default {
51
51
  type: String,
52
52
  required: true,
53
53
  },
54
+ /**
55
+ * Validation errors from the server. Generally passed to the component after making an API call.
56
+ */
57
+ serverValidations: {
58
+ type: Object,
59
+ required: false,
60
+ default() {
61
+ return {};
62
+ },
63
+ },
54
64
  },
55
65
  data() {
56
66
  return {
@@ -64,7 +74,8 @@ export default {
64
74
  },
65
75
  fieldValidationProps() {
66
76
  return mapValues(this.fields, (_, fieldName) => {
67
- const invalidFeedback = this.fieldValidations[fieldName] || '';
77
+ const invalidFeedback =
78
+ this.serverValidations[fieldName] || this.fieldValidations[fieldName] || '';
68
79
 
69
80
  return {
70
81
  invalidFeedback,
@@ -1,5 +1,4 @@
1
- import { userEvent, within, waitFor } from '@storybook/testing-library';
2
- import { expect } from '@storybook/jest';
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
3
2
  import { makeContainer } from '../../../utils/story_decorators/container';
4
3
  import GlSorting from './sorting.vue';
5
4
  import readme from './sorting.md';
@@ -1,5 +1,4 @@
1
- import { userEvent, within, waitFor } from '@storybook/testing-library';
2
- import { expect } from '@storybook/jest';
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
3
2
  import Vue from 'vue';
4
3
  import GlButton from '../button/button.vue';
5
4
  import GlToast from './toast';
@@ -1,5 +1,4 @@
1
- import { userEvent, within, waitFor } from '@storybook/testing-library';
2
- import { expect } from '@storybook/jest';
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
3
2
  import readme from './token_selector.md';
4
3
  import GlTokenSelector from './token_selector.vue';
5
4
 
@@ -1,5 +1,4 @@
1
- import { userEvent, within, waitFor } from '@storybook/testing-library';
2
- import { expect } from '@storybook/jest';
1
+ import { userEvent, within, waitFor, expect } from '@storybook/test';
3
2
  import { GlTooltipDirective } from '../../../directives/tooltip';
4
3
  import GlButton from '../button/button.vue';
5
4
  import GlTooltip from './tooltip.vue';
@@ -481,6 +481,14 @@ $gl-animate-skeleton-loader-max-width: 64 * $grid-size;
481
481
  background-color: $purple-50 !important
482
482
  }
483
483
 
484
+ .gl-bg-purple-500 {
485
+ background-color: $purple-500
486
+ }
487
+
488
+ .gl-bg-purple-500\! {
489
+ background-color: $purple-500 !important
490
+ }
491
+
484
492
  .gl-bg-purple-800 {
485
493
  background-color: $purple-800
486
494
  }
@@ -1388,6 +1396,14 @@ $gl-animate-skeleton-loader-max-width: 64 * $grid-size;
1388
1396
  border-color: $purple-300 !important;
1389
1397
  }
1390
1398
 
1399
+ .gl-border-purple-500 {
1400
+ border-color: $purple-500;
1401
+ }
1402
+
1403
+ .gl-border-purple-500\! {
1404
+ border-color: $purple-500 !important;
1405
+ }
1406
+
1391
1407
  .gl-border-purple-700 {
1392
1408
  border-color: $purple-700;
1393
1409
  }
@@ -2816,6 +2832,14 @@ $gl-animate-skeleton-loader-max-width: 64 * $grid-size;
2816
2832
  color: $red-900 !important;
2817
2833
  }
2818
2834
 
2835
+ .gl-text-purple-500 {
2836
+ color: $purple-500;
2837
+ }
2838
+
2839
+ .gl-text-purple-500\! {
2840
+ color: $purple-500 !important;
2841
+ }
2842
+
2819
2843
  .gl-text-purple-600 {
2820
2844
  color: $purple-600;
2821
2845
  }
@@ -150,6 +150,10 @@
150
150
  background-color: $purple-50;
151
151
  }
152
152
 
153
+ @mixin gl-bg-purple-500 {
154
+ background-color: $purple-500;
155
+ }
156
+
153
157
  @mixin gl-bg-purple-800 {
154
158
  background-color: $purple-800;
155
159
  }
@@ -183,6 +183,10 @@
183
183
  border-color: $purple-300;
184
184
  }
185
185
 
186
+ @mixin gl-border-purple-500 {
187
+ border-color: $purple-500;
188
+ }
189
+
186
190
  @mixin gl-border-purple-700 {
187
191
  border-color: $purple-700;
188
192
  }
@@ -193,6 +193,10 @@
193
193
  color: $red-900;
194
194
  }
195
195
 
196
+ @mixin gl-text-purple-500 {
197
+ color: $purple-500;
198
+ }
199
+
196
200
  @mixin gl-text-purple-600 {
197
201
  color: $purple-600;
198
202
  }
@@ -1,4 +1,4 @@
1
- import { userEvent } from '@storybook/testing-library';
1
+ import { userEvent } from '@storybook/test';
2
2
 
3
3
  export const triggerBlurEvent = async () =>
4
4
  userEvent.pointer([