@gitlab/ui 38.1.0 → 38.3.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 (94) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/base/dropdown/dropdown.documentation.js +1 -5
  3. package/dist/components/base/dropdown/dropdown_item.documentation.js +2 -3
  4. package/dist/components/base/filtered_search/filtered_search.js +13 -20
  5. package/dist/components/base/filtered_search/filtered_search_suggestion.js +1 -1
  6. package/dist/components/base/filtered_search/filtered_search_token.js +31 -23
  7. package/dist/components/base/filtered_search/filtered_search_utils.js +42 -9
  8. package/dist/components/base/form/form_checkbox_tree/form_checkbox_tree.documentation.js +2 -27
  9. package/dist/components/base/form/form_checkbox_tree/form_checkbox_tree.js +16 -1
  10. package/dist/index.css +1 -1
  11. package/dist/index.css.map +1 -1
  12. package/dist/utility_classes.css +1 -1
  13. package/dist/utility_classes.css.map +1 -1
  14. package/dist/utils/use_mock_intersection_observer.js +2 -2
  15. package/documentation/components_documentation.js +0 -4
  16. package/documentation/documented_stories.js +4 -1
  17. package/package.json +12 -12
  18. package/src/components/base/avatar_link/avatar_link.stories.js +2 -2
  19. package/src/components/base/dropdown/dropdown.documentation.js +0 -3
  20. package/src/components/base/dropdown/dropdown.md +7 -2
  21. package/src/components/base/dropdown/dropdown.stories.js +487 -439
  22. package/src/components/base/dropdown/dropdown_item.documentation.js +0 -1
  23. package/src/components/base/dropdown/dropdown_item.md +0 -6
  24. package/src/components/base/dropdown/dropdown_item.stories.js +107 -35
  25. package/src/components/base/filtered_search/filtered_search.spec.js +37 -12
  26. package/src/components/base/filtered_search/filtered_search.stories.js +15 -7
  27. package/src/components/base/filtered_search/filtered_search.vue +12 -14
  28. package/src/components/base/filtered_search/filtered_search_suggestion.vue +1 -0
  29. package/src/components/base/filtered_search/filtered_search_token.spec.js +31 -1
  30. package/src/components/base/filtered_search/filtered_search_token.stories.js +1 -0
  31. package/src/components/base/filtered_search/filtered_search_token.vue +30 -21
  32. package/src/components/base/filtered_search/filtered_search_utils.js +38 -5
  33. package/src/components/base/form/form.stories.js +2 -0
  34. package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.documentation.js +0 -26
  35. package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.md +0 -4
  36. package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.stories.js +123 -92
  37. package/src/components/base/form/form_checkbox_tree/form_checkbox_tree.vue +13 -1
  38. package/src/components/base/form/form_radio_group/form_radio_group.stories.js +2 -1
  39. package/src/components/base/markdown/markdown.scss +21 -0
  40. package/src/components/base/markdown/markdown_typescale_demo.html +17 -6
  41. package/src/components/base/navbar/navbar.stories.js +2 -1
  42. package/src/components/base/skeleton_loader/skeleton_loader.stories.js +67 -21
  43. package/src/components/base/tabs/tabs/tabs.stories.js +2 -2
  44. package/src/scss/typescale/typescale.md +0 -2
  45. package/src/scss/typescale/typescale.stories.js +17 -4
  46. package/src/scss/utilities.scss +24 -0
  47. package/src/scss/utility-mixins/display.scss +12 -0
  48. package/src/utils/use_mock_intersection_observer.js +3 -3
  49. package/dist/components/base/dropdown/dropdown_divider.documentation.js +0 -8
  50. package/dist/components/base/dropdown/dropdown_form.documentation.js +0 -17
  51. package/dist/components/base/dropdown/dropdown_section_header.documentation.js +0 -8
  52. package/dist/components/base/dropdown/dropdown_text.documentation.js +0 -8
  53. package/dist/components/base/dropdown/examples/dropdown.default.example.js +0 -38
  54. package/dist/components/base/dropdown/examples/dropdown.links.example.js +0 -38
  55. package/dist/components/base/dropdown/examples/dropdown.with_avatar_and_secondary_text.example.js +0 -38
  56. package/dist/components/base/dropdown/examples/dropdown.with_checked_items.example.js +0 -38
  57. package/dist/components/base/dropdown/examples/dropdown.with_clear_all.example.js +0 -38
  58. package/dist/components/base/dropdown/examples/dropdown.with_divider.example.js +0 -38
  59. package/dist/components/base/dropdown/examples/dropdown.with_form.example.js +0 -38
  60. package/dist/components/base/dropdown/examples/dropdown.with_header.example.js +0 -38
  61. package/dist/components/base/dropdown/examples/dropdown.with_highlighted_items.example.js +0 -38
  62. package/dist/components/base/dropdown/examples/dropdown.with_icons.example.js +0 -38
  63. package/dist/components/base/dropdown/examples/dropdown.with_right_align.example.js +0 -38
  64. package/dist/components/base/dropdown/examples/dropdown.with_search.example.js +0 -67
  65. package/dist/components/base/dropdown/examples/dropdown.with_section_headers.example.js +0 -38
  66. package/dist/components/base/dropdown/examples/index.js +0 -85
  67. package/dist/components/base/form/form_checkbox_tree/examples/form_checkbox_tree.basic.example.js +0 -103
  68. package/dist/components/base/form/form_checkbox_tree/examples/index.js +0 -13
  69. package/src/components/base/dropdown/dropdown_divider.documentation.js +0 -6
  70. package/src/components/base/dropdown/dropdown_divider.md +0 -7
  71. package/src/components/base/dropdown/dropdown_divider.stories.js +0 -16
  72. package/src/components/base/dropdown/dropdown_form.documentation.js +0 -9
  73. package/src/components/base/dropdown/dropdown_form.md +0 -4
  74. package/src/components/base/dropdown/dropdown_form.stories.js +0 -17
  75. package/src/components/base/dropdown/dropdown_section_header.documentation.js +0 -6
  76. package/src/components/base/dropdown/dropdown_section_header.stories.js +0 -17
  77. package/src/components/base/dropdown/dropdown_text.documentation.js +0 -6
  78. package/src/components/base/dropdown/dropdown_text.stories.js +0 -16
  79. package/src/components/base/dropdown/examples/dropdown.default.example.vue +0 -7
  80. package/src/components/base/dropdown/examples/dropdown.links.example.vue +0 -7
  81. package/src/components/base/dropdown/examples/dropdown.with_avatar_and_secondary_text.example.vue +0 -7
  82. package/src/components/base/dropdown/examples/dropdown.with_checked_items.example.vue +0 -6
  83. package/src/components/base/dropdown/examples/dropdown.with_clear_all.example.vue +0 -7
  84. package/src/components/base/dropdown/examples/dropdown.with_divider.example.vue +0 -9
  85. package/src/components/base/dropdown/examples/dropdown.with_form.example.vue +0 -10
  86. package/src/components/base/dropdown/examples/dropdown.with_header.example.vue +0 -7
  87. package/src/components/base/dropdown/examples/dropdown.with_highlighted_items.example.vue +0 -9
  88. package/src/components/base/dropdown/examples/dropdown.with_icons.example.vue +0 -43
  89. package/src/components/base/dropdown/examples/dropdown.with_right_align.example.vue +0 -7
  90. package/src/components/base/dropdown/examples/dropdown.with_search.example.vue +0 -38
  91. package/src/components/base/dropdown/examples/dropdown.with_section_headers.example.vue +0 -10
  92. package/src/components/base/dropdown/examples/index.js +0 -99
  93. package/src/components/base/form/form_checkbox_tree/examples/form_checkbox_tree.basic.example.vue +0 -77
  94. package/src/components/base/form/form_checkbox_tree/examples/index.js +0 -15
@@ -1,8 +1,9 @@
1
1
  <script>
2
+ import { cloneDeep } from 'lodash';
2
3
  import { COMMA } from '../../../utils/constants';
3
4
  import GlToken from '../token/token.vue';
4
5
  import GlFilteredSearchTokenSegment from './filtered_search_token_segment.vue';
5
- import { TERM_TOKEN_TYPE } from './filtered_search_utils';
6
+ import { createTerm } from './filtered_search_utils';
6
7
 
7
8
  const SEGMENT_TITLE = 'TYPE';
8
9
  const SEGMENT_OPERATOR = 'OPERATOR';
@@ -68,6 +69,7 @@ export default {
68
69
  data() {
69
70
  return {
70
71
  activeSegment: null,
72
+ tokenValue: cloneDeep(this.value),
71
73
  };
72
74
  },
73
75
 
@@ -77,7 +79,7 @@ export default {
77
79
  },
78
80
 
79
81
  hasDataOrDataSegmentIsCurrentlyActive() {
80
- return this.value.data !== '' || this.isSegmentActive(SEGMENT_DATA);
82
+ return this.tokenValue.data !== '' || this.isSegmentActive(SEGMENT_DATA);
81
83
  },
82
84
 
83
85
  availableTokensWithSelf() {
@@ -88,7 +90,7 @@ export default {
88
90
  },
89
91
 
90
92
  operatorDescription() {
91
- const operator = this.operators.find((op) => op.value === this.value.operator);
93
+ const operator = this.operators.find((op) => op.value === this.tokenValue.operator);
92
94
  return this.showFriendlyText ? operator?.description : operator?.value;
93
95
  },
94
96
  },
@@ -98,7 +100,7 @@ export default {
98
100
  SEGMENT_OPERATOR,
99
101
  },
100
102
  watch: {
101
- value: {
103
+ tokenValue: {
102
104
  deep: true,
103
105
  handler(newValue) {
104
106
  /**
@@ -111,14 +113,24 @@ export default {
111
113
  },
112
114
  },
113
115
 
116
+ value: {
117
+ handler(newValue, oldValue) {
118
+ if (newValue?.data === oldValue?.data && newValue?.operator === oldValue?.operator) {
119
+ return;
120
+ }
121
+
122
+ this.tokenValue = cloneDeep(newValue);
123
+ },
124
+ },
125
+
114
126
  active: {
115
127
  immediate: true,
116
128
  handler(newValue) {
117
129
  if (newValue) {
118
130
  if (!this.activeSegment) {
119
- this.activateSegment(this.value.data !== '' ? SEGMENT_DATA : SEGMENT_OPERATOR);
131
+ this.activateSegment(this.tokenValue.data !== '' ? SEGMENT_DATA : SEGMENT_OPERATOR);
120
132
  }
121
- } else if (this.value.data === '') {
133
+ } else if (this.tokenValue.data === '') {
122
134
  this.activeSegment = null;
123
135
  /**
124
136
  * Emitted when token is about to be destroyed.
@@ -132,13 +144,13 @@ export default {
132
144
  },
133
145
 
134
146
  created() {
135
- if (!('operator' in this.value)) {
147
+ if (!('operator' in this.tokenValue)) {
136
148
  if (this.operators.length === 1) {
137
149
  const operator = this.operators[0].value;
138
- this.$emit('input', { ...this.value, operator });
150
+ this.$emit('input', { ...this.tokenValue, operator });
139
151
  this.activeSegment = SEGMENT_DATA;
140
152
  } else {
141
- this.$emit('input', { ...this.value, operator: '' });
153
+ this.$emit('input', { ...this.tokenValue, operator: '' });
142
154
  }
143
155
  }
144
156
  },
@@ -166,12 +178,12 @@ export default {
166
178
  },
167
179
 
168
180
  replaceWithTermIfEmpty() {
169
- if (this.value.operator === '' && this.value.data === '') {
181
+ if (this.tokenValue.operator === '' && this.tokenValue.data === '') {
170
182
  /**
171
183
  * Emitted when this token is converted to another type
172
184
  * @property {object} token Replacement token configuration
173
185
  */
174
- this.$emit('replace', { type: TERM_TOKEN_TYPE, value: { data: this.config.title } });
186
+ this.$emit('replace', createTerm(this.config.title));
175
187
  }
176
188
  },
177
189
 
@@ -195,7 +207,7 @@ export default {
195
207
  this.config.dataType && this.config.dataType === newTokenConfig.dataType;
196
208
  this.$emit('replace', {
197
209
  type: newTokenConfig.type,
198
- value: isCompatible ? this.value : { data: '' },
210
+ value: isCompatible ? this.tokenValue : { data: '' },
199
211
  });
200
212
  }
201
213
  },
@@ -212,7 +224,7 @@ export default {
212
224
  key.length === 1 &&
213
225
  !this.operators.find(({ value }) => value.startsWith(potentialValue))
214
226
  ) {
215
- if (this.value.data === '') {
227
+ if (this.tokenValue.data === '') {
216
228
  applySuggestion(suggestedValue);
217
229
  } else {
218
230
  evt.preventDefault();
@@ -222,14 +234,14 @@ export default {
222
234
 
223
235
  activateDataSegment() {
224
236
  if (this.config.multiSelect) {
225
- this.$emit('input', { ...this.value, data: '' });
237
+ this.$emit('input', { ...this.tokenValue, data: '' });
226
238
  }
227
239
  this.activateSegment(this.$options.segments.SEGMENT_DATA);
228
240
  },
229
241
 
230
242
  handleComplete() {
231
243
  if (this.config.multiSelect) {
232
- this.$emit('input', { ...this.value, data: this.multiSelectValues.join(COMMA) });
244
+ this.$emit('input', { ...this.tokenValue, data: this.multiSelectValues.join(COMMA) });
233
245
  }
234
246
  /**
235
247
  * Emitted when the token entry has been completed.
@@ -242,6 +254,7 @@ export default {
242
254
  destroyByClose(event) {
243
255
  if (event.target.closest(TOKEN_CLOSE_SELECTOR)) {
244
256
  event.preventDefault();
257
+ event.stopPropagation();
245
258
  this.$emit('destroy');
246
259
  }
247
260
  },
@@ -275,10 +288,9 @@ export default {
275
288
  >
276
289
  </template>
277
290
  </gl-filtered-search-token-segment>
278
- <!-- eslint-disable vue/no-mutating-props -->
279
291
  <gl-filtered-search-token-segment
280
292
  key="operator-segment"
281
- v-model="value.operator"
293
+ v-model="tokenValue.operator"
282
294
  :active="isSegmentActive($options.segments.SEGMENT_OPERATOR)"
283
295
  :options="operators"
284
296
  :custom-input-keydown-handler="handleOperatorKeydown"
@@ -288,7 +300,6 @@ export default {
288
300
  @complete="activateSegment($options.segments.SEGMENT_DATA)"
289
301
  @deactivate="$emit('deactivate')"
290
302
  >
291
- <!-- eslint-enable vue/no-mutating-props -->
292
303
  <template #view>
293
304
  <gl-token
294
305
  class="gl-filtered-search-token-operator"
@@ -307,7 +318,6 @@ export default {
307
318
  </div>
308
319
  </template>
309
320
  </gl-filtered-search-token-segment>
310
- <!-- eslint-disable vue/no-mutating-props -->
311
321
  <!--
312
322
  Emitted when a suggestion has been selected.
313
323
  @event select
@@ -321,7 +331,7 @@ export default {
321
331
  <gl-filtered-search-token-segment
322
332
  v-if="hasDataOrDataSegmentIsCurrentlyActive"
323
333
  key="data-segment"
324
- v-model="value.data"
334
+ v-model="tokenValue.data"
325
335
  :active="isSegmentActive($options.segments.SEGMENT_DATA)"
326
336
  :multi-select="config.multiSelect"
327
337
  :options="config.options"
@@ -334,7 +344,6 @@ export default {
334
344
  @deactivate="$emit('deactivate')"
335
345
  @split="$emit('split', $event)"
336
346
  >
337
- <!-- eslint-enable vue/no-mutating-props -->
338
347
  <template #suggestions>
339
348
  <!-- @slot The suggestions (implemented with GlFilteredSearchSuggestion). -->
340
349
  <slot name="suggestions"></slot>
@@ -39,7 +39,42 @@ export function needDenormalization(tokens) {
39
39
 
40
40
  assertValidTokens(tokens);
41
41
 
42
- return tokens.some((t) => typeof t === 'string');
42
+ return tokens.some((t) => typeof t === 'string' || !t.id);
43
+ }
44
+
45
+ let tokenIdCounter = 0;
46
+ const getTokenId = () => {
47
+ const tokenId = `token-${tokenIdCounter}`;
48
+ tokenIdCounter += 1;
49
+ return tokenId;
50
+ };
51
+ /**
52
+ * Ensure the given token has an `id` property, which `GlFilteredSearch` relies
53
+ * on as a unique key for the token.
54
+ *
55
+ * If the given token does not have an `id`, it returns a shallow copy of the
56
+ * token with an `id`. Otherwise, it returns the given token.
57
+ *
58
+ * @param {object} token The token to check.
59
+ * @returns {object} A token with an `id`.
60
+ */
61
+ export function ensureTokenId(token) {
62
+ if (!token.id) {
63
+ return {
64
+ ...token,
65
+ id: getTokenId(),
66
+ };
67
+ }
68
+
69
+ return token;
70
+ }
71
+
72
+ export function createTerm(data = '') {
73
+ return {
74
+ id: getTokenId(),
75
+ type: TERM_TOKEN_TYPE,
76
+ value: { data },
77
+ };
43
78
  }
44
79
 
45
80
  export function denormalizeTokens(inputTokens) {
@@ -51,11 +86,9 @@ export function denormalizeTokens(inputTokens) {
51
86
  tokens.forEach((t) => {
52
87
  if (typeof t === 'string') {
53
88
  const stringTokens = t.split(' ').filter(Boolean);
54
- stringTokens.forEach((strToken) =>
55
- result.push({ type: TERM_TOKEN_TYPE, value: { data: strToken } })
56
- );
89
+ stringTokens.forEach((strToken) => result.push(createTerm(strToken)));
57
90
  } else {
58
- result.push(t);
91
+ result.push(ensureTokenId(t));
59
92
  }
60
93
  });
61
94
  return result;
@@ -4,6 +4,7 @@ import {
4
4
  GlFormInput,
5
5
  GlFormSelect,
6
6
  GlFormCheckbox,
7
+ GlFormCheckboxGroup,
7
8
  GlButton,
8
9
  } from '../../../index';
9
10
  import { setStoryTimeout } from '../../../utils/test_utils';
@@ -16,6 +17,7 @@ export const Default = (args) => ({
16
17
  GlFormInput,
17
18
  GlFormSelect,
18
19
  GlFormCheckbox,
20
+ GlFormCheckboxGroup,
19
21
  GlButton,
20
22
  },
21
23
  props: Object.keys(args),
@@ -1,31 +1,5 @@
1
- import examples from './examples';
2
1
  import * as description from './form_checkbox_tree.md';
3
- import { V_MODEL } from './models/constants';
4
2
 
5
3
  export default {
6
4
  description,
7
- examples,
8
- propsInfo: {
9
- options: {
10
- additionalInfo: 'The options tree.',
11
- },
12
- [V_MODEL.PROP]: {
13
- additionalInfo: 'The selected options as an array of values.',
14
- },
15
- hideToggleAll: {
16
- additionalInfo: 'Set to true to hide the "Select/unselect all" checkbox',
17
- },
18
- selectAllLabel: {
19
- additionalInfo: 'Label for the toggle all checkbox when some or all options are unchecked',
20
- },
21
- unselectAllLabel: {
22
- additionalInfo: 'Label for the toggle all checkbox when all options are checked',
23
- },
24
- },
25
- events: [
26
- {
27
- event: V_MODEL.EVENT,
28
- description: 'Emitted the selection changes.',
29
- },
30
- ],
31
5
  };
@@ -1,7 +1,3 @@
1
- # GlFormCheckboxTree
2
-
3
- <!-- STORY -->
4
-
5
1
  `GlFormCheckboxTree` lets you display an options structure where any option can have n-level of
6
2
  children. It can be useful for creating a search filter that has nested facets.
7
3
 
@@ -1,5 +1,3 @@
1
- import { withKnobs, boolean } from '@storybook/addon-knobs';
2
- import { documentedStoriesOf } from '../../../../../documentation/documented_stories';
3
1
  import GlToken from '../../token/token.vue';
4
2
  import readme from './form_checkbox_tree.md';
5
3
  import GlFormCheckboxTree from './form_checkbox_tree.vue';
@@ -9,95 +7,128 @@ const components = {
9
7
  GlToken,
10
8
  };
11
9
 
12
- documentedStoriesOf('base/form/form-checkbox-tree', readme)
13
- .addDecorator(withKnobs)
14
- .add('default', () => ({
15
- props: {
16
- hideToggleAll: {
17
- default: boolean('Hide toggle all checkbox?', false),
10
+ const defaultOptions = [
11
+ {
12
+ value: 1,
13
+ label: 'Felidae',
14
+ children: [
15
+ {
16
+ value: 11,
17
+ label: 'Lion',
18
+ },
19
+ {
20
+ value: 12,
21
+ label: 'Felinae',
22
+ children: [
23
+ {
24
+ value: 121,
25
+ label: 'Cheetah',
26
+ },
27
+ {
28
+ value: 122,
29
+ label: 'Ocelot',
30
+ },
31
+ ],
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ value: 2,
37
+ label: 'Canidae',
38
+ children: [
39
+ {
40
+ value: 21,
41
+ label: 'Caninae',
42
+ children: [
43
+ {
44
+ value: 211,
45
+ label: 'Canis lupus',
46
+ children: [
47
+ {
48
+ value: 2112,
49
+ label: 'Wolf',
50
+ },
51
+ {
52
+ value: 2113,
53
+ label: 'Himalayan wolf',
54
+ },
55
+ {
56
+ value: 2114,
57
+ label: 'Dingo',
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ value: 212,
63
+ label: 'Black-backed jackal',
64
+ },
65
+ ],
66
+ },
67
+ {
68
+ value: 22,
69
+ label: 'Fennec fox',
70
+ },
71
+ ],
72
+ },
73
+ {
74
+ value: 3,
75
+ label: 'Karabair',
76
+ },
77
+ {
78
+ value: 4,
79
+ label: 'Okapi',
80
+ },
81
+ ];
82
+
83
+ const defaultValue = (prop) => GlFormCheckboxTree.props[prop].default;
84
+
85
+ const generateProps = ({
86
+ options = defaultOptions,
87
+ hideToggleAll = defaultValue('hideToggleAll'),
88
+ selectAllLabel = defaultValue('selectAllLabel'),
89
+ unselectAllLabel = defaultValue('unselectAllLabel'),
90
+ label = defaultValue('label'),
91
+ labelSrOnly = defaultValue('labelSrOnly'),
92
+ } = {}) => ({
93
+ options,
94
+ hideToggleAll,
95
+ selectAllLabel,
96
+ unselectAllLabel,
97
+ label,
98
+ labelSrOnly,
99
+ });
100
+
101
+ export const Default = (args, { argTypes }) => ({
102
+ props: Object.keys(argTypes),
103
+ data: () => ({
104
+ checked: [1, 11, 12, 121, 122, 2113, 3],
105
+ }),
106
+ components,
107
+ template: `
108
+ <div>
109
+ <gl-form-checkbox-tree
110
+ v-model="checked"
111
+ :options="options"
112
+ :hide-toggle-all="hideToggleAll"
113
+ :select-all-label="selectAllLabel"
114
+ :unselect-all-label="unselectAllLabel"
115
+ :label="label"
116
+ :label-sr-only="labelSrOnly" />
117
+ Selected options:
118
+ <gl-token v-for="value in checked" :key="value" class="gl-mr-1" view-only>{{ value }}</gl-token>
119
+ </div>
120
+ `,
121
+ });
122
+ Default.args = generateProps();
123
+
124
+ export default {
125
+ title: 'base/form/form-checkbox-tree',
126
+ component: GlFormCheckboxTree,
127
+ parameters: {
128
+ docs: {
129
+ description: {
130
+ component: readme,
18
131
  },
19
132
  },
20
- data: () => ({
21
- checked: [1, 11, 12, 121, 122, 2113, 3],
22
- options: [
23
- {
24
- value: 1,
25
- label: 'Felidae',
26
- children: [
27
- {
28
- value: 11,
29
- label: 'Lion',
30
- },
31
- {
32
- value: 12,
33
- label: 'Felinae',
34
- children: [
35
- {
36
- value: 121,
37
- label: 'Cheetah',
38
- },
39
- {
40
- value: 122,
41
- label: 'Ocelot',
42
- },
43
- ],
44
- },
45
- ],
46
- },
47
- {
48
- value: 2,
49
- label: 'Canidae',
50
- children: [
51
- {
52
- value: 21,
53
- label: 'Caninae',
54
- children: [
55
- {
56
- value: 211,
57
- label: 'Canis lupus',
58
- children: [
59
- {
60
- value: 2112,
61
- label: 'Wolf',
62
- },
63
- {
64
- value: 2113,
65
- label: 'Himalayan wolf',
66
- },
67
- {
68
- value: 2114,
69
- label: 'Dingo',
70
- },
71
- ],
72
- },
73
- {
74
- value: 212,
75
- label: 'Black-backed jackal',
76
- },
77
- ],
78
- },
79
- {
80
- value: 22,
81
- label: 'Fennec fox',
82
- },
83
- ],
84
- },
85
- {
86
- value: 3,
87
- label: 'Karabair',
88
- },
89
- {
90
- value: 4,
91
- label: 'Okapi',
92
- },
93
- ],
94
- }),
95
- components,
96
- template: `
97
- <div>
98
- <gl-form-checkbox-tree :hide-toggle-all="hideToggleAll" :options="options" v-model="checked" />
99
- Selected options:
100
- <gl-token v-for="value in checked" :key="value" class="gl-mr-1" view-only>{{ value }}</gl-token>
101
- </div>
102
- `,
103
- }));
133
+ },
134
+ };
@@ -34,23 +34,32 @@ export default {
34
34
  required: true,
35
35
  },
36
36
  /**
37
- * Selected options
37
+ * The selected options as an array of values
38
38
  */
39
39
  value: {
40
40
  type: Array,
41
41
  required: false,
42
42
  default: () => [],
43
43
  },
44
+ /**
45
+ * Set to true to hide the "Select/unselect all" checkbox
46
+ */
44
47
  hideToggleAll: {
45
48
  type: Boolean,
46
49
  required: false,
47
50
  default: false,
48
51
  },
52
+ /**
53
+ * Label for the toggle all checkbox when some or all options are unchecked
54
+ */
49
55
  selectAllLabel: {
50
56
  type: String,
51
57
  required: false,
52
58
  default: 'Select all',
53
59
  },
60
+ /**
61
+ * Label for the toggle all checkbox when all options are checked
62
+ */
54
63
  unselectAllLabel: {
55
64
  type: String,
56
65
  required: false,
@@ -80,6 +89,9 @@ export default {
80
89
  watch: {
81
90
  'tree.selected': {
82
91
  handler(selected) {
92
+ /**
93
+ * Emitted when the selection changes.
94
+ */
83
95
  this.$emit(V_MODEL.EVENT, selected);
84
96
  },
85
97
  },
@@ -1,4 +1,4 @@
1
- import { GlFormRadioGroup } from '../../../../index';
1
+ import { GlFormRadioGroup, GlFormRadio } from '../../../../index';
2
2
  import readme from './form_radio_group.md';
3
3
 
4
4
  const defaultOptions = [
@@ -34,6 +34,7 @@ const template = `
34
34
  const Template = (args, { argTypes }) => ({
35
35
  components: {
36
36
  GlFormRadioGroup,
37
+ GlFormRadio,
37
38
  },
38
39
  props: Object.keys(argTypes),
39
40
  template,
@@ -162,6 +162,27 @@
162
162
  @include gl-px-2;
163
163
  @include gl-py-1;
164
164
  }
165
+
166
+ .audio-container {
167
+ @include gl-display-inline-flex;
168
+ @include gl-flex-direction-column;
169
+ @include gl-w-full;
170
+
171
+ audio {
172
+ @include gl-w-full;
173
+ }
174
+
175
+ a {
176
+ @include gl-mt-3;
177
+
178
+ &::before {
179
+ @include gl-mr-2;
180
+ text-rendering: auto;
181
+ -webkit-font-smoothing: antialiased;
182
+ content: '📎';
183
+ }
184
+ }
185
+ }
165
186
  }
166
187
 
167
188
  .gl-compact-markdown {
@@ -3,8 +3,8 @@
3
3
  significant ways to add some useful functionality. You can use GFM in the following areas: comments, issues, merge
4
4
  requests, milestones, snippets and more.</p>
5
5
  <p class="sm">MD Doc Small Paragraph • GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown
6
- in a few significant ways to add some useful functionality. You can use GFM in the following areas: comments, issues,
7
- merge requests, milestones, snippets and more.</p>
6
+ in a few significant ways to add some useful functionality. You can use GFM in the following areas: comments, issues,
7
+ merge requests, milestones, snippets and more.</p>
8
8
  <p class="monospace">UI Monospace</p>
9
9
  <p class="monospace sm">UI Small Monospace</p>
10
10
  <h2>MD Doc h2 • GitLab uses "GitLab Flavored Markdown" (GFM)</h2>
@@ -29,15 +29,26 @@ merge requests, milestones, snippets and more.</p>
29
29
  requests, milestones, snippets and more.</p>
30
30
  <blockquote>
31
31
  <p>
32
- MD Doc Blockquote • GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few
33
- significant ways to add some useful functionality. You can use GFM in the following areas: comments, issues, merge
34
- requests, milestones, snippets and more.
32
+ MD Doc Blockquote • GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few
33
+ significant ways to add some useful functionality. You can use GFM in the following areas: comments, issues, merge
34
+ requests, milestones, snippets and more.
35
35
  </p>
36
36
  </blockquote>
37
37
  <p>
38
38
  This is a paragraph with two types inline diff <span class="idiff addition">addition</span> and
39
39
  <span class="idiff deletion">deletion</span>
40
40
  </p>
41
- <p>
41
+ <p>
42
42
  This block implements the "GitLab Flavored Markdown" <code>Code span</code> styles.
43
43
  </p>
44
+
45
+ <p>
46
+ This is an audio file
47
+ <span class="media-container audio-container">
48
+ <audio src="file.mp3" controls="true" data-setup="{}" data-title="file.mp3" data-canonical-src="file.mp3"
49
+ class="gfm">
50
+ </audio>
51
+ <a href="file.mp3" target="_blank" rel="noopener noreferrer" title="Download file.mp3" data-canonical-src="file.mp3"
52
+ data-link="true" class="gfm">file.mp3</a>
53
+ </span>
54
+ </p>
@@ -1,8 +1,9 @@
1
+ import { BNavbarBrand } from 'bootstrap-vue';
1
2
  import { GlNavbar } from '../../../index';
2
3
  import readme from './navbar.md';
3
4
 
4
5
  const Template = (args, { argTypes }) => ({
5
- components: { GlNavbar },
6
+ components: { GlNavbar, BNavbarBrand },
6
7
  props: Object.keys(argTypes),
7
8
  template: `
8
9
  <gl-navbar variant="dark" type="dark">