@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
package/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ # [38.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v38.2.1...v38.3.0) (2022-04-04)
2
+
3
+
4
+ ### Features
5
+
6
+ * **css:** Add responsive display inline classes ([21a6358](https://gitlab.com/gitlab-org/gitlab-ui/commit/21a6358266f0183f4b3b0c8b90dc379f3ab8d3a3))
7
+
8
+ ## [38.2.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v38.2.0...v38.2.1) (2022-04-01)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **GlFilteredSearch:** Generate stable token keys ([88dccde](https://gitlab.com/gitlab-org/gitlab-ui/commit/88dccde9f4df1352a7e06e831de8baced4a8d18f))
14
+
15
+ # [38.2.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v38.1.0...v38.2.0) (2022-03-31)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **GlFilteredSearch:** Stop mutating value prop ([79aa5bc](https://gitlab.com/gitlab-org/gitlab-ui/commit/79aa5bc9712e293e08842c8c0234e29511de3401))
21
+ * **GlFilteredSearch:** Stop mutating value prop ([31808db](https://gitlab.com/gitlab-org/gitlab-ui/commit/31808dbcf6b3c412db7191fe12317009b0d95542))
22
+
23
+
24
+ ### Features
25
+
26
+ * **audio:** Implementation of GitLab Flavoured Markdown audio styles ([e4c613f](https://gitlab.com/gitlab-org/gitlab-ui/commit/e4c613f0892b7b1bf3bd97b17e64e4d2e6492ebe))
27
+
1
28
  # [38.1.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v38.0.1...v38.1.0) (2022-03-28)
2
29
 
3
30
 
@@ -1,11 +1,7 @@
1
- import examples from './examples';
2
-
3
- var description = "## Usage\n\nThe dropdown component offers a user multiple items or actions to choose from which are initially\ncollapsed behind a button.\n\n### Icon-only dropdown\n\nIcon-only dropdowns must have an accessible name.\nYou can provide this with the combination of `text` and `text-sr-only` props.\n\nOptionally, you can use `no-caret` to remove the caret and `category=\"tertiary\"` to remove the border.\n\n```html\n<gl-dropdown\n icon=\"ellipsis_v\"\n text=\"More actions\"\n :text-sr-only=\"true\"\n category=\"tertiary\"\n no-caret\n>\n```\n\n### Button Content\n\nThere are 3 ways to set the dropdown button's content.\n\n1. Use the `text` attribute. This will display the text with the loading spinner (shown with the\n`loading` attribute), icon (if provided by the `icon` attribute), and dropdown caret:\n\n ```html\n <gl-dropdown text=\"Button text\">\n ```\n\n1. Use the `button-text` template. This allows custom content for the button's text, but keeps the\nloading spinner, icon, and dropdown caret:\n\n ```html\n <gl-dropdown>\n <template #button-text>\n <!-- Loading spinner shown here -->\n <!-- Icon shown here -->\n Custom <strong>Content</strong> with <em>HTML</em> via Slot\n <gl-truncate position=\"middle\" text=\"Truncated button text\"/>\n <!-- Dropdown arrow shown here -->\n </template>\n </gl-dropdown>\n ```\n\n1. Use the `button-content` template. This will replace everything in the button with the template:\n\n ```html\n <gl-dropdown>\n <template #button-content>\n Custom <strong>Content</strong> with <em>HTML</em> via Slot\n </template>\n </gl-dropdown>\n ```\n";
1
+ var description = "The dropdown component offers a user multiple items or actions to choose from which are initially\ncollapsed behind a button.\n\n### Icon-only dropdown\n\nIcon-only dropdowns must have an accessible name.\nYou can provide this with the combination of `text` and `text-sr-only` props.\n\nOptionally, you can use `no-caret` to remove the caret and `category=\"tertiary\"` to remove the border.\n\n```html\n<gl-dropdown\n icon=\"ellipsis_v\"\n text=\"More actions\"\n :text-sr-only=\"true\"\n category=\"tertiary\"\n no-caret\n>\n```\n\n### Button Content\n\nThere are 3 ways to set the dropdown button's content.\n\n1. Use the `text` attribute. This will display the text with the loading spinner (shown with the\n`loading` attribute), icon (if provided by the `icon` attribute), and dropdown caret:\n\n ```html\n <gl-dropdown text=\"Button text\">\n ```\n\n1. Use the `button-text` template. This allows custom content for the button's text, but keeps the\nloading spinner, icon, and dropdown caret:\n\n ```html\n <gl-dropdown>\n <template #button-text>\n <!-- Loading spinner shown here -->\n <!-- Icon shown here -->\n Custom <strong>Content</strong> with <em>HTML</em> via Slot\n <gl-truncate position=\"middle\" text=\"Truncated button text\"/>\n <!-- Dropdown arrow shown here -->\n </template>\n </gl-dropdown>\n ```\n\n1. Use the `button-content` template. This will replace everything in the button with the template:\n\n ```html\n <gl-dropdown>\n <template #button-content>\n Custom <strong>Content</strong> with <em>HTML</em> via Slot\n </template>\n </gl-dropdown>\n ```\n\n### GlDropdownForm\n\nUnlike `b-dropdown-form`, we do _not_ add any additional padding with the `gl-dropdown-form` component.\nThis is to prevent double padding with `gl-dropdown-item` and similar components, so in most cases\nshouldn't be needed. To add padding, either add a padding utility class to your form, or an inner\nelement with some padding.\n";
4
2
 
5
3
  var dropdown_documentation = {
6
4
  description,
7
- bootstrapComponent: 'b-dropdown',
8
- examples,
9
5
  followsDesignSystem: false
10
6
  };
11
7
 
@@ -1,8 +1,7 @@
1
- var description = "# Dropdown Item\n\n<!-- STORY -->\n\n## Usage\n\nThe dropdown item component is meant to be used for clickable entries inside a dropdown component.\nIf you provide the `href` attribute, it renders a link instead of a button.\n";
1
+ var description = "The dropdown item component is meant to be used for clickable entries inside a dropdown component.\nIf you provide the `href` attribute, it renders a link instead of a button.\n";
2
2
 
3
3
  var dropdown_item_documentation = {
4
- description,
5
- bootstrapComponent: 'b-dropdown'
4
+ description
6
5
  };
7
6
 
8
7
  export default dropdown_item_documentation;
@@ -5,22 +5,12 @@ import { GlTooltipDirective } from '../../../directives/tooltip';
5
5
  import GlIcon from '../icon/icon';
6
6
  import GlSearchBoxByClick from '../search_box_by_click/search_box_by_click';
7
7
  import GlFilteredSearchTerm from './filtered_search_term';
8
- import { TERM_TOKEN_TYPE, needDenormalization, denormalizeTokens, isEmptyTerm, INTENT_ACTIVATE_PREVIOUS, normalizeTokens } from './filtered_search_utils';
8
+ import { createTerm, needDenormalization, denormalizeTokens, isEmptyTerm, INTENT_ACTIVATE_PREVIOUS, ensureTokenId, normalizeTokens } from './filtered_search_utils';
9
9
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
10
10
 
11
11
  Vue.use(PortalVue);
12
12
  let portalUuid = 0;
13
13
 
14
- function createTerm() {
15
- let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
16
- return {
17
- type: TERM_TOKEN_TYPE,
18
- value: {
19
- data
20
- }
21
- };
22
- }
23
-
24
14
  function initialState() {
25
15
  return [createTerm()];
26
16
  }
@@ -172,6 +162,14 @@ var script = {
172
162
  watch: {
173
163
  tokens: {
174
164
  handler() {
165
+ if (process.env.NODE_ENV !== 'production') {
166
+ const invalidToken = this.tokens.find(token => !token.id);
167
+
168
+ if (invalidToken) {
169
+ throw new Error(`Token does not have an id:\n${JSON.stringify(invalidToken)}`);
170
+ }
171
+ }
172
+
175
173
  if (this.tokens.length === 0 || !this.isLastTokenEmpty()) {
176
174
  this.tokens.push(createTerm());
177
175
  }
@@ -278,12 +276,12 @@ var script = {
278
276
  },
279
277
 
280
278
  replaceToken(idx, token) {
281
- this.$set(this.tokens, idx, { ...token,
279
+ this.$set(this.tokens, idx, ensureTokenId({ ...token,
282
280
  value: {
283
281
  data: '',
284
282
  ...token.value
285
283
  }
286
- });
284
+ }));
287
285
  this.activeTokenIdx = idx;
288
286
  },
289
287
 
@@ -295,12 +293,7 @@ var script = {
295
293
  return;
296
294
  }
297
295
 
298
- const newTokens = newStrings.map(data => ({
299
- type: TERM_TOKEN_TYPE,
300
- value: {
301
- data
302
- }
303
- }));
296
+ const newTokens = newStrings.map(data => createTerm(data));
304
297
  this.tokens.splice(idx + 1, 0, ...newTokens);
305
298
  this.activeTokenIdx = idx + newStrings.length;
306
299
  },
@@ -333,7 +326,7 @@ var script = {
333
326
  const __vue_script__ = script;
334
327
 
335
328
  /* template */
336
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-search-box-by-click',_vm._b({attrs:{"value":_vm.tokens,"history-items":_vm.historyItems,"clearable":_vm.hasValue,"search-button-attributes":_vm.searchButtonAttributes,"data-testid":"filtered-search-input"},on:{"submit":_vm.submit,"input":_vm.applyNewValue,"history-item-selected":function($event){return _vm.$emit('history-item-selected', $event)},"clear":function($event){return _vm.$emit('clear')},"clear-history":function($event){return _vm.$emit('clear-history')}},scopedSlots:_vm._u([{key:"history-item",fn:function(slotScope){return [_vm._t("history-item",null,null,slotScope)]}},{key:"input",fn:function(){return [_c('div',{staticClass:"gl-filtered-search-scrollable"},[_vm._l((_vm.tokens),function(token,idx){return [_c(_vm.getTokenComponent(token.type),{key:((token.type) + "-" + idx),ref:"tokens",refInFor:true,tag:"component",staticClass:"gl-filtered-search-item",class:{
329
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-search-box-by-click',_vm._b({attrs:{"value":_vm.tokens,"history-items":_vm.historyItems,"clearable":_vm.hasValue,"search-button-attributes":_vm.searchButtonAttributes,"data-testid":"filtered-search-input"},on:{"submit":_vm.submit,"input":_vm.applyNewValue,"history-item-selected":function($event){return _vm.$emit('history-item-selected', $event)},"clear":function($event){return _vm.$emit('clear')},"clear-history":function($event){return _vm.$emit('clear-history')}},scopedSlots:_vm._u([{key:"history-item",fn:function(slotScope){return [_vm._t("history-item",null,null,slotScope)]}},{key:"input",fn:function(){return [_c('div',{staticClass:"gl-filtered-search-scrollable"},[_vm._l((_vm.tokens),function(token,idx){return [_c(_vm.getTokenComponent(token.type),{key:token.id,ref:"tokens",refInFor:true,tag:"component",staticClass:"gl-filtered-search-item",class:{
337
330
  'gl-filtered-search-last-item': _vm.isLastToken(idx),
338
331
  },attrs:{"config":_vm.getTokenEntry(token.type),"active":_vm.activeTokenIdx === idx,"available-tokens":_vm.currentAvailableTokens,"current-value":_vm.tokens,"index":idx,"placeholder":_vm.termPlaceholder,"show-friendly-text":_vm.showFriendlyText,"search-input-attributes":_vm.searchInputAttributes,"is-last-token":_vm.isLastToken(idx)},on:{"activate":function($event){return _vm.activate(idx)},"deactivate":function($event){return _vm.deactivate(token)},"destroy":function($event){return _vm.destroyToken(idx, $event)},"replace":function($event){return _vm.replaceToken(idx, $event)},"complete":_vm.completeToken,"submit":_vm.submit,"split":function($event){return _vm.createTokens(idx, $event)}},model:{value:(token.value),callback:function ($$v) {_vm.$set(token, "value", $$v);},expression:"token.value"}})]})],2),_vm._v(" "),_c('portal-target',{key:_vm.activeTokenIdx,ref:"menu",style:(_vm.suggestionsStyle),attrs:{"name":_vm.portalName,"slim":""}})]},proxy:true}],null,true)},'gl-search-box-by-click',_vm.$attrs,false))};
