@vaadin/multi-select-combo-box 23.1.0 → 23.2.0-alpha2

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/lit.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './src/lit/renderer-directives.js';
package/lit.js ADDED
@@ -0,0 +1 @@
1
+ export * from './src/lit/renderer-directives.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/multi-select-combo-box",
3
- "version": "23.1.0",
3
+ "version": "23.2.0-alpha2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,6 +19,8 @@
19
19
  "main": "vaadin-multi-select-combo-box.js",
20
20
  "module": "vaadin-multi-select-combo-box.js",
21
21
  "files": [
22
+ "lit.js",
23
+ "lit.d.ts",
22
24
  "src",
23
25
  "theme",
24
26
  "vaadin-*.d.ts",
@@ -33,18 +35,19 @@
33
35
  ],
34
36
  "dependencies": {
35
37
  "@polymer/polymer": "^3.0.0",
36
- "@vaadin/combo-box": "^23.1.0",
37
- "@vaadin/component-base": "^23.1.0",
38
- "@vaadin/field-base": "^23.1.0",
39
- "@vaadin/input-container": "^23.1.0",
40
- "@vaadin/vaadin-lumo-styles": "^23.1.0",
41
- "@vaadin/vaadin-material-styles": "^23.1.0",
42
- "@vaadin/vaadin-themable-mixin": "^23.1.0"
38
+ "@vaadin/combo-box": "23.2.0-alpha2",
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/lit-renderer": "23.2.0-alpha2",
43
+ "@vaadin/vaadin-lumo-styles": "23.2.0-alpha2",
44
+ "@vaadin/vaadin-material-styles": "23.2.0-alpha2",
45
+ "@vaadin/vaadin-themable-mixin": "23.2.0-alpha2"
43
46
  },
44
47
  "devDependencies": {
45
48
  "@esm-bundle/chai": "^4.3.4",
46
49
  "@vaadin/testing-helpers": "^0.3.2",
47
50
  "sinon": "^13.0.2"
48
51
  },
49
- "gitHead": "322bba42b83f908a78cd972b06acadc5da95a69d"
52
+ "gitHead": "c9b8113d0fa9a602f8b9cb915c1826355af2e8df"
50
53
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { TemplateResult } from 'lit';
7
+ import { DirectiveResult } from 'lit/directive.js';
8
+ import { ComboBoxItemModel } from '@vaadin/combo-box/src/vaadin-combo-box.js';
9
+ import { LitRendererDirective } from '@vaadin/lit-renderer';
10
+ import { MultiSelectComboBox } from '../vaadin-multi-select-combo-box.js';
11
+
12
+ export type MultiSelectComboBoxLitRenderer<TItem> = (
13
+ item: TItem,
14
+ model: ComboBoxItemModel<TItem>,
15
+ comboBox: MultiSelectComboBox<TItem>,
16
+ ) => TemplateResult;
17
+
18
+ export class MultiSelectComboBoxRendererDirective<TItem> extends LitRendererDirective<
19
+ MultiSelectComboBox,
20
+ MultiSelectComboBoxLitRenderer<TItem>
21
+ > {
22
+ /**
23
+ * Adds the renderer callback to the combo-box.
24
+ */
25
+ addRenderer(): void;
26
+
27
+ /**
28
+ * Runs the renderer callback on the combo-box.
29
+ */
30
+ runRenderer(): void;
31
+
32
+ /**
33
+ * Removes the renderer callback from the combo-box.
34
+ */
35
+ removeRenderer(): void;
36
+ }
37
+
38
+ /**
39
+ * A Lit directive for rendering the content of the `<vaadin-multi-select-combo-box-item>` elements.
40
+ *
41
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the combo-box
42
+ * via the `renderer` property. The renderer is called for each combo-box item when assigned
43
+ * and whenever a single dependency or an array of dependencies changes.
44
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
45
+ *
46
+ * Dependencies can be a single value or an array of values.
47
+ * Values are checked against previous values with strict equality (`===`),
48
+ * so the check won't detect nested property changes inside objects or arrays.
49
+ * When dependencies are provided as an array, each item is checked against the previous value
50
+ * at the same index with strict equality. Nested arrays are also checked only by strict
51
+ * equality.
52
+ *
53
+ * Example of usage:
54
+ * ```js
55
+ * `<vaadin-multi-select-combo-box
56
+ * ${multiSelectComboBoxRenderer((item, model, comboBox) => html`...`)}
57
+ * ></vaadin-multi-select-combo-box>`
58
+ * ```
59
+ *
60
+ * @param renderer the renderer callback that returns a Lit template.
61
+ * @param dependencies a single dependency or an array of dependencies
62
+ * which trigger a re-render when changed.
63
+ */
64
+ export declare function multiSelectComboBoxRenderer<TItem>(
65
+ renderer: MultiSelectComboBoxLitRenderer<TItem>,
66
+ dependencies?: unknown,
67
+ ): DirectiveResult<typeof MultiSelectComboBoxRendererDirective>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2022 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { directive } from 'lit/directive.js';
7
+ import { LitRendererDirective } from '@vaadin/lit-renderer';
8
+
9
+ export class MultiSelectComboBoxRendererDirective extends LitRendererDirective {
10
+ /**
11
+ * Adds the renderer callback to the combo-box.
12
+ */
13
+ addRenderer() {
14
+ this.element.renderer = (root, comboBox, model) => {
15
+ this.renderRenderer(root, model.item, model, comboBox);
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Runs the renderer callback on the combo-box.
21
+ */
22
+ runRenderer() {
23
+ this.element.requestContentUpdate();
24
+ }
25
+
26
+ /**
27
+ * Removes the renderer callback from the combo-box.
28
+ */
29
+ removeRenderer() {
30
+ this.element.renderer = null;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * A Lit directive for rendering the content of the `<vaadin-multi-select-combo-box-item>` elements.
36
+ *
37
+ * The directive accepts a renderer callback returning a Lit template and assigns it to the combo-box
38
+ * via the `renderer` property. The renderer is called for each combo-box item when assigned
39
+ * and whenever a single dependency or an array of dependencies changes.
40
+ * It is not guaranteed that the renderer will be called immediately (synchronously) in both cases.
41
+ *
42
+ * Dependencies can be a single value or an array of values.
43
+ * Values are checked against previous values with strict equality (`===`),
44
+ * so the check won't detect nested property changes inside objects or arrays.
45
+ * When dependencies are provided as an array, each item is checked against the previous value
46
+ * at the same index with strict equality. Nested arrays are also checked only by strict
47
+ * equality.
48
+ *
49
+ * Example of usage:
50
+ * ```js
51
+ * `<vaadin-multi-select-combo-box
52
+ * ${multiSelectComboBoxRenderer((item, model, comboBox) => html`...`)}
53
+ * ></vaadin-multi-select-combo-box>`
54
+ * ```
55
+ *
56
+ * @param renderer the renderer callback that returns a Lit template.
57
+ * @param dependencies a single dependency or an array of dependencies
58
+ * which trigger a re-render when changed.
59
+ */
60
+ export const multiSelectComboBoxRenderer = directive(MultiSelectComboBoxRendererDirective);
@@ -3,7 +3,9 @@
3
3
  * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import './vaadin-multi-select-combo-box-dropdown.js';
6
+ import './vaadin-multi-select-combo-box-item.js';
7
+ import './vaadin-multi-select-combo-box-overlay.js';
8
+ import './vaadin-multi-select-combo-box-scroller.js';
7
9
  import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
8
10
  import { ComboBoxDataProviderMixin } from '@vaadin/combo-box/src/vaadin-combo-box-data-provider-mixin.js';
9
11
  import { ComboBoxMixin } from '@vaadin/combo-box/src/vaadin-combo-box-mixin.js';
@@ -34,22 +36,29 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
34
36
 
35
37
  <slot></slot>
36
38
 
37
- <vaadin-multi-select-combo-box-dropdown
38
- id="dropdown"
39
- opened="[[opened]]"
39
+ <vaadin-multi-select-combo-box-overlay
40
+ id="overlay"
41
+ hidden$="[[_isOverlayHidden(filteredItems, loading)]]"
42
+ opened="[[_overlayOpened]]"
43
+ loading$="[[loading]]"
44
+ theme$="[[_theme]]"
40
45
  position-target="[[_target]]"
41
- renderer="[[renderer]]"
42
- _focused-index="[[_focusedIndex]]"
43
- _item-id-path="[[itemIdPath]]"
44
- _item-label-path="[[itemLabelPath]]"
45
- loading="[[loading]]"
46
- theme="[[theme]]"
47
- ></vaadin-multi-select-combo-box-dropdown>
46
+ no-vertical-overlap
47
+ restore-focus-node="[[inputElement]]"
48
+ ></vaadin-multi-select-combo-box-overlay>
48
49
  `;
49
50
  }
50
51
 
51
52
  static get properties() {
52
53
  return {
54
+ /**
55
+ * A subset of items, filtered based on the user input.
56
+ */
57
+ filteredItems: {
58
+ type: Array,
59
+ notify: true,
60
+ },
61
+
53
62
  /**
54
63
  * When set to `true`, "loading" attribute is set
55
64
  * on the host and the overlay element.
@@ -84,10 +93,6 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
84
93
  };
85
94
  }
86
95
 
87
- static get observers() {
88
- return ['_readonlyItemsChanged(readonly, selectedItems)'];
89
- }
90
-
91
96
  /**
92
97
  * Reference to the clear button element.
93
98
  * @protected
@@ -97,6 +102,15 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
97
102
  return this.querySelector('[part="clear-button"]');
98
103
  }
99
104
 
105
+ /**
106
+ * Tag name prefix used by scroller and items.
107
+ * @protected
108
+ * @return {string}
109
+ */
110
+ get _tagNamePrefix() {
111
+ return 'vaadin-multi-select-combo-box';
112
+ }
113
+
100
114
  /**
101
115
  * Override method inherited from the combo-box
102
116
  * to allow opening dropdown when readonly.
@@ -108,14 +122,6 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
108
122
  }
109
123
  }
110
124
 
111
- /**
112
- * @protected
113
- * @override
114
- */
115
- _getItemElements() {
116
- return Array.from(this.$.dropdown._scroller.querySelectorAll('vaadin-multi-select-combo-box-item'));
117
- }
118
-
119
125
  /** @protected */
120
126
  ready() {
121
127
  super.ready();
@@ -124,6 +130,20 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
124
130
  this._toggleElement = this.querySelector('.toggle-button');
125
131
  }
126
132
 
133
+ /**
134
+ * Override combo-box method to set correct owner for using by item renderers.
135
+ * This needs to be done before the scroller gets added to the DOM to ensure
136
+ * Lit directive works in case when combo-box is opened using attribute.
137
+ *
138
+ * @protected
139
+ * @override
140
+ */
141
+ _initScroller() {
142
+ const comboBox = this.getRootNode().host;
143
+
144
+ super._initScroller(comboBox);
145
+ }
146
+
127
147
  /**
128
148
  * Override method from `InputMixin`.
129
149
  *
@@ -270,19 +290,6 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
270
290
  }
271
291
  }
272
292
 
273
- /**
274
- * Override method inherited from the combo-box
275
- * to render only selected items when read-only,
276
- * even if a different set of items is provided.
277
- *
278
- * @protected
279
- * @override
280
- */
281
- _setOverlayItems(items) {
282
- const effectiveItems = this.readonly ? this.selectedItems : items;
283
- super._setOverlayItems(effectiveItems);
284
- }
285
-
286
293
  /**
287
294
  * Override method inherited from the combo-box
288
295
  * to not request data provider when read-only.
@@ -299,20 +306,6 @@ class MultiSelectComboBoxInternal extends ComboBoxDataProviderMixin(ComboBoxMixi
299
306
 
300
307
  return super._shouldLoadPage(page);
301
308
  }
302
-
303
- /** @private */
304
- _readonlyItemsChanged(readonly, selectedItems) {
305
- if (readonly && selectedItems) {
306
- this.__savedItems = this._getOverlayItems();
307
- this._setOverlayItems(selectedItems);
308
- }
309
-
310
- // Restore the original dropdown items
311
- if (readonly === false && this.__savedItems) {
312
- this._setOverlayItems(this.__savedItems);
313
- this.__savedItems = null;
314
- }
315
- }
316
309
  }
317
310
 
318
311
  customElements.define(MultiSelectComboBoxInternal.is, MultiSelectComboBoxInternal);
@@ -153,7 +153,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
153
153
 
154
154
  <vaadin-multi-select-combo-box-internal
155
155
  id="comboBox"
156
- items="[[items]]"
156
+ items="[[__effectiveItems]]"
157
157
  item-id-path="[[itemIdPath]]"
158
158
  item-label-path="[[itemLabelPath]]"
159
159
  item-value-path="[[itemValuePath]]"
@@ -165,7 +165,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
165
165
  filter="{{filter}}"
166
166
  loading="{{loading}}"
167
167
  size="{{size}}"
168
- filtered-items="[[filteredItems]]"
168
+ filtered-items="[[__effectiveFilteredItems]]"
169
169
  selected-items="[[selectedItems]]"
170
170
  opened="{{opened}}"
171
171
  renderer="[[renderer]]"
@@ -173,6 +173,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
173
173
  on-combo-box-item-selected="_onComboBoxItemSelected"
174
174
  on-change="_onComboBoxChange"
175
175
  on-custom-value-set="_onCustomValueSet"
176
+ on-filtered-items-changed="_onFilteredItemsChanged"
176
177
  >
177
178
  <vaadin-multi-select-combo-box-container
178
179
  part="input-field"
@@ -422,6 +423,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
422
423
  */
423
424
  filteredItems: Array,
424
425
 
426
+ /** @private */
427
+ __effectiveItems: {
428
+ type: Array,
429
+ computed: '__computeEffectiveItems(items, selectedItems, readonly)',
430
+ },
431
+
432
+ /** @private */
433
+ __effectiveFilteredItems: {
434
+ type: Array,
435
+ computed: '__computeEffectiveFilteredItems(items, filteredItems, selectedItems, readonly)',
436
+ },
437
+
425
438
  /** @protected */
426
439
  _hasValue: {
427
440
  type: Boolean,
@@ -605,6 +618,20 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
605
618
  }
606
619
  }
607
620
 
621
+ /**
622
+ * Implement two-way binding for the `filteredItems` property
623
+ * that can be set on the internal combo-box element.
624
+ *
625
+ * @param {CustomEvent} event
626
+ * @private
627
+ */
628
+ _onFilteredItemsChanged(event) {
629
+ const { value } = event.detail;
630
+ if (Array.isArray(value) || value == null) {
631
+ this.filteredItems = value;
632
+ }
633
+ }
634
+
608
635
  /** @private */
609
636
  _readonlyChanged(readonly, oldReadonly) {
610
637
  if (readonly || oldReadonly) {
@@ -660,7 +687,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
660
687
 
661
688
  /** @private */
662
689
  _getItemLabel(item) {
663
- return item && Object.prototype.hasOwnProperty.call(item, this.itemLabelPath) ? item[this.itemLabelPath] : item;
690
+ return this.$.comboBox._getItemLabel(item);
664
691
  }
665
692
 
666
693
  /** @private */
@@ -863,6 +890,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
863
890
  announce(this.i18n.cleared);
864
891
  }
865
892
 
893
+ /**
894
+ * Override an event listener from `InputControlMixin` to
895
+ * stop the change event re-targeted from the input.
896
+ *
897
+ * @param {!Event} event
898
+ * @protected
899
+ * @override
900
+ */
901
+ _onChange(event) {
902
+ event.stopPropagation();
903
+ }
904
+
866
905
  /**
867
906
  * Override an event listener from `KeyboardMixin`.
868
907
  * Do not call `super` in order to override clear
@@ -1043,6 +1082,16 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
1043
1082
  // and keep the overlay opened when clicking a chip.
1044
1083
  event.preventDefault();
1045
1084
  }
1085
+
1086
+ /** @private */
1087
+ __computeEffectiveItems(items, selectedItems, readonly) {
1088
+ return items && readonly ? selectedItems : items;
1089
+ }
1090
+
1091
+ /** @private */
1092
+ __computeEffectiveFilteredItems(items, filteredItems, selectedItems, readonly) {
1093
+ return !items && readonly ? selectedItems : filteredItems;
1094
+ }
1046
1095
  }
1047
1096
 
1048
1097
  customElements.define(MultiSelectComboBox.is, MultiSelectComboBox);
@@ -1,47 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright (c) 2021 - 2022 Vaadin Ltd.
4
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
- */
6
- import './vaadin-multi-select-combo-box-item.js';
7
- import './vaadin-multi-select-combo-box-overlay.js';
8
- import './vaadin-multi-select-combo-box-scroller.js';
9
- import { html } from '@polymer/polymer/lib/utils/html-tag.js';
10
- import { ComboBoxDropdown } from '@vaadin/combo-box/src/vaadin-combo-box-dropdown.js';
11
-
12
- /**
13
- * An element used internally by `<vaadin-multi-select-combo-box>`. Not intended to be used separately.
14
- *
15
- * @extends ComboBoxDropdown
16
- * @private
17
- */
18
- class MultiSelectComboBoxDropdown extends ComboBoxDropdown {
19
- static get is() {
20
- return 'vaadin-multi-select-combo-box-dropdown';
21
- }
22
-
23
- static get template() {
24
- return html`
25
- <vaadin-multi-select-combo-box-overlay
26
- id="overlay"
27
- hidden$="[[_isOverlayHidden(_items.*, loading)]]"
28
- loading$="[[loading]]"
29
- opened="{{_overlayOpened}}"
30
- theme$="[[theme]]"
31
- position-target="[[positionTarget]]"
32
- no-vertical-overlap
33
- ></vaadin-multi-select-combo-box-overlay>
34
- `;
35
- }
36
-
37
- /** @protected */
38
- ready() {
39
- super.ready();
40
-
41
- // Set owner for using by item renderers
42
- const comboBox = this.getRootNode().host;
43
- this._scroller.comboBox = comboBox.getRootNode().host;
44
- }
45
- }
46
-
47
- customElements.define(MultiSelectComboBoxDropdown.is, MultiSelectComboBoxDropdown);