@gitlab/ui 61.2.0 → 62.0.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 (33) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/base/daterange_picker/daterange_picker.js +1 -1
  3. package/dist/components/base/filtered_search/common_story_options.js +2 -1
  4. package/dist/components/base/filtered_search/filtered_search.js +28 -4
  5. package/dist/components/base/filtered_search/filtered_search_suggestion_list.js +13 -5
  6. package/dist/components/base/filtered_search/filtered_search_term.js +51 -4
  7. package/dist/components/base/filtered_search/filtered_search_token.js +1 -2
  8. package/dist/components/base/filtered_search/filtered_search_token_segment.js +18 -5
  9. package/dist/components/base/filtered_search/filtered_search_utils.js +18 -7
  10. package/dist/components/base/token_selector/token_container.js +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/package.json +1 -1
  15. package/src/components/base/daterange_picker/daterange_picker.vue +1 -1
  16. package/src/components/base/filtered_search/__snapshots__/filtered_search_term.spec.js.snap +2 -5
  17. package/src/components/base/filtered_search/common_story_options.js +1 -0
  18. package/src/components/base/filtered_search/filtered_search.md +10 -1
  19. package/src/components/base/filtered_search/filtered_search.spec.js +14 -2
  20. package/src/components/base/filtered_search/filtered_search.stories.js +17 -0
  21. package/src/components/base/filtered_search/filtered_search.vue +29 -1
  22. package/src/components/base/filtered_search/filtered_search_suggestion_list.spec.js +222 -75
  23. package/src/components/base/filtered_search/filtered_search_suggestion_list.vue +15 -6
  24. package/src/components/base/filtered_search/filtered_search_term.spec.js +73 -14
  25. package/src/components/base/filtered_search/filtered_search_term.vue +64 -6
  26. package/src/components/base/filtered_search/filtered_search_token.spec.js +1 -0
  27. package/src/components/base/filtered_search/filtered_search_token.vue +2 -2
  28. package/src/components/base/filtered_search/filtered_search_token_segment.spec.js +46 -2
  29. package/src/components/base/filtered_search/filtered_search_token_segment.vue +22 -5
  30. package/src/components/base/filtered_search/filtered_search_utils.js +20 -7
  31. package/src/components/base/token_selector/token_container.vue +1 -1
  32. package/src/scss/utilities.scss +0 -72
  33. package/src/scss/utility-mixins/flex.scss +0 -41
package/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ # [62.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v61.3.0...v62.0.0) (2023-04-19)
2
+
3
+
4
+ ### Code Refactoring
5
+
6
+ * remove gl-*flex-wrap-wrap classes ([fc405cc](https://gitlab.com/gitlab-org/gitlab-ui/commit/fc405cc59dc743209c0ea00a583b31cb77fc1218))
7
+
8
+
9
+ ### BREAKING CHANGES
10
+
11
+ * remove deprecated `gl-[breakpoint?]-flex-wrap-wrap`,
12
+ `gl-[breakpoint?]-flex-wrap-nowrap`, and
13
+ `gl-[breakpoint?]-flex-wrap-wrap-reverse` classes.
14
+
15
+ Instead, use these classes: `gl-[breakpoint?]-flex-wrap`,
16
+ `gl-[breakpoint?]-flex-nowrap`, and
17
+ `gl-[breakpoint?]-flex-wrap-reverse`.
18
+
19
+ # [61.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v61.2.0...v61.3.0) (2023-04-19)
20
+
21
+
22
+ ### Features
23
+
24
+ * **GlFilteredSearch:** Terms as tokens ([7149a54](https://gitlab.com/gitlab-org/gitlab-ui/commit/7149a541f4dc29d7f364ee1ab02a1c88be3824ed))
25
+
1
26
  # [61.2.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v61.1.3...v61.2.0) (2023-04-18)
2
27
 
3
28
 
@@ -4,7 +4,7 @@ import GlDatepicker from '../datepicker/datepicker';
4
4
  import GlIcon from '../icon/icon';
5
5
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
6
6
 
7
- const CONTAINER_CLASSES = ['gl-display-flex', 'gl-align-items-baseline', 'gl-flex-wrap', 'gl-sm-flex-wrap-nowrap', 'gl-sm-gap-3'];
7
+ const CONTAINER_CLASSES = ['gl-display-flex', 'gl-align-items-baseline', 'gl-flex-wrap', 'gl-sm-flex-nowrap', 'gl-sm-gap-3'];
8
8
  var script = {
9
9
  name: 'GlDaterangePicker',
10
10
  components: {
@@ -7,7 +7,8 @@ const noop = () => {};
7
7
  const provide = () => ({
8
8
  portalName: 'portal',
9
9
  alignSuggestions: noop,
10
- suggestionsListClass: noop
10
+ suggestionsListClass: noop,
11
+ termsAsTokens: () => false
11
12
  });
12
13
 
13
14
  export { provide };
@@ -6,7 +6,7 @@ import { GlTooltipDirective } from '../../../directives/tooltip';
6
6
  import GlIcon from '../icon/icon';
7
7
  import GlSearchBoxByClick from '../search_box_by_click/search_box_by_click';
8
8
  import GlFilteredSearchTerm from './filtered_search_term';
9
- import { createTerm, needDenormalization, denormalizeTokens, isEmptyTerm, INTENT_ACTIVATE_PREVIOUS, ensureTokenId, normalizeTokens } from './filtered_search_utils';
9
+ import { termTokenDefinition, createTerm, needDenormalization, denormalizeTokens, isEmptyTerm, INTENT_ACTIVATE_PREVIOUS, ensureTokenId, normalizeTokens } from './filtered_search_utils';
10
10
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
11
11
 
12
12
  Vue.use(PortalVue);
@@ -32,7 +32,8 @@ var script = {
32
32
  // Return a function reference instead of a prop to work around vue-apollo@3 bug.
33
33
  // TODO: This can be reverted once https://github.com/vuejs/vue-apollo/pull/1153
34
34
  // has been merged and we consume it, or we upgrade to vue-apollo@4.
35
- suggestionsListClass: () => this.suggestionsListClass
35
+ suggestionsListClass: () => this.suggestionsListClass,
36
+ termsAsTokens: () => this.termsAsTokens
36
37
  };
37
38
  },
38
39
  inheritAttrs: false,
@@ -128,6 +129,28 @@ var script = {
128
129
  type: Boolean,
129
130
  required: false,
130
131
  default: false
132
+ },
133
+ /**
134
+ * Render search terms as GlTokens. Ideally, this prop will be as
135
+ * short-lived as possible, and this behavior will become the default and
136
+ * only behavior.
137
+ *
138
+ * This prop is *not* reactive.
139
+ *
140
+ * See https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2159.
141
+ */
142
+ termsAsTokens: {
143
+ type: Boolean,
144
+ required: false,
145
+ default: false
146
+ },
147
+ /**
148
+ * The title of the text search option. Ignored unless termsAsTokens is enabled.
149
+ */
150
+ searchTextOptionLabel: {
151
+ type: String,
152
+ required: false,
153
+ default: termTokenDefinition.title
131
154
  }
132
155
  },
133
156
  data() {
@@ -200,7 +223,7 @@ var script = {
200
223
  },
201
224
  methods: {
202
225
  applyNewValue(newValue) {
203
- this.tokens = needDenormalization(newValue) ? denormalizeTokens(newValue) : newValue;
226
+ this.tokens = needDenormalization(newValue) ? denormalizeTokens(newValue, this.termsAsTokens) : newValue;
204
227
  },
205
228
  isActiveToken(idx) {
206
229
  return this.activeTokenIdx === idx;
@@ -300,6 +323,7 @@ var script = {
300
323
  }));
301
324
  this.activeTokenIdx = idx;
302
325
  },
326
+ // This method can be deleted once termsAsTokens behavior is the default.
303
327
  createTokens(idx) {
304
328
  let newStrings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [''];
305
329
  if (!this.isLastTokenActive && newStrings.length === 1 && newStrings[0] === '') {
@@ -331,7 +355,7 @@ var script = {
331
355
  const __vue_script__ = script;
332
356
 
333
357
  /* template */
334
- 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,"disabled":_vm.viewOnly,"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",class:{ 'gl-bg-gray-10! gl-inset-border-1-gray-100!': _vm.viewOnly }},_vm._l((_vm.tokens),function(token,idx){return _c(_vm.getTokenComponent(token.type),{key:token.id,ref:"tokens",refInFor:true,tag:"component",class:_vm.getTokenClassList(idx),attrs:{"config":_vm.getTokenEntry(token.type),"active":_vm.activeTokenIdx === idx,"cursor-position":_vm.intendedCursorPosition,"available-tokens":_vm.currentAvailableTokens,"current-value":_vm.tokens,"index":idx,"placeholder":_vm.termPlaceholder,"show-friendly-text":_vm.showFriendlyText,"search-input-attributes":_vm.searchInputAttributes,"view-only":_vm.viewOnly,"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)},"previous":_vm.activatePreviousToken,"next":_vm.activateNextToken},model:{value:(token.value),callback:function ($$v) {_vm.$set(token, "value", $$v);},expression:"token.value"}})}),1),_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))};
358
+ 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,"disabled":_vm.viewOnly,"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",class:{ 'gl-bg-gray-10! gl-inset-border-1-gray-100!': _vm.viewOnly }},_vm._l((_vm.tokens),function(token,idx){return _c(_vm.getTokenComponent(token.type),{key:token.id,ref:"tokens",refInFor:true,tag:"component",class:_vm.getTokenClassList(idx),attrs:{"config":_vm.getTokenEntry(token.type),"active":_vm.activeTokenIdx === idx,"cursor-position":_vm.intendedCursorPosition,"available-tokens":_vm.currentAvailableTokens,"current-value":_vm.tokens,"index":idx,"placeholder":_vm.termPlaceholder,"show-friendly-text":_vm.showFriendlyText,"search-input-attributes":_vm.searchInputAttributes,"view-only":_vm.viewOnly,"is-last-token":_vm.isLastToken(idx),"search-text-option-label":_vm.searchTextOptionLabel},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)},"previous":_vm.activatePreviousToken,"next":_vm.activateNextToken},model:{value:(token.value),callback:function ($$v) {_vm.$set(token, "value", $$v);},expression:"token.value"}})}),1),_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))};
335
359
  var __vue_staticRenderFns__ = [];
336
360
 
337
361
  /* style */
@@ -5,7 +5,7 @@ const DEFER_TO_INITIAL_VALUE = -1;
5
5
  const NO_ACTIVE_ITEM = -2;
6
6
  var script = {
7
7
  name: 'GlFilteredSearchSuggestionList',
8
- inject: ['suggestionsListClass'],
8
+ inject: ['suggestionsListClass', 'termsAsTokens'],
9
9
  provide() {
10
10
  return {
11
11
  filteredSearchSuggestionListInstance: this
@@ -35,7 +35,7 @@ var script = {
35
35
  return this.registeredItems[this.initialActiveIdx];
36
36
  },
37
37
  activeItem() {
38
- if (this.activeIdx === NO_ACTIVE_ITEM) return null;
38
+ if (!this.termsAsTokens() && this.activeIdx === NO_ACTIVE_ITEM) return null;
39
39
  if (this.activeIdx === DEFER_TO_INITIAL_VALUE) return this.initialActiveItem;
40
40
  return this.registeredItems[this.activeIdx];
41
41
  },
@@ -66,13 +66,21 @@ var script = {
66
66
  }
67
67
  },
68
68
  nextItem() {
69
- this.stepItem(1, this.registeredItems.length - 1);
69
+ if (this.termsAsTokens()) {
70
+ this.stepItem(1);
71
+ } else {
72
+ this.stepItem(1, this.registeredItems.length - 1);
73
+ }
70
74
  },
71
75
  prevItem() {
72
- this.stepItem(-1, 0);
76
+ if (this.termsAsTokens()) {
77
+ this.stepItem(-1);
78
+ } else {
79
+ this.stepItem(-1, 0);
80
+ }
73
81
  },
74
82
  stepItem(direction, endIdx) {
75
- if (this.activeIdx === endIdx || this.activeIdx === DEFER_TO_INITIAL_VALUE && this.initialActiveIdx === endIdx) {
83
+ if (!this.termsAsTokens() && (this.activeIdx === endIdx || this.activeIdx === DEFER_TO_INITIAL_VALUE && this.initialActiveIdx === endIdx)) {
76
84
  // The user wants to move past the end of the list, so ensure nothing is selected.
77
85
  this.activeIdx = NO_ACTIVE_ITEM;
78
86
  } else {
@@ -1,12 +1,16 @@
1
+ import GlToken from '../token/token';
2
+ import { stopEvent } from '../../../utils/utils';
1
3
  import GlFilteredSearchTokenSegment from './filtered_search_token_segment';
2
- import { match, tokenToOption, INTENT_ACTIVATE_PREVIOUS } from './filtered_search_utils';
4
+ import { termTokenDefinition, match, tokenToOption, INTENT_ACTIVATE_PREVIOUS, TOKEN_CLOSE_SELECTOR, TERM_TOKEN_TYPE } from './filtered_search_utils';
3
5
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
4
6
 
5
7
  var script = {
6
8
  name: 'GlFilteredSearchTerm',
7
9
  components: {
8
- GlFilteredSearchTokenSegment
10
+ GlFilteredSearchTokenSegment,
11
+ GlToken
9
12
  },
13
+ inject: ['termsAsTokens'],
10
14
  inheritAttrs: false,
11
15
  props: {
12
16
  /**
@@ -69,6 +73,14 @@ var script = {
69
73
  default: 'end',
70
74
  validator: value => ['start', 'end'].includes(value)
71
75
  },
76
+ /**
77
+ * The title of the text search option. Ignored unless termsAsTokens is enabled.
78
+ */
79
+ searchTextOptionLabel: {
80
+ type: String,
81
+ required: false,
82
+ default: termTokenDefinition.title
83
+ },
72
84
  viewOnly: {
73
85
  type: Boolean,
74
86
  required: false,
@@ -76,8 +88,21 @@ var script = {
76
88
  }
77
89
  },
78
90
  computed: {
91
+ showInput() {
92
+ return this.termsAsTokens() || Boolean(this.placeholder);
93
+ },
94
+ showToken() {
95
+ return this.termsAsTokens() && Boolean(this.value.data);
96
+ },
79
97
  suggestedTokens() {
80
- return this.availableTokens.filter(token => match(token.title, this.value.data)).map(tokenToOption);
98
+ const tokens = this.availableTokens.filter(token => match(token.title, this.value.data));
99
+ if (this.termsAsTokens() && this.value.data) {
100
+ tokens.push({
101
+ ...termTokenDefinition,
102
+ title: this.searchTextOptionLabel
103
+ });
104
+ }
105
+ return tokens.map(tokenToOption);
81
106
  },
82
107
  internalValue: {
83
108
  get() {
@@ -94,6 +119,11 @@ var script = {
94
119
  data
95
120
  });
96
121
  }
122
+ },
123
+ eventListeners() {
124
+ return this.viewOnly ? {} : {
125
+ mousedown: this.destroyByClose
126
+ };
97
127
  }
98
128
  },
99
129
  methods: {
@@ -108,6 +138,23 @@ var script = {
108
138
  this.$emit('destroy', {
109
139
  intent: INTENT_ACTIVATE_PREVIOUS
110
140
  });
141
+ },
142
+ destroyByClose(event) {
143
+ if (event.target.closest(TOKEN_CLOSE_SELECTOR)) {
144
+ stopEvent(event);
145
+ this.$emit('destroy');
146
+ }
147
+ },
148
+ onComplete(type) {
149
+ if (type === TERM_TOKEN_TYPE) {
150
+ // We've completed this term token
151
+ this.$emit('complete');
152
+ } else {
153
+ // We're changing the current token type
154
+ this.$emit('replace', {
155
+ type
156
+ });
157
+ }
111
158
  }
112
159
  }
113
160
  };
@@ -116,7 +163,7 @@ var script = {
116
163
  const __vue_script__ = script;
117
164
 
118
165
  /* template */
119
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-h-auto gl-filtered-search-term",attrs:{"data-testid":"filtered-search-term"}},[_c('gl-filtered-search-token-segment',{ref:"segment",staticClass:"gl-filtered-search-term-token",attrs:{"is-term":"","active":_vm.active,"cursor-position":_vm.cursorPosition,"search-input-attributes":_vm.searchInputAttributes,"is-last-token":_vm.isLastToken,"current-value":_vm.currentValue,"view-only":_vm.viewOnly,"options":_vm.suggestedTokens},on:{"activate":function($event){return _vm.$emit('activate')},"deactivate":function($event){return _vm.$emit('deactivate')},"complete":function($event){return _vm.$emit('replace', { type: $event })},"backspace":_vm.onBackspace,"submit":function($event){return _vm.$emit('submit')},"split":function($event){return _vm.$emit('split', $event)},"previous":function($event){return _vm.$emit('previous')},"next":function($event){return _vm.$emit('next')}},scopedSlots:_vm._u([{key:"view",fn:function(){return [(_vm.placeholder)?_c('input',_vm._b({staticClass:"gl-filtered-search-term-input",class:{ 'gl-bg-gray-10': _vm.viewOnly },attrs:{"placeholder":_vm.placeholder,"aria-label":_vm.placeholder,"readonly":_vm.viewOnly,"data-testid":"filtered-search-term-input"},on:{"focusin":function($event){return _vm.$emit('activate')},"focusout":function($event){return _vm.$emit('deactivate')}}},'input',_vm.searchInputAttributes,false)):[_vm._v(_vm._s(_vm.value.data))]]},proxy:true}]),model:{value:(_vm.internalValue),callback:function ($$v) {_vm.internalValue=$$v;},expression:"internalValue"}})],1)};
166
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-h-auto gl-filtered-search-term",attrs:{"data-testid":"filtered-search-term"}},[_c('gl-filtered-search-token-segment',{ref:"segment",staticClass:"gl-filtered-search-term-token",attrs:{"is-term":"","active":_vm.active,"cursor-position":_vm.cursorPosition,"search-input-attributes":_vm.searchInputAttributes,"is-last-token":_vm.isLastToken,"current-value":_vm.currentValue,"view-only":_vm.viewOnly,"options":_vm.suggestedTokens},on:{"activate":function($event){return _vm.$emit('activate')},"deactivate":function($event){return _vm.$emit('deactivate')},"complete":_vm.onComplete,"backspace":_vm.onBackspace,"submit":function($event){return _vm.$emit('submit')},"split":function($event){return _vm.$emit('split', $event)},"previous":function($event){return _vm.$emit('previous')},"next":function($event){return _vm.$emit('next')}},scopedSlots:_vm._u([{key:"view",fn:function(){return [(_vm.showToken)?_c('gl-token',_vm._g({class:{ 'gl-cursor-pointer': !_vm.viewOnly },attrs:{"view-only":_vm.viewOnly}},_vm.eventListeners),[_vm._v(_vm._s(_vm.value.data))]):(_vm.showInput)?_c('input',_vm._b({staticClass:"gl-filtered-search-term-input",class:{ 'gl-bg-gray-10': _vm.viewOnly },attrs:{"placeholder":_vm.placeholder,"aria-label":_vm.placeholder,"readonly":_vm.viewOnly,"data-testid":"filtered-search-term-input"},on:{"focusin":function($event){return _vm.$emit('activate')},"focusout":function($event){return _vm.$emit('deactivate')}}},'input',_vm.searchInputAttributes,false)):[_vm._v(_vm._s(_vm.value.data))]]},proxy:true}]),model:{value:(_vm.internalValue),callback:function ($$v) {_vm.internalValue=$$v;},expression:"internalValue"}})],1)};
120
167
  var __vue_staticRenderFns__ = [];
121
168
 
122
169
  /* style */
@@ -2,13 +2,12 @@ import cloneDeep from 'lodash/cloneDeep';
2
2
  import { COMMA } from '../../../utils/constants';
3
3
  import GlToken from '../token/token';
4
4
  import GlFilteredSearchTokenSegment from './filtered_search_token_segment';
5
- import { tokenToOption, createTerm } from './filtered_search_utils';
5
+ import { tokenToOption, createTerm, TOKEN_CLOSE_SELECTOR } from './filtered_search_utils';
6
6
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
7
7
 
8
8
  const SEGMENT_TITLE = 'TYPE';
9
9
  const SEGMENT_OPERATOR = 'OPERATOR';
10
10
  const SEGMENT_DATA = 'DATA';
11
- const TOKEN_CLOSE_SELECTOR = '.gl-token-close';
12
11
  const DEFAULT_OPERATORS = [{
13
12
  value: '=',
14
13
  description: 'is',
@@ -3,7 +3,7 @@ import { Portal } from 'portal-vue';
3
3
  import { COMMA, LEFT_MOUSE_BUTTON } from '../../../utils/constants';
4
4
  import GlFilteredSearchSuggestion from './filtered_search_suggestion';
5
5
  import GlFilteredSearchSuggestionList from './filtered_search_suggestion_list';
6
- import { splitOnQuotes, match, wrapTokenInQuotes } from './filtered_search_utils';
6
+ import { TERM_TOKEN_TYPE, splitOnQuotes, match, wrapTokenInQuotes } from './filtered_search_utils';
7
7
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
8
8
 
9
9
  // We need some helpers to ensure @vue/compat compatibility
@@ -49,7 +49,7 @@ var script = {
49
49
  GlFilteredSearchSuggestionList,
50
50
  GlFilteredSearchSuggestion
51
51
  },
52
- inject: ['portalName', 'alignSuggestions'],
52
+ inject: ['portalName', 'alignSuggestions', 'termsAsTokens'],
53
53
  inheritAttrs: false,
54
54
  props: {
55
55
  /**
@@ -136,6 +136,16 @@ var script = {
136
136
  };
137
137
  },
138
138
  computed: {
139
+ hasTermSuggestion() {
140
+ if (!this.termsAsTokens()) return false;
141
+ if (!this.options) return false;
142
+ return this.options.some(_ref => {
143
+ let {
144
+ value
145
+ } = _ref;
146
+ return value === TERM_TOKEN_TYPE;
147
+ });
148
+ },
139
149
  matchingOption() {
140
150
  var _this$options;
141
151
  return (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.find(o => o.value === this.value);
@@ -173,7 +183,9 @@ var script = {
173
183
  const option = this.getMatchingOptionForInputValue(this.inputValue) || this.getMatchingOptionForInputValue(this.inputValue, {
174
184
  loose: true
175
185
  });
176
- return option === null || option === void 0 ? void 0 : option.value;
186
+ if (option) return option.value;
187
+ if (this.hasTermSuggestion) return TERM_TOKEN_TYPE;
188
+ return null;
177
189
  }
178
190
  const defaultOption = this.options.find(op => op.default);
179
191
  if (defaultOption) {
@@ -197,6 +209,7 @@ var script = {
197
209
  }
198
210
  },
199
211
  inputValue(newValue) {
212
+ if (this.termsAsTokens()) return;
200
213
  const hasUnclosedQuote = newValue.split('"').length % 2 === 0;
201
214
  if (newValue.indexOf(' ') === -1 || hasUnclosedQuote) {
202
215
  return;
@@ -260,7 +273,7 @@ var script = {
260
273
  }
261
274
  },
262
275
  applySuggestion(suggestedValue) {
263
- const formattedSuggestedValue = wrapTokenInQuotes(suggestedValue);
276
+ const formattedSuggestedValue = this.termsAsTokens() ? suggestedValue : wrapTokenInQuotes(suggestedValue);
264
277
 
265
278
  /**
266
279
  * Emitted when autocomplete entry is selected.
@@ -269,7 +282,7 @@ var script = {
269
282
  */
270
283
  this.$emit('select', formattedSuggestedValue);
271
284
  if (!this.multiSelect) {
272
- this.$emit('input', formattedSuggestedValue);
285
+ this.$emit('input', formattedSuggestedValue === TERM_TOKEN_TYPE ? this.inputValue : formattedSuggestedValue);
273
286
  this.$emit('complete', formattedSuggestedValue);
274
287
  }
275
288
  },
@@ -5,6 +5,7 @@ import { modulo } from '../../../utils/number_utils';
5
5
 
6
6
  const TERM_TOKEN_TYPE = 'filtered-search-term';
7
7
  const INTENT_ACTIVATE_PREVIOUS = 'intent-activate-previous';
8
+ const TOKEN_CLOSE_SELECTOR = '.gl-token-close';
8
9
  function isEmptyTerm(token) {
9
10
  return token.type === TERM_TOKEN_TYPE && token.value.data.trim() === '';
10
11
  }
@@ -137,18 +138,23 @@ function createTerm() {
137
138
  };
138
139
  }
139
140
  function denormalizeTokens(inputTokens) {
141
+ let termsAsTokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
140
142
  assertValidTokens(inputTokens);
141
143
  const tokens = Array.isArray(inputTokens) ? inputTokens : [inputTokens];
142
- const result = [];
143
- tokens.forEach(t => {
144
+ return tokens.reduce((result, t) => {
144
145
  if (typeof t === 'string') {
145
- const stringTokens = t.split(' ').filter(Boolean);
146
- stringTokens.forEach(strToken => result.push(createTerm(strToken)));
146
+ if (termsAsTokens) {
147
+ const trimmedText = t.trim();
148
+ if (trimmedText) result.push(createTerm(trimmedText));
149
+ } else {
150
+ const stringTokens = t.split(' ').filter(Boolean);
151
+ stringTokens.forEach(strToken => result.push(createTerm(strToken)));
152
+ }
147
153
  } else {
148
154
  result.push(ensureTokenId(t));
149
155
  }
150
- });
151
- return result;
156
+ return result;
157
+ }, []);
152
158
  }
153
159
 
154
160
  /**
@@ -163,6 +169,11 @@ function denormalizeTokens(inputTokens) {
163
169
  function match(text, query) {
164
170
  return text.toLowerCase().includes(query.toLowerCase());
165
171
  }
172
+ const termTokenDefinition = {
173
+ type: TERM_TOKEN_TYPE,
174
+ icon: 'title',
175
+ title: 'Search for this text'
176
+ };
166
177
  function splitOnQuotes(str) {
167
178
  if (first(str) === "'" && last(str) === "'") {
168
179
  return [str];
@@ -228,4 +239,4 @@ function wrapTokenInQuotes(token) {
228
239
  return `"${token}"`;
229
240
  }
230
241
 
231
- export { INTENT_ACTIVATE_PREVIOUS, TERM_TOKEN_TYPE, createTerm, denormalizeTokens, ensureTokenId, isEmptyTerm, match, needDenormalization, normalizeTokens, splitOnQuotes, stepIndexAndWrap, tokenToOption, wrapTokenInQuotes };
242
+ export { INTENT_ACTIVATE_PREVIOUS, TERM_TOKEN_TYPE, TOKEN_CLOSE_SELECTOR, createTerm, denormalizeTokens, ensureTokenId, isEmptyTerm, match, needDenormalization, normalizeTokens, splitOnQuotes, stepIndexAndWrap, termTokenDefinition, tokenToOption, wrapTokenInQuotes };
@@ -130,7 +130,7 @@ var script = {
130
130
  const __vue_script__ = script;
131
131
 
132
132
  /* template */
133
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-display-flex gl-flex-wrap-nowrap gl-align-items-flex-start gl-w-full"},[_c('div',{ref:"tokenContainer",staticClass:"gl-display-flex gl-flex-wrap gl-align-items-center gl-my-n1 gl-mx-n1 gl-w-full",attrs:{"role":"listbox","aria-multiselectable":"false","aria-orientation":"horizontal","aria-invalid":_vm.state === false && 'true'},on:{"keydown":[function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"left",37,$event.key,["Left","ArrowLeft"])){ return null; }if('button' in $event && $event.button !== 0){ return null; }return _vm.handleLeftArrow.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"right",39,$event.key,["Right","ArrowRight"])){ return null; }if('button' in $event && $event.button !== 2){ return null; }return _vm.handleRightArrow.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"home",undefined,$event.key,undefined)){ return null; }return _vm.handleHome.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"end",undefined,$event.key,undefined)){ return null; }return _vm.handleEnd.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete","Del"])){ return null; }return _vm.handleDelete.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }return _vm.handleEscape.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"tab",9,$event.key,"Tab")){ return null; }if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey){ return null; }$event.preventDefault();return _vm.handleTab.apply(null, arguments)}]}},[_vm._l((_vm.tokens),function(token,index){return _c('div',{key:token.id,ref:"tokens",refInFor:true,staticClass:"gl-token-selector-token-container gl-px-1 gl-py-2 gl-outline-none",attrs:{"data-token-id":token.id,"role":"option","tabindex":"-1"},on:{"focus":function($event){_vm.bindFocusEvent ? _vm.handleTokenFocus(index) : null;}}},[_c('gl-token',{staticClass:"gl-cursor-default",class:token.class,style:(token.style),attrs:{"view-only":_vm.viewOnly},on:{"close":function($event){return _vm.handleClose(token)}}},[_vm._t("token-content",function(){return [_c('span',[_vm._v("\n "+_vm._s(token.name)+"\n ")])]},{"token":token})],2)],1)}),_vm._v(" "),_vm._t("text-input")],2),_vm._v(" "),(_vm.showClearAllButton)?_c('div',{staticClass:"gl-ml-3 gl-p-1"},[_c('gl-button',{attrs:{"size":"small","aria-label":"Clear all","icon":"clear","category":"tertiary","data-testid":"clear-all-button"},on:{"click":function($event){$event.stopPropagation();return _vm.$emit('clear-all')}}})],1):_vm._e()])};
133
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"gl-display-flex gl-flex-nowrap gl-align-items-flex-start gl-w-full"},[_c('div',{ref:"tokenContainer",staticClass:"gl-display-flex gl-flex-wrap gl-align-items-center gl-my-n1 gl-mx-n1 gl-w-full",attrs:{"role":"listbox","aria-multiselectable":"false","aria-orientation":"horizontal","aria-invalid":_vm.state === false && 'true'},on:{"keydown":[function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"left",37,$event.key,["Left","ArrowLeft"])){ return null; }if('button' in $event && $event.button !== 0){ return null; }return _vm.handleLeftArrow.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"right",39,$event.key,["Right","ArrowRight"])){ return null; }if('button' in $event && $event.button !== 2){ return null; }return _vm.handleRightArrow.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"home",undefined,$event.key,undefined)){ return null; }return _vm.handleHome.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"end",undefined,$event.key,undefined)){ return null; }return _vm.handleEnd.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"delete",[8,46],$event.key,["Backspace","Delete","Del"])){ return null; }return _vm.handleDelete.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"esc",27,$event.key,["Esc","Escape"])){ return null; }return _vm.handleEscape.apply(null, arguments)},function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"tab",9,$event.key,"Tab")){ return null; }if($event.ctrlKey||$event.shiftKey||$event.altKey||$event.metaKey){ return null; }$event.preventDefault();return _vm.handleTab.apply(null, arguments)}]}},[_vm._l((_vm.tokens),function(token,index){return _c('div',{key:token.id,ref:"tokens",refInFor:true,staticClass:"gl-token-selector-token-container gl-px-1 gl-py-2 gl-outline-none",attrs:{"data-token-id":token.id,"role":"option","tabindex":"-1"},on:{"focus":function($event){_vm.bindFocusEvent ? _vm.handleTokenFocus(index) : null;}}},[_c('gl-token',{staticClass:"gl-cursor-default",class:token.class,style:(token.style),attrs:{"view-only":_vm.viewOnly},on:{"close":function($event){return _vm.handleClose(token)}}},[_vm._t("token-content",function(){return [_c('span',[_vm._v("\n "+_vm._s(token.name)+"\n ")])]},{"token":token})],2)],1)}),_vm._v(" "),_vm._t("text-input")],2),_vm._v(" "),(_vm.showClearAllButton)?_c('div',{staticClass:"gl-ml-3 gl-p-1"},[_c('gl-button',{attrs:{"size":"small","aria-label":"Clear all","icon":"clear","category":"tertiary","data-testid":"clear-all-button"},on:{"click":function($event){$event.stopPropagation();return _vm.$emit('clear-all')}}})],1):_vm._e()])};
134
134
  var __vue_staticRenderFns__ = [];
135
135
 
136
136
  /* style */