Skip to content

Commit

Permalink
feat: add custom CSS property to customize select overlay width (#7578)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan authored Jul 24, 2024
1 parent 2e5bf2a commit 580f225
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 45 deletions.
19 changes: 7 additions & 12 deletions packages/select/src/vaadin-lit-select-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,20 @@
*/
import { css, html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { SelectOverlayMixin } from './vaadin-select-overlay-mixin.js';

/**
* An element used internally by `<vaadin-select>`. Not intended to be used separately.
*
* @extends HTMLElement
* @mixes PositionMixin
* @mixes OverlayMixin
* @mixes DirMixin
* @mixes SelectOverlayMixin
* @mixes ThemableMixin
* @protected
*/
class SelectOverlay extends PositionMixin(OverlayMixin(ThemableMixin(DirMixin(PolylitMixin(LitElement))))) {
class SelectOverlay extends SelectOverlayMixin(ThemableMixin(PolylitMixin(LitElement))) {
static get is() {
return 'vaadin-select-overlay';
}
Expand All @@ -36,6 +32,10 @@ class SelectOverlay extends PositionMixin(OverlayMixin(ThemableMixin(DirMixin(Po
justify-content: flex-start;
}
:host(:not([phone])) [part='overlay'] {
min-width: var(--vaadin-select-overlay-width, var(--vaadin-select-text-field-width));
}
@media (forced-colors: active) {
[part='overlay'] {
outline: 3px solid;
Expand Down Expand Up @@ -75,11 +75,6 @@ class SelectOverlay extends PositionMixin(OverlayMixin(ThemableMixin(DirMixin(Po
this.owner._assignMenuElement(menuElement);
}
}

/** @protected */
_getMenuElement() {
return Array.from(this.children).find((el) => el.localName !== 'style');
}
}

defineCustomElement(SelectOverlay);
40 changes: 40 additions & 0 deletions packages/select/src/vaadin-select-overlay-mixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @license
* Copyright (c) 2017 - 2024 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';

/**
* @polymerMixin
* @mixes DirMixin
* @mixes OverlayMixin
* @mixes PositionMixin
*/
export const SelectOverlayMixin = (superClass) =>
class SelectOverlayMixin extends PositionMixin(OverlayMixin(DirMixin(superClass))) {
static get observers() {
return ['_updateOverlayWidth(opened, owner)'];
}

/** @protected */
_getMenuElement() {
return Array.from(this.children).find((el) => el.localName !== 'style');
}

/** @private */
_updateOverlayWidth(opened, owner) {
if (opened && owner) {
const widthProperty = '--vaadin-select-overlay-width';
const customWidth = getComputedStyle(owner).getPropertyValue(widthProperty);

if (customWidth === '') {
this.style.removeProperty(widthProperty);
} else {
this.style.setProperty(widthProperty, customWidth);
}
}
}
};
19 changes: 7 additions & 12 deletions packages/select/src/vaadin-select-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
*/
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
import { css, registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { SelectOverlayMixin } from './vaadin-select-overlay-mixin.js';

const selectOverlayStyles = css`
:host {
align-items: flex-start;
justify-content: flex-start;
}
:host(:not([phone])) [part='overlay'] {
min-width: var(--vaadin-select-overlay-width, var(--vaadin-select-text-field-width));
}
@media (forced-colors: active) {
[part='overlay'] {
outline: 3px solid;
Expand All @@ -33,13 +35,11 @@ registerStyles('vaadin-select-overlay', [overlayStyles, selectOverlayStyles], {
*
* @customElement
* @extends HTMLElement
* @mixes DirMixin
* @mixes OverlayMixin
* @mixes PositionMixin
* @mixes SelectOverlayMixin
* @mixes ThemableMixin
* @private
*/
export class SelectOverlay extends PositionMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
export class SelectOverlay extends SelectOverlayMixin(ThemableMixin(PolymerElement)) {
static get is() {
return 'vaadin-select-overlay';
}
Expand Down Expand Up @@ -75,11 +75,6 @@ export class SelectOverlay extends PositionMixin(OverlayMixin(DirMixin(ThemableM
this.owner._assignMenuElement(menuElement);
}
}

/** @protected */
_getMenuElement() {
return Array.from(this.children).find((el) => el.localName !== 'style');
}
}

defineCustomElement(SelectOverlay);
1 change: 1 addition & 0 deletions packages/select/src/vaadin-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ registerStyles('vaadin-select', [fieldShared, inputFieldContainer, screenReaderO
* -----------------------------------|------------------------------|----------------------------------
* `--vaadin-field-default-width` | Default width of the field | :host | `12em`
* `--vaadin-select-text-field-width` | Effective width of the field | `vaadin-select-overlay` |
* `--vaadin-select-overlay-width` | Width of the overlay | `vaadin-select-overlay` |
*
* `<vaadin-select>` provides mostly the same set of shadow DOM parts and state attributes as `<vaadin-text-field>`.
* See [`<vaadin-text-field>`](#/elements/vaadin-text-field) for the styling documentation.
Expand Down
60 changes: 50 additions & 10 deletions packages/select/test/select.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,16 +378,6 @@ describe('vaadin-select', () => {
expect(overlayRect.top).to.be.equal(inputRect.top);
expect(inputRect.right).to.be.equal(inputRect.right);
});

it('should store the text-field width in the custom CSS property on overlay opening', async () => {
valueButton.style.width = '200px';
select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');
const prop = '--vaadin-select-text-field-width';
const inputRect = select._inputContainer.getBoundingClientRect();
const value = getComputedStyle(overlay).getPropertyValue(prop);
expect(value).to.be.equal(`${inputRect.width}px`);
});
});

describe('overlay opened', () => {
Expand Down Expand Up @@ -682,6 +672,56 @@ describe('vaadin-select', () => {
expect(overlayRect.top).to.be.equal(inputRect.bottom);
});
});

describe('overlay width', () => {
let overlay;

beforeEach(() => {
overlay = select._overlayElement;
select.style.setProperty('--vaadin-select-overlay-width', '400px');
});

it('should forward overlay width custom CSS property to the overlay when opened', async () => {
select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');
const prop = '--vaadin-select-overlay-width';
const value = getComputedStyle(overlay).getPropertyValue(prop);
expect(value).to.be.equal('400px');
});

it('should set overlay part width based on the overlay width custom CSS property', async () => {
select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');
expect(overlay.$.overlay.getBoundingClientRect().width).to.equal(400);
});

it('should not set overlay part width based on the custom CSS property when phone', async () => {
select._phone = true;
select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');
expect(overlay.$.overlay.getBoundingClientRect().width).to.not.equal(400);
});

it('should store the select width in the custom CSS property on overlay opening', async () => {
select.style.width = '200px';
select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');
const prop = '--vaadin-select-text-field-width';
const inputRect = select._inputContainer.getBoundingClientRect();
const value = getComputedStyle(overlay).getPropertyValue(prop);
expect(value).to.be.equal(`${inputRect.width}px`);
});

it('should fallback to the select field width when custom CSS property is unset', async () => {
select.style.width = '200px';
select.style.removeProperty('--vaadin-select-overlay-width');

select.opened = true;
await oneEvent(overlay, 'vaadin-overlay-open');

expect(overlay.$.overlay.getBoundingClientRect().width).to.equal(200);
});
});
});

describe('with value', () => {
Expand Down
4 changes: 0 additions & 4 deletions packages/select/theme/lumo/vaadin-select-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ const selectOverlay = css`
--_lumo-item-selected-icon-display: block;
}
[part~='overlay'] {
min-width: var(--vaadin-select-text-field-width);
}
/* Small viewport adjustment */
:host([phone]) {
/* stylelint-disable declaration-block-no-redundant-longhand-properties */
Expand Down
8 changes: 1 addition & 7 deletions packages/select/theme/material/vaadin-select-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,4 @@ registerStyles(
{ moduleId: 'material-select-value-button' },
);

const selectOverlay = css`
[part='overlay'] {
min-width: var(--vaadin-select-text-field-width);
}
`;

registerStyles('vaadin-select-overlay', [menuOverlay, selectOverlay], { moduleId: 'material-select-overlay' });
registerStyles('vaadin-select-overlay', [menuOverlay], { moduleId: 'material-select-overlay' });

0 comments on commit 580f225

Please sign in to comment.