@gitlab/ui 32.43.3 → 32.46.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 (166) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/config.js +15 -3
  3. package/dist/components/base/avatar/avatar.documentation.js +2 -5
  4. package/dist/components/base/avatar_link/avatar_link.documentation.js +2 -5
  5. package/dist/components/base/form/form_group/form_group.js +11 -1
  6. package/dist/components/base/form/form_input/form_input.documentation.js +2 -27
  7. package/dist/components/base/form/form_input/form_input.js +23 -6
  8. package/dist/components/base/form/form_text/form_text.documentation.js +1 -4
  9. package/dist/components/base/label/label.documentation.js +2 -9
  10. package/dist/components/base/label/label.js +23 -1
  11. package/dist/components/base/pagination/pagination.documentation.js +2 -85
  12. package/dist/components/base/pagination/pagination.js +76 -0
  13. package/dist/components/base/segmented_control/segmented_control.documentation.js +2 -14
  14. package/dist/components/base/segmented_control/segmented_control.js +6 -0
  15. package/dist/components/base/skeleton_loader/skeleton_loader.documentation.js +2 -28
  16. package/dist/components/base/skeleton_loader/skeleton_loader.js +30 -0
  17. package/dist/components/charts/chart/chart.js +17 -4
  18. package/dist/components/charts/discrete_scatter/discrete_scatter.documentation.js +1 -7
  19. package/dist/components/charts/heatmap/heatmap.js +1 -9
  20. package/dist/components/charts/sparkline/sparkline.js +1 -1
  21. package/dist/components/charts/stacked_column/stacked_column.documentation.js +2 -5
  22. package/dist/config.js +15 -3
  23. package/dist/index.css +1 -1
  24. package/dist/index.css.map +1 -1
  25. package/dist/utility_classes.css +1 -1
  26. package/dist/utility_classes.css.map +1 -1
  27. package/documentation/documented_stories.js +9 -0
  28. package/package.json +11 -10
  29. package/src/components/base/alert/alert.spec.js +2 -2
  30. package/src/components/base/avatar/avatar.documentation.js +0 -2
  31. package/src/components/base/avatar/avatar.md +0 -2
  32. package/src/components/base/avatar/avatar.spec.js +1 -2
  33. package/src/components/base/avatar/avatar.stories.js +88 -101
  34. package/src/components/base/avatar_link/avatar_link.documentation.js +0 -2
  35. package/src/components/base/avatar_link/avatar_link.md +4 -7
  36. package/src/components/base/avatar_link/avatar_link.stories.js +66 -54
  37. package/src/components/base/filtered_search/filtered_search.spec.js +35 -35
  38. package/src/components/base/filtered_search/filtered_search_term.spec.js +1 -1
  39. package/src/components/base/form/form_group/form_group.scss +4 -0
  40. package/src/components/base/form/form_group/form_group.spec.js +66 -64
  41. package/src/components/base/form/form_group/form_group.stories.js +36 -13
  42. package/src/components/base/form/form_group/form_group.vue +15 -2
  43. package/src/components/base/form/form_input/form_input.documentation.js +0 -31
  44. package/src/components/base/form/form_input/form_input.md +0 -2
  45. package/src/components/base/form/form_input/form_input.stories.js +50 -42
  46. package/src/components/base/form/form_input/form_input.vue +23 -6
  47. package/src/components/base/form/form_input_group/form_input_group.spec.js +1 -3
  48. package/src/components/base/form/form_text/form_text.documentation.js +0 -2
  49. package/src/components/base/form/form_text/form_text.md +1 -3
  50. package/src/components/base/form/form_text/form_text.stories.js +20 -8
  51. package/src/components/base/icon/icon.spec.js +1 -4
  52. package/src/components/base/infinite_scroll/infinite_scroll.spec.js +1 -4
  53. package/src/components/base/label/label.documentation.js +2 -12
  54. package/src/components/base/label/label.md +2 -7
  55. package/src/components/base/label/label.stories.js +66 -92
  56. package/src/components/base/label/label.vue +22 -2
  57. package/src/components/base/modal/modal.spec.js +19 -23
  58. package/src/components/base/paginated_list/__snapshots__/paginated_list.spec.js.snap +10 -10
  59. package/src/components/base/pagination/pagination.documentation.js +0 -100
  60. package/src/components/base/pagination/pagination.md +5 -9
  61. package/src/components/base/pagination/pagination.spec.js +1 -4
  62. package/src/components/base/pagination/pagination.stories.js +109 -117
  63. package/src/components/base/pagination/pagination.vue +85 -0
  64. package/src/components/base/search_box_by_click/search_box_by_click.spec.js +1 -5
  65. package/src/components/base/segmented_control/segmented_control.documentation.js +0 -15
  66. package/src/components/base/segmented_control/segmented_control.md +0 -2
  67. package/src/components/base/segmented_control/segmented_control.stories.js +46 -36
  68. package/src/components/base/segmented_control/segmented_control.vue +5 -0
  69. package/src/components/base/skeleton_loader/skeleton_loader.documentation.js +0 -27
  70. package/src/components/base/skeleton_loader/skeleton_loader.md +0 -2
  71. package/src/components/base/skeleton_loader/skeleton_loader.stories.js +23 -9
  72. package/src/components/base/skeleton_loader/skeleton_loader.vue +24 -0
  73. package/src/components/base/sorting/sorting.spec.js +1 -4
  74. package/src/components/base/toast/toast.spec.js +4 -6
  75. package/src/components/base/token/token.spec.js +1 -4
  76. package/src/components/base/token_selector/token_container.spec.js +2 -3
  77. package/src/components/charts/chart/chart.spec.js +33 -4
  78. package/src/components/charts/chart/chart.vue +16 -4
  79. package/src/components/charts/discrete_scatter/discrete_scatter.documentation.js +0 -5
  80. package/src/components/charts/discrete_scatter/discrete_scatter.stories.js +34 -46
  81. package/src/components/charts/gauge/gauge.spec.js +7 -7
  82. package/src/components/charts/heatmap/heatmap.vue +2 -9
  83. package/src/components/charts/sparkline/sparkline.spec.js +1 -4
  84. package/src/components/charts/sparkline/sparkline.vue +7 -1
  85. package/src/components/charts/stacked_column/stacked_column.documentation.js +0 -2
  86. package/src/components/charts/stacked_column/stacked_column.md +0 -2
  87. package/src/components/charts/stacked_column/stacked_column.stories.js +74 -99
  88. package/src/components/utilities/friendly_wrap/friendly_wrap.spec.js +1 -4
  89. package/src/components/utilities/intersperse/intersperse.spec.js +1 -4
  90. package/src/directives/hover_load/hover_load.spec.js +2 -13
  91. package/src/directives/outside/outside.spec.js +1 -6
  92. package/src/directives/resize_observer/resize_observer.spec.js +4 -10
  93. package/src/scss/storybook.scss +8 -0
  94. package/src/scss/utilities.scss +8 -0
  95. package/src/scss/utility-mixins/transform.scss +4 -0
  96. package/dist/components/base/avatar/examples/avatar.fallback.example.js +0 -38
  97. package/dist/components/base/avatar/examples/avatar.image.example.js +0 -38
  98. package/dist/components/base/avatar/examples/avatar.rect.example.js +0 -38
  99. package/dist/components/base/avatar/examples/avatar.tooltip.example.js +0 -38
  100. package/dist/components/base/avatar/examples/index.js +0 -31
  101. package/dist/components/base/avatar_link/examples/avatar.link.example.js +0 -38
  102. package/dist/components/base/avatar_link/examples/index.js +0 -13
  103. package/dist/components/base/form/form_input/examples/form_input/form_input.text.example.js +0 -38
  104. package/dist/components/base/form/form_input/examples/form_input/form_input.text_disabled.example.js +0 -38
  105. package/dist/components/base/form/form_input/examples/form_input/form_input.text_reactive.example.js +0 -57
  106. package/dist/components/base/form/form_input/examples/form_input/index.js +0 -22
  107. package/dist/components/base/form/form_text/examples/form_text.basic.example.js +0 -38
  108. package/dist/components/base/form/form_text/examples/index.js +0 -13
  109. package/dist/components/base/label/examples/index.js +0 -19
  110. package/dist/components/base/label/examples/label.basic.example.js +0 -38
  111. package/dist/components/base/label/examples/label.scoped.example.js +0 -38
  112. package/dist/components/base/pagination/examples/index.js +0 -37
  113. package/dist/components/base/pagination/examples/pagination.basic.example.js +0 -45
  114. package/dist/components/base/pagination/examples/pagination.compact.example.js +0 -58
  115. package/dist/components/base/pagination/examples/pagination.double_truncation.example.js +0 -45
  116. package/dist/components/base/pagination/examples/pagination.event.example.js +0 -51
  117. package/dist/components/base/pagination/examples/pagination.links.example.js +0 -45
  118. package/dist/components/base/segmented_control/examples/index.js +0 -19
  119. package/dist/components/base/segmented_control/examples/segmented_control.basic.example.js +0 -65
  120. package/dist/components/base/segmented_control/examples/segmented_control.whitespace.example.js +0 -55
  121. package/dist/components/base/skeleton_loader/examples/ci_header_skeleton.basic.example.js +0 -38
  122. package/dist/components/base/skeleton_loader/examples/default_skeleton.basic.example.js +0 -38
  123. package/dist/components/base/skeleton_loader/examples/default_skeleton_custom_props.basic.example.js +0 -38
  124. package/dist/components/base/skeleton_loader/examples/index.js +0 -37
  125. package/dist/components/base/skeleton_loader/examples/issue_card_skeleton.basic.example.js +0 -38
  126. package/dist/components/base/skeleton_loader/examples/job_log_skeleton.basic.example.js +0 -38
  127. package/dist/components/charts/discrete_scatter/examples/discrete_scatter.basic.example.js +0 -51
  128. package/dist/components/charts/discrete_scatter/examples/index.js +0 -13
  129. package/dist/components/charts/stacked_column/examples/index.js +0 -13
  130. package/dist/components/charts/stacked_column/examples/stacked_column.basic.example.js +0 -46
  131. package/src/components/base/avatar/examples/avatar.fallback.example.vue +0 -3
  132. package/src/components/base/avatar/examples/avatar.image.example.vue +0 -3
  133. package/src/components/base/avatar/examples/avatar.rect.example.vue +0 -6
  134. package/src/components/base/avatar/examples/avatar.tooltip.example.vue +0 -3
  135. package/src/components/base/avatar/examples/index.js +0 -36
  136. package/src/components/base/avatar_link/examples/avatar.link.example.vue +0 -5
  137. package/src/components/base/avatar_link/examples/index.js +0 -15
  138. package/src/components/base/form/form_input/examples/form_input/form_input.text.example.vue +0 -3
  139. package/src/components/base/form/form_input/examples/form_input/form_input.text_disabled.example.vue +0 -3
  140. package/src/components/base/form/form_input/examples/form_input/form_input.text_reactive.example.vue +0 -24
  141. package/src/components/base/form/form_input/examples/form_input/index.js +0 -26
  142. package/src/components/base/form/form_text/examples/form_text.basic.example.vue +0 -5
  143. package/src/components/base/form/form_text/examples/index.js +0 -15
  144. package/src/components/base/label/examples/index.js +0 -22
  145. package/src/components/base/label/examples/label.basic.example.vue +0 -3
  146. package/src/components/base/label/examples/label.scoped.example.vue +0 -3
  147. package/src/components/base/pagination/examples/index.js +0 -43
  148. package/src/components/base/pagination/examples/pagination.basic.example.vue +0 -17
  149. package/src/components/base/pagination/examples/pagination.compact.example.vue +0 -33
  150. package/src/components/base/pagination/examples/pagination.double_truncation.example.vue +0 -11
  151. package/src/components/base/pagination/examples/pagination.event.example.vue +0 -26
  152. package/src/components/base/pagination/examples/pagination.links.example.vue +0 -18
  153. package/src/components/base/segmented_control/examples/index.js +0 -22
  154. package/src/components/base/segmented_control/examples/segmented_control.basic.example.vue +0 -19
  155. package/src/components/base/segmented_control/examples/segmented_control.whitespace.example.vue +0 -18
  156. package/src/components/base/skeleton_loader/examples/ci_header_skeleton.basic.example.vue +0 -10
  157. package/src/components/base/skeleton_loader/examples/default_skeleton.basic.example.vue +0 -3
  158. package/src/components/base/skeleton_loader/examples/default_skeleton_custom_props.basic.example.vue +0 -9
  159. package/src/components/base/skeleton_loader/examples/index.js +0 -44
  160. package/src/components/base/skeleton_loader/examples/issue_card_skeleton.basic.example.vue +0 -26
  161. package/src/components/base/skeleton_loader/examples/job_log_skeleton.basic.example.vue +0 -13
  162. package/src/components/charts/discrete_scatter/discrete_scatter.md +0 -1
  163. package/src/components/charts/discrete_scatter/examples/discrete_scatter.basic.example.vue +0 -31
  164. package/src/components/charts/discrete_scatter/examples/index.js +0 -15
  165. package/src/components/charts/stacked_column/examples/index.js +0 -15
  166. package/src/components/charts/stacked_column/examples/stacked_column.basic.example.vue +0 -18
@@ -1,4 +1,5 @@
1
- import { shallowMount, mount, createLocalVue } from '@vue/test-utils';
1
+ import Vue from 'vue';
2
+ import { shallowMount, mount } from '@vue/test-utils';
2
3
  import GlFilteredSearch from './filtered_search.vue';
3
4
  import GlFilteredSearchSuggestion from './filtered_search_suggestion.vue';
4
5
  import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list.vue';
@@ -14,8 +15,7 @@ const FakeToken = {
14
15
  render: (h) => h('div'),
15
16
  };
16
17
 
17
- const localVue = createLocalVue();
18
- localVue.directive('GlTooltip', () => {});
18
+ Vue.directive('GlTooltip', () => {});
19
19
 
20
20
  let wrapper;
21
21
  describe('Filtered search', () => {
@@ -23,12 +23,11 @@ describe('Filtered search', () => {
23
23
  availableTokens: [{ type: 'faketoken', token: FakeToken }],
24
24
  };
25
25
 
26
- const findSearchBox = () => wrapper.find({ name: 'GlSearchBoxByClickStub' });
26
+ const findSearchBox = () => wrapper.findComponent({ name: 'GlSearchBoxByClickStub' });
27
27
 
28
28
  const createComponent = (props) => {
29
29
  wrapper = shallowMount(GlFilteredSearch, {
30
30
  propsData: { ...defaultProps, ...props },
31
- localVue,
32
31
  stubs: {
33
32
  GlSearchBoxByClick: {
34
33
  name: 'GlSearchBoxByClickStub',
@@ -116,11 +115,11 @@ describe('Filtered search', () => {
116
115
  });
117
116
  await wrapper.vm.$nextTick();
118
117
 
119
- wrapper.find(FakeToken).vm.$emit('activate');
118
+ wrapper.findComponent(FakeToken).vm.$emit('activate');
120
119
 
121
120
  await wrapper.vm.$nextTick();
122
121
 
123
- expect(wrapper.find(FakeToken).props('active')).toBe(true);
122
+ expect(wrapper.findComponent(FakeToken).props('active')).toBe(true);
124
123
  });
125
124
 
126
125
  it('deactivates token when requested', async () => {
@@ -129,8 +128,8 @@ describe('Filtered search', () => {
129
128
  });
130
129
  await wrapper.vm.$nextTick();
131
130
 
132
- wrapper.find(FakeToken).vm.$emit('activate');
133
- wrapper.find(FakeToken).vm.$emit('deactivate');
131
+ wrapper.findComponent(FakeToken).vm.$emit('activate');
132
+ wrapper.findComponent(FakeToken).vm.$emit('deactivate');
134
133
 
135
134
  await wrapper.vm.$nextTick();
136
135
 
@@ -148,12 +147,12 @@ describe('Filtered search', () => {
148
147
  });
149
148
  await wrapper.vm.$nextTick();
150
149
 
151
- wrapper.find(FakeToken).vm.$emit('activate');
150
+ wrapper.findComponent(FakeToken).vm.$emit('activate');
152
151
  wrapper.findAllComponents(FakeToken).at(1).vm.$emit('deactivate');
153
152
 
154
153
  await wrapper.vm.$nextTick();
155
154
 
156
- expect(wrapper.find(FakeToken).props('active')).toBe(true);
155
+ expect(wrapper.findComponent(FakeToken).props('active')).toBe(true);
157
156
  });
158
157
 
159
158
  it('removes empty term tokens on deactivate', async () => {
@@ -187,7 +186,7 @@ describe('Filtered search', () => {
187
186
  });
188
187
  await wrapper.vm.$nextTick();
189
188
 
190
- wrapper.find(FakeToken).vm.$emit('destroy');
189
+ wrapper.findComponent(FakeToken).vm.$emit('destroy');
191
190
 
192
191
  await wrapper.vm.$nextTick();
193
192
 
@@ -203,16 +202,16 @@ describe('Filtered search', () => {
203
202
  });
204
203
  await wrapper.vm.$nextTick();
205
204
 
206
- wrapper.find(FakeToken).vm.$emit('destroy');
205
+ wrapper.findComponent(FakeToken).vm.$emit('destroy');
207
206
 
208
207
  await wrapper.vm.$nextTick();
209
208
 
210
- expect(wrapper.find(GlFilteredSearchTerm).props('active')).toBe(true);
209
+ expect(wrapper.findComponent(GlFilteredSearchTerm).props('active')).toBe(true);
211
210
  });
212
211
 
213
212
  it('does not destroy last token', async () => {
214
213
  createComponent();
215
- wrapper.find(GlFilteredSearchTerm).vm.$emit('destroy');
214
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('destroy');
216
215
 
217
216
  await wrapper.vm.$nextTick();
218
217
 
@@ -224,7 +223,7 @@ describe('Filtered search', () => {
224
223
  it('replaces token when requested', async () => {
225
224
  createComponent();
226
225
  wrapper
227
- .find(GlFilteredSearchTerm)
226
+ .findComponent(GlFilteredSearchTerm)
228
227
  .vm.$emit('replace', { type: 'faketoken', value: { data: 'test' } });
229
228
 
230
229
  await wrapper.vm.$nextTick();
@@ -245,7 +244,7 @@ describe('Filtered search', () => {
245
244
  await wrapper.vm.$nextTick();
246
245
 
247
246
  wrapper
248
- .find(GlFilteredSearchTerm)
247
+ .findComponent(GlFilteredSearchTerm)
249
248
  .vm.$emit('replace', { type: 'faketoken', value: { data: 'test' } });
250
249
 
251
250
  await wrapper.vm.$nextTick();
@@ -258,8 +257,8 @@ describe('Filtered search', () => {
258
257
 
259
258
  it('inserts single token when requested', async () => {
260
259
  createComponent({ value: ['one'] });
261
- wrapper.find(GlFilteredSearchTerm).vm.$emit('activate');
262
- wrapper.find(GlFilteredSearchTerm).vm.$emit('split');
260
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('activate');
261
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('split');
263
262
 
264
263
  await wrapper.vm.$nextTick();
265
264
 
@@ -273,8 +272,8 @@ describe('Filtered search', () => {
273
272
  createComponent({ value: ['one', 'two'] });
274
273
  await wrapper.vm.$nextTick();
275
274
 
276
- wrapper.find(GlFilteredSearchTerm).vm.$emit('activate');
277
- wrapper.find(GlFilteredSearchTerm).vm.$emit('split');
275
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('activate');
276
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('split');
278
277
 
279
278
  await wrapper.vm.$nextTick();
280
279
 
@@ -288,11 +287,11 @@ describe('Filtered search', () => {
288
287
 
289
288
  it('inserts multiple tokens when requested', async () => {
290
289
  createComponent({ value: ['one'] });
291
- wrapper.find(GlFilteredSearchTerm).vm.$emit('activate');
290
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('activate');
292
291
 
293
292
  await wrapper.vm.$nextTick();
294
293
 
295
- wrapper.find(GlFilteredSearchTerm).vm.$emit('split', ['foo', 'bar']);
294
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('split', ['foo', 'bar']);
296
295
 
297
296
  await wrapper.vm.$nextTick();
298
297
 
@@ -306,7 +305,7 @@ describe('Filtered search', () => {
306
305
 
307
306
  it('submits entire search when submit is requested', () => {
308
307
  createComponent();
309
- wrapper.find(GlFilteredSearchTerm).vm.$emit('submit');
308
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
310
309
  expect(wrapper.emitted().submit).toBeDefined();
311
310
  });
312
311
  });
@@ -315,7 +314,7 @@ describe('Filtered search', () => {
315
314
  createComponent({
316
315
  value: ['one'],
317
316
  });
318
- wrapper.find(GlFilteredSearchTerm).vm.$emit('submit');
317
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
319
318
  expect(wrapper.emitted().submit).toBeDefined();
320
319
  expect(wrapper.emitted().submit[0][0]).toStrictEqual(['one']);
321
320
  });
@@ -324,7 +323,7 @@ describe('Filtered search', () => {
324
323
  createComponent({
325
324
  value: ['one', 'two', { type: 'faketoken', value: { data: 'smth' } }, 'four', 'five'],
326
325
  });
327
- wrapper.find(GlFilteredSearchTerm).vm.$emit('submit');
326
+ wrapper.findComponent(GlFilteredSearchTerm).vm.$emit('submit');
328
327
  expect(wrapper.emitted().submit).toBeDefined();
329
328
  expect(wrapper.emitted().submit[0][0]).toStrictEqual([
330
329
  'one two',
@@ -339,7 +338,7 @@ describe('Filtered search', () => {
339
338
  });
340
339
  await wrapper.vm.$nextTick();
341
340
 
342
- const fakeTokenInstance = wrapper.find(FakeToken);
341
+ const fakeTokenInstance = wrapper.findComponent(FakeToken);
343
342
  expect(fakeTokenInstance.exists()).toBe(true);
344
343
  expect(Object.keys(fakeTokenInstance.attributes())).toEqual(
345
344
  expect.arrayContaining(['current-value', 'index', 'config', 'value'])
@@ -383,7 +382,6 @@ describe('Filtered search integration tests', () => {
383
382
 
384
383
  const mountComponent = (props) => {
385
384
  wrapper = mount(GlFilteredSearch, {
386
- localVue,
387
385
  propsData: {
388
386
  availableTokens: testTokens,
389
387
  ...props,
@@ -432,7 +430,7 @@ describe('Filtered search integration tests', () => {
432
430
  });
433
431
 
434
432
  it('displays suggestions list', () => {
435
- const suggestions = wrapper.find(GlFilteredSearchSuggestionList);
433
+ const suggestions = wrapper.findComponent(GlFilteredSearchSuggestionList);
436
434
  expect(suggestions.exists()).toBe(true);
437
435
  expect(suggestions.findAllComponents(GlFilteredSearchSuggestion)).toHaveLength(
438
436
  testTokens.filter((t) => !t.disabled).length
@@ -445,7 +443,7 @@ describe('Filtered search integration tests', () => {
445
443
 
446
444
  await wrapper.vm.$nextTick();
447
445
 
448
- const suggestions = wrapper.find(GlFilteredSearchSuggestionList);
446
+ const suggestions = wrapper.findComponent(GlFilteredSearchSuggestionList);
449
447
  expect(suggestions.exists()).toBe(true);
450
448
  expect(suggestions.findAllComponents(GlFilteredSearchSuggestion)).toHaveLength(1);
451
449
  });
@@ -456,7 +454,7 @@ describe('Filtered search integration tests', () => {
456
454
 
457
455
  await wrapper.vm.$nextTick();
458
456
 
459
- const suggestions = wrapper.find(GlFilteredSearchSuggestionList);
457
+ const suggestions = wrapper.findComponent(GlFilteredSearchSuggestionList);
460
458
  expect(suggestions.exists()).toBe(true);
461
459
  expect(suggestions.findAllComponents(GlFilteredSearchSuggestion)).toHaveLength(3);
462
460
  });
@@ -467,7 +465,7 @@ describe('Filtered search integration tests', () => {
467
465
 
468
466
  await wrapper.vm.$nextTick();
469
467
 
470
- const suggestions = wrapper.find(GlFilteredSearchSuggestionList);
468
+ const suggestions = wrapper.findComponent(GlFilteredSearchSuggestionList);
471
469
  expect(suggestions.exists()).toBe(false);
472
470
  });
473
471
 
@@ -481,7 +479,7 @@ describe('Filtered search integration tests', () => {
481
479
 
482
480
  await wrapper.vm.$nextTick();
483
481
 
484
- const token = wrapper.find(GlFilteredSearchToken);
482
+ const token = wrapper.findComponent(GlFilteredSearchToken);
485
483
  expect(token.exists()).toBe(true);
486
484
  });
487
485
 
@@ -518,7 +516,7 @@ describe('Filtered search integration tests', () => {
518
516
 
519
517
  await wrapper.vm.$nextTick();
520
518
 
521
- const suggestions = wrapper.find(GlFilteredSearchSuggestionList);
519
+ const suggestions = wrapper.findComponent(GlFilteredSearchSuggestionList);
522
520
  expect(suggestions.exists()).toBe(true);
523
521
  expect(suggestions.findAllComponents(GlFilteredSearchSuggestion)).toHaveLength(2);
524
522
  });
@@ -549,7 +547,9 @@ describe('Filtered search integration tests', () => {
549
547
 
550
548
  await wrapper.vm.$nextTick();
551
549
 
552
- expect(document.activeElement).toBe(wrapper.find(GlFilteredSearchTerm).find('input').element);
550
+ expect(document.activeElement).toBe(
551
+ wrapper.findComponent(GlFilteredSearchTerm).find('input').element
552
+ );
553
553
  });
554
554
 
555
555
  it('clicking clear button clears component input', async () => {
@@ -64,7 +64,7 @@ describe('Filtered search term', () => {
64
64
  ({ originalEvent, emittedEvent }) => {
65
65
  createComponent({ active: true, value: { data: 'something' } });
66
66
 
67
- wrapper.find(segmentStub).vm.$emit(originalEvent);
67
+ wrapper.findComponent(segmentStub).vm.$emit(originalEvent);
68
68
 
69
69
  return wrapper.vm.$nextTick().then(() => {
70
70
  expect(wrapper.emitted()[emittedEvent]).toHaveLength(1);
@@ -13,6 +13,10 @@
13
13
  }
14
14
  }
15
15
 
16
+ .optional-label {
17
+ @include gl-font-weight-normal;
18
+ }
19
+
16
20
  .invalid-feedback,
17
21
  .text-gl-muted {
18
22
  @include gl-font-base;
@@ -1,17 +1,17 @@
1
- import { shallowMount, mount } from '@vue/test-utils';
1
+ import { shallowMount } from '@vue/test-utils';
2
2
  import { BFormGroup } from 'bootstrap-vue';
3
- import GlFormText from '../form_text/form_text.vue';
4
3
  import GlFormGroup from './form_group.vue';
5
4
 
6
5
  describe('Form group component', () => {
7
6
  let wrapper;
8
7
 
9
- const findDescription = () => {
10
- return wrapper.find('[data-testid="label-description"]');
11
- };
8
+ const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
9
+
10
+ const findLabelDescription = () => findByTestId('label-description');
11
+ const findOptionalLabel = () => findByTestId('optional-label');
12
12
 
13
- const createComponent = (options, mountFn = shallowMount) => {
14
- wrapper = mountFn(GlFormGroup, {
13
+ const createComponent = (options) => {
14
+ wrapper = shallowMount(GlFormGroup, {
15
15
  ...options,
16
16
  });
17
17
  };
@@ -35,73 +35,75 @@ describe('Form group component', () => {
35
35
  }
36
36
  );
37
37
 
38
- describe('description slot', () => {
39
- it('renders text when label-description prop is defined', () => {
40
- const labelDescription = 'description via props';
41
-
42
- createComponent(
43
- {
44
- propsData: {
45
- labelDescription,
46
- },
47
- },
48
- mount
49
- );
50
-
51
- expect(findDescription().text()).toBe(labelDescription);
52
- });
53
-
54
- it('renders a user provided label-description slot', () => {
55
- const labelDescription = 'description via slot';
56
-
57
- createComponent(
58
- {
59
- slots: {
60
- 'label-description': 'description via slot',
61
- },
62
- stubs: {
63
- GlFormText,
64
- },
65
- },
66
- mount
67
- );
68
-
69
- expect(findDescription().text()).toBe(labelDescription);
70
- });
38
+ describe('label-description slot', () => {
39
+ const labelDescriptionFromPropOptions = {
40
+ propsData: { labelDescription: 'label-description from props' },
41
+ };
42
+ const labelDescriptionFromSlotOptions = {
43
+ slots: { 'label-description': 'label-description from slots' },
44
+ };
45
+
46
+ it.each`
47
+ labelDescriptionFrom | options
48
+ ${'prop'} | ${labelDescriptionFromPropOptions}
49
+ ${'prop'} | ${labelDescriptionFromPropOptions}
50
+ ${'slot'} | ${labelDescriptionFromSlotOptions}
51
+ ${'slot'} | ${labelDescriptionFromSlotOptions}
52
+ `(
53
+ 'when label-description is provided from $labelDescriptionFrom',
54
+ ({ labelDescriptionFrom, options }) => {
55
+ createComponent({
56
+ ...options,
57
+ });
58
+
59
+ expect(findLabelDescription().text()).toContain(
60
+ `label-description from ${labelDescriptionFrom}`
61
+ );
62
+ }
63
+ );
71
64
  });
72
65
 
73
66
  describe('label slot', () => {
74
- it('renders text when label prop is defined', () => {
75
- const label = 'label via props';
76
-
77
- createComponent(
78
- {
67
+ const labelFromPropOptions = {
68
+ propsData: { label: 'label from props' },
69
+ };
70
+ const labelFromSlotOptions = {
71
+ slots: { label: 'label from slots' },
72
+ };
73
+
74
+ it.each`
75
+ labelFrom | options | optional | expectedOptional
76
+ ${'prop'} | ${labelFromPropOptions} | ${true} | ${true}
77
+ ${'prop'} | ${labelFromPropOptions} | ${false} | ${false}
78
+ ${'slot'} | ${labelFromSlotOptions} | ${true} | ${false}
79
+ ${'slot'} | ${labelFromSlotOptions} | ${false} | ${false}
80
+ `(
81
+ 'when label is provided from $labelFrom, `optional` is $optional',
82
+ ({ labelFrom, options, optional, expectedOptional }) => {
83
+ createComponent({
84
+ ...options,
79
85
  propsData: {
80
- label,
86
+ ...options.propsData,
87
+ optional,
81
88
  },
82
- },
83
- mount
84
- );
89
+ });
85
90
 
86
- expect(wrapper.text()).toBe(label);
87
- });
91
+ expect(wrapper.text()).toContain(`label from ${labelFrom}`);
92
+ expect(findOptionalLabel().exists()).toBe(expectedOptional);
93
+ }
94
+ );
88
95
 
89
- it('renders a user provided label slot', () => {
90
- const label = 'label via slot';
96
+ it('renders optionalText when `optional` is true', () => {
97
+ const optionalText = '(not required)';
91
98
 
92
- createComponent(
93
- {
94
- slots: {
95
- label: 'label via slot',
96
- },
97
- stubs: {
98
- GlFormText,
99
- },
99
+ createComponent({
100
+ propsData: {
101
+ optional: true,
102
+ optionalText,
100
103
  },
101
- mount
102
- );
104
+ });
103
105
 
104
- expect(wrapper.text()).toBe(label);
106
+ expect(findOptionalLabel().text()).toBe(optionalText);
105
107
  });
106
108
  });
107
109
  });
@@ -13,6 +13,8 @@ function generateProps({
13
13
  label = 'Label Name',
14
14
  description = 'form group description',
15
15
  labelDescription = 'form label description',
16
+ optional = GlFormGroup.props.optional.default,
17
+ optionalText = GlFormGroup.props.optionalText.default,
16
18
  horizontal = false,
17
19
  } = {}) {
18
20
  return {
@@ -36,6 +38,14 @@ function generateProps({
36
38
  type: String,
37
39
  default: text('label-description', labelDescription),
38
40
  },
41
+ optional: {
42
+ type: Boolean,
43
+ default: boolean('optional', optional),
44
+ },
45
+ optionalText: {
46
+ type: String,
47
+ default: text('optional-text', optionalText),
48
+ },
39
49
  horizontal: {
40
50
  type: Boolean,
41
51
  default: boolean('horizontal', horizontal),
@@ -53,6 +63,8 @@ documentedStoriesOf('base/form/form-group', readme)
53
63
  :id="id"
54
64
  :label="label"
55
65
  :label-size="labelSize"
66
+ :optional="optional"
67
+ :optional-text="optionalText"
56
68
  :description="description"
57
69
  :horizontal="horizontal"
58
70
  label-for="label1"
@@ -69,6 +81,8 @@ documentedStoriesOf('base/form/form-group', readme)
69
81
  id="group-id"
70
82
  label="Label Name"
71
83
  label-size="sm"
84
+ :optional="optional"
85
+ :optional-text="optionalText"
72
86
  description="This feature is disabled"
73
87
  label-for="input1"
74
88
  >
@@ -77,14 +91,21 @@ documentedStoriesOf('base/form/form-group', readme)
77
91
  `,
78
92
  }))
79
93
  .add('with textarea', () => ({
94
+ props: generateProps({ optional: true }),
80
95
  template: `
81
- <gl-form-group id="group-id-textarea2" label="Label Name" label-for="textarea2">
96
+ <gl-form-group
97
+ id="group-id-textarea2"
98
+ label="Label Name"
99
+ label-for="textarea2"
100
+ :optional="optional"
101
+ :optional-text="optionalText"
102
+ >
82
103
  <gl-form-textarea id="textarea2" placeholder="Enter something" />
83
104
  </gl-form-group>
84
105
  `,
85
106
  }))
86
107
  .add('with label description', () => ({
87
- props: generateProps(),
108
+ props: generateProps({ optional: true }),
88
109
  components,
89
110
  template: `
90
111
  <gl-form-group
@@ -93,6 +114,8 @@ documentedStoriesOf('base/form/form-group', readme)
93
114
  :label-size="labelSize"
94
115
  :description="description"
95
116
  :label-description="labelDescription"
117
+ :optional="optional"
118
+ :optional-text="optionalText"
96
119
  :horizontal="horizontal"
97
120
  label-for="label1"
98
121
  >
@@ -125,16 +148,16 @@ documentedStoriesOf('base/form/form-group', readme)
125
148
  };
126
149
  },
127
150
  template: `
128
- <gl-form-group
129
- :id="id"
130
- :label="label"
131
- :label-size="labelSize"
132
- :description="description"
133
- :invalid-feedback="invalidFeedback"
134
- :state="state"
135
- label-for="label1"
136
- >
137
- <gl-form-input id="input1" :state="state" v-model.trim="name" />
138
- </gl-form-group>
151
+ <gl-form-group
152
+ :id="id"
153
+ :label="label"
154
+ :label-size="labelSize"
155
+ :description="description"
156
+ :invalid-feedback="invalidFeedback"
157
+ :state="state"
158
+ label-for="label1"
159
+ >
160
+ <gl-form-input id="input1" :state="state" v-model.trim="name" />
161
+ </gl-form-group>
139
162
  `,
140
163
  }));
@@ -20,6 +20,16 @@ export default {
20
20
  required: false,
21
21
  default: '',
22
22
  },
23
+ optional: {
24
+ type: Boolean,
25
+ required: false,
26
+ default: false,
27
+ },
28
+ optionalText: {
29
+ type: String,
30
+ required: false,
31
+ default: '(optional)',
32
+ },
23
33
  },
24
34
  computed: {
25
35
  actualLabelClass() {
@@ -45,11 +55,14 @@ export default {
45
55
  </script>
46
56
  <template>
47
57
  <b-form-group v-bind="$attrs" class="gl-form-group" :label-class="actualLabelClass">
48
- <template v-if="hasLabelDescription" #label>
58
+ <template #label>
49
59
  <slot name="label">
50
60
  {{ $attrs.label }}
61
+ <span v-if="optional" class="optional-label" data-testid="optional-label">{{
62
+ optionalText
63
+ }}</span>
51
64
  </slot>
52
- <gl-form-text data-testid="label-description">
65
+ <gl-form-text v-if="hasLabelDescription" data-testid="label-description">
53
66
  <slot name="label-description">{{ labelDescription }}</slot>
54
67
  </gl-form-text>
55
68
  </template>
@@ -1,37 +1,6 @@
1
- import examples from './examples/form_input';
2
1
  import description from './form_input.md';
3
2
 
4
3
  export default {
5
4
  description,
6
- examples,
7
- bootstrapComponent: 'b-form-input',
8
5
  followsDesignSystem: true,
9
- propsInfo: {
10
- size: {
11
- additionalInfo: 'Maximum width of the input',
12
- enum: 'formInputSizes',
13
- },
14
- },
15
- events: [
16
- {
17
- event: 'input',
18
- args: [
19
- {
20
- arg: 'value',
21
- description: '(String)',
22
- },
23
- ],
24
- description: 'Emitted to update the v-model',
25
- },
26
- {
27
- event: 'update',
28
- args: [
29
- {
30
- arg: 'value',
31
- description: '(String)',
32
- },
33
- ],
34
- description: `Triggered by user interaction. Emitted after any formatting (not including 'trim' or 'number' props). Useful for getting the currently entered value when the 'debounce' or 'lazy' props are set.`,
35
- },
36
- ],
37
6
  };
@@ -1,3 +1 @@
1
- # Form Input
2
-
3
1
  General user input to be used in forms.