diff --git a/src/components/chips/ha-assist-chip.ts b/src/components/chips/ha-assist-chip.ts
index 7071663cd2..5a7b0d1fd5 100644
--- a/src/components/chips/ha-assist-chip.ts
+++ b/src/components/chips/ha-assist-chip.ts
@@ -22,14 +22,6 @@ export class HaAssistChip extends MdAssistChip {
);
--md-assist-chip-outline-color: var(--outline-color);
--md-assist-chip-label-text-weight: 400;
- --ha-assist-chip-filled-container-color: rgba(
- var(--rgb-primary-text-color),
- 0.15
- );
- --ha-assist-chip-active-container-color: rgba(
- var(--rgb-primary-color),
- 0.15
- );
}
/** Material 3 doesn't have a filled chip, so we have to make our own **/
.filled {
@@ -52,6 +44,10 @@ export class HaAssistChip extends MdAssistChip {
margin-inline-end: unset;
margin-inline-start: var(--_icon-label-space);
}
+ ::before {
+ background: var(--ha-assist-chip-container-color);
+ opacity: var(--ha-assist-chip-container-opacity);
+ }
:where(.active)::before {
background: var(--ha-assist-chip-active-container-color);
opacity: var(--ha-assist-chip-active-container-opacity);
diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts
index fbd6d97281..e514526c3b 100644
--- a/src/components/data-table/ha-data-table.ts
+++ b/src/components/data-table/ha-data-table.ts
@@ -181,6 +181,13 @@ export class HaDataTable extends LitElement {
this._checkedRowsChanged();
}
+ public selectAll(): void {
+ this._checkedRows = this._filteredData
+ .filter((data) => data.selectable !== false)
+ .map((data) => data[this.id]);
+ this._checkedRowsChanged();
+ }
+
public connectedCallback() {
super.connectedCallback();
if (this._items.length) {
@@ -593,10 +600,7 @@ export class HaDataTable extends LitElement {
private _handleHeaderRowCheckboxClick(ev: Event) {
const checkbox = ev.target as HaCheckbox;
if (checkbox.checked) {
- this._checkedRows = this._filteredData
- .filter((data) => data.selectable !== false)
- .map((data) => data[this.id]);
- this._checkedRowsChanged();
+ this.selectAll();
} else {
this._checkedRows = [];
this._checkedRowsChanged();
diff --git a/src/components/ha-button-menu-new.ts b/src/components/ha-button-menu-new.ts
new file mode 100644
index 0000000000..3ec12b1108
--- /dev/null
+++ b/src/components/ha-button-menu-new.ts
@@ -0,0 +1,89 @@
+import { Button } from "@material/mwc-button";
+import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
+import { customElement, property, query } from "lit/decorators";
+import { FOCUS_TARGET } from "../dialogs/make-dialog-manager";
+import type { HaIconButton } from "./ha-icon-button";
+import "./ha-menu";
+import type { HaMenu } from "./ha-menu";
+
+@customElement("ha-button-menu-new")
+export class HaButtonMenuNew extends LitElement {
+ protected readonly [FOCUS_TARGET];
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property() public positioning?: "fixed" | "absolute" | "popover";
+
+ @property({ type: Boolean, attribute: "has-overflow" }) public hasOverflow =
+ false;
+
+ @query("ha-menu", true) private _menu!: HaMenu;
+
+ 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 _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"], mwc-button[slot="trigger"], ha-assist-chip[slot="trigger"]'
+ ) as HaIconButton | Button | null;
+ }
+
+ private _setTriggerAria() {
+ if (this._triggerButton) {
+ this._triggerButton.ariaHasPopup = "menu";
+ }
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ :host {
+ display: inline-block;
+ position: relative;
+ }
+ ::slotted([disabled]) {
+ color: var(--disabled-text-color);
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-button-menu-new": HaButtonMenuNew;
+ }
+}
diff --git a/src/components/ha-sub-menu.ts b/src/components/ha-sub-menu.ts
new file mode 100644
index 0000000000..15a5afdc47
--- /dev/null
+++ b/src/components/ha-sub-menu.ts
@@ -0,0 +1,38 @@
+import { customElement } from "lit/decorators";
+import "element-internals-polyfill";
+import { CSSResult, css } from "lit";
+import { MdSubMenu } from "@material/web/menu/sub-menu";
+
+@customElement("ha-sub-menu")
+// @ts-expect-error
+export class HaSubMenu extends MdSubMenu {
+ static override styles: CSSResult[] = [
+ MdSubMenu.styles,
+ css`
+ :host {
+ --ha-icon-display: block;
+ --md-sys-color-primary: var(--primary-text-color);
+ --md-sys-color-on-primary: var(--primary-text-color);
+ --md-sys-color-secondary: var(--secondary-text-color);
+ --md-sys-color-surface: var(--card-background-color);
+ --md-sys-color-on-surface: var(--primary-text-color);
+ --md-sys-color-on-surface-variant: var(--secondary-text-color);
+ --md-sys-color-secondary-container: rgba(
+ var(--rgb-primary-color),
+ 0.15
+ );
+ --md-sys-color-on-secondary-container: var(--text-primary-color);
+ --mdc-icon-size: 16px;
+
+ --md-sys-color-on-primary-container: var(--primary-text-color);
+ --md-sys-color-on-secondary-container: var(--primary-text-color);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-sub-menu": HaSubMenu;
+ }
+}
diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts
index b58d073165..53a60e37e3 100644
--- a/src/layouts/hass-tabs-subpage-data-table.ts
+++ b/src/layouts/hass-tabs-subpage-data-table.ts
@@ -1,12 +1,13 @@
import { ResizeController } from "@lit-labs/observers/resize-controller";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import "@material/mwc-button/mwc-button";
+import "@material/web/divider/divider";
import {
mdiArrowDown,
mdiArrowUp,
mdiClose,
- mdiFilterVariantRemove,
mdiFilterVariant,
+ mdiFilterVariantRemove,
mdiFormatListChecks,
mdiMenuDown,
} from "@mdi/js";
@@ -31,14 +32,14 @@ import type {
HaDataTable,
SortingDirection,
} from "../components/data-table/ha-data-table";
+import "../components/ha-button-menu-new";
import "../components/ha-dialog";
-import "../components/search-input-outlined";
-import "../components/ha-menu";
+import { HaMenu } from "../components/ha-menu";
import "../components/ha-menu-item";
+import "../components/search-input-outlined";
import type { HomeAssistant, Route } from "../types";
import "./hass-tabs-subpage";
import type { PageNavigation } from "./hass-tabs-subpage";
-import type { HaMenu } from "../components/ha-menu";
declare global {
// for fire event
@@ -227,7 +228,7 @@ export class HaTabsSubpageDataTable extends LitElement {
class="has-dropdown select-mode-chip"
.active=${this._selectMode}
@click=${this._enableSelectMode}
- .label=${localize(
+ .title=${localize(
"ui.components.subpage-data-table.enter_selection_mode"
)}
>
@@ -255,8 +256,11 @@ export class HaTabsSubpageDataTable extends LitElement {
id="sort-by-anchor"
@click=${this._toggleSortBy}
>
-
+
+
`
: nothing;
@@ -293,7 +297,7 @@ export class HaTabsSubpageDataTable extends LitElement {
>
${this._selectMode
? html`
-
+
+
+
+
+
+ ${localize("ui.components.subpage-data-table.select_all")}
+
+ ${localize("ui.components.subpage-data-table.select_none")}
+
+
+ ${localize(
+ "ui.components.subpage-data-table.close_select_mode"
+ )}
+
+
${localize("ui.components.subpage-data-table.selected", {
selected: this.selected || "0",
@@ -440,16 +475,15 @@ export class HaTabsSubpageDataTable extends LitElement {
`
: nothing
)}
-
+
${localize(
- "ui.components.subpage-data-table.dont_group_by"
- )}
+ ${localize("ui.components.subpage-data-table.dont_group_by")}
+