Skip to content

Commit 2a04128

Browse files
authored
experiment: add multi-select-combo-box base styles and visual tests (#9608)
1 parent a20b939 commit 2a04128

39 files changed

+458
-27
lines changed

packages/multi-select-combo-box/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
"lit.d.ts",
2424
"lit.js",
2525
"src",
26+
"!src/styles/*-base-styles.d.ts",
27+
"!src/styles/*-base-styles.js",
2628
"theme",
2729
"vaadin-*.d.ts",
2830
"vaadin-*.js",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import type { CSSResult } from 'lit';
7+
8+
export const multiSelectComboBoxStyles: CSSResult;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import { css } from 'lit';
7+
import { comboBoxStyles } from '@vaadin/combo-box/src/styles/vaadin-combo-box-base-styles.js';
8+
9+
export const multiSelectComboBoxStyles = [
10+
comboBoxStyles,
11+
css`
12+
@layer base {
13+
:host {
14+
max-width: 100%;
15+
--_input-min-width: var(--vaadin-multi-select-combo-box-input-min-width, 4rem);
16+
--_chip-min-width: var(--vaadin-multi-select-combo-box-chip-min-width, var(--vaadin-chip-min-width, 48px));
17+
--_wrapper-gap: var(--vaadin-multi-select-combo-box-chips-gap, 2px);
18+
}
19+
20+
#chips {
21+
display: flex;
22+
align-items: center;
23+
gap: var(--vaadin-multi-select-combo-box-chips-gap, 2px);
24+
}
25+
26+
::slotted(input) {
27+
box-sizing: border-box;
28+
flex: 1 0 var(--_input-min-width);
29+
}
30+
31+
::slotted([slot='chip']),
32+
::slotted([slot='overflow']) {
33+
flex: 0 1 auto;
34+
}
35+
36+
::slotted([slot='chip']) {
37+
overflow: hidden;
38+
}
39+
40+
:host(:is([readonly], [disabled])) ::slotted(input) {
41+
flex-grow: 0;
42+
flex-basis: 0;
43+
padding: 0;
44+
}
45+
46+
:host([readonly]:not([disabled])) [part$='button'] {
47+
cursor: var(--vaadin-clickable-cursor);
48+
}
49+
50+
:host([auto-expand-vertically]) #chips {
51+
display: contents;
52+
}
53+
54+
:host([auto-expand-horizontally]) [class$='container'] {
55+
width: auto;
56+
}
57+
}
58+
`,
59+
];
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import '@vaadin/component-base/src/style-props.js';
7+
import { css } from 'lit';
8+
9+
export const multiSelectComboBoxChipStyles = css`
10+
@layer base {
11+
:host {
12+
display: inline-flex;
13+
align-items: center;
14+
justify-content: center;
15+
white-space: nowrap;
16+
box-sizing: border-box;
17+
gap: var(--vaadin-chip-gap, var(--vaadin-chip-padding, 0.3em));
18+
background: var(--vaadin-chip-background, var(--vaadin-background-container));
19+
color: var(--vaadin-chip-color, var(--vaadin-color));
20+
font-size: var(--vaadin-chip-font-size, 0.875em);
21+
font-weight: var(--vaadin-chip-font-weight, 500);
22+
line-height: var(--vaadin-input-field-value-line-height, inherit);
23+
padding: 0 var(--vaadin-chip-padding, 0.3em);
24+
height: var(--vaadin-chip-height, calc(1lh / 0.875));
25+
border-radius: var(--vaadin-chip-border-radius, var(--vaadin-radius-m));
26+
border: var(--vaadin-chip-border-width, 1px) solid var(--vaadin-chip-border-color, var(--vaadin-border-color));
27+
cursor: default;
28+
}
29+
30+
:host(:not([slot='overflow'])) {
31+
min-width: min(
32+
max-content,
33+
var(--vaadin-multi-select-combo-box-chip-min-width, var(--vaadin-chip-min-width, 48px))
34+
);
35+
}
36+
37+
:host([focused]) {
38+
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
39+
outline-offset: calc(var(--vaadin-chip-border-width, 1px) * -1);
40+
}
41+
42+
[part='label'] {
43+
overflow: hidden;
44+
text-overflow: ellipsis;
45+
}
46+
47+
[part='remove-button'] {
48+
flex: none;
49+
display: block;
50+
margin-inline: auto calc(var(--vaadin-chip-padding, 0.3em) * -1);
51+
color: var(--vaadin-chip-remove-button-color, var(--vaadin-color-subtle));
52+
cursor: var(--vaadin-clickable-cursor);
53+
}
54+
55+
[part='remove-button']::before {
56+
content: '';
57+
display: block;
58+
width: var(--vaadin-icon-size, 1lh);
59+
height: var(--vaadin-icon-size, 1lh);
60+
background: currentColor;
61+
mask-image: var(--_vaadin-icon-cross);
62+
}
63+
64+
:host([disabled]) {
65+
cursor: var(--vaadin-disabled-cursor);
66+
}
67+
68+
:host([disabled]) [part='label'] {
69+
--vaadin-chip-color: var(--vaadin-color-disabled);
70+
}
71+
72+
:host([hidden]),
73+
:host(:is([readonly], [disabled], [slot='overflow'])) [part='remove-button'] {
74+
display: none !important;
75+
}
76+
77+
:host([slot='overflow']) {
78+
position: relative;
79+
margin-inline-start: 8px;
80+
min-width: 1.5em;
81+
}
82+
83+
:host([slot='overflow'])::before,
84+
:host([slot='overflow'])::after {
85+
content: '';
86+
position: absolute;
87+
inset: calc(var(--vaadin-chip-border-width, 1px) * -1);
88+
border-inline-start: 2px solid var(--vaadin-chip-border-color, var(--vaadin-border-color));
89+
border-radius: inherit;
90+
}
91+
92+
:host([slot='overflow'])::before {
93+
left: calc(-4px - var(--vaadin-chip-border-width, 1px));
94+
}
95+
96+
:host([slot='overflow'])::after {
97+
left: calc(-8px - var(--vaadin-chip-border-width, 1px));
98+
}
99+
100+
:host([count='2']) {
101+
margin-inline-start: 4px;
102+
}
103+
104+
:host([count='1']) {
105+
margin-inline-start: 0;
106+
}
107+
108+
:host([count='2'])::after,
109+
:host([count='1'])::before,
110+
:host([count='1'])::after {
111+
display: none;
112+
}
113+
}
114+
`;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import { css } from 'lit';
7+
import { comboBoxOverlayStyles } from '@vaadin/combo-box/src/styles/vaadin-combo-box-overlay-base-styles.js';
8+
9+
export const multiSelectComboBoxOverlayStyles = [
10+
comboBoxOverlayStyles,
11+
css`
12+
@layer base {
13+
#overlay {
14+
width: var(
15+
--vaadin-multi-select-combo-box-overlay-width,
16+
var(--_vaadin-multi-select-combo-box-overlay-default-width, auto)
17+
);
18+
}
19+
}
20+
`,
21+
];
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 - 2025 Vaadin Ltd.
4+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5+
*/
6+
import { comboBoxScrollerStyles } from '@vaadin/combo-box/src/styles/vaadin-combo-box-scroller-base-styles.js';
7+
8+
export const multiSelectComboBoxScrollerStyles = comboBoxScrollerStyles;

packages/multi-select-combo-box/src/vaadin-multi-select-combo-box-container.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class MultiSelectComboBoxContainer extends InputContainer {
2727
display: flex;
2828
width: 100%;
2929
min-width: 0;
30+
gap: var(--_wrapper-gap);
3031
}
3132
3233
:host([auto-expand-vertically]) #wrapper {

packages/multi-select-combo-box/src/vaadin-multi-select-combo-box.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export interface MultiSelectComboBoxEventMap<TItem> extends HTMLElementEventMap
130130
* `--vaadin-field-default-width` | Default width of the field | `12em`
131131
* `--vaadin-multi-select-combo-box-overlay-width` | Width of the overlay | `auto`
132132
* `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
133-
* `--vaadin-multi-select-combo-box-chip-min-width` | Min width of the chip | `50px`
134133
* `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
135134
*
136135
* ### Internal components

packages/multi-select-combo-box/src/vaadin-multi-select-combo-box.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ import { MultiSelectComboBoxMixin } from './vaadin-multi-select-combo-box-mixin.
6969
* `--vaadin-field-default-width` | Default width of the field | `12em`
7070
* `--vaadin-multi-select-combo-box-overlay-width` | Width of the overlay | `auto`
7171
* `--vaadin-multi-select-combo-box-overlay-max-height` | Max height of the overlay | `65vh`
72-
* `--vaadin-multi-select-combo-box-chip-min-width` | Min width of the chip | `50px`
7372
* `--vaadin-multi-select-combo-box-input-min-width` | Min width of the input | `4em`
7473
*
7574
* ### Internal components

packages/multi-select-combo-box/test/chips.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ describe('chips', () => {
171171
it('should update overflow chip on resize when width changes', async () => {
172172
expect(overflow.hasAttribute('hidden')).to.be.false;
173173

174-
comboBox.style.width = '350px';
174+
comboBox.style.width = '400px';
175175
await nextResize(comboBox);
176176
expect(overflow.hasAttribute('hidden')).to.be.true;
177177

@@ -181,7 +181,7 @@ describe('chips', () => {
181181
});
182182

183183
it('should update overflow chip on clear button state change', async () => {
184-
comboBox.style.width = '340px';
184+
comboBox.style.width = '370px';
185185
await nextResize(comboBox);
186186

187187
comboBox.clearButtonVisible = true;

0 commit comments

Comments
 (0)