mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-22 23:59:26 +00:00
Compare commits
11 Commits
fix_hold_a
...
dev
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8093f7f4cb | ||
![]() |
b26c914ff9 | ||
![]() |
b2fa97b6dc | ||
![]() |
8a8bba422a | ||
![]() |
76ca66b1b5 | ||
![]() |
280dbfc958 | ||
![]() |
0b10ad3e78 | ||
![]() |
04d0aa2f22 | ||
![]() |
4b901101da | ||
![]() |
4960284e2d | ||
![]() |
11d32300e9 |
@@ -191,7 +191,7 @@
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-lit": "2.1.1",
|
||||
"eslint-plugin-lit-a11y": "5.1.1",
|
||||
"eslint-plugin-unused-imports": "4.1.4",
|
||||
"eslint-plugin-unused-imports": "4.2.0",
|
||||
"eslint-plugin-wc": "3.0.1",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.3.1",
|
||||
@@ -218,7 +218,7 @@
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.39.1",
|
||||
"typescript-eslint": "8.40.0",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
|
@@ -101,7 +101,7 @@ export class StateHistoryChartTimeline extends LitElement {
|
||||
fill: api.value(4) as string,
|
||||
},
|
||||
};
|
||||
const text = api.value(3) as string;
|
||||
const text = (api.value(3) as string).replaceAll("\n", " ");
|
||||
const textWidth = measureTextWidth(text, 12);
|
||||
const LABEL_PADDING = 4;
|
||||
if (textWidth < rectShape.width - LABEL_PADDING * 2) {
|
||||
|
@@ -2,10 +2,16 @@ import type { Condition } from "../../../panels/lovelace/common/validate-conditi
|
||||
import type { LovelaceCardConfig } from "./card";
|
||||
import type { LovelaceStrategyConfig } from "./strategy";
|
||||
|
||||
export interface LovelaceSectionStyleConfig {
|
||||
background_color?: string;
|
||||
background_opacity?: number;
|
||||
}
|
||||
|
||||
export interface LovelaceBaseSectionConfig {
|
||||
visibility?: Condition[];
|
||||
column_span?: number;
|
||||
row_span?: number;
|
||||
style?: LovelaceSectionStyleConfig;
|
||||
/**
|
||||
* @deprecated Use heading card instead.
|
||||
*/
|
||||
|
@@ -12,6 +12,7 @@ export interface Zone {
|
||||
}
|
||||
|
||||
export interface HomeZoneMutableParams {
|
||||
name?: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
radius: number;
|
||||
|
@@ -856,7 +856,9 @@ export class QuickBar extends LitElement {
|
||||
|
||||
private _generateNavigationPanelCommands(): BaseNavigationCommand[] {
|
||||
return Object.keys(this.hass.panels)
|
||||
.filter((panelKey) => panelKey !== "_my_redirect")
|
||||
.filter(
|
||||
(panelKey) => panelKey !== "_my_redirect" && panelKey !== "hassio"
|
||||
)
|
||||
.map((panelKey) => {
|
||||
const panel = this.hass.panels[panelKey];
|
||||
const translationKey = getPanelNameTranslationKey(panel);
|
||||
|
@@ -112,7 +112,9 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
|
||||
this.assistConfiguration.available_wake_words.length > 1
|
||||
? html`<div class="row">
|
||||
<ha-select
|
||||
.label=${"Wake word"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.detail.form.wake_word_id"
|
||||
)}
|
||||
@closed=${stopPropagation}
|
||||
fixedMenuPosition
|
||||
naturalMenuWidth
|
||||
@@ -144,7 +146,9 @@ export class HaVoiceAssistantSetupStepSuccess extends LitElement {
|
||||
${pipelineEntity
|
||||
? html`<div class="row">
|
||||
<ha-select
|
||||
.label=${"Assistant"}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.assistants.pipeline.devices.pipeline"
|
||||
)}
|
||||
@closed=${stopPropagation}
|
||||
.value=${pipelineEntity?.state}
|
||||
fixedMenuPosition
|
||||
|
@@ -85,7 +85,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
this._deviceTrackers = this._params.entry.device_trackers || [];
|
||||
this._picture = this._params.entry.picture || null;
|
||||
this._user = this._userId
|
||||
? this._params.users.find((user) => user.id === this._userId)
|
||||
? this._params.users?.find((user) => user.id === this._userId)
|
||||
: undefined;
|
||||
this._isAdmin = this._user?.group_ids.includes(SYSTEM_GROUP_ID_ADMIN);
|
||||
this._localOnly = this._user?.local_only;
|
||||
@@ -372,10 +372,10 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
userAddedCallback: async (user?: User) => {
|
||||
if (user) {
|
||||
target.checked = true;
|
||||
if (this._params!.entry) {
|
||||
if (this._params!.entry && this._params!.updateEntry) {
|
||||
await this._params!.updateEntry({ user_id: user.id });
|
||||
}
|
||||
this._params?.refreshUsers();
|
||||
this._params?.refreshUsers?.();
|
||||
this._user = user;
|
||||
this._userId = user.id;
|
||||
this._isAdmin = user.group_ids.includes(SYSTEM_GROUP_ID_ADMIN);
|
||||
@@ -403,7 +403,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
return;
|
||||
}
|
||||
await deleteUser(this.hass, this._userId);
|
||||
this._params?.refreshUsers();
|
||||
this._params?.refreshUsers?.();
|
||||
this._userId = undefined;
|
||||
this._user = undefined;
|
||||
this._isAdmin = undefined;
|
||||
@@ -466,7 +466,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
if (newUsername) {
|
||||
try {
|
||||
await adminChangeUsername(this.hass, this._user.id, newUsername);
|
||||
this._params?.refreshUsers();
|
||||
this._params?.refreshUsers?.();
|
||||
this._user = { ...this._user, username: newUsername };
|
||||
showAlertDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@@ -500,7 +500,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
],
|
||||
local_only: this._localOnly,
|
||||
});
|
||||
this._params?.refreshUsers();
|
||||
this._params?.refreshUsers?.();
|
||||
}
|
||||
const values: PersonMutableParams = {
|
||||
name: this._name.trim(),
|
||||
@@ -509,9 +509,9 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
picture: this._picture,
|
||||
};
|
||||
if (this._params!.entry) {
|
||||
await this._params!.updateEntry(values);
|
||||
await this._params!.updateEntry?.(values);
|
||||
} else {
|
||||
await this._params!.createEntry(values);
|
||||
await this._params!.createEntry?.(values);
|
||||
this._personExists = true;
|
||||
}
|
||||
this.closeDialog();
|
||||
@@ -525,7 +525,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
|
||||
private async _deleteEntry() {
|
||||
this._submitting = true;
|
||||
try {
|
||||
if (await this._params!.removeEntry()) {
|
||||
if (await this._params!.removeEntry?.()) {
|
||||
if (this._params!.entry!.user_id) {
|
||||
deleteUser(this.hass, this._params!.entry!.user_id);
|
||||
}
|
||||
|
@@ -4,22 +4,22 @@ import type { User } from "../../../data/user";
|
||||
|
||||
export interface PersonDetailDialogParams {
|
||||
entry?: Person;
|
||||
users: User[];
|
||||
refreshUsers: () => void;
|
||||
createEntry: (values: PersonMutableParams) => Promise<unknown>;
|
||||
updateEntry: (updates: Partial<PersonMutableParams>) => Promise<unknown>;
|
||||
removeEntry: () => Promise<boolean>;
|
||||
users?: User[];
|
||||
refreshUsers?: () => void;
|
||||
createEntry?: (values: PersonMutableParams) => Promise<unknown>;
|
||||
updateEntry?: (updates: Partial<PersonMutableParams>) => Promise<unknown>;
|
||||
removeEntry?: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
export const loadPersonDetailDialog = () => import("./dialog-person-detail");
|
||||
|
||||
export const showPersonDetailDialog = (
|
||||
element: HTMLElement,
|
||||
systemLogDetailParams: PersonDetailDialogParams
|
||||
params: PersonDetailDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-person-detail",
|
||||
dialogImport: loadPersonDetailDialog,
|
||||
dialogParams: systemLogDetailParams,
|
||||
dialogParams: params,
|
||||
});
|
||||
};
|
||||
|
@@ -34,6 +34,7 @@ class DialogHomeZoneDetail extends LitElement {
|
||||
this._params = params;
|
||||
this._error = undefined;
|
||||
this._data = {
|
||||
name: this.hass.config.location_name,
|
||||
latitude: this.hass.config.latitude,
|
||||
longitude: this.hass.config.longitude,
|
||||
radius: this.hass.config.radius,
|
||||
@@ -63,7 +64,7 @@ class DialogHomeZoneDetail extends LitElement {
|
||||
escapeKeyAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass!.localize("ui.panel.config.zone.edit_home")
|
||||
this.hass!.localize("ui.common.edit_item", { name: this._data.name })
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
|
@@ -85,7 +85,9 @@ class DialogZoneDetail extends LitElement {
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this._params.entry
|
||||
? this._params.entry.name
|
||||
? this.hass!.localize("ui.common.edit_item", {
|
||||
name: this._params.entry.name,
|
||||
})
|
||||
: this.hass!.localize("ui.panel.config.zone.detail.new_zone")
|
||||
)}
|
||||
>
|
||||
|
@@ -165,9 +165,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
.entry=${entry}
|
||||
@click=${this._openEditEntry}
|
||||
.path=${mdiPencil}
|
||||
.label=${hass.localize(
|
||||
"ui.panel.config.zone.edit_zone"
|
||||
)}
|
||||
.label=${hass.localize("ui.common.edit_item", {
|
||||
name: entry.name,
|
||||
})}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`
|
||||
@@ -218,9 +218,9 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
this._canEditCore
|
||||
? mdiPencil
|
||||
: mdiPencilOff}
|
||||
.label=${stateObject.entity_id === "zone.home"
|
||||
? hass.localize("ui.panel.config.zone.edit_home")
|
||||
: hass.localize("ui.panel.config.zone.edit_zone")}
|
||||
.label=${hass.localize("ui.common.edit_item", {
|
||||
name: hass.config.location_name,
|
||||
})}
|
||||
@click=${this._editHomeZone}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>`}
|
||||
|
@@ -0,0 +1,323 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
mdiPause,
|
||||
mdiPlay,
|
||||
mdiPlayPause,
|
||||
mdiPower,
|
||||
mdiSkipNext,
|
||||
mdiSkipPrevious,
|
||||
mdiStop,
|
||||
} from "@mdi/js";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { LovelaceCardFeature } from "../types";
|
||||
import { cardFeatureStyles } from "./common/card-feature-styles";
|
||||
import type {
|
||||
LovelaceCardFeatureContext,
|
||||
MediaPlayerPlaybackCardFeatureConfig,
|
||||
} from "./types";
|
||||
import type {
|
||||
ControlButton,
|
||||
MediaPlayerEntity,
|
||||
} from "../../../data/media-player";
|
||||
import { MediaPlayerEntityFeature } from "../../../data/media-player";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { isUnavailableState } from "../../../data/entity";
|
||||
import { hasConfigChanged } from "../common/has-changed";
|
||||
import "../../../components/ha-control-button-group";
|
||||
import "../../../components/ha-control-button";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon";
|
||||
|
||||
export const supportsMediaPlayerPlaybackCardFeature = (
|
||||
hass: HomeAssistant,
|
||||
context: LovelaceCardFeatureContext
|
||||
) => {
|
||||
const stateObj = context.entity_id
|
||||
? hass.states[context.entity_id]
|
||||
: undefined;
|
||||
if (!stateObj) return false;
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return domain === "media_player";
|
||||
};
|
||||
|
||||
@customElement("hui-media-player-playback-card-feature")
|
||||
class HuiMediaPlayerPlaybackCardFeature
|
||||
extends LitElement
|
||||
implements LovelaceCardFeature
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public context?: LovelaceCardFeatureContext;
|
||||
|
||||
@property({ attribute: false }) public color?: string;
|
||||
|
||||
@state() private _config?: MediaPlayerPlaybackCardFeatureConfig;
|
||||
|
||||
@state() private _narrow?: boolean = false;
|
||||
|
||||
private get _stateObj() {
|
||||
if (!this.hass || !this.context || !this.context.entity_id) {
|
||||
return undefined;
|
||||
}
|
||||
return this.hass.states[this.context.entity_id] as
|
||||
| MediaPlayerEntity
|
||||
| undefined;
|
||||
}
|
||||
|
||||
static getStubConfig(): MediaPlayerPlaybackCardFeatureConfig {
|
||||
return {
|
||||
type: "media-player-playback",
|
||||
};
|
||||
}
|
||||
|
||||
public setConfig(config: MediaPlayerPlaybackCardFeatureConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public willUpdate(): void {
|
||||
if (!this.hasUpdated) {
|
||||
this._measureCard();
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
const entityId = this.context?.entity_id;
|
||||
return (
|
||||
hasConfigChanged(this, changedProps) ||
|
||||
(changedProps.has("hass") &&
|
||||
(!oldHass ||
|
||||
!entityId ||
|
||||
oldHass.states[entityId] !== this.hass!.states[entityId]))
|
||||
);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
!this.context ||
|
||||
!supportsMediaPlayerPlaybackCardFeature(this.hass, this.context) ||
|
||||
!this._stateObj
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const buttons = this._computeButtons(this._stateObj);
|
||||
|
||||
return html`
|
||||
<ha-control-button-group>
|
||||
${supportsFeature(this._stateObj, MediaPlayerEntityFeature.TURN_OFF) &&
|
||||
stateActive(this._stateObj)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.media_player.turn_off")}
|
||||
@click=${this._togglePower}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
: ""}
|
||||
${supportsFeature(this._stateObj, MediaPlayerEntityFeature.TURN_ON) &&
|
||||
!stateActive(this._stateObj) &&
|
||||
!isUnavailableState(this._stateObj.state)
|
||||
? html`
|
||||
<ha-control-button
|
||||
.label=${this.hass.localize("ui.card.media_player.turn_on")}
|
||||
@click=${this._togglePower}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
: buttons.map(
|
||||
(button) => html`
|
||||
<ha-control-button
|
||||
key=${button.action}
|
||||
.label=${this.hass?.localize(
|
||||
`ui.card.media_player.${button.action}`
|
||||
)}
|
||||
@click=${this._action}
|
||||
>
|
||||
<ha-svg-icon .path=${button.icon}></ha-svg-icon>
|
||||
</ha-control-button>
|
||||
`
|
||||
)}
|
||||
</ha-control-button-group>
|
||||
`;
|
||||
}
|
||||
|
||||
private _measureCard() {
|
||||
if (!this.isConnected) {
|
||||
return;
|
||||
}
|
||||
const host = (this.getRootNode() as ShadowRoot).host as
|
||||
| HTMLElement
|
||||
| undefined;
|
||||
const width = host?.clientWidth ?? this.clientWidth ?? 0;
|
||||
this._narrow = width < 300;
|
||||
}
|
||||
|
||||
private _computeControlButton(stateObj: MediaPlayerEntity): ControlButton {
|
||||
return stateObj.state === "on"
|
||||
? { icon: mdiPlayPause, action: "media_play_pause" }
|
||||
: stateObj.state !== "playing"
|
||||
? { icon: mdiPlay, action: "media_play" }
|
||||
: supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE)
|
||||
? { icon: mdiPause, action: "media_pause" }
|
||||
: { icon: mdiStop, action: "media_stop" };
|
||||
}
|
||||
|
||||
private _computeButtons(stateObj: MediaPlayerEntity): ControlButton[] {
|
||||
const controlButton = this._computeControlButton(stateObj);
|
||||
const assumedState = stateObj.attributes.assumed_state === true;
|
||||
|
||||
const controls: ControlButton[] = [];
|
||||
|
||||
if (
|
||||
!this._narrow &&
|
||||
(stateObj.state === "playing" || assumedState) &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PREVIOUS_TRACK)
|
||||
) {
|
||||
controls.push({ icon: mdiSkipPrevious, action: "media_previous_track" });
|
||||
}
|
||||
|
||||
if (
|
||||
!assumedState &&
|
||||
((stateObj.state === "playing" &&
|
||||
(supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE) ||
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.STOP))) ||
|
||||
((stateObj.state === "paused" || stateObj.state === "idle") &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY)) ||
|
||||
(stateObj.state === "on" &&
|
||||
(supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY) ||
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE))))
|
||||
) {
|
||||
controls.push({ icon: controlButton.icon, action: controlButton.action });
|
||||
}
|
||||
|
||||
if (assumedState) {
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.PLAY)) {
|
||||
controls.push({ icon: mdiPlay, action: "media_play" });
|
||||
}
|
||||
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.PAUSE)) {
|
||||
controls.push({ icon: mdiPause, action: "media_pause" });
|
||||
}
|
||||
|
||||
if (supportsFeature(stateObj, MediaPlayerEntityFeature.STOP)) {
|
||||
controls.push({ icon: mdiStop, action: "media_stop" });
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(stateObj.state === "playing" || assumedState) &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.NEXT_TRACK)
|
||||
) {
|
||||
controls.push({ icon: mdiSkipNext, action: "media_next_track" });
|
||||
}
|
||||
|
||||
return controls;
|
||||
}
|
||||
|
||||
private _togglePower(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService(
|
||||
"media_player",
|
||||
stateActive(this._stateObj) ? "turn_off" : "turn_on",
|
||||
{
|
||||
entity_id: this._stateObj.entity_id,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _action(e: Event): void {
|
||||
const action = (e.currentTarget as HTMLElement).getAttribute("key");
|
||||
if (!action) return;
|
||||
|
||||
switch (action) {
|
||||
case "media_play_pause":
|
||||
this._playPauseStop();
|
||||
break;
|
||||
case "media_play":
|
||||
this._play();
|
||||
break;
|
||||
case "media_pause":
|
||||
this._pause();
|
||||
break;
|
||||
case "media_stop":
|
||||
this._stop();
|
||||
break;
|
||||
case "media_previous_track":
|
||||
this._previousTrack();
|
||||
break;
|
||||
case "media_next_track":
|
||||
this._nextTrack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _playPauseStop(): void {
|
||||
if (!this._stateObj) return;
|
||||
|
||||
const service =
|
||||
this._stateObj.state !== "playing"
|
||||
? "media_play"
|
||||
: supportsFeature(this._stateObj, MediaPlayerEntityFeature.PAUSE)
|
||||
? "media_pause"
|
||||
: "media_stop";
|
||||
|
||||
this.hass!.callService("media_player", service, {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _play(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_play", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _pause(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_pause", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _stop(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_stop", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _previousTrack(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_previous_track", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _nextTrack(): void {
|
||||
if (!this._stateObj) return;
|
||||
this.hass!.callService("media_player", "media_next_track", {
|
||||
entity_id: this._stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
static styles = cardFeatureStyles;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-media-player-playback-card-feature": HuiMediaPlayerPlaybackCardFeature;
|
||||
}
|
||||
}
|
@@ -39,6 +39,10 @@ export interface LockOpenDoorCardFeatureConfig {
|
||||
type: "lock-open-door";
|
||||
}
|
||||
|
||||
export interface MediaPlayerPlaybackCardFeatureConfig {
|
||||
type: "media-player-playback";
|
||||
}
|
||||
|
||||
export interface MediaPlayerVolumeSliderCardFeatureConfig {
|
||||
type: "media-player-volume-slider";
|
||||
}
|
||||
@@ -242,6 +246,7 @@ export type LovelaceCardFeatureConfig =
|
||||
| LightColorTempCardFeatureConfig
|
||||
| LockCommandsCardFeatureConfig
|
||||
| LockOpenDoorCardFeatureConfig
|
||||
| MediaPlayerPlaybackCardFeatureConfig
|
||||
| MediaPlayerVolumeSliderCardFeatureConfig
|
||||
| NumericInputCardFeatureConfig
|
||||
| SelectOptionsCardFeatureConfig
|
||||
|
@@ -163,8 +163,20 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<div
|
||||
class="image-container"
|
||||
<hui-image
|
||||
.hass=${this.hass}
|
||||
.image=${image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.cameraImage=${domain === "camera"
|
||||
? this._config.entity
|
||||
: this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.entity=${this._config.entity}
|
||||
.aspectRatio=${ignoreAspectRatio
|
||||
? undefined
|
||||
: this._config.aspect_ratio}
|
||||
.fitMode=${this._config.fit_mode}
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: hasAction(this._config!.hold_action),
|
||||
@@ -175,28 +187,7 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
? "0"
|
||||
: undefined
|
||||
)}
|
||||
role=${ifDefined(
|
||||
hasAction(this._config.tap_action) || this._config.entity
|
||||
? "0"
|
||||
: undefined
|
||||
)}
|
||||
>
|
||||
<hui-image
|
||||
.hass=${this.hass}
|
||||
.image=${image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.cameraImage=${domain === "camera"
|
||||
? this._config.entity
|
||||
: this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.entity=${this._config.entity}
|
||||
.aspectRatio=${ignoreAspectRatio
|
||||
? undefined
|
||||
: this._config.aspect_ratio}
|
||||
.fitMode=${this._config.fit_mode}
|
||||
></hui-image>
|
||||
</div>
|
||||
></hui-image>
|
||||
${footer}
|
||||
</ha-card>
|
||||
`;
|
||||
@@ -211,14 +202,8 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
hui-image {
|
||||
cursor: pointer;
|
||||
pointer-events: none;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
@@ -219,13 +219,13 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<div
|
||||
class="image-container ${classMap({
|
||||
<hui-image
|
||||
class=${classMap({
|
||||
clickable:
|
||||
hasTapAction ||
|
||||
hasAction(this._config.hold_action) ||
|
||||
hasAction(this._config.double_tap_action),
|
||||
})}"
|
||||
})}
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
hasTap: hasTapAction,
|
||||
@@ -233,23 +233,19 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
hasDoubleClick: hasAction(this._config.double_tap_action),
|
||||
})}
|
||||
tabindex=${ifDefined(hasTapAction ? "0" : undefined)}
|
||||
role=${ifDefined(hasTapAction ? "button" : undefined)}
|
||||
.config=${this._config}
|
||||
>
|
||||
<hui-image
|
||||
.hass=${this.hass}
|
||||
.image=${image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.cameraImage=${this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.entity=${this._config.entity}
|
||||
.fitMode=${this._config.fit_mode}
|
||||
.aspectRatio=${ignoreAspectRatio
|
||||
? undefined
|
||||
: this._config.aspect_ratio}
|
||||
></hui-image>
|
||||
</div>
|
||||
.hass=${this.hass}
|
||||
.image=${image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.cameraImage=${this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.entity=${this._config.entity}
|
||||
.fitMode=${this._config.fit_mode}
|
||||
.aspectRatio=${ignoreAspectRatio
|
||||
? undefined
|
||||
: this._config.aspect_ratio}
|
||||
></hui-image>
|
||||
<div class="box">
|
||||
${this._config.title
|
||||
? html`<div class="title">${this._config.title}</div>`
|
||||
@@ -346,16 +342,12 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.image-container {
|
||||
height: 100%;
|
||||
}
|
||||
.image-container.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
hui-image {
|
||||
pointer-events: none;
|
||||
height: 100%;
|
||||
}
|
||||
hui-image.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.box {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
@@ -22,6 +22,7 @@ import "../card-features/hui-light-brightness-card-feature";
|
||||
import "../card-features/hui-light-color-temp-card-feature";
|
||||
import "../card-features/hui-lock-commands-card-feature";
|
||||
import "../card-features/hui-lock-open-door-card-feature";
|
||||
import "../card-features/hui-media-player-playback-card-feature";
|
||||
import "../card-features/hui-media-player-volume-slider-card-feature";
|
||||
import "../card-features/hui-numeric-input-card-feature";
|
||||
import "../card-features/hui-select-options-card-feature";
|
||||
@@ -70,6 +71,7 @@ const TYPES = new Set<LovelaceCardFeatureConfig["type"]>([
|
||||
"light-color-temp",
|
||||
"lock-commands",
|
||||
"lock-open-door",
|
||||
"media-player-playback",
|
||||
"media-player-volume-slider",
|
||||
"numeric-input",
|
||||
"select-options",
|
||||
|
@@ -42,6 +42,7 @@ import { supportsLightBrightnessCardFeature } from "../../card-features/hui-ligh
|
||||
import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature";
|
||||
import { supportsLockCommandsCardFeature } from "../../card-features/hui-lock-commands-card-feature";
|
||||
import { supportsLockOpenDoorCardFeature } from "../../card-features/hui-lock-open-door-card-feature";
|
||||
import { supportsMediaPlayerPlaybackCardFeature } from "../../card-features/hui-media-player-playback-card-feature";
|
||||
import { supportsMediaPlayerVolumeSliderCardFeature } from "../../card-features/hui-media-player-volume-slider-card-feature";
|
||||
import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature";
|
||||
import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature";
|
||||
@@ -95,6 +96,7 @@ const UI_FEATURE_TYPES = [
|
||||
"light-color-temp",
|
||||
"lock-commands",
|
||||
"lock-open-door",
|
||||
"media-player-playback",
|
||||
"media-player-volume-slider",
|
||||
"numeric-input",
|
||||
"select-options",
|
||||
@@ -162,6 +164,7 @@ const SUPPORTS_FEATURE_TYPES: Record<
|
||||
"light-color-temp": supportsLightColorTempCardFeature,
|
||||
"lock-commands": supportsLockCommandsCardFeature,
|
||||
"lock-open-door": supportsLockOpenDoorCardFeature,
|
||||
"media-player-playback": supportsMediaPlayerPlaybackCardFeature,
|
||||
"media-player-volume-slider": supportsMediaPlayerVolumeSliderCardFeature,
|
||||
"numeric-input": supportsNumericInputCardFeature,
|
||||
"select-options": supportsSelectOptionsCardFeature,
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { mdiFormatColorFill } from "@mdi/js";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
@@ -10,9 +12,13 @@ import "../../../../components/ha-form/ha-form";
|
||||
import type { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
|
||||
import type { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { hex2rgb, rgb2hex } from "../../../../common/color/convert-color";
|
||||
|
||||
interface SettingsData {
|
||||
column_span?: number;
|
||||
background_type: "none" | "color";
|
||||
background_color?: number[];
|
||||
background_opacity?: number;
|
||||
}
|
||||
|
||||
@customElement("hui-section-settings-editor")
|
||||
@@ -23,8 +29,10 @@ export class HuiDialogEditSection extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
|
||||
|
||||
@state() private _selectorBackgroundType: "none" | "color" = "none";
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(maxColumns: number) =>
|
||||
(maxColumns: number, enableBackground: boolean) =>
|
||||
[
|
||||
{
|
||||
name: "column_span",
|
||||
@@ -36,15 +44,91 @@ export class HuiDialogEditSection extends LitElement {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "styling",
|
||||
type: "expandable",
|
||||
flatten: true,
|
||||
iconPath: mdiFormatColorFill,
|
||||
schema: [
|
||||
{
|
||||
name: "background_settings",
|
||||
flatten: true,
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "background_type",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
{
|
||||
value: "none",
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_section.settings.background_type_none_option"
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "color",
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_section.settings.background_type_color_option"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "background_color",
|
||||
selector: {
|
||||
color_rgb: {},
|
||||
},
|
||||
disabled: !enableBackground,
|
||||
},
|
||||
{
|
||||
name: "background_opacity",
|
||||
selector: {
|
||||
number: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
unit_of_measurement: "%",
|
||||
},
|
||||
},
|
||||
disabled: !enableBackground,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
] as const satisfies HaFormSchema[]
|
||||
);
|
||||
|
||||
protected firstUpdated(_changedProperties: PropertyValues) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
if (this.config.style?.background_color) {
|
||||
this._selectorBackgroundType = "color";
|
||||
} else {
|
||||
this._selectorBackgroundType = "none";
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const data: SettingsData = {
|
||||
column_span: this.config.column_span || 1,
|
||||
background_type: this._selectorBackgroundType,
|
||||
background_color: this.config.style?.background_color
|
||||
? hex2rgb(this.config.style?.background_color as any)
|
||||
: [],
|
||||
background_opacity: this.config.style?.background_opacity || 100,
|
||||
};
|
||||
|
||||
const schema = this._schema(this.viewConfig.max_columns || 4);
|
||||
const schema = this._schema(
|
||||
this.viewConfig.max_columns || 4,
|
||||
this._selectorBackgroundType === "color"
|
||||
);
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
@@ -76,11 +160,27 @@ export class HuiDialogEditSection extends LitElement {
|
||||
ev.stopPropagation();
|
||||
const newData = ev.detail.value as SettingsData;
|
||||
|
||||
this._selectorBackgroundType = newData.background_type;
|
||||
|
||||
const newConfig: LovelaceSectionRawConfig = {
|
||||
...this.config,
|
||||
column_span: newData.column_span,
|
||||
};
|
||||
|
||||
if (newData.background_type === "color") {
|
||||
newConfig.style = {
|
||||
...newConfig.style,
|
||||
background_color: rgb2hex(newData.background_color as any),
|
||||
background_opacity: newData.background_opacity,
|
||||
};
|
||||
} else {
|
||||
newConfig.style = {
|
||||
...newConfig.style,
|
||||
background_color: undefined,
|
||||
background_opacity: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value: newConfig });
|
||||
}
|
||||
}
|
||||
|
@@ -51,7 +51,19 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<div
|
||||
<hui-image
|
||||
.hass=${this.hass}
|
||||
.entity=${this._config.entity}
|
||||
.image=${stateObj ? computeImageUrl(stateObj) : this._config.image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.cameraImage=${this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.filter=${this._config.filter}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.title=${computeTooltip(this.hass, this._config)}
|
||||
.aspectRatio=${this._config.aspect_ratio}
|
||||
.darkModeImage=${this._config.dark_mode_image}
|
||||
.darkModeFilter=${this._config.dark_mode_filter}
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: hasAction(this._config!.hold_action),
|
||||
@@ -60,25 +72,7 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
|
||||
tabindex=${ifDefined(
|
||||
hasAction(this._config.tap_action) ? "0" : undefined
|
||||
)}
|
||||
role=${ifDefined(
|
||||
hasAction(this._config.tap_action) ? "button" : undefined
|
||||
)}
|
||||
>
|
||||
<hui-image
|
||||
.hass=${this.hass}
|
||||
.entity=${this._config.entity}
|
||||
.image=${stateObj ? computeImageUrl(stateObj) : this._config.image}
|
||||
.stateImage=${this._config.state_image}
|
||||
.cameraImage=${this._config.camera_image}
|
||||
.cameraView=${this._config.camera_view}
|
||||
.filter=${this._config.filter}
|
||||
.stateFilter=${this._config.state_filter}
|
||||
.title=${computeTooltip(this.hass, this._config)}
|
||||
.aspectRatio=${this._config.aspect_ratio}
|
||||
.darkModeImage=${this._config.dark_mode_image}
|
||||
.darkModeFilter=${this._config.dark_mode_filter}
|
||||
></hui-image>
|
||||
</div>
|
||||
></hui-image>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -90,12 +84,9 @@ export class HuiImageElement extends LitElement implements LovelaceElement {
|
||||
}
|
||||
hui-image {
|
||||
-webkit-user-select: none !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
div:focus {
|
||||
hui-image:focus {
|
||||
outline: none;
|
||||
}
|
||||
div:focus hui-image {
|
||||
background: var(--divider-color);
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiCodeBraces,
|
||||
mdiCommentProcessingOutline,
|
||||
mdiDevices,
|
||||
mdiDotsVertical,
|
||||
mdiFileMultiple,
|
||||
mdiFormatListBulletedTriangle,
|
||||
@@ -10,7 +12,9 @@ import {
|
||||
mdiPencil,
|
||||
mdiPlus,
|
||||
mdiRefresh,
|
||||
mdiRobot,
|
||||
mdiShape,
|
||||
mdiSofa,
|
||||
mdiViewDashboard,
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
@@ -52,6 +56,7 @@ import {
|
||||
updateDashboard,
|
||||
} from "../../data/lovelace/dashboard";
|
||||
import { getPanelTitle } from "../../data/panel";
|
||||
import { createPerson } from "../../data/person";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@@ -66,7 +71,10 @@ import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, PanelInfo } from "../../types";
|
||||
import { documentationUrl } from "../../util/documentation-url";
|
||||
import { showNewAutomationDialog } from "../config/automation/show-dialog-new-automation";
|
||||
import { showAddIntegrationDialog } from "../config/integrations/show-add-integration-dialog";
|
||||
import { showDashboardDetailDialog } from "../config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail";
|
||||
import { showPersonDetailDialog } from "../config/person/show-dialog-person-detail";
|
||||
import { swapView } from "./editor/config-util";
|
||||
import { showDashboardStrategyEditorDialog } from "./editor/dashboard-strategy-editor/dialogs/show-dialog-dashboard-strategy-editor";
|
||||
import { showSaveDialog } from "./editor/show-save-config-dialog";
|
||||
@@ -78,6 +86,28 @@ import "./views/hui-view";
|
||||
import type { HUIView } from "./views/hui-view";
|
||||
import "./views/hui-view-background";
|
||||
import "./views/hui-view-container";
|
||||
import { showAreaRegistryDetailDialog } from "../config/areas/show-dialog-area-registry-detail";
|
||||
import { createAreaRegistryEntry } from "../../data/area_registry";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
interface ActionItem {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
overflowAction?: any;
|
||||
buttonAction?: any;
|
||||
visible: boolean | undefined;
|
||||
overflow: boolean;
|
||||
overflow_can_promote?: boolean;
|
||||
suffix?: string;
|
||||
subItems?: SubActionItem[];
|
||||
}
|
||||
|
||||
interface SubActionItem {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
action?: any;
|
||||
visible: boolean | undefined;
|
||||
}
|
||||
|
||||
@customElement("hui-root")
|
||||
class HUIRoot extends LitElement {
|
||||
@@ -145,16 +175,7 @@ class HUIRoot extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
const items: {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
overflowAction?: any;
|
||||
buttonAction?: any;
|
||||
visible: boolean | undefined;
|
||||
overflow: boolean;
|
||||
overflow_can_promote?: boolean;
|
||||
suffix?: string;
|
||||
}[] = [
|
||||
const items: ActionItem[] = [
|
||||
{
|
||||
icon: mdiFormatListBulletedTriangle,
|
||||
key: "ui.panel.lovelace.unused_entities.title",
|
||||
@@ -183,13 +204,45 @@ class HUIRoot extends LitElement {
|
||||
visible: this._editMode && this.hass.userData?.showAdvanced,
|
||||
overflow: true,
|
||||
},
|
||||
{
|
||||
icon: mdiPlus,
|
||||
key: "ui.panel.lovelace.menu.add",
|
||||
visible: !this._editMode && this.hass.user?.is_admin,
|
||||
overflow: false,
|
||||
subItems: [
|
||||
{
|
||||
icon: mdiDevices,
|
||||
key: "ui.panel.lovelace.menu.add_device",
|
||||
visible: true,
|
||||
action: this._handleAddDevice,
|
||||
},
|
||||
{
|
||||
icon: mdiRobot,
|
||||
key: "ui.panel.lovelace.menu.create_automation",
|
||||
visible: true,
|
||||
action: this._handleACreateAutomation,
|
||||
},
|
||||
{
|
||||
icon: mdiSofa,
|
||||
key: "ui.panel.lovelace.menu.add_area",
|
||||
visible: true,
|
||||
action: this._handleAddArea,
|
||||
},
|
||||
{
|
||||
icon: mdiAccount,
|
||||
key: "ui.panel.lovelace.menu.invite_person",
|
||||
visible: true,
|
||||
action: this._handleInvitePerson,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: mdiMagnify,
|
||||
key: "ui.panel.lovelace.menu.search_entities",
|
||||
buttonAction: this._showQuickBar,
|
||||
overflowAction: this._handleShowQuickBar,
|
||||
visible: !this._editMode,
|
||||
overflow: this.narrow,
|
||||
overflow: false,
|
||||
suffix: this.hass.enableShortcuts ? "(E)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -199,7 +252,7 @@ class HUIRoot extends LitElement {
|
||||
overflowAction: this._handleShowVoiceCommandDialog,
|
||||
visible:
|
||||
!this._editMode && this._conversation(this.hass.config.components),
|
||||
overflow: this.narrow,
|
||||
overflow: false,
|
||||
suffix: this.hass.enableShortcuts ? "(A)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -247,20 +300,50 @@ class HUIRoot extends LitElement {
|
||||
(i) => i.visible && (!i.overflow || overflowCanPromote)
|
||||
);
|
||||
|
||||
buttonItems.forEach((i) => {
|
||||
result.push(
|
||||
html`<ha-tooltip
|
||||
slot="actionItems"
|
||||
placement="bottom"
|
||||
.content=${[this.hass!.localize(i.key), i.suffix].join(" ")}
|
||||
>
|
||||
<ha-icon-button
|
||||
.path=${i.icon}
|
||||
@click=${i.buttonAction}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>`
|
||||
);
|
||||
buttonItems.forEach((item) => {
|
||||
const label = [this.hass!.localize(item.key), item.suffix].join(" ");
|
||||
const button = item.subItems
|
||||
? html`
|
||||
<ha-button-menu
|
||||
slot="actionItems"
|
||||
corner="BOTTOM_END"
|
||||
menu-corner="END"
|
||||
>
|
||||
<ha-icon-button
|
||||
.label=${label}
|
||||
.path=${item.icon}
|
||||
slot="trigger"
|
||||
></ha-icon-button>
|
||||
${item.subItems
|
||||
.filter((subItem) => subItem.visible)
|
||||
.map(
|
||||
(subItem) => html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.key=${subItem.key}
|
||||
@request-selected=${subItem.action}
|
||||
>
|
||||
${this.hass!.localize(subItem.key)}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${subItem.icon}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
`
|
||||
: html`
|
||||
<ha-tooltip slot="actionItems" placement="bottom" .content=${label}>
|
||||
<ha-icon-button
|
||||
.path=${item.icon}
|
||||
@click=${item.buttonAction}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
result.push(button);
|
||||
});
|
||||
|
||||
if (overflowItems.length && !overflowCanPromote) {
|
||||
const listItems: TemplateResult[] = [];
|
||||
overflowItems.forEach((i) => {
|
||||
@@ -373,10 +456,15 @@ class HUIRoot extends LitElement {
|
||||
})}
|
||||
</sl-tab-group>`;
|
||||
|
||||
const isSubview = curViewConfig?.subview;
|
||||
const hasTabViews = views.filter((view) => !view.subview).length > 1;
|
||||
const showTabBar = this._editMode || (!isSubview && hasTabViews);
|
||||
|
||||
return html`
|
||||
<div
|
||||
class=${classMap({
|
||||
"edit-mode": this._editMode,
|
||||
narrow: this.narrow,
|
||||
})}
|
||||
>
|
||||
<div class="header">
|
||||
@@ -399,7 +487,7 @@ class HUIRoot extends LitElement {
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`
|
||||
: html`
|
||||
${curViewConfig?.subview
|
||||
${isSubview
|
||||
? html`
|
||||
<ha-icon-button-arrow-prev
|
||||
slot="navigationIcon"
|
||||
@@ -413,34 +501,37 @@ class HUIRoot extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
`}
|
||||
${curViewConfig?.subview
|
||||
${isSubview
|
||||
? html`<div class="main-title">${curViewConfig.title}</div>`
|
||||
: views.filter((view) => !view.subview).length > 1
|
||||
: hasTabViews && !showTabBar
|
||||
? tabs
|
||||
: html`
|
||||
<div class="main-title">
|
||||
${views[0]?.title ?? dashboardTitle}
|
||||
${curViewConfig?.title ?? dashboardTitle}
|
||||
</div>
|
||||
`}
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`}
|
||||
</div>
|
||||
${this._editMode
|
||||
${showTabBar
|
||||
? html`<div class="edit-tab-bar">
|
||||
${tabs}
|
||||
<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>
|
||||
${this._editMode
|
||||
? html`<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
<hui-view-container
|
||||
class=${showTabBar ? "has-tab-bar" : ""}
|
||||
.hass=${this.hass}
|
||||
.theme=${curViewConfig?.theme}
|
||||
id="view"
|
||||
@@ -696,6 +787,79 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleAddDevice(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAddIntegrationDialog(this);
|
||||
}
|
||||
|
||||
private async _handleACreateAutomation(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showNewAutomationDialog(this, { mode: "automation" });
|
||||
}
|
||||
|
||||
private async _handleAddArea(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAreaRegistryDetailDialog(this, {
|
||||
createEntry: async (values) => {
|
||||
const area = await createAreaRegistryEntry(this.hass, values);
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_area_success"
|
||||
),
|
||||
action: {
|
||||
action: () => {
|
||||
navigate(`/config/areas/area/${area.area_id}`);
|
||||
},
|
||||
text: this.hass.localize("ui.panel.lovelace.menu.add_area_action"),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async _handleInvitePerson(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showPersonDetailDialog(this, {
|
||||
users: [],
|
||||
createEntry: async (values) => {
|
||||
await createPerson(this.hass!, values);
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_person_success"
|
||||
),
|
||||
action: {
|
||||
action: () => {
|
||||
navigate(`/config/person`);
|
||||
},
|
||||
text: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_person_action"
|
||||
),
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
@@ -1050,6 +1214,14 @@ class HUIRoot extends LitElement {
|
||||
margin: var(--margin-title);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
flex-grow: 1;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
min-width: 0;
|
||||
}
|
||||
.narrow .main-title {
|
||||
margin: 0;
|
||||
margin-inline-start: 8px;
|
||||
}
|
||||
.action-items {
|
||||
white-space: nowrap;
|
||||
@@ -1114,9 +1286,6 @@ class HUIRoot extends LitElement {
|
||||
--ha-tab-active-text-color: var(--app-header-edit-text-color, #fff);
|
||||
--ha-tab-indicator-color: var(--app-header-edit-text-color, #fff);
|
||||
}
|
||||
.edit-mode sl-tab {
|
||||
height: 54px;
|
||||
}
|
||||
sl-tab {
|
||||
height: calc(var(--header-height, 56px) - 2px);
|
||||
}
|
||||
@@ -1188,9 +1357,10 @@ class HUIRoot extends LitElement {
|
||||
/**
|
||||
* In edit mode we have the tab bar on a new line *
|
||||
*/
|
||||
.edit-mode hui-view-container {
|
||||
hui-view-container.has-tab-bar {
|
||||
padding-top: calc(
|
||||
var(--header-height) + 48px + var(--safe-area-inset-top)
|
||||
var(--header-height) + calc(var(--header-height, 56px) - 2px) +
|
||||
var(--safe-area-inset-top)
|
||||
);
|
||||
}
|
||||
.hide-tab {
|
||||
|
@@ -20,6 +20,7 @@ import "../components/hui-card-edit-mode";
|
||||
import { moveCard } from "../editor/config-util";
|
||||
import type { LovelaceCardPath } from "../editor/lovelace-path";
|
||||
import type { Lovelace } from "../types";
|
||||
import { hex2rgb } from "../../../common/color/convert-color";
|
||||
|
||||
const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
|
||||
delay: 100,
|
||||
@@ -86,6 +87,12 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
? IMPORT_MODE_CARD_SORTABLE_OPTIONS
|
||||
: CARD_SORTABLE_OPTIONS;
|
||||
|
||||
const backgroundOpacity =
|
||||
(this._config.style?.background_opacity || 100) / 100;
|
||||
const background = this._config.style?.background_color
|
||||
? `rgba(${hex2rgb(this._config.style.background_color)}, ${backgroundOpacity})`
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
@@ -103,7 +110,11 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
class="container ${classMap({
|
||||
"edit-mode": editMode,
|
||||
"import-only": this.importOnly,
|
||||
"has-background": Boolean(background),
|
||||
})}"
|
||||
style=${styleMap({
|
||||
background: background,
|
||||
})}
|
||||
>
|
||||
${repeat(
|
||||
cardsConfig,
|
||||
@@ -250,6 +261,10 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
border: none;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.container.has-background {
|
||||
padding: 8px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
|
@@ -413,6 +413,7 @@
|
||||
"add": "Add",
|
||||
"create": "Create",
|
||||
"edit": "Edit",
|
||||
"edit_item": "Edit {name}",
|
||||
"submit": "Submit",
|
||||
"rename": "Rename",
|
||||
"search": "[%key:ui::components::data-table::search%]",
|
||||
@@ -439,7 +440,8 @@
|
||||
"replace": "Replace",
|
||||
"append": "Append",
|
||||
"supports_markdown": "Supports {markdown_help_link}",
|
||||
"markdown": "Markdown"
|
||||
"markdown": "Markdown",
|
||||
"none": "None"
|
||||
},
|
||||
"components": {
|
||||
"selectors": {
|
||||
@@ -5337,8 +5339,6 @@
|
||||
"introduction": "Zones allow you to specify certain regions on Earth. When a person is within a zone, the state will take the name from the zone. Zones can also be used as a trigger or condition inside automation setups.",
|
||||
"no_zones_created_yet": "Looks like you have not created any zones yet.",
|
||||
"create_zone": "Create zone",
|
||||
"edit_zone": "Edit zone",
|
||||
"edit_home": "Edit home",
|
||||
"confirm_delete": "Are you sure you want to delete this zone?",
|
||||
"can_not_edit": "Unable to edit zone",
|
||||
"configured_in_yaml": "Zones configured via configuration.yaml cannot be edited via the UI.",
|
||||
@@ -6968,7 +6968,16 @@
|
||||
"assist_tooltip": "Assist",
|
||||
"reload_resources": "Reload resources",
|
||||
"exit_edit_mode": "Done",
|
||||
"close": "Close"
|
||||
"close": "Close",
|
||||
"add": "Add to Home Assistant",
|
||||
"add_device": "Add device",
|
||||
"create_automation": "Create automation",
|
||||
"add_area": "Add area",
|
||||
"add_area_success": "Area added",
|
||||
"add_area_action": "View area",
|
||||
"add_person_success": "Person added",
|
||||
"add_person_action": "View persons",
|
||||
"invite_person": "Invite person"
|
||||
},
|
||||
"reload_resources": {
|
||||
"refresh_header": "Do you want to refresh?",
|
||||
@@ -7249,7 +7258,13 @@
|
||||
"edit_yaml": "[%key:ui::panel::lovelace::editor::edit_view::edit_yaml%]",
|
||||
"settings": {
|
||||
"column_span": "Width",
|
||||
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)"
|
||||
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)",
|
||||
"styling": "Styling",
|
||||
"background_type": "Background type",
|
||||
"background_type_none_option": "None",
|
||||
"background_type_color_option": "Color",
|
||||
"background_color": "Background color",
|
||||
"background_opacity": "Background opacity"
|
||||
},
|
||||
"visibility": {
|
||||
"explanation": "The section will be shown when ALL conditions below are fulfilled. If no conditions are set, the section will always be shown."
|
||||
@@ -7905,6 +7920,9 @@
|
||||
"lock-open-door": {
|
||||
"label": "Lock open door"
|
||||
},
|
||||
"media-player-playback": {
|
||||
"label": "Media player playback controls"
|
||||
},
|
||||
"media-player-volume-slider": {
|
||||
"label": "Media player volume slider"
|
||||
},
|
||||
|
160
yarn.lock
160
yarn.lock
@@ -4994,76 +4994,67 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.39.1"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.40.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/type-utils": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^7.0.0"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.39.1
|
||||
"@typescript-eslint/parser": ^8.40.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/446050aa43d54c0107c7c927ae1f68a4384c2bba514d5c22edabbe355426cb37bd5bb5a3faf240a6be8ef06f68de6099c2a53d9cbb1849ed35a152fb156171e2
|
||||
checksum: 10/9df4d4ac58734a34964b791622dcb94ffc6c49c1d0f4fd0480b3fc0e026527df7167ff78a4f8bbd29089d605756c28c1a90b2f0653df34b40ac8b969bc6c92e9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/parser@npm:8.39.1"
|
||||
"@typescript-eslint/parser@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/ff45ce76353ed564e0f9db47b02b4b20895c96182b3693c610ef3dbceda373c476037a99f90d9f28633c192f301e5d554c89e1ba72da216763f960648ddf1f34
|
||||
checksum: 10/1e60f70e9d02f930553db7f4684c27c376fadf345db155414a22d1a32cd21def7d36496bd63c1acbf3afbec9fb8794947e880f88c1143b83e1d3c45146cec41a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/project-service@npm:8.39.1"
|
||||
"@typescript-eslint/project-service@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.39.1"
|
||||
"@typescript-eslint/types": "npm:^8.39.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.40.0"
|
||||
"@typescript-eslint/types": "npm:^8.40.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/1970633d1a338190f0125e186beaa39b3ef912f287e4815934faf64b72f140e87fdf7d861962683635a450d270dd76faf0c865d72bfd57b471a36739f943676b
|
||||
checksum: 10/86491aa65c1dd78c9784dddd8467601aef8be652c5fb3a901e8b1995cf07c1dbe11d0ab4610d770e3f4063c0c254a6c6aa5fb7cf724bf12fa4ee56f47f3a2955
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.39.1"
|
||||
"@typescript-eslint/scope-manager@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
checksum: 10/8874f7479043b3fc878f2c04b2c565051deceb7e425a8e4e79a7f40f1ee696bb979bd91fff619e016fe6793f537b30609c0ee8a5c40911c4829fa264863f7a70
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
checksum: 10/0c5aa10208bfbb506bf3925a420c3de667298064bde400f03ee52c19cd0785dd05c2c820e05724d005737e2920d925aff0318ec3308156f9b81c84736a1fe46b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.39.1"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/38c1e1982504e606e525ad0ce47fdb4c7acc686a28a94c2b30fe988c439977e991ce69cb88a1724a41a8096fc2d18d7ced7fe8725e42879d841515ff36a37ecf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:^8.39.1":
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.40.0, @typescript-eslint/tsconfig-utils@npm:^8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.40.0"
|
||||
peerDependencies:
|
||||
@@ -5072,44 +5063,37 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.39.1"
|
||||
"@typescript-eslint/type-utils@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/1195d65970f79f820558810f7e1edf0ea360bbeee55841fdbb71b5b40c09f1a65741b67a70b85c2834ae1f9a027b82da4234d01f42ab4e85dceef3eea84bfdaa
|
||||
checksum: 10/296c718330b2ac4408840258c30c01072de01ffe1c009be00c5049be1b19a71cbb2e258363ae349150760bcd2d34799df305b4cfc4d7f3b2fa9760ac8ffb3f75
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/types@npm:8.39.1"
|
||||
checksum: 10/8013f4f48a98da0de270d5fef1ff28b35407de82fce5acf3efa212fce60bc92a81bbb15b4b358d9facf4f161e49feec856fbf1a6d96f5027d013b542f2fe1bcc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:^8.39.1":
|
||||
"@typescript-eslint/types@npm:8.40.0, @typescript-eslint/types@npm:^8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/types@npm:8.40.0"
|
||||
checksum: 10/f3931d0920a42b3bc69e9cdeb67a0c710597271cdd9d7c736302bdc52d21df1c962082df7cd712eeabd2c47658415d0a4b7d72f819cb38f82f4e234b48dbaa57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.39.1"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.39.1"
|
||||
"@typescript-eslint/project-service": "npm:8.40.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.40.0"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
@@ -5118,32 +5102,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/07ed9d7ab4d146ee3ce6cf82ffebf947e045a9289b01522e11b3985b64f590c00cac0ca10366df828ca213bf08216a67c7b2b76e7c8be650df2511a7e6385425
|
||||
checksum: 10/2e61ecfecb933f644799a7c11e4c7a730df57290c8d0482082cff7739b2401b0cf3b1ebef7b08a54a90285978957a49850d1a53061e8770164da651172ebee32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/utils@npm:8.39.1"
|
||||
"@typescript-eslint/utils@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.40.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.7.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/scope-manager": "npm:8.40.0"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/39bb105f26aa1ba234ad7d284c277cbd66df9d51e245094892db140aac80d3656d0480f133b2db54e87af3ef9c371a12973120c9cfbff71e8e85865f9e1d0077
|
||||
checksum: 10/b4cd1e6a4f55cc6475189de12e6bd418080a227e794745a2af304ab21655b031c28dae6387d4e9b54dd2f420696cec4f77cca9c66db405ed2281e0e09c95ba1c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.39.1"
|
||||
"@typescript-eslint/visitor-keys@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.39.1"
|
||||
"@typescript-eslint/types": "npm:8.40.0"
|
||||
eslint-visitor-keys: "npm:^4.2.1"
|
||||
checksum: 10/6d4e4d0b19ebb3f21b692bbb0dcf9961876ca28cdf502296888a78eb4cd802a2ec8d3d5721d19970411edfd1c06f3e272e4057014c859ee1f0546804d07945e3
|
||||
checksum: 10/191f47998001a5e9cdde7491b0215d9c6c45c637aedd7d32cafd35ce2a4a0f4b8582edab015e09238f48e025a788b99efd8e70e4e3200e32143f91c95112abcd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -8157,16 +8141,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-unused-imports@npm:4.1.4":
|
||||
version: 4.1.4
|
||||
resolution: "eslint-plugin-unused-imports@npm:4.1.4"
|
||||
"eslint-plugin-unused-imports@npm:4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "eslint-plugin-unused-imports@npm:4.2.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/eslint-plugin": ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
|
||||
eslint: ^9.0.0 || ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
"@typescript-eslint/eslint-plugin":
|
||||
optional: true
|
||||
checksum: 10/8e987028ad925ce1e04c01dcae70adbf44c2878a8b15c4327b33a2861e471d7fe00f6fe213fbd2b936f3fcefc8ccabb0d778aa1d6e0e0387a3dc7fe150cd4ed4
|
||||
checksum: 10/99285bd61a46ad5eaacd54525c04564feed3529dc2ae7800c736b7f4f011daa370133adb481677ad840f020681c0f409f3edfe3bc8f9f234c42bf4674bc4b576
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9517,7 +9501,7 @@ __metadata:
|
||||
eslint-plugin-import: "npm:2.32.0"
|
||||
eslint-plugin-lit: "npm:2.1.1"
|
||||
eslint-plugin-lit-a11y: "npm:5.1.1"
|
||||
eslint-plugin-unused-imports: "npm:4.1.4"
|
||||
eslint-plugin-unused-imports: "npm:4.2.0"
|
||||
eslint-plugin-wc: "npm:3.0.1"
|
||||
fancy-log: "npm:2.0.0"
|
||||
fs-extra: "npm:11.3.1"
|
||||
@@ -9571,7 +9555,7 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:5.9.2"
|
||||
typescript-eslint: "npm:8.39.1"
|
||||
typescript-eslint: "npm:8.40.0"
|
||||
ua-parser-js: "npm:2.0.4"
|
||||
vite-tsconfig-paths: "npm:5.1.4"
|
||||
vitest: "npm:3.2.4"
|
||||
@@ -14619,18 +14603,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.39.1":
|
||||
version: 8.39.1
|
||||
resolution: "typescript-eslint@npm:8.39.1"
|
||||
"typescript-eslint@npm:8.40.0":
|
||||
version: 8.40.0
|
||||
resolution: "typescript-eslint@npm:8.40.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.39.1"
|
||||
"@typescript-eslint/parser": "npm:8.39.1"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.39.1"
|
||||
"@typescript-eslint/utils": "npm:8.39.1"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.40.0"
|
||||
"@typescript-eslint/parser": "npm:8.40.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.40.0"
|
||||
"@typescript-eslint/utils": "npm:8.40.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/1c29c18f2e93b8b74d019590196b158006d7c65be87a56a4c953e52a9c4c40280a42f8ff1464fea870b3a1a4d54925b5cb7d54b4dc86b23cdf65a9b7787585b5
|
||||
checksum: 10/b96dc4e70bd551e5399b928e946957cce622cba89f0ff87521f9e93f223acbe406930a1ebee845b158f586959cb7d85f15ea2250b97341aa87f50a3c987d068a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Reference in New Issue
Block a user