Skip to content

Commit

Permalink
feat: add option to always show all chips for selected items (#6515)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan committed Nov 15, 2023
1 parent 8d9143f commit 875fc5f
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ registerStyles(
display: flex;
width: 100%;
}
:host([all-chips-visible]) #wrapper {
flex-wrap: wrap;
}
`,
{
moduleId: 'vaadin-multi-select-combo-box-container-styles',
Expand Down Expand Up @@ -47,6 +51,20 @@ class MultiSelectComboBoxContainer extends InputContainer {
}
return memoizedTemplate;
}

static get properties() {
return {
/**
* Set true to not collapse selected items chips into the overflow
* chip and instead always show them, causing input field to grow.
* @attr {boolean} all-chips-visible
*/
allChipsVisible: {
type: Boolean,
reflectToAttribute: true,
},
};
}
}

customElements.define(MultiSelectComboBoxContainer.is, MultiSelectComboBoxContainer);
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
* @fires {CustomEvent} validated - Fired whenever the field is validated.
*/
declare class MultiSelectComboBox<TItem = ComboBoxDefaultItem> extends HTMLElement {
/**
* Set to true to not collapse selected items chips into the overflow
* chip and instead always show them all, causing input field to grow
* and wrap into multiple lines when width is limited.
* @attr {boolean} all-chips-visible
*/
allChipsVisible: boolean;

/**
* When true, the user can input a value that is not present in the items list.
* @attr {boolean} allow-custom-value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ const multiSelectComboBox = css`
flex-basis: 0;
padding: 0;
}
:host([all-chips-visible]) #chips {
display: contents;
}
:host([all-chips-visible]) [class$='container'] {
width: fit-content;
}
`;

registerStyles('vaadin-multi-select-combo-box', [inputFieldShared, multiSelectComboBox], {
Expand Down Expand Up @@ -179,6 +187,7 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
>
<vaadin-multi-select-combo-box-container
part="input-field"
all-chips-visible="[[allChipsVisible]]"
readonly="[[readonly]]"
disabled="[[disabled]]"
invalid="[[invalid]]"
Expand Down Expand Up @@ -223,6 +232,19 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El

static get properties() {
return {
/**
* Set to true to not collapse selected items chips into the overflow
* chip and instead always show them all, causing input field to grow
* and wrap into multiple lines when width is limited.
* @attr {boolean} all-chips-visible
*/
allChipsVisible: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: '_allChipsVisibleChanged',
},

/**
* Set true to prevent the overlay from opening automatically.
* @attr {boolean} auto-open-disabled
Expand Down Expand Up @@ -650,6 +672,13 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
super._delegateAttribute(name, value);
}

/** @private */
_allChipsVisibleChanged(visible, oldVisible) {
if (visible || oldVisible) {
this.__updateChips();
}
}

/**
* Setting clear button visible reduces total space available
* for rendering chips, and making it hidden increases it.
Expand Down Expand Up @@ -921,7 +950,8 @@ class MultiSelectComboBox extends ResizeMixin(InputControlMixin(ThemableMixin(El
const chip = this.__createChip(items[i]);
this.$.chips.insertBefore(chip, refNode);

if (this.$.chips.clientWidth > remainingWidth) {
// If all the chips are visible, no need to measure remaining width
if (!this.allChipsVisible && this.$.chips.clientWidth > remainingWidth) {
chip.remove();
break;
}
Expand Down
50 changes: 50 additions & 0 deletions packages/multi-select-combo-box/test/chips.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,4 +418,54 @@ describe('chips', () => {
});
});
});

describe('allChipsVisible', () => {
let overflow;

beforeEach(async () => {
comboBox.style.width = '250px';
await nextResize(comboBox);
overflow = getChips(comboBox)[0];
});

it('should not show overflow chip when allChipsVisible is set to true', async () => {
comboBox.allChipsVisible = true;
comboBox.selectedItems = ['apple', 'banana'];
await nextRender();
expect(getChips(comboBox).length).to.equal(3);
expect(overflow.hasAttribute('hidden')).to.be.true;
});

it('should show overflow chip when allChipsVisible is set to false', async () => {
comboBox.allChipsVisible = true;
comboBox.selectedItems = ['apple', 'banana'];
await nextRender();

comboBox.allChipsVisible = false;
await nextRender();
expect(getChips(comboBox).length).to.equal(2);
expect(overflow.hasAttribute('hidden')).to.be.false;
});

it('should update chips when allChipsVisible is set after selectedItems', async () => {
comboBox.selectedItems = ['apple', 'banana'];
await nextRender();
expect(getChips(comboBox).length).to.equal(2);
expect(overflow.hasAttribute('hidden')).to.be.false;

comboBox.allChipsVisible = true;
await nextRender();
expect(getChips(comboBox).length).to.equal(3);
expect(overflow.hasAttribute('hidden')).to.be.true;
});

it('should wrap chips and increase input field height if chips do not fit', async () => {
const inputField = comboBox.shadowRoot.querySelector('[part="input-field"]');
const height = inputField.clientHeight;
comboBox.allChipsVisible = true;
comboBox.selectedItems = ['apple', 'banana', 'lemon', 'orange'];
await nextRender();
expect(inputField.clientHeight).to.be.greaterThan(height);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ assertType<string | null | undefined>(narrowedComboBox.label);
assertType<boolean>(narrowedComboBox.required);
assertType<string | null | undefined>(narrowedComboBox.theme);
assertType<boolean>(narrowedComboBox.selectedItemsOnTop);
assertType<boolean>(narrowedComboBox.allChipsVisible);

// Mixins
assertType<ControllerMixinClass>(narrowedComboBox);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ describe('multi-select-combo-box', () => {
});
});

describe('all chips visible', () => {
beforeEach(() => {
element.selectedItems = [...element.items];
element.allChipsVisible = true;
});

it('all chips visible', async () => {
await visualDiff(div, 'all-chips-visible');
});

it('all chips visible max width', async () => {
element.style.maxWidth = '250px';
await visualDiff(div, 'all-chips-visible-max-width');
});
});

describe('opened', () => {
beforeEach(() => {
div.style.height = '200px';
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ describe('multi-select-combo-box', () => {
});
});

describe('all chips visible', () => {
beforeEach(() => {
element.selectedItems = [...element.items];
element.allChipsVisible = true;
});

it('all chips visible', async () => {
await visualDiff(div, 'all-chips-visible');
});

it('all chips visible max width', async () => {
element.style.maxWidth = '250px';
await visualDiff(div, 'all-chips-visible-max-width');
});
});

describe('opened', () => {
beforeEach(() => {
div.style.height = '200px';
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ registerStyles(
},
);

registerStyles(
'vaadin-multi-select-combo-box-container',
css`
:host([all-chips-visible]) {
padding-block: var(--lumo-space-xs);
}
`,
{ moduleId: 'lumo-multi-select-combo-box-container' },
);

const multiSelectComboBox = css`
:host([has-value]) {
padding-inline-start: 0;
Expand All @@ -38,6 +48,14 @@ const multiSelectComboBox = css`
margin-inline-end: var(--lumo-space-xs);
}
:host([all-chips-visible]) [part~='chip'] {
margin-block: calc(var(--lumo-space-xs) / 2);
}
:host([all-chips-visible]) ::slotted([slot='input']) {
min-height: calc(var(--lumo-text-field-size, var(--lumo-size-m)) - 2 * var(--lumo-space-xs));
}
[part~='overflow']:not([hidden]) + :not(:empty) {
margin-inline-start: var(--lumo-space-xs);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const multiSelectComboBox = css`
min-height: 32px;
}
:host([all-chips-visible]) [part~='chip'] {
margin-top: 0.25rem;
align-self: flex-start;
}
[part='input-field'] ::slotted(input) {
padding: 6px 0;
}
Expand Down

0 comments on commit 875fc5f

Please sign in to comment.