Compare commits

..
43 changed files with 1306 additions and 1335 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@58bff37c8947f690ace498be413a9b78d6f30f93 # master
uses: home-assistant/actions/helpers/verify-version@a7c616ce81ccda50150bf1595786c71b1883fabb # master
- name: Setup Node and install
uses: ./.github/actions/setup
@@ -0,0 +1,87 @@
diff --git a/round-slider.cjs b/round-slider.cjs
index f5abedb900513f18ab914f94900d0cb15b87b73b..0a8fdc22d2362ef67d0d25e72a69119001f06096 100644
--- a/round-slider.cjs
+++ b/round-slider.cjs
@@ -78,6 +78,7 @@ var nt;null===(nt=window.HTMLSlotElement)||void 0===nt||nt.prototype.assignedEle
viewBox="${-t.left} ${-t.up} ${t.width} ${t.height}"
style="margin: ${this.handleSize*this.handleZoom}px;"
?disabled=${this.disabled}
+ ?readonly=${!this._showHandle}
focusable="false"
>
<g class="slider">
@@ -160,6 +161,16 @@ var nt;null===(nt=window.HTMLSlotElement)||void 0===nt||nt.prototype.assignedEle
stroke-linecap: round;
cursor: var(--round-slider-handle-cursor, pointer);
}
+ .shadowpath {
+ cursor: var(
+ --round-slider-path-cursor,
+ var(--round-slider-handle-cursor, pointer)
+ );
+ }
+ svg[disabled] .shadowpath,
+ svg[readonly] .shadowpath {
+ cursor: default;
+ }
g.low.handle {
stroke: var(--round-slider-low-handle-color);
}
diff --git a/round-slider.iife.js b/round-slider.iife.js
index 8d9e578c5891ebfbdf6cff6bd9f7ea965bb6ab0b..d4b6c33d8620c4316b8890dfa4eb74cd7fb0933c 100644
--- a/round-slider.iife.js
+++ b/round-slider.iife.js
@@ -78,6 +78,7 @@ var ht;null===(ht=window.HTMLSlotElement)||void 0===ht||ht.prototype.assignedEle
viewBox="${-t.left} ${-t.up} ${t.width} ${t.height}"
style="margin: ${this.handleSize*this.handleZoom}px;"
?disabled=${this.disabled}
+ ?readonly=${!this._showHandle}
focusable="false"
>
<g class="slider">
@@ -160,6 +161,16 @@ var ht;null===(ht=window.HTMLSlotElement)||void 0===ht||ht.prototype.assignedEle
stroke-linecap: round;
cursor: var(--round-slider-handle-cursor, pointer);
}
+ .shadowpath {
+ cursor: var(
+ --round-slider-path-cursor,
+ var(--round-slider-handle-cursor, pointer)
+ );
+ }
+ svg[disabled] .shadowpath,
+ svg[readonly] .shadowpath {
+ cursor: default;
+ }
g.low.handle {
stroke: var(--round-slider-low-handle-color);
}
diff --git a/round-slider.js b/round-slider.js
index 9bfdf73cc3913e10133255b2d346ba36c11d8dc9..6c4b14674d52d28a6ab8a0c38b1cb1768eeabbba 100644
--- a/round-slider.js
+++ b/round-slider.js
@@ -363,6 +363,7 @@ export class RoundSlider extends LitElement {
viewBox="${-view.left} ${-view.up} ${view.width} ${view.height}"
style="margin: ${this.handleSize * this.handleZoom}px;"
?disabled=${this.disabled}
+ ?readonly=${!this._showHandle}
focusable="false"
>
<g class="slider">
@@ -456,6 +457,16 @@ export class RoundSlider extends LitElement {
stroke-linecap: round;
cursor: var(--round-slider-handle-cursor, pointer);
}
+ .shadowpath {
+ cursor: var(
+ --round-slider-path-cursor,
+ var(--round-slider-handle-cursor, pointer)
+ );
+ }
+ svg[disabled] .shadowpath,
+ svg[readonly] .shadowpath {
+ cursor: default;
+ }
g.low.handle {
stroke: var(--round-slider-low-handle-color);
}
@@ -12,29 +12,19 @@ const CONNECTIONS: ModbusConnection[] = [
{
endpoint: ["serial", RS485_PORT],
connected: true,
source: "config_entry",
units: { [FLEXIT_ENTRY_ID]: [1], [SOLAREDGE_ENTRY_ID]: [2] },
},
{
endpoint: ["tcp", "192.168.1.42", 502],
connected: true,
source: "config_entry",
units: { [FRONIUS_ENTRY_ID]: [1] },
},
// A second inverter behind a gateway that is not answering
{
endpoint: ["tcp", "modbus-gateway.local", 502],
connected: false,
source: "config_entry",
units: { [FRONIUS_ENTRY_ID]: [2] },
},
// A YAML hub keeps a link of its own to a device an integration also talks to
{
endpoint: ["tcp", "192.168.1.42", 502],
connected: true,
source: "yaml",
units: { modbus_hub: [10, 11] },
},
];
export const mockModbus = (hass: MockHomeAssistant) => {
-6
View File
@@ -358,12 +358,6 @@ export const mockHassioSupervisor = (hass: MockHomeAssistant) => {
return data;
}
if (msg.endpoint === "/ingress/panels") {
// The navigation picker waits for this collection before it enables
// itself, so it has to answer even when no add-on exposes a panel.
return { panels: {} };
}
if (msg.endpoint === "/store/reload") {
return null;
}
+1 -257
View File
@@ -21,8 +21,6 @@ import "../../../../src/components/ha-settings-row";
import type { BlueprintInput } from "../../../../src/data/blueprint";
import type { DeviceRegistryEntry } from "../../../../src/data/device/device_registry";
import type { LabelRegistryEntry } from "../../../../src/data/label/label_registry";
import { StatisticMeanType } from "../../../../src/data/recorder";
import type { SerialPort } from "../../../../src/data/usb";
import {
showDialog,
type ShowDialogParams,
@@ -295,72 +293,9 @@ const LABELS: LabelRegistryEntry[] = [
},
];
const serialPort = (port: Partial<SerialPort>): SerialPort => ({
device: "/dev/ttyUSB0",
resolved_device: null,
serial_number: null,
manufacturer: null,
description: null,
matching_integrations: [],
present: true,
...port,
});
// One port per section the picker groups by, relative to the "zha" domain the
// serial port selector below is given as its flow context
const SERIAL_PORTS: SerialPort[] = [
serialPort({
device:
"/dev/serial/by-id/usb-Nabu_Casa_SkyConnect_v1.0_9e2adbd75b8beb119fe564a0f320645d-if00-port0",
description: "SkyConnect v1.0",
manufacturer: "Nabu Casa",
serial_number: "9e2adbd75b8beb119fe564a0f320645d",
vid: "10C4",
pid: "EA60",
matching_integrations: ["zha"],
}),
serialPort({
device: "esphome-hass://01JQ8Z5X9WQ0/?port_name=UART0",
}),
serialPort({
device: "socket://192.168.1.10:6638",
}),
serialPort({
device: "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AB0KVD1L-if00-port0",
description: "FT232R USB UART",
manufacturer: "FTDI",
serial_number: "AB0KVD1L",
vid: "0403",
pid: "6001",
}),
serialPort({
device: "/dev/ttyS0",
description: "ttyS0",
manufacturer: "Intel",
}),
serialPort({ device: "/dev/ttyAMA0" }),
serialPort({
device:
"/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0",
description: "CP2102 USB to UART Bridge Controller",
manufacturer: "Silicon Labs",
serial_number: "0001",
vid: "10C4",
pid: "EA60",
matching_integrations: ["matter"],
}),
];
const SCHEMAS: {
name: string;
input: Record<
string,
| (BlueprintInput & {
required?: boolean;
context?: Record<string, unknown>;
})
| null
>;
input: Record<string, (BlueprintInput & { required?: boolean }) | null>;
}[] = [
{
name: "One of each",
@@ -385,13 +320,6 @@ const SCHEMAS: {
},
duration: { name: "Duration", selector: { duration: {} } },
app: { name: "App", selector: { app: {} } },
serial_port: {
name: "Serial port",
selector: { serial_port: {} },
// A config flow passes its own domain as context, which is what the
// picker groups recommended and not recommended ports by
context: { domain: "zha" },
},
number_box: {
name: "Number Box",
selector: {
@@ -576,99 +504,6 @@ const SCHEMAS: {
},
},
},
addon: { name: "Add-on", selector: { addon: {} } },
areas_display: {
name: "Areas display",
selector: { areas_display: {} },
},
assist_pipeline: {
name: "Assist pipeline",
selector: { assist_pipeline: {} },
},
automation_behavior: {
name: "Automation behavior",
selector: { automation_behavior: { mode: "trigger" } },
},
backup_location: {
name: "Backup location",
selector: { backup_location: {} },
},
button_toggle: {
name: "Button toggle",
selector: {
button_toggle: {
options: [
{ label: "Left", value: "left" },
{ label: "Center", value: "center" },
{ label: "Right", value: "right" },
],
},
},
},
condition: { name: "Condition", selector: { condition: {} } },
conversation_agent: {
name: "Conversation agent",
selector: { conversation_agent: {} },
},
country: {
name: "Country",
selector: { country: { countries: ["DE", "GB", "NL", "US"] } },
},
entity_name: {
name: "Entity name",
selector: { entity_name: { entity_id: "light.bedroom" } },
},
file: {
name: "File",
selector: { file: { accept: "image/png,image/jpeg" } },
},
language: { name: "Language", selector: { language: {} } },
navigation: { name: "Navigation", selector: { navigation: {} } },
numeric_threshold: {
name: "Numeric threshold",
selector: { numeric_threshold: {} },
},
period: {
name: "Period",
selector: {
period: {
options: ["today", "yesterday", "this_week", "this_month"],
},
},
// Without a value that matches one of the options the selector offers
// its custom-period editor instead of the list
default: { calendar: { period: "day" } },
},
selector: {
name: "Selector",
selector: { selector: {} },
default: { text: {} },
},
state_class: { name: "State class", selector: { state_class: {} } },
statistic: { name: "Statistic", selector: { statistic: {} } },
stt: { name: "Speech-to-text", selector: { stt: {} } },
theme: { name: "Theme", selector: { theme: {} } },
timezone: { name: "Time zone", selector: { timezone: {} } },
trigger: { name: "Trigger", selector: { trigger: {} } },
tts: { name: "Text-to-speech", selector: { tts: {} } },
tts_voice: {
name: "Text-to-speech voice",
selector: { tts_voice: { engineId: "tts.cloud", language: "en-US" } },
},
ui_action: { name: "UI action", selector: { ui_action: {} } },
ui_clock_date_format: {
name: "Clock date format",
selector: { ui_clock_date_format: {} },
},
ui_color: { name: "UI color", selector: { ui_color: {} } },
ui_state_content: {
name: "State content",
selector: { ui_state_content: { entity_id: "light.bedroom" } },
},
ui_time_format: {
name: "Time format",
selector: { ui_time_format: {} },
},
},
},
{
@@ -770,98 +605,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
mockFloorRegistry(hass, FLOORS);
mockLabelRegistry(hass, LABELS);
mockHassioSupervisor(hass);
hass.addTranslations({
"component.matter.title": "Matter",
"component.zha.title": "Zigbee Home Automation",
});
hass.updateHass({
config: {
...hass.config,
components: [...hass.config.components, "usb"],
},
});
hass.mockWS("auth/sign_path", (params) => params);
hass.mockWS("media_player/browse_media", this._browseMedia);
hass.mockWS("usb/list_serial_ports", () => SERIAL_PORTS);
hass.mockWS("recorder/list_statistic_ids", () => [
{
statistic_id: "sensor.energy_consumption",
statistics_unit_of_measurement: "kWh",
source: "recorder",
name: null,
has_sum: true,
mean_type: StatisticMeanType.NONE,
unit_class: "energy",
},
{
statistic_id: "sensor.outside_temperature",
statistics_unit_of_measurement: "\u00b0C",
source: "recorder",
name: null,
has_sum: false,
mean_type: StatisticMeanType.ARITHMETIC,
unit_class: "temperature",
},
]);
hass.mockWS("assist_pipeline/pipeline/list", () => ({
pipelines: [
{
id: "pipeline_home",
name: "Home Assistant",
language: "en",
conversation_engine: "conversation.home_assistant",
conversation_language: "en",
stt_engine: "stt.cloud",
stt_language: "en-US",
tts_engine: "tts.cloud",
tts_language: "en-US",
tts_voice: "JennyNeural",
wake_word_entity: null,
wake_word_id: null,
},
],
preferred_pipeline: "pipeline_home",
}));
hass.mockWS("conversation/agent/list", () => ({
agents: [
{
id: "conversation.home_assistant",
name: "Home Assistant",
supported_languages: "*",
},
{
id: "conversation.openai",
name: "OpenAI Conversation",
supported_languages: ["en"],
},
],
}));
hass.mockWS("stt/engine/list", () => ({
providers: [
{
engine_id: "stt.cloud",
name: "Home Assistant Cloud",
supported_languages: ["en-US"],
deprecated: false,
},
],
}));
hass.mockWS("tts/engine/list", () => ({
providers: [
{
engine_id: "tts.cloud",
name: "Home Assistant Cloud",
supported_languages: ["en-US"],
deprecated: false,
},
],
}));
hass.mockWS("tts/engine/voices", () => ({
voices: [
{ voice_id: "JennyNeural", name: "Jenny" },
{ voice_id: "GuyNeural", name: "Guy" },
],
}));
}
public provideHass(el) {
@@ -1031,7 +776,6 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
<ha-selector
.hass=${this.hass}
.selector=${value!.selector}
.context=${value!.context}
.key=${key}
.label=${this._label ? value!.name : undefined}
.value=${data[key] ?? value!.default}
+3 -4
View File
@@ -21,8 +21,7 @@ const ENTITIES = [
state: "on",
attributes: {
friendly_name: "Dining Room",
supported_color_modes: ["brightness"],
color_mode: "brightness",
supported_features: 1,
brightness: 100,
},
},
@@ -31,7 +30,7 @@ const ENTITIES = [
state: "off",
attributes: {
friendly_name: "Dining Room",
supported_color_modes: ["brightness"],
supported_features: 1,
},
},
{
@@ -39,7 +38,7 @@ const ENTITIES = [
state: "unavailable",
attributes: {
friendly_name: "Lost Light",
supported_color_modes: ["brightness"],
supported_features: 1,
},
},
];
+7 -6
View File
@@ -39,7 +39,7 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "8.0.5",
"@babel/runtime": "8.0.0",
"@braintree/sanitize-url": "7.1.2",
"@codemirror/autocomplete": "6.20.3",
"@codemirror/commands": "6.11.0",
@@ -84,6 +84,7 @@
"@mdi/svg": "7.4.47",
"@replit/codemirror-indentation-markers": "6.5.3",
"@swc/helpers": "0.5.23",
"@thomasloven/round-slider": "patch:@thomasloven/round-slider@npm%3A0.6.0#~/.yarn/patches/@thomasloven-round-slider-npm-0.6.0-d7176d9db7.patch",
"@tsparticles/engine": "4.4.0",
"@tsparticles/preset-links": "4.4.0",
"@vibrant/color": "4.0.4",
@@ -138,10 +139,10 @@
},
"devDependencies": {
"@ampproject/remapping": "2.3.0",
"@babel/core": "8.0.5",
"@babel/core": "8.0.1",
"@babel/helper-define-polyfill-provider": "1.0.0",
"@babel/plugin-transform-runtime": "8.0.1",
"@babel/preset-env": "8.0.5",
"@babel/preset-env": "8.0.2",
"@bundle-stats/plugin-webpack-filter": "4.22.3",
"@eslint/js": "10.0.1",
"@gfx/zopfli": "1.0.15",
@@ -194,10 +195,10 @@
"html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"jsdom": "30.0.1",
"jszip": "3.10.2",
"jszip": "3.10.1",
"license-checker-rseidelsohn": "5.0.1",
"lightningcss": "1.33.0",
"lint-staged": "17.5.1",
"lint-staged": "17.5.0",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.18.1",
@@ -213,7 +214,7 @@
"ts-lit-plugin": "2.0.2",
"typescript": "6.0.3",
"typescript-eslint": "8.70.0",
"vite": "8.3.0",
"vite": "8.2.2",
"vite-tsconfig-paths": "6.1.1",
"vitest": "5.0.0",
"webpack-stats-plugin": "1.1.3",
+21 -19
View File
@@ -9,34 +9,36 @@ export const createDurationData = (
}
if (typeof duration !== "object") {
if (typeof duration === "string" || isNaN(duration)) {
const durationString = duration.toString().trim();
// A leading "-" negates the whole period, matching
// `cv.time_period_str` in core.
const negative = durationString[0] === "-";
const parts = durationString
.split(":")
.map((part) =>
negative && part ? -Math.abs(Number(part)) : Number(part)
);
const parts = duration?.toString().split(":") || [];
if (parts.length === 1) {
return { seconds: parts[0] };
return { seconds: Number(parts[0]) };
}
if (parts.length > 3) {
return undefined;
}
const seconds = parts[2] || 0;
const secondsWhole = Math.trunc(seconds);
const seconds = Number(parts[2]) || 0;
const seconds_whole = Math.floor(seconds);
return {
hours: parts[0] || 0,
minutes: parts[1] || 0,
seconds: secondsWhole,
milliseconds: Math.trunc(
Number((seconds - secondsWhole).toFixed(4)) * 1000
hours: Number(parts[0]) || 0,
minutes: Number(parts[1]) || 0,
seconds: seconds_whole,
milliseconds: Math.floor(
Number((seconds - seconds_whole).toFixed(4)) * 1000
),
};
}
return { seconds: duration };
}
return duration;
if (!("days" in duration)) {
return duration;
}
const { days, minutes, seconds, milliseconds } = duration;
let hours = duration.hours || 0;
hours = (hours || 0) + (days || 0) * 24;
return {
hours,
minutes,
seconds,
milliseconds,
};
};
@@ -1,48 +0,0 @@
import {
DateFormat,
FirstWeekday,
NumberFormat,
TimeFormat,
TimeZone,
} from "../../data/translation";
import { translationMetadata } from "../../resources/translations-metadata";
import type { HomeAssistantInternationalization } from "../../types";
import type { LocalizeFunc } from "./localize";
/**
* Builds an internationalization context value for the "lite" localize mode
* used before a `hass` object exists. Locale falls back to browser defaults and
* the lazy loaders are stubs that warn when called.
*/
export const buildLiteInternationalization = (
language: string,
localize: LocalizeFunc
): HomeAssistantInternationalization => ({
language,
selectedLanguage: language,
locale: {
language,
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
},
localize,
translationMetadata,
loadBackendTranslation: async (category, integrations, configFlow) => {
// eslint-disable-next-line no-console
console.warn(
"loadBackendTranslation called in lite i18n mode; backend strings are not available",
{ category, integrations, configFlow }
);
return localize;
},
loadFragmentTranslation: async (fragment) => {
// eslint-disable-next-line no-console
console.warn(
`loadFragmentTranslation("${fragment}") called in lite i18n mode; fragment not loaded`
);
return undefined;
},
});
@@ -44,8 +44,7 @@ export class StateHistoryChartTimeline extends LitElement {
@property({ attribute: "show-names", type: Boolean }) public showNames = true;
// Render each row's name inside the plot (under its bar) instead of in a
// left-hand category-label column. Opt-in; used by the history panel and
// history-graph card.
// left-hand category-label column. Opt-in; used by the history panel.
@property({ attribute: "inside-labels", type: Boolean })
public insideLabels = false;
@@ -80,9 +79,7 @@ export class StateHistoryChartTimeline extends LitElement {
.options=${this._chartOptions}
.height=${`${
this.data.length *
(this.insideLabels && (this.chunked || this.showNames)
? ROW_HEIGHT_INSIDE_LABELS
: ROW_HEIGHT) +
(this.insideLabels ? ROW_HEIGHT_INSIDE_LABELS : ROW_HEIGHT) +
GRID_BOTTOM
}px`}
.data=${this._chartData as HaECSeries}
+1 -1
View File
@@ -80,7 +80,7 @@ export class StateHistoryCharts extends LitElement {
@property({ attribute: "show-names", type: Boolean }) public showNames = true;
// Render timeline row names inside the plot (under each bar) instead of in a
// left-hand column. Opt-in; used by the history panel and history-graph card.
// left-hand column. Opt-in; used by the history panel.
@property({ attribute: "inside-labels", type: Boolean })
public insideLabels = false;
+59 -90
View File
@@ -1,100 +1,69 @@
import { AssistChip } from "@material/web/chips/internal/assist-chip";
import { styles } from "@material/web/chips/internal/assist-styles.cssresult.js";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles.cssresult.js";
import { styles as elevatedStyles } from "@material/web/chips/internal/elevated-styles.cssresult.js";
import { css, html } from "lit";
import type { CSSResultGroup } from "lit";
import { css } from "lit";
import { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-assist-chip")
// @ts-ignore
export class HaAssistChip extends AssistChip {
export class HaAssistChip extends HaChipBase {
@property({ type: Boolean, reflect: true }) filled = false;
@property({ type: Boolean }) active = false;
@property({ type: Boolean, reflect: true }) active = false;
static override styles = [
sharedStyles,
elevatedStyles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-assist-chip-container-shape: var(
--ha-assist-chip-container-shape,
16px
);
--md-assist-chip-outline-color: var(--outline-color);
--md-assist-chip-label-text-weight: 400;
}
/** Material 3 doesn't have a filled chip, so we have to make our own **/
.filled {
display: flex;
pointer-events: none;
border-radius: inherit;
inset: 0;
position: absolute;
background-color: var(--ha-assist-chip-filled-container-color);
}
/** Set the size of mdc icons **/
::slotted([slot="icon"]),
::slotted([slot="trailing-icon"]) {
display: flex;
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
font-size: var(--_label-text-size) !important;
}
@property({ type: Boolean, reflect: true }) elevated = false;
.trailing.icon ::slotted(*),
.trailing.icon svg {
margin-inline-end: unset;
margin-inline-start: var(--_icon-label-space);
}
::before {
background: var(--ha-assist-chip-container-color, transparent);
opacity: var(--ha-assist-chip-container-opacity, 1);
}
:where(.active)::before {
background: var(--ha-assist-chip-active-container-color);
opacity: var(--ha-assist-chip-active-container-opacity);
}
.label {
font-family: var(--ha-font-family-body);
}
`,
];
protected override renderOutline() {
if (this.filled) {
return html`<span class="filled"></span>`;
}
return super.renderOutline();
}
protected override getContainerClasses() {
return {
...super.getContainerClasses(),
active: this.active,
};
}
protected override renderPrimaryContent() {
return html`
<span class="leading icon" aria-hidden="true">
${this.renderLeadingIcon()}
</span>
<span class="label">${this.label}</span>
<span class="touch"></span>
<span class="trailing leading icon" aria-hidden="true">
${this.renderTrailingIcon()}
</span>
`;
}
protected renderTrailingIcon() {
return html`<slot name="trailing-icon"></slot>`;
static override get styles(): CSSResultGroup {
return [
super.styles,
css`
:host {
--ha-chip-label-color: var(
--md-assist-chip-label-text-color,
var(--md-sys-color-on-surface, var(--primary-text-color))
);
--ha-button-border-radius: var(
--ha-assist-chip-container-shape,
16px
);
--ha-chip-container-color: var(
--ha-assist-chip-container-color,
transparent
);
--ha-chip-container-opacity: var(
--ha-assist-chip-container-opacity,
1
);
--ha-chip-outline-color: var(
--md-assist-chip-outline-color,
var(--outline-color)
);
--ha-chip-icon-label-space: var(
--md-assist-chip-icon-label-space,
var(--ha-space-2)
);
}
:host([filled]) {
--ha-chip-container-color: var(
--ha-assist-chip-filled-container-color
);
--ha-chip-outline-color: transparent;
}
:host([active]) {
--ha-chip-container-color: var(
--ha-assist-chip-active-container-color
);
--ha-chip-container-opacity: var(
--ha-assist-chip-active-container-opacity,
1
);
}
.primary {
padding-inline-end: var(
--md-assist-chip-trailing-space,
var(--ha-space-4)
);
}
`,
];
}
}
+452
View File
@@ -0,0 +1,452 @@
import { LocalizeController } from "@home-assistant/webawesome/dist/utilities/localize.js";
import { mdiClose } from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, nothing } from "lit";
import { property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../common/dom/fire_event";
import { HaButton } from "../ha-button";
import "../ha-svg-icon";
export interface ChipFocusOptions extends FocusOptions {
trailing?: boolean;
}
export class HaChipBase extends HaButton {
@property() label = "";
@property({ type: Boolean }) removable = false;
@property({ type: Boolean, attribute: "remove-only" }) removeOnly = false;
@property({ type: Boolean, reflect: true, attribute: "soft-disabled" })
softDisabled = false;
@property({ type: Boolean, attribute: "always-focusable" })
alwaysFocusable = false;
@property({ type: Boolean, reflect: true, attribute: "has-icon" })
hasIcon = false;
@property({ type: Number, reflect: true, attribute: "tabindex" })
override tabIndex = 0;
@property({ attribute: "aria-label-remove" }) ariaLabelRemove: string | null =
null;
@query(".primary") private _primary?: HTMLButtonElement | HTMLAnchorElement;
@query(".remove") private _remove?: HTMLButtonElement;
@state() private _trailingFocused = false;
@state() private _hasTrailingIcon = false;
private _chipLocalize = new LocalizeController(this);
override variant: HaButton["variant"] = "neutral";
override appearance: HaButton["appearance"] = "outlined";
override size: HaButton["size"] = "s";
protected get pressed(): boolean | undefined {
return undefined;
}
get focusable() {
return !this.disabled || this.alwaysFocusable;
}
constructor() {
super();
this.addEventListener("click", this._blockDisabledClick);
this.addEventListener("keydown", this._handleKeyDown);
}
override focus(options?: ChipFocusOptions) {
if (!this.focusable) {
return;
}
if (
(options?.trailing || (this.removeOnly && !this.href)) &&
this._remove
) {
this._remove.focus(options);
} else {
this._primary?.focus(options);
}
}
override click() {
if (this.removeOnly && !this.href) {
this._remove?.click();
} else {
this._primary?.click();
}
}
override blur() {
this._primary?.blur();
this._remove?.blur();
}
protected override updated(changed: PropertyValues<this>) {
super.updated(changed);
if (changed.has("disabled") || changed.has("alwaysFocusable")) {
fireEvent(this, "update-focus", undefined, { composed: false });
}
}
override render() {
return html`
<div class=${classMap({ container: true, "has-remove": this.removable })}>
${this._renderPrimaryAction()}
${
this.removable
? html`
<span id="remove-label" hidden>
${this._chipLocalize.term("remove")}
</span>
<span id="accessible-label" hidden>${this.ariaLabel}</span>
<button
class="button remove trailing action"
part="remove-button"
type="button"
?disabled=${this.disabled && !this.alwaysFocusable}
aria-disabled=${this.softDisabled ? "true" : nothing}
aria-label=${this.ariaLabelRemove || nothing}
aria-labelledby=${
this.ariaLabelRemove
? nothing
: this.ariaLabel
? "remove-label accessible-label"
: "remove-label label"
}
tabindex=${this.removeOnly && !this.href ? this.tabIndex : -1}
@click=${this._handleRemove}
@focus=${this._handleRemoveFocus}
@blur=${this._handleRemoveBlur}
>
<span class="icon" aria-hidden="true">
<slot name="remove-trailing-icon">
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</slot>
</span>
</button>
`
: nothing
}
</div>
`;
}
private _renderPrimaryAction() {
if (this.href) {
return html`<a
class="button primary action"
part="base"
title=${this.title || nothing}
href=${this.href}
target=${this.target || nothing}
download=${this.download || nothing}
rel=${this.rel || nothing}
aria-label=${this.ariaLabel || nothing}
tabindex=${this._trailingFocused ? -1 : this.tabIndex}
@click=${this.handlePrimaryClick}
>${this.renderPrimaryContent()}</a
>`;
}
if (this.removeOnly) {
return html`<span class="content" title=${this.title || nothing}>
${this.renderPrimaryContent()}
</span>`;
}
return html`<button
class=${classMap({
button: true,
primary: true,
action: true,
disabled: this.disabled || this.softDisabled,
})}
part="base"
type="button"
title=${this.title || nothing}
?disabled=${this.disabled && !this.alwaysFocusable}
aria-disabled=${
this.softDisabled || (this.disabled && this.alwaysFocusable)
? "true"
: nothing
}
aria-label=${this.ariaLabel || nothing}
aria-pressed=${this.pressed ?? nothing}
tabindex=${this._trailingFocused ? -1 : this.tabIndex}
@click=${this.handlePrimaryClick}
>
${this.renderPrimaryContent()}
</button>`;
}
protected renderPrimaryContent() {
return html`
${this.renderLeadingIcon()}
<span class="label" id="label" part="label">
${this.label || html`<slot></slot>`}
</span>
<span class="icon" aria-hidden="true" ?hidden=${!this._hasTrailingIcon}>
<slot name="trailing-icon" @slotchange=${this._iconChanged}></slot>
</span>
`;
}
protected renderLeadingIcon(): TemplateResult | typeof nothing {
return html`<span class="icon leading" aria-hidden="true">
<slot name="icon" @slotchange=${this._iconChanged}></slot>
</span>`;
}
protected handlePrimaryClick(event: MouseEvent) {
this._blockDisabledClick(event);
}
private _iconChanged(event: Event) {
if (!(event.target instanceof HTMLSlotElement)) {
return;
}
const hasIcon = event.target.assignedElements({ flatten: true }).length > 0;
if (event.target.name === "icon") {
this.hasIcon = hasIcon;
} else {
this._hasTrailingIcon = hasIcon;
}
}
private _blockDisabledClick(event: MouseEvent) {
if (
this.softDisabled ||
(this.disabled && (!this.href || this.alwaysFocusable))
) {
event.preventDefault();
event.stopImmediatePropagation();
}
}
private _handleRemove(event: MouseEvent) {
event.stopPropagation();
if (this.disabled || this.softDisabled) {
return;
}
if (
!fireEvent(this, "remove", undefined, {
bubbles: false,
composed: false,
cancelable: true,
}).defaultPrevented
) {
this.remove();
}
}
private _handleRemoveFocus() {
this._trailingFocused = true;
}
private _handleRemoveBlur() {
this._trailingFocused = false;
}
private _handleKeyDown(event: KeyboardEvent) {
if (
(event.key !== "ArrowLeft" && event.key !== "ArrowRight") ||
!this._primary ||
!this._remove
) {
return;
}
const forwards =
(event.key === "ArrowRight") !==
(getComputedStyle(this).direction === "rtl");
if (
(forwards && this.shadowRoot?.activeElement === this._primary) ||
(!forwards && this.shadowRoot?.activeElement === this._remove)
) {
event.preventDefault();
event.stopPropagation();
(forwards ? this._remove : this._primary).focus();
}
}
static override get styles(): CSSResultGroup {
return [
super.styles,
css`
:host {
display: inline-flex;
max-width: 100%;
vertical-align: middle;
--ha-button-height: 32px;
--ha-button-border-radius: var(--ha-border-radius-pill);
--wa-font-weight-action: var(--ha-font-weight-normal);
--wa-button-transform-hover: none;
--wa-button-transform-active: none;
}
:host([variant]) {
--wa-color-on-quiet: var(
--ha-chip-label-color,
var(--primary-text-color)
);
--wa-color-fill-quiet: color-mix(
in srgb,
var(--ha-chip-label-color, var(--primary-text-color)) 8%,
transparent
);
}
.container {
display: flex;
align-items: center;
min-width: 0;
max-width: 100%;
height: var(--ha-button-height);
position: relative;
border-radius: var(--ha-button-border-radius);
}
.container::before,
.container::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
border-radius: inherit;
}
.container::before {
background: var(--ha-chip-container-color, transparent);
opacity: var(--ha-chip-container-opacity, 1);
}
.container::after {
border: var(--ha-chip-outline-width, 1px) solid
var(--ha-chip-outline-color, var(--outline-color));
}
.button,
.content {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--ha-chip-icon-label-space, var(--ha-space-2));
min-width: 0;
border: 0;
border-radius: inherit;
color: var(--ha-chip-label-color, var(--primary-text-color));
background: transparent;
font-family: var(--ha-font-family-body);
font-size: var(--ha-font-size-m);
font-weight: var(--ha-font-weight-normal);
padding-inline: var(--ha-space-4);
position: relative;
box-shadow: none;
}
.button.primary,
.content {
flex: 1;
height: var(--ha-button-height);
min-height: var(--ha-button-height);
}
.label {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
font-size: var(--ha-chip-label-size, 0.875rem);
font-weight: var(
--ha-chip-label-weight,
var(--ha-font-weight-normal)
);
line-height: var(--ha-chip-label-line-height, 1.25rem);
color: var(--ha-chip-label-color, var(--primary-text-color));
}
.button.remove {
flex: none;
padding: 0;
width: calc(var(--ha-chip-icon-size, 18px) + 2 * var(--ha-space-2));
height: var(--ha-button-height);
min-height: var(--ha-button-height);
border-start-start-radius: 0;
border-end-start-radius: 0;
}
.has-remove .primary,
.has-remove .content {
border-start-end-radius: 0;
border-end-end-radius: 0;
padding-inline-end: 0;
}
:host([has-icon]) .primary,
:host([has-icon]) .content {
padding-inline-start: var(--ha-space-2);
}
.button::after {
content: "";
position: absolute;
inset: -8px 0;
}
slot:not([name]),
slot[name="icon"],
slot[name="trailing-icon"],
slot[name="selected-icon"],
slot[name="remove-trailing-icon"] {
display: contents;
}
.icon {
display: flex;
flex: none;
color: var(--ha-chip-label-color, var(--primary-text-color));
}
:host(:not([has-icon])) .leading {
display: none;
}
.icon[hidden] {
display: none;
}
ha-svg-icon,
::slotted([slot]) {
flex: none;
display: flex;
--mdc-icon-size: var(--ha-chip-icon-size, 18px);
}
:host([disabled]),
:host([soft-disabled]) {
opacity: 1;
}
:host([disabled]) .label,
:host([disabled]) .icon,
:host([soft-disabled]) .label,
:host([soft-disabled]) .icon {
opacity: 0.38;
}
:host([disabled][selected]) .container::before,
:host([soft-disabled][selected]) .container::before {
background-color: var(--primary-text-color);
opacity: 0.12;
}
:host([elevated]) .container {
box-shadow: var(--ha-box-shadow-s);
}
`,
];
}
}
declare global {
interface HASSDomEvents {
remove: undefined;
"update-focus": undefined;
}
}
+87 -3
View File
@@ -1,8 +1,92 @@
import { MdChipSet } from "@material/web/chips/chip-set";
import { customElement } from "lit/decorators";
import { css, html, LitElement } from "lit";
import { customElement, queryAssignedElements } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-chip-set")
export class HaChipSet extends MdChipSet {}
export class HaChipSet extends LitElement {
@queryAssignedElements({ flatten: true }) private _children!: HTMLElement[];
get chips(): HaChipBase[] {
return this._children.filter(
(child): child is HaChipBase => child instanceof HaChipBase
);
}
override connectedCallback() {
super.connectedCallback();
this.setAttribute("role", "toolbar");
this.addEventListener("keydown", this._handleKeyDown);
this.addEventListener("focusin", this._updateTabIndices);
this.addEventListener("update-focus", this._updateTabIndices);
}
override disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener("keydown", this._handleKeyDown);
this.removeEventListener("focusin", this._updateTabIndices);
this.removeEventListener("update-focus", this._updateTabIndices);
}
protected render() {
return html`<slot @slotchange=${this._updateTabIndices}></slot>`;
}
private _updateTabIndices() {
const chips = this.chips;
const active =
chips.find((chip) => chip.focusable && chip.shadowRoot?.activeElement) ||
chips.find((chip) => chip.focusable);
for (const chip of chips) {
chip.tabIndex = chip === active ? 0 : -1;
}
}
private _handleKeyDown(event: KeyboardEvent) {
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) {
return;
}
const chips = this.chips.filter((chip) => chip.focusable);
if (!chips.length) {
return;
}
event.preventDefault();
const forwards =
(event.key === "ArrowRight") !==
(getComputedStyle(this).direction === "rtl");
const current = chips.findIndex((chip) => chip.shadowRoot?.activeElement);
const index =
event.key === "Home"
? 0
: event.key === "End"
? chips.length - 1
: current === -1
? forwards
? 0
: chips.length - 1
: (current + (forwards ? 1 : -1) + chips.length) % chips.length;
chips[index].focus({
trailing: event.key === "End" || (event.key !== "Home" && !forwards),
});
this._updateTabIndices();
}
static styles = css`
:host {
display: flex;
flex-wrap: wrap;
gap: var(--ha-space-2);
}
`;
}
declare global {
interface HTMLElementTagNameMap {
+68 -41
View File
@@ -1,54 +1,81 @@
import { styles as elevatedStyles } from "@material/web/chips/internal/elevated-styles.cssresult.js";
import { FilterChip } from "@material/web/chips/internal/filter-chip";
import { styles } from "@material/web/chips/internal/filter-styles.cssresult.js";
import { styles as selectableStyles } from "@material/web/chips/internal/selectable-styles.cssresult.js";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles.cssresult.js";
import { styles as trailingIconStyles } from "@material/web/chips/internal/trailing-icon-styles.cssresult.js";
import { css, html } from "lit";
import { mdiCheck } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-filter-chip")
export class HaFilterChip extends FilterChip {
export class HaFilterChip extends HaChipBase {
@property({ type: Boolean, reflect: true }) selected = false;
@property({ type: Boolean, reflect: true }) elevated = false;
@property({ type: Boolean, reflect: true, attribute: "no-leading-icon" })
noLeadingIcon = false;
static override styles = [
sharedStyles,
elevatedStyles,
trailingIconStyles,
selectableStyles,
styles,
css`
:host {
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-sys-color-on-surface-variant: var(--primary-text-color);
--md-sys-color-on-secondary-container: var(--primary-text-color);
--md-filter-chip-container-shape: var(--ha-border-radius-md);
--md-filter-chip-outline-color: var(--outline-color);
--md-filter-chip-selected-container-color: rgba(
var(--rgb-primary-text-color),
0.15
);
--_label-text-font: var(--ha-font-family-body);
}
`,
];
protected getContainerClasses() {
const classes = super.getContainerClasses();
if (this.noLeadingIcon) {
classes["has-icon"] = false;
}
return classes;
protected override get pressed() {
return this.selected;
}
protected renderLeadingIcon() {
protected override renderLeadingIcon() {
if (this.noLeadingIcon) {
// eslint-disable-next-line lit/prefer-nothing
return html``;
return nothing;
}
return super.renderLeadingIcon();
return this.selected
? html`<span class="icon" aria-hidden="true">
<slot name="selected-icon">
<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>
</slot>
</span>`
: super.renderLeadingIcon();
}
protected override handlePrimaryClick(event: MouseEvent) {
if (this.disabled || this.softDisabled) {
return;
}
const previous = this.selected;
this.selected = !this.selected;
event.stopPropagation();
// Dispatch from the chip so listeners see the new selection before deciding
// whether to cancel it. Preserve pointer and modifier-key information.
const click =
typeof PointerEvent !== "undefined" && event instanceof PointerEvent
? new PointerEvent("click", event)
: new MouseEvent("click", event);
if (!this.dispatchEvent(click)) {
this.selected = previous;
event.preventDefault();
}
}
static override get styles(): CSSResultGroup {
return [
super.styles,
css`
:host {
--ha-button-border-radius: var(--ha-border-radius-md);
--ha-chip-label-weight: var(--ha-font-weight-medium);
}
:host([selected]) {
--ha-chip-outline-width: var(
--md-filter-chip-selected-outline-width,
0px
);
--ha-chip-container-color: var(
--md-filter-chip-selected-container-color,
rgba(var(--rgb-primary-text-color), 0.15)
);
}
:host([selected]:not([no-leading-icon])) .primary {
padding-inline-start: var(--ha-space-2);
}
`,
];
}
}
+40 -39
View File
@@ -1,45 +1,46 @@
import { InputChip } from "@material/web/chips/internal/input-chip";
import { styles } from "@material/web/chips/internal/input-styles.cssresult.js";
import { styles as selectableStyles } from "@material/web/chips/internal/selectable-styles.cssresult.js";
import { styles as sharedStyles } from "@material/web/chips/internal/shared-styles.cssresult.js";
import { styles as trailingIconStyles } from "@material/web/chips/internal/trailing-icon-styles.cssresult.js";
import type { CSSResultGroup } from "lit";
import { css } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-input-chip")
export class HaInputChip extends InputChip {
static override styles = [
sharedStyles,
trailingIconStyles,
selectableStyles,
styles,
css`
:host {
max-width: 100%;
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-on-surface: var(--primary-text-color);
--md-sys-color-on-surface-variant: var(--primary-text-color);
--md-sys-color-on-secondary-container: var(--primary-text-color);
--md-input-chip-container-shape: 16px;
--md-input-chip-outline-color: var(--outline-color);
--md-input-chip-selected-container-color: rgba(
var(--rgb-primary-text-color),
0.15
);
--ha-input-chip-selected-container-opacity: 1;
--md-input-chip-label-text-font: Roboto, sans-serif;
--md-input-chip-label-text-weight: 400;
}
/** Set the size of mdc icons **/
::slotted([slot="icon"]) {
display: flex;
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
}
.selected::before {
opacity: var(--ha-input-chip-selected-container-opacity);
}
`,
];
export class HaInputChip extends HaChipBase {
@property({ type: Boolean, reflect: true }) selected = false;
@property({ type: Boolean, reflect: true }) avatar = false;
override removable = true;
static override get styles(): CSSResultGroup {
return [
super.styles,
css`
:host {
--ha-button-border-radius: 16px;
--ha-chip-icon-size: var(--md-input-chip-icon-size, 18px);
}
:host([selected]) {
--ha-chip-container-color: var(
--md-input-chip-selected-container-color,
rgba(var(--rgb-primary-text-color), 0.15)
);
--ha-chip-outline-width: var(
--md-input-chip-selected-outline-width,
0px
);
--ha-chip-container-opacity: var(
--ha-input-chip-selected-container-opacity,
1
);
}
:host([avatar]) ::slotted([slot="icon"]) {
width: 24px;
height: 24px;
border-radius: var(--ha-border-radius-circle);
}
`,
];
}
}
declare global {
+32 -50
View File
@@ -103,87 +103,69 @@ export class HaDurationInput extends LitElement {
`;
}
// Fold units we do not render into the smallest unit we do, so a value the
// user cannot see is not silently dropped on the next edit.
private get _data(): HaDurationData | undefined {
if (!this.data) {
return this.data;
}
const data = { ...this.data };
if (!this.enableDay && data.days) {
data.hours = (data.hours || 0) + data.days * 24;
delete data.days;
}
if (!this.enableMillisecond && data.milliseconds) {
data.seconds = (data.seconds || 0) + data.milliseconds / 1000;
delete data.milliseconds;
}
return data;
}
private get _negative() {
return (
this._toggleNegative ||
(this._data?.days
? this._data.days < 0
: this._data?.hours
? this._data.hours < 0
: this._data?.minutes
? this._data.minutes < 0
: this._data?.seconds
? this._data.seconds < 0
: this._data?.milliseconds
? this._data.milliseconds < 0
(this.data?.days
? this.data.days < 0
: this.data?.hours
? this.data.hours < 0
: this.data?.minutes
? this.data.minutes < 0
: this.data?.seconds
? this.data.seconds < 0
: this.data?.milliseconds
? this.data.milliseconds < 0
: false)
);
}
private get _days() {
return this._data?.days
return this.data?.days
? this.allowNegative
? Math.abs(Number(this._data.days))
: Number(this._data.days)
: this.required || this._data
? Math.abs(Number(this.data.days))
: Number(this.data.days)
: this.required || this.data
? 0
: NaN;
}
private get _hours() {
return this._data?.hours
return this.data?.hours
? this.allowNegative
? Math.abs(Number(this._data.hours))
: Number(this._data.hours)
: this.required || this._data
? Math.abs(Number(this.data.hours))
: Number(this.data.hours)
: this.required || this.data
? 0
: NaN;
}
private get _minutes() {
return this._data?.minutes
return this.data?.minutes
? this.allowNegative
? Math.abs(Number(this._data.minutes))
: Number(this._data.minutes)
: this.required || this._data
? Math.abs(Number(this.data.minutes))
: Number(this.data.minutes)
: this.required || this.data
? 0
: NaN;
}
private get _seconds() {
return this._data?.seconds
return this.data?.seconds
? this.allowNegative
? Math.abs(Number(this._data.seconds))
: Number(this._data.seconds)
: this.required || this._data
? Math.abs(Number(this.data.seconds))
: Number(this.data.seconds)
: this.required || this.data
? 0
: NaN;
}
private get _milliseconds() {
return this._data?.milliseconds
return this.data?.milliseconds
? this.allowNegative
? Math.abs(Number(this._data.milliseconds))
: Number(this._data.milliseconds)
: this.required || this._data
? Math.abs(Number(this.data.milliseconds))
: Number(this.data.milliseconds)
: this.required || this.data
? 0
: NaN;
}
@@ -254,8 +236,8 @@ export class HaDurationInput extends LitElement {
ev.stopPropagation();
const negative = (ev.detail?.value || ev.target.value) === "-";
this._toggleNegative = negative;
if (this._data) {
const value = { ...this._data };
if (this.data) {
const value = { ...this.data };
FIELDS.forEach((t) => {
if (value[t]) {
value[t] = negative ? -Math.abs(value[t]) : Math.abs(value[t]);
-16
View File
@@ -1,16 +0,0 @@
import { mdiArrowLeft, mdiArrowRight } from "@mdi/js";
import { customElement, property } from "lit/decorators";
import { mainWindow } from "../common/dom/get_main_window";
import { HaSvgIcon } from "./ha-svg-icon";
@customElement("ha-icon-arrow-next")
export class HaIconArrowNext extends HaSvgIcon {
@property() public override path =
mainWindow.document.dir === "rtl" ? mdiArrowLeft : mdiArrowRight;
}
declare global {
interface HTMLElementTagNameMap {
"ha-icon-arrow-next": HaIconArrowNext;
}
}
-16
View File
@@ -1,16 +0,0 @@
import { mdiArrowLeft, mdiArrowRight } from "@mdi/js";
import { customElement, property } from "lit/decorators";
import { mainWindow } from "../common/dom/get_main_window";
import { HaSvgIcon } from "./ha-svg-icon";
@customElement("ha-icon-arrow-prev")
export class HaIconArrowPrev extends HaSvgIcon {
@property() public override path =
mainWindow.document.dir === "rtl" ? mdiArrowRight : mdiArrowLeft;
}
declare global {
interface HTMLElementTagNameMap {
"ha-icon-arrow-prev": HaIconArrowPrev;
}
}
@@ -45,11 +45,8 @@ export class HaChooseSelector extends LitElement {
}
if (
changedProperties.has("value") &&
typeof this.value === "object" &&
this.value !== null &&
"active_choice" in this.value &&
this.value.active_choice in this.selector.choose.choices &&
this.value.active_choice !== this._activeChoice
changedProperties.get("value")?.active_choice &&
changedProperties.get("value")?.active_choice !== this._activeChoice
) {
this._setActiveChoice();
}
@@ -153,14 +150,14 @@ export class HaChooseSelector extends LitElement {
if (this.value === null || this.value === undefined) {
return undefined;
}
return typeof this.value === "object" && "active_choice" in this.value
return typeof this.value === "object"
? this.value[choice || this.value.active_choice]
: this.value;
}
private _setActiveChoice() {
if (this.value) {
if (typeof this.value === "object" && "active_choice" in this.value) {
if (typeof this.value === "object") {
if (this.value.active_choice in this.selector.choose.choices) {
this._activeChoice = this.value.active_choice;
return;
@@ -202,22 +199,6 @@ export class HaChooseSelector extends LitElement {
];
return;
}
if (
typeofValue === "object" &&
!Array.isArray(this.value) &&
Object.keys(this.value).length > 0 &&
Object.keys(this.value).every((key) =>
["days", "hours", "minutes", "seconds", "milliseconds"].includes(
key
)
) &&
selectorTypes.includes("duration")
) {
this._activeChoice = Object.keys(this.selector.choose.choices)[
selectorTypes.indexOf("duration")
];
return;
}
}
}
this._activeChoice = Object.keys(this.selector.choose.choices)[0];
@@ -4,7 +4,6 @@ import memoizeOne from "memoize-one";
import type { DurationSelector } from "../../data/selector";
import "../ha-duration-input";
import type { HaDurationData, HaDurationInput } from "../ha-duration-input";
import { createDurationData } from "../../common/datetime/create_duration_data";
@customElement("ha-selector-duration")
export class HaTimeDuration extends LitElement {
@@ -28,8 +27,33 @@ export class HaTimeDuration extends LitElement {
}
private _data = memoizeOne(
(value?: HaDurationData | string | number): HaDurationData | undefined =>
createDurationData(value)
(value?: HaDurationData | string | number): HaDurationData | undefined => {
if (typeof value === "number") {
return { seconds: value };
}
if (typeof value === "string") {
const negative = value.trim()[0] === "-";
const parts = value
.split(":")
.map((p) => (negative && p ? -Math.abs(Number(p)) : Number(p)));
if (parts.length === 1) {
return { seconds: parts[0] };
}
if (parts.length === 2) {
return { hours: parts[0], minutes: parts[1] };
}
if (parts.length === 3) {
return {
hours: parts[0],
minutes: parts[1],
seconds: parts[2],
};
}
return undefined;
}
return value;
}
);
protected render() {
-4
View File
@@ -1327,9 +1327,6 @@ export class HaMap extends ReactiveElement {
.maplibregl-popup-anchor-top .maplibregl-popup-tip {
border-bottom-color: rgba(80, 80, 80, 0.9) !important;
}
.maplibregl-ctrl-bottom-left {
direction: ltr;
}
.dark .leaflet-bar a {
background-color: #1c1c1c;
color: #ffffff;
@@ -1380,7 +1377,6 @@ export class HaMap extends ReactiveElement {
transparent
) !important;
text-shadow: none !important;
direction: ltr;
}
/* the theme tokens follow the page, so forced modes need the opposite values */
#map.forced-light .leaflet-control-scale-line {
+1 -8
View File
@@ -3,17 +3,10 @@ import type { HomeAssistant } from "../types";
/** Transport with host and port, or with the serial device path. */
export type ModbusEndpoint = [string, string, number] | [string, string];
/** Whether a connection belongs to a config entry or to a YAML hub. */
export type ModbusConnectionSource = "config_entry" | "yaml";
export interface ModbusConnection {
endpoint: ModbusEndpoint;
connected: boolean;
source: ModbusConnectionSource;
/**
* The unit IDs each holder uses, keyed by config entry ID, or by hub name
* when `source` is `"yaml"`.
*/
/** The unit IDs each config entry holds, keyed by config entry ID. */
units: Record<string, number[]>;
}
@@ -1,14 +1,16 @@
import { mdiArrowRight } from "@mdi/js";
import { ERR_CONNECTION_LOST } from "home-assistant-js-websocket";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { formatNumericDuration } from "../../common/datetime/format_duration";
import { fireEvent } from "../../common/dom/fire_event";
import { computeRTL } from "../../common/util/compute_rtl";
import "../../components/ha-alert";
import "../../components/ha-button";
import "../../components/ha-dialog-footer";
import "../../components/ha-dialog";
import "../../components/ha-svg-icon";
import "../../components/ha-icon-arrow-next";
import type { HttpConfig } from "../../data/http";
import {
HTTP_CONFIG_FIELDS,
@@ -156,6 +158,10 @@ export class DialogHttpPendingConfig
const changes = this._changedFields;
const { stable, pending } = this._params.state;
const rtl = computeRTL(
this.hass.language,
this.hass.translationMetadata.translations
);
return html`
<ha-dialog
@@ -227,7 +233,12 @@ export class DialogHttpPendingConfig
<span class="old"
>${this._formatValue(key, stable[key])}</span
>
<ha-icon-arrow-next></ha-icon-arrow-next>
<ha-svg-icon
.path=${mdiArrowRight}
style=${styleMap({
transform: rtl ? "scaleX(-1)" : "",
})}
></ha-svg-icon>
<span class="new"
>${this._formatValue(key, pending![key])}</span
>
@@ -392,7 +403,7 @@ export class DialogHttpPendingConfig
.values .new {
color: var(--primary-text-color);
}
.values ha-icon-arrow-next {
.values ha-svg-icon {
--mdc-icon-size: 18px;
flex-shrink: 0;
}
+1 -6
View File
@@ -60,9 +60,7 @@ export class HaInitPage extends LitElement {
: nothing
}
`
: html`<p
class=${classMap({ "loading-text": !this.migration, rtl: document.dir === "rtl" })}
>
: html`<p class=${classMap({ "loading-text": !this.migration })}>
${
this.migration
? html`<span class="migration-text"
@@ -126,9 +124,6 @@ export class HaInitPage extends LitElement {
.loading-text {
opacity: 0.66;
}
.rtl {
direction: rtl;
}
`;
}
+4 -17
View File
@@ -17,7 +17,6 @@ import { applyThemesOnElement } from "../common/dom/apply_themes_on_element";
import type { HASSDomEvent } from "../common/dom/fire_event";
import { mainWindow } from "../common/dom/get_main_window";
import { navigate } from "../common/navigate";
import { buildLiteInternationalization } from "../common/translations/lite-internationalization";
import {
addSearchParam,
extractSearchParam,
@@ -25,7 +24,6 @@ import {
} from "../common/url/search-params";
import { subscribeOne } from "../common/util/subscribe-one";
import "../components/ha-card";
import "../components/progress/ha-progress-bar";
import type { AuthUrlSearchParams } from "../data/auth";
import { hassUrl } from "../data/auth";
import { saveFrontendSystemData } from "../data/frontend";
@@ -42,6 +40,7 @@ import { HassElement } from "../state/hass-element";
import type { HomeAssistant, ValueChangedEvent } from "../types";
import { storeState } from "../util/ha-pref-storage";
import { registerServiceWorker } from "../util/register-service-worker";
import "../components/progress/ha-progress-bar";
import "./onboarding-analytics";
import "./onboarding-create-user";
import "./onboarding-loading";
@@ -166,7 +165,9 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
}
if (this._init) {
return html`<onboarding-welcome></onboarding-welcome>`;
return html`<onboarding-welcome
.localize=${this.localize}
></onboarding-welcome>`;
}
const step = this._curStep()!;
@@ -229,20 +230,6 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
import("../components/ha-language-picker");
}
protected willUpdate(changedProps: PropertyValues<this>) {
super.willUpdate(changedProps);
// Before `hass` connects, feed the context providers from the lite localize
// state so context-consuming components render on the onboarding screens.
if (
!this.hass &&
(changedProps.has("localize") || changedProps.has("language"))
) {
this._provideLiteInternationalization(
buildLiteInternationalization(this.language, this.localize)
);
}
}
protected updated(changedProps: PropertyValues) {
super.updated(changedProps);
if (changedProps.has("_page")) {
+12 -12
View File
@@ -1,36 +1,36 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { consumeLocalize } from "../common/decorators/consume-context-entry";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import type { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-button";
import "../components/ha-icon-next";
import "../components/item/ha-list-item-button";
import "../components/list/ha-list-base";
import type { HomeAssistant } from "../types";
import { onBoardingStyles } from "./styles";
@customElement("onboarding-welcome")
class OnboardingWelcome extends LitElement {
@state()
@consumeLocalize()
private _localize!: LocalizeFunc;
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public localize!: LocalizeFunc;
protected render(): TemplateResult {
return html`
<h1>${this._localize("ui.panel.page-onboarding.welcome.header")}</h1>
<p>${this._localize("ui.panel.page-onboarding.intro")}</p>
<h1>${this.localize("ui.panel.page-onboarding.welcome.header")}</h1>
<p>${this.localize("ui.panel.page-onboarding.intro")}</p>
<ha-button @click=${this._start} class="start">
${this._localize("ui.panel.page-onboarding.welcome.start")}
${this.localize("ui.panel.page-onboarding.welcome.start")}
</ha-button>
<div class="divider">
<wa-divider></wa-divider>
<div>
<span
>${this._localize(
>${this.localize(
"ui.panel.page-onboarding.welcome.or_restore"
)}</span
>
@@ -40,10 +40,10 @@ class OnboardingWelcome extends LitElement {
<ha-list-base>
<ha-list-item-button @click=${this._restoreBackupUpload}>
<div slot="headline">
${this._localize("ui.panel.page-onboarding.restore.upload_backup")}
${this.localize("ui.panel.page-onboarding.restore.upload_backup")}
</div>
<div slot="supporting-text">
${this._localize(
${this.localize(
"ui.panel.page-onboarding.restore.options.upload_description"
)}
</div>
@@ -52,7 +52,7 @@ class OnboardingWelcome extends LitElement {
<ha-list-item-button @click=${this._restoreBackupCloud}>
<div slot="headline">Home Assistant Cloud</div>
<div slot="supporting-text">
${this._localize(
${this.localize(
"ui.panel.page-onboarding.restore.ha-cloud.description"
)}
</div>
@@ -8,7 +8,6 @@ import type { TriggerElement } from "../ha-automation-trigger-row";
import type { HaDurationData } from "../../../../../components/ha-duration-input";
import "../../../../../components/ha-form/ha-form";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { durationDataToSeconds } from "../../../../../common/datetime/duration_to_seconds";
import type { LocalizeFunc } from "../../../../../common/translations/localize";
import type { SchemaUnion } from "../../../../../components/ha-form/types";
@@ -83,21 +82,13 @@ export class HaCalendarTrigger extends LitElement implements TriggerElement {
const schema = this._schema(this.hass.localize);
// Convert from string representation to ha form duration representation
const trigger_offset = this.trigger.offset;
// Copy, `createDurationData` returns the input object as-is for dict values.
const duration: HaDurationData = { ...createDurationData(trigger_offset)! };
const duration: HaDurationData = createDurationData(trigger_offset)!;
let offset_type = "after";
if (durationDataToSeconds(duration) < 0) {
// A negative offset negates the whole period, and the sign is shown by
// the separate before/after select instead.
if (duration.days) {
duration.days = Math.abs(duration.days);
}
duration.hours = Math.abs(duration.hours ?? 0);
duration.minutes = Math.abs(duration.minutes ?? 0);
duration.seconds = Math.abs(duration.seconds ?? 0);
if (duration.milliseconds) {
duration.milliseconds = Math.abs(duration.milliseconds);
}
if (
(typeof trigger_offset === "object" && duration!.hours! < 0) ||
(typeof trigger_offset === "string" && trigger_offset.startsWith("-"))
) {
duration.hours = Math.abs(duration.hours!);
offset_type = "before";
}
const data = {
@@ -122,12 +113,11 @@ export class HaCalendarTrigger extends LitElement implements TriggerElement {
// Convert back to duration string representation
const duration = ev.detail.value.offset;
const offsetType = ev.detail.value.offset_type === "before" ? "-" : "";
const h = (duration.days ?? 0) * 24 + (duration.hours ?? 0);
const m = duration.minutes ?? 0;
const s = (duration.seconds ?? 0) + (duration.milliseconds ?? 0) / 1000;
const newTrigger = {
...ev.detail.value,
offset: `${offsetType}${h}:${m}:${s}`,
offset: `${offsetType}${duration.hours ?? 0}:${duration.minutes ?? 0}:${
duration.seconds ?? 0
}`,
};
delete newTrigger.offset_type;
fireEvent(this, "value-changed", { value: newTrigger });
@@ -2,7 +2,9 @@ import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
import "../../../../../components/ha-form/ha-form";
import type { SchemaUnion } from "../../../../../components/ha-form/types";
import type { NumericStateTrigger } from "../../../../../data/automation";
@@ -196,6 +198,21 @@ export class HaNumericStateTrigger extends LitElement {
};
}
private _wrapForValue(
forValue: NumericStateTrigger["for"]
): Record<string, unknown> | undefined {
if (forValue === undefined) {
return undefined;
}
if (typeof forValue === "string" && hasTemplate(forValue)) {
return { active_choice: "template", template: forValue };
}
return {
active_choice: "duration",
duration: createDurationData(forValue),
};
}
private _unwrapForValue(
forValue: Record<string, unknown> | undefined
): NumericStateTrigger["for"] {
@@ -223,6 +240,7 @@ export class HaNumericStateTrigger extends LitElement {
private _data = memoizeOne((trigger: NumericStateTrigger) => ({
...trigger,
entity_id: ensureArray(trigger.entity_id),
for: this._wrapForValue(trigger.for),
}));
public render() {
@@ -15,6 +15,7 @@ import {
union,
} from "superstruct";
import { ensureArray } from "../../../../../common/array/ensure-array";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
import type { LocalizeFunc } from "../../../../../common/translations/localize";
@@ -219,6 +220,21 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
return true;
}
private _wrapForValue(
forValue: StateTrigger["for"]
): Record<string, unknown> | undefined {
if (forValue === undefined) {
return undefined;
}
if (typeof forValue === "string" && hasTemplate(forValue)) {
return { active_choice: "template", template: forValue };
}
return {
active_choice: "duration",
duration: createDurationData(forValue),
};
}
private _unwrapForValue(
forValue: Record<string, unknown> | undefined
): StateTrigger["for"] {
@@ -235,6 +251,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
const data = {
...this.trigger,
entity_id: ensureArray(this.trigger.entity_id),
for: this._wrapForValue(this.trigger.for),
};
data.to = this._normalizeStates(this.trigger.to, data.attribute);
@@ -3,7 +3,9 @@ import { customElement, property } from "lit/decorators";
import type { TemplateTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import "../../../../../components/ha-form/ha-form";
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { hasTemplate } from "../../../../../common/string/has-template";
import type { SchemaUnion } from "../../../../../components/ha-form/types";
const SCHEMA = [
@@ -35,6 +37,21 @@ export class HaTemplateTrigger extends LitElement {
return { trigger: "template", value_template: "" };
}
private _wrapForValue(
forValue: TemplateTrigger["for"]
): Record<string, unknown> | undefined {
if (forValue === undefined) {
return undefined;
}
if (typeof forValue === "string" && hasTemplate(forValue)) {
return { active_choice: "template", template: forValue };
}
return {
active_choice: "duration",
duration: createDurationData(forValue),
};
}
private _unwrapForValue(
forValue: Record<string, unknown> | undefined
): TemplateTrigger["for"] {
@@ -50,6 +67,7 @@ export class HaTemplateTrigger extends LitElement {
protected render() {
const data = {
...this.trigger,
for: this._wrapForValue(this.trigger.for),
};
return html`
@@ -1,6 +1,5 @@
import {
mdiCableData,
mdiFileDocumentOutline,
mdiLan,
mdiPuzzle,
mdiRefresh,
@@ -23,10 +22,7 @@ import "../../../../../components/ha-svg-icon";
import type { ConfigEntry } from "../../../../../data/config_entries";
import { getConfigEntries } from "../../../../../data/config_entries";
import { domainToName } from "../../../../../data/integration";
import type {
ModbusConnection,
ModbusConnectionSource,
} from "../../../../../data/modbus";
import type { ModbusConnection } from "../../../../../data/modbus";
import {
listModbusConnections,
modbusEndpointTarget,
@@ -47,8 +43,7 @@ const isKnownTransport = (transport: string): transport is ModbusTransport =>
(TRANSPORTS as readonly string[]).includes(transport);
interface ConnectionHolder {
/** A config entry ID, or a hub name on a YAML connection. */
id: string;
entryId: string;
entry?: ConfigEntry;
units: number[];
}
@@ -56,10 +51,9 @@ interface ConnectionHolder {
interface ConnectionListItem {
icon: string;
primary: string;
secondary: string;
transport: string;
state: string;
serialDevice?: string;
source: ModbusConnectionSource;
holders: ConnectionHolder[];
connection: ModbusConnection;
}
@@ -120,34 +114,22 @@ export class ModbusConfigDashboard extends LitElement {
);
}
// A YAML hub is a link of its own rather than a hold on a shared
// connection, so the same device can be listed twice
private _secondaryName(connection: ModbusConnection): string {
const transport = this._transportName(connection.endpoint[0]);
if (connection.source !== "yaml") {
return transport;
}
return `${transport}${this.hass.localize(
"ui.panel.config.modbus.configured_in_yaml"
)}`;
}
private _connectionListItem(
connection: ModbusConnection,
entries: Record<string, ConfigEntry>
): ConnectionListItem {
const [transport] = connection.endpoint;
const serialDevice = modbusSerialDevice(connection.endpoint);
return {
icon: serialDevice ? mdiCableData : mdiLan,
primary: modbusEndpointTarget(connection.endpoint),
secondary: this._secondaryName(connection),
transport: this._transportName(transport),
state: this._stateName(connection.connected, serialDevice !== undefined),
serialDevice,
source: connection.source,
holders: Object.entries(connection.units).map(([id, units]) => ({
id,
entry: connection.source === "yaml" ? undefined : entries[id],
holders: Object.entries(connection.units).map(([entryId, units]) => ({
entryId,
entry: entries[entryId],
units,
})),
connection,
@@ -179,20 +161,13 @@ export class ModbusConfigDashboard extends LitElement {
`;
}
private _renderHolder(
holder: ConnectionHolder,
source: ModbusConnectionSource
): TemplateResult {
// A YAML hub is named by the key it is configured under, and an entry
// removed while the connection was listed has nowhere to link to
private _renderHolder(holder: ConnectionHolder): TemplateResult {
// An entry removed while the connection was listed has nowhere to link to
if (!holder.entry) {
return html`
<ha-md-list-item class="holder">
<ha-svg-icon
slot="start"
.path=${source === "yaml" ? mdiFileDocumentOutline : mdiPuzzle}
></ha-svg-icon>
<div slot="headline">${holder.id}</div>
<ha-svg-icon slot="start" .path=${mdiPuzzle}></ha-svg-icon>
<div slot="headline">${holder.entryId}</div>
${this._renderUnits(holder)}
</ha-md-list-item>
`;
@@ -204,7 +179,7 @@ export class ModbusConfigDashboard extends LitElement {
<ha-md-list-item
type="link"
class="holder"
href=${`/config/integrations/integration/${domain}#config_entry=${holder.id}`}
href=${`/config/integrations/integration/${domain}#config_entry=${holder.entryId}`}
>
<img
slot="start"
@@ -259,10 +234,10 @@ export class ModbusConfigDashboard extends LitElement {
<ha-md-list-item class="connection">
<ha-svg-icon slot="start" .path=${item.icon}></ha-svg-icon>
<div slot="headline">${item.primary}</div>
<div slot="supporting-text">${item.secondary}</div>
<div slot="supporting-text">${item.transport}</div>
${this._renderState(item)}
</ha-md-list-item>
${item.holders.map((holder) => this._renderHolder(holder, item.source))}
${item.holders.map((holder) => this._renderHolder(holder))}
${
item.serialDevice && isComponentLoaded(this.hass.config, "usb")
? this._renderSerialPortLink()
@@ -103,7 +103,6 @@ class HaConfigSectionNetwork extends LitElement {
max-width: 600px;
}
.discovery-card ha-md-list {
background: none;
padding-top: 0;
}
`;
@@ -2,7 +2,6 @@ import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import type { HassEntity } from "home-assistant-js-websocket";
import { theme2hex } from "../../../common/color/convert-color";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { createSearchParam } from "../../../common/url/search-params";
@@ -106,22 +105,10 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
}
this._names = {};
this._entities.forEach((entity) => {
// Leave unset so timeline/line charts use computeHistory's Device ▸ Entity
// labels. Only YAML `name` overrides that default.
if (entity.name === undefined) {
return;
}
const stateObj =
this.hass!.states[entity.entity] ??
({
entity_id: entity.entity,
state: "unavailable",
attributes: {},
} as HassEntity);
this._names[entity.entity] = this.hass!.formatEntityName(
stateObj,
entity.name
);
const stateObj = this.hass!.states[entity.entity];
this._names[entity.entity] = stateObj
? this.hass!.formatEntityName(stateObj, entity.name)
: entity.entity;
});
}
@@ -328,7 +315,6 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
const columns = this._config.grid_options?.columns ?? 12;
const narrow = typeof columns === "number" && columns <= 12;
const hasFixedHeight = typeof this._config.grid_options?.rows === "number";
const showNames = this._config.show_names !== false;
return html`
<ha-card>
@@ -374,8 +360,11 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
.names=${this._names}
up-to-now
.hoursToShow=${this._hoursToShow}
.showNames=${showNames}
?inside-labels=${showNames}
.showNames=${
this._config.show_names !== undefined
? this._config.show_names
: true
}
.logarithmicScale=${this._config.logarithmic_scale || false}
.minYAxis=${this._config.min_y_axis}
.maxYAxis=${this._config.max_y_axis}
+15 -24
View File
@@ -1,15 +1,14 @@
import { mdiDotsVertical } from "@mdi/js";
import "@thomasloven/round-slider";
import type { PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { fireEvent } from "../../../common/dom/fire_event";
import { stateColorBrightness } from "../../../common/entity/state_color";
import "../../../components/ha-card";
import "../../../components/ha-control-circular-slider";
import "../../../components/ha-icon-button";
import "../../../components/ha-state-icon";
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity/entity";
@@ -109,14 +108,12 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
<div class="content">
<div id="controls">
<div id="slider">
<ha-control-circular-slider
mode="start"
.min=${1}
.max=${100}
.step=${1}
<!-- @ts-ignore Round-slider has no tag definition or exported type -->
<round-slider
min="1"
max="100"
.value=${brightness}
.disabled=${stateObj.state === UNAVAILABLE}
prevent-interaction-on-scroll
@value-changing=${this._dragEvent}
@value-changed=${this._setBrightness}
style=${styleMap({
@@ -124,7 +121,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
? "visible"
: "hidden",
})}
></ha-control-circular-slider>
></round-slider>
<ha-icon-button
class="light-button ${classMap({
"slider-center": lightSupportsBrightness(stateObj),
@@ -194,10 +191,9 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
}
}
private _dragEvent(ev: HASSDomEvent<HASSDomEvents["value-changing"]>): void {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
this.shadowRoot!.querySelector(".brightness")!.innerHTML = `${value} %`;
private _dragEvent(e: any): void {
this.shadowRoot!.querySelector(".brightness")!.innerHTML =
`${e.detail.value} %`;
this._showBrightness();
this._hideBrightness();
}
@@ -217,14 +213,10 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
}, 500);
}
private _setBrightness(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
): void {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
private _setBrightness(e: any): void {
this.hass!.callService("light", "turn_on", {
entity_id: this._config!.entity,
brightness_pct: value,
brightness_pct: e.detail.value,
});
}
@@ -300,11 +292,10 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
min-width: 100px;
}
ha-control-circular-slider {
width: 100%;
--control-circular-slider-color: var(--primary-color);
--control-circular-slider-background: var(--slider-track-color);
--control-circular-slider-background-opacity: 1;
round-slider {
--round-slider-path-color: var(--slider-track-color);
--round-slider-bar-color: var(--primary-color);
padding-bottom: 10%;
}
.light-button {
+3 -9
View File
@@ -391,19 +391,10 @@ export const getMyRedirects = (): Redirects => ({
component: "hassio",
redirect: "/config/apps/available",
},
supervisor_apps: {
component: "hassio",
redirect: "/config/apps",
},
supervisor_addons: {
component: "hassio",
redirect: "/config/apps",
},
supervisor: {
// Supervisor panel was removed in 2026.2, fallback to apps
component: "hassio",
redirect: "/config/apps",
},
supervisor_app: {
component: "hassio",
redirect: "/config/app",
@@ -440,6 +431,9 @@ export const getMyRedirects = (): Redirects => ({
category: "string?",
},
},
lights: {
redirect: "/lights",
},
});
const getRedirect = (path: string): Redirect | undefined =>
+3 -17
View File
@@ -1,6 +1,4 @@
import { ContextProvider } from "@lit/context";
import type { ConditionDescriptions } from "../data/condition";
import { subscribeConditions } from "../data/condition";
import {
ConfigEntryStream,
type ConfigEntryUpdate,
@@ -36,17 +34,15 @@ import {
userContext,
userDataContext,
} from "../data/context";
import type { ConditionDescriptions } from "../data/condition";
import { subscribeConditions } from "../data/condition";
import { updateHassGroups } from "../data/context/updateContext";
import { subscribeEntityRegistry } from "../data/entity/entity_registry";
import { fetchIntegrationManifestsCollection } from "../data/integration";
import { subscribeLabelRegistry } from "../data/label/label_registry";
import type { TriggerDescriptions } from "../data/trigger";
import { subscribeTriggers } from "../data/trigger";
import type {
Constructor,
HomeAssistant,
HomeAssistantInternationalization,
} from "../types";
import type { Constructor, HomeAssistant } from "../types";
import type { HassBaseEl } from "./hass-base-mixin";
import { LazyContextProvider } from "./lazy-context-provider";
import { RelatedContextProvider } from "./related-context-provider";
@@ -278,16 +274,6 @@ export const contextMixin = <T extends Constructor<HassBaseEl>>(
}
}
// Publishes i18n contexts from a "lite" localize source before a full `hass` exists
// Once `hass` connects it overwrites these values.
protected _provideLiteInternationalization(
value: HomeAssistantInternationalization
) {
this.__hassContextProviderGroups.internationalization!.setValue(value);
this.__contextProviders.localize?.setValue(value.localize);
this.__contextProviders.locale?.setValue(value.locale);
}
public disconnectedCallback() {
super.disconnectedCallback();
for (const provider of Object.values(this.__lazyContextProviders)) {
+1 -11
View File
@@ -1,10 +1,7 @@
import type { Auth, Connection } from "home-assistant-js-websocket";
import { LitElement } from "lit";
import { property } from "lit/decorators";
import type {
HomeAssistant,
HomeAssistantInternationalization,
} from "../types";
import type { HomeAssistant } from "../types";
export class HassBaseEl extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@@ -42,13 +39,6 @@ export class HassBaseEl extends LitElement {
// eslint-disable-next-line @typescript-eslint/no-empty-function
protected checkHttpPendingConfig() {}
// Overridden by contextMixin to publish i18n contexts before `hass` exists.
protected _provideLiteInternationalization(
_value: HomeAssistantInternationalization
): void {
// no-op by default
}
protected hassChanged(hass, _oldHass) {
this.__provideHass.forEach((el) => {
(el as any).hass = hass;
+1 -2
View File
@@ -7665,8 +7665,7 @@
"title": "Modbus",
"status_summary": "{units, plural,\n one {# unit}\n other {# units}\n} on {total, plural,\n one {# connection}\n other {# connections}\n}",
"connections": "Connections",
"connections_description": "Every integration talking to a Modbus device shares one connection to it. A hub configured in YAML keeps a connection of its own.",
"configured_in_yaml": "Configured in YAML",
"connections_description": "Every integration talking to a Modbus device shares one connection to it.",
"state_connected": "Connected",
"state_not_connected": "Not connected",
"state_open": "Open",
@@ -1,4 +1,4 @@
import { describe, expect, it } from "vitest";
import { describe, it, expect } from "vitest";
import { createDurationData } from "../../../src/common/datetime/create_duration_data";
describe("createDurationData", () => {
@@ -17,26 +17,6 @@ describe("createDurationData", () => {
expect(createDurationData("20")).toEqual({
seconds: 20,
});
expect(createDurationData("3:00")).toEqual({
hours: 3,
minutes: 0,
seconds: 0,
milliseconds: 0,
});
});
it("should negate the whole period for a negative string duration", () => {
expect(createDurationData("-1:30:15.001")).toEqual({
hours: -1,
minutes: -30,
seconds: -15,
milliseconds: -1,
});
expect(createDurationData("-20")).toEqual({
seconds: -20,
});
});
it("should return undefined for invalid string duration", () => {
@@ -53,13 +33,19 @@ describe("createDurationData", () => {
expect(createDurationData(1.25)).toEqual({ seconds: 1.25 });
});
it("should return object duration unchanged", () => {
const duration = { hours: 1, minutes: 30 };
expect(createDurationData(duration)).toEqual(duration);
it("should parse object duration without days correctly", () => {
expect(createDurationData({ hours: 1, minutes: 30 })).toEqual({
hours: 1,
minutes: 30,
});
});
it("should keep days in object duration", () => {
const duration = { days: 1, hours: 1 };
expect(createDurationData(duration)).toEqual(duration);
it("should handle days in object duration correctly", () => {
expect(createDurationData({ days: 1, hours: 1 })).toEqual({
hours: 25,
minutes: undefined,
seconds: undefined,
milliseconds: undefined,
});
});
});
@@ -1,226 +0,0 @@
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { HaChooseSelector } from "../../../src/components/ha-selector/ha-selector-choose";
class HaSelectorStub extends HTMLElement {
public hass?: unknown;
public selector?: unknown;
public value?: unknown;
public disabled?: boolean;
public required?: boolean;
public helper?: string;
public localizeValue?: (key: string) => string;
}
// Mock the child selector so its real selector tree cannot start async imports.
vi.mock("../../../src/components/ha-selector/ha-selector", () => {
if (!customElements.get("ha-selector")) {
customElements.define(
"ha-selector",
HaSelectorStub as unknown as CustomElementConstructor
);
}
return { HaSelector: HaSelectorStub };
});
beforeAll(async () => {
// Handle 'setValidity is not a function' on the button group.
Object.defineProperty(HTMLElement.prototype, "attachInternals", {
configurable: true,
value() {
return {
setValidity: () => {
/* empty */
},
setFormValue: () => {
/* empty */
},
checkValidity: () => true,
reportValidity: () => true,
validity: {},
validationMessage: "",
willValidate: true,
};
},
});
await import("../../../src/components/ha-selector/ha-selector-choose");
});
describe("<ha-selector-choose>", () => {
const selector = {
choose: {
choices: {
text: { selector: { text: {} } },
entity: { selector: { entity: {} } },
number: { selector: { number: {} } },
duration: { selector: { duration: {} } },
template: { selector: { template: {} } },
},
},
} as any;
beforeEach(() => {
document.body.innerHTML = "";
});
const waitForSelector = async (element: HaChooseSelector) => {
await element.updateComplete;
};
const createElement = async (value: unknown) => {
const element = document.createElement(
"ha-selector-choose"
) as HaChooseSelector;
element.hass = {} as any;
element.selector = selector;
element.value = value;
document.body.append(element);
await waitForSelector(element);
return element;
};
it("uses value.active_choice as the initial active choice when it exists", async () => {
const element = await createElement({
active_choice: "entity",
entity: "light.kitchen",
});
expect(element._activeChoice).toBe("entity");
const toggleGroup = element.shadowRoot!.querySelector(
"ha-button-toggle-group"
) as HTMLElementTagNameMap["ha-button-toggle-group"];
expect(toggleGroup.active).toBe("entity");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.selector).toEqual(
selector.choose.choices.entity.selector
);
expect(nestedSelector.value).toBe("light.kitchen");
});
it("falls back to the first choice for an undefined initial value", async () => {
const element = await createElement(undefined);
expect(element._activeChoice).toBe("text");
});
it("falls back to text for an initial text value without active_choice", async () => {
const element = await createElement("hello world");
expect(element._activeChoice).toBe("text");
});
it("falls back to entity for an initial entity_id value without active_choice", async () => {
const element = await createElement("sun.sun");
expect(element._activeChoice).toBe("entity");
});
it("changes active choice when a new value specifies a valid active_choice", async () => {
const element = await createElement({
active_choice: "text",
text: "hello",
});
expect(element._activeChoice).toBe("text");
element.value = {
active_choice: "entity",
entity: "light.kitchen",
};
await waitForSelector(element);
expect(element._activeChoice).toBe("entity");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.selector).toEqual(
selector.choose.choices.entity.selector
);
expect(nestedSelector.value).toBe("light.kitchen");
});
it("keeps the active choice when the next value has no active_choice", async () => {
const element = await createElement({
active_choice: "entity",
entity: "light.kitchen",
});
element.value = "plain text";
await waitForSelector(element);
expect(element._activeChoice).toBe("entity");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.selector).toEqual(
selector.choose.choices.entity.selector
);
expect(nestedSelector.value).toBe("plain text");
});
it("does not switch choices when the updated value retains its active_choice", async () => {
const element = await createElement({
active_choice: "entity",
entity: "light.kitchen",
});
element.value = {
active_choice: "entity",
entity: "light.living_room",
};
await waitForSelector(element);
expect(element._activeChoice).toBe("entity");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.value).toBe("light.living_room");
});
it("passes an object without active_choice through to a duration selector", async () => {
const duration = {
hours: 0,
minutes: 5,
seconds: 0,
};
const element = await createElement(duration);
expect(element._activeChoice).toBe("duration");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.selector).toEqual(
selector.choose.choices.duration.selector
);
expect(nestedSelector.value).toEqual(duration);
});
it("passes a template without active_choice through to a template selector", async () => {
const template = "{{ xyz }}";
const element = await createElement(template);
expect(element._activeChoice).toBe("template");
const nestedSelector = element.shadowRoot!.querySelector(
"ha-selector"
) as HTMLElementTagNameMap["ha-selector"];
expect(nestedSelector.selector).toEqual(
selector.choose.choices.template.selector
);
expect(nestedSelector.value).toEqual(template);
});
});
@@ -18,9 +18,14 @@ vi.mock("../../../src/components/ha-dialog", () => {
return {};
});
vi.mock("../../../src/components/ha-button", () => {
customElements.define("ha-button", class extends HTMLElement {});
return {};
vi.mock("../../../src/components/ha-button", async () => {
const lit = await import("lit");
class HaButton extends lit.LitElement {}
customElements.define("ha-button", HaButton);
return { HaButton };
});
vi.mock("../../../src/components/ha-dialog-footer", () => {
+252 -248
View File
@@ -91,25 +91,25 @@ __metadata:
languageName: node
linkType: hard
"@babel/compat-data@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/compat-data@npm:8.0.5"
checksum: 10/c1bedf2ee94c7bf8b18f7672dba651791ef0908596c4300f006804b23b5833132a16c210187848b92fd86c36a04aaff1ea2810ae20a319438763dd679704fc89
"@babel/compat-data@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/compat-data@npm:8.0.0"
checksum: 10/83b1776ecfdaf02559a4b4fb2f4a2c5e6ba8a2b41bf898807caaf863379ee9c8e91c163de71e79d73eb68659b58bcb18cbcff9a39aae6f88c106af680619326c
languageName: node
linkType: hard
"@babel/core@npm:8.0.5":
version: 8.0.5
resolution: "@babel/core@npm:8.0.5"
"@babel/core@npm:8.0.1":
version: 8.0.1
resolution: "@babel/core@npm:8.0.1"
dependencies:
"@babel/code-frame": "npm:^8.0.0"
"@babel/generator": "npm:^8.0.5"
"@babel/helper-compilation-targets": "npm:^8.0.5"
"@babel/helpers": "npm:^8.0.5"
"@babel/parser": "npm:^8.0.5"
"@babel/generator": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.0"
"@babel/helpers": "npm:^8.0.0"
"@babel/parser": "npm:^8.0.0"
"@babel/template": "npm:^8.0.0"
"@babel/traverse": "npm:^8.0.5"
"@babel/types": "npm:^8.0.5"
"@babel/traverse": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
"@types/gensync": "npm:^1.0.5"
convert-source-map: "npm:^2.0.0"
empathic: "npm:^2.0.1"
@@ -117,8 +117,8 @@ __metadata:
import-meta-resolve: "npm:^4.2.0"
json5: "npm:^2.2.3"
obug: "npm:^2.1.1"
verkit: "npm:^0.3.2"
checksum: 10/655ab58882afecbbe0fb8d6cef5a571b72b8c593b248dd9b2fd7c2b831fd6ab79c2f13451e1d2873d62cf6a6ccf626b4f6485d08ff30442a81df8b61ee02645f
semver: "npm:^7.7.3"
checksum: 10/def06f2ddcb0cf6872ccbd72742d21b16c4af1eee01b5aae800b4456e03ef50a3f8e976c09158b1a684d0c3f09b6c9a1c1bed65cc15390f0d8abbbe3c9516a28
languageName: node
linkType: hard
@@ -158,17 +158,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/generator@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/generator@npm:8.0.5"
"@babel/generator@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/generator@npm:8.0.0"
dependencies:
"@babel/parser": "npm:^8.0.5"
"@babel/types": "npm:^8.0.5"
"@jridgewell/gen-mapping": "npm:0.4.0-beta.0"
"@jridgewell/trace-mapping": "npm:^0.3.31"
"@babel/parser": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
"@jridgewell/gen-mapping": "npm:^0.3.12"
"@jridgewell/trace-mapping": "npm:^0.3.28"
"@types/jsesc": "npm:^2.5.0"
jsesc: "npm:^3.0.2"
checksum: 10/750f3f74ae05aea0978d19e80bb4b2c5343b523ef90768b3e68ab103c07dae26524d591a5195c06d6886bc7e088ba861216d08602df14a625e7b0e169a1958a2
checksum: 10/8d9b801886b4bbe46b101768abae0ffa1c9435601a8788358331c115b1a38a7c5acdd0e8b85b4d0c00806b0b74a0cc0e75ef50647f7322ffa3646a238e1b5420
languageName: node
linkType: hard
@@ -203,16 +203,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-compilation-targets@npm:^8.0.0, @babel/helper-compilation-targets@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/helper-compilation-targets@npm:8.0.5"
"@babel/helper-compilation-targets@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/helper-compilation-targets@npm:8.0.0"
dependencies:
"@babel/compat-data": "npm:^8.0.5"
"@babel/compat-data": "npm:^8.0.0"
"@babel/helper-validator-option": "npm:^8.0.0"
browserslist: "npm:^4.24.0"
lru-cache: "npm:^11.0.0"
verkit: "npm:^0.3.2"
checksum: 10/49775a5b74e84b83f99392d85016a604227894a8face3e2d9209074c8db6b9b1442c00397fc0029585de88b00bacc40302465462c68041563d0fb2d1ad9aaebb
semver: "npm:^7.7.3"
checksum: 10/2814f178f119887abe5221fb6178f62f1adfec9561a915aa67ca65f5ece8d6f1ee83ed731a3e335065d579c1f3c73fc4fdbf83a70fa4ea0113b8932f173b2262
languageName: node
linkType: hard
@@ -233,20 +233,20 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-create-class-features-plugin@npm:^8.0.1, @babel/helper-create-class-features-plugin@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/helper-create-class-features-plugin@npm:8.0.5"
"@babel/helper-create-class-features-plugin@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/helper-create-class-features-plugin@npm:8.0.1"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-member-expression-to-functions": "npm:^8.0.5"
"@babel/helper-member-expression-to-functions": "npm:^8.0.0"
"@babel/helper-optimise-call-expression": "npm:^8.0.0"
"@babel/helper-replace-supers": "npm:^8.0.1"
"@babel/helper-skip-transparent-expression-wrappers": "npm:^8.0.0"
"@babel/traverse": "npm:^8.0.5"
verkit: "npm:^0.3.2"
"@babel/traverse": "npm:^8.0.0"
semver: "npm:^7.7.3"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/fec84233555462d62c1c28b6683bf5ace0c93f7a6e6494945e75df5946fb0472f88a5b086cad8706941801ac06a0dc341a7d2a38a6275ba190f89e64589c3e6b
checksum: 10/97d111c4b06da821d4cbd4c8439b7ba9614faaf6a7e565df14660b9a2f8f39aae6b903c07c3f34288ff44ca1c8f95b782430f4ab7afce8a5a0fdd72af914d553
languageName: node
linkType: hard
@@ -328,13 +328,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-member-expression-to-functions@npm:^8.0.0, @babel/helper-member-expression-to-functions@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/helper-member-expression-to-functions@npm:8.0.5"
"@babel/helper-member-expression-to-functions@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/helper-member-expression-to-functions@npm:8.0.0"
dependencies:
"@babel/traverse": "npm:^8.0.5"
"@babel/types": "npm:^8.0.5"
checksum: 10/a8e4ca0275aba747e8c26253040c8b8429e015a4065adb9dd7342b3e52bd537d986104b044b9b409a6f6dd674f9865e09b54c292b5ed0ff0630f1c714e809ae3
"@babel/traverse": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
checksum: 10/ec4ab0494f3500a69b4b85034eb03e82941e2e0140f5608b51cdccb5586426d573939e06489714d7d7c0b6cb6585cb71fde7a8d51e1c0bb82dabf917acb094ad
languageName: node
linkType: hard
@@ -564,13 +564,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helpers@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/helpers@npm:8.0.5"
"@babel/helpers@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/helpers@npm:8.0.0"
dependencies:
"@babel/template": "npm:^8.0.0"
"@babel/types": "npm:^8.0.5"
checksum: 10/56adcdcfcff33adcc4ce57633a20ba4d7fac7618cdae544ce8828291ab47c936d6cda4c6f5e364385b5e525b6415ea8dda061c6a11ce7eabc2df109e4ce557c5
"@babel/types": "npm:^8.0.0"
checksum: 10/129fca6e339022059028b7189c9cb6907ed813233ef335d8636a82b927282fea022970fc4da33bc575d6dbb8900ca550c5dcaaae84f7265c4808e8514ec81339
languageName: node
linkType: hard
@@ -585,14 +585,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/parser@npm:^8.0.0, @babel/parser@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/parser@npm:8.0.5"
"@babel/parser@npm:^8.0.0, @babel/parser@npm:^8.0.4":
version: 8.0.4
resolution: "@babel/parser@npm:8.0.4"
dependencies:
"@babel/types": "npm:^8.0.5"
"@babel/types": "npm:^8.0.4"
bin:
parser: ./bin/babel-parser.js
checksum: 10/3e58342925f3729e1e4bd144af0718b160a337c3427608555768b6aa3319b89be9b8573dd5e0d0c0ee4c5b35f62f16036f28dd43ccdf9b181f55c3e35eb94735
checksum: 10/230554794a2c296ce1fb60f57459d94903802369e14e1d83c3ea266b64a4f88ab292eadf5213823d87c04541c9c43b8b6daaae919f25551d3637800663fb25bf
languageName: node
linkType: hard
@@ -675,15 +675,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:8.0.5"
"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/helper-skip-transparent-expression-wrappers": "npm:^8.0.0"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/df5440172fab0c7ee2f8bd973dc947379b3b618ec7abe804282b304a807e09a6d1e67e79b5b7b841d0e79ad2de2522cb344bb3a7f4e5b9b48430ad1b72ead9db
checksum: 10/795b63579f39b7699655c3fc90d8f855181a365db174a475c4e69fdd6ad2059ed9a9c34975c1300e52faddd2a70b332f6171936960eb7501452237a19968be31
languageName: node
linkType: hard
@@ -886,14 +886,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-block-scoping@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-block-scoping@npm:8.0.5"
"@babel/plugin-transform-block-scoping@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-block-scoping@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/26efc50c4f9042f502a929de6619ce756fe092d1b56176d1f797ab711590f6ea47f8521927821d5629889a8cc1187645d6a08ab912aa250bc3607299e4dfcf09
checksum: 10/9f922f531974f8a8484a50705bc43baf69bf231afc663e6a7100a4e7c3b7c8242901a2f760dc7714dd13b986760679d33d04733c0c3c411ce2e8113b2ef4ad41
languageName: node
linkType: hard
@@ -933,15 +933,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-class-static-block@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-class-static-block@npm:8.0.5"
"@babel/plugin-transform-class-static-block@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-class-static-block@npm:8.0.1"
dependencies:
"@babel/helper-create-class-features-plugin": "npm:^8.0.5"
"@babel/helper-create-class-features-plugin": "npm:^8.0.1"
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/cebde27ab9f26b237e34ca77bd28b4b61600dfaefcb258f132cc5589f7ee009d8ab0323fba868b29758ad865b42e4bbcc485a2646815ee6b94600e8d5945712d
checksum: 10/b927af27b34b3d3e54ce51af1af5ea47ddb2a2a1537341153556452996cf58f67e04cd27734947b197224e05c8b1b673247ad2b729b19927c911870b15f0a478
languageName: node
linkType: hard
@@ -961,19 +961,19 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-classes@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-classes@npm:8.0.5"
"@babel/plugin-transform-classes@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-classes@npm:8.0.1"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.5"
"@babel/helper-compilation-targets": "npm:^8.0.0"
"@babel/helper-globals": "npm:^8.0.0"
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/helper-replace-supers": "npm:^8.0.1"
"@babel/traverse": "npm:^8.0.5"
"@babel/traverse": "npm:^8.0.0"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/2fc6df7ef5d3c46a9cdf9a0feae69b543de16af16972d9833db04499c9a49257809a305a39a0757d8325424d1670555fa9055274a0060bccb4a07fddf4387604
checksum: 10/605b6d19ce75b6c40484b4ad6de49fc6ab2efaf71e56982c6b712c5d7d3598e6fd334a40c389418416425b295684763f4912af5f75a8005011200372ec23f3c1
languageName: node
linkType: hard
@@ -1012,14 +1012,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-destructuring@npm:^8.0.1, @babel/plugin-transform-destructuring@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-destructuring@npm:8.0.5"
"@babel/plugin-transform-destructuring@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-destructuring@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/ee5ca59cf5a9dea20bc615c305b6dffd3e195ce75dfa1dd5a7dab5fdfb28687fb27da5888d9fae320296818eb651fb8f8e54abee0512b5f85dbf035ea47269b0
checksum: 10/0943cf0b04d532576b865f75dc96dc24474550f554bdf43d2f9d6406eae99b76c6a70cdfdeac2f206d1e42cce26a4378679e2828c5d4c5e0155fef064152612e
languageName: node
linkType: hard
@@ -1127,15 +1127,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-explicit-resource-management@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-explicit-resource-management@npm:8.0.5"
"@babel/plugin-transform-explicit-resource-management@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-explicit-resource-management@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.5"
"@babel/plugin-transform-destructuring": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/b9bc20dff616168fe45ee1aadaa7b03cff004a19ad1d8e19d72b5920d6b4996311ce155d87f52e473743d456c599bac90bae0098210b888a06a1edbb23c11791
checksum: 10/45f849f44927ffc0e57fb2723173a0717f1458584d51f3b94f8bd6cab73d7e73e60613bf704c2358ceb4eeee9c54bb93a7bd8ca4ce064469be58f90c88d7b3d8
languageName: node
linkType: hard
@@ -1596,15 +1596,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-optional-chaining@npm:^8.0.1, @babel/plugin-transform-optional-chaining@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-optional-chaining@npm:8.0.5"
"@babel/plugin-transform-optional-chaining@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-optional-chaining@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/helper-skip-transparent-expression-wrappers": "npm:^8.0.0"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/35561003194fcbb21fb1e24777793fed729fbfbb24670b005e450923c3af3ac4799ef7ef7bb4ce14e41aef39c0f695209656537d43174556f43bc77362d92afb
checksum: 10/0098572efbf897678ba2e58cdf53fabb699bffe7c90c6be83879e1b799e167306e406ae03721656e51d333cca037b60e643ad2fbba82c4738af09d709973cc64
languageName: node
linkType: hard
@@ -1619,14 +1619,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-parameters@npm:^8.0.1, @babel/plugin-transform-parameters@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-parameters@npm:8.0.5"
"@babel/plugin-transform-parameters@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-parameters@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/9c1f1ea54e5212f8d10e7f5698409da6658e8762056a70c8000266cb79feb0a6b83809cf2a897df0dc1fa14f42d5451f6059ffc050a67ad91b6b4c4bd4abb647
checksum: 10/0ad77e2a72b9f2882983a38367b149c0abe7867cc3503ac4eec96b6f192e51e23f9e37f60daf3caf54d81d3767b85609f51a509554ed4de2982cc17bd6eb5115
languageName: node
linkType: hard
@@ -1667,16 +1667,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-private-property-in-object@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-private-property-in-object@npm:8.0.5"
"@babel/plugin-transform-private-property-in-object@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-private-property-in-object@npm:8.0.1"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-create-class-features-plugin": "npm:^8.0.5"
"@babel/helper-create-class-features-plugin": "npm:^8.0.1"
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/55fc5edc56808125d3c2fe813f7d41cdf1287e56f7b11a0b2a2db46d01274200a3258f80c9319040e7c52c40378eeac59efde5200c6eb1bf1e70a42d098f7901
checksum: 10/70d921b70726cb68770d1dfc0b72b58c3bbeacd9b9ff06cd9b81618430cf2e312410c489c506001c78e35a069c15fff7e6bcee5531120e3d69cd6c2074eaa315
languageName: node
linkType: hard
@@ -1713,14 +1713,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-regenerator@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-regenerator@npm:8.0.5"
"@babel/plugin-transform-regenerator@npm:^8.0.2":
version: 8.0.2
resolution: "@babel/plugin-transform-regenerator@npm:8.0.2"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/290cad28d2f9370af9b9da3a6d11454739e9630ada216dfeb390f39c20f192a567ffc96d9e6dddaab85649c71f7424c43f75a50423d39b04ad2cc17dc3924932
checksum: 10/81b865156ef174acad44fb589f4cc01f912148a907dfa9a30a6669504e9218c40ad7bee98b33149d3a9a1dc2b5659405765bc07598ae41084b9f5258322ac153
languageName: node
linkType: hard
@@ -1816,15 +1816,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-spread@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-spread@npm:8.0.5"
"@babel/plugin-transform-spread@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-spread@npm:8.0.1"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/helper-skip-transparent-expression-wrappers": "npm:^8.0.0"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/502942686a85fb5536a7b44d64d3597442100132d861239541a50a5b38058c0a6d0ae0252099b20b204ad0783eefc68acf30a54c3a5c1c5e52a2ab6170e29966
checksum: 10/3487febd0eda7988f0538dd0fc683574b5c4a6551ad3625e453adec0f58617bb0b4cd93223a9659850d23d2da30d7a3ab14a94eae01771c0bcde672953595e4a
languageName: node
linkType: hard
@@ -1988,35 +1988,35 @@ __metadata:
languageName: node
linkType: hard
"@babel/preset-env@npm:8.0.5":
version: 8.0.5
resolution: "@babel/preset-env@npm:8.0.5"
"@babel/preset-env@npm:8.0.2":
version: 8.0.2
resolution: "@babel/preset-env@npm:8.0.2"
dependencies:
"@babel/compat-data": "npm:^8.0.5"
"@babel/helper-compilation-targets": "npm:^8.0.5"
"@babel/compat-data": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.0"
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/helper-validator-option": "npm:^8.0.0"
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^8.0.1"
"@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^8.0.1"
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^8.0.1"
"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "npm:^8.0.5"
"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "npm:^8.0.1"
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^8.0.1"
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^8.0.1"
"@babel/plugin-transform-arrow-functions": "npm:^8.0.1"
"@babel/plugin-transform-async-generator-functions": "npm:^8.0.1"
"@babel/plugin-transform-async-to-generator": "npm:^8.0.1"
"@babel/plugin-transform-block-scoped-functions": "npm:^8.0.1"
"@babel/plugin-transform-block-scoping": "npm:^8.0.5"
"@babel/plugin-transform-block-scoping": "npm:^8.0.1"
"@babel/plugin-transform-class-properties": "npm:^8.0.1"
"@babel/plugin-transform-class-static-block": "npm:^8.0.5"
"@babel/plugin-transform-classes": "npm:^8.0.5"
"@babel/plugin-transform-class-static-block": "npm:^8.0.1"
"@babel/plugin-transform-classes": "npm:^8.0.1"
"@babel/plugin-transform-computed-properties": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.5"
"@babel/plugin-transform-destructuring": "npm:^8.0.1"
"@babel/plugin-transform-dotall-regex": "npm:^8.0.1"
"@babel/plugin-transform-duplicate-keys": "npm:^8.0.1"
"@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^8.0.1"
"@babel/plugin-transform-dynamic-import": "npm:^8.0.1"
"@babel/plugin-transform-explicit-resource-management": "npm:^8.0.5"
"@babel/plugin-transform-explicit-resource-management": "npm:^8.0.1"
"@babel/plugin-transform-exponentiation-operator": "npm:^8.0.1"
"@babel/plugin-transform-export-namespace-from": "npm:^8.0.1"
"@babel/plugin-transform-for-of": "npm:^8.0.1"
@@ -2036,16 +2036,16 @@ __metadata:
"@babel/plugin-transform-object-rest-spread": "npm:^8.0.1"
"@babel/plugin-transform-object-super": "npm:^8.0.1"
"@babel/plugin-transform-optional-catch-binding": "npm:^8.0.1"
"@babel/plugin-transform-optional-chaining": "npm:^8.0.5"
"@babel/plugin-transform-parameters": "npm:^8.0.5"
"@babel/plugin-transform-optional-chaining": "npm:^8.0.1"
"@babel/plugin-transform-parameters": "npm:^8.0.1"
"@babel/plugin-transform-private-methods": "npm:^8.0.1"
"@babel/plugin-transform-private-property-in-object": "npm:^8.0.5"
"@babel/plugin-transform-private-property-in-object": "npm:^8.0.1"
"@babel/plugin-transform-property-literals": "npm:^8.0.1"
"@babel/plugin-transform-regenerator": "npm:^8.0.5"
"@babel/plugin-transform-regenerator": "npm:^8.0.2"
"@babel/plugin-transform-regexp-modifiers": "npm:^8.0.1"
"@babel/plugin-transform-reserved-words": "npm:^8.0.1"
"@babel/plugin-transform-shorthand-properties": "npm:^8.0.1"
"@babel/plugin-transform-spread": "npm:^8.0.5"
"@babel/plugin-transform-spread": "npm:^8.0.1"
"@babel/plugin-transform-sticky-regex": "npm:^8.0.1"
"@babel/plugin-transform-template-literals": "npm:^8.0.1"
"@babel/plugin-transform-typeof-symbol": "npm:^8.0.1"
@@ -2056,10 +2056,10 @@ __metadata:
"@babel/preset-modules": "npm:^0.2.0"
babel-plugin-polyfill-corejs3: "npm:^1.0.0"
core-js-compat: "npm:^3.48.0"
verkit: "npm:^0.3.2"
semver: "npm:^7.7.3"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/4bd1d0cebad897bbe501c299231daaa7971516da200fc47536e999212c6e49f3c82818f445afc9376302c0ee2ef1ef54f364643ed4f91a601d16e1d23cd8d294
checksum: 10/58afb0d1c8583c27eaf1d9c6f57704cd8f58f16e7687af2b2012cea0375189f5e296132b6eb2516f96a70a999d657411adcbf8a9743b62e2f70b599be6208a44
languageName: node
linkType: hard
@@ -2172,10 +2172,10 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:8.0.5":
version: 8.0.5
resolution: "@babel/runtime@npm:8.0.5"
checksum: 10/f54e8051ff2c2b7b21b0c3a6b668799a6d033fb3f4edffdcb78928985b15def38b515ecabac477abb04485346328331b2cd0effd892503737773164203604d76
"@babel/runtime@npm:8.0.0":
version: 8.0.0
resolution: "@babel/runtime@npm:8.0.0"
checksum: 10/1aa5079d7d22d0b7eab30596e85b8c7d4a1003166ff4bb5fffadbc779b24c1acf8a08007e7afadd73191ed67b8249da66c5a2b5df29396f975e58c7df952d1a7
languageName: node
linkType: hard
@@ -2223,18 +2223,18 @@ __metadata:
languageName: node
linkType: hard
"@babel/traverse@npm:^8.0.0, @babel/traverse@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/traverse@npm:8.0.5"
"@babel/traverse@npm:^8.0.0":
version: 8.0.4
resolution: "@babel/traverse@npm:8.0.4"
dependencies:
"@babel/code-frame": "npm:^8.0.0"
"@babel/generator": "npm:^8.0.5"
"@babel/generator": "npm:^8.0.0"
"@babel/helper-globals": "npm:^8.0.0"
"@babel/parser": "npm:^8.0.5"
"@babel/parser": "npm:^8.0.4"
"@babel/template": "npm:^8.0.0"
"@babel/types": "npm:^8.0.5"
"@babel/types": "npm:^8.0.4"
obug: "npm:^2.1.1"
checksum: 10/8827cfd21c3523d370377e8e0360f76c3590a9c6c6d731699aa495697cf8f12abcf475d11130e0c962187d0b1be0d8e55f950a1c4d0ed07780d12d0af82c0ada
checksum: 10/234bc16c8c14af13e9471141bfd371186bb7fd2c347b1b416c46040e6fc1995242e3852d36181fa7a0240543b8d642a91d33261f942880584c87a7420df7247d
languageName: node
linkType: hard
@@ -2248,13 +2248,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/types@npm:^8.0.0, @babel/types@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/types@npm:8.0.5"
"@babel/types@npm:^8.0.0, @babel/types@npm:^8.0.4":
version: 8.0.4
resolution: "@babel/types@npm:8.0.4"
dependencies:
"@babel/helper-string-parser": "npm:^8.0.0"
"@babel/helper-validator-identifier": "npm:^8.0.4"
checksum: 10/ef05d52ad29993af2513ba5a6d6df4187a33d366241090e5994cc139f527d1f207fdc828302f5cc2f68fc2585dfe93abd8b47941c225b70ac4317df7ce875519
checksum: 10/7b58bdb4c9149fb5ea6a272912f8cd8af082939a9fc97c6de126299b38f258dd9f78717f7cad3c7fe8bfa7d1fce4cff5fa26b0e80885935255fd3a062e9296ad
languageName: node
linkType: hard
@@ -3315,16 +3315,6 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/gen-mapping@npm:0.4.0-beta.0":
version: 0.4.0-beta.0
resolution: "@jridgewell/gen-mapping@npm:0.4.0-beta.0"
dependencies:
"@jridgewell/sourcemap-codec": "npm:^1.6.0-beta.0"
"@jridgewell/trace-mapping": "npm:^0.3.24"
checksum: 10/57be5567be163d42aaf95db0fc31d7191d623b3718933f0d17e847d039cf206eab6a3b83adba0411d0cee4ad7660660cf50c92572bf7d8bbd7d87b31a3aa1290
languageName: node
linkType: hard
"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.13
resolution: "@jridgewell/gen-mapping@npm:0.3.13"
@@ -3362,10 +3352,10 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5, @jridgewell/sourcemap-codec@npm:^1.6.0-beta.0":
version: 1.6.0
resolution: "@jridgewell/sourcemap-codec@npm:1.6.0"
checksum: 10/eb53fbf7eb4051302a599d6b91425f381168b2856f321336fb00852cea1e0c1904af2610c157b1535e94a61caa98f0bd068d1d0394dd46adf9e9c45c4e11af91
"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5":
version: 1.5.5
resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
checksum: 10/5d9d207b462c11e322d71911e55e21a4e2772f71ffe8d6f1221b8eb5ae6774458c1d242f897fb0814e8714ca9a6b498abfa74dfe4f434493342902b1a48b33a5
languageName: node
linkType: hard
@@ -4606,10 +4596,10 @@ __metadata:
languageName: node
linkType: hard
"@oxc-project/types@npm:=0.149.0":
version: 0.149.0
resolution: "@oxc-project/types@npm:0.149.0"
checksum: 10/6bd7b656ecdbfa96eea3ca0d79264ad367f941eaec1c47883b7c763a300ac81750de23862089b959b0c9a865abd171145d639368294a9daab0d47df07b1f8c6e
"@oxc-project/types@npm:=0.148.0":
version: 0.148.0
resolution: "@oxc-project/types@npm:0.148.0"
checksum: 10/835b0479161cd80c7dee653b77d31f6d5239e20530cda8a10466bcbb17de08363777939c29670e82fb9d9eca89dc49030e50742051418d987ec70f62faa3317b
languageName: node
linkType: hard
@@ -4635,107 +4625,107 @@ __metadata:
languageName: node
linkType: hard
"@rolldown/binding-android-arm-eabi@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-android-arm-eabi@npm:1.2.8"
"@rolldown/binding-android-arm-eabi@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-android-arm-eabi@npm:1.2.7"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"@rolldown/binding-android-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-android-arm64@npm:1.2.8"
"@rolldown/binding-android-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-android-arm64@npm:1.2.7"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-darwin-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-darwin-arm64@npm:1.2.8"
"@rolldown/binding-darwin-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-darwin-arm64@npm:1.2.7"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-darwin-x64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-darwin-x64@npm:1.2.8"
"@rolldown/binding-darwin-x64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-darwin-x64@npm:1.2.7"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rolldown/binding-freebsd-x64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-freebsd-x64@npm:1.2.8"
"@rolldown/binding-freebsd-x64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-freebsd-x64@npm:1.2.7"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
"@rolldown/binding-linux-arm-gnueabihf@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.2.8"
"@rolldown/binding-linux-arm-gnueabihf@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.2.7"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@rolldown/binding-linux-arm64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.2.8"
"@rolldown/binding-linux-arm64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.2.7"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-arm64-musl@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm64-musl@npm:1.2.8"
"@rolldown/binding-linux-arm64-musl@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm64-musl@npm:1.2.7"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rolldown/binding-linux-ppc64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.2.8"
"@rolldown/binding-linux-ppc64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.2.7"
conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-s390x-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.2.8"
"@rolldown/binding-linux-s390x-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.2.7"
conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-x64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-x64-gnu@npm:1.2.8"
"@rolldown/binding-linux-x64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-x64-gnu@npm:1.2.7"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-x64-musl@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-x64-musl@npm:1.2.8"
"@rolldown/binding-linux-x64-musl@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-x64-musl@npm:1.2.7"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rolldown/binding-openharmony-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-openharmony-arm64@npm:1.2.8"
"@rolldown/binding-openharmony-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-openharmony-arm64@npm:1.2.7"
conditions: os=openharmony & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-win32-arm64-msvc@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.2.8"
"@rolldown/binding-win32-arm64-msvc@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.2.7"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-win32-x64-msvc@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-win32-x64-msvc@npm:1.2.8"
"@rolldown/binding-win32-x64-msvc@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-win32-x64-msvc@npm:1.2.7"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@@ -5655,6 +5645,26 @@ __metadata:
languageName: node
linkType: hard
"@thomasloven/round-slider@npm:0.6.0":
version: 0.6.0
resolution: "@thomasloven/round-slider@npm:0.6.0"
dependencies:
lit: "npm:^2.0.0-rc.2"
tslib: "npm:^2.2.0"
checksum: 10/0430009230daa0720b5520e96fad0ebcd7d200200279bd8a300bb7a98bb47b38c6feae3459d57b91d42f958742a5cb4b3ad34aa29b0e55934b660f6fc126da36
languageName: node
linkType: hard
"@thomasloven/round-slider@patch:@thomasloven/round-slider@npm%3A0.6.0#~/.yarn/patches/@thomasloven-round-slider-npm-0.6.0-d7176d9db7.patch":
version: 0.6.0
resolution: "@thomasloven/round-slider@patch:@thomasloven/round-slider@npm%3A0.6.0#~/.yarn/patches/@thomasloven-round-slider-npm-0.6.0-d7176d9db7.patch::version=0.6.0&hash=f6a9fe"
dependencies:
lit: "npm:^2.0.0-rc.2"
tslib: "npm:^2.2.0"
checksum: 10/3762f6cdfc935b4bd9073b6379586147017fd0a9e5cdcc39d7a526fb436f81be54461a3da26f9fe6be716954be3c3b5039aa2acaf7ae8258cfb968d64965a5f2
languageName: node
linkType: hard
"@tokenizer/token@npm:^0.3.0":
version: 0.3.0
resolution: "@tokenizer/token@npm:0.3.0"
@@ -10350,11 +10360,11 @@ __metadata:
resolution: "home-assistant-frontend@workspace:."
dependencies:
"@ampproject/remapping": "npm:2.3.0"
"@babel/core": "npm:8.0.5"
"@babel/core": "npm:8.0.1"
"@babel/helper-define-polyfill-provider": "npm:1.0.0"
"@babel/plugin-transform-runtime": "npm:8.0.1"
"@babel/preset-env": "npm:8.0.5"
"@babel/runtime": "npm:8.0.5"
"@babel/preset-env": "npm:8.0.2"
"@babel/runtime": "npm:8.0.0"
"@braintree/sanitize-url": "npm:7.1.2"
"@bundle-stats/plugin-webpack-filter": "npm:4.22.3"
"@codemirror/autocomplete": "npm:6.20.3"
@@ -10411,6 +10421,7 @@ __metadata:
"@rspack/core": "npm:2.2.3"
"@rspack/dev-server": "npm:2.2.1"
"@swc/helpers": "npm:0.5.23"
"@thomasloven/round-slider": "patch:@thomasloven/round-slider@npm%3A0.6.0#~/.yarn/patches/@thomasloven-round-slider-npm-0.6.0-d7176d9db7.patch"
"@tsparticles/engine": "npm:4.4.0"
"@tsparticles/preset-links": "npm:4.4.0"
"@types/babel__plugin-transform-runtime": "npm:7.9.5"
@@ -10475,12 +10486,12 @@ __metadata:
intl-messageformat: "npm:11.2.14"
js-yaml: "npm:5.4.1"
jsdom: "npm:30.0.1"
jszip: "npm:3.10.2"
jszip: "npm:3.10.1"
leaflet: "npm:1.9.4"
leaflet.markercluster: "npm:1.5.3"
license-checker-rseidelsohn: "npm:5.0.1"
lightningcss: "npm:1.33.0"
lint-staged: "npm:17.5.1"
lint-staged: "npm:17.5.0"
lit: "npm:3.3.3"
lit-analyzer: "npm:2.0.3"
lit-html: "npm:3.3.3"
@@ -10513,7 +10524,7 @@ __metadata:
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:6.0.3"
typescript-eslint: "npm:8.70.0"
vite: "npm:8.3.0"
vite: "npm:8.2.2"
vite-tsconfig-paths: "npm:6.1.1"
vitest: "npm:5.0.0"
webpack-stats-plugin: "npm:1.1.3"
@@ -11594,15 +11605,15 @@ __metadata:
languageName: node
linkType: hard
"jszip@npm:3.10.2":
version: 3.10.2
resolution: "jszip@npm:3.10.2"
"jszip@npm:3.10.1":
version: 3.10.1
resolution: "jszip@npm:3.10.1"
dependencies:
lie: "npm:~3.3.0"
pako: "npm:~1.0.2"
readable-stream: "npm:~2.3.6"
setimmediate: "npm:^1.0.5"
checksum: 10/86666f57397df56a29968e5cbf25a6b50a4812ab7258e1165ae907e6d3b442e84290cd5eefa9cdd4298653009ebe4599dae17f3de30050e4bf4a5e54462fdfd6
checksum: 10/bfbfbb9b0a27121330ac46ab9cdb3b4812433faa9ba4a54742c87ca441e31a6194ff70ae12acefa5fe25406c432290e68003900541d948a169b23d30c34dd984
languageName: node
linkType: hard
@@ -11882,9 +11893,9 @@ __metadata:
languageName: node
linkType: hard
"lint-staged@npm:17.5.1":
version: 17.5.1
resolution: "lint-staged@npm:17.5.1"
"lint-staged@npm:17.5.0":
version: 17.5.0
resolution: "lint-staged@npm:17.5.0"
dependencies:
picomatch: "npm:^4.0.7"
string-argv: "npm:^0.3.2"
@@ -11895,7 +11906,7 @@ __metadata:
optional: true
bin:
lint-staged: bin/lint-staged.js
checksum: 10/2e10b821214eafce576e8505d6b5cee3a83dd40d68b2d3705b0c69abe35a26e3ad3fcd9cc8379bab47c3e5b3cb8042923d8fbe42e7f72b28da54e6c7d4b4986a
checksum: 10/3ca6263488ae3e8e4915e5c6ee70bb3b54bbffcb7e84dd2fb05c02032563401e5bb41c3d216cdc43933c6d6ff3ed66319d22c5cb5c63727e00af966b95929516
languageName: node
linkType: hard
@@ -13366,7 +13377,7 @@ __metadata:
languageName: node
linkType: hard
"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4, picomatch@npm:^4.0.7":
"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4, picomatch@npm:^4.0.5, picomatch@npm:^4.0.7":
version: 4.0.7
resolution: "picomatch@npm:4.0.7"
checksum: 10/66e1df34bc39c72fa3756be4069f7887ea3e35e94bba1c3f6167763007698cb04b8a0a365161d186fda6e9571a2d3efb606b2966eb6a7dea6252911224dc2f48
@@ -13467,7 +13478,7 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:^8.5.28":
"postcss@npm:^8.5.26":
version: 8.5.28
resolution: "postcss@npm:8.5.28"
dependencies:
@@ -14045,26 +14056,26 @@ __metadata:
languageName: node
linkType: hard
"rolldown@npm:~1.2.6":
version: 1.2.8
resolution: "rolldown@npm:1.2.8"
"rolldown@npm:~1.2.4":
version: 1.2.7
resolution: "rolldown@npm:1.2.7"
dependencies:
"@oxc-project/types": "npm:=0.149.0"
"@rolldown/binding-android-arm-eabi": "npm:1.2.8"
"@rolldown/binding-android-arm64": "npm:1.2.8"
"@rolldown/binding-darwin-arm64": "npm:1.2.8"
"@rolldown/binding-darwin-x64": "npm:1.2.8"
"@rolldown/binding-freebsd-x64": "npm:1.2.8"
"@rolldown/binding-linux-arm-gnueabihf": "npm:1.2.8"
"@rolldown/binding-linux-arm64-gnu": "npm:1.2.8"
"@rolldown/binding-linux-arm64-musl": "npm:1.2.8"
"@rolldown/binding-linux-ppc64-gnu": "npm:1.2.8"
"@rolldown/binding-linux-s390x-gnu": "npm:1.2.8"
"@rolldown/binding-linux-x64-gnu": "npm:1.2.8"
"@rolldown/binding-linux-x64-musl": "npm:1.2.8"
"@rolldown/binding-openharmony-arm64": "npm:1.2.8"
"@rolldown/binding-win32-arm64-msvc": "npm:1.2.8"
"@rolldown/binding-win32-x64-msvc": "npm:1.2.8"
"@oxc-project/types": "npm:=0.148.0"
"@rolldown/binding-android-arm-eabi": "npm:1.2.7"
"@rolldown/binding-android-arm64": "npm:1.2.7"
"@rolldown/binding-darwin-arm64": "npm:1.2.7"
"@rolldown/binding-darwin-x64": "npm:1.2.7"
"@rolldown/binding-freebsd-x64": "npm:1.2.7"
"@rolldown/binding-linux-arm-gnueabihf": "npm:1.2.7"
"@rolldown/binding-linux-arm64-gnu": "npm:1.2.7"
"@rolldown/binding-linux-arm64-musl": "npm:1.2.7"
"@rolldown/binding-linux-ppc64-gnu": "npm:1.2.7"
"@rolldown/binding-linux-s390x-gnu": "npm:1.2.7"
"@rolldown/binding-linux-x64-gnu": "npm:1.2.7"
"@rolldown/binding-linux-x64-musl": "npm:1.2.7"
"@rolldown/binding-openharmony-arm64": "npm:1.2.7"
"@rolldown/binding-win32-arm64-msvc": "npm:1.2.7"
"@rolldown/binding-win32-x64-msvc": "npm:1.2.7"
"@rolldown/pluginutils": "npm:^1.0.0"
dependenciesMeta:
"@rolldown/binding-android-arm-eabi":
@@ -14099,7 +14110,7 @@ __metadata:
optional: true
bin:
rolldown: ./bin/cli.mjs
checksum: 10/7260c1f3d6ee32358f110a425174ae44df9383957cf2364195db371ab407ed3dced45afe14a86556df551fba4efbe073ef53fb994ffd8c5d517754ec55c872b0
checksum: 10/e3c23a65a2dbd4733d508a5464727064c7c838e3ff2a76b59c5b6f512a250e21fdc3e622af8f985d1970d0d72518afbd7117fb8f111b65a6d2c228e4b666633c
languageName: node
linkType: hard
@@ -16001,13 +16012,6 @@ __metadata:
languageName: node
linkType: hard
"verkit@npm:^0.3.2":
version: 0.3.2
resolution: "verkit@npm:0.3.2"
checksum: 10/23e57c28094da170e381e27c020cddde0543fbac377b111c325a18440da4502d21c58446ef25794ecc1f2434df1d6297edf760910245ac5b90199a9bb18d8634
languageName: node
linkType: hard
"vinyl-contents@npm:^2.0.0":
version: 2.0.0
resolution: "vinyl-contents@npm:2.0.0"
@@ -16093,19 +16097,19 @@ __metadata:
languageName: node
linkType: hard
"vite@npm:8.3.0":
version: 8.3.0
resolution: "vite@npm:8.3.0"
"vite@npm:8.2.2":
version: 8.2.2
resolution: "vite@npm:8.2.2"
dependencies:
fsevents: "npm:~2.3.3"
lightningcss: "npm:^1.33.0"
picomatch: "npm:^4.0.7"
postcss: "npm:^8.5.28"
rolldown: "npm:~1.2.6"
picomatch: "npm:^4.0.5"
postcss: "npm:^8.5.26"
rolldown: "npm:~1.2.4"
tinyglobby: "npm:^0.2.17"
peerDependencies:
"@types/node": ^20.19.0 || >=22.12.0
"@vitejs/devtools": ^0.7.1
"@vitejs/devtools": ^0.4.0 || ^0.5.0
esbuild: ^0.27.0 || ^0.28.0
jiti: ">=1.21.0"
less: ^4.0.0
@@ -16146,7 +16150,7 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
checksum: 10/7f373449d1189c6b54c24555aab260afb0863e864a7f4a0b52e59dbbe86e4166ee6e82c3b4ab82cb00b38a5f0922ab665cf2dcfb5c7fb6a31812cc71a456fe72
checksum: 10/65cd73267ea2fd49736e51e91681ddc5cbee3af880f20ce5c8df3d4c97d811a11e3ca62d3899fc8ac98ec442b5bc6f55a5d7625ac574ab68c7e3e541e543f264
languageName: node
linkType: hard