mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 21:17:47 +00:00
Fix ha-progress-button
This commit is contained in:
parent
39171c95d9
commit
7ce88da20e
32
gallery/src/pages/components/ha-progress-button.markdown
Normal file
32
gallery/src/pages/components/ha-progress-button.markdown
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
title: Progress Button
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
# Progress Button `<ha-progress-button>`
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
This component is a wrapper around `<ha-button>` that adds support for showing progress
|
||||||
|
|
||||||
|
**Slots**
|
||||||
|
|
||||||
|
- default slot: Label of the button
|
||||||
|
` - no default
|
||||||
|
|
||||||
|
**Properties/Attributes**
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
| ---------- | ---------------------------------------------- | --------- | -------------------------------------------------- |
|
||||||
|
| label | string | "accent" | Sets the button label. |
|
||||||
|
| disabled | Boolean | false | Disables the button if true. |
|
||||||
|
| progress | Boolean | false | Shows a progress indicator on the button. |
|
||||||
|
| appearance | "accent"/"filled"/"plain" | "accent" | Sets the button appearance. |
|
||||||
|
| variants | "brand"/"danger"/"neutral"/"warning"/"success" | "brand" | Sets the button color variant. "brand" is default. |
|
||||||
|
| iconPath | string | undefined | Sets the icon path for the button. |
|
139
gallery/src/pages/components/ha-progress-button.ts
Normal file
139
gallery/src/pages/components/ha-progress-button.ts
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import type { TemplateResult } from "lit";
|
||||||
|
import { css, html, LitElement } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { applyThemesOnElement } from "../../../../src/common/dom/apply_themes_on_element";
|
||||||
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-svg-icon";
|
||||||
|
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
|
||||||
|
|
||||||
|
@customElement("demo-components-ha-progress-button")
|
||||||
|
export class DemoHaProgressButton extends LitElement {
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
${["light", "dark"].map(
|
||||||
|
(mode) => html`
|
||||||
|
<div class=${mode}>
|
||||||
|
<ha-card header="ha-progress-button in ${mode}">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-progress-button @click=${this._clickedSuccess}>
|
||||||
|
Success
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button @click=${this._clickedFail}>
|
||||||
|
Fail
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button size="small" @click=${this._clickedSuccess}>
|
||||||
|
small
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button
|
||||||
|
appearance="filled"
|
||||||
|
@click=${this._clickedSuccess}
|
||||||
|
>
|
||||||
|
filled
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button
|
||||||
|
appearance="plain"
|
||||||
|
@click=${this._clickedSuccess}
|
||||||
|
>
|
||||||
|
plain
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button
|
||||||
|
variant="warning"
|
||||||
|
@click=${this._clickedSuccess}
|
||||||
|
>
|
||||||
|
warning
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button
|
||||||
|
variant="neutral"
|
||||||
|
@click=${this._clickedSuccess}
|
||||||
|
label="with icon"
|
||||||
|
.iconPath=${mdiHomeAssistant}
|
||||||
|
>
|
||||||
|
With Icon
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button progress @click=${this._clickedSuccess}>
|
||||||
|
progress
|
||||||
|
</ha-progress-button>
|
||||||
|
<ha-progress-button disabled @click=${this._clickedSuccess}>
|
||||||
|
disabled
|
||||||
|
</ha-progress-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
applyThemesOnElement(
|
||||||
|
this.shadowRoot!.querySelector(".dark"),
|
||||||
|
{
|
||||||
|
default_theme: "default",
|
||||||
|
default_dark_theme: "default",
|
||||||
|
themes: {},
|
||||||
|
darkMode: true,
|
||||||
|
theme: "default",
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _clickedSuccess(ev: CustomEvent): Promise<void> {
|
||||||
|
console.log("Clicked success");
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
|
button.progress = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
button.actionSuccess();
|
||||||
|
button.progress = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _clickedFail(ev: CustomEvent): Promise<void> {
|
||||||
|
const button = ev.currentTarget as any;
|
||||||
|
button.progress = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
button.actionError();
|
||||||
|
button.progress = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.dark,
|
||||||
|
.light {
|
||||||
|
display: block;
|
||||||
|
background-color: var(--primary-background-color);
|
||||||
|
padding: 0 50px;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
padding: unset;
|
||||||
|
}
|
||||||
|
ha-card {
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
.card-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
.card-content div {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-components-ha-progress-button": DemoHaProgressButton;
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,8 @@ import { css, html, LitElement } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../src/components/ha-button-menu";
|
|
||||||
import "../../../src/components/ha-button";
|
import "../../../src/components/ha-button";
|
||||||
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import type { HassioStats } from "../../../src/data/hassio/common";
|
import type { HassioStats } from "../../../src/data/hassio/common";
|
||||||
@ -94,7 +94,7 @@ class HassioCoreInfo extends LitElement {
|
|||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
class="warning"
|
variant="danger"
|
||||||
@click=${this._coreRestart}
|
@click=${this._coreRestart}
|
||||||
.title=${this.supervisor.localize("common.restart_name", {
|
.title=${this.supervisor.localize("common.restart_name", {
|
||||||
name: "Core",
|
name: "Core",
|
||||||
@ -187,11 +187,6 @@ class HassioCoreInfo extends LitElement {
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
|
||||||
--mdc-theme-primary: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-button-menu {
|
ha-button-menu {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
--mdc-menu-min-width: 200px;
|
--mdc-menu-min-width: 200px;
|
||||||
|
@ -171,7 +171,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
${this.supervisor.host.features.includes("reboot")
|
${this.supervisor.host.features.includes("reboot")
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button class="warning" @click=${this._hostReboot}>
|
<ha-progress-button variant="danger" @click=${this._hostReboot}>
|
||||||
${this.supervisor.localize("system.host.reboot_host")}
|
${this.supervisor.localize("system.host.reboot_host")}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
`
|
`
|
||||||
@ -179,7 +179,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
${this.supervisor.host.features.includes("shutdown")
|
${this.supervisor.host.features.includes("shutdown")
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
class="warning"
|
variant="danger"
|
||||||
@click=${this._hostShutdown}
|
@click=${this._hostShutdown}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("system.host.shutdown_host")}
|
${this.supervisor.localize("system.host.shutdown_host")}
|
||||||
@ -435,10 +435,6 @@ class HassioHostInfo extends LitElement {
|
|||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
|
||||||
--mdc-theme-primary: var(--error-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-button-menu {
|
ha-button-menu {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
--mdc-menu-min-width: 200px;
|
--mdc-menu-min-width: 200px;
|
||||||
|
@ -2,16 +2,11 @@ import { mdiAlertOctagram, mdiCheckBold } from "@mdi/js";
|
|||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
import "../ha-button";
|
import "../ha-button";
|
||||||
|
import type { Appearance } from "../ha-button";
|
||||||
import "../ha-spinner";
|
import "../ha-spinner";
|
||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
import type { Appearance } from "../ha-button";
|
|
||||||
|
|
||||||
const HIGHLIGHT_APPEARANCE = {
|
|
||||||
accent: "accent" as Appearance,
|
|
||||||
filled: "accent" as Appearance,
|
|
||||||
plain: "filled" as Appearance,
|
|
||||||
};
|
|
||||||
|
|
||||||
@customElement("ha-progress-button")
|
@customElement("ha-progress-button")
|
||||||
export class HaProgressButton extends LitElement {
|
export class HaProgressButton extends LitElement {
|
||||||
@ -23,18 +18,16 @@ export class HaProgressButton extends LitElement {
|
|||||||
|
|
||||||
@property() appearance: Appearance = "accent";
|
@property() appearance: Appearance = "accent";
|
||||||
|
|
||||||
|
@property({ attribute: false }) public iconPath?: string;
|
||||||
|
|
||||||
@property() variant: "brand" | "danger" | "neutral" | "warning" | "success" =
|
@property() variant: "brand" | "danger" | "neutral" | "warning" | "success" =
|
||||||
"brand";
|
"brand";
|
||||||
|
|
||||||
@state() private _result?: "success" | "error";
|
@state() private _result?: "success" | "error";
|
||||||
|
|
||||||
@state() private _hasInitialIcon = false;
|
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
const appearance =
|
const appearance =
|
||||||
this.progress || this._result
|
this.progress || this._result ? "accent" : this.appearance;
|
||||||
? HIGHLIGHT_APPEARANCE[this.appearance]
|
|
||||||
: this.appearance;
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-button
|
<ha-button
|
||||||
@ -46,20 +39,20 @@ export class HaProgressButton extends LitElement {
|
|||||||
: this._result === "error"
|
: this._result === "error"
|
||||||
? "danger"
|
? "danger"
|
||||||
: this.variant}
|
: this.variant}
|
||||||
.hideContent=${this._result !== undefined}
|
class=${classMap({
|
||||||
|
result: !!this._result,
|
||||||
|
success: this._result === "success",
|
||||||
|
error: this._result === "error",
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
${this._hasInitialIcon
|
${this.iconPath
|
||||||
? html`<slot name="icon" slot="start"></slot>`
|
? html`<ha-svg-icon
|
||||||
|
.path=${this.iconPath}
|
||||||
|
slot="start"
|
||||||
|
></ha-svg-icon>`
|
||||||
: nothing}
|
: nothing}
|
||||||
<slot
|
|
||||||
>${this._result
|
<slot>${this.label}</slot>
|
||||||
? html`<ha-svg-icon
|
|
||||||
.path=${this._result === "success"
|
|
||||||
? mdiCheckBold
|
|
||||||
: mdiAlertOctagram}
|
|
||||||
></ha-svg-icon>`
|
|
||||||
: this.label}</slot
|
|
||||||
>
|
|
||||||
</ha-button>
|
</ha-button>
|
||||||
${!this._result
|
${!this._result
|
||||||
? nothing
|
? nothing
|
||||||
@ -75,14 +68,6 @@ export class HaProgressButton extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
const iconSlot = this.shadowRoot!.querySelector(
|
|
||||||
'slot[name="icon"]'
|
|
||||||
) as HTMLSlotElement;
|
|
||||||
this._hasInitialIcon =
|
|
||||||
iconSlot && iconSlot.assignedNodes({ flatten: true }).length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public actionSuccess(): void {
|
public actionSuccess(): void {
|
||||||
this._setResult("success");
|
this._setResult("success");
|
||||||
}
|
}
|
||||||
@ -109,10 +94,6 @@ export class HaProgressButton extends LitElement {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-button {
|
|
||||||
transition: all 1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -123,14 +104,21 @@ export class HaProgressButton extends LitElement {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-svg-icon {
|
ha-button {
|
||||||
color: white;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-button.success slot,
|
ha-button.result::part(start),
|
||||||
ha-button.error slot {
|
ha-button.result::part(end),
|
||||||
|
ha-button.result::part(label),
|
||||||
|
ha-button.result::part(caret),
|
||||||
|
ha-button.result::part(spinner) {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha-svg-icon {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Button from "@awesome.me/webawesome/dist/components/button/button";
|
import Button from "@awesome.me/webawesome/dist/components/button/button";
|
||||||
import { css, type CSSResultGroup } from "lit";
|
import { css, type CSSResultGroup } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
|
|
||||||
export type Appearance = "accent" | "filled" | "outlined" | "plain";
|
export type Appearance = "accent" | "filled" | "outlined" | "plain";
|
||||||
|
|
||||||
@ -36,9 +36,6 @@ export type Appearance = "accent" | "filled" | "outlined" | "plain";
|
|||||||
export class HaButton extends Button {
|
export class HaButton extends Button {
|
||||||
variant: "brand" | "neutral" | "success" | "warning" | "danger" = "brand";
|
variant: "brand" | "neutral" | "success" | "warning" | "danger" = "brand";
|
||||||
|
|
||||||
@property({ type: Boolean, attribute: "hide-content", reflect: true })
|
|
||||||
hideContent = false;
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
Button.styles,
|
Button.styles,
|
||||||
@ -150,6 +147,10 @@ export class HaButton extends Button {
|
|||||||
background-color: var(--color-fill-disabled-loud-resting);
|
background-color: var(--color-fill-disabled-loud-resting);
|
||||||
color: var(--color-on-disabled-loud);
|
color: var(--color-on-disabled-loud);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host([loading]) {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { css, html, LitElement, nothing } from "lit";
|
|||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { storage } from "../../common/decorators/storage";
|
import { storage } from "../../common/decorators/storage";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import "../../components/buttons/ha-progress-button";
|
||||||
import { createCloseHeading } from "../../components/ha-dialog";
|
import { createCloseHeading } from "../../components/ha-dialog";
|
||||||
import "../../components/ha-textarea";
|
import "../../components/ha-textarea";
|
||||||
import type { HaTextArea } from "../../components/ha-textarea";
|
import type { HaTextArea } from "../../components/ha-textarea";
|
||||||
@ -10,7 +11,6 @@ import { convertTextToSpeech } from "../../data/tts";
|
|||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { showAlertDialog } from "../generic/show-dialog-box";
|
import { showAlertDialog } from "../generic/show-dialog-box";
|
||||||
import type { TTSTryDialogParams } from "./show-dialog-tts-try";
|
import type { TTSTryDialogParams } from "./show-dialog-tts-try";
|
||||||
import "../../components/buttons/ha-progress-button";
|
|
||||||
|
|
||||||
@customElement("dialog-tts-try")
|
@customElement("dialog-tts-try")
|
||||||
export class TTSTryDialog extends LitElement {
|
export class TTSTryDialog extends LitElement {
|
||||||
@ -85,11 +85,11 @@ export class TTSTryDialog extends LitElement {
|
|||||||
.progress=${this._loadingExample}
|
.progress=${this._loadingExample}
|
||||||
?dialogInitialFocus=${Boolean(this._defaultMessage)}
|
?dialogInitialFocus=${Boolean(this._defaultMessage)}
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
.label=${this.hass.localize("ui.dialogs.tts-try.play")}
|
|
||||||
@click=${this._playExample}
|
@click=${this._playExample}
|
||||||
.disabled=${!this._valid}
|
.disabled=${!this._valid}
|
||||||
|
.iconPath=${mdiPlayCircleOutline}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="icon" .path=${mdiPlayCircleOutline}></ha-svg-icon>
|
${this.hass.localize("ui.dialogs.tts-try.play")}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
|
@ -114,7 +114,6 @@ export class CloudLogin extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
unelevated
|
|
||||||
@click=${this._handleLogin}
|
@click=${this._handleLogin}
|
||||||
.progress=${this._inProgress}
|
.progress=${this._inProgress}
|
||||||
>${this.localize(
|
>${this.localize(
|
||||||
|
@ -8,7 +8,6 @@ import memoizeOne from "memoize-one";
|
|||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { round } from "../../../common/number/round";
|
import { round } from "../../../common/number/round";
|
||||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
import "../../../components/buttons/ha-progress-button";
|
|
||||||
import "../../../components/chart/ha-chart-base";
|
import "../../../components/chart/ha-chart-base";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user