339
332
  var __vue_staticRenderFns__ = [];
@@ -59,7 +59,7 @@ var script = {
59
59
  const __vue_script__ = script;
60
60
 
61
61
  /* template */
62
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-dropdown-item',_vm._b({ref:"item",staticClass:"gl-filtered-search-suggestion",class:{ 'gl-filtered-search-suggestion-active': _vm.isActive },attrs:{"href":"#"},nativeOn:{"mousedown":function($event){$event.preventDefault();return _vm.emitValue($event)}}},'gl-dropdown-item',_vm.$attrs,false),[_vm._t("default")],2)};
62
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-dropdown-item',_vm._b({ref:"item",staticClass:"gl-filtered-search-suggestion",class:{ 'gl-filtered-search-suggestion-active': _vm.isActive },attrs:{"data-testid":"filtered-search-suggestion","href":"#"},nativeOn:{"mousedown":function($event){$event.preventDefault();return _vm.emitValue($event)}}},'gl-dropdown-item',_vm.$attrs,false),[_vm._t("default")],2)};
63
63
  var __vue_staticRenderFns__ = [];
64
64
 
65
65
  /* style */
@@ -1,7 +1,8 @@
1
+ import _cloneDeep from 'lodash/cloneDeep';
1
2
  import { COMMA } from '../../../utils/constants';
2
3
  import GlToken from '../token/token';
3
4
  import GlFilteredSearchTokenSegment from './filtered_search_token_segment';
4
- import { TERM_TOKEN_TYPE } from './filtered_search_utils';
5
+ import { createTerm } from './filtered_search_utils';
5
6
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
6
7
 
7
8
  const SEGMENT_TITLE = 'TYPE';
@@ -77,7 +78,8 @@ var script = {
77
78
 
78
79
  data() {
79
80
  return {
80
- activeSegment: null
81
+ activeSegment: null,
82
+ tokenValue: _cloneDeep(this.value)
81
83
  };
82
84
  },
83
85
 
@@ -87,7 +89,7 @@ var script = {
87
89
  },
88
90
 
89
91
  hasDataOrDataSegmentIsCurrentlyActive() {
90
- return this.value.data !== '' || this.isSegmentActive(SEGMENT_DATA);
92
+ return this.tokenValue.data !== '' || this.isSegmentActive(SEGMENT_DATA);
91
93
  },
92
94
 
93
95
  availableTokensWithSelf() {
@@ -97,7 +99,7 @@ var script = {
97
99
  },
98
100
 
99
101
  operatorDescription() {
100
- const operator = this.operators.find(op => op.value === this.value.operator);
102
+ const operator = this.operators.find(op => op.value === this.tokenValue.operator);
101
103
  return this.showFriendlyText ? operator === null || operator === void 0 ? void 0 : operator.description : operator === null || operator === void 0 ? void 0 : operator.value;
102
104
  }
103
105
 
@@ -108,7 +110,7 @@ var script = {
108
110
  SEGMENT_OPERATOR
109
111
  },
110
112
  watch: {
111
- value: {
113
+ tokenValue: {
112
114
  deep: true,
113
115
 
114
116
  handler(newValue) {
@@ -121,6 +123,16 @@ var script = {
121
123
  this.$emit('input', newValue);
122
124
  }
123
125
 
126
+ },
127
+ value: {
128
+ handler(newValue, oldValue) {
129
+ if ((newValue === null || newValue === void 0 ? void 0 : newValue.data) === (oldValue === null || oldValue === void 0 ? void 0 : oldValue.data) && (newValue === null || newValue === void 0 ? void 0 : newValue.operator) === (oldValue === null || oldValue === void 0 ? void 0 : oldValue.operator)) {
130
+ return;
131
+ }
132
+
133
+ this.tokenValue = _cloneDeep(newValue);
134
+ }
135
+
124
136
  },
125
137
  active: {
126
138
  immediate: true,
@@ -128,9 +140,9 @@ var script = {
128
140
  handler(newValue) {
129
141
  if (newValue) {
130
142
  if (!this.activeSegment) {
131
- this.activateSegment(this.value.data !== '' ? SEGMENT_DATA : SEGMENT_OPERATOR);
143
+ this.activateSegment(this.tokenValue.data !== '' ? SEGMENT_DATA : SEGMENT_OPERATOR);
132
144
  }
133
- } else if (this.value.data === '') {
145
+ } else if (this.tokenValue.data === '') {
134
146
  this.activeSegment = null;
135
147
  /**
136
148
  * Emitted when token is about to be destroyed.
@@ -146,15 +158,15 @@ var script = {
146
158
  },
147
159
 
148
160
  created() {
149
- if (!('operator' in this.value)) {
161
+ if (!('operator' in this.tokenValue)) {
150
162
  if (this.operators.length === 1) {
151
163
  const operator = this.operators[0].value;
152
- this.$emit('input', { ...this.value,
164
+ this.$emit('input', { ...this.tokenValue,
153
165
  operator
154
166
  });
155
167
  this.activeSegment = SEGMENT_DATA;
156
168
  } else {
157
- this.$emit('input', { ...this.value,
169
+ this.$emit('input', { ...this.tokenValue,
158
170
  operator: ''
159
171
  });
160
172
  }
@@ -186,17 +198,12 @@ var script = {
186
198
  },
187
199
 
188
200
  replaceWithTermIfEmpty() {
189
- if (this.value.operator === '' && this.value.data === '') {
201
+ if (this.tokenValue.operator === '' && this.tokenValue.data === '') {
190
202
  /**
191
203
  * Emitted when this token is converted to another type
192
204
  * @property {object} token Replacement token configuration
193
205
  */
194
- this.$emit('replace', {
195
- type: TERM_TOKEN_TYPE,
196
- value: {
197
- data: this.config.title
198
- }
199
- });
206
+ this.$emit('replace', createTerm(this.config.title));
200
207
  }
201
208
  },
202
209
 
@@ -219,7 +226,7 @@ var script = {
219
226
  const isCompatible = this.config.dataType && this.config.dataType === newTokenConfig.dataType;
220
227
  this.$emit('replace', {
221
228
  type: newTokenConfig.type,
222
- value: isCompatible ? this.value : {
229
+ value: isCompatible ? this.tokenValue : {
223
230
  data: ''
224
231
  }
225
232
  });
@@ -249,7 +256,7 @@ var script = {
249
256
  } = _ref2;
250
257
  return value.startsWith(potentialValue);
251
258
  })) {
252
- if (this.value.data === '') {
259
+ if (this.tokenValue.data === '') {
253
260
  applySuggestion(suggestedValue);
254
261
  } else {
255
262
  evt.preventDefault();
@@ -259,7 +266,7 @@ var script = {
259
266
 
260
267
  activateDataSegment() {
261
268
  if (this.config.multiSelect) {
262
- this.$emit('input', { ...this.value,
269
+ this.$emit('input', { ...this.tokenValue,
263
270
  data: ''
264
271
  });
265
272
  }
@@ -269,7 +276,7 @@ var script = {
269
276
 
270
277
  handleComplete() {
271
278
  if (this.config.multiSelect) {
272
- this.$emit('input', { ...this.value,
279
+ this.$emit('input', { ...this.tokenValue,
273
280
  data: this.multiSelectValues.join(COMMA)
274
281
  });
275
282
  }
@@ -286,6 +293,7 @@ var script = {
286
293
  destroyByClose(event) {
287
294
  if (event.target.closest(TOKEN_CLOSE_SELECTOR)) {
288
295
  event.preventDefault();
296
+ event.stopPropagation();
289
297
  this.$emit('destroy');
290
298
  }
291
299
  }
@@ -301,14 +309,14 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
301
309
  var inputValue = ref.inputValue;
302
310
  return [_c('gl-token',{staticClass:"gl-filtered-search-token-type",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_TITLE),attrs:{"view-only":""}},[_vm._v(_vm._s(inputValue))])]}}])}),_vm._v(" "),_c('gl-filtered-search-token-segment',{key:"operator-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_OPERATOR),"options":_vm.operators,"custom-input-keydown-handler":_vm.handleOperatorKeydown,"view-only":""},on:{"activate":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"backspace":_vm.replaceWithTermIfEmpty,"complete":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_DATA)},"deactivate":function($event){return _vm.$emit('deactivate')}},scopedSlots:_vm._u([{key:"view",fn:function(){return [_c('gl-token',{staticClass:"gl-filtered-search-token-operator",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_OPERATOR),attrs:{"variant":"search-value","view-only":""}},[_vm._v(_vm._s(_vm.operatorDescription))])]},proxy:true},{key:"option",fn:function(ref){
303
311
  var option = ref.option;
304
- return [_c('div',{staticClass:"gl-display-flex"},[_vm._v("\n "+_vm._s(option.value)+"\n "),(option.description)?_c('span',{staticClass:"gl-filtered-search-token-operator-description"},[_vm._v("\n "+_vm._s(option.description)+"\n ")]):_vm._e()])]}}]),model:{value:(_vm.value.operator),callback:function ($$v) {_vm.$set(_vm.value, "operator", $$v);},expression:"value.operator"}}),_vm._v(" "),(_vm.hasDataOrDataSegmentIsCurrentlyActive)?_c('gl-filtered-search-token-segment',{key:"data-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_DATA),"multi-select":_vm.config.multiSelect,"options":_vm.config.options,"option-text-field":"title"},on:{"activate":_vm.activateDataSegment,"backspace":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"complete":_vm.handleComplete,"select":function($event){return _vm.$emit('select', $event)},"submit":function($event){return _vm.$emit('submit')},"deactivate":function($event){return _vm.$emit('deactivate')},"split":function($event){return _vm.$emit('split', $event)}},scopedSlots:_vm._u([{key:"suggestions",fn:function(){return [_vm._t("suggestions")]},proxy:true},{key:"view",fn:function(ref){
312
+ return [_c('div',{staticClass:"gl-display-flex"},[_vm._v("\n "+_vm._s(option.value)+"\n "),(option.description)?_c('span',{staticClass:"gl-filtered-search-token-operator-description"},[_vm._v("\n "+_vm._s(option.description)+"\n ")]):_vm._e()])]}}]),model:{value:(_vm.tokenValue.operator),callback:function ($$v) {_vm.$set(_vm.tokenValue, "operator", $$v);},expression:"tokenValue.operator"}}),_vm._v(" "),(_vm.hasDataOrDataSegmentIsCurrentlyActive)?_c('gl-filtered-search-token-segment',{key:"data-segment",attrs:{"active":_vm.isSegmentActive(_vm.$options.segments.SEGMENT_DATA),"multi-select":_vm.config.multiSelect,"options":_vm.config.options,"option-text-field":"title"},on:{"activate":_vm.activateDataSegment,"backspace":function($event){return _vm.activateSegment(_vm.$options.segments.SEGMENT_OPERATOR)},"complete":_vm.handleComplete,"select":function($event){return _vm.$emit('select', $event)},"submit":function($event){return _vm.$emit('submit')},"deactivate":function($event){return _vm.$emit('deactivate')},"split":function($event){return _vm.$emit('split', $event)}},scopedSlots:_vm._u([{key:"suggestions",fn:function(){return [_vm._t("suggestions")]},proxy:true},{key:"view",fn:function(ref){
305
313
  var inputValue = ref.inputValue;
306
314
  return [_vm._t("view-token",[_c('gl-token',{staticClass:"gl-filtered-search-token-data",class:_vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_DATA),attrs:{"variant":"search-value"},on:{"mousedown":_vm.destroyByClose}},[_c('span',{staticClass:"gl-filtered-search-token-data-content"},[_vm._t("view",[_vm._v(_vm._s(inputValue))],null,{ inputValue: inputValue })],2)])],null,{
307
315
  inputValue: inputValue,
308
316
  listeners: { mousedown: _vm.destroyByClose },
309
317
  cssClasses: Object.assign({}, {'gl-filtered-search-token-data': true},
310
318
  _vm.getAdditionalSegmentClasses(_vm.$options.segments.SEGMENT_DATA)),
311
- })]}}],null,true),model:{value:(_vm.value.data),callback:function ($$v) {_vm.$set(_vm.value, "data", $$v);},expression:"value.data"}}):_vm._e()],1)};
319
+ })]}}],null,true),model:{value:(_vm.tokenValue.data),callback:function ($$v) {_vm.$set(_vm.tokenValue, "data", $$v);},expression:"tokenValue.data"}}):_vm._e()],1)};
312
320
  var __vue_staticRenderFns__ = [];
