Создание веб-компонента
Web Components можно создавать с нуля на основе библиотек Polymer 3 или Lit. После реализации веб-компонента на JavaScript, для него можно создать Java API.
Пример ниже показывает, как построить переключатель светлой/темной темы на основе Lit.
Создание JavaScript веб-компонента
Создайте файл theme-toggle.js в папке frontend/src/component/theme-toggle. Он содержит веб-компонент, реализующий переключатель светлой/темной темы.
import {html, LitElement} from 'lit';
import {PolylitMixin} from '@vaadin/component-base/src/polylit-mixin.js';
import {defineCustomElement} from '@vaadin/component-base/src/define.js';
import {ElementMixin} from '@vaadin/component-base/src/element-mixin.js';
import {TooltipController} from "@vaadin/component-base/src/tooltip-controller";
import {css, ThemableMixin} from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import {buttonStyles} from '@vaadin/button/src/vaadin-button-base.js';
import {button as buttonLumoStyles} from '@vaadin/button/theme/lumo/vaadin-button-styles.js';
import {ButtonMixin} from '@vaadin/button/src/vaadin-button-mixin.js';
const themeToggleStyles = css`
    :host {
        background: transparent;
        color: var(--lumo-text-color);
        min-width: var(--lumo-button-size);
        padding-left: calc(var(--lumo-button-size) / 4);
        padding-right: calc(var(--lumo-button-size) / 4);
    }
`;
class ThemeToggle extends ButtonMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) { (1)
    static get is() {
        return 'theme-toggle'; (2)
    }
    static get styles() { (3)
        return [buttonStyles, buttonLumoStyles, themeToggleStyles];
    }
    render() { (4)
        return html`
            <div class="vaadin-button-container">
                <vaadin-icon icon="vaadin:adjust"></vaadin-icon>
            </div>
            <slot name="tooltip"></slot>
        `;
    }
    static get properties() { (5)
        return {
            ariaLabel: {
                type: String,
                value: 'Theme toggle',
                reflectToAttribute: true,
            }
        };
    }
    constructor() {
        super();
        this._storageKey = "app-theme";
        this.addEventListener('click', () => this.toggleTheme());
    }
    /** @protected */
    ready() {
        super.ready();
        this._tooltipController = new TooltipController(this); (6)
        this.addController(this._tooltipController);
        this.applyStorageTheme();
    }
    applyStorageTheme() {
        let storageTheme = this.getStorageTheme();
        let currentTheme = this.getCurrentTheme();
        if (storageTheme && currentTheme !== storageTheme) {
            this.applyTheme(storageTheme);
        }
    }
    getStorageTheme() {
        return localStorage.getItem(this._storageKey);
    }
    getCurrentTheme() {
        return document.documentElement.getAttribute("theme");
    }
    toggleTheme() {
        const theme = this.getCurrentTheme();
        this.applyTheme(theme === "dark" ? "" : "dark");
    }
    applyTheme(theme) {
        document.documentElement.setAttribute("theme", theme);
        localStorage.setItem(this._storageKey, theme);
        const customEvent = new CustomEvent('theme-changed', {detail: {value: theme}});
        this.dispatchEvent(customEvent); (7)
    }
}
defineCustomElement(ThemeToggle); (8)
export {ThemeToggle};| 1 | Определяет базовые классы для пользовательских компонентов. Поскольку ThemeToggleдолжен выглядеть и вести себя как кнопка, одним из базовых классов являетсяButtonMixin, который предоставляет свойства и обработчики, характерные для кнопок. | 
| 2 | Определяет имя HTML-элемента. | 
| 3 | Определяет стили компонента как комбинацию импортированных стилей vaadin-buttonи пользовательских стилей. | 
| 4 | Определяет шаблон Shadow DOM | 
| 5 | Определяет пользовательские свойства. | 
| 6 | Инициализирует класс TooltipController, который обрабатывает изменения всплывающих подсказок. Классы контроллеров используются в качестве делегатов для повторяющейся функциональности визуальных компонентов. | 
| 7 | Отправляет пользовательское событие с именем theme-changed. | 
| 8 | Экспортирует пользовательский HTML-элемент с именем, определенным в методе static get is(). | 
Создание Java API для веб-компонента
Создайте файл ThemeToggle.java, который является классом UI-компонента. Он определяет API для серверного кода, методы доступа, обработчики событий и подключение источников данных.
import com.vaadin.flow.component.*;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.shared.HasTooltip;
import com.vaadin.flow.shared.Registration;
@Tag("theme-toggle") (1)
@JsModule("./src/component/theme-toggle/theme-toggle.js") (2)
public class ThemeToggle extends Component implements ClickNotifier<ThemeToggle>,
        Focusable<ThemeToggle>, HasTheme, HasEnabled, HasSize, HasStyle, HasTooltip, HasAriaLabel { (3)
    public ThemeToggle() {
    }
    public Registration addThemeChangeListener(ComponentEventListener<ThemeToggleThemeChangedEvent> listener) {
        return addListener(ThemeToggleThemeChangedEvent.class, listener);
    }
    @DomEvent("theme-changed") (4)
    public static class ThemeToggleThemeChangedEvent extends ComponentEvent<ThemeToggle> {
        protected String value;
        public ThemeToggleThemeChangedEvent(ThemeToggle source, boolean fromClient,
                                            @EventData("event.detail.value") String value) { (5)
            super(source, fromClient);
            this.value = value;
        }
        public String getValue() {
            return value;
        }
    }
}| 1 | Определяет корневой элемент, который автоматически создается классом Componentи к которому можно обращаться с помощью методаgetElement(). Должен совпадать с экспортом веб-компонента. | 
| 2 | Аннотация @JsModuleопределяет импорт JavaScript-модуля. | 
| 3 | Использование Vaadin Mixin Interfaces для предоставления общих API и поведения по умолчанию для наборов функциональности, встречающихся в большинстве веб-компонентов. | 
| 4 | Использование аннотации @DomEventдля подключения компонента ThemeToggle к событию DOMtheme-changed. | 
| 5 | Использование аннотации @EventDataдля определения дополнительных данных события, в данном случае значения темы. | 
| Более подробную информацию о создании пользовательских компонентов можно найти в документации Vaadin: Creating Components, Using Vaadin Mixin Interfaces, Using Events with Components&. | 
