1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-04-17 15:45:43 +01:00
Files
frontend/src/components/ha-icon-button.ts
2026-02-27 15:44:21 +00:00

114 lines
3.1 KiB
TypeScript

import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import "./ha-button";
import "./ha-svg-icon";
@customElement("ha-icon-button")
export class HaIconButton extends LitElement {
@property({ type: Boolean, reflect: true }) disabled = false;
// SVG icon path (if you need a non SVG icon instead, use the provided slot to pass an <ha-icon> in)
@property({ type: String }) path?: string;
// Label that is used for ARIA support and as tooltip
@property({ type: String }) label?: string;
// These should always be set as properties, not attributes,
// so that only the <button> element gets the attribute
@property({ type: String, attribute: "aria-haspopup" })
ariaHasPopup!: "false" | "true" | "menu" | "listbox" | "tree" | "grid";
@property({ attribute: "hide-title", type: Boolean }) hideTitle = false;
@property({ type: Boolean, reflect: true }) selected = false;
@property() href?: string;
@property() target?: "_blank" | "_parent" | "_self" | "_top";
@property() rel?: string;
@property() download?: string;
static shadowRootOptions: ShadowRootInit = {
mode: "open",
delegatesFocus: true,
};
protected render(): TemplateResult {
return html`
<ha-button
appearance="plain"
variant="neutral"
aria-label=${ifDefined(this.label)}
title=${ifDefined(this.hideTitle ? undefined : this.label)}
aria-haspopup=${ifDefined(this.ariaHasPopup)}
.disabled=${this.disabled}
.iconTag=${this.path ? "ha-svg-icon" : "span"}
.href=${this.href}
.target=${this.target}
.rel=${this.rel}
.download=${this.download}
>
${this.path
? html`<ha-svg-icon .path=${this.path}></ha-svg-icon>`
: html`<span><slot></slot></span>`}
</ha-button>
`;
}
static styles: CSSResultGroup = css`
:host {
display: inline-block;
outline: none;
--ha-button-height: var(--ha-icon-button-size, 48px);
}
ha-button {
position: relative;
isolation: isolate;
--wa-form-control-padding-inline: var(
--ha-icon-button-padding-inline,
--ha-space-2
);
--wa-color-on-normal: currentColor;
--wa-color-fill-quiet: transparent;
--ha-button-label-overflow: visible;
}
ha-button::after {
content: "";
position: absolute;
inset: 0;
z-index: -1;
border-radius: 50%;
background-color: currentColor;
opacity: 0;
pointer-events: none;
}
ha-button::part(base) {
width: var(--wa-form-control-height);
aspect-ratio: 1;
outline-offset: -4px;
}
ha-button::part(label) {
display: flex;
}
:host([selected]) ha-button::after {
opacity: 0.1;
}
@media (hover: hover) {
:host(:hover:not([disabled])) ha-button::after {
opacity: 0.1;
}
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-icon-button": HaIconButton;
}
}