import {
mdiInformationOutline,
mdiLabel,
mdiPlus,
mdiTextureBox,
} from "@mdi/js";
import { LitElement, css, html, nothing, type TemplateResult } from "lit";
import {
customElement,
eventOptions,
property,
query,
state,
} from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
import { stopPropagation } from "../../../../common/dom/stop_propagation";
import "../../../../components/entity/state-badge";
import "../../../../components/ha-domain-icon";
import "../../../../components/ha-floor-icon";
import "../../../../components/ha-icon-next";
import "../../../../components/ha-md-list";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-svg-icon";
import "../../../../components/ha-tooltip";
import type { ConfigEntry } from "../../../../data/config_entries";
import type { HomeAssistant } from "../../../../types";
import type { AddAutomationElementListItem } from "../add-automation-element-dialog";
type Target = [string, string | undefined, string | undefined];
@customElement("ha-automation-add-items")
export class HaAutomationAddItems extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public items?: {
title: string;
items: AddAutomationElementListItem[];
}[];
@property() public error?: string;
@property({ attribute: "select-label" }) public selectLabel!: string;
@property({ attribute: "empty-label" }) public emptyLabel!: string;
@property({ attribute: false }) public target?: Target;
@property({ attribute: false }) public getLabel!: (
id: string
) => { name: string; icon?: string } | undefined;
@property({ attribute: false }) public configEntryLookup: Record<
string,
ConfigEntry
> = {};
@property({ type: Boolean, attribute: "tooltip-description" })
public tooltipDescription = false;
@state() private _itemsScrolled = false;
@query(".items")
private _itemsDiv!: HTMLDivElement;
protected render() {
return html`
${!this.items && !this.error
? this.selectLabel
: this.error
? html`${this.error}
${this._renderTarget(this.target)}
`
: this.items && !this.items.length
? html`${this.emptyLabel}
${this.target
? html`
${this._renderTarget(this.target)}
`
: nothing}`
: repeat(
this.items,
(_, index) => `item-group-${index}`,
(itemGroup) =>
this._renderItemList(itemGroup.title, itemGroup.items)
)}
`;
}
private _renderItemList(title, items?: AddAutomationElementListItem[]) {
if (!items || !items.length) {
return nothing;
}
return html`
${title}
${repeat(
items,
(item) => item.key,
(item) => html`
${item.name}${this._renderTarget(this.target)}
${!this.tooltipDescription && item.description
? html`${item.description}
`
: nothing}
${item.icon
? html`${item.icon}`
: item.iconPath
? html``
: nothing}
${this.tooltipDescription && item.description
? html`
${item.description} `
: nothing}
`
)}
`;
}
private _renderTarget = memoizeOne((target?: Target) => {
if (!target) {
return nothing;
}
return html`
${this._getSelectedTargetIcon(target[0], target[1])}
${target[2]}
`;
});
private _getSelectedTargetIcon(
targetType: string,
targetId: string | undefined
): TemplateResult | typeof nothing {
if (!targetId) {
return nothing;
}
if (targetType === "floor") {
return html``;
}
if (targetType === "area" && this.hass.areas[targetId]) {
const area = this.hass.areas[targetId];
if (area.icon) {
return html``;
}
return html``;
}
if (targetType === "device" && this.hass.devices[targetId]) {
const device = this.hass.devices[targetId];
const configEntry = device.primary_config_entry
? this.configEntryLookup[device.primary_config_entry]
: undefined;
const domain = configEntry?.domain;
if (domain) {
return html``;
}
}
if (targetType === "entity" && this.hass.states[targetId]) {
const stateObj = this.hass.states[targetId];
if (stateObj) {
return html``;
}
}
if (targetType === "label") {
const label = this.getLabel(targetId);
if (label?.icon) {
return html``;
}
return html``;
}
return nothing;
}
private _selected(ev) {
const item = ev.currentTarget;
fireEvent(this, "value-changed", {
value: item.value,
});
}
@eventOptions({ passive: true })
private _onItemsScroll(ev) {
const top = ev.target.scrollTop ?? 0;
this._itemsScrolled = top > 0;
}
public override scrollTo(options?: ScrollToOptions): void;
public override scrollTo(x: number, y: number): void;
public override scrollTo(
xOrOptions?: number | ScrollToOptions,
y?: number
): void {
if (typeof xOrOptions === "number") {
this._itemsDiv?.scrollTo(xOrOptions, y!);
} else {
this._itemsDiv?.scrollTo(xOrOptions);
}
}
static styles = css`
:host {
display: flex;
}
.items {
display: flex;
flex-direction: column;
overflow: auto;
flex: 1;
}
.items.blank {
border-radius: var(--ha-border-radius-xl);
background-color: var(--ha-color-surface-default);
align-items: center;
color: var(--ha-color-text-secondary);
padding: var(--ha-space-0);
margin: var(--ha-space-0) var(--ha-space-4)
max(var(--safe-area-inset-bottom), var(--ha-space-3));
line-height: var(--ha-line-height-expanded);
justify-content: center;
}
.items.error {
background-color: var(--ha-color-fill-danger-quiet-resting);
color: var(--ha-color-on-danger-normal);
}
.items ha-md-list {
--md-list-item-two-line-container-height: var(--ha-space-12);
--md-list-item-leading-space: var(--ha-space-3);
--md-list-item-trailing-space: var(--md-list-item-leading-space);
--md-list-item-bottom-space: var(--ha-space-2);
--md-list-item-top-space: var(--md-list-item-bottom-space);
--md-list-item-supporting-text-font: var(--ha-font-family-body);
--ha-md-list-item-gap: var(--ha-space-3);
gap: var(--ha-space-2);
padding: var(--ha-space-0) var(--ha-space-4);
}
.items ha-md-list ha-md-list-item {
border-radius: var(--ha-border-radius-lg);
border: 1px solid var(--ha-color-border-neutral-quiet);
}
.items ha-md-list {
padding-bottom: max(var(--safe-area-inset-bottom), var(--ha-space-3));
}
.items .item-headline {
display: flex;
align-items: center;
gap: var(--ha-space-2);
min-height: var(--ha-space-9);
flex-wrap: wrap;
}
.items-title {
position: sticky;
display: flex;
align-items: center;
font-weight: var(--ha-font-weight-medium);
padding-top: var(--ha-space-2);
padding-bottom: var(--ha-space-2);
padding-inline-start: var(--ha-space-8);
padding-inline-end: var(--ha-space-3);
top: 0;
z-index: 1;
background-color: var(--card-background-color);
}
ha-bottom-sheet .items-title {
padding-top: var(--ha-space-3);
}
.scrolled .items-title:first-of-type {
box-shadow: var(--bar-box-shadow);
border-bottom: 1px solid var(--ha-color-border-neutral-quiet);
}
ha-icon-next {
width: var(--ha-space-6);
}
ha-svg-icon.plus {
color: var(--primary-color);
}
.selected-target {
display: inline-flex;
gap: var(--ha-space-1);
justify-content: center;
align-items: center;
border-radius: var(--ha-border-radius-md);
background: var(--ha-color-fill-neutral-normal-resting);
padding: 0 var(--ha-space-2) 0 var(--ha-space-1);
color: var(--ha-color-on-neutral-normal);
overflow: hidden;
}
.selected-target .label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.selected-target ha-icon,
.selected-target ha-svg-icon,
.selected-target state-badge,
.selected-target ha-domain-icon {
display: flex;
padding: var(--ha-space-1) 0;
}
.selected-target state-badge {
--mdc-icon-size: 24px;
}
.selected-target state-badge,
.selected-target ha-floor-icon {
display: flex;
height: 32px;
width: 24px;
align-items: center;
}
.selected-target ha-domain-icon {
filter: grayscale(100%);
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-add-items": HaAutomationAddItems;
}
}