mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 05:27:46 +00:00
Finish new button api
This commit is contained in:
parent
422f05dc3b
commit
bc3933d7d7
@ -3,141 +3,123 @@ import styles from "@shoelace-style/shoelace/dist/components/button/button.style
|
|||||||
import { css } from "lit";
|
import { css } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Home Assistant button component
|
||||||
|
*
|
||||||
|
* @element ha-button
|
||||||
|
* @extends {Button}
|
||||||
|
*
|
||||||
|
* @summary
|
||||||
|
* A stylable button component supporting Home Assistant theming, variants, and appearances.
|
||||||
|
*
|
||||||
|
* @slot - Label of the button
|
||||||
|
* @slot prefix - The prefix container (usually for icons).
|
||||||
|
* @slot suffix - The suffix container (usually for icons).
|
||||||
|
*
|
||||||
|
* @csspart base - The component's base wrapper.
|
||||||
|
* @csspart prefix - The container that wraps the prefix.
|
||||||
|
* @csspart label - The button's label.
|
||||||
|
* @csspart suffix - The container that wraps the suffix.
|
||||||
|
* @csspart caret - The button's caret icon, an `<sl-icon>` element.
|
||||||
|
* @csspart spinner - The spinner that shows when the button is in the loading state.
|
||||||
|
*
|
||||||
|
* @cssprop --ha-button-font-family - Font family for the button text.
|
||||||
|
* @cssprop --ha-font-weight-medium - Medium font weight for button text.
|
||||||
|
* @cssprop --ha-button-line-height - Line height for button text.
|
||||||
|
* @cssprop --ha-button-border-width - Border width for the button.
|
||||||
|
* @cssprop --ha-button-theme-color - Main color for the button.
|
||||||
|
* @cssprop --ha-button-theme-darker-color - Darker variant of the main color.
|
||||||
|
* @cssprop --ha-button-theme-lighter-color - Lighter variant of the main color.
|
||||||
|
* @cssprop --ha-button-height - Height of the button.
|
||||||
|
* @cssprop --ha-button-border-radius - Border radius for the button.
|
||||||
|
* @cssprop --ha-button-text-color - Text color for the button.
|
||||||
|
*
|
||||||
|
* @attr {("small"|"medium")} size - Sets the button size.
|
||||||
|
* @attr {("primary"|"danger"|"neutral")} variant - Sets the button color variant. "primary" is default.
|
||||||
|
* @attr {("accent"|"filled"|"plain")} appearance - Sets the button appearance.
|
||||||
|
*/
|
||||||
@customElement("ha-button")
|
@customElement("ha-button")
|
||||||
export class HaButton extends Button {
|
export class HaButton extends Button {
|
||||||
@property({ type: Boolean }) pill = true;
|
@property() appearance?: "accent" | "filled" | "plain";
|
||||||
|
|
||||||
static override styles = [
|
static override styles = [
|
||||||
styles,
|
styles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
--sl-input-border-width: 0;
|
|
||||||
--sl-input-font-family: var(
|
--sl-input-font-family: var(
|
||||||
--ha-button-font-family,
|
--ha-button-font-family,
|
||||||
var(--ha-font-family-body)
|
var(--ha-font-family-body)
|
||||||
);
|
);
|
||||||
--sl-font-weight-semibold: var(--ha-font-weight-medium);
|
--sl-font-weight-semibold: var(
|
||||||
--sl-transition-x-fast: 0.1s; /* ? */
|
--ha-button-font-weight,
|
||||||
--sl-focus-ring: none; /* ? */
|
var(--ha-font-weight-medium)
|
||||||
--sl-focus-ring-offset: 0; /* ? */
|
);
|
||||||
|
--sl-transition-x-fast: 0.4s;
|
||||||
|
--sl-focus-ring: solid 4px var(--accent-color);
|
||||||
|
--sl-focus-ring-offset: 1px;
|
||||||
|
|
||||||
|
--sl-spacing-medium: 16px;
|
||||||
|
--sl-spacing-small: 12px;
|
||||||
|
--sl-spacing-x-small: 8px;
|
||||||
|
|
||||||
|
--ha-button-theme-color: var(--primary-color);
|
||||||
|
--ha-button-theme-darker-color: var(--dark-primary-color);
|
||||||
|
--ha-button-theme-lighter-color: var(--light-primary-color);
|
||||||
|
|
||||||
|
line-height: var(--ha-button-line-height, var(--ha-line-height-normal));
|
||||||
|
--sl-input-border-width: var(--ha-button-border-width, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([destructive]), /* Deprecated */
|
||||||
|
:host([variant="danger"]) {
|
||||||
|
--ha-button-theme-color: var(--error-color);
|
||||||
|
--ha-button-theme-darker-color: var(--error-color-darker);
|
||||||
|
--ha-button-theme-lighter-color: var(--error-color-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([variant="neutral"]) {
|
||||||
|
--ha-button-theme-color: var(--primary-text-color);
|
||||||
|
--ha-button-theme-darker-color: var(--dark-primary-color);
|
||||||
|
--ha-button-theme-lighter-color: var(--light-primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
height: 40px;
|
height: var(--ha-button-height, var(--button-height, 40px));
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
border-radius: var(--ha-button-border-radius, 48px);
|
||||||
}
|
}
|
||||||
.button.button--small {
|
.button.button--small {
|
||||||
height: 32px;
|
border-radius: var(--ha-button-border-radius, 32px);
|
||||||
|
height: var(--ha-button-height, var(--button-height, 32px));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default */
|
.button,
|
||||||
.button--standard.button--default,
|
.button:active:not(.button--disabled) {
|
||||||
.button--standard.button--primary:active:not(.button--disabled) {
|
background-color: var(--ha-button-theme-color);
|
||||||
background-color: var(
|
|
||||||
--ha-button-background-color,
|
|
||||||
var(--primary-color)
|
|
||||||
);
|
|
||||||
color: var(--ha-button-text-color, var(--white-color));
|
color: var(--ha-button-text-color, var(--white-color));
|
||||||
}
|
}
|
||||||
.button--standard.button--default:hover:not(.button--disabled) {
|
.button:hover:not(.button--disabled) {
|
||||||
background-color: var(
|
background-color: var(--ha-button-theme-darker-color);
|
||||||
--ha-button-background-color,
|
|
||||||
var(--dark-primary-color)
|
|
||||||
);
|
|
||||||
color: var(--ha-button-text-color, var(--white-color));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Danger */
|
:host([appearance="filled"]) .button,
|
||||||
:host([destructive]) .button--standard,
|
:host([appearance="filled"]) .button:active:not(.button--disabled) {
|
||||||
.button--standard.button--danger,
|
background-color: var(--ha-button-theme-lighter-color);
|
||||||
.button--standard.button--danger:active:not(.button--disabled) {
|
color: var(--ha-button-text-color, var(--ha-button-theme-color));
|
||||||
background-color: var(--ha-button-background-color, var(--error-color));
|
}
|
||||||
color: var(--ha-button-text-color, var(--white-color));
|
:host([appearance="filled"]) .button:hover:not(.button--disabled) {
|
||||||
|
background-color: var(--ha-button-theme-color);
|
||||||
|
color: var(--white-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([destructive]) .button--standard:hover:not(.button--disabled),
|
:host([appearance="plain"]) .button,
|
||||||
.button--standard.button--danger:hover:not(.button--disabled) {
|
:host([appearance="plain"]) .button:active:not(.button--disabled) {
|
||||||
background-color: var(--ha-button-background-color, var(--error-color));
|
|
||||||
color: var(--ha-button-text-color, var(--white-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Text buttons
|
|
||||||
*/
|
|
||||||
|
|
||||||
.button--text,
|
|
||||||
.button--text:active:not(.button--disabled) {
|
|
||||||
color: var(--ha-button-text-color, var(--primary-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--text:hover:not(.button--disabled),
|
|
||||||
.button--text:focus-visible:not(.button--disabled) {
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-color: transparent;
|
color: var(--ha-button-text-color, var(--ha-button-theme-color));
|
||||||
color: var(--ha-button-text-color, var(--dark-primary-color));
|
|
||||||
}
|
}
|
||||||
|
:host([appearance="plain"]) .button:hover:not(.button--disabled) {
|
||||||
.button--pill.button--small {
|
background-color: var(--ha-button-theme-lighter-color);
|
||||||
border-radius: 30px;
|
color: var(--ha-button-text-color, var(--ha-button-theme-darker-color));
|
||||||
}
|
|
||||||
|
|
||||||
.button--pill.button--medium {
|
|
||||||
border-radius: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Button spacing
|
|
||||||
*/
|
|
||||||
|
|
||||||
.button--has-label.button--small .button__label {
|
|
||||||
padding: 0 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--has-label.button--medium .button__label {
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--has-prefix.button--small,
|
|
||||||
.button--has-prefix.button--small .button__label {
|
|
||||||
padding-inline-start: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--has-prefix.button--medium,
|
|
||||||
.button--has-prefix.button--medium .button__label {
|
|
||||||
padding-inline-start: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--has-suffix.button--small,
|
|
||||||
.button--caret.button--small,
|
|
||||||
.button--has-suffix.button--small .button__label,
|
|
||||||
.button--caret.button--small .button__label {
|
|
||||||
padding-inline-end: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button--has-suffix.button--medium,
|
|
||||||
.button--caret.button--medium,
|
|
||||||
.button--has-suffix.button--medium .button__label,
|
|
||||||
.button--caret.button--medium .button__label {
|
|
||||||
padding-inline-end: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::slotted([slot="icon"]) {
|
|
||||||
margin-inline-start: 0px;
|
|
||||||
margin-inline-end: 8px;
|
|
||||||
direction: var(--direction);
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.mdc-button {
|
|
||||||
height: var(--button-height, 36px);
|
|
||||||
}
|
|
||||||
.trailing-icon {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.slot-container {
|
|
||||||
overflow: var(--button-slot-container-overflow, visible);
|
|
||||||
}
|
|
||||||
:host([destructive]) {
|
|
||||||
--mdc-theme-primary: var(--error-color);
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -4,6 +4,9 @@ import { LitElement, css, html } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import "../../../components/ha-button";
|
||||||
|
import "../../../components/ha-button-menu";
|
||||||
|
import "../../../components/ha-list-item";
|
||||||
import {
|
import {
|
||||||
ATTENTION_SOURCES,
|
ATTENTION_SOURCES,
|
||||||
DISCOVERY_SOURCES,
|
DISCOVERY_SOURCES,
|
||||||
@ -17,9 +20,6 @@ import type { HomeAssistant } from "../../../types";
|
|||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
|
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
|
||||||
import "./ha-integration-action-card";
|
import "./ha-integration-action-card";
|
||||||
import "../../../components/ha-button-menu";
|
|
||||||
import "../../../components/ha-button";
|
|
||||||
import "../../../components/ha-list-item";
|
|
||||||
|
|
||||||
@customElement("ha-config-flow-card")
|
@customElement("ha-config-flow-card")
|
||||||
export class HaConfigFlowCard extends LitElement {
|
export class HaConfigFlowCard extends LitElement {
|
||||||
@ -41,24 +41,25 @@ export class HaConfigFlowCard extends LitElement {
|
|||||||
.domain=${this.flow.handler}
|
.domain=${this.flow.handler}
|
||||||
.label=${this.flow.localized_title}
|
.label=${this.flow.localized_title}
|
||||||
>
|
>
|
||||||
|
${DISCOVERY_SOURCES.includes(this.flow.context.source) &&
|
||||||
|
this.flow.context.unique_id
|
||||||
|
? html`<ha-button appearance="plain" @click=${this._ignoreFlow}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.integrations.ignore.ignore"
|
||||||
|
)}</ha-button
|
||||||
|
>`
|
||||||
|
: ""}
|
||||||
<ha-button
|
<ha-button
|
||||||
unelevated
|
|
||||||
@click=${this._continueFlow}
|
@click=${this._continueFlow}
|
||||||
.label=${this.hass.localize(
|
variant=${attention ? "danger" : "primary"}
|
||||||
|
appearance="filled"
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
attention
|
attention
|
||||||
? "ui.panel.config.integrations.reconfigure"
|
? "ui.panel.config.integrations.reconfigure"
|
||||||
: "ui.common.add"
|
: "ui.common.add"
|
||||||
)}
|
)}
|
||||||
></ha-button>
|
</ha-button>
|
||||||
${DISCOVERY_SOURCES.includes(this.flow.context.source) &&
|
|
||||||
this.flow.context.unique_id
|
|
||||||
? html`<ha-button
|
|
||||||
@click=${this._ignoreFlow}
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.ignore.ignore"
|
|
||||||
)}
|
|
||||||
></ha-button>`
|
|
||||||
: ""}
|
|
||||||
${this.flow.context.configuration_url || this.manifest
|
${this.flow.context.configuration_url || this.manifest
|
||||||
? html`<ha-button-menu slot="header-button">
|
? html`<ha-button-menu slot="header-button">
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
|
@ -4,6 +4,7 @@ import { LitElement, css, html, nothing } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { PROTOCOL_INTEGRATIONS } from "../../../common/integrations/protocolIntegrationPicked";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
@ -23,7 +24,6 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import type { ConfigEntryExtended } from "./ha-config-integrations";
|
import type { ConfigEntryExtended } from "./ha-config-integrations";
|
||||||
import "./ha-integration-header";
|
import "./ha-integration-header";
|
||||||
import { PROTOCOL_INTEGRATIONS } from "../../../common/integrations/protocolIntegrationPicked";
|
|
||||||
|
|
||||||
@customElement("ha-integration-card")
|
@customElement("ha-integration-card")
|
||||||
export class HaIntegrationCard extends LitElement {
|
export class HaIntegrationCard extends LitElement {
|
||||||
@ -120,7 +120,7 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
? `/config/devices/device/${devices[0].id}`
|
? `/config/devices/device/${devices[0].id}`
|
||||||
: `/config/devices/dashboard?historyBack=1&domain=${this.domain}`}
|
: `/config/devices/dashboard?historyBack=1&domain=${this.domain}`}
|
||||||
>
|
>
|
||||||
<ha-button>
|
<ha-button appearance="plain">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.integrations.config_entry.${
|
`ui.panel.config.integrations.config_entry.${
|
||||||
services ? "services" : "devices"
|
services ? "services" : "devices"
|
||||||
@ -133,7 +133,7 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
? html`<a
|
? html`<a
|
||||||
href=${`/config/entities?historyBack=1&domain=${this.domain}`}
|
href=${`/config/entities?historyBack=1&domain=${this.domain}`}
|
||||||
>
|
>
|
||||||
<ha-button>
|
<ha-button appearance="plain">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.integrations.config_entry.entities`,
|
`ui.panel.config.integrations.config_entry.entities`,
|
||||||
{ count: entitiesCount }
|
{ count: entitiesCount }
|
||||||
@ -144,7 +144,7 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
? html`<a
|
? html`<a
|
||||||
href=${`/config/integrations/integration/${this.domain}`}
|
href=${`/config/integrations/integration/${this.domain}`}
|
||||||
>
|
>
|
||||||
<ha-button>
|
<ha-button appearance="plain">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
`ui.panel.config.integrations.config_entry.entries`,
|
`ui.panel.config.integrations.config_entry.entries`,
|
||||||
{
|
{
|
||||||
@ -309,6 +309,7 @@ export class HaIntegrationCard extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
padding: 4px 16px 4px 4px;
|
||||||
}
|
}
|
||||||
.debug-logging {
|
.debug-logging {
|
||||||
--state-color: var(--warning-color);
|
--state-color: var(--warning-color);
|
||||||
|
@ -34,6 +34,8 @@ export const colorStyles = css`
|
|||||||
--scrollbar-thumb-color: rgb(194, 194, 194);
|
--scrollbar-thumb-color: rgb(194, 194, 194);
|
||||||
|
|
||||||
--error-color: #db4437;
|
--error-color: #db4437;
|
||||||
|
--error-color-lighter: #ffdedc;
|
||||||
|
--error-color-darker: #b30532;
|
||||||
--warning-color: #ffa600;
|
--warning-color: #ffa600;
|
||||||
--success-color: #43a047;
|
--success-color: #43a047;
|
||||||
--info-color: #039be5;
|
--info-color: #039be5;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user