313
321
 
314
322
  /* style */
@@ -38,7 +38,45 @@ function needDenormalization(tokens) {
38
38
  }
39
39
 
40
40
  assertValidTokens(tokens);
41
- return tokens.some(t => typeof t === 'string');
41
+ return tokens.some(t => typeof t === 'string' || !t.id);
42
+ }
43
+ let tokenIdCounter = 0;
44
+
45
+ const getTokenId = () => {
46
+ const tokenId = `token-${tokenIdCounter}`;
47
+ tokenIdCounter += 1;
48
+ return tokenId;
49
+ };
50
+ /**
51
+ * Ensure the given token has an `id` property, which `GlFilteredSearch` relies
52
+ * on as a unique key for the token.
53
+ *
54
+ * If the given token does not have an `id`, it returns a shallow copy of the
55
+ * token with an `id`. Otherwise, it returns the given token.
56
+ *
57
+ * @param {object} token The token to check.
58
+ * @returns {object} A token with an `id`.
59
+ */
60
+
61
+
62
+ function ensureTokenId(token) {
63
+ if (!token.id) {
64
+ return { ...token,
65
+ id: getTokenId()
66
+ };
67
+ }
68
+
69
+ return token;
70
+ }
71
+ function createTerm() {
72
+ let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
73
+ return {
74
+ id: getTokenId(),
75
+ type: TERM_TOKEN_TYPE,
76
+ value: {
77
+ data
78
+ }
79
+ };
42
80
  }
