diff --git a/src/components/ha-form/ha-form-multi_select.ts b/src/components/ha-form/ha-form-multi_select.ts index 37155d4ecc..9640aa53cc 100644 --- a/src/components/ha-form/ha-form-multi_select.ts +++ b/src/components/ha-form/ha-form-multi_select.ts @@ -1,17 +1,18 @@ -import { mdiMenuDown, mdiMenuUp } from "@mdi/js"; import type { PropertyValues, TemplateResult } from "lit"; import { css, html, LitElement } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../ha-check-list-item"; import "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox"; +import "../ha-dropdown"; +import "../ha-dropdown-item"; import "../ha-formfield"; import "../ha-icon-button"; -import "../ha-md-button-menu"; -import "../ha-md-menu-item"; -import "../ha-textfield"; +import "../ha-picker-field"; +import type { HaDropdown } from "../ha-dropdown"; +import type { HaDropdownItem } from "../ha-dropdown-item"; import type { HaFormElement, HaFormMultiSelectData, @@ -36,16 +37,12 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { @property() public label!: string; - @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean, reflect: true }) public disabled = false; - @state() private _opened = false; - - @query("ha-md-button-menu") private _input?: HTMLElement; + @query("ha-dropdown") private _dropdown!: HaDropdown; public focus(): void { - if (this._input) { - this._input.focus(); - } + this._dropdown?.focus(); } protected render(): TemplateResult { @@ -74,13 +71,14 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { } return html` - - - + hide-clear-icon + > + ${options.map((item: string | [string, string]) => { const value = optionValue(item); const selected = data.includes(value); - return html` - ${optionLabel(item)} - `; + `; })} - + `; } - protected _keydown(ev) { - if (ev.code === "Space" || ev.code === "Enter") { - ev.preventDefault(); - this._toggleItem(ev); - } - } + protected _toggleItem(ev: CustomEvent<{ item: HaDropdownItem }>) { + ev.preventDefault(); // keep the dropdown open + const value = ev.detail.item.value; + const action = (ev.detail.item as any).action; - protected _toggleItem(ev) { const oldData = this.data || []; let newData: string[]; - if (ev.currentTarget.action === "add") { - newData = [...oldData, ev.currentTarget.value]; + if (action === "add") { + newData = [...oldData, value]; } else { - newData = oldData.filter((d) => d !== ev.currentTarget.value); + newData = oldData.filter((d) => d !== value); } fireEvent(this, "value-changed", { value: newData, }); } - protected firstUpdated() { - this.updateComplete.then(() => { - const { formElement, mdcRoot } = - this.shadowRoot?.querySelector("ha-textfield") || ({} as any); - if (formElement) { - formElement.style.textOverflow = "ellipsis"; - } - if (mdcRoot) { - mdcRoot.style.cursor = "pointer"; - } - }); - } - protected updated(changedProps: PropertyValues): void { if (changedProps.has("schema")) { this.toggleAttribute( @@ -194,25 +163,28 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { }); } - private _handleOpen(ev: Event): void { - ev.stopPropagation(); - this._opened = true; - this.toggleAttribute("opened", true); + private _showDropdown(ev) { + if (this.disabled) { + ev.preventDefault(); + } + this.style.setProperty( + "--dropdown-width", + `${this._dropdown.offsetWidth}px` + ); } - private _handleClose(ev: Event): void { - ev.stopPropagation(); - this._opened = false; - this.toggleAttribute("opened", false); + private _handleKeydown(ev) { + if ((ev.code === "Space" || ev.code === "Enter") && this._dropdown) { + this._dropdown.open = true; + } } static styles = css` :host([own-margin]) { margin-bottom: 5px; } - ha-md-button-menu { + ha-dropdown { display: block; - cursor: pointer; } ha-formfield { display: block; @@ -239,9 +211,15 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { :host([opened]) ha-icon-button { color: var(--primary-color); } - :host([opened]) ha-md-button-menu { - --mdc-text-field-idle-line-color: var(--input-hover-line-color); - --mdc-text-field-label-ink-color: var(--primary-color); + + ha-dropdown::part(menu) { + border-top-left-radius: 0; + border-top-right-radius: 0; + width: var(--dropdown-width); + } + + :host([disabled]) ha-dropdown ha-picker-field { + cursor: not-allowed; } `; } diff --git a/src/components/ha-md-button-menu.ts b/src/components/ha-md-button-menu.ts deleted file mode 100644 index 4e07f40bee..0000000000 --- a/src/components/ha-md-button-menu.ts +++ /dev/null @@ -1,123 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, query } from "lit/decorators"; -import { fireEvent } from "../common/dom/fire_event"; -import { FOCUS_TARGET } from "../dialogs/make-dialog-manager"; -import type { HaButton } from "./ha-button"; -import type { HaIconButton } from "./ha-icon-button"; -import "./ha-md-menu"; -import type { HaMdMenu } from "./ha-md-menu"; - -@customElement("ha-md-button-menu") -export class HaMdButtonMenu extends LitElement { - protected readonly [FOCUS_TARGET]; - - @property({ type: Boolean }) public disabled = false; - - @property() public positioning?: "fixed" | "absolute" | "popover"; - - @property({ attribute: "anchor-corner" }) public anchorCorner: - | "start-start" - | "start-end" - | "end-start" - | "end-end" = "end-start"; - - @property({ attribute: "menu-corner" }) public menuCorner: - | "start-start" - | "start-end" - | "end-start" - | "end-end" = "start-start"; - - @property({ type: Boolean, attribute: "has-overflow" }) public hasOverflow = - false; - - @property({ type: Boolean }) public quick = false; - - @query("ha-md-menu", true) private _menu!: HaMdMenu; - - public get items() { - return this._menu.items; - } - - public override focus() { - if (this._menu.open) { - this._menu.focus(); - } else { - this._triggerButton?.focus(); - } - } - - protected render(): TemplateResult { - return html` -
- -
- - - - `; - } - - private _handleOpening(): void { - fireEvent(this, "opening", undefined, { composed: false }); - } - - private _handleClosing(): void { - fireEvent(this, "closing", undefined, { composed: false }); - } - - private _handleClick(): void { - if (this.disabled) { - return; - } - this._menu.anchorElement = this; - if (this._menu.open) { - this._menu.close(); - } else { - this._menu.show(); - } - } - - private get _triggerButton() { - return this.querySelector( - 'ha-icon-button[slot="trigger"], ha-button[slot="trigger"], ha-assist-chip[slot="trigger"]' - ) as HaIconButton | HaButton | null; - } - - private _setTriggerAria() { - if (this._triggerButton) { - this._triggerButton.ariaHasPopup = "menu"; - } - } - - static styles = css` - :host { - display: inline-block; - position: relative; - } - ::slotted([disabled]) { - color: var(--disabled-text-color); - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "ha-md-button-menu": HaMdButtonMenu; - } -} - -declare global { - interface HASSDomEvents { - opening: undefined; - closing: undefined; - } -} diff --git a/src/dialogs/voice-assistant-setup/voice-assistant-setup-dialog.ts b/src/dialogs/voice-assistant-setup/voice-assistant-setup-dialog.ts index 1cc04ab578..23bbadad6d 100644 --- a/src/dialogs/voice-assistant-setup/voice-assistant-setup-dialog.ts +++ b/src/dialogs/voice-assistant-setup/voice-assistant-setup-dialog.ts @@ -8,8 +8,10 @@ import { computeDomain } from "../../common/entity/compute_domain"; import { formatLanguageCode } from "../../common/language/format_language"; import "../../components/chips/ha-assist-chip"; import "../../components/ha-dialog"; +import "../../components/ha-dropdown"; +import "../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../components/ha-dropdown-item"; import { getLanguageOptions } from "../../components/ha-language-picker"; -import "../../components/ha-md-button-menu"; import type { AssistSatelliteConfiguration } from "../../data/assist_satellite"; import { fetchAssistSatelliteConfiguration } from "../../data/assist_satellite"; import { getLanguageScores } from "../../data/conversation"; @@ -169,9 +171,9 @@ export class HaVoiceAssistantSetupDialog extends LitElement { >` : this._step === STEP.PIPELINE ? this._language - ? html` - html` ${lang.primary} - ` + ` )} - ` + ` : nothing : nothing} @@ -328,10 +328,8 @@ export class HaVoiceAssistantSetupDialog extends LitElement { } } - private _handlePickLanguage(ev) { - if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") return; - - this._language = ev.target.value; + private _handlePickLanguage(ev: CustomEvent<{ item: HaDropdownItem }>) { + this._language = ev.detail.item.value; } private _languageChanged(ev: CustomEvent) { @@ -401,7 +399,7 @@ export class HaVoiceAssistantSetupDialog extends LitElement { margin: 24px; display: block; } - ha-md-button-menu { + ha-dropdown { height: 48px; display: flex; align-items: center; @@ -409,6 +407,13 @@ export class HaVoiceAssistantSetupDialog extends LitElement { margin-inline-end: 12px; margin-inline-start: initial; } + ha-dropdown-item.selected { + border: 1px solid var(--primary-color); + font-weight: var(--ha-font-weight-medium); + color: var(--primary-color); + background-color: var(--ha-color-fill-primary-quiet-resting); + --icon-primary-color: var(--primary-color); + } `, ]; } diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts index 8aa7cacad3..3b5e5a8bf1 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts @@ -4,6 +4,7 @@ import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { firstWeekdayIndex } from "../../../../../common/datetime/first_weekday"; import { fireEvent } from "../../../../../common/dom/fire_event"; +import { computeDomain } from "../../../../../common/entity/compute_domain"; import type { LocalizeFunc } from "../../../../../common/translations/localize"; import "../../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../../components/ha-form/types"; @@ -11,7 +12,6 @@ import type { TimeTrigger } from "../../../../../data/automation"; import type { FrontendLocaleData } from "../../../../../data/translation"; import type { HomeAssistant } from "../../../../../types"; import type { TriggerElement } from "../ha-automation-trigger-row"; -import { computeDomain } from "../../../../../common/entity/compute_domain"; const MODE_TIME = "time"; const MODE_ENTITY = "entity"; diff --git a/src/panels/profile/ha-refresh-tokens-card.ts b/src/panels/profile/ha-refresh-tokens-card.ts index f960a43cc7..1e575f2708 100644 --- a/src/panels/profile/ha-refresh-tokens-card.ts +++ b/src/panels/profile/ha-refresh-tokens-card.ts @@ -20,7 +20,6 @@ import "../../components/ha-dropdown-item"; import "../../components/ha-icon-button"; import "../../components/ha-label"; import "../../components/ha-list-item"; -import "../../components/ha-md-button-menu"; import "../../components/ha-md-menu-item"; import "../../components/ha-settings-row"; import { deleteAllRefreshTokens } from "../../data/auth";