@vaadin/combo-box 23.2.0-alpha2 → 23.2.0-dev.48e5e3967

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/combo-box",
3
- "version": "23.2.0-alpha2",
3
+ "version": "23.2.0-dev.48e5e3967",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -36,23 +36,23 @@
36
36
  "dependencies": {
37
37
  "@open-wc/dedupe-mixin": "^1.3.0",
38
38
  "@polymer/polymer": "^3.0.0",
39
- "@vaadin/component-base": "23.2.0-alpha2",
40
- "@vaadin/field-base": "23.2.0-alpha2",
41
- "@vaadin/input-container": "23.2.0-alpha2",
42
- "@vaadin/item": "23.2.0-alpha2",
43
- "@vaadin/lit-renderer": "23.2.0-alpha2",
44
- "@vaadin/vaadin-lumo-styles": "23.2.0-alpha2",
45
- "@vaadin/vaadin-material-styles": "23.2.0-alpha2",
46
- "@vaadin/vaadin-overlay": "23.2.0-alpha2",
47
- "@vaadin/vaadin-themable-mixin": "23.2.0-alpha2"
39
+ "@vaadin/component-base": "23.2.0-dev.48e5e3967",
40
+ "@vaadin/field-base": "23.2.0-dev.48e5e3967",
41
+ "@vaadin/input-container": "23.2.0-dev.48e5e3967",
42
+ "@vaadin/item": "23.2.0-dev.48e5e3967",
43
+ "@vaadin/lit-renderer": "23.2.0-dev.48e5e3967",
44
+ "@vaadin/vaadin-lumo-styles": "23.2.0-dev.48e5e3967",
45
+ "@vaadin/vaadin-material-styles": "23.2.0-dev.48e5e3967",
46
+ "@vaadin/vaadin-overlay": "23.2.0-dev.48e5e3967",
47
+ "@vaadin/vaadin-themable-mixin": "23.2.0-dev.48e5e3967"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@esm-bundle/chai": "^4.3.4",
51
- "@vaadin/polymer-legacy-adapter": "23.2.0-alpha2",
51
+ "@vaadin/polymer-legacy-adapter": "23.2.0-dev.48e5e3967",
52
52
  "@vaadin/testing-helpers": "^0.3.2",
53
- "@vaadin/text-field": "23.2.0-alpha2",
53
+ "@vaadin/text-field": "23.2.0-dev.48e5e3967",
54
54
  "lit": "^2.0.0",
55
55
  "sinon": "^13.0.2"
56
56
  },
57
- "gitHead": "c9b8113d0fa9a602f8b9cb915c1826355af2e8df"
57
+ "gitHead": "961bc4ae5b707c3c02f12b99819b3c12c9b478aa"
58
58
  }
@@ -62,13 +62,17 @@ export const ComboBoxDataProviderMixin = (superClass) =>
62
62
  __placeHolder: {
63
63
  value: new ComboBoxPlaceholder(),
64
64
  },
65
+
66
+ /** @private */
67
+ __previousDataProviderFilter: {
68
+ type: String,
69
+ },
65
70
  };
66
71
  }
67
72
 
68
73
  static get observers() {
69
74
  return [
70
- '_dataProviderFilterChanged(filter, dataProvider)',
71
- '_dataProviderClearFilter(dataProvider, opened, value)',
75
+ '_dataProviderFilterChanged(filter)',
72
76
  '_warnDataProviderValue(dataProvider, value)',
73
77
  '_ensureFirstPage(opened)',
74
78
  ];
@@ -77,7 +81,6 @@ export const ComboBoxDataProviderMixin = (superClass) =>
77
81
  /** @protected */
78
82
  ready() {
79
83
  super.ready();
80
- this.clearCache();
81
84
  this._scroller.addEventListener('index-requested', (e) => {
82
85
  const index = e.detail.index;
83
86
  const currentScrollerPos = e.detail.currentScrollerPos;
@@ -101,38 +104,25 @@ export const ComboBoxDataProviderMixin = (superClass) =>
101
104
  }
102
105
 
103
106
  /** @private */
104
- _dataProviderFilterChanged() {
105
- if (!this._shouldFetchData()) {
107
+ _dataProviderFilterChanged(filter) {
108
+ if (this.__previousDataProviderFilter === undefined && filter === '') {
109
+ this.__previousDataProviderFilter = filter;
106
110
  return;
107
111
  }
108
112
 
109
- this._refreshData();
110
- }
113
+ if (this.__previousDataProviderFilter !== filter) {
114
+ this.__previousDataProviderFilter = filter;
111
115
 
112
- /** @private */
113
- _dataProviderClearFilter(dataProvider, opened, value) {
114
- // Can't depend on filter in this observer as we don't want
115
- // to clear the filter whenever it's set
116
- if (dataProvider && !this.loading && this.filter && !(opened && this.autoOpenDisabled && value === this.filter)) {
117
- this._refreshData(true);
118
- }
119
- }
116
+ this._pendingRequests = {};
117
+ // Immediately mark as loading if this refresh leads to re-fetching pages
118
+ // This prevents some issues with the properties below triggering
119
+ // observers that also rely on the loading state
120
+ this.loading = this._shouldFetchData();
121
+ // Reset size and internal loading state
122
+ this.size = undefined;
120
123
 
121
- /** @private */
122
- _refreshData(clearFilter) {
123
- // Immediately mark as loading if this refresh leads to re-fetching pages
124
- // This prevents some issues with the properties below triggering
125
- // observers that also rely on the loading state
126
- this.loading = this._shouldFetchData();
127
- // Reset size and internal loading state
128
- this.size = undefined;
129
- this._pendingRequests = {};
130
- // Clear filter if requested
131
- if (clearFilter) {
132
- this.filter = '';
124
+ this.clearCache();
133
125
  }
134
- // Clear cached pages, and reload current page if we need the data
135
- this.clearCache();
136
126
  }
137
127
 
138
128
  /** @private */
@@ -229,13 +219,16 @@ export const ComboBoxDataProviderMixin = (superClass) =>
229
219
  if (!this.dataProvider) {
230
220
  return;
231
221
  }
222
+
232
223
  this._pendingRequests = {};
233
224
  const filteredItems = [];
234
225
  for (let i = 0; i < (this.size || 0); i++) {
235
226
  filteredItems.push(this.__placeHolder);
236
227
  }
237
228
  this.filteredItems = filteredItems;
229
+
238
230
  if (this._shouldFetchData()) {
231
+ this._forceNextRequest = false;
239
232
  this._loadPage(0);
240
233
  } else {
241
234
  this._forceNextRequest = true;
@@ -269,6 +262,8 @@ export const ComboBoxDataProviderMixin = (superClass) =>
269
262
  this._ensureItemsOrDataProvider(() => {
270
263
  this.dataProvider = oldDataProvider;
271
264
  });
265
+
266
+ this.clearCache();
272
267
  }
273
268
 
274
269
  /** @private */
@@ -6,6 +6,7 @@
6
6
  import { DisabledMixinClass } from '@vaadin/component-base/src/disabled-mixin.js';
7
7
  import { KeyboardMixinClass } from '@vaadin/component-base/src/keyboard-mixin.js';
8
8
  import { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
9
+ import { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
9
10
  import { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
10
11
  import { ComboBoxDataProviderMixinClass } from './vaadin-combo-box-data-provider-mixin.js';
11
12
  import { ComboBoxMixinClass } from './vaadin-combo-box-mixin.js';
@@ -142,7 +143,8 @@ interface ComboBoxLight<TItem = ComboBoxDefaultItem>
142
143
  KeyboardMixinClass,
143
144
  InputMixinClass,
144
145
  DisabledMixinClass,
145
- ThemableMixinClass {}
146
+ ThemableMixinClass,
147
+ ValidateMixinClass {}
146
148
 
147
149
  declare global {
148
150
  interface HTMLElementTagNameMap {
@@ -8,6 +8,7 @@ import './vaadin-combo-box-overlay.js';
8
8
  import './vaadin-combo-box-scroller.js';
9
9
  import { dashToCamelCase } from '@polymer/polymer/lib/utils/case-map.js';
10
10
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
11
+ import { ValidateMixin } from '@vaadin/field-base/src/validate-mixin.js';
11
12
  import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
12
13
  import { ComboBoxDataProviderMixin } from './vaadin-combo-box-data-provider-mixin.js';
13
14
  import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
@@ -61,8 +62,9 @@ import { ComboBoxMixin } from './vaadin-combo-box-mixin.js';
61
62
  * @mixes ComboBoxDataProviderMixin
62
63
  * @mixes ComboBoxMixin
63
64
  * @mixes ThemableMixin
65
+ * @mixes ValidateMixin
64
66
  */
65
- class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ThemableMixin(PolymerElement))) {
67
+ class ComboBoxLight extends ComboBoxDataProviderMixin(ComboBoxMixin(ValidateMixin(ThemableMixin(PolymerElement)))) {
66
68
  static get is() {
67
69
  return 'vaadin-combo-box-light';
68
70
  }
@@ -138,11 +138,6 @@ export declare class ComboBoxMixinClass<TItem> {
138
138
  */
139
139
  itemIdPath: string | null | undefined;
140
140
 
141
- /**
142
- * Set to true if the value is invalid.
143
- */
144
- invalid: boolean;
145
-
146
141
  protected readonly _propertyForValue: string;
147
142
 
148
143
  protected _inputElementValue: string | undefined;
@@ -236,7 +236,6 @@ export const ComboBoxMixin = (subclass) =>
236
236
 
237
237
  static get observers() {
238
238
  return [
239
- '_filterChanged(filter, itemValuePath, itemLabelPath)',
240
239
  '_selectedItemChanged(selectedItem, itemValuePath, itemLabelPath)',
241
240
  '_openedOrItemsChanged(opened, filteredItems, loading)',
242
241
  '_updateScroller(_scroller, filteredItems, opened, loading, selectedItem, itemIdPath, _focusedIndex, renderer, theme)',
@@ -382,6 +381,25 @@ export const ComboBoxMixin = (subclass) =>
382
381
  this.opened = false;
383
382
  }
384
383
 
384
+ /**
385
+ * Override Polymer lifecycle callback to handle `filter` property change after
386
+ * the observer for `opened` property is triggered. This is needed when opening
387
+ * combo-box on user input to ensure the focused index is set correctly.
388
+ *
389
+ * @param {!Object} currentProps Current accessor values
390
+ * @param {?Object} changedProps Properties changed since the last call
391
+ * @param {?Object} oldProps Previous values for each changed property
392
+ * @protected
393
+ * @override
394
+ */
395
+ _propertiesChanged(currentProps, changedProps, oldProps) {
396
+ super._propertiesChanged(currentProps, changedProps, oldProps);
397
+
398
+ if (changedProps.filter !== undefined) {
399
+ this._filterChanged(changedProps.filter);
400
+ }
401
+ }
402
+
385
403
  /** @private */
386
404
  _initOverlay() {
387
405
  const overlay = this.$.overlay;
@@ -926,9 +944,7 @@ export const ComboBoxMixin = (subclass) =>
926
944
 
927
945
  this._clearSelectionRange();
928
946
 
929
- if (!this.dataProvider) {
930
- this.filter = '';
931
- }
947
+ this.filter = '';
932
948
  }
933
949
 
934
950
  /**
@@ -946,19 +962,27 @@ export const ComboBoxMixin = (subclass) =>
946
962
  * @override
947
963
  */
948
964
  _onInput(event) {
949
- if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
950
- this.open();
951
- }
965
+ const filter = this._inputElementValue;
966
+
967
+ // When opening dropdown on user input, both `opened` and `filter` properties are set.
968
+ // Perform a batched property update instead of relying on sync property observers.
969
+ // This is necessary to avoid an extra data-provider request for loading first page.
970
+ const props = {};
952
971
 
953
- const value = this._inputElementValue;
954
- if (this.filter === value) {
972
+ if (this.filter === filter) {
955
973
  // Filter and input value might get out of sync, while keyboard navigating for example.
956
974
  // Afterwards, input value might be changed to the same value as used in filtering.
957
975
  // In situation like these, we need to make sure all the filter changes handlers are run.
958
- this._filterChanged(this.filter, this.itemValuePath, this.itemLabelPath);
976
+ this._filterChanged(this.filter);
959
977
  } else {
960
- this.filter = value;
978
+ props.filter = filter;
961
979
  }
980
+
981
+ if (!this.opened && !this._isClearButton(event) && !this.autoOpenDisabled) {
982
+ props.opened = true;
983
+ }
984
+
985
+ this.setProperties(props);
962
986
  }
963
987
 
964
988
  /**
@@ -981,11 +1005,7 @@ export const ComboBoxMixin = (subclass) =>
981
1005
  }
982
1006
 
983
1007
  /** @private */
984
- _filterChanged(filter, _itemValuePath, _itemLabelPath) {
985
- if (filter === undefined) {
986
- return;
987
- }
988
-
1008
+ _filterChanged(filter) {
989
1009
  // Scroll to the top of the list whenever the filter changes.
990
1010
  this._scrollIntoView(0);
991
1011
 
@@ -1064,14 +1084,11 @@ export const ComboBoxMixin = (subclass) =>
1064
1084
  }
1065
1085
 
1066
1086
  if (isValidValue(value)) {
1067
- let item;
1068
1087
  if (this._getItemValue(this.selectedItem) !== value) {
1069
1088
  this._selectItemForValue(value);
1070
- } else {
1071
- item = this.selectedItem;
1072
1089
  }
1073
1090
 
1074
- if (!item && this.allowCustomValue) {
1091
+ if (!this.selectedItem && this.allowCustomValue) {
1075
1092
  this._inputElementValue = value;
1076
1093
  }
1077
1094
 
@@ -1079,6 +1096,9 @@ export const ComboBoxMixin = (subclass) =>
1079
1096
  } else {
1080
1097
  this.selectedItem = null;
1081
1098
  }
1099
+
1100
+ this.filter = '';
1101
+
1082
1102
  // In the next _detectAndDispatchChange() call, the change detection should pass
1083
1103
  this._lastCommittedValue = undefined;
1084
1104
  }
@@ -1277,29 +1297,6 @@ export const ComboBoxMixin = (subclass) =>
1277
1297
  this._clear();
1278
1298
  }
1279
1299
 
1280
- /**
1281
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
1282
- *
1283
- * @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
1284
- */
1285
- validate() {
1286
- return !(this.invalid = !this.checkValidity());
1287
- }
1288
-
1289
- /**
1290
- * Returns true if the current input value satisfies all constraints (if any).
1291
- * You can override this method for custom validations.
1292
- *
1293
- * @return {boolean}
1294
- */
1295
- checkValidity() {
1296
- if (super.checkValidity) {
1297
- return super.checkValidity();
1298
- }
1299
-
1300
- return !this.required || !!this.value;
1301
- }
1302
-
1303
1300
  /**
1304
1301
  * Fired when the value changes.
1305
1302
  *
@@ -165,6 +165,7 @@ export interface ComboBoxEventMap<TItem> extends HTMLElementEventMap {
165
165
  * Custom property | Description | Default
166
166
  * ----------------------------------------|----------------------------|---------
167
167
  * `--vaadin-field-default-width` | Default width of the field | `12em`
168
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
168
169
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
169
170
  *
170
171
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
@@ -104,6 +104,7 @@ registerStyles('vaadin-combo-box', inputFieldShared, { moduleId: 'vaadin-combo-b
104
104
  * Custom property | Description | Default
105
105
  * ----------------------------------------|----------------------------|---------
106
106
  * `--vaadin-field-default-width` | Default width of the field | `12em`
107
+ * `--vaadin-combo-box-overlay-width` | Width of the overlay | `auto`
107
108
  * `--vaadin-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
108
109
  *
109
110
  * `<vaadin-combo-box>` provides the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.