43
81
  function denormalizeTokens(inputTokens) {
44
82
  assertValidTokens(inputTokens);
@@ -47,14 +85,9 @@ function denormalizeTokens(inputTokens) {
47
85
  tokens.forEach(t => {
48
86
  if (typeof t === 'string') {
49
87
  const stringTokens = t.split(' ').filter(Boolean);
50
- stringTokens.forEach(strToken => result.push({
51
- type: TERM_TOKEN_TYPE,
52
- value: {
53
- data: strToken
54
- }
55
- }));
88
+ stringTokens.forEach(strToken => result.push(createTerm(strToken)));
56
89
  } else {
57
- result.push(t);
90
+ result.push(ensureTokenId(t));
58
91
  }
59
92
  });
60
93
  return result;
@@ -135,4 +168,4 @@ function wrapTokenInQuotes(token) {
135
168
  return `"${token}"`;
136
169
  }
137
170
 
138
- export { INTENT_ACTIVATE_PREVIOUS, TERM_TOKEN_TYPE, denormalizeTokens, isEmptyTerm, needDenormalization, normalizeTokens, splitOnQuotes, wrapTokenInQuotes };
171
+ export { INTENT_ACTIVATE_PREVIOUS, TERM_TOKEN_TYPE, createTerm, denormalizeTokens, ensureTokenId, isEmptyTerm, needDenormalization, normalizeTokens, splitOnQuotes, wrapTokenInQuotes };
@@ -1,7 +1,4 @@
1
- import examples from './examples';
2
- import { V_MODEL } from './models/constants';
3
-
4
- var form_checkbox_tree = "# GlFormCheckboxTree\n\n<!-- STORY -->\n\n`GlFormCheckboxTree` lets you display an options structure where any option can have n-level of\nchildren. It can be useful for creating a search filter that has nested facets.\n\n## Usage\n\n`GlFormCheckboxTree` accepts an `options` prop representing the available options in the form of\nan n-level deep tree. Each option should have a `value` and can have optional\n`label` and `children`. If `label` is omitted, `value` is used as the checkbox's label.\nHere's a simple `options` tree for example:\n\n```js\n[\n {\n label: 'Option #1',\n value: 1,\n children: [\n {\n label: 'Option #2',\n value: 2,\n },\n ],\n },\n {\n label: 'Option #3',\n value: 3,\n },\n]\n```\n\n`GlFormCheckboxTree` exposes the selected options via a `v-model` which is being kept in sync with\nthe `change` event.\n\n## Dos and don'ts\n\n### Don't\n\nWhen rendering a `GlFormCheckboxTree` with pre-selected options, all the selected values should be\npassed to the component via the `v-model`/`value` property. For example, with the options tree\nabove, if you wanted options `1` and `2` to be pre-selected, make sure that they are both included\nin the initial value, don't rely on the component to infer initially checked boxes by only passing\n`1` or `2`.\n\n```html\n<!-- Good -->\n<gl-form-checkbox-tree\n :value=\"[1, 2]\"\n :options=\"[\n {\n value: 1,\n children: [\n {\n value: 2,\n },\n ],\n },\n ]\"\n/>\n\n<!-- Bad -->\n<gl-form-checkbox-tree\n :value=\"[1]\"\n :options=\"[\n {\n value: 1,\n children: [\n {\n value: 2,\n },\n ],\n },\n ]\"\n/>\n```\n";
1
+ var form_checkbox_tree = "`GlFormCheckboxTree` lets you display an options structure where any option can have n-level of\nchildren. It can be useful for creating a search filter that has nested facets.\n\n## Usage\n\n`GlFormCheckboxTree` accepts an `options` prop representing the available options in the form of\nan n-level deep tree. Each option should have a `value` and can have optional\n`label` and `children`. If `label` is omitted, `value` is used as the checkbox's label.\nHere's a simple `options` tree for example:\n\n```js\n[\n {\n label: 'Option #1',\n value: 1,\n children: [\n {\n label: 'Option #2',\n value: 2,\n },\n ],\n },\n {\n label: 'Option #3',\n value: 3,\n },\n]\n```\n\n`GlFormCheckboxTree` exposes the selected options via a `v-model` which is being kept in sync with\nthe `change` event.\n\n## Dos and don'ts\n\n### Don't\n\nWhen rendering a `GlFormCheckboxTree` with pre-selected options, all the selected values should be\npassed to the component via the `v-model`/`value` property. For example, with the options tree\nabove, if you wanted options `1` and `2` to be pre-selected, make sure that they are both included\nin the initial value, don't rely on the component to infer initially checked boxes by only passing\n`1` or `2`.\n\n```html\n<!-- Good -->\n<gl-form-checkbox-tree\n :value=\"[1, 2]\"\n :options=\"[\n {\n value: 1,\n children: [\n {\n value: 2,\n },\n ],\n },\n ]\"\n/>\n\n<!-- Bad -->\n<gl-form-checkbox-tree\n :value=\"[1]\"\n :options=\"[\n {\n value: 1,\n children: [\n {\n value: 2,\n },\n ],\n },\n ]\"\n/>\n```\n";
5
2
 
6
3
  var description = /*#__PURE__*/Object.freeze({
7
4
  __proto__: null,
@@ -9,29 +6,7 @@ var description = /*#__PURE__*/Object.freeze({
9
6
  });
10
7
 
11
8
  var form_checkbox_tree_documentation = {
12
- description,
13
- examples,
14
- propsInfo: {
15
- options: {
16
- additionalInfo: 'The options tree.'
17
- },
18
- [V_MODEL.PROP]: {
19
- additionalInfo: 'The selected options as an array of values.'
20
- },
21
- hideToggleAll: {
22
- additionalInfo: 'Set to true to hide the "Select/unselect all" checkbox'
23
- },
24
- selectAllLabel: {
25
- additionalInfo: 'Label for the toggle all checkbox when some or all options are unchecked'
26
- },
27
- unselectAllLabel: {
28
- additionalInfo: 'Label for the toggle all checkbox when all options are checked'
29
- }
30
- },
31
- events: [{
32
- event: V_MODEL.EVENT,
33
- description: 'Emitted the selection changes.'
34
- }]
9
+ description
35
10
  };
36
11
 
37
12
  export default form_checkbox_tree_documentation;
@@ -37,23 +37,35 @@ var script = {
37
37
  },
38
38
 
39
39
  /**
40
- * Selected options
40
+ * The selected options as an array of values
41
41
  */
42
42
  value: {
43
43
  type: Array,
44
44
  required: false,
45
45
  default: () => []
46
46
  },
47
+
48
+ /**
49
+ * Set to true to hide the "Select/unselect all" checkbox
50
+ */
47
51
  hideToggleAll: {
48
52
  type: Boolean,
49
53
  required: false,
50
54
  default: false
51
55
  },
56
+
57
+ /**
58
+ * Label for the toggle all checkbox when some or all options are unchecked
59
+ */
52
60
  selectAllLabel: {
53
61
  type: String,
54
62
  required: false,
55
63
  default: 'Select all'
56
64
  },
65
+
66
+ /**
67
+ * Label for the toggle all checkbox when all options are checked
68
+ */
57
69
  unselectAllLabel: {
58
70
  type: String,
59
71
  required: false,
@@ -86,6 +98,9 @@ var script = {
86
98
  watch: {
87
99
  'tree.selected': {
88
100
  handler(selected) {
101
+ /**
102
+ * Emitted when the selection changes.
103
+ */
89
104
  this.$emit(V_MODEL.EVENT, selected);
90
105
  }
91
106