@gitlab/ui 32.44.0 → 32.47.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 (93) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/config.js +15 -3
  3. package/dist/components/base/form/form_combobox/form_combobox.documentation.js +2 -9
  4. package/dist/components/base/form/form_combobox/form_combobox.js +5 -0
  5. package/dist/components/base/form/form_group/form_group.js +11 -1
  6. package/dist/components/base/form/input_group_text/input_group_text.documentation.js +1 -5
  7. package/dist/components/base/label/label.documentation.js +2 -9
  8. package/dist/components/base/label/label.js +23 -1
  9. package/dist/components/base/skeleton_loader/skeleton_loader.documentation.js +2 -28
  10. package/dist/components/base/skeleton_loader/skeleton_loader.js +30 -0
  11. package/dist/components/charts/chart/chart.js +17 -4
  12. package/dist/components/charts/discrete_scatter/discrete_scatter.documentation.js +1 -7
  13. package/dist/components/charts/heatmap/heatmap.js +1 -9
  14. package/dist/components/charts/sparkline/sparkline.js +1 -1
  15. package/dist/components/charts/stacked_column/stacked_column.documentation.js +2 -5
  16. package/dist/components/charts/tooltip/tooltip.documentation.js +1 -5
  17. package/dist/config.js +15 -3
  18. package/dist/index.css +1 -1
  19. package/dist/index.css.map +1 -1
  20. package/dist/utility_classes.css +1 -1
  21. package/dist/utility_classes.css.map +1 -1
  22. package/documentation/documented_stories.js +7 -0
  23. package/package.json +1 -1
  24. package/src/components/base/form/form_combobox/form_combobox.documentation.js +0 -8
  25. package/src/components/base/form/form_combobox/form_combobox.md +0 -2
  26. package/src/components/base/form/form_combobox/form_combobox.stories.js +30 -30
  27. package/src/components/base/form/form_combobox/form_combobox.vue +4 -0
  28. package/src/components/base/form/form_group/form_group.scss +4 -0
  29. package/src/components/base/form/form_group/form_group.spec.js +66 -64
  30. package/src/components/base/form/form_group/form_group.stories.js +36 -13
  31. package/src/components/base/form/form_group/form_group.vue +15 -2
  32. package/src/components/base/form/input_group_text/input_group_text.documentation.js +0 -3
  33. package/src/components/base/form/input_group_text/input_group_text.stories.js +24 -18
  34. package/src/components/base/label/label.documentation.js +2 -12
  35. package/src/components/base/label/label.md +2 -7
  36. package/src/components/base/label/label.stories.js +66 -92
  37. package/src/components/base/label/label.vue +22 -2
  38. package/src/components/base/skeleton_loader/skeleton_loader.documentation.js +0 -27
  39. package/src/components/base/skeleton_loader/skeleton_loader.md +0 -2
  40. package/src/components/base/skeleton_loader/skeleton_loader.stories.js +23 -9
  41. package/src/components/base/skeleton_loader/skeleton_loader.vue +24 -0
  42. package/src/components/charts/chart/chart.spec.js +33 -4
  43. package/src/components/charts/chart/chart.vue +16 -4
  44. package/src/components/charts/discrete_scatter/discrete_scatter.documentation.js +0 -5
  45. package/src/components/charts/discrete_scatter/discrete_scatter.stories.js +34 -46
  46. package/src/components/charts/heatmap/heatmap.vue +2 -9
  47. package/src/components/charts/sparkline/sparkline.vue +7 -1
  48. package/src/components/charts/stacked_column/stacked_column.documentation.js +0 -2
  49. package/src/components/charts/stacked_column/stacked_column.md +0 -2
  50. package/src/components/charts/stacked_column/stacked_column.stories.js +74 -99
  51. package/src/components/charts/tooltip/tooltip.documentation.js +0 -3
  52. package/src/components/charts/tooltip/tooltip.stories.js +59 -44
  53. package/src/scss/utilities.scss +8 -0
  54. package/src/scss/utility-mixins/transform.scss +4 -0
  55. package/dist/components/base/form/form_combobox/examples/form_combobox.basic.example.js +0 -50
  56. package/dist/components/base/form/form_combobox/examples/index.js +0 -13
  57. package/dist/components/base/form/input_group_text/examples/index.js +0 -13
  58. package/dist/components/base/form/input_group_text/examples/input_group_text.basic.example.js +0 -38
  59. package/dist/components/base/label/examples/index.js +0 -19
  60. package/dist/components/base/label/examples/label.basic.example.js +0 -38
  61. package/dist/components/base/label/examples/label.scoped.example.js +0 -38
  62. package/dist/components/base/skeleton_loader/examples/ci_header_skeleton.basic.example.js +0 -38
  63. package/dist/components/base/skeleton_loader/examples/default_skeleton.basic.example.js +0 -38
  64. package/dist/components/base/skeleton_loader/examples/default_skeleton_custom_props.basic.example.js +0 -38
  65. package/dist/components/base/skeleton_loader/examples/index.js +0 -37
  66. package/dist/components/base/skeleton_loader/examples/issue_card_skeleton.basic.example.js +0 -38
  67. package/dist/components/base/skeleton_loader/examples/job_log_skeleton.basic.example.js +0 -38
  68. package/dist/components/charts/discrete_scatter/examples/discrete_scatter.basic.example.js +0 -51
  69. package/dist/components/charts/discrete_scatter/examples/index.js +0 -13
  70. package/dist/components/charts/stacked_column/examples/index.js +0 -13
  71. package/dist/components/charts/stacked_column/examples/stacked_column.basic.example.js +0 -46
  72. package/dist/components/charts/tooltip/examples/chart_tooltip.basic.example.js +0 -54
  73. package/dist/components/charts/tooltip/examples/index.js +0 -13
  74. package/src/components/base/form/form_combobox/examples/form_combobox.basic.example.vue +0 -31
  75. package/src/components/base/form/form_combobox/examples/index.js +0 -15
  76. package/src/components/base/form/input_group_text/examples/index.js +0 -15
  77. package/src/components/base/form/input_group_text/examples/input_group_text.basic.example.vue +0 -3
  78. package/src/components/base/label/examples/index.js +0 -22
  79. package/src/components/base/label/examples/label.basic.example.vue +0 -3
  80. package/src/components/base/label/examples/label.scoped.example.vue +0 -3
  81. package/src/components/base/skeleton_loader/examples/ci_header_skeleton.basic.example.vue +0 -10
  82. package/src/components/base/skeleton_loader/examples/default_skeleton.basic.example.vue +0 -3
  83. package/src/components/base/skeleton_loader/examples/default_skeleton_custom_props.basic.example.vue +0 -9
  84. package/src/components/base/skeleton_loader/examples/index.js +0 -44
  85. package/src/components/base/skeleton_loader/examples/issue_card_skeleton.basic.example.vue +0 -26
  86. package/src/components/base/skeleton_loader/examples/job_log_skeleton.basic.example.vue +0 -13
  87. package/src/components/charts/discrete_scatter/discrete_scatter.md +0 -1
  88. package/src/components/charts/discrete_scatter/examples/discrete_scatter.basic.example.vue +0 -31
  89. package/src/components/charts/discrete_scatter/examples/index.js +0 -15
  90. package/src/components/charts/stacked_column/examples/index.js +0 -15
  91. package/src/components/charts/stacked_column/examples/stacked_column.basic.example.vue +0 -18
  92. package/src/components/charts/tooltip/examples/chart_tooltip.basic.example.vue +0 -32
  93. package/src/components/charts/tooltip/examples/index.js +0 -15
@@ -100,6 +100,13 @@ export const setupStorybookReadme = () =>
100
100
  'GlAvatar',
101
101
  'GlAvatarLink',
102
102
  'GlPagination',
103
+ 'GlSkeletonLoader',
104
+ 'GlLabel',
105
+ 'GlStackedColumnChart',
106
+ 'GlDiscreteScatterChart',
107
+ 'GlFormCombobox',
108
+ 'GlChartTooltip',
109
+ 'GlInputGroupText',
103
110
  ],
104
111
  components: {
105
112
  GlComponentDocumentation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "32.44.0",
3
+ "version": "32.47.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -1,14 +1,6 @@
1
- import examples from './examples';
2
1
  import * as description from './form_combobox.md';
3
2
 
4
3
  export default {
5
4
  followsDesignSystem: true,
6
5
  description,
7
- examples,
8
- events: [
9
- {
10
- event: 'value-selected',
11
- description: 'Emitted when a value is selected.',
12
- },
13
- ],
14
6
  };
@@ -1,5 +1,3 @@
1
- # GlFormCombobox
2
-
3
1
  Use this component to add a [`FormInput`](/?path=/story/base-form-form-input--default) component
4
2
  with synchronous autocomplete dropdown. It behaves as follows:
5
3
 
@@ -1,41 +1,41 @@
1
- import { withKnobs, object, text } from '@storybook/addon-knobs';
2
- import { documentedStoriesOf } from '../../../../../documentation/documented_stories';
3
1
  import { tokenList, labelText } from './constants';
4
2
  import readme from './form_combobox.md';
5
3
  import GlFormCombobox from './form_combobox.vue';
6
4
 
7
- const components = {
8
- GlFormCombobox,
9
- };
10
-
11
- const getProps = () => {
12
- return {
13
- tokenList: {
14
- type: Array,
15
- default: object('tokens', tokenList),
16
- },
17
- labelText: {
18
- type: String,
19
- default: text('label text', labelText),
20
- },
21
- };
22
- };
5
+ const getProps = () => ({
6
+ tokenList,
7
+ labelText,
8
+ });
23
9
 
24
- documentedStoriesOf('base/form/form-combobox', readme)
25
- .addDecorator(withKnobs)
26
- .add('default', () => ({
27
- components,
28
- props: getProps(),
29
- data: () => {
30
- return {
31
- value: '',
32
- };
33
- },
34
- template: `
10
+ const Template = (args) => ({
11
+ components: { GlFormCombobox },
12
+ data: () => {
13
+ return {
14
+ value: '',
15
+ };
16
+ },
17
+ props: Object.keys(args),
18
+ template: `
35
19
  <gl-form-combobox
36
20
  v-model="value"
37
21
  :token-list="tokenList"
38
22
  :labelText="labelText"
39
23
  />
40
24
  `,
41
- }));
25
+ });
26
+
27
+ export const Default = Template.bind({});
28
+ Default.args = getProps();
29
+
30
+ export default {
31
+ title: 'base/form/form-combobox',
32
+ component: GlFormCombobox,
33
+ parameters: {
34
+ knobs: { disable: true },
35
+ docs: {
36
+ description: {
37
+ component: readme,
38
+ },
39
+ },
40
+ },
41
+ };
@@ -128,6 +128,10 @@ export default {
128
128
  selectToken(value) {
129
129
  this.$emit('input', value);
130
130
  this.closeSuggestions();
131
+ /**
132
+ * Emitted when a value is selected.
133
+ * @event value-selected
134
+ */
131
135
  this.$emit('value-selected', value);
132
136
  },
133
137
  },
@@ -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,8 +1,5 @@
1
- import examples from './examples';
2
1
  import * as description from './input_group_text.md';
3
2
 
4
3
  export default {
5
4
  description,
6
- examples,
7
- propsInfo: {},
8
5
  };
@@ -1,25 +1,31 @@
1
- import { documentedStoriesOf } from '../../../../../documentation/documented_stories';
2
1
  import readme from './input_group_text.md';
3
2
  import GlInputGroupText from './input_group_text.vue';
4
3
 
5
- const components = {
6
- GlInputGroupText,
7
- };
8
-
9
- const defaultProps = {};
10
-
11
- function generateProps(props = {}) {
12
- return {
13
- ...defaultProps,
14
- ...props,
15
- };
16
- }
4
+ const generateProps = (props = {}) => ({
5
+ ...props,
6
+ });
17
7
 
18
- documentedStoriesOf('base/form/input-group-text', readme).add('default', () => ({
19
- components,
20
- props: generateProps(),
21
- data: () => ({}),
8
+ const Template = (args) => ({
9
+ components: { GlInputGroupText },
10
+ props: Object.keys(args),
22
11
  template: `
23
12
  <gl-input-group-text>Some text</gl-input-group-text>
24
13
  `,
25
- }));
14
+ });
15
+
16
+ export const Default = Template.bind({});
17
+ Default.args = generateProps();
18
+
19
+ export default {
20
+ title: 'base/form/input-group-text',
21
+ component: GlInputGroupText,
22
+ parameters: {
23
+ controls: { disable: true },
24
+ knobs: { disable: true },
25
+ docs: {
26
+ description: {
27
+ component: readme,
28
+ },
29
+ },
30
+ },
31
+ };
@@ -1,16 +1,6 @@
1
- import examples from './examples';
1
+ import description from './label.vue';
2
2
 
3
3
  export default {
4
4
  followsDesignSystem: true,
5
- examples,
6
- events: [
7
- {
8
- event: 'click',
9
- description: 'Emitted when label is clicked',
10
- },
11
- {
12
- event: 'close',
13
- description: 'Emitted when x is clicked',
14
- },
15
- ],
5
+ description,
16
6
  };
@@ -1,15 +1,10 @@
1
- # Label
2
-
3
- <!-- STORY -->
4
- ## Usage
5
-
6
1
  Labels are editable objects that allow users to manually categorize other objects, like issues,
7
2
  merge requests, and epics. They have a name, description, and a customizable background color.
8
3
  They provide a quick way to recognize which categories the labeled object belongs to.
9
4
 
10
5
  ## Using the component
11
6
 
12
- ~~~js
7
+ ```js
13
8
  <gl-label
14
9
  background-color="#D9C2EE"
15
10
  title="Label content"
@@ -18,4 +13,4 @@ They provide a quick way to recognize which categories the labeled object belong
18
13
  tooltipPlacement="top"
19
14
  target="http://some.url"
20
15
  />
21
- ~~~
16
+ ```