Compare commits

..

9 Commits

Author SHA1 Message Date
Wendelin
25d9d88776 Revive automation row overflow menu 2025-09-18 16:32:59 +02:00
renovate[bot]
6a23dbf204 Update vaadinWebComponents monorepo to v24.9.0 (#27086)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-18 14:35:17 +03:00
Paul Bottein
cef8fc1d38 Move the logic to show common controls inside the strategy itself (#27088) 2025-09-18 14:34:46 +03:00
Norbert Rittel
7c06e33b50 Clarify sidebar setting for add-ons (#27085) 2025-09-18 09:55:39 +02:00
renovate[bot]
cb365d4635 Update dependency marked to v16.3.0 (#27080)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 20:03:35 +02:00
Paulus Schoutsen
525102678b Limit to 4 common entities on landing page. (#27082) 2025-09-17 20:03:10 +02:00
Paulus Schoutsen
dfc4b0bba2 Show generated media in action dev tools (#26927)
* Show generated image in action dev tools

* Resolve media_source_id

* Render other media content too

* Update src/panels/developer-tools/action/developer-tools-action.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Fix

* Remove translation placeholder

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-09-17 19:07:32 +02:00
Jan-Philipp Benecke
846692bc8a Migrate ha-slider to webawesome (#27075)
* Migrate ha-slider to webawesome

* Fix labeled slider

* Change slider surface color

* Trigger Build

* Remove large and border

* Run prettier

* enable tooltip and focus ring
2025-09-17 19:06:13 +02:00
Douwe
3b90b5fcb1 Add feature gap theme variable for hui-card-features (#27076)
* Update hui-card-features.ts

Add CSS variable for gap

* Renamed variable
2025-09-17 14:03:49 +02:00
31 changed files with 1296 additions and 1030 deletions

View File

@@ -0,0 +1,36 @@
---
title: Slider
subtitle: A slider component for selecting a value from a range.
---
<style>
.wrapper {
display: flex;
gap: 24px;
}
</style>
# Slider `<ha-slider>`
## Implementation
### Example Usage
<div class="wrapper">
<ha-slider size="small" with-markers min="0" max="8" value="4"></ha-slider>
<ha-slider size="medium"></ha-slider>
</div>
```html
<ha-slider size="small" with-markers min="0" max="8" value="4"></ha-slider>
<ha-slider size="medium"></ha-slider>
```
### API
This component is based on the webawesome slider component.
Check the [webawesome documentation](https://webawesome.com/docs/components/slider/) for more details.
**CSS Custom Properties**
- `--ha-slider-track-size` - Height of the slider track. Defaults to `4px`.

View File

@@ -0,0 +1,100 @@
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { applyThemesOnElement } from "../../../../src/common/dom/apply_themes_on_element";
import "../../../../src/components/ha-bar";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-slider";
import type { HomeAssistant } from "../../../../src/types";
@customElement("demo-components-ha-slider")
export class DemoHaSlider extends LitElement {
@property({ attribute: false }) hass!: HomeAssistant;
protected render(): TemplateResult {
return html`
${["light", "dark"].map(
(mode) => html`
<div class=${mode}>
<ha-card header="ha-slider ${mode} demo">
<div class="card-content">
<span>Default (disabled)</span>
<ha-slider
disabled
min="0"
max="8"
value="4"
with-markers
></ha-slider>
<span>Small</span>
<ha-slider
size="small"
min="0"
max="8"
value="4"
with-markers
></ha-slider>
<span>Medium</span>
<ha-slider
size="medium"
min="0"
max="8"
value="4"
with-markers
></ha-slider>
</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
);
}
static styles = css`
:host {
display: flex;
justify-content: center;
}
.dark,
.light {
display: block;
background-color: var(--primary-background-color);
padding: 0 50px;
margin: 16px;
border-radius: 8px;
}
ha-card {
margin: 24px auto;
}
.card-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"demo-components-ha-slider": DemoHaSlider;
}
}

View File

@@ -89,8 +89,8 @@
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.9.1",
"@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.8.7",
"@vaadin/vaadin-themable-mixin": "24.8.7",
"@vaadin/combo-box": "24.9.0",
"@vaadin/vaadin-themable-mixin": "24.9.0",
"@vibrant/color": "4.0.0",
"@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
@@ -122,7 +122,7 @@
"lit": "3.3.1",
"lit-html": "3.3.1",
"luxon": "3.7.2",
"marked": "16.2.1",
"marked": "16.3.0",
"memoize-one": "6.0.0",
"node-vibrant": "4.0.3",
"object-hash": "3.0.0",

View File

@@ -1,13 +1,13 @@
import type { HassConfig, HassEntity } from "home-assistant-js-websocket";
import type { FrontendLocaleData } from "../../data/translation";
import type { HomeAssistant } from "../../types";
import { ensureArray } from "../array/ensure-array";
import { computeAreaName } from "../entity/compute_area_name";
import { computeDeviceName } from "../entity/compute_device_name";
import { computeEntityName } from "../entity/compute_entity_name";
import { computeFloorName } from "../entity/compute_floor_name";
import { getEntityContext } from "../entity/context/get_entity_context";
import type { LocalizeFunc } from "./localize";
import { computeEntityName } from "../entity/compute_entity_name";
import { computeDeviceName } from "../entity/compute_device_name";
import { getEntityContext } from "../entity/context/get_entity_context";
import { computeAreaName } from "../entity/compute_area_name";
import { computeFloorName } from "../entity/compute_floor_name";
import { ensureArray } from "../array/ensure-array";
export type FormatEntityStateFunc = (
stateObj: HassEntity,
@@ -77,6 +77,7 @@ export const computeFormatFunctions = async (
computeAttributeNameDisplay(localize, stateObj, entities, attribute),
formatEntityName: (stateObj, type, separator = " ") => {
const types = ensureArray(type);
const namesList: (string | undefined)[] = [];
const { device, area, floor } = getEntityContext(
stateObj,
@@ -86,24 +87,33 @@ export const computeFormatFunctions = async (
floors
);
const names = types
.map((t) => {
switch (t) {
case "entity":
return computeEntityName(stateObj, entities, devices);
case "device":
return device ? computeDeviceName(device) : undefined;
case "area":
return area ? computeAreaName(area) : undefined;
case "floor":
return floor ? computeFloorName(floor) : undefined;
default:
return t;
for (const t of types) {
switch (t) {
case "entity": {
namesList.push(computeEntityName(stateObj, entities, devices));
break;
}
})
.filter((name) => name !== undefined);
return names.join(separator);
case "device": {
if (device) {
namesList.push(computeDeviceName(device));
}
break;
}
case "area": {
if (area) {
namesList.push(computeAreaName(area));
}
break;
}
case "floor": {
if (floor) {
namesList.push(computeFloorName(floor));
}
break;
}
}
}
return namesList.filter((name) => name !== undefined).join(separator);
},
};
};

View File

@@ -1,309 +0,0 @@
import { mdiDrag } from "@mdi/js";
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
import { css, html, LitElement, nothing, type PropertyValues } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { ensureArray } from "../../common/array/ensure-array";
import { fireEvent } from "../../common/dom/fire_event";
import { getEntityContext } from "../../common/entity/context/get_entity_context";
import type { EntityNameType } from "../../common/translations/entity-state";
import { computeEntityDisplayName } from "../../panels/lovelace/common/entity/compute-display-name";
import type { HomeAssistant, ValueChangedEvent } from "../../types";
import "../chips/ha-chip-set";
import "../chips/ha-filter-chip";
import "../chips/ha-input-chip";
import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";
import "../ha-list-item";
import "../ha-select";
import "../ha-sortable";
import "../ha-textfield";
const NAMES: EntityNameType[] = ["entity", "device", "area", "floor"];
interface EntityNameItem {
primary: string;
secondary?: string;
value: string;
}
const rowRenderer: ComboBoxLitRenderer<EntityNameItem> = (item) => html`
<ha-combo-box-item type="button">
<span slot="headline">${item.primary}</span>
${item.secondary
? html`<span slot="supporting-text">${item.secondary}</span>`
: nothing}
</ha-combo-box-item>
`;
@customElement("ha-entity-name-picker")
export class HaEntityNamePicker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public entityId?: string;
@property() public value?: string[] | string;
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public required = false;
@property({ type: Boolean, reflect: true }) public disabled = false;
@state() private _opened = false;
@query("ha-combo-box", true) private _comboBox!: HaComboBox;
protected shouldUpdate(changedProps: PropertyValues) {
return !(!changedProps.has("_opened") && this._opened);
}
protected updated(changedProps: PropertyValues) {
if (
(changedProps.has("_opened") && this._opened) ||
changedProps.has("entityId")
) {
const options = this._getItems(this.entityId);
const optionItems = options.filter(
(option) => !this._value.includes(option.value)
);
(this._comboBox as any).filteredItems = optionItems;
}
}
private _validOptions = memoizeOne((entityId: string) => {
const stateObj = this.hass.states[entityId];
if (!stateObj) {
return [];
}
const context = getEntityContext(
stateObj,
this.hass.entities,
this.hass.devices,
this.hass.areas,
this.hass.floors
);
const options: EntityNameType[] = ["entity"];
if (context.device) options.push("device");
if (context.area) options.push("area");
if (context.floor) options.push("floor");
return options;
});
private _getItems = memoizeOne((entityId?: string) => {
if (!entityId) {
return [];
}
const items = this._validOptions(entityId).map<EntityNameItem>((name) => ({
primary: this.hass.localize(
`ui.components.entity.entity-name-picker.types.${name}`
),
secondary: computeEntityDisplayName(
this.hass,
this.hass.states[entityId],
name
),
value: name,
}));
return items;
});
protected render() {
if (!this.hass) {
return nothing;
}
const value = this._value;
const options = this._getItems(this.entityId);
const optionItems = options.filter(
(option) => !this._value.includes(option.value)
);
return html`
${value?.length
? html`
<ha-sortable
no-style
@item-moved=${this._moveItem}
.disabled=${this.disabled}
handle-selector="button.primary.action"
>
<ha-chip-set>
${repeat(
this._value,
(item) => item,
(item, idx) => {
const label = NAMES.includes(item)
? this.hass.localize(
`ui.components.entity.entity-name-picker.types.${item as EntityNameType}`
)
: item;
return html`
<ha-input-chip
data-idx=${idx}
@remove=${this._removeItem}
.label=${label}
selected
>
<ha-svg-icon slot="icon" .path=${mdiDrag}></ha-svg-icon>
<span>${label}</span>
</ha-input-chip>
`;
}
)}
</ha-chip-set>
</ha-sortable>
`
: nothing}
<ha-combo-box
hide-clear-icon
.hass=${this.hass}
.value=${""}
.autofocus=${this.autofocus}
.label=${this.label}
.disabled=${this.disabled || !this.entityId}
.required=${this.required && !value.length}
.helper=${this.helper}
.allowCustomValue=${true}
item-id-path="value"
item-value-path="value"
item-label-path="primary"
.renderer=${rowRenderer}
.items=${optionItems}
@opened-changed=${this._openedChanged}
@value-changed=${this._comboBoxValueChanged}
@filter-changed=${this._filterChanged}
>
</ha-combo-box>
`;
}
private get _value() {
return !this.value ? [] : ensureArray(this.value);
}
private _openedChanged(ev: ValueChangedEvent<boolean>) {
this._opened = ev.detail.value;
if (this._opened) {
const options = this._getItems(this.entityId);
const optionItems = options.filter(
(option) => !this._value.includes(option.value)
);
this._comboBox.filteredItems = optionItems;
}
}
private _filterChanged(ev: ValueChangedEvent<string>) {
const filter = ev.detail.value?.toLowerCase() || "";
const options = this._getItems(this.entityId);
const optionItems = options.filter(
(option) => !this._value.includes(option.value)
);
const filteredItems = optionItems.filter((item) => {
const label = item.primary || item.value;
return label.toLowerCase().includes(filter);
});
if (filter) {
filteredItems.unshift({
primary: filter,
value: filter,
secondary: undefined,
});
}
this._comboBox.filteredItems = filteredItems;
}
private async _moveItem(ev: CustomEvent) {
ev.stopPropagation();
const { oldIndex, newIndex } = ev.detail;
const value = this._value;
const newValue = value.concat();
const element = newValue.splice(oldIndex, 1)[0];
newValue.splice(newIndex, 0, element);
this._setValue(newValue);
await this.updateComplete;
this._filterChanged({ detail: { value: "" } } as ValueChangedEvent<string>);
}
private async _removeItem(ev) {
ev.stopPropagation();
const value: string[] = [...this._value];
const idx = parseInt(ev.target.dataset.idx, 10);
value.splice(idx, 1);
this._setValue(value);
await this.updateComplete;
this._filterChanged({ detail: { value: "" } } as ValueChangedEvent<string>);
}
private _comboBoxValueChanged(ev: ValueChangedEvent<string>): void {
ev.stopPropagation();
const newValue = ev.detail.value;
if (this.disabled || newValue === "") {
return;
}
const currentValue = this._value;
if (currentValue.includes(newValue)) {
return;
}
setTimeout(() => {
this._filterChanged({
detail: { value: "" },
} as ValueChangedEvent<string>);
this._comboBox.setInputValue("");
}, 0);
this._setValue([...currentValue, newValue]);
}
private _setValue(value: string[]) {
const newValue =
value.length === 0 ? undefined : value.length === 1 ? value[0] : value;
this.value = newValue;
fireEvent(this, "value-changed", {
value: newValue,
});
}
static styles = css`
:host {
position: relative;
}
ha-chip-set {
padding: 8px 0;
}
.sortable-fallback {
display: none;
opacity: 0;
}
.sortable-ghost {
opacity: 0.4;
}
.sortable-drag {
cursor: grabbing;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-entity-name-picker": HaEntityNamePicker;
}
}

View File

@@ -36,15 +36,17 @@ class HaLabeledSlider extends LitElement {
<div class="extra-container"><slot name="extra"></slot></div>
<div class="slider-container">
${this.icon ? html`<ha-icon icon=${this.icon}></ha-icon>` : nothing}
<ha-slider
.min=${this.min}
.max=${this.max}
.step=${this.step}
.labeled=${this.labeled}
.disabled=${this.disabled}
.value=${this.value}
@change=${this._inputChanged}
></ha-slider>
<div class="slider-wrapper">
<ha-slider
.min=${this.min}
.max=${this.max}
.step=${this.step}
.labeled=${this.labeled}
.disabled=${this.disabled}
.value=${this.value}
@change=${this._inputChanged}
></ha-slider>
</div>
</div>
${this.helper
? html`<ha-input-helper-text .disabled=${this.disabled}>
@@ -83,7 +85,8 @@ class HaLabeledSlider extends LitElement {
color: var(--secondary-text-color);
}
ha-slider {
.slider-wrapper {
padding: 0 8px;
display: flex;
flex-grow: 1;
align-items: center;
@@ -91,6 +94,10 @@ class HaLabeledSlider extends LitElement {
border-radius: 4px;
height: 32px;
}
ha-slider {
width: 100%;
}
`;
}

View File

@@ -1,48 +0,0 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import type { EntityNameSelector } from "../../data/selector";
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import type { HomeAssistant } from "../../types";
import "../entity/ha-entity-name-picker";
@customElement("ha-selector-entity_name")
export class HaSelectorEntityName extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public selector!: EntityNameSelector;
@property() public value?: string | string[];
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@property({ attribute: false }) public context?: {
entity?: string;
};
protected render() {
return html`
<ha-entity-name-picker
.hass=${this.hass}
.entityId=${this.selector.entity_name?.entity_id ||
this.context?.entity}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
></ha-entity-name-picker>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-entity_name": HaSelectorEntityName;
}
}

View File

@@ -29,7 +29,6 @@ const LOAD_ELEMENTS = {
device: () => import("./ha-selector-device"),
duration: () => import("./ha-selector-duration"),
entity: () => import("./ha-selector-entity"),
entity_name: () => import("./ha-selector-entity-name"),
statistic: () => import("./ha-selector-statistic"),
file: () => import("./ha-selector-file"),
floor: () => import("./ha-selector-floor"),

View File

@@ -1,33 +1,81 @@
import { Slider } from "@material/web/slider/internal/slider";
import { styles } from "@material/web/slider/internal/slider-styles";
import { css } from "lit";
import { customElement } from "lit/decorators";
import Slider from "@home-assistant/webawesome/dist/components/slider/slider";
import { css, type CSSResultGroup } from "lit";
import { customElement, property } from "lit/decorators";
import { mainWindow } from "../common/dom/get_main_window";
@customElement("ha-slider")
export class HaSlider extends Slider {
@property({ reflect: true }) size: "small" | "medium" = "small";
@property({ type: Boolean, attribute: "with-tooltip" }) withTooltip = true;
public connectedCallback() {
super.connectedCallback();
this.dir = mainWindow.document.dir;
}
static override styles = [
styles,
css`
:host {
--md-sys-color-primary: var(--primary-color);
--md-sys-color-on-primary: var(--text-primary-color);
--md-sys-color-outline: var(--outline-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-slider-handle-width: 14px;
--md-slider-handle-height: 14px;
--md-slider-state-layer-size: 24px;
min-width: 100px;
min-inline-size: 100px;
width: 200px;
}
`,
];
static get styles(): CSSResultGroup {
return [
Slider.styles,
css`
:host {
--wa-form-control-activated-color: var(--primary-color);
--track-size: var(--ha-slider-track-size, 4px);
--marker-height: calc(var(--ha-slider-track-size, 4px) / 2);
--marker-width: calc(var(--ha-slider-track-size, 4px) / 2);
--wa-color-surface-default: var(--card-background-color);
--wa-color-neutral-fill-normal: var(--disabled-color);
--wa-tooltip-background-color: var(--secondary-background-color);
--wa-tooltip-color: var(--primary-text-color);
--wa-tooltip-font-family: var(
--ha-tooltip-font-family,
var(--ha-font-family-body)
);
--wa-tooltip-font-size: var(
--ha-tooltip-font-size,
var(--ha-font-size-s)
);
--wa-tooltip-font-weight: var(
--ha-tooltip-font-weight,
var(--ha-font-weight-normal)
);
--wa-tooltip-line-height: var(
--ha-tooltip-line-height,
var(--ha-line-height-condensed)
);
--wa-tooltip-padding: 8px;
--wa-tooltip-border-radius: var(--ha-tooltip-border-radius, 4px);
--wa-tooltip-arrow-size: var(--ha-tooltip-arrow-size, 8px);
--wa-z-index-tooltip: var(--ha-tooltip-z-index, 1000);
min-width: 100px;
min-inline-size: 100px;
width: 200px;
}
#thumb {
border: none;
}
#slider {
&:focus-visible:not(.disabled) #thumb,
&:focus-visible:not(.disabled) #thumb-min,
&:focus-visible:not(.disabled) #thumb-max {
outline: var(--wa-focus-ring);
}
}
:host([size="medium"]) {
--thumb-width: var(--ha-font-size-l, 1.25em);
--thumb-height: var(--ha-font-size-l, 1.25em);
}
:host([size="small"]) {
--thumb-width: var(--ha-font-size-m, 1em);
--thumb-height: var(--ha-font-size-m, 1em);
}
`,
];
}
}
declare global {

View File

@@ -41,7 +41,6 @@ export type Selector =
| LegacyDeviceSelector
| DurationSelector
| EntitySelector
| EntityNameSelector
| LegacyEntitySelector
| FileSelector
| IconSelector
@@ -500,12 +499,6 @@ export interface UiStateContentSelector {
} | null;
}
export interface EntityNameSelector {
entity_name: {
entity_id?: string;
} | null;
}
export const expandLabelTarget = (
hass: HomeAssistant,
labelId: string,

View File

@@ -1,6 +1,7 @@
import { consume } from "@lit/context";
import {
mdiAlertCircleCheck,
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiContentCopy,
@@ -15,7 +16,7 @@ import {
mdiStopCircleOutline,
} from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { PropertyValues } from "lit";
import type { PropertyValues, TemplateResult } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -70,9 +71,10 @@ import {
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showToast } from "../../../../util/toast";
import "../ha-automation-editor-warning";
import { rowStyles } from "../styles";
import { overflowStyles, rowStyles } from "../styles";
import "./ha-automation-action-editor";
import type HaAutomationActionEditor from "./ha-automation-action-editor";
import "./types/ha-automation-action-choose";
@@ -222,6 +224,20 @@ export default class HaAutomationActionRow extends LitElement {
}
}
private _renderOverflowLabel(label: string, shortcut?: TemplateResult) {
return html`
<div class="overflow-label">
${label}
${this.optionsInSidebar && !this.narrow
? shortcut ||
html`<span
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>`
: nothing}
</div>
`;
}
private _renderRow() {
const type = getAutomationActionType(this.action);
@@ -269,136 +285,200 @@ export default class HaAutomationActionRow extends LitElement {
)}
</ha-tooltip>`
: nothing}
${!this.optionsInSidebar
? html`<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item .clickAction=${this._runAction}>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.run"
)}
<ha-svg-icon slot="start" .path=${mdiPlay}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameAction}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.rename"
)}
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._duplicateAction}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)}
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._copyAction}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
)}
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item .clickAction=${this._runAction}>
<ha-svg-icon slot="start" .path=${mdiPlay}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize("ui.panel.config.automation.editor.actions.run")
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._duplicateAction}
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
<ha-md-menu-item
.clickAction=${this._cutAction}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
)}
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
</ha-md-menu-item>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize("ui.panel.config.automation.editor.move_up")}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._copyAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>C</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._cutAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>X</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!this._uiModeAvailable || !!this._warnings}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
`
: nothing}
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!this._uiModeAvailable || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
.path=${this.action.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.actions.${this.action.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
${this.action.enabled === false
? this.hass.localize(
"ui.panel.config.automation.editor.actions.enable"
)
: this.hass.localize(
"ui.panel.config.automation.editor.actions.disable"
)}
<ha-svg-icon
slot="start"
.path=${this.action.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
</ha-md-menu-item>
</ha-md-button-menu>`
: nothing}
${!this.optionsInSidebar
? html`${this._warnings
? html`<ha-automation-editor-warning
@@ -668,7 +748,7 @@ export default class HaAutomationActionRow extends LitElement {
fireEvent(this, "move-down");
};
private _toggleYamlMode = () => {
private _toggleYamlMode = (item?: HTMLElement) => {
if (this._yamlMode) {
this._switchUiMode();
} else {
@@ -677,6 +757,8 @@ export default class HaAutomationActionRow extends LitElement {
if (!this.optionsInSidebar) {
this.expand();
} else if (item) {
this.openSidebar();
}
};
@@ -791,7 +873,7 @@ export default class HaAutomationActionRow extends LitElement {
this._automationRowElement?.focus();
}
static styles = rowStyles;
static styles = [rowStyles, overflowStyles];
}
declare global {

View File

@@ -1,5 +1,6 @@
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiContentCopy,
@@ -14,7 +15,7 @@ import {
mdiStopCircleOutline,
} from "@mdi/js";
import deepClone from "deep-clone-simple";
import type { CSSResultGroup, PropertyValues } from "lit";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -53,9 +54,10 @@ import {
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showToast } from "../../../../util/toast";
import "../ha-automation-editor-warning";
import { rowStyles } from "../styles";
import { overflowStyles, rowStyles } from "../styles";
import "./ha-automation-condition-editor";
import type HaAutomationConditionEditor from "./ha-automation-condition-editor";
import "./types/ha-automation-condition-and";
@@ -159,6 +161,20 @@ export default class HaAutomationConditionRow extends LitElement {
return this._selected;
}
private _renderOverflowLabel(label: string, shortcut?: TemplateResult) {
return html`
<div class="overflow-label">
${label}
${this.optionsInSidebar && !this.narrow
? shortcut ||
html`<span
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>`
: nothing}
</div>
`;
}
private _renderRow() {
return html`
<ha-svg-icon
@@ -174,140 +190,198 @@ export default class HaAutomationConditionRow extends LitElement {
<slot name="icons" slot="icons"></slot>
${!this.optionsInSidebar
? html`<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
>
</ha-icon-button>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
>
</ha-icon-button>
<ha-md-menu-item .clickAction=${this._testCondition}>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.test"
)}
<ha-svg-icon slot="start" .path=${mdiFlask}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameCondition}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.rename"
)}
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item .clickAction=${this._testCondition}>
<ha-svg-icon slot="start" .path=${mdiFlask}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.conditions.test"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.conditions.rename"
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._duplicateCondition}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)}
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._duplicateCondition}
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._copyCondition}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
)}
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._copyCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon
>${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>C</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._cutCondition}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
)}
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._cutCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon
>${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>X</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || this.first}
>
${this.hass.localize("ui.panel.config.automation.editor.move_up")}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
`
: nothing}
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item .clickAction=${this._toggleYamlMode}>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${this._uiSupported(this.condition.condition) ||
!!this._warnings}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
.path=${this.condition.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
${this.condition.enabled === false
? this.hass.localize(
"ui.panel.config.automation.editor.actions.enable"
)
: this.hass.localize(
"ui.panel.config.automation.editor.actions.disable"
)}
<ha-svg-icon
slot="start"
.path=${this.condition.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
</ha-md-menu-item>
</ha-md-button-menu>`
: nothing}
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.actions.${this.condition.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
${!this.optionsInSidebar
? html`${this._warnings
? html`<ha-automation-editor-warning
@@ -614,7 +688,7 @@ export default class HaAutomationConditionRow extends LitElement {
fireEvent(this, "move-down");
};
private _toggleYamlMode = () => {
private _toggleYamlMode = (item?: HTMLElement) => {
if (this._yamlMode) {
this._switchUiMode();
} else {
@@ -623,6 +697,8 @@ export default class HaAutomationConditionRow extends LitElement {
if (!this.optionsInSidebar) {
this.expand();
} else if (item) {
this.openSidebar();
}
};
@@ -729,6 +805,7 @@ export default class HaAutomationConditionRow extends LitElement {
static get styles(): CSSResultGroup {
return [
rowStyles,
overflowStyles,
css`
.testing {
position: absolute;

View File

@@ -1,5 +1,6 @@
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiDelete,
@@ -7,7 +8,7 @@ import {
mdiPlusCircleMultipleOutline,
mdiRenameBox,
} from "@mdi/js";
import type { CSSResultGroup } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -37,11 +38,17 @@ import {
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../action/ha-automation-action";
import type HaAutomationAction from "../action/ha-automation-action";
import "../condition/ha-automation-condition";
import type HaAutomationCondition from "../condition/ha-automation-condition";
import { editorStyles, indentStyle, rowStyles } from "../styles";
import {
editorStyles,
indentStyle,
overflowStyles,
rowStyles,
} from "../styles";
@customElement("ha-automation-option-row")
export default class HaAutomationOptionRow extends LitElement {
@@ -119,6 +126,20 @@ export default class HaAutomationOptionRow extends LitElement {
return str;
}
private _renderOverflowLabel(label: string, shortcut?: TemplateResult) {
return html`
<div class="overflow-label">
${label}
${this.optionsInSidebar && !this.narrow
? shortcut ||
html`<span
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>`
: nothing}
</div>
`;
}
private _renderRow() {
return html`
<h3 slot="header">
@@ -134,7 +155,7 @@ export default class HaAutomationOptionRow extends LitElement {
<slot name="icons" slot="icons"></slot>
${this.option && !this.optionsInSidebar
${this.option
? html`
<ha-md-button-menu
quick
@@ -156,58 +177,92 @@ export default class HaAutomationOptionRow extends LitElement {
@click=${this._renameOption}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.rename"
)}
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
@click=${this._duplicateOption}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)}
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
@click=${this._moveUp}
.disabled=${this.disabled || this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
@click=${this._moveDown}
.disabled=${this.disabled || this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon>
</ha-md-menu-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon
slot="start"
.path=${mdiArrowUp}
></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon
slot="start"
.path=${mdiArrowDown}
></ha-svg-icon
></ha-md-menu-item>
`
: nothing}
<ha-md-menu-item
@click=${this._removeOption}
class="warning"
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.remove_option"
)}
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.remove_option"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
`
@@ -457,6 +512,7 @@ export default class HaAutomationOptionRow extends LitElement {
return [
rowStyles,
editorStyles,
overflowStyles,
indentStyle,
css`
li[role="separator"] {

View File

@@ -26,7 +26,7 @@ import { isMac } from "../../../../util/is_mac";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import { getAutomationActionType } from "../action/ha-automation-action-row";
import { getRepeatType } from "../action/types/ha-automation-action-repeat";
import { sidebarEditorStyles } from "../styles";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "../trigger/ha-automation-trigger-editor";
import "./ha-automation-sidebar-card";
@@ -315,7 +315,7 @@ export default class HaAutomationSidebarAction extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
static styles = sidebarEditorStyles;
static styles = [sidebarEditorStyles, overflowStyles];
}
declare global {

View File

@@ -27,7 +27,7 @@ import { isMac } from "../../../../util/is_mac";
import { showAlertDialog } from "../../../lovelace/custom-card-helpers";
import "../condition/ha-automation-condition-editor";
import type HaAutomationConditionEditor from "../condition/ha-automation-condition-editor";
import { sidebarEditorStyles } from "../styles";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
@customElement("ha-automation-sidebar-condition")
@@ -395,6 +395,7 @@ export default class HaAutomationSidebarCondition extends LitElement {
static styles = [
sidebarEditorStyles,
overflowStyles,
css`
ha-automation-sidebar-card {
position: relative;

View File

@@ -10,7 +10,7 @@ import type { OptionSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import { sidebarEditorStyles } from "../styles";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
@customElement("ha-automation-sidebar-option")
@@ -127,7 +127,7 @@ export default class HaAutomationSidebarOption extends LitElement {
</ha-automation-sidebar-card>`;
}
static styles = sidebarEditorStyles;
static styles = [sidebarEditorStyles, overflowStyles];
}
declare global {

View File

@@ -8,7 +8,7 @@ import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import "../../script/ha-script-field-editor";
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
import { sidebarEditorStyles } from "../styles";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "./ha-automation-sidebar-card";
@customElement("ha-automation-sidebar-script-field")
@@ -153,7 +153,7 @@ export default class HaAutomationSidebarScriptField extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
static styles = sidebarEditorStyles;
static styles = [sidebarEditorStyles, overflowStyles];
}
declare global {

View File

@@ -19,7 +19,7 @@ import type { TriggerSidebarConfig } from "../../../../data/automation";
import { isTriggerList } from "../../../../data/trigger";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { sidebarEditorStyles } from "../styles";
import { overflowStyles, sidebarEditorStyles } from "../styles";
import "../trigger/ha-automation-trigger-editor";
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
import "./ha-automation-sidebar-card";
@@ -313,7 +313,7 @@ export default class HaAutomationSidebarTrigger extends LitElement {
this._requestShowId = true;
};
static styles = sidebarEditorStyles;
static styles = [sidebarEditorStyles, overflowStyles];
}
declare global {

View File

@@ -230,6 +230,9 @@ export const sidebarEditorStyles = css`
.description {
padding-top: 16px;
}
`;
export const overflowStyles = css`
.overflow-label {
display: flex;
justify-content: space-between;

View File

@@ -1,5 +1,6 @@
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
mdiArrowDown,
mdiArrowUp,
mdiContentCopy,
@@ -14,7 +15,7 @@ import {
mdiStopCircleOutline,
} from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -52,9 +53,10 @@ import {
showPromptDialog,
} from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showToast } from "../../../../util/toast";
import "../ha-automation-editor-warning";
import { rowStyles } from "../styles";
import { overflowStyles, rowStyles } from "../styles";
import "./ha-automation-trigger-editor";
import type HaAutomationTriggerEditor from "./ha-automation-trigger-editor";
import "./types/ha-automation-trigger-calendar";
@@ -160,6 +162,20 @@ export default class HaAutomationTriggerRow extends LitElement {
private _triggerUnsub?: Promise<UnsubscribeFunc>;
private _renderOverflowLabel(label: string, shortcut?: TemplateResult) {
return html`
<div class="overflow-label">
${label}
${this.optionsInSidebar && !this.narrow
? shortcut ||
html`<span
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>`
: nothing}
</div>
`;
}
private _renderRow() {
const type = this._getType(this.trigger);
@@ -179,142 +195,204 @@ export default class HaAutomationTriggerRow extends LitElement {
<slot name="icons" slot="icons"></slot>
${!this.optionsInSidebar
? html`<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._renameTrigger}
.disabled=${this.disabled || type === "list"}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)}
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._renameTrigger}
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._showTriggerId}
.disabled=${this.disabled || type === "list"}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.edit_id"
)}
<ha-svg-icon slot="start" .path=${mdiIdentifier}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._showTriggerId}
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon slot="start" .path=${mdiIdentifier}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.edit_id"
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._duplicateTrigger}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.duplicate"
)}
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._duplicateTrigger}
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
<ha-md-menu-item
.clickAction=${this._copyTrigger}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
)}
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
</ha-md-menu-item>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._cutTrigger}
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
)}
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._copyTrigger}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>C</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || this.first}
>
${this.hass.localize("ui.panel.config.automation.editor.move_up")}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._cutTrigger}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span>X</span>
</span>`
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
`
: nothing}
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!supported || !!this._warnings}
>
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
.disabled=${!supported || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled || type === "list"}
>
${"enabled" in this.trigger && this.trigger.enabled === false
? this.hass.localize(
"ui.panel.config.automation.editor.actions.enable"
)
: this.hass.localize(
"ui.panel.config.automation.editor.actions.disable"
)}
<ha-svg-icon
slot="start"
.path=${"enabled" in this.trigger &&
this.trigger.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
class="warning"
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
</ha-md-menu-item>
</ha-md-button-menu>`
: nothing}
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon
slot="start"
.path=${"enabled" in this.trigger && this.trigger.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.actions.${"enabled" in this.trigger && this.trigger.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
class="warning"
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
),
html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
${!this.optionsInSidebar
? html`${this._warnings
? html`<ha-automation-editor-warning
@@ -668,7 +746,7 @@ export default class HaAutomationTriggerRow extends LitElement {
fireEvent(this, "move-down");
};
private _toggleYamlMode = () => {
private _toggleYamlMode = (item?: HTMLElement) => {
if (this._yamlMode) {
this._switchUiMode();
} else {
@@ -677,6 +755,8 @@ export default class HaAutomationTriggerRow extends LitElement {
if (!this.optionsInSidebar) {
this.expand();
} else if (item) {
this.openSidebar();
}
};
@@ -702,6 +782,7 @@ export default class HaAutomationTriggerRow extends LitElement {
static get styles(): CSSResultGroup {
return [
rowStyles,
overflowStyles,
css`
.triggered {
cursor: pointer;

View File

@@ -1,19 +1,30 @@
import {
mdiAppleKeyboardCommand,
mdiDelete,
mdiDotsVertical,
mdiPlaylistEdit,
} from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../../common/dom/fire_event";
import { preventDefaultStopPropagation } from "../../../common/dom/prevent_default_stop_propagation";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import type { LocalizeKeys } from "../../../common/translations/localize";
import "../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../components/ha-automation-row";
import "../../../components/ha-card";
import "../../../components/ha-md-button-menu";
import "../../../components/ha-md-menu-item";
import type { ScriptFieldSidebarConfig } from "../../../data/automation";
import type { Field } from "../../../data/script";
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { indentStyle } from "../automation/styles";
import { isMac } from "../../../util/is_mac";
import { indentStyle, overflowStyles } from "../automation/styles";
import "./ha-script-field-selector-editor";
import type HaScriptFieldSelectorEditor from "./ha-script-field-selector-editor";
@@ -66,6 +77,64 @@ export default class HaScriptFieldRow extends LitElement {
.highlight=${this.highlight}
@delete-row=${this._onDelete}
>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item .clickAction=${this._toggleYamlMode}>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
.disabled=${this.disabled}
class="warning"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
${!this.narrow
? html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-md-button-menu>
<h3 slot="header">${this.key}</h3>
<slot name="icons" slot="icons"></slot>
@@ -97,6 +166,71 @@ export default class HaScriptFieldRow extends LitElement {
"ui.panel.config.script.editor.field.selector"
)}
</h3>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
selector-row
>
<ha-svg-icon
slot="start"
.path=${mdiPlaylistEdit}
></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<span
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
.disabled=${this.disabled}
class="warning"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
${!this.narrow
? html`<span class="shortcut">
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
"ui.panel.config.automation.editor.ctrl"
)}</span
>
<span>+</span>
<span
>${this.hass.localize(
"ui.panel.config.automation.editor.del"
)}</span
>
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-md-button-menu>
</ha-automation-row>
</ha-card>
${typeof this.field.selector === "object" &&
@@ -243,8 +377,12 @@ export default class HaScriptFieldRow extends LitElement {
}
}
private _toggleYamlMode = () => {
private _toggleYamlMode = (item?: HTMLElement) => {
this._yamlMode = !this._yamlMode;
if (item) {
this.openSidebar(item.hasAttribute("selector-row"));
}
};
private _onDelete = () => {
@@ -279,6 +417,7 @@ export default class HaScriptFieldRow extends LitElement {
return [
haStyle,
indentStyle,
overflowStyles,
css`
.disabled {
opacity: 0.5;

View File

@@ -2,9 +2,10 @@ import { mdiHelpCircle } from "@mdi/js";
import type { HassService } from "home-assistant-js-websocket";
import { ERR_CONNECTION_LOST } from "home-assistant-js-websocket";
import { load } from "js-yaml";
import type { CSSResultGroup } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { until } from "lit/directives/until";
import memoizeOne from "memoize-one";
import { storage } from "../../../common/decorators/storage";
import { computeDomain } from "../../../common/entity/compute_domain";
@@ -37,6 +38,7 @@ import {
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { resolveMediaSource } from "../../../data/media_source";
@customElement("developer-tools-action")
class HaPanelDevAction extends LitElement {
@@ -46,7 +48,12 @@ class HaPanelDevAction extends LitElement {
@state() private _uiAvailable = true;
@state() private _response?: Record<string, any>;
@state() private _response?: {
domain: string;
service: string;
result: Record<string, any>;
media?: Promise<TemplateResult | typeof nothing>;
};
@state() private _error?: string;
@@ -199,7 +206,7 @@ class HaPanelDevAction extends LitElement {
</div>
</div>
${this._response
? html`<div class="content">
? html`<div class="content response">
<ha-card
.header=${this.hass.localize(
"ui.panel.developer-tools.tabs.actions.response"
@@ -212,7 +219,7 @@ class HaPanelDevAction extends LitElement {
read-only
auto-update
has-extra-actions
.value=${this._response}
.value=${this._response.result}
>
<ha-button
appearance="plain"
@@ -223,6 +230,7 @@ class HaPanelDevAction extends LitElement {
)}</ha-button
>
</ha-yaml-editor>
${until(this._response.media)}
</div>
</ha-card>
</div>`
@@ -328,7 +336,7 @@ class HaPanelDevAction extends LitElement {
private async _copyTemplate(): Promise<void> {
await copyToClipboard(
`{% set ${this._serviceData?.response_variable || "action_response"} = ${JSON.stringify(this._response)} %}`
`{% set ${this._serviceData?.response_variable || "action_response"} = ${JSON.stringify(this._response!.result)} %}`
);
showToast(this, {
message: this.hass.localize("ui.common.copied_clipboard"),
@@ -478,7 +486,48 @@ class HaPanelDevAction extends LitElement {
}
button.progress = true;
try {
this._response = (await callExecuteScript(this.hass, script)).response;
const result = (await callExecuteScript(this.hass, script)).response;
this._response = {
domain,
service,
result,
media:
"media_source_id" in result
? resolveMediaSource(this.hass, result.media_source_id).then(
(resolved) =>
resolved.mime_type.startsWith("image/")
? html`<img src=${resolved.url} alt="Media content" />`
: resolved.mime_type.startsWith("video/")
? html`
<video
controls
src=${resolved.url}
alt="Video content"
></video>
`
: resolved.mime_type.startsWith("audio/")
? html`
<audio
controls
src=${resolved.url}
alt="Audio content"
></audio>
`
: html`
<a
href=${resolved.url}
target="_blank"
rel="noreferrer"
><ha-button>
${this.hass.localize(
"ui.panel.developer-tools.tabs.actions.open_media"
)}
</ha-button></a
>
`
)
: undefined,
};
} catch (err: any) {
if (
err.error?.code === ERR_CONNECTION_LOST &&
@@ -682,6 +731,12 @@ class HaPanelDevAction extends LitElement {
display: flex;
align-items: center;
}
.response img {
max-width: 100%;
height: auto;
margin-top: 24px;
}
`,
];
}

View File

@@ -65,7 +65,7 @@ export class HuiCardFeatures extends LitElement {
width: 100%;
display: flex;
flex-direction: column;
gap: 12px;
gap: var(--ha-card-feature-gap, 12px);
width: 100%;
box-sizing: border-box;
justify-content: space-evenly;

View File

@@ -9,6 +9,7 @@ import { computeCssColor } from "../../../common/color/compute-color";
import { hsv2rgb, rgb2hex, rgb2hsv } from "../../../common/color/convert-color";
import { DOMAINS_TOGGLE } from "../../../common/const";
import { computeDomain } from "../../../common/entity/compute_domain";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { stateActive } from "../../../common/entity/state_active";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-card";
@@ -25,7 +26,6 @@ import type { HomeAssistant } from "../../../types";
import "../card-features/hui-card-features";
import type { LovelaceCardFeatureContext } from "../card-features/types";
import { actionHandler } from "../common/directives/action-handler-directive";
import { computeEntityDisplayName } from "../common/entity/compute-display-name";
import { findEntities } from "../common/find-entities";
import { handleAction } from "../common/handle-action";
import { hasAction } from "../common/has-action";
@@ -255,10 +255,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
const contentClasses = { vertical: Boolean(this._config.vertical) };
const name =
this._config.name ||
computeEntityDisplayName(this.hass, stateObj, this._config.name_content);
const name = this._config.name || computeStateName(stateObj);
const active = stateActive(stateObj);
const color = this._computeStateColor(stateObj, this._config.color);
const domain = computeDomain(stateObj.entity_id);

View File

@@ -3,7 +3,6 @@ import type { HaDurationData } from "../../../components/ha-duration-input";
import type { ActionConfig } from "../../../data/lovelace/config/action";
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import type { Statistic, StatisticType } from "../../../data/recorder";
import type { TimeFormat } from "../../../data/translation";
import type { ForecastType } from "../../../data/weather";
import type {
FullCalendarView,
@@ -26,8 +25,8 @@ import type {
} from "../entity-rows/types";
import type { LovelaceHeaderFooterConfig } from "../header-footer/types";
import type { LovelaceHeadingBadgeConfig } from "../heading-badges/types";
import type { TimeFormat } from "../../../data/translation";
import type { HomeSummary } from "../strategies/home/helpers/home-summaries";
import type { EntityNameType } from "../../../common/translations/entity-state";
export type AlarmPanelCardConfigState =
| "arm_away"
@@ -566,7 +565,6 @@ export interface WeatherForecastCardConfig extends LovelaceCardConfig {
export interface TileCardConfig extends LovelaceCardConfig {
entity: string;
name?: string;
name_content?: EntityNameType | EntityNameType[];
hide_state?: boolean;
state_content?: string | string[];
icon?: string;

View File

@@ -1,37 +0,0 @@
import type { HassEntity } from "home-assistant-js-websocket";
import { ensureArray } from "../../../../common/array/ensure-array";
import { computeEntityName } from "../../../../common/entity/compute_entity_name";
import { computeStateName } from "../../../../common/entity/compute_state_name";
import type { EntityNameType } from "../../../../common/translations/entity-state";
import type { HomeAssistant } from "../../../../types";
export const computeEntityDisplayName = (
hass: HomeAssistant,
stateObj: HassEntity,
name?: EntityNameType | EntityNameType[]
) => {
let names = ensureArray(name);
if (!name) {
return computeStateName(stateObj);
}
const entityUseDeviceName = !computeEntityName(
stateObj,
hass.entities,
hass.devices
);
// If entity has no custom name, use device name instead of entity name
if (entityUseDeviceName) {
names = names.map((n) => (n === "entity" ? "device" : n));
}
// Remove duplicates while preserving order
names = names.filter((item, pos) => names.indexOf(item) === pos);
// Fallback to state name (friendly name) if no name could be computed
return (
hass.formatEntityName(stateObj, names, " · ") || computeStateName(stateObj)
);
};

View File

@@ -44,12 +44,6 @@ const cardConfigStruct = assign(
object({
entity: optional(string()),
name: optional(string()),
name_content: optional(
union([
enums(["floor", "area", "device", "entity"]),
array(enums(["floor", "area", "device", "entity"])),
])
),
icon: optional(string()),
color: optional(string()),
show_entity_picture: optional(boolean()),
@@ -103,19 +97,11 @@ export class HuiTileCardEditor
type: "expandable",
iconPath: mdiTextShort,
schema: [
{
name: "name_content",
selector: { entity_name: {} },
context: { entity: "entity" },
},
{
name: "name",
selector: { text: {} },
},
{
name: "",
type: "grid",
schema: [
{ name: "name", selector: { text: {} } },
{
name: "icon",
selector: {
@@ -420,7 +406,6 @@ export class HuiTileCardEditor
| SchemaUnion<ReturnType<typeof this._featuresSchema>>
) => {
switch (schema.name) {
case "name_content":
case "color":
case "icon_tap_action":
case "icon_hold_action":

View File

@@ -19,6 +19,7 @@ import type {
WeatherForecastCardConfig,
} from "../../cards/types";
import { getAreas } from "../areas/helpers/areas-strategy-helper";
import type { CommonControlSectionStrategyConfig } from "../usage_prediction/common-controls-section-strategy";
export interface HomeMainViewStrategyConfig {
type: "home-main";
@@ -105,18 +106,16 @@ export class HomeMainViewStrategy extends ReactiveElement {
);
}
const commonControlsSection = isComponentLoaded(hass, "usage_prediction")
? ({
strategy: {
type: "common-controls",
title: hass.localize(
"ui.panel.lovelace.strategy.home.common_controls"
),
exclude_entities: favoriteEntities,
},
column_span: maxColumns,
} as LovelaceStrategySectionConfig)
: undefined;
const commonControlsSection = {
strategy: {
type: "common-controls",
title: hass.localize("ui.panel.lovelace.strategy.home.common_controls"),
limit: 4,
exclude_entities: favoriteEntities,
hide_empty: true,
} satisfies CommonControlSectionStrategyConfig,
column_span: maxColumns,
} as LovelaceStrategySectionConfig;
const summarySection: LovelaceSectionConfig = {
type: "grid",

View File

@@ -8,17 +8,18 @@ import type { TileCardConfig } from "../../cards/types";
const DEFAULT_LIMIT = 8;
export interface OriginalStatesViewStrategyConfig {
export interface CommonControlSectionStrategyConfig {
type: "common-controls";
title?: string;
limit?: number;
exclude_entities?: string[];
hide_empty?: boolean;
}
@customElement("common-controls-section-strategy")
export class CommonControlsSectionStrategy extends ReactiveElement {
static async generate(
config: OriginalStatesViewStrategyConfig,
config: CommonControlSectionStrategyConfig,
hass: HomeAssistant
): Promise<LovelaceSectionConfig> {
const section: LovelaceSectionConfig = {
@@ -40,6 +41,7 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
"ui.panel.lovelace.strategy.common_controls.not_loaded"
),
});
section.disabled = config.hide_empty;
return section;
}
@@ -73,6 +75,7 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
"ui.panel.lovelace.strategy.common_controls.no_data"
),
});
section.disabled = config.hide_empty;
}
return section;

View File

@@ -651,15 +651,6 @@
"placeholder": "Select an entity",
"create_helper": "Create a new {domain, select, \n undefined {} \n other {{domain} }\n } helper."
},
"entity-name-picker": {
"types": {
"floor": "Floor",
"area": "Area",
"device": "Device",
"entity": "Entity"
},
"friendly_name": "Friendly name"
},
"entity-attribute-picker": {
"attribute": "Attribute",
"show_attributes": "Show attributes"
@@ -7933,7 +7924,6 @@
},
"tile": {
"name": "Tile",
"name_content": "Name content",
"description": "The Tile card gives you a quick overview of an entity. The card allows you to toggle the entity, show the More info dialog or trigger custom actions.",
"color": "Color",
"color_helper": "Inactive state (e.g. off, closed) will not be colored.",
@@ -8807,6 +8797,7 @@
"accepts_target": "This action accepts a target, for example: `entity_id: light.bed_light`",
"no_template_ui_support": "The UI does not support templates, you can still use the YAML editor.",
"copy_clipboard_template": "Copy to clipboard as template",
"open_media": "Open media",
"errors": {
"ui": {
"no_action": "No action selected, please select an action",
@@ -9490,8 +9481,8 @@
"description": "Autoupdate the add-on when there is a new version available"
},
"ingress_panel": {
"title": "Show in sidebar",
"description": "Add this add-on to your sidebar"
"title": "Add to sidebar",
"description": "Allows users to show or hide the add-on"
},
"protected": {
"title": "Protection mode",

180
yarn.lock
View File

@@ -5120,131 +5120,131 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/a11y-base@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/a11y-base@npm:24.8.7"
"@vaadin/a11y-base@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/a11y-base@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/76e354ff25fa7c5e5f9f410b7cb9eca647c358739329b3f1e30b833c3dc4765bcbb9614dd4ef2a1ee455807773843f782a6e8205698db4506846479bfcb0ae69
checksum: 10/b236c20b057717c22b436e07b26ec317a29a168ecc9a0c7fd6751fd81a1f56f0fd7d7f34d26ea17d7cac2041321eba5f01f742ed2e917993ac452a582409839d
languageName: node
linkType: hard
"@vaadin/combo-box@npm:24.8.7":
version: 24.8.7
resolution: "@vaadin/combo-box@npm:24.8.7"
"@vaadin/combo-box@npm:24.9.0":
version: 24.9.0
resolution: "@vaadin/combo-box@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/field-base": "npm:~24.8.7"
"@vaadin/input-container": "npm:~24.8.7"
"@vaadin/item": "npm:~24.8.7"
"@vaadin/lit-renderer": "npm:~24.8.7"
"@vaadin/overlay": "npm:~24.8.7"
"@vaadin/vaadin-lumo-styles": "npm:~24.8.7"
"@vaadin/vaadin-material-styles": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
"@vaadin/a11y-base": "npm:~24.9.0"
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/field-base": "npm:~24.9.0"
"@vaadin/input-container": "npm:~24.9.0"
"@vaadin/item": "npm:~24.9.0"
"@vaadin/lit-renderer": "npm:~24.9.0"
"@vaadin/overlay": "npm:~24.9.0"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.0"
"@vaadin/vaadin-material-styles": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/323b0164ce31ba95a5ad09a211accdc08d804a71b6b368080e18736b418497432e781f80da8b7c47e04797c5eccf6759a1dcc99bd3129cea9ddb3899f191d731
checksum: 10/8b9c290c97447aac51b965f2a6f02c260ea245ec7007a1ae41aaa9ab536b7e2602d29e3e44e542999dce22c0a8048ca9b7265aad85ecc4fa550b34eb1ccc1bb5
languageName: node
linkType: hard
"@vaadin/component-base@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/component-base@npm:24.8.7"
"@vaadin/component-base@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/component-base@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/vaadin-development-mode-detector": "npm:^2.0.0"
"@vaadin/vaadin-usage-statistics": "npm:^2.1.0"
lit: "npm:^3.0.0"
checksum: 10/cd22b5834cf90cd41e66a69c2d75b01fcdb7d34e0b10a87e4c236471512c34038a7e0de0f69474da819cbc26a51303b985c8876ab3a3ae36dd590b6f77e5527e
checksum: 10/4f1bb215ce948eed443bcc681b7f60c6724d5080038d8ee69802af62c6fbe1278129ad3b50f6a708d4f9db77986a69c335b63e4fec24256e45a6909232b173cf
languageName: node
linkType: hard
"@vaadin/field-base@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/field-base@npm:24.8.7"
"@vaadin/field-base@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/field-base@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/a11y-base": "npm:~24.9.0"
"@vaadin/component-base": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/0c5bfc31bbfa0fbab121ccb3db6dff565725f456d9a269ff298c021ca9a3331e7e806eb4e5281052bb7a8e184dd091b4cd746a3e41a63f6a996cfd513e029bbc
checksum: 10/93febd981bc7628934c752d6f7d2f29c858593020e445640d4fc27b31b74c1808e559fd49d8249ac25b1011c9d143afc27f78741f8d49438804f6f43a7374c9b
languageName: node
linkType: hard
"@vaadin/icon@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/icon@npm:24.8.7"
"@vaadin/icon@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/icon@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/vaadin-lumo-styles": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/b182245273240d8794e0922d996eb4bf633cbfcf5dccc5323f6b1b77d4861c7113be35539c9bacef8fe4bab8995047529b3130dc5f273f3d4ab3add0eef2079b
checksum: 10/06c3ce8f85f8a5dfa8ac17b33999334ba0f863ba2c2f032eb745155e197b16f8897839efc2f4171d0d7b134f74d45edb4d62a7eeb2e10c7727613fe678da6300
languageName: node
linkType: hard
"@vaadin/input-container@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/input-container@npm:24.8.7"
"@vaadin/input-container@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/input-container@npm:24.9.0"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/vaadin-lumo-styles": "npm:~24.8.7"
"@vaadin/vaadin-material-styles": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.0"
"@vaadin/vaadin-material-styles": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/dabf6ac85ea632f8d295a9c225d66dbedb646541d242db5580c707fd44f7671bb3bc619d43e4fdd9041fdab818a1dedb06d659569f525c9aad3482bc7dd4bca8
checksum: 10/eed1e686bb690d1861b34edefa3d9a7bc0ae4f80b71c98d4162a0ebb3aa60994e623dc276a450ce26f262ad972c258909af51909a037f3ff062a5c32aadeaa88
languageName: node
linkType: hard
"@vaadin/item@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/item@npm:24.8.7"
"@vaadin/item@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/item@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/vaadin-lumo-styles": "npm:~24.8.7"
"@vaadin/vaadin-material-styles": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
"@vaadin/a11y-base": "npm:~24.9.0"
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.0"
"@vaadin/vaadin-material-styles": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/57d63ff8df827d2324ebbeb54e911b7e7e5ee7d7b3ef8179e9c2e3b5e6a5db8a332e425eee8e3a33ec720e5a9b3735b717721ac5d0e8ef4469b1cfacfc97dc01
checksum: 10/fe2f941c9acab5fc80bf24abb3216d9b490b46a33bea2b18297c965af3b1dba6fe0b9c471d16cd4c2626e0536a089ce03632a95f886712d0b7d197dc4c48c995
languageName: node
linkType: hard
"@vaadin/lit-renderer@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/lit-renderer@npm:24.8.7"
"@vaadin/lit-renderer@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/lit-renderer@npm:24.9.0"
dependencies:
lit: "npm:^3.0.0"
checksum: 10/be89ec15b40f67f19daff422445de67725fb77b9433c93ee6727ce8dc2513dfc6f1ecaed26374a0a39e995035a89408408acf5f233f7c9a30ddafb63746aec5e
checksum: 10/2b0f57c7a63a22ee0996e19844bd7529ccc688d9a687655a04e021787adfca83cb2aafd5bced61ebcfdba7108fe16d14435f4294dee1d240fcc39390deabb2af
languageName: node
linkType: hard
"@vaadin/overlay@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/overlay@npm:24.8.7"
"@vaadin/overlay@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/overlay@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/a11y-base": "npm:~24.8.7"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/vaadin-lumo-styles": "npm:~24.8.7"
"@vaadin/vaadin-material-styles": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
"@vaadin/a11y-base": "npm:~24.9.0"
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/vaadin-lumo-styles": "npm:~24.9.0"
"@vaadin/vaadin-material-styles": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
lit: "npm:^3.0.0"
checksum: 10/598c66a9e36c76e883750e733a64ff84906055ed14c2b27d92a850ae6f7f2daf763adb15dfdfc4708e8cae25e857d4e53498ccc5f1e7463b1d04b045a65f9049
checksum: 10/e0758d2eb2ddd40edc1e4073adf5cb2f21836fa5ba50ae97c08fb29115d11521ef0faaca93493d5ab47a8d9186637167ac382ed88a097583fa9dc0672f9af773
languageName: node
linkType: hard
@@ -5255,37 +5255,37 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/vaadin-lumo-styles@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/vaadin-lumo-styles@npm:24.8.7"
"@vaadin/vaadin-lumo-styles@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/vaadin-lumo-styles@npm:24.9.0"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/icon": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
checksum: 10/4c89524eab8a63e8135548ba2120403f599c1962fc81fcae5d6222e24ede5f6ade7eca6b928227c4572ae2c7d5cec00039efd9a195e32397656c28d351bcb88b
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/icon": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
checksum: 10/e21b8e2180a47a9c4b1208af474a796b42f5bbaca85ef8f19c5dd512d82dc7457e674041200f2b77c8aa0b5439ba00e75a526ec263cc4f9a051ed33f1d1f632b
languageName: node
linkType: hard
"@vaadin/vaadin-material-styles@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/vaadin-material-styles@npm:24.8.7"
"@vaadin/vaadin-material-styles@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/vaadin-material-styles@npm:24.9.0"
dependencies:
"@polymer/polymer": "npm:^3.0.0"
"@vaadin/component-base": "npm:~24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:~24.8.7"
checksum: 10/ab6bcca41971d4a4a8733addc6413ea683eb40c672a541f688125ed51225b84330a0189367535d32dc3a1b596963e9c2302ae783a97d641845848b5af7214b61
"@vaadin/component-base": "npm:~24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:~24.9.0"
checksum: 10/99925a620ee5b69aa2cc140356c79d709d7ace9c6db6b4b27baf84658cad9b5cb5bc206904b85e23c43c59fdecfd48e164d78d4c7d132964049f1193745f5056
languageName: node
linkType: hard
"@vaadin/vaadin-themable-mixin@npm:24.8.7, @vaadin/vaadin-themable-mixin@npm:~24.8.7":
version: 24.8.7
resolution: "@vaadin/vaadin-themable-mixin@npm:24.8.7"
"@vaadin/vaadin-themable-mixin@npm:24.9.0, @vaadin/vaadin-themable-mixin@npm:~24.9.0":
version: 24.9.0
resolution: "@vaadin/vaadin-themable-mixin@npm:24.9.0"
dependencies:
"@open-wc/dedupe-mixin": "npm:^1.3.0"
lit: "npm:^3.0.0"
style-observer: "npm:^0.0.8"
checksum: 10/bcb6413d5c4a55df623e35bf9ea1eae17623643313b0016df376a9d947940f4ec32765faf0cdf6b7b443f5341fbb13cfb54bfc268c23407dae72a42dc132686f
checksum: 10/2fd82ee583e8098f29ac32c7192a2f289b556ad93d3cb6394e5e587497d9278e65adb3f6a48003ecc2e2f99a3abe2af26b60d5ee7a625a69841afe24febe1dc4
languageName: node
linkType: hard
@@ -9417,8 +9417,8 @@ __metadata:
"@types/tar": "npm:6.1.13"
"@types/ua-parser-js": "npm:0.7.39"
"@types/webspeechapi": "npm:0.0.29"
"@vaadin/combo-box": "npm:24.8.7"
"@vaadin/vaadin-themable-mixin": "npm:24.8.7"
"@vaadin/combo-box": "npm:24.9.0"
"@vaadin/vaadin-themable-mixin": "npm:24.9.0"
"@vibrant/color": "npm:4.0.0"
"@vitest/coverage-v8": "npm:3.2.4"
"@vue/web-component-wrapper": "npm:1.3.0"
@@ -9480,7 +9480,7 @@ __metadata:
lodash.template: "npm:4.5.0"
luxon: "npm:3.7.2"
map-stream: "npm:0.0.7"
marked: "npm:16.2.1"
marked: "npm:16.3.0"
memoize-one: "npm:6.0.0"
node-vibrant: "npm:4.0.3"
object-hash: "npm:3.0.0"
@@ -11151,12 +11151,12 @@ __metadata:
languageName: node
linkType: hard
"marked@npm:16.2.1":
version: 16.2.1
resolution: "marked@npm:16.2.1"
"marked@npm:16.3.0":
version: 16.3.0
resolution: "marked@npm:16.3.0"
bin:
marked: bin/marked.js
checksum: 10/67e911a7dd416869649dee18dc4a9683c0ccd8e72ba0fee3b3f578f857416e69780013e9d63762c600e6f9cf997c5af9fa0507a2053f8e65d39c5459c245c0cd
checksum: 10/60497834b9acfb3b3994222509d359ecb9a197c885dfeb77e2050a287cd2f4ab19f00d5597172b47f9e0c54d9e1e13d8b2dd73322b7838599e1f16d1d6283f5b
languageName: node
linkType: hard