@gitlab/ui 38.8.2 → 38.9.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/base/form/form_textarea/form_textarea.js +62 -2
  3. package/dist/index.css +1 -1
  4. package/dist/index.css.map +1 -1
  5. package/dist/utils/constants.js +7 -2
  6. package/package.json +1 -1
  7. package/src/components/base/accordion/accordion.stories.js +2 -4
  8. package/src/components/base/accordion/accordion_item.stories.js +2 -4
  9. package/src/components/base/alert/alert.stories.js +2 -4
  10. package/src/components/base/avatar/avatar.stories.js +3 -9
  11. package/src/components/base/avatar_labeled/avatar_labeled.stories.js +6 -12
  12. package/src/components/base/avatar_link/avatar_link.stories.js +2 -6
  13. package/src/components/base/avatars_inline/avatars_inline.stories.js +2 -4
  14. package/src/components/base/badge/badge.scss +10 -0
  15. package/src/components/base/badge/badge.stories.js +3 -9
  16. package/src/components/base/banner/banner.stories.js +1 -3
  17. package/src/components/base/broadcast_message/broadcast_message.stories.js +4 -8
  18. package/src/components/base/button/button.stories.js +8 -16
  19. package/src/components/base/datepicker/datepicker.stories.js +2 -2
  20. package/src/components/base/daterange_picker/daterange_picker.stories.js +2 -6
  21. package/src/components/base/dropdown/dropdown.stories.js +4 -12
  22. package/src/components/base/dropdown/dropdown_item.stories.js +2 -6
  23. package/src/components/base/form/form_group/form_group.stories.js +1 -1
  24. package/src/components/base/form/form_input/form_input.stories.js +1 -3
  25. package/src/components/base/form/form_input_group/form_input_group.stories.js +4 -12
  26. package/src/components/base/form/form_radio/form_radio.stories.js +1 -3
  27. package/src/components/base/form/form_select/form_select.stories.js +4 -8
  28. package/src/components/base/form/form_textarea/form_textarea.spec.js +115 -8
  29. package/src/components/base/form/form_textarea/form_textarea.stories.js +21 -0
  30. package/src/components/base/form/form_textarea/form_textarea.vue +73 -8
  31. package/src/components/base/icon/icon.stories.js +4 -8
  32. package/src/components/base/label/label.stories.js +2 -6
  33. package/src/components/base/link/link.stories.js +2 -4
  34. package/src/components/base/loading_icon/loading_icon.stories.js +4 -8
  35. package/src/components/base/modal/modal.stories.js +16 -32
  36. package/src/components/base/path/path.stories.js +2 -6
  37. package/src/components/base/popover/popover.stories.js +2 -4
  38. package/src/components/base/progress_bar/progress_bar.stories.js +2 -4
  39. package/src/components/base/search_box_by_click/search_box_by_click.stories.js +1 -3
  40. package/src/components/base/segmented_control/segmented_control.stories.js +1 -3
  41. package/src/components/base/skeleton_loading/skeleton_loading.stories.js +2 -4
  42. package/src/components/base/table/table.stories.js +2 -4
  43. package/src/components/base/toggle/toggle.stories.js +4 -10
  44. package/src/components/base/token/token.stories.js +2 -4
  45. package/src/components/base/token_selector/token_selector.stories.js +2 -4
  46. package/src/components/charts/single_stat/single_stat.stories.js +1 -3
  47. package/src/directives/resize_observer/resize_observer.stories.js +1 -3
  48. package/src/utils/constants.js +6 -0
@@ -32,7 +32,8 @@ const badgeVariantOptions = {
32
32
  info: 'info',
33
33
  success: 'success',
34
34
  warning: 'warning',
35
- danger: 'danger'
35
+ danger: 'danger',
36
+ tier: 'tier'
36
37
  };
37
38
  const variantCssColorMap = {
38
39
  muted: 'gl-text-gray-500',
@@ -250,5 +251,9 @@ const loadingIconSizes = {
250
251
  'lg (32x32)': 'lg',
251
252
  'xl (64x64)': 'xl'
252
253
  };
254
+ const textareaCountOptions = {
255
+ max: 'max',
256
+ recommended: 'recommended'
257
+ };
253
258
 
254
- export { COMMA, alertVariantIconMap, alertVariantOptions, alignOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, buttonCategoryOptions, buttonSizeOptions, buttonSizeOptionsMap, buttonVariantOptions, colorThemes, columnOptions, defaultDateFormat, drawerVariants, dropdownVariantOptions, focusableTags, formInputSizes, formStateOptions, glThemes, iconSizeOptions, keyboard, labelColorOptions, labelSizeOptions, loadingIconSizes, maxZIndex, modalButtonDefaults, modalSizeOptions, popoverPlacements, resizeDebounceTime, sizeOptions, sizeOptionsWithNoDefault, tabsButtonDefaults, targetOptions, toggleLabelPosition, tokenVariants, tooltipActionEvents, tooltipDelay, tooltipPlacements, triggerVariantOptions, truncateOptions, variantCssColorMap, variantOptions, variantOptionsWithNoDefault, viewModeOptions };
259
+ export { COMMA, alertVariantIconMap, alertVariantOptions, alignOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, buttonCategoryOptions, buttonSizeOptions, buttonSizeOptionsMap, buttonVariantOptions, colorThemes, columnOptions, defaultDateFormat, drawerVariants, dropdownVariantOptions, focusableTags, formInputSizes, formStateOptions, glThemes, iconSizeOptions, keyboard, labelColorOptions, labelSizeOptions, loadingIconSizes, maxZIndex, modalButtonDefaults, modalSizeOptions, popoverPlacements, resizeDebounceTime, sizeOptions, sizeOptionsWithNoDefault, tabsButtonDefaults, targetOptions, textareaCountOptions, toggleLabelPosition, tokenVariants, tooltipActionEvents, tooltipDelay, tooltipPlacements, triggerVariantOptions, truncateOptions, variantCssColorMap, variantOptions, variantOptionsWithNoDefault, viewModeOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "38.8.2",
3
+ "version": "38.9.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -59,10 +59,8 @@ export default {
59
59
  },
60
60
  argTypes: {
61
61
  headerLevel: {
62
- control: {
63
- type: 'select',
64
- options: [1, 2, 3, 4, 5, 6],
65
- },
62
+ options: [1, 2, 3, 4, 5, 6],
63
+ control: 'select',
66
64
  },
67
65
  ...disableControls(['autoCollapse']),
68
66
  },
@@ -54,10 +54,8 @@ export default {
54
54
  },
55
55
  argTypes: {
56
56
  headerLevel: {
57
- control: {
58
- type: 'select',
59
- options: [1, 2, 3, 4, 5, 6],
60
- },
57
+ options: [1, 2, 3, 4, 5, 6],
58
+ control: 'select',
61
59
  },
62
60
  },
63
61
  };
@@ -140,10 +140,8 @@ export default {
140
140
  },
141
141
  argTypes: {
142
142
  variant: {
143
- control: {
144
- type: 'select',
145
- options: alertVariantOptions,
146
- },
143
+ options: alertVariantOptions,
144
+ control: 'select',
147
145
  },
148
146
  },
149
147
  };
@@ -102,21 +102,15 @@ export default {
102
102
  argTypes: {
103
103
  size: {
104
104
  options: avatarSizeOptions,
105
- control: {
106
- type: 'select',
107
- },
105
+ control: 'select',
108
106
  },
109
107
  shape: {
110
108
  options: avatarShapeOptions,
111
- control: {
112
- type: 'select',
113
- },
109
+ control: 'select',
114
110
  },
115
111
  placement: {
116
112
  options: tooltipPlacements,
117
- control: {
118
- type: 'select',
119
- },
113
+ control: 'select',
120
114
  },
121
115
  },
122
116
  };
@@ -60,10 +60,8 @@ export const WithTooltip = (args, { argTypes }) => ({
60
60
  WithTooltip.args = { ...generateProps(), ...generateTooltipProps() };
61
61
  WithTooltip.argTypes = {
62
62
  placement: {
63
- control: {
64
- type: 'select',
65
- options: tooltipPlacements,
66
- },
63
+ options: tooltipPlacements,
64
+ control: 'select',
67
65
  },
68
66
  };
69
67
 
@@ -104,16 +102,12 @@ export default {
104
102
  },
105
103
  argTypes: {
106
104
  size: {
107
- control: {
108
- type: 'select',
109
- options: avatarSizeOptions,
110
- },
105
+ options: avatarSizeOptions,
106
+ control: 'select',
111
107
  },
112
108
  shape: {
113
- control: {
114
- type: 'select',
115
- options: avatarShapeOptions,
116
- },
109
+ options: avatarShapeOptions,
110
+ control: 'select',
117
111
  },
118
112
  },
119
113
  };
@@ -76,15 +76,11 @@ export default {
76
76
  argTypes: {
77
77
  shape: {
78
78
  options: avatarShapeOptions,
79
- control: {
80
- type: 'select',
81
- },
79
+ control: 'select',
82
80
  },
83
81
  size: {
84
82
  options: avatarSizeOptions,
85
- control: {
86
- type: 'select',
87
- },
83
+ control: 'select',
88
84
  },
89
85
  },
90
86
  };
@@ -74,10 +74,8 @@ export default {
74
74
  },
75
75
  argTypes: {
76
76
  avatarSize: {
77
- control: {
78
- type: 'select',
79
- options: avatarsInlineSizeOptions,
80
- },
77
+ options: avatarsInlineSizeOptions,
78
+ control: 'select',
81
79
  },
82
80
  },
83
81
  };
@@ -135,6 +135,16 @@
135
135
  $active-bg: $red-200
136
136
  );
137
137
 
138
+ @include gl-badge-variant(
139
+ $variant: tier,
140
+ $color: $purple-700,
141
+ $bg: $purple-100,
142
+ $hover-color: $purple-800,
143
+ $border-color: $purple-200,
144
+ $active-color: $purple-900,
145
+ $active-bg: $purple-200
146
+ );
147
+
138
148
  // overriding Bootstap's `.btn .badge {top: -1px}` as the badge is not vertically centered otherwise
139
149
  .gl-button .gl-badge {
140
150
  top: 0;
@@ -154,21 +154,15 @@ export default {
154
154
  argTypes: {
155
155
  variant: {
156
156
  options: Object.keys(badgeVariantOptions),
157
- control: {
158
- type: 'select',
159
- },
157
+ control: 'select',
160
158
  },
161
159
  size: {
162
160
  options: Object.keys(badgeSizeOptions),
163
- control: {
164
- type: 'select',
165
- },
161
+ control: 'select',
166
162
  },
167
163
  icon: {
168
164
  options: ['', ...iconSpriteInfo.icons],
169
- control: {
170
- type: 'select',
171
- },
165
+ control: 'select',
172
166
  },
173
167
  },
174
168
  };
@@ -99,9 +99,7 @@ export default {
99
99
  argTypes: {
100
100
  variant: {
101
101
  options: bannerVariants,
102
- control: {
103
- type: 'select',
104
- },
102
+ control: 'select',
105
103
  },
106
104
  svgPath: {
107
105
  control: 'text',
@@ -78,16 +78,12 @@ export default {
78
78
  },
79
79
  argTypes: {
80
80
  iconName: {
81
- control: {
82
- type: 'select',
83
- options: iconSpriteInfo.icons,
84
- },
81
+ options: iconSpriteInfo.icons,
82
+ control: 'select',
85
83
  },
86
84
  theme: {
87
- control: {
88
- type: 'select',
89
- options: Object.keys(colorThemes),
90
- },
85
+ options: Object.keys(colorThemes),
86
+ control: 'select',
91
87
  },
92
88
  },
93
89
  };
@@ -511,28 +511,20 @@ export default {
511
511
  },
512
512
  argTypes: {
513
513
  category: {
514
- control: {
515
- type: 'select',
516
- options: buttonCategoryOptions,
517
- },
514
+ options: buttonCategoryOptions,
515
+ control: 'select',
518
516
  },
519
517
  variant: {
520
- control: {
521
- type: 'select',
522
- options: buttonVariantOptions,
523
- },
518
+ options: buttonVariantOptions,
519
+ control: 'select',
524
520
  },
525
521
  size: {
526
- control: {
527
- type: 'select',
528
- options: buttonSizeOptions,
529
- },
522
+ options: buttonSizeOptions,
523
+ control: 'select',
530
524
  },
531
525
  target: {
532
- control: {
533
- type: 'select',
534
- options: targetOptions,
535
- },
526
+ options: targetOptions,
527
+ control: 'select',
536
528
  },
537
529
  },
538
530
  };
@@ -101,10 +101,10 @@ export default {
101
101
  'inputName',
102
102
  ]),
103
103
  minDate: {
104
- control: { type: 'date' },
104
+ control: 'date',
105
105
  },
106
106
  maxDate: {
107
- control: { type: 'date' },
107
+ control: 'date',
108
108
  },
109
109
  },
110
110
  };
@@ -132,14 +132,10 @@ export default {
132
132
  'defaultEndDate',
133
133
  ]),
134
134
  defaultMinDate: {
135
- control: {
136
- type: 'date',
137
- },
135
+ control: 'date',
138
136
  },
139
137
  defaultMaxDate: {
140
- control: {
141
- type: 'date',
142
- },
138
+ control: 'date',
143
139
  },
144
140
  },
145
141
  };
@@ -535,27 +535,19 @@ export default {
535
535
  argTypes: {
536
536
  category: {
537
537
  options: Object.keys(buttonCategoryOptions),
538
- control: {
539
- type: 'select',
540
- },
538
+ control: 'select',
541
539
  },
542
540
  variant: {
543
541
  options: Object.keys(dropdownVariantOptions),
544
- control: {
545
- type: 'select',
546
- },
542
+ control: 'select',
547
543
  },
548
544
  size: {
549
545
  options: Object.keys(buttonSizeOptions),
550
- control: {
551
- type: 'select',
552
- },
546
+ control: 'select',
553
547
  },
554
548
  icon: {
555
549
  options: iconSpriteInfo.icons,
556
- control: {
557
- type: 'select',
558
- },
550
+ control: 'select',
559
551
  },
560
552
  },
561
553
  };
@@ -100,15 +100,11 @@ export default {
100
100
  argTypes: {
101
101
  iconColor: {
102
102
  options: Object.keys(variantCssColorMap),
103
- control: {
104
- type: 'select',
105
- },
103
+ control: 'select',
106
104
  },
107
105
  iconName: {
108
106
  options: iconSpriteInfo.icons,
109
- control: {
110
- type: 'select',
111
- },
107
+ control: 'select',
112
108
  },
113
109
  },
114
110
  };
@@ -119,7 +119,7 @@ export default {
119
119
  argTypes: {
120
120
  ...disableControls(['labelClass']),
121
121
  label: {
122
- control: { type: 'text' },
122
+ control: 'text',
123
123
  },
124
124
  },
125
125
  };
@@ -72,9 +72,7 @@ export default {
72
72
  argTypes: {
73
73
  size: {
74
74
  options: formInputSizes,
75
- control: {
76
- type: 'select',
77
- },
75
+ control: 'select',
78
76
  },
79
77
  },
80
78
  };
@@ -72,24 +72,16 @@ export default {
72
72
  argTypes: {
73
73
  ...disableControls(['value']),
74
74
  prepend: {
75
- control: {
76
- type: 'text',
77
- },
75
+ control: 'text',
78
76
  },
79
77
  append: {
80
- control: {
81
- type: 'text',
82
- },
78
+ control: 'text',
83
79
  },
84
80
  inputClass: {
85
- control: {
86
- type: 'text',
87
- },
81
+ control: 'text',
88
82
  },
89
83
  label: {
90
- control: {
91
- type: 'text',
92
- },
84
+ control: 'text',
93
85
  },
94
86
  },
95
87
  };
@@ -52,9 +52,7 @@ export default {
52
52
  argTypes: {
53
53
  checked: {
54
54
  options: defaultOptions.map(({ value }) => value),
55
- control: {
56
- type: 'select',
57
- },
55
+ control: 'select',
58
56
  },
59
57
  },
60
58
  };
@@ -91,16 +91,12 @@ export default {
91
91
  },
92
92
  argTypes: {
93
93
  size: {
94
- control: {
95
- type: 'select',
96
- options: sizeOptions,
97
- },
94
+ options: sizeOptions,
95
+ control: 'select',
98
96
  },
99
97
  state: {
100
- control: {
101
- type: 'select',
102
- options: formStateOptions,
103
- },
98
+ options: formStateOptions,
99
+ control: 'select',
104
100
  },
105
101
  input: {
106
102
  description: 'Emitted with the select value changes.',
@@ -1,4 +1,5 @@
1
1
  import { mount } from '@vue/test-utils';
2
+ import { textareaCountOptions } from '../../../../utils/constants';
2
3
  import GlFormTextarea from './form_textarea.vue';
3
4
 
4
5
  const modelEvent = GlFormTextarea.model.event;
@@ -6,11 +7,13 @@ const newValue = 'foo';
6
7
 
7
8
  describe('GlFormTextArea', () => {
8
9
  let wrapper;
10
+ let textarea;
9
11
 
10
12
  const createComponent = (propsData = {}) => {
11
13
  wrapper = mount(GlFormTextarea, {
12
14
  propsData,
13
15
  });
16
+ textarea = wrapper.find('textarea');
14
17
  };
15
18
 
16
19
  describe('v-model', () => {
@@ -20,7 +23,7 @@ describe('GlFormTextArea', () => {
20
23
  });
21
24
 
22
25
  it(`sets the textarea's value`, () => {
23
- expect(wrapper.element.value).toBe('initial');
26
+ expect(textarea.element.value).toBe('initial');
24
27
  });
25
28
 
26
29
  describe('when the value prop changes', () => {
@@ -30,7 +33,7 @@ describe('GlFormTextArea', () => {
30
33
  });
31
34
 
32
35
  it(`updates the textarea's value`, () => {
33
- expect(wrapper.element.value).toBe(newValue);
36
+ expect(textarea.element.value).toBe(newValue);
34
37
  });
35
38
  });
36
39
  });
@@ -39,7 +42,7 @@ describe('GlFormTextArea', () => {
39
42
  beforeEach(() => {
40
43
  createComponent();
41
44
 
42
- wrapper.setValue(newValue);
45
+ textarea.setValue(newValue);
43
46
  });
44
47
 
45
48
  it('synchronously emits update event', () => {
@@ -59,7 +62,7 @@ describe('GlFormTextArea', () => {
59
62
 
60
63
  createComponent({ debounce });
61
64
 
62
- wrapper.setValue(newValue);
65
+ textarea.setValue(newValue);
63
66
  });
64
67
 
65
68
  it('synchronously emits an update event', () => {
@@ -82,7 +85,7 @@ describe('GlFormTextArea', () => {
82
85
  beforeEach(() => {
83
86
  createComponent({ lazy: true });
84
87
 
85
- wrapper.setValue(newValue);
88
+ textarea.setValue(newValue);
86
89
  });
87
90
 
88
91
  it('synchronously emits an update event', () => {
@@ -92,7 +95,7 @@ describe('GlFormTextArea', () => {
92
95
  it.each(['change', 'blur'])('updates model after %s event', (event) => {
93
96
  expect(wrapper.emitted(modelEvent)).toBe(undefined);
94
97
 
95
- wrapper.trigger(event);
98
+ textarea.trigger(event);
96
99
 
97
100
  expect(wrapper.emitted(modelEvent)).toEqual([[newValue]]);
98
101
  });
@@ -102,7 +105,7 @@ describe('GlFormTextArea', () => {
102
105
  it('should be false by default', () => {
103
106
  createComponent({});
104
107
 
105
- wrapper.trigger('keyup.enter', {
108
+ textarea.trigger('keyup.enter', {
106
109
  metaKey: true,
107
110
  });
108
111
 
@@ -112,11 +115,115 @@ describe('GlFormTextArea', () => {
112
115
  it('should emit submit when cmd+enter is pressed', async () => {
113
116
  createComponent({ submitOnEnter: true });
114
117
 
115
- wrapper.trigger('keyup.enter', {
118
+ textarea.trigger('keyup.enter', {
116
119
  metaKey: true,
117
120
  });
118
121
 
119
122
  expect(wrapper.emitted().submit).toEqual([[]]);
120
123
  });
121
124
  });
125
+
126
+ describe('count', () => {
127
+ it('should be 0 by default', () => {
128
+ createComponent({
129
+ characterCountText: '%{count} characters left',
130
+ characterCountOverLimitText: '%{count} characters over limit',
131
+ });
132
+
133
+ expect(wrapper.text()).not.toContain('characters left');
134
+ expect(wrapper.text()).not.toContain('characters over limit');
135
+ });
136
+
137
+ it('should display the remaining characters when a count is provided', () => {
138
+ createComponent({
139
+ count: 400,
140
+ characterCountText: '%{count} characters left',
141
+ characterCountOverLimitText: '%{count} characters over limit',
142
+ });
143
+
144
+ expect(wrapper.text()).toContain('400 characters left');
145
+ });
146
+
147
+ it('should display the difference between the limit and the length of the value', () => {
148
+ const value = 'hello';
149
+
150
+ createComponent({
151
+ value,
152
+ count: 400,
153
+ characterCountText: '%{count} characters left',
154
+ characterCountOverLimitText: '%{count} characters over limit',
155
+ });
156
+
157
+ const { length } = value;
158
+
159
+ expect(wrapper.text()).toContain(`${400 - length} characters left`);
160
+ });
161
+
162
+ it('should display the over limit text once over the limit', () => {
163
+ const value = 'hello';
164
+ const count = 4;
165
+
166
+ createComponent({
167
+ value,
168
+ count,
169
+ characterCountText: '%{count} characters left',
170
+ characterCountOverLimitText: '%{count} characters over limit',
171
+ });
172
+
173
+ const diff = Math.abs(count - value.length);
174
+
175
+ expect(wrapper.text()).toContain(`${diff} characters over limit`);
176
+ });
177
+
178
+ describe('max', () => {
179
+ it('should display the text as grey when up to the limit', () => {
180
+ const value = 'hello';
181
+ const count = 5;
182
+
183
+ createComponent({
184
+ value,
185
+ count,
186
+ characterCountText: '%{count} characters left',
187
+ characterCountOverLimitText: '%{count} characters over limit',
188
+ });
189
+
190
+ const small = wrapper.find('small');
191
+
192
+ expect(small.classes()).toContain('gl-text-gray-500');
193
+ });
194
+ it('should display the text as danger when over the limit', () => {
195
+ const value = 'hello';
196
+ const count = 4;
197
+
198
+ createComponent({
199
+ value,
200
+ count,
201
+ characterCountText: '%{count} characters left',
202
+ characterCountOverLimitText: '%{count} characters over limit',
203
+ });
204
+
205
+ const small = wrapper.find('small');
206
+
207
+ expect(small.classes()).toContain('gl-text-red-500');
208
+ });
209
+ });
210
+ describe('recommended', () => {
211
+ it('should display the text as gray when over the limit', () => {
212
+ const value = 'hello';
213
+ const count = 4;
214
+
215
+ createComponent({
216
+ value,
217
+ count,
218
+ countType: textareaCountOptions.recommended,
219
+ characterCountText: '%{count} characters left',
220
+ characterCountOverLimitText: '%{count} characters over limit',
221
+ });
222
+
223
+ const small = wrapper.find('small');
224
+
225
+ expect(small.classes()).toContain('gl-text-gray-500');
226
+ });
227
+ });
228
+ });
122
229
  });