Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ class MultiSelectComboBoxChip extends ThemableMixin(PolymerElement) {
text-overflow: ellipsis;
}

:host(:is([readonly], [disabled], [part~='overflow'])) [part='remove-button'] {
:host([hidden]),
:host(:is([readonly], [disabled], [slot='overflow'])) [part='remove-button'] {
display: none !important;
}
</style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,13 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
*
* Part name | Description
* -----------------------|----------------
* `chips` | The element that wraps chips for selected items
* `chip` | Chip shown for every selected item
* `chips` | The element that wraps slotted chips for selected items
* `label` | The label element
* `input-field` | The element that wraps prefix, value and suffix
* `clear-button` | The clear button
* `error-message` | The error message element
* `helper-text` | The helper text element wrapper
* `required-indicator` | The `required` state indicator element
* `overflow` | The chip shown when component width is not enough to fit all chips
* `overflow-one` | Set on the overflow chip when only one chip does not fit
* `overflow-two` | Set on the overflow chip when two chips do not fit
* `toggle-button` | The toggle button
*
* The following state attributes are available for styling:
Expand Down
115 changes: 52 additions & 63 deletions packages/multi-select-combo-box/src/vaadin-multi-select-combo-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { announce } from '@vaadin/component-base/src/a11y-announcer.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { ResizeMixin } from '@vaadin/component-base/src/resize-mixin.js';
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
import { processTemplates } from '@vaadin/component-base/src/templates.js';
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
import { InputControlMixin } from '@vaadin/field-base/src/input-control-mixin.js';
Expand All @@ -23,10 +24,6 @@ const multiSelectComboBox = css`
--input-min-width: var(--vaadin-multi-select-combo-box-input-min-width, 4em);
}

[hidden] {
display: none !important;
}
Comment on lines -26 to -28
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CSS is now moved to vaadin-multi-select-combo-box-chip.


#chips {
display: flex;
align-items: center;
Expand All @@ -37,7 +34,8 @@ const multiSelectComboBox = css`
flex: 1 0 var(--input-min-width);
}

[part='chip'] {
::slotted([slot='chip']),
::slotted([slot='overflow']) {
flex: 0 1 auto;
}

Expand Down Expand Up @@ -72,17 +70,13 @@ registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectCo
*
* Part name | Description
* -----------------------|----------------
* `chips` | The element that wraps chips for selected items
* `chip` | Chip shown for every selected item
* `chips` | The element that wraps slotted chips for selected items
* `label` | The label element
* `input-field` | The element that wraps prefix, value and suffix
* `clear-button` | The clear button
* `error-message` | The error message element
* `helper-text` | The helper text element wrapper
* `required-indicator` | The `required` state indicator element
* `overflow` | The chip shown when component width is not enough to fit all chips
* `overflow-one` | Set on the overflow chip when only one chip does not fit
* `overflow-two` | Set on the overflow chip when two chips do not fit
* `toggle-button` | The toggle button
*
* The following state attributes are available for styling:
Expand Down Expand Up @@ -182,18 +176,10 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
invalid="[[invalid]]"
theme$="[[_theme]]"
>
<vaadin-multi-select-combo-box-chip
id="overflow"
slot="prefix"
part$="[[_getOverflowPart(_overflowItems.length)]]"
disabled="[[disabled]]"
readonly="[[readonly]]"
label="[[_getOverflowLabel(_overflowItems.length)]]"
title$="[[_getOverflowTitle(_overflowItems)]]"
hidden$="[[_isOverflowHidden(_overflowItems.length)]]"
on-mousedown="_preventBlur"
></vaadin-multi-select-combo-box-chip>
<div id="chips" part="chips" slot="prefix"></div>
<slot name="overflow" slot="prefix"></slot>
<div id="chips" part="chips" slot="prefix">
<slot name="chip"></slot>
</div>
<slot name="input"></slot>
<div
id="clearButton"
Expand Down Expand Up @@ -469,7 +455,10 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
}

static get observers() {
return ['_selectedItemsChanged(selectedItems, selectedItems.*)'];
return [
'_selectedItemsChanged(selectedItems, selectedItems.*)',
'__updateOverflowChip(_overflow, _overflowItems, disabled, readonly)',
];
}

/** @protected */
Expand All @@ -496,7 +485,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El

/** @protected */
get _chips() {
return this.shadowRoot.querySelectorAll('[part~="chip"]');
return [...this.querySelectorAll('[slot="chip"]')];
}

/** @protected */
Expand All @@ -519,6 +508,18 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
this._tooltipController.setShouldShow((target) => !target.opened);

this._inputField = this.shadowRoot.querySelector('[part="input-field"]');

this._overflowController = new SlotController(
this,
'overflow',
() => document.createElement('vaadin-multi-select-combo-box-chip'),
(_, chip) => {
chip.addEventListener('mousedown', (e) => this._preventBlur(e));
this._overflow = chip;
},
);
this.addController(this._overflowController);

this.__updateChips();

processTemplates(this);
Expand Down Expand Up @@ -716,34 +717,6 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
return this.$.comboBox._getItemLabel(item);
}

/** @private */
_getOverflowLabel(length) {
return length;
}

/** @private */
_getOverflowPart(length) {
let part = `chip overflow`;

if (length === 1) {
part += ' overflow-one';
} else if (length === 2) {
part += ' overflow-two';
}

return part;
}

/** @private */
_getOverflowTitle(items) {
return this._mergeItemLabels(items);
}

/** @private */
_isOverflowHidden(length) {
return length === 0;
}

/** @private */
_mergeItemLabels(items) {
return items.map((item) => this._getItemLabel(item)).join(', ');
Expand Down Expand Up @@ -828,8 +801,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
/** @private */
__createChip(item) {
const chip = document.createElement('vaadin-multi-select-combo-box-chip');
chip.setAttribute('part', 'chip');
chip.setAttribute('slot', 'prefix');
chip.setAttribute('slot', 'chip');

chip.item = item;
chip.disabled = this.disabled;
Expand All @@ -847,16 +819,20 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El

/** @private */
__getOverflowWidth() {
const chip = this.$.overflow;
const chip = this._overflow;

chip.style.visibility = 'hidden';
chip.removeAttribute('hidden');

const count = chip.getAttribute('count');

// Detect max possible width of the overflow chip
chip.setAttribute('part', 'chip overflow');
// by measuring it with widest number (2 digits)
chip.setAttribute('count', '99');
const overflowStyle = getComputedStyle(chip);
const overflowWidth = chip.clientWidth + parseInt(overflowStyle.marginInlineStart);

chip.setAttribute('count', count);
chip.setAttribute('hidden', '');
chip.style.visibility = '';

Expand All @@ -870,10 +846,8 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
}

// Clear all chips except the overflow
Array.from(this._chips).forEach((chip) => {
if (chip !== this.$.overflow) {
chip.remove();
}
this._chips.forEach((chip) => {
chip.remove();
});

const items = [...this.selectedItems];
Expand All @@ -891,7 +865,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
// Add chips until remaining width is exceeded
for (let i = items.length - 1, refNode = null; i >= 0; i--) {
const chip = this.__createChip(items[i]);
this.$.chips.insertBefore(chip, refNode);
this.insertBefore(chip, refNode);

if (this.$.chips.clientWidth > remainingWidth) {
chip.remove();
Expand All @@ -905,6 +879,21 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
this._overflowItems = items;
}

/** @private */
__updateOverflowChip(overflow, items, disabled, readonly) {
if (overflow) {
const count = items.length;

overflow.label = `${count}`;
overflow.setAttribute('count', `${count}`);
overflow.setAttribute('title', this._mergeItemLabels(items));
overflow.toggleAttribute('hidden', count === 0);

overflow.disabled = disabled;
overflow.readonly = readonly;
}
}

/** @private */
_onClearButtonTouchend(event) {
// Cancel the following click and focus events
Expand Down Expand Up @@ -961,7 +950,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
_onKeyDown(event) {
super._onKeyDown(event);

const chips = Array.from(this._chips).slice(1);
const chips = this._chips;
Comment on lines -964 to +953
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to call .slice(1) anymore because this._chips no longer includes overflow chip.


if (!this.readonly && chips.length > 0) {
switch (event.key) {
Expand Down Expand Up @@ -1059,7 +1048,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
/** @private */
_focusedChipIndexChanged(focusedIndex, oldFocusedIndex) {
if (focusedIndex > -1 || oldFocusedIndex > -1) {
const chips = Array.from(this._chips).slice(1);
const chips = this._chips;
chips.forEach((chip, index) => {
chip.toggleAttribute('focused', index === focusedIndex);
});
Expand Down
24 changes: 8 additions & 16 deletions packages/multi-select-combo-box/test/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ describe('basic', () => {
});

describe('chips', () => {
const getChips = (combo) => combo.shadowRoot.querySelectorAll('[part~="chip"]');
const getChips = (combo) => combo.querySelectorAll('vaadin-multi-select-combo-box-chip');

const getChipContent = (chip) => chip.shadowRoot.querySelector('[part="label"]').textContent;

Expand Down Expand Up @@ -366,28 +366,20 @@ describe('basic', () => {
it('should set overflow chip label as not fitting chips count', async () => {
comboBox.selectedItems = ['apple', 'banana', 'orange'];
await nextRender();
expect(overflow.label).to.equal(2);
expect(overflow.label).to.equal('2');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property was previously set as number, apparently because of data binding usage.

});

it('should set overflow chip title as not fitting chips labels', async () => {
it('should set overflow chip count as not fitting chips count', async () => {
comboBox.selectedItems = ['apple', 'banana', 'orange'];
await nextRender();
const title = overflow.getAttribute('title');
expect(title).to.equal('apple, banana');
});

it('should set overflow chip part if only one chip does not fit', async () => {
comboBox.selectedItems = ['apple', 'banana'];
await nextRender();
const part = overflow.getAttribute('part');
expect(part).to.contain('overflow-one');
expect(overflow.getAttribute('count')).to.equal('2');
});

it('should set overflow chip part if two chips do not fit', async () => {
it('should set overflow chip title as not fitting chips labels', async () => {
comboBox.selectedItems = ['apple', 'banana', 'orange'];
await nextRender();
const part = overflow.getAttribute('part');
expect(part).to.contain('overflow-two');
const title = overflow.getAttribute('title');
expect(title).to.equal('apple, banana');
});

describe('resize', () => {
Expand Down Expand Up @@ -629,7 +621,7 @@ describe('basic', () => {
});

it('should fire change when chip is removed', () => {
const chip = comboBox.shadowRoot.querySelector('[part="chip"]');
const chip = comboBox.querySelector('[slot="chip"]');
chip.shadowRoot.querySelector('[part="remove-button"]').click();
expect(spy.calledOnce).to.be.true;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["vaadin-multi-select-combo-box default"] =
snapshots["vaadin-multi-select-combo-box host default"] =
`<vaadin-multi-select-combo-box placeholder="">
<label
for="input-vaadin-multi-select-combo-box-4"
id="label-vaadin-multi-select-combo-box-0"
slot="label"
>
</label>
<div
hidden=""
id="error-message-vaadin-multi-select-combo-box-2"
slot="error-message"
>
</div>
<input
aria-autocomplete="list"
aria-expanded="false"
autocapitalize="off"
autocomplete="off"
autocorrect="off"
id="input-vaadin-multi-select-combo-box-4"
role="combobox"
slot="input"
spellcheck="false"
>
<vaadin-multi-select-combo-box-chip
count="0"
hidden=""
slot="overflow"
title=""
>
</vaadin-multi-select-combo-box-chip>
</vaadin-multi-select-combo-box>
`;
/* end snapshot vaadin-multi-select-combo-box host default */

snapshots["vaadin-multi-select-combo-box shadow default"] =
`<div class="vaadin-multi-select-combo-box-container">
<div part="label">
<slot name="label">
Expand All @@ -14,19 +50,18 @@ snapshots["vaadin-multi-select-combo-box default"] =
</div>
<vaadin-multi-select-combo-box-internal id="comboBox">
<vaadin-multi-select-combo-box-container part="input-field">
<vaadin-multi-select-combo-box-chip
hidden=""
id="overflow"
part="chip overflow"
<slot
name="overflow"
slot="prefix"
title=""
>
</vaadin-multi-select-combo-box-chip>
</slot>
<div
id="chips"
part="chips"
slot="prefix"
>
<slot name="chip">
</slot>
</div>
<slot name="input">
</slot>
Expand Down Expand Up @@ -59,5 +94,5 @@ snapshots["vaadin-multi-select-combo-box default"] =
<slot name="tooltip">
</slot>
`;
/* end snapshot vaadin-multi-select-combo-box default */
/* end snapshot vaadin-multi-select-combo-box shadow default */

Loading