From 681b60614f6bf342a76d31f0afaae71942c8caaa Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 20 Jan 2026 15:20:29 +0100 Subject: [PATCH] Migrate button-menu to ha-dropdown in 9 files (#29089) Co-authored-by: Claude Sonnet 4.5 --- .../config/cloud/account/cloud-account.ts | 31 +++-- .../config/cloud/login/cloud-login-panel.ts | 31 +++-- .../storage/ha-config-section-storage.ts | 1 - .../config/voice-assistants/assist-pref.ts | 124 ++++++++++-------- .../components/hui-badge-edit-mode.ts | 66 +++++----- .../components/hui-energy-period-selector.ts | 50 ++++--- .../components/hui-section-edit-mode.ts | 2 - .../section-editor/hui-dialog-edit-section.ts | 44 +++---- .../media-browser/ha-panel-media-browser.ts | 80 ++++++----- 9 files changed, 223 insertions(+), 206 deletions(-) diff --git a/src/panels/config/cloud/account/cloud-account.ts b/src/panels/config/cloud/account/cloud-account.ts index 6dd24ba959..b625864bc0 100644 --- a/src/panels/config/cloud/account/cloud-account.ts +++ b/src/panels/config/cloud/account/cloud-account.ts @@ -6,9 +6,12 @@ import { fireEvent } from "../../../../common/dom/fire_event"; import { debounce } from "../../../../common/util/debounce"; import "../../../../components/ha-alert"; import "../../../../components/ha-button"; -import "../../../../components/ha-button-menu"; import "../../../../components/ha-card"; +import "../../../../components/ha-dropdown"; +import "../../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../../components/ha-dropdown-item"; import "../../../../components/ha-list-item"; +import "../../../../components/ha-svg-icon"; import "../../../../components/ha-tip"; import type { CloudStatusLoggedIn, @@ -53,26 +56,26 @@ export class CloudAccount extends SubscribeMixin(LitElement) { .narrow=${this.narrow} header="Home Assistant Cloud" > - + - + ${this.hass.localize( "ui.panel.config.cloud.account.reset_cloud_data" )} - - - + + + ${this.hass.localize( "ui.panel.config.cloud.account.download_support_package" )} - - - + + +
Home Assistant Cloud @@ -297,13 +300,15 @@ export class CloudAccount extends SubscribeMixin(LitElement) { fireEvent(this, "ha-refresh-cloud-status"); } - private _handleMenuAction(ev) { - switch (ev.detail.index) { - case 0: + private _handleMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + switch (value) { + case "reset": this._deleteCloudData(); break; - case 1: + case "download": this._downloadSupportPackage(); + break; } } diff --git a/src/panels/config/cloud/login/cloud-login-panel.ts b/src/panels/config/cloud/login/cloud-login-panel.ts index dd9e9622b2..114eec0b4a 100644 --- a/src/panels/config/cloud/login/cloud-login-panel.ts +++ b/src/panels/config/cloud/login/cloud-login-panel.ts @@ -5,11 +5,14 @@ import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import { navigate } from "../../../../common/navigate"; import "../../../../components/ha-alert"; -import "../../../../components/ha-button-menu"; import "../../../../components/ha-card"; +import "../../../../components/ha-dropdown"; +import "../../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../../components/ha-dropdown-item"; import "../../../../components/ha-icon-next"; import "../../../../components/ha-list"; import "../../../../components/ha-list-item"; +import "../../../../components/ha-svg-icon"; import { removeCloudData } from "../../../../data/cloud"; import { showAlertDialog, @@ -44,26 +47,26 @@ export class CloudLoginPanel extends LitElement { .narrow=${this.narrow} header="Home Assistant Cloud" > - + - + ${this.hass.localize( "ui.panel.config.cloud.account.reset_cloud_data" )} - - - + + + ${this.hass.localize( "ui.panel.config.cloud.account.download_support_package" )} - - - + + +
Home Assistant Cloud @@ -164,13 +167,15 @@ export class CloudLoginPanel extends LitElement { fireEvent(this, "flash-message-changed", { value: "" }); } - private _handleMenuAction(ev) { - switch (ev.detail.index) { - case 0: + private _handleMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + switch (value) { + case "reset": this._deleteCloudData(); break; - case 1: + case "download": this._downloadSupportPackage(); + break; } } diff --git a/src/panels/config/storage/ha-config-section-storage.ts b/src/panels/config/storage/ha-config-section-storage.ts index d435a20e41..0ce4d8a45a 100644 --- a/src/panels/config/storage/ha-config-section-storage.ts +++ b/src/panels/config/storage/ha-config-section-storage.ts @@ -14,7 +14,6 @@ import { navigate } from "../../../common/navigate"; import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; import "../../../components/ha-alert"; import "../../../components/ha-button"; -import "../../../components/ha-button-menu"; import "../../../components/ha-icon-button"; import "../../../components/ha-icon-next"; import "../../../components/ha-list"; diff --git a/src/panels/config/voice-assistants/assist-pref.ts b/src/panels/config/voice-assistants/assist-pref.ts index 41ed0a112e..118547de1e 100644 --- a/src/panels/config/voice-assistants/assist-pref.ts +++ b/src/panels/config/voice-assistants/assist-pref.ts @@ -1,3 +1,4 @@ +import "@home-assistant/webawesome/dist/components/divider/divider"; import { mdiBug, mdiCommentProcessingOutline, @@ -18,14 +19,17 @@ import { formatLanguageCode } from "../../../common/language/format_language"; import { navigate } from "../../../common/navigate"; import "../../../components/ha-alert"; import "../../../components/ha-button"; -import "../../../components/ha-button-menu"; import "../../../components/ha-card"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-icon-button"; import "../../../components/ha-list"; import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; import "../../../components/ha-switch"; import type { HaSwitch } from "../../../components/ha-switch"; +import "../../../components/voice-assistant-brand-icon"; import type { AssistPipeline } from "../../../data/assist_pipeline"; import { createAssistPipeline, @@ -48,7 +52,6 @@ import { showVoiceCommandDialog } from "../../../dialogs/voice-command-dialog/sh import type { HomeAssistant } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; import { showVoiceAssistantPipelineDetailDialog } from "./show-dialog-voice-assistant-pipeline-detail"; -import "../../../components/voice-assistant-brand-icon"; @customElement("assist-pref") export class AssistPref extends LitElement { @@ -144,7 +147,12 @@ export class AssistPref extends LitElement { ${formatLanguageCode(pipeline.language, this.hass.locale)} - + - + ${this.hass!.localize( "ui.panel.config.voice_assistants.assistants.pipeline.start_conversation" )} - - + ${this.hass.localize( "ui.panel.config.voice_assistants.assistants.pipeline.detail.set_as_preferred" )} - - - + + + ${this.hass.localize( "ui.panel.config.voice_assistants.assistants.pipeline.detail.debug" )} - - - + + + ${this.hass.localize("ui.common.duplicate")} - - + + ${this.hass.localize("ui.common.delete")} - - - + + + ` )} @@ -286,24 +278,42 @@ export class AssistPref extends LitElement { } } - private _talkWithPipeline(ev) { - const id = ev.currentTarget.id as string; + private _handlePipelineMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + const id = (ev.detail.item as any).data as string; + switch (value) { + case "talk": + this._talkWithPipeline(id); + break; + case "set-preferred": + this._setPreferredPipeline(id); + break; + case "debug": + this._debugPipeline(id); + break; + case "duplicate": + this._duplicatePipeline(id); + break; + case "delete": + this._deletePipeline(id); + break; + } + } + + private _talkWithPipeline(id: string) { showVoiceCommandDialog(this, this.hass, { pipeline_id: id }); } - private async _setPreferredPipeline(ev) { - const id = ev.currentTarget.id as string; + private async _setPreferredPipeline(id: string) { await setAssistPipelinePreferred(this.hass!, id); this._preferred = id; } - private async _debugPipeline(ev) { - const id = ev.currentTarget.id as string; + private async _debugPipeline(id: string) { navigate(`/config/voice-assistants/debug/${id}`); } - private async _duplicatePipeline(ev: Event) { - const id = (ev.currentTarget as HTMLElement).id as string; + private async _duplicatePipeline(id: string) { const pipeline = this._pipelines.find((res) => res.id === id); if (!pipeline) { showAlertDialog(this, { @@ -326,8 +336,7 @@ export class AssistPref extends LitElement { this._openDialog(newPipeline); } - private async _deletePipeline(ev) { - const id = ev.currentTarget.id as string; + private async _deletePipeline(id: string) { if (this._preferred === id) { showAlertDialog(this, { text: this.hass!.localize( @@ -426,16 +435,11 @@ export class AssistPref extends LitElement { --mdc-list-side-padding-left: 16px; } - ha-list-item.danger { - color: var(--error-color); - border-top: 1px solid var(--divider-color); - } - ha-button-menu a { text-decoration: none; } - ha-svg-icon { + ha-list-item span ha-svg-icon { color: currentColor; width: 16px; } @@ -460,6 +464,12 @@ export class AssistPref extends LitElement { margin-inline-end: 16px; margin-inline-start: initial; } + + ha-dropdown { + font-size: var(--ha-font-size-m); + font-family: var(--ha-font-family-body); + letter-spacing: normal; + } `; } diff --git a/src/panels/lovelace/components/hui-badge-edit-mode.ts b/src/panels/lovelace/components/hui-badge-edit-mode.ts index 0bc367daab..cf2952a232 100644 --- a/src/panels/lovelace/components/hui-badge-edit-mode.ts +++ b/src/panels/lovelace/components/hui-badge-edit-mode.ts @@ -1,4 +1,4 @@ -import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; +import "@home-assistant/webawesome/dist/components/divider/divider"; import { mdiContentCopy, mdiContentCut, @@ -14,9 +14,10 @@ import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { storage } from "../../../common/decorators/storage"; import { fireEvent } from "../../../common/dom/fire_event"; -import "../../../components/ha-button-menu"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-icon-button"; -import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; import { ensureBadgeConfig } from "../../../data/lovelace/config/badge"; import type { LovelaceCardConfig } from "../../../data/lovelace/config/card"; @@ -120,48 +121,46 @@ export class HuiBadgeEditMode extends LitElement {
- - - + + ${this.hass.localize("ui.panel.lovelace.editor.edit_card.edit")} - - + + ${this.hass.localize( "ui.panel.lovelace.editor.edit_card.duplicate" )} - - - + + + ${this.hass.localize("ui.panel.lovelace.editor.edit_card.copy")} - - - + + + ${this.hass.localize("ui.panel.lovelace.editor.edit_card.cut")} - -
  • - + + + ${this.hass.localize("ui.panel.lovelace.editor.edit_card.delete")} - -
    + +
    `; } @@ -186,21 +185,22 @@ export class HuiBadgeEditMode extends LitElement { this._editBadge(); } - private _handleAction(ev: CustomEvent) { - switch (ev.detail.index) { - case 0: + private _handleAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + switch (value) { + case "edit": this._editBadge(); break; - case 1: + case "duplicate": this._duplicateBadge(); break; - case 2: + case "copy": this._copyBadge(); break; - case 3: + case "cut": this._cutBadge(); break; - case 4: + case "delete": this._deleteBadge(); break; } @@ -297,7 +297,7 @@ export class HuiBadgeEditMode extends LitElement { background: var(--secondary-background-color); --mdc-icon-size: 16px; } - .more { + .more ha-icon-button { position: absolute; right: -8px; top: -8px; diff --git a/src/panels/lovelace/components/hui-energy-period-selector.ts b/src/panels/lovelace/components/hui-energy-period-selector.ts index 42267dadf6..14c8577f38 100644 --- a/src/panels/lovelace/components/hui-energy-period-selector.ts +++ b/src/panels/lovelace/components/hui-energy-period-selector.ts @@ -1,5 +1,4 @@ -import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; -import { mdiDotsVertical } from "@mdi/js"; +import { mdiCheck, mdiDotsVertical } from "@mdi/js"; import { differenceInDays, differenceInMonths, @@ -16,14 +15,16 @@ import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { PropertyValues } from "lit"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; import { classMap } from "lit/directives/class-map"; +import memoizeOne from "memoize-one"; import { calcDate, - calcDateProperty, calcDateDifferenceProperty, + calcDateProperty, shiftDateRange, } from "../../../common/datetime/calc_date"; +import type { DateRange } from "../../../common/datetime/calc_date_range"; +import { calcDateRange } from "../../../common/datetime/calc_date_range"; import { firstWeekdayIndex } from "../../../common/datetime/first_weekday"; import { formatDate, @@ -33,19 +34,19 @@ import { formatDateYear, } from "../../../common/datetime/format_date"; import { debounce } from "../../../common/util/debounce"; -import "../../../components/ha-button-menu"; import "../../../components/ha-button"; -import "../../../components/ha-check-list-item"; import "../../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../../components/ha-date-range-picker"; +import "../../../components/ha-dropdown"; +import "../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../components/ha-dropdown-item"; import "../../../components/ha-icon-button-next"; import "../../../components/ha-icon-button-prev"; +import "../../../components/ha-svg-icon"; import type { EnergyData } from "../../../data/energy"; import { CompareMode, getEnergyDataCollection } from "../../../data/energy"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import type { HomeAssistant } from "../../../types"; -import { calcDateRange } from "../../../common/datetime/calc_date_range"; -import type { DateRange } from "../../../common/datetime/calc_date_range"; const RANGE_KEYS: DateRange[] = [ "today", @@ -233,25 +234,30 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) { ` : nothing} - + ${this.allowCompare - ? html` + ? html` + ${this._compare + ? html`` + : nothing} ${this.hass.localize( "ui.panel.lovelace.components.energy_period_selector.compare" )} - ` + ` : nothing} - + `; } @@ -464,11 +470,15 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) { this._datepickerOpen = ev.detail.open; } - private _toggleCompare(ev: CustomEvent) { - if (ev.detail.source !== "interaction") { - return; + private _handleMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + if (value === "toggle-compare") { + this._toggleCompare(); } - this._compare = ev.detail.selected; + } + + private _toggleCompare() { + this._compare = !this._compare; const energyCollection = getEnergyDataCollection(this.hass, { key: this.collectionKey, }); diff --git a/src/panels/lovelace/components/hui-section-edit-mode.ts b/src/panels/lovelace/components/hui-section-edit-mode.ts index b1cf2404ad..31698696db 100644 --- a/src/panels/lovelace/components/hui-section-edit-mode.ts +++ b/src/panels/lovelace/components/hui-section-edit-mode.ts @@ -2,9 +2,7 @@ import { mdiDelete, mdiDragHorizontalVariant, mdiPencil } from "@mdi/js"; import type { CSSResultGroup, TemplateResult } from "lit"; import { LitElement, css, html } from "lit"; import { customElement, property } from "lit/decorators"; -import "../../../components/ha-button-menu"; import "../../../components/ha-icon-button"; -import "../../../components/ha-list-item"; import "../../../components/ha-svg-icon"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import { haStyle } from "../../../resources/styles"; diff --git a/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts b/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts index c4b78c4767..414be54c27 100644 --- a/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts +++ b/src/panels/lovelace/editor/section-editor/hui-dialog-edit-section.ts @@ -1,4 +1,3 @@ -import type { ActionDetail } from "@material/mwc-list"; import { mdiClose, mdiDotsVertical, @@ -12,11 +11,12 @@ import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../../common/dom/fire_event"; import { stopPropagation } from "../../../../common/dom/stop_propagation"; import "../../../../components/ha-button"; -import "../../../../components/ha-button-menu"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; +import "../../../../components/ha-dropdown"; +import "../../../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../../../components/ha-dropdown-item"; import "../../../../components/ha-icon-button"; -import "../../../../components/ha-list-item"; import "../../../../components/ha-tab-group"; import "../../../../components/ha-tab-group-tab"; import "../../../../components/ha-yaml-editor"; @@ -165,38 +165,33 @@ export class HuiDialogEditSection .path=${mdiClose} > ${heading} - - + + ${this.hass.localize( `ui.panel.lovelace.editor.edit_view.edit_${!this._yamlMode ? "yaml" : "ui"}` )} + + - - ${this.hass!.localize( "ui.panel.lovelace.editor.edit_view.move_to_view" )} - - - + + ${!this._yamlMode ? html` @@ -246,14 +241,13 @@ export class HuiDialogEditSection this._currTab = newTab; } - private async _handleAction(ev: CustomEvent) { - ev.stopPropagation(); - ev.preventDefault(); - switch (ev.detail.index) { - case 0: + private async _handleAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + switch (value) { + case "toggle-yaml": this._yamlMode = !this._yamlMode; break; - case 1: + case "move-to-view": this._openSelectView(); break; } diff --git a/src/panels/media-browser/ha-panel-media-browser.ts b/src/panels/media-browser/ha-panel-media-browser.ts index 8272c84205..dcae744852 100644 --- a/src/panels/media-browser/ha-panel-media-browser.ts +++ b/src/panels/media-browser/ha-panel-media-browser.ts @@ -1,4 +1,3 @@ -import type { ActionDetail } from "@material/mwc-list"; import { mdiAlphaABoxOutline, mdiDotsVertical, @@ -12,9 +11,11 @@ import { storage } from "../../common/decorators/storage"; import type { HASSDomEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event"; import { navigate } from "../../common/navigate"; +import "../../components/ha-dropdown"; +import "../../components/ha-dropdown-item"; +import type { HaDropdownItem } from "../../components/ha-dropdown-item"; import "../../components/ha-icon-button"; import "../../components/ha-icon-button-arrow-prev"; -import "../../components/ha-list-item"; import "../../components/ha-menu-button"; import "../../components/ha-top-app-bar-fixed"; import "../../components/media-player/ha-media-manage-button"; @@ -119,43 +120,40 @@ class PanelMediaBrowser extends LitElement { .currentItem=${this._currentItem} @media-refresh=${this._refreshMedia} > - + - + ${this.hass.localize("ui.components.media-browser.auto")} - - - + + + ${this.hass.localize("ui.components.media-browser.grid")} - - - + + + ${this.hass.localize("ui.components.media-browser.list")} - - - + + + ) { - switch (ev.detail.index) { - case 0: - this._preferredLayout = "auto"; - break; - case 1: - this._preferredLayout = "grid"; - break; - case 2: - this._preferredLayout = "list"; - break; + private _handleMenuAction(ev: CustomEvent<{ item: HaDropdownItem }>) { + const value = ev.detail.item.value; + + if (["auto", "grid", "list"].includes(value)) { + this._preferredLayout = value as MediaPlayerLayoutType; } } @@ -372,6 +364,10 @@ class PanelMediaBrowser extends LitElement { color: var(--primary-color); } + .selected_menu_item ha-svg-icon { + color: currentColor; + } + ha-bar-media-player { position: fixed; bottom: var(--safe-area-inset-bottom, 0px);