mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Light more info enhancement (#16673)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
7b350e31dd
commit
0771a780d9
39
.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch
Normal file
39
.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch
Normal file
@ -0,0 +1,39 @@
|
||||
diff --git a/modular/sortable.complete.esm.js b/modular/sortable.complete.esm.js
|
||||
index 02e9f2d6bebeb430fe6e7c1cc3f9c3c9df051f14..bb8268b0844a1faa4108cc92c0be2a3dbaf23f83 100644
|
||||
--- a/modular/sortable.complete.esm.js
|
||||
+++ b/modular/sortable.complete.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
||||
diff --git a/modular/sortable.core.esm.js b/modular/sortable.core.esm.js
|
||||
index b04c8b4634f7c6b4ef1aadbb48afe6564306dea9..39a107163c8c336ebd669b5ea8a936af87e1c1e7 100644
|
||||
--- a/modular/sortable.core.esm.js
|
||||
+++ b/modular/sortable.core.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
||||
diff --git a/modular/sortable.esm.js b/modular/sortable.esm.js
|
||||
index 6ec7ed1bb557e21c2578200161e989c65d23150b..0a05475a22904472fac6c13f524c674da76584b0 100644
|
||||
--- a/modular/sortable.esm.js
|
||||
+++ b/modular/sortable.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
@ -248,7 +248,8 @@
|
||||
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
||||
"resolutions": {
|
||||
"@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
||||
"@material/mwc-button@^0.25.3": "^0.27.0"
|
||||
"@material/mwc-button@^0.25.3": "^0.27.0",
|
||||
"sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5",
|
||||
|
@ -24,6 +24,11 @@ export class HaOutlinedIconButton extends IconButton {
|
||||
--md-sys-color-on-surface-variant: var(--secondary-text-color);
|
||||
--md-sys-color-on-surface-rgb: var(--rgb-secondary-text-color);
|
||||
}
|
||||
:host([no-ripple]) .outlined {
|
||||
--md-ripple-focus-opacity: 0;
|
||||
--md-ripple-hover-opacity: 0;
|
||||
--md-ripple-pressed-opacity: 0;
|
||||
}
|
||||
button {
|
||||
/* Fix md-outlined-icon-button padding for iOS */
|
||||
padding: 0;
|
||||
|
@ -76,7 +76,7 @@ export interface SensorEntityOptions {
|
||||
}
|
||||
|
||||
export interface LightEntityOptions {
|
||||
favorites_colors?: LightColor[];
|
||||
favorite_colors?: LightColor[];
|
||||
}
|
||||
|
||||
export interface NumberEntityOptions {
|
||||
|
@ -107,7 +107,7 @@ export type LightColor =
|
||||
rgbww_color: [number, number, number, number, number];
|
||||
};
|
||||
|
||||
const FAVORITE_COLOR_COUNT = 6;
|
||||
const FAVORITE_COLOR_COUNT = 8;
|
||||
|
||||
export const computeDefaultFavoriteColors = (
|
||||
stateObj: LightEntity
|
||||
@ -119,8 +119,6 @@ export const computeDefaultFavoriteColors = (
|
||||
LightColorMode.COLOR_TEMP
|
||||
);
|
||||
|
||||
const supportsWhite = lightSupportsColorMode(stateObj, LightColorMode.WHITE);
|
||||
|
||||
const supportsColor = lightSupportsColor(stateObj);
|
||||
|
||||
const colorPerMode =
|
||||
@ -149,9 +147,5 @@ export const computeDefaultFavoriteColors = (
|
||||
}
|
||||
}
|
||||
|
||||
// Remove last color by white mode if supported
|
||||
if (supportsWhite) {
|
||||
colors.pop();
|
||||
}
|
||||
return colors;
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ class DialogLightColorFavorite extends LitElement {
|
||||
public closeDialog(): void {
|
||||
this._dialogParams = undefined;
|
||||
this._entry = undefined;
|
||||
this._color = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@ -59,10 +60,13 @@ class DialogLightColorFavorite extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const title = this.hass.localize("ui.dialogs.light-color-favorite.title");
|
||||
|
||||
return html`
|
||||
<ha-dialog open @closed=${this._cancel} .heading=${title} flexContent>
|
||||
<ha-dialog
|
||||
open
|
||||
@closed=${this._cancel}
|
||||
.heading=${this._dialogParams?.title ?? ""}
|
||||
flexContent
|
||||
>
|
||||
<ha-dialog-header slot="heading">
|
||||
<ha-icon-button
|
||||
slot="navigationIcon"
|
||||
@ -70,7 +74,7 @@ class DialogLightColorFavorite extends LitElement {
|
||||
.label=${this.hass.localize("ui.common.close")}
|
||||
.path=${mdiClose}
|
||||
></ha-icon-button>
|
||||
<span slot="title">${title}</span>
|
||||
<span slot="title">${this._dialogParams?.title}</span>
|
||||
</ha-dialog-header>
|
||||
<light-color-picker
|
||||
.hass=${this.hass}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { mdiPencil } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
@ -28,31 +27,32 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
||||
|
||||
@property() color!: LightColor;
|
||||
|
||||
@property() editMode?: boolean;
|
||||
|
||||
@query("ha-outlined-icon-button", true)
|
||||
private _button?: HaOutlinedIconButton;
|
||||
|
||||
private get _rgbColor(): [number, number, number] {
|
||||
if ("hs_color" in this.color) {
|
||||
return hs2rgb([this.color.hs_color[0], this.color.hs_color[1] / 100]);
|
||||
}
|
||||
if ("color_temp_kelvin" in this.color) {
|
||||
return temperature2rgb(this.color.color_temp_kelvin);
|
||||
}
|
||||
if ("rgb_color" in this.color) {
|
||||
return this.color.rgb_color;
|
||||
}
|
||||
if ("rgbw_color" in this.color) {
|
||||
return rgbw2rgb(this.color.rgbw_color);
|
||||
}
|
||||
if ("rgbww_color" in this.color) {
|
||||
return rgbww2rgb(
|
||||
this.color.rgbww_color,
|
||||
this.stateObj?.attributes.min_color_temp_kelvin,
|
||||
this.stateObj?.attributes.max_color_temp_kelvin
|
||||
);
|
||||
if (this.color) {
|
||||
if ("hs_color" in this.color) {
|
||||
return hs2rgb([this.color.hs_color[0], this.color.hs_color[1] / 100]);
|
||||
}
|
||||
if ("color_temp_kelvin" in this.color) {
|
||||
return temperature2rgb(this.color.color_temp_kelvin);
|
||||
}
|
||||
if ("rgb_color" in this.color) {
|
||||
return this.color.rgb_color;
|
||||
}
|
||||
if ("rgbw_color" in this.color) {
|
||||
return rgbw2rgb(this.color.rgbw_color);
|
||||
}
|
||||
if ("rgbww_color" in this.color) {
|
||||
return rgbww2rgb(
|
||||
this.color.rgbww_color,
|
||||
this.stateObj?.attributes.min_color_temp_kelvin,
|
||||
this.stateObj?.attributes.max_color_temp_kelvin
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [255, 255, 255];
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-outlined-icon-button
|
||||
no-ripple
|
||||
.disabled=${this.disabled}
|
||||
title=${ifDefined(this.label)}
|
||||
aria-label=${ifDefined(this.label)}
|
||||
@ -75,17 +76,16 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
||||
"--icon-color": hexIconColor,
|
||||
"--rgb-icon-color": rgbIconColor,
|
||||
})}
|
||||
>
|
||||
${this.editMode
|
||||
? html`<ha-svg-icon .path=${mdiPencil}></ha-svg-icon>`
|
||||
: nothing}
|
||||
</ha-outlined-icon-button>
|
||||
></ha-outlined-icon-button>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
ha-outlined-icon-button {
|
||||
--ha-icon-display: block;
|
||||
--md-sys-color-on-surface: var(
|
||||
@ -101,6 +101,9 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
||||
var(--rgb-secondary-text-color)
|
||||
);
|
||||
--md-sys-color-outline: var(--divider-color);
|
||||
--md-ripple-focus-color: 0;
|
||||
--md-ripple-hover-opacity: 0;
|
||||
--md-ripple-pressed-opacity: 0;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
:host([disabled]) {
|
||||
|
@ -0,0 +1,377 @@
|
||||
import { mdiCheck, mdiMinus, mdiPlus } from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import type { SortableEvent } from "sortablejs";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-control-slider";
|
||||
import { UNAVAILABLE } from "../../../../data/entity";
|
||||
import {
|
||||
ExtEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../../data/entity_registry";
|
||||
import {
|
||||
computeDefaultFavoriteColors,
|
||||
LightColor,
|
||||
LightEntity,
|
||||
} from "../../../../data/light";
|
||||
import { actionHandler } from "../../../../panels/lovelace/common/directives/action-handler-directive";
|
||||
import {
|
||||
loadSortable,
|
||||
SortableInstance,
|
||||
} from "../../../../resources/sortable.ondemand";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { showConfirmationDialog } from "../../../generic/show-dialog-box";
|
||||
import "./ha-favorite-color-button";
|
||||
import { showLightColorFavoriteDialog } from "./show-dialog-light-color-favorite";
|
||||
|
||||
@customElement("ha-more-info-light-favorite-colors")
|
||||
export class HaMoreInfoLightFavoriteColors extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj!: LightEntity;
|
||||
|
||||
@property({ attribute: false }) public entry?: ExtEntityRegistryEntry | null;
|
||||
|
||||
@property({ attribute: false }) public editMode?: boolean;
|
||||
|
||||
@state() private _favoriteColors: LightColor[] = [];
|
||||
|
||||
private _sortable?: SortableInstance;
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (changedProps.has("editMode")) {
|
||||
if (this.editMode) {
|
||||
this._createSortable();
|
||||
} else {
|
||||
this._destroySortable();
|
||||
}
|
||||
}
|
||||
if (changedProps.has("entry")) {
|
||||
if (this.entry) {
|
||||
if (this.entry.options?.light?.favorite_colors) {
|
||||
this._favoriteColors = this.entry.options.light.favorite_colors;
|
||||
} else if (this.stateObj) {
|
||||
this._favoriteColors = computeDefaultFavoriteColors(this.stateObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _createSortable() {
|
||||
const Sortable = await loadSortable();
|
||||
this._sortable = new Sortable(
|
||||
this.shadowRoot!.querySelector(".container")!,
|
||||
{
|
||||
animation: 150,
|
||||
fallbackClass: "sortable-fallback",
|
||||
draggable: ".color",
|
||||
onChoose: (evt: SortableEvent) => {
|
||||
(evt.item as any).placeholder =
|
||||
document.createComment("sort-placeholder");
|
||||
evt.item.after((evt.item as any).placeholder);
|
||||
},
|
||||
onEnd: (evt: SortableEvent) => {
|
||||
// put back in original location
|
||||
if ((evt.item as any).placeholder) {
|
||||
(evt.item as any).placeholder.replaceWith(evt.item);
|
||||
delete (evt.item as any).placeholder;
|
||||
}
|
||||
this._dragged(evt);
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _dragged(ev: SortableEvent): void {
|
||||
if (ev.oldIndex === ev.newIndex) return;
|
||||
this._move(ev.oldIndex!, ev.newIndex!);
|
||||
}
|
||||
|
||||
private _move(index: number, newIndex: number) {
|
||||
const favoriteColors = this._favoriteColors.concat();
|
||||
const action = favoriteColors.splice(index, 1)[0];
|
||||
favoriteColors.splice(newIndex, 0, action);
|
||||
this._favoriteColors = favoriteColors;
|
||||
this._save(favoriteColors);
|
||||
}
|
||||
|
||||
private _destroySortable() {
|
||||
this._sortable?.destroy();
|
||||
this._sortable = undefined;
|
||||
}
|
||||
|
||||
private _apply = (index: number) => {
|
||||
const favorite = this._favoriteColors[index];
|
||||
this.hass.callService("light", "turn_on", {
|
||||
entity_id: this.stateObj!.entity_id,
|
||||
...favorite,
|
||||
});
|
||||
};
|
||||
|
||||
private async _save(newFavoriteColors: LightColor[]) {
|
||||
const result = await updateEntityRegistryEntry(
|
||||
this.hass,
|
||||
this.entry!.entity_id,
|
||||
{
|
||||
options_domain: "light",
|
||||
options: {
|
||||
favorite_colors: newFavoriteColors,
|
||||
},
|
||||
}
|
||||
);
|
||||
fireEvent(this, "entity-entry-updated", result.entity_entry);
|
||||
}
|
||||
|
||||
private _add = async () => {
|
||||
const color = await showLightColorFavoriteDialog(this, {
|
||||
entry: this.entry!,
|
||||
title: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.favorite_color.add_title"
|
||||
),
|
||||
});
|
||||
if (color) {
|
||||
const newFavoriteColors = [...this._favoriteColors, color];
|
||||
this._save(newFavoriteColors);
|
||||
}
|
||||
};
|
||||
|
||||
private _edit = async (index) => {
|
||||
// Make sure the current favorite color is set
|
||||
await this._apply(index);
|
||||
const color = await showLightColorFavoriteDialog(this, {
|
||||
entry: this.entry!,
|
||||
title: this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.favorite_color.edit_title"
|
||||
),
|
||||
});
|
||||
|
||||
if (color) {
|
||||
const newFavoriteColors = [...this._favoriteColors];
|
||||
newFavoriteColors[index] = color;
|
||||
this._save(newFavoriteColors);
|
||||
} else {
|
||||
this._apply(index);
|
||||
}
|
||||
};
|
||||
|
||||
private _remove = async (index) => {
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
destructive: true,
|
||||
title: this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.remove_confirm_title`
|
||||
),
|
||||
text: this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.remove_confirm_text`
|
||||
),
|
||||
confirmText: this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.remove_confirm_action`
|
||||
),
|
||||
});
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
const newFavoriteColors = this._favoriteColors.filter(
|
||||
(_, i) => index !== i
|
||||
);
|
||||
this._save(newFavoriteColors);
|
||||
};
|
||||
|
||||
private _handleDeleteButton = (ev) => {
|
||||
ev.stopPropagation();
|
||||
const index = ev.target.index;
|
||||
this._remove(index);
|
||||
};
|
||||
|
||||
private _handleAddButton = (ev) => {
|
||||
ev.stopPropagation();
|
||||
this._add();
|
||||
};
|
||||
|
||||
private _handleColorAction = (ev) => {
|
||||
ev.stopPropagation();
|
||||
if (ev.detail.action === "hold" && this.hass.user?.is_admin) {
|
||||
fireEvent(this, "toggle-edit-mode", true);
|
||||
return;
|
||||
}
|
||||
|
||||
const index = ev.target.index;
|
||||
if (this.editMode) {
|
||||
this._edit(index);
|
||||
return;
|
||||
}
|
||||
this._apply(index);
|
||||
};
|
||||
|
||||
private _exitEditMode = (ev) => {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "toggle-edit-mode", false);
|
||||
};
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="container">
|
||||
${this._favoriteColors.map(
|
||||
(color, index) => html`
|
||||
<div class="color">
|
||||
<div
|
||||
class="color-bubble ${classMap({
|
||||
shake: !!this.editMode,
|
||||
})}"
|
||||
>
|
||||
<ha-favorite-color-button
|
||||
.label=${this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.${
|
||||
this.editMode ? "edit" : "set"
|
||||
}`,
|
||||
{ number: index }
|
||||
)}
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.color=${color}
|
||||
.index=${index}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: !this.editMode && this.hass.user?.is_admin,
|
||||
disabled: this.stateObj!.state === UNAVAILABLE,
|
||||
})}
|
||||
@action=${this._handleColorAction}
|
||||
>
|
||||
</ha-favorite-color-button>
|
||||
${this.editMode
|
||||
? html`
|
||||
<button
|
||||
@click=${this._handleDeleteButton}
|
||||
class="delete"
|
||||
.index=${index}
|
||||
aria-label=${this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.remove`,
|
||||
{ number: index }
|
||||
)}
|
||||
.title=${this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.remove`,
|
||||
{ number: index }
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiMinus}></ha-svg-icon>
|
||||
</button>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
${this.editMode
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
class="button"
|
||||
@click=${this._handleAddButton}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>
|
||||
<ha-outlined-icon-button
|
||||
@click=${this._exitEditMode}
|
||||
class="button"
|
||||
>
|
||||
<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 12px;
|
||||
flex-wrap: wrap;
|
||||
max-width: 250px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.color {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.color .color-bubble.shake {
|
||||
position: relative;
|
||||
display: block;
|
||||
animation: shake 0.45s linear infinite;
|
||||
}
|
||||
.color:nth-child(3n + 1) .color-bubble.shake {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
.color:nth-child(3n + 2) .color-bubble.shake {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.sortable-ghost {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.sortable-fallback {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: rotateZ(0deg) translateX(-1px) translateY(0) scale(1);
|
||||
}
|
||||
20% {
|
||||
transform: rotateZ(-3deg) translateX(0) translateY();
|
||||
}
|
||||
40% {
|
||||
transform: rotateZ(0deg) translateX(1px) translateY(0);
|
||||
}
|
||||
60% {
|
||||
transform: rotateZ(3deg) translateX(0) translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: rotateZ(0deg) translateX(-1px) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.delete {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
outline: none;
|
||||
background-color: var(--secondary-background-color);
|
||||
padding: 0;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
.delete {
|
||||
--mdc-icon-size: 12px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.delete * {
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-more-info-light-favorite-colors": HaMoreInfoLightFavoriteColors;
|
||||
}
|
||||
}
|
@ -16,7 +16,11 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<light-color-picker .hass=${this.hass} entityId=${this.params.entityId}>
|
||||
<light-color-picker
|
||||
.hass=${this.hass}
|
||||
.entityId=${this.params.entityId}
|
||||
.defaultMode=${this.params.defaultMode}
|
||||
>
|
||||
</light-color-picker>
|
||||
`;
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ class LightColorPicker extends LitElement {
|
||||
|
||||
@property() public entityId!: string;
|
||||
|
||||
@property() public defaultMode!: Mode;
|
||||
|
||||
@state() private _cwSliderValue?: number;
|
||||
|
||||
@state() private _wwSliderValue?: number;
|
||||
@ -274,11 +276,13 @@ class LightColorPicker extends LitElement {
|
||||
}
|
||||
|
||||
this._modes = modes;
|
||||
this._mode = this.stateObj!.attributes.color_mode
|
||||
? this.stateObj!.attributes.color_mode === LightColorMode.COLOR_TEMP
|
||||
? LightColorMode.COLOR_TEMP
|
||||
: "color"
|
||||
: this._modes[0];
|
||||
this._mode =
|
||||
this.defaultMode ??
|
||||
(this.stateObj!.attributes.color_mode
|
||||
? this.stateObj!.attributes.color_mode === LightColorMode.COLOR_TEMP
|
||||
? LightColorMode.COLOR_TEMP
|
||||
: "color"
|
||||
: this._modes[0]);
|
||||
}
|
||||
|
||||
this._updateSliderValues();
|
||||
|
@ -4,6 +4,7 @@ import { LightColor } from "../../../../data/light";
|
||||
|
||||
export interface LightColorFavoriteDialogParams {
|
||||
entry: ExtEntityRegistryEntry;
|
||||
title: string;
|
||||
submit?: (color?: LightColor) => void;
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
export interface LightColorPickerViewParams {
|
||||
entityId: string;
|
||||
defaultMode: "color" | "color_temp";
|
||||
}
|
||||
|
||||
export const loadLightColorPickerView = () =>
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import {
|
||||
computeAttributeNameDisplay,
|
||||
@ -29,15 +27,10 @@ import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-outlined-button";
|
||||
import "../../../components/ha-outlined-icon-button";
|
||||
import "../../../components/ha-select";
|
||||
import { ON, UNAVAILABLE } from "../../../data/entity";
|
||||
import {
|
||||
ExtEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import { ExtEntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import { forwardHaptic } from "../../../data/haptics";
|
||||
import {
|
||||
computeDefaultFavoriteColors,
|
||||
LightColor,
|
||||
LightColorMode,
|
||||
LightEntity,
|
||||
LightEntityFeature,
|
||||
@ -51,7 +44,7 @@ import "../components/ha-more-info-state-header";
|
||||
import "../components/ha-more-info-toggle";
|
||||
import "../components/lights/ha-favorite-color-button";
|
||||
import "../components/lights/ha-more-info-light-brightness";
|
||||
import { showLightColorFavoriteDialog } from "../components/lights/show-dialog-light-color-favorite";
|
||||
import "../components/lights/ha-more-info-light-favorite-colors";
|
||||
import { showLightColorPickerView } from "../components/lights/show-view-light-color-picker";
|
||||
|
||||
@customElement("more-info-light")
|
||||
@ -62,12 +55,12 @@ class MoreInfoLight extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public entry?: ExtEntityRegistryEntry | null;
|
||||
|
||||
@property({ attribute: false }) public editMode?: boolean;
|
||||
|
||||
@state() private _effect?: string;
|
||||
|
||||
@state() private _selectedBrightness?: number;
|
||||
|
||||
@state() private _focusedFavoriteIndex?: number;
|
||||
|
||||
private _brightnessChanged(ev) {
|
||||
const value = (ev.detail as any).value;
|
||||
if (isNaN(value)) return;
|
||||
@ -80,25 +73,9 @@ class MoreInfoLight extends LitElement {
|
||||
? Math.round((this.stateObj.attributes.brightness * 100) / 255)
|
||||
: undefined;
|
||||
this._effect = this.stateObj?.attributes.effect;
|
||||
|
||||
if (this.stateObj?.state !== ON) {
|
||||
this._focusedFavoriteIndex = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get _favoriteColors(): LightColor[] {
|
||||
if (this.entry) {
|
||||
if (this.entry.options?.light?.favorites_colors) {
|
||||
return this.entry.options.light.favorites_colors;
|
||||
}
|
||||
if (this.stateObj) {
|
||||
return computeDefaultFavoriteColors(this.stateObj);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || !this.stateObj) {
|
||||
return nothing;
|
||||
@ -155,74 +132,87 @@ class MoreInfoLight extends LitElement {
|
||||
`}
|
||||
${supportsColorTemp || supportsColor || supportsBrightness
|
||||
? html`
|
||||
<div class="buttons">
|
||||
${supportsBrightness
|
||||
? html`<ha-outlined-icon-button
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.toggle"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.toggle"
|
||||
)}
|
||||
@click=${this._toggle}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>`
|
||||
: nothing}
|
||||
${supportsColor || supportsColorTemp
|
||||
? html`<ha-outlined-icon-button
|
||||
class=${classMap({
|
||||
"color-rgb-mode": supportsColor,
|
||||
"color-temp-mode": !supportsColor,
|
||||
})}
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
@click=${this._showLightColorPickerView}
|
||||
>
|
||||
</ha-outlined-icon-button>`
|
||||
: nothing}
|
||||
${supportsWhite
|
||||
<div>
|
||||
<div class="buttons">
|
||||
${supportsBrightness
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.toggle"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.toggle"
|
||||
)}
|
||||
@click=${this._toggle}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPower}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
${supportsColor
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
class="color-mode"
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
.mode=${"color"}
|
||||
@click=${this._showLightColorPickerView}
|
||||
>
|
||||
</ha-outlined-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
${supportsColorTemp
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
class="color-temp-mode"
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.change_color"
|
||||
)}
|
||||
.mode=${"color_temp"}
|
||||
@click=${this._showLightColorPickerView}
|
||||
>
|
||||
</ha-outlined-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
${supportsWhite
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.set_white"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.set_white"
|
||||
)}
|
||||
@click=${this._setWhite}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiFileWordBox}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
${this.editMode ||
|
||||
(this.entry?.options?.light?.favorite_colors?.length ?? 0) > 0
|
||||
? html`
|
||||
<ha-outlined-icon-button
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.title=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.set_white"
|
||||
)}
|
||||
.ariaLabel=${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.light.set_white"
|
||||
)}
|
||||
@click=${this._setWhite}
|
||||
<ha-more-info-light-favorite-colors
|
||||
.hass=${this.hass}
|
||||
.stateObj=${this.stateObj}
|
||||
.entry=${this.entry}
|
||||
.editMode=${this.editMode}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiFileWordBox}></ha-svg-icon>
|
||||
</ha-outlined-icon-button>
|
||||
</ha-more-info-light-favorite-colors>
|
||||
`
|
||||
: nothing}
|
||||
${this._favoriteColors.map((color, index) => {
|
||||
const editMode = this._focusedFavoriteIndex === index;
|
||||
return html`
|
||||
<ha-favorite-color-button
|
||||
.label=${this.hass.localize(
|
||||
`ui.dialogs.more_info_control.light.favorite_color.${
|
||||
editMode ? "edit" : "set"
|
||||
}`,
|
||||
{ number: index }
|
||||
)}
|
||||
.disabled=${this.stateObj!.state === UNAVAILABLE}
|
||||
.color=${color}
|
||||
.index=${index}
|
||||
@click=${this._handleFavoriteButton}
|
||||
@blur=${this._removeFocus}
|
||||
.editMode=${editMode}
|
||||
>
|
||||
</ha-favorite-color-button>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
@ -285,10 +275,6 @@ class MoreInfoLight extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _removeFocus = () => {
|
||||
this._focusedFavoriteIndex = undefined;
|
||||
};
|
||||
|
||||
private _toggle = () => {
|
||||
const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on";
|
||||
forwardHaptic("light");
|
||||
@ -297,7 +283,7 @@ class MoreInfoLight extends LitElement {
|
||||
});
|
||||
};
|
||||
|
||||
private _showLightColorPickerView = () => {
|
||||
private _showLightColorPickerView = (ev) => {
|
||||
showLightColorPickerView(
|
||||
this,
|
||||
this.hass.localize(
|
||||
@ -305,48 +291,11 @@ class MoreInfoLight extends LitElement {
|
||||
),
|
||||
{
|
||||
entityId: this.stateObj!.entity_id,
|
||||
defaultMode: ev.target.mode,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
private _editFavoriteColor = async (index) => {
|
||||
// Make sure the current favorite color is set
|
||||
this._applyFavoriteColor(index);
|
||||
const color = await showLightColorFavoriteDialog(this, {
|
||||
entry: this.entry!,
|
||||
});
|
||||
|
||||
if (color) {
|
||||
const newFavoriteColors = [...this._favoriteColors];
|
||||
|
||||
newFavoriteColors[index] = color;
|
||||
|
||||
const result = await updateEntityRegistryEntry(
|
||||
this.hass,
|
||||
this.entry!.entity_id,
|
||||
{
|
||||
options_domain: "light",
|
||||
options: {
|
||||
favorites_colors: newFavoriteColors,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
fireEvent(this, "entity-entry-updated", result.entity_entry);
|
||||
} else {
|
||||
this._applyFavoriteColor(index);
|
||||
}
|
||||
this._focusedFavoriteIndex = index;
|
||||
};
|
||||
|
||||
private _applyFavoriteColor = (index: number) => {
|
||||
const favorite = this._favoriteColors[index];
|
||||
this.hass.callService("light", "turn_on", {
|
||||
entity_id: this.stateObj!.entity_id,
|
||||
...favorite,
|
||||
});
|
||||
};
|
||||
|
||||
private _setWhite = () => {
|
||||
this.hass.callService("light", "turn_on", {
|
||||
entity_id: this.stateObj!.entity_id,
|
||||
@ -354,19 +303,6 @@ class MoreInfoLight extends LitElement {
|
||||
});
|
||||
};
|
||||
|
||||
private _handleFavoriteButton = (ev) => {
|
||||
ev.stopPropagation();
|
||||
const index = ev.target.index;
|
||||
if (this._focusedFavoriteIndex === index) {
|
||||
this._editFavoriteColor(index);
|
||||
return;
|
||||
}
|
||||
if (this.hass.user?.is_admin) {
|
||||
this._focusedFavoriteIndex = index;
|
||||
}
|
||||
this._applyFavoriteColor(index);
|
||||
};
|
||||
|
||||
private _handleEffectButton(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
@ -391,12 +327,12 @@ class MoreInfoLight extends LitElement {
|
||||
flex-wrap: wrap;
|
||||
max-width: 250px;
|
||||
}
|
||||
.color-rgb-mode,
|
||||
.color-mode,
|
||||
.color-temp-mode {
|
||||
border-radius: 9999px;
|
||||
--md-sys-color-outline: var(--divider-color);
|
||||
}
|
||||
.color-rgb-mode {
|
||||
.color-mode {
|
||||
background-image: url("/static/images/color_wheel.png");
|
||||
background-size: cover;
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import {
|
||||
mdiDevices,
|
||||
mdiDotsVertical,
|
||||
mdiInformationOutline,
|
||||
mdiPencil,
|
||||
mdiPencilOff,
|
||||
mdiPencilOutline,
|
||||
} from "@mdi/js";
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
@ -67,6 +69,9 @@ declare global {
|
||||
interface HASSDomEvents {
|
||||
"show-child-view": ChildView;
|
||||
}
|
||||
interface HASSDomEvents {
|
||||
"toggle-edit-mode": boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("ha-more-info-dialog")
|
||||
@ -83,6 +88,8 @@ export class MoreInfoDialog extends LitElement {
|
||||
|
||||
@state() private _entry?: ExtEntityRegistryEntry | null;
|
||||
|
||||
@state() private _infoEditMode = false;
|
||||
|
||||
public showDialog(params: MoreInfoDialogParams) {
|
||||
this._entityId = params.entityId;
|
||||
if (!this._entityId) {
|
||||
@ -218,6 +225,15 @@ export class MoreInfoDialog extends LitElement {
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
private _toggleInfoEditMode(ev) {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) return;
|
||||
this._infoEditMode = !this._infoEditMode;
|
||||
}
|
||||
|
||||
private _handleToggleInfoEditModeEvent(ev) {
|
||||
this._infoEditMode = ev.detail;
|
||||
}
|
||||
|
||||
private _goToRelated(ev): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) return;
|
||||
this.setView("related");
|
||||
@ -342,6 +358,28 @@ export class MoreInfoDialog extends LitElement {
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
${this._entry && domain === "light"
|
||||
? html`
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@request-selected=${this._toggleInfoEditMode}
|
||||
>
|
||||
${this._infoEditMode
|
||||
? this.hass.localize(
|
||||
`ui.dialogs.more_info_control.exit_edit_mode`
|
||||
)
|
||||
: this.hass.localize(
|
||||
`ui.dialogs.more_info_control.${domain}.edit_mode`
|
||||
)}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${this._infoEditMode
|
||||
? mdiPencilOff
|
||||
: mdiPencil}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
: nothing}
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@request-selected=${this._goToRelated}
|
||||
@ -366,6 +404,7 @@ export class MoreInfoDialog extends LitElement {
|
||||
dialogInitialFocus
|
||||
@show-child-view=${this._showChildView}
|
||||
@entity-entry-updated=${this._entryUpdated}
|
||||
@toggle-edit-mode=${this._handleToggleInfoEditModeEvent}
|
||||
>
|
||||
${this._childView
|
||||
? html`
|
||||
@ -385,6 +424,7 @@ export class MoreInfoDialog extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.entityId=${this._entityId}
|
||||
.entry=${this._entry}
|
||||
.editMode=${this._infoEditMode}
|
||||
></ha-more-info-info>
|
||||
`
|
||||
: this._currView === "history"
|
||||
@ -428,6 +468,7 @@ export class MoreInfoDialog extends LitElement {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("_currView")) {
|
||||
this._childView = undefined;
|
||||
this._infoEditMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,11 @@ import "./more-info-content";
|
||||
export class MoreInfoInfo extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public entityId!: string;
|
||||
@property({ attribute: false }) public entityId!: string;
|
||||
|
||||
@property() public entry?: ExtEntityRegistryEntry | null;
|
||||
@property({ attribute: false }) public entry?: ExtEntityRegistryEntry | null;
|
||||
|
||||
@property({ attribute: false }) public editMode?: boolean;
|
||||
|
||||
protected render() {
|
||||
const entityId = this.entityId;
|
||||
@ -78,6 +80,7 @@ export class MoreInfoInfo extends LitElement {
|
||||
.stateObj=${stateObj}
|
||||
.hass=${this.hass}
|
||||
.entry=${this.entry}
|
||||
.editMode=${this.editMode}
|
||||
></more-info-content>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,6 +14,8 @@ class MoreInfoContent extends ReactiveElement {
|
||||
|
||||
@property({ attribute: false }) public entry?: ExtEntityRegistryEntry | null;
|
||||
|
||||
@property({ attribute: false }) public editMode?: boolean;
|
||||
|
||||
private _detachedChild?: ChildNode;
|
||||
|
||||
protected createRenderRoot() {
|
||||
@ -26,6 +28,7 @@ class MoreInfoContent extends ReactiveElement {
|
||||
const stateObj = this.stateObj;
|
||||
const entry = this.entry;
|
||||
const hass = this.hass;
|
||||
const editMode = this.editMode;
|
||||
|
||||
if (!stateObj || !hass) {
|
||||
if (this.lastChild) {
|
||||
@ -59,6 +62,7 @@ class MoreInfoContent extends ReactiveElement {
|
||||
hass,
|
||||
stateObj,
|
||||
entry,
|
||||
editMode,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -869,6 +869,7 @@
|
||||
"turn_on": "Turn on",
|
||||
"turn_off": "Turn off",
|
||||
"toggle": "Toggle",
|
||||
"exit_edit_mode": "Exit edit mode",
|
||||
"script": {
|
||||
"last_action": "Last action",
|
||||
"last_triggered": "Last triggered"
|
||||
@ -926,6 +927,7 @@
|
||||
"graph_unit": "People in zone"
|
||||
},
|
||||
"light": {
|
||||
"edit_mode": "Edit favorite colors",
|
||||
"toggle": "Toggle",
|
||||
"change_color": "Change color",
|
||||
"set_white": "Set white",
|
||||
@ -940,7 +942,14 @@
|
||||
},
|
||||
"favorite_color": {
|
||||
"set": "Set favorite color {number}",
|
||||
"edit": "Edit favorite color {number}"
|
||||
"edit": "Edit favorite color {number}",
|
||||
"remove": "Remove favorite color {number}",
|
||||
"remove_confirm_title": "Remove favorite color?",
|
||||
"remove_confirm_text": "This favorite color will be permanently removed.",
|
||||
"remove_confirm_action": "Remove",
|
||||
"add": "Add new favorite color",
|
||||
"edit_title": "Edit favorite color",
|
||||
"add_title": "Add favorite color"
|
||||
}
|
||||
},
|
||||
"fan": {
|
||||
@ -1336,9 +1345,6 @@
|
||||
"title": "Enter code",
|
||||
"input_label": "Code"
|
||||
},
|
||||
"light-color-favorite": {
|
||||
"title": "Edit favorite color"
|
||||
},
|
||||
"tts-try": {
|
||||
"header": "Try text-to-speech",
|
||||
"message": "Message",
|
||||
|
@ -14473,6 +14473,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sortablejs@patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch::locator=home-assistant-frontend%40workspace%3A.":
|
||||
version: 1.15.0
|
||||
resolution: "sortablejs@patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch::version=1.15.0&hash=29e891&locator=home-assistant-frontend%40workspace%3A."
|
||||
checksum: 9a5c899bc4ec1a99732a44511ef7188ae0aba59b98bce66b952590a33a12e0779cebe8664a5565815facfeb0a32072418a2447eb690a5d3c234981126462da7e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"source-list-map@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "source-list-map@npm:2.0.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user