mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-13 13:00:24 +00:00
Compare commits
1 Commits
copilot/fi
...
button-hea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
885a590443 |
@@ -1,4 +1,5 @@
|
|||||||
import "../heading-badges/hui-entity-heading-badge";
|
import "../heading-badges/hui-entity-heading-badge";
|
||||||
|
import "../heading-badges/hui-button-heading-badge";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createLovelaceElement,
|
createLovelaceElement,
|
||||||
@@ -6,7 +7,7 @@ import {
|
|||||||
} from "./create-element-base";
|
} from "./create-element-base";
|
||||||
import type { LovelaceHeadingBadgeConfig } from "../heading-badges/types";
|
import type { LovelaceHeadingBadgeConfig } from "../heading-badges/types";
|
||||||
|
|
||||||
const ALWAYS_LOADED_TYPES = new Set(["error", "entity"]);
|
const ALWAYS_LOADED_TYPES = new Set(["error", "entity", "button"]);
|
||||||
|
|
||||||
export const createHeadingBadgeElement = (config: LovelaceHeadingBadgeConfig) =>
|
export const createHeadingBadgeElement = (config: LovelaceHeadingBadgeConfig) =>
|
||||||
createLovelaceElement(
|
createLovelaceElement(
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
import { mdiEye, mdiGestureTap, mdiTextShort } from "@mdi/js";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { any, array, assert, object, optional, string } from "superstruct";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-expansion-panel";
|
||||||
|
import "../../../../components/ha-form/ha-form";
|
||||||
|
import type {
|
||||||
|
HaFormSchema,
|
||||||
|
SchemaUnion,
|
||||||
|
} from "../../../../components/ha-form/types";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import type { Condition } from "../../common/validate-condition";
|
||||||
|
import type { UiAction } from "../../components/hui-action-editor";
|
||||||
|
import type { ButtonHeadingBadgeConfig } from "../../heading-badges/types";
|
||||||
|
import type { LovelaceGenericElementEditor } from "../../types";
|
||||||
|
import "../conditions/ha-card-conditions-editor";
|
||||||
|
import { configElementStyle } from "../config-elements/config-elements-style";
|
||||||
|
import { actionConfigStruct } from "../structs/action-struct";
|
||||||
|
|
||||||
|
export const DEFAULT_CONFIG: Partial<ButtonHeadingBadgeConfig> = {
|
||||||
|
type: "button",
|
||||||
|
};
|
||||||
|
|
||||||
|
const entityConfigStruct = object({
|
||||||
|
type: optional(string()),
|
||||||
|
text: optional(string()),
|
||||||
|
icon: optional(string()),
|
||||||
|
tap_action: optional(actionConfigStruct),
|
||||||
|
hold_action: optional(actionConfigStruct),
|
||||||
|
double_tap_action: optional(actionConfigStruct),
|
||||||
|
visibility: optional(array(any())),
|
||||||
|
});
|
||||||
|
|
||||||
|
const ALLOWED_ACTIONS: UiAction[] = [
|
||||||
|
"navigate",
|
||||||
|
"url",
|
||||||
|
"assist",
|
||||||
|
"call-service",
|
||||||
|
"none",
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("hui-heading-button-editor")
|
||||||
|
export class HuiHeadingButtonEditor
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceGenericElementEditor
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public preview = false;
|
||||||
|
|
||||||
|
@state() private _config?: ButtonHeadingBadgeConfig;
|
||||||
|
|
||||||
|
public setConfig(config: ButtonHeadingBadgeConfig): void {
|
||||||
|
assert(config, entityConfigStruct);
|
||||||
|
this._config = {
|
||||||
|
...DEFAULT_CONFIG,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _schema = memoizeOne(
|
||||||
|
() =>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "content",
|
||||||
|
type: "expandable",
|
||||||
|
flatten: true,
|
||||||
|
iconPath: mdiTextShort,
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
type: "grid",
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
selector: {
|
||||||
|
text: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "icon",
|
||||||
|
selector: { icon: {} },
|
||||||
|
context: { icon_entity: "entity" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "interactions",
|
||||||
|
type: "expandable",
|
||||||
|
flatten: true,
|
||||||
|
iconPath: mdiGestureTap,
|
||||||
|
schema: [
|
||||||
|
{
|
||||||
|
name: "tap_action",
|
||||||
|
selector: {
|
||||||
|
ui_action: {
|
||||||
|
default_action: "none",
|
||||||
|
actions: ALLOWED_ACTIONS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
type: "optional_actions",
|
||||||
|
flatten: true,
|
||||||
|
schema: (["hold_action", "double_tap_action"] as const).map(
|
||||||
|
(action) => ({
|
||||||
|
name: action,
|
||||||
|
selector: {
|
||||||
|
ui_action: {
|
||||||
|
default_action: "none" as const,
|
||||||
|
actions: ALLOWED_ACTIONS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as const satisfies readonly HaFormSchema[]
|
||||||
|
);
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = this._schema();
|
||||||
|
|
||||||
|
const conditions = this._config.visibility ?? [];
|
||||||
|
return html`
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${this._config}
|
||||||
|
.schema=${schema}
|
||||||
|
.computeLabel=${this._computeLabelCallback}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></ha-form>
|
||||||
|
<ha-expansion-panel outlined>
|
||||||
|
<ha-svg-icon slot="leading-icon" .path=${mdiEye}></ha-svg-icon>
|
||||||
|
<h3 slot="header">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.heading.entity_config.visibility"
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
<div class="content">
|
||||||
|
<p class="intro">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.heading.entity_config.visibility_explanation"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<ha-card-conditions-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.conditions=${conditions}
|
||||||
|
@value-changed=${this._conditionChanged}
|
||||||
|
>
|
||||||
|
</ha-card-conditions-editor>
|
||||||
|
</div>
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = { ...ev.detail.value } as FormData;
|
||||||
|
|
||||||
|
fireEvent(this, "config-changed", { config });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _conditionChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const conditions = ev.detail.value as Condition[];
|
||||||
|
|
||||||
|
const newConfig: ButtonHeadingBadgeConfig = {
|
||||||
|
...this._config,
|
||||||
|
visibility: conditions,
|
||||||
|
};
|
||||||
|
if (newConfig.visibility?.length === 0) {
|
||||||
|
delete newConfig.visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "config-changed", { config: newConfig });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeLabelCallback = (
|
||||||
|
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||||
|
) => {
|
||||||
|
switch (schema.name) {
|
||||||
|
case "text":
|
||||||
|
return this.hass!.localize(
|
||||||
|
`ui.panel.lovelace.editor.card.heading.button_config.${schema.name}`
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return this.hass!.localize(
|
||||||
|
`ui.panel.lovelace.editor.card.generic.${schema.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [
|
||||||
|
configElementStyle,
|
||||||
|
css`
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
ha-form {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.intro {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-heading-button-editor": HuiHeadingButtonEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../components/ha-state-icon";
|
||||||
|
import type { ActionHandlerEvent } from "../../../data/lovelace/action_handler";
|
||||||
|
import "../../../state-display/state-display";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||||
|
import { handleAction } from "../common/handle-action";
|
||||||
|
import { hasAction } from "../common/has-action";
|
||||||
|
import { DEFAULT_CONFIG } from "../editor/heading-badge-editor/hui-entity-heading-badge-editor";
|
||||||
|
import type {
|
||||||
|
LovelaceHeadingBadge,
|
||||||
|
LovelaceHeadingBadgeEditor,
|
||||||
|
} from "../types";
|
||||||
|
import type { ButtonHeadingBadgeConfig } from "./types";
|
||||||
|
|
||||||
|
const DEFAULT_ACTIONS: Pick<
|
||||||
|
ButtonHeadingBadgeConfig,
|
||||||
|
"tap_action" | "hold_action" | "double_tap_action"
|
||||||
|
> = {
|
||||||
|
tap_action: { action: "none" },
|
||||||
|
hold_action: { action: "none" },
|
||||||
|
double_tap_action: { action: "none" },
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("hui-button-heading-badge")
|
||||||
|
export class HuiButtonHeadingBadge
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceHeadingBadge
|
||||||
|
{
|
||||||
|
public static async getConfigElement(): Promise<LovelaceHeadingBadgeEditor> {
|
||||||
|
await import(
|
||||||
|
"../editor/heading-badge-editor/hui-button-heading-badge-editor"
|
||||||
|
);
|
||||||
|
return document.createElement("hui-heading-button-editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _config?: ButtonHeadingBadgeConfig;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public preview = false;
|
||||||
|
|
||||||
|
public setConfig(config): void {
|
||||||
|
this._config = {
|
||||||
|
...DEFAULT_CONFIG,
|
||||||
|
...DEFAULT_ACTIONS,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasAction() {
|
||||||
|
return (
|
||||||
|
hasAction(this._config?.tap_action) ||
|
||||||
|
hasAction(this._config?.hold_action) ||
|
||||||
|
hasAction(this._config?.double_tap_action)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleAction(ev: ActionHandlerEvent) {
|
||||||
|
handleAction(this, this.hass!, this._config!, ev.detail.action!);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = this._config;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-button
|
||||||
|
@action=${this._handleAction}
|
||||||
|
.actionHandler=${actionHandler({
|
||||||
|
hasHold: hasAction(this._config!.hold_action),
|
||||||
|
hasDoubleClick: hasAction(this._config!.double_tap_action),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ha-icon .icon=${config.icon}></ha-icon>
|
||||||
|
${this._config.text}
|
||||||
|
</ha-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
[role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-button-heading-badge": HuiButtonHeadingBadge;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,3 +26,12 @@ export interface EntityHeadingBadgeConfig extends LovelaceHeadingBadgeConfig {
|
|||||||
hold_action?: ActionConfig;
|
hold_action?: ActionConfig;
|
||||||
double_tap_action?: ActionConfig;
|
double_tap_action?: ActionConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ButtonHeadingBadgeConfig extends LovelaceHeadingBadgeConfig {
|
||||||
|
type?: "button";
|
||||||
|
icon: string;
|
||||||
|
text?: string;
|
||||||
|
tap_action: ActionConfig;
|
||||||
|
hold_action?: ActionConfig;
|
||||||
|
double_tap_action?: ActionConfig;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7766,6 +7766,9 @@
|
|||||||
"state": "[%key:ui::panel::lovelace::editor::badge::entity::displayed_elements_options::state%]"
|
"state": "[%key:ui::panel::lovelace::editor::badge::entity::displayed_elements_options::state%]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"button_config": {
|
||||||
|
"text": "Text"
|
||||||
|
},
|
||||||
"default_heading": "Kitchen"
|
"default_heading": "Kitchen"
|
||||||
},
|
},
|
||||||
"map": {
|
"map": {
|
||||||
|
|||||||
Reference in New Issue
Block a user