Compare commits

..
Author SHA1 Message Date
Yosi Levy 7dec4a57e8 Various RTL fixes (#54117)
* Various RTL fixes

* Fixes - no keyboard focus

* Fix style
2026-09-14 06:47:51 +02:00
Paulus SchoutsenandClaude aa78f368b1 Fix discovery list covering card corners on network page (#54157)
The ha-md-list inside the network discovery card draws its own surface
background. That square background hides the rounded bottom corners of
the card. Remove the list background so the card shows through.


Claude-Session: https://claude.ai/code/session_01PLf4NaCFm5tWguyUSmSAEx

Co-authored-by: Claude <[email protected]>
2026-09-14 06:47:01 +02:00
renovate[bot] 06901dedaa Update dependency lint-staged to v17.5.1 (#54155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:45:23 +02:00
renovate[bot] 43f194dad2 Update dependency vite to v8.3.0 (#54156)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:45:04 +02:00
renovate[bot] e7acf97b1a Update babel monorepo to v8.0.5 (#54161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-14 06:44:12 +02:00
Paulus SchoutsenandClaude Opus 5 9409db7fda Show YAML-configured Modbus hubs in the Modbus panel (#54134)
* Show YAML-configured Modbus hubs in the connections panel

The backend now lists a hub configured in YAML as a connection of its
own, flagged with its source. Render those rows with the hub name and
the units it addresses, marked as configured in YAML, since there is no
config entry to link to.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018gAhZ9auwjmQaTg91efAD4

* Demo the Modbus YAML hub on a TCP device

One serial port cannot carry two links, so a YAML hub sharing the
RS-485 port was not a state the panel can reach. Put the hub on the TCP
device an integration also talks to, where two sockets are real.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018gAhZ9auwjmQaTg91efAD4

---------

Co-authored-by: Claude Opus 5 <[email protected]>
2026-09-13 07:08:44 +00:00
dependabot[bot] d917df359f Bump home-assistant/actions/helpers/verify-version from a7c616ce81ccda50150bf1595786c71b1883fabb to 58bff37c8947f690ace498be413a9b78d6f30f93 (#54138)
Bump home-assistant/actions/helpers/verify-version

Bumps [home-assistant/actions/helpers/verify-version](https://github.com/home-assistant/actions) from a7c616ce81ccda50150bf1595786c71b1883fabb to 58bff37c8947f690ace498be413a9b78d6f30f93.
- [Release notes](https://github.com/home-assistant/actions/releases)
- [Commits](https://github.com/home-assistant/actions/compare/a7c616ce81ccda50150bf1595786c71b1883fabb...58bff37c8947f690ace498be413a9b78d6f30f93)

---
updated-dependencies:
- dependency-name: home-assistant/actions/helpers/verify-version
  dependency-version: 58bff37c8947f690ace498be413a9b78d6f30f93
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 09:36:50 +03:00
Petar PetrovandCursor Agent 6dcca89185 Move history-graph card timeline names under the bars (#54102)
* Move history-graph card timeline names under the bars

Enable the same inside-labels layout as the History panel on the
Lovelace history-graph card. Custom entity names still override
the default Device ▸ Entity labels from computeHistory.

* Keep compact timeline rows when names are hidden

inside-labels only applies when the history-graph card is showing
names, and the timeline uses the taller row height only when those
under-bar labels are actually drawn.

* Match timeline row height to when inside labels are drawn

Use the same chunked || showNames condition as the axis options so
virtualized charts keep enough room for under-bar names. String YAML
names still apply when the entity is missing from current state;
structured names fall through to computeHistory instead of the entity ID.

* Preserve structured YAML names without a current state

formatEntityName still needs an entity id when the override is an
EntityNameItem. Use a stub state so device/text/entity name configs
apply even if the entity is missing from hass.states.

---------

Co-authored-by: Cursor Agent <[email protected]>
2026-09-12 13:28:53 +02:00
Wendelin 3f1b2ef65f Onboarding: lite internationalization context (#54125)
* Add internatinalization context to onboarding

* Use the context in welcome
2026-09-12 11:53:30 +02:00
Petar Petrov 34afbe37c3 Use ha-control-circular-slider in the light card (#54123)
Replace the legacy @thomasloven/round-slider brightness ring with the
in-house ha-control-circular-slider (already used by the thermostat and
humidifier cards). The card keeps its layout, center toggle button,
brightness readout, size, and all config options, so existing dashboards
are unaffected. The light card was the last consumer of round-slider, so
the dependency and its patch are dropped.
2026-09-12 11:53:05 +02:00
renovate[bot] 848e81313e Update dependency jszip to v3.10.2 (#54132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-12 09:32:56 +03:00
Paul Bottein 24e7bd306a Sync My redirects with my.home-assistant.io (#53956) 2026-09-11 16:13:45 +02:00
3791548067 Show every selector on the gallery selector page (#54121)
* Show the serial port selector in the gallery

The selector page had no serial_port entry, so the picker could only be
exercised against a running instance with real hardware attached.

Add it to "One of each", backed by a scan mock with one port per section
the picker groups by. The entry carries a flow context, and the page now
forwards that to ha-selector, because the recommended and not recommended
grouping is keyed off the domain a config flow supplies.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Answer the ingress panel list in the supervisor demo stub

The navigation picker waits for that collection before it enables itself,
so with the endpoint rejecting it stayed disabled for the whole demo and
gallery, with nothing on screen to say why.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Show every selector on the gallery selector page

Twenty-nine of the sixty selectors had no entry, so they could only be
looked at inside a config flow or a blueprint that happened to use one.

Add the missing entries to "One of each", with the mocks the assist and
statistic pickers need to return a list. A few carry a value or a config
because they render their fallback without one: the meta selector reads
the first key of its value, the period selector offers its custom-period
editor, and the voice list is fetched per engine and language.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NTxTXXEY4FnQryNFbtB5tf

* Add new serial port configuration

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-11 17:11:41 +03:00
01cef9a99b Fix trigger 'for' choose (#53749)
* Fix trigger 'for' choose

* fix stub

* try something else

* merge duration-selector with create_duration_data

* handle negatives

* default ms to false for selector

* Handle hidden duration units in ha-duration-input

createDurationData grew three flags describing which fields the duration
input renders, but the input already owns enableDay, enableMillisecond,
enableSecond and allowNegative. Fold the units it does not render there
instead, so createDurationData keeps its single-argument signature.

This handles days and milliseconds symmetrically, and covers every
ha-duration-input consumer rather than only ha-selector-duration:
ha-form-positive_time_period_dict passes .data straight through without
enable-day and dropped days in exactly the same way.

A leading "-" negates the whole period in cv.time_period_str, so the
sign is now always distributed across all parts. The calendar trigger is
the only caller that can see a negative value and does its own sign
handling, so it takes the absolute value of every part instead of just
hours, and copies the duration first since createDurationData returns
dict values by reference.

Co-Authored-By: Claude Opus 5 <[email protected]>

* cleanup calendar trigger

* Refine duration type check for object values

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-09-11 16:34:29 +03:00
43 changed files with 1333 additions and 1304 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@a7c616ce81ccda50150bf1595786c71b1883fabb # master
uses: home-assistant/actions/helpers/verify-version@58bff37c8947f690ace498be413a9b78d6f30f93 # master
- name: Setup Node and install
uses: ./.github/actions/setup
@@ -1,87 +0,0 @@
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,19 +12,29 @@ 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,6 +358,12 @@ 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;
}
+257 -1
View File
@@ -21,6 +21,8 @@ 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,
@@ -293,9 +295,72 @@ 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 }) | null>;
input: Record<
string,
| (BlueprintInput & {
required?: boolean;
context?: Record<string, unknown>;
})
| null
>;
}[] = [
{
name: "One of each",
@@ -320,6 +385,13 @@ 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: {
@@ -504,6 +576,99 @@ 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: {} },
},
},
},
{
@@ -605,8 +770,98 @@ 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) {
@@ -776,6 +1031,7 @@ 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}
+4 -3
View File
@@ -21,7 +21,8 @@ const ENTITIES = [
state: "on",
attributes: {
friendly_name: "Dining Room",
supported_features: 1,
supported_color_modes: ["brightness"],
color_mode: "brightness",
brightness: 100,
},
},
@@ -30,7 +31,7 @@ const ENTITIES = [
state: "off",
attributes: {
friendly_name: "Dining Room",
supported_features: 1,
supported_color_modes: ["brightness"],
},
},
{
@@ -38,7 +39,7 @@ const ENTITIES = [
state: "unavailable",
attributes: {
friendly_name: "Lost Light",
supported_features: 1,
supported_color_modes: ["brightness"],
},
},
];
+6 -7
View File
@@ -39,7 +39,7 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "8.0.0",
"@babel/runtime": "8.0.5",
"@braintree/sanitize-url": "7.1.2",
"@codemirror/autocomplete": "6.20.3",
"@codemirror/commands": "6.11.0",
@@ -84,7 +84,6 @@
"@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",
@@ -139,10 +138,10 @@
},
"devDependencies": {
"@ampproject/remapping": "2.3.0",
"@babel/core": "8.0.1",
"@babel/core": "8.0.5",
"@babel/helper-define-polyfill-provider": "1.0.0",
"@babel/plugin-transform-runtime": "8.0.1",
"@babel/preset-env": "8.0.2",
"@babel/preset-env": "8.0.5",
"@bundle-stats/plugin-webpack-filter": "4.22.3",
"@eslint/js": "10.0.1",
"@gfx/zopfli": "1.0.15",
@@ -195,10 +194,10 @@
"html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"jsdom": "30.0.1",
"jszip": "3.10.1",
"jszip": "3.10.2",
"license-checker-rseidelsohn": "5.0.1",
"lightningcss": "1.33.0",
"lint-staged": "17.5.0",
"lint-staged": "17.5.1",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.18.1",
@@ -214,7 +213,7 @@
"ts-lit-plugin": "2.0.2",
"typescript": "6.0.3",
"typescript-eslint": "8.70.0",
"vite": "8.2.2",
"vite": "8.3.0",
"vite-tsconfig-paths": "6.1.1",
"vitest": "5.0.0",
"webpack-stats-plugin": "1.1.3",
+19 -21
View File
@@ -9,36 +9,34 @@ export const createDurationData = (
}
if (typeof duration !== "object") {
if (typeof duration === "string" || isNaN(duration)) {
const parts = duration?.toString().split(":") || [];
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)
);
if (parts.length === 1) {
return { seconds: Number(parts[0]) };
return { seconds: parts[0] };
}
if (parts.length > 3) {
return undefined;
}
const seconds = Number(parts[2]) || 0;
const seconds_whole = Math.floor(seconds);
const seconds = parts[2] || 0;
const secondsWhole = Math.trunc(seconds);
return {
hours: Number(parts[0]) || 0,
minutes: Number(parts[1]) || 0,
seconds: seconds_whole,
milliseconds: Math.floor(
Number((seconds - seconds_whole).toFixed(4)) * 1000
hours: parts[0] || 0,
minutes: parts[1] || 0,
seconds: secondsWhole,
milliseconds: Math.trunc(
Number((seconds - secondsWhole).toFixed(4)) * 1000
),
};
}
return { seconds: 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,
};
return duration;
};
@@ -0,0 +1,48 @@
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,7 +44,8 @@ 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.
// left-hand category-label column. Opt-in; used by the history panel and
// history-graph card.
@property({ attribute: "inside-labels", type: Boolean })
public insideLabels = false;
@@ -79,7 +80,9 @@ export class StateHistoryChartTimeline extends LitElement {
.options=${this._chartOptions}
.height=${`${
this.data.length *
(this.insideLabels ? ROW_HEIGHT_INSIDE_LABELS : ROW_HEIGHT) +
(this.insideLabels && (this.chunked || this.showNames)
? 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.
// left-hand column. Opt-in; used by the history panel and history-graph card.
@property({ attribute: "inside-labels", type: Boolean })
public insideLabels = false;
+90 -59
View File
@@ -1,69 +1,100 @@
import type { CSSResultGroup } from "lit";
import { css } from "lit";
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 { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-assist-chip")
export class HaAssistChip extends HaChipBase {
// @ts-ignore
export class HaAssistChip extends AssistChip {
@property({ type: Boolean, reflect: true }) filled = false;
@property({ type: Boolean, reflect: true }) active = false;
@property({ type: Boolean }) active = false;
@property({ type: Boolean, reflect: true }) elevated = 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;
}
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)
);
}
`,
];
.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>`;
}
}
-452
View File
@@ -1,452 +0,0 @@
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;
}
}
+3 -87
View File
@@ -1,92 +1,8 @@
import { css, html, LitElement } from "lit";
import { customElement, queryAssignedElements } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
import { MdChipSet } from "@material/web/chips/chip-set";
import { customElement } from "lit/decorators";
@customElement("ha-chip-set")
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);
}
`;
}
export class HaChipSet extends MdChipSet {}
declare global {
interface HTMLElementTagNameMap {
+39 -66
View File
@@ -1,81 +1,54 @@
import { mdiCheck } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, nothing } from "lit";
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 { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
@customElement("ha-filter-chip")
export class HaFilterChip extends HaChipBase {
@property({ type: Boolean, reflect: true }) selected = false;
@property({ type: Boolean, reflect: true }) elevated = false;
export class HaFilterChip extends FilterChip {
@property({ type: Boolean, reflect: true, attribute: "no-leading-icon" })
noLeadingIcon = false;
protected override get pressed() {
return this.selected;
}
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 override renderLeadingIcon() {
protected getContainerClasses() {
const classes = super.getContainerClasses();
if (this.noLeadingIcon) {
return nothing;
classes["has-icon"] = false;
}
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();
return classes;
}
protected override handlePrimaryClick(event: MouseEvent) {
if (this.disabled || this.softDisabled) {
return;
protected renderLeadingIcon() {
if (this.noLeadingIcon) {
// eslint-disable-next-line lit/prefer-nothing
return html``;
}
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);
}
`,
];
return super.renderLeadingIcon();
}
}
+39 -40
View File
@@ -1,46 +1,45 @@
import type { CSSResultGroup } from "lit";
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 { css } from "lit";
import { customElement, property } from "lit/decorators";
import { HaChipBase } from "./ha-chip-base";
import { customElement } from "lit/decorators";
@customElement("ha-input-chip")
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);
}
`,
];
}
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);
}
`,
];
}
declare global {
+50 -32
View File
@@ -103,69 +103,87 @@ 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;
}
@@ -236,8 +254,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
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,16 @@
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,8 +45,11 @@ export class HaChooseSelector extends LitElement {
}
if (
changedProperties.has("value") &&
changedProperties.get("value")?.active_choice &&
changedProperties.get("value")?.active_choice !== this._activeChoice
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
) {
this._setActiveChoice();
}
@@ -150,14 +153,14 @@ export class HaChooseSelector extends LitElement {
if (this.value === null || this.value === undefined) {
return undefined;
}
return typeof this.value === "object"
return typeof this.value === "object" && "active_choice" in this.value
? this.value[choice || this.value.active_choice]
: this.value;
}
private _setActiveChoice() {
if (this.value) {
if (typeof this.value === "object") {
if (typeof this.value === "object" && "active_choice" in this.value) {
if (this.value.active_choice in this.selector.choose.choices) {
this._activeChoice = this.value.active_choice;
return;
@@ -199,6 +202,22 @@ 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,6 +4,7 @@ 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 {
@@ -27,33 +28,8 @@ export class HaTimeDuration extends LitElement {
}
private _data = memoizeOne(
(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;
}
(value?: HaDurationData | string | number): HaDurationData | undefined =>
createDurationData(value)
);
protected render() {
+4
View File
@@ -1327,6 +1327,9 @@ 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;
@@ -1377,6 +1380,7 @@ 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 {
+8 -1
View File
@@ -3,10 +3,17 @@ 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;
/** The unit IDs each config entry holds, keyed by config entry ID. */
source: ModbusConnectionSource;
/**
* The unit IDs each holder uses, keyed by config entry ID, or by hub name
* when `source` is `"yaml"`.
*/
units: Record<string, number[]>;
}
@@ -1,16 +1,14 @@
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,
@@ -158,10 +156,6 @@ 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
@@ -233,12 +227,7 @@ export class DialogHttpPendingConfig
<span class="old"
>${this._formatValue(key, stable[key])}</span
>
<ha-svg-icon
.path=${mdiArrowRight}
style=${styleMap({
transform: rtl ? "scaleX(-1)" : "",
})}
></ha-svg-icon>
<ha-icon-arrow-next></ha-icon-arrow-next>
<span class="new"
>${this._formatValue(key, pending![key])}</span
>
@@ -403,7 +392,7 @@ export class DialogHttpPendingConfig
.values .new {
color: var(--primary-text-color);
}
.values ha-svg-icon {
.values ha-icon-arrow-next {
--mdc-icon-size: 18px;
flex-shrink: 0;
}
+6 -1
View File
@@ -60,7 +60,9 @@ export class HaInitPage extends LitElement {
: nothing
}
`
: html`<p class=${classMap({ "loading-text": !this.migration })}>
: html`<p
class=${classMap({ "loading-text": !this.migration, rtl: document.dir === "rtl" })}
>
${
this.migration
? html`<span class="migration-text"
@@ -124,6 +126,9 @@ export class HaInitPage extends LitElement {
.loading-text {
opacity: 0.66;
}
.rtl {
direction: rtl;
}
`;
}
+17 -4
View File
@@ -17,6 +17,7 @@ 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,
@@ -24,6 +25,7 @@ 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";
@@ -40,7 +42,6 @@ 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";
@@ -165,9 +166,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
}
if (this._init) {
return html`<onboarding-welcome
.localize=${this.localize}
></onboarding-welcome>`;
return html`<onboarding-welcome></onboarding-welcome>`;
}
const step = this._curStep()!;
@@ -230,6 +229,20 @@ 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, property } from "lit/decorators";
import { customElement, state } from "lit/decorators";
import { consumeLocalize } from "../common/decorators/consume-context-entry";
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 {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public localize!: LocalizeFunc;
@state()
@consumeLocalize()
private _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,6 +8,7 @@ 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";
@@ -82,13 +83,21 @@ 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;
const duration: HaDurationData = createDurationData(trigger_offset)!;
// Copy, `createDurationData` returns the input object as-is for dict values.
const duration: HaDurationData = { ...createDurationData(trigger_offset)! };
let offset_type = "after";
if (
(typeof trigger_offset === "object" && duration!.hours! < 0) ||
(typeof trigger_offset === "string" && trigger_offset.startsWith("-"))
) {
duration.hours = Math.abs(duration.hours!);
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);
}
offset_type = "before";
}
const data = {
@@ -113,11 +122,12 @@ 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}${duration.hours ?? 0}:${duration.minutes ?? 0}:${
duration.seconds ?? 0
}`,
offset: `${offsetType}${h}:${m}:${s}`,
};
delete newTrigger.offset_type;
fireEvent(this, "value-changed", { value: newTrigger });
@@ -2,9 +2,7 @@ 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";
@@ -198,21 +196,6 @@ 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"] {
@@ -240,7 +223,6 @@ 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,7 +15,6 @@ 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";
@@ -220,21 +219,6 @@ 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"] {
@@ -251,7 +235,6 @@ 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,9 +3,7 @@ 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 = [
@@ -37,21 +35,6 @@ 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"] {
@@ -67,7 +50,6 @@ export class HaTemplateTrigger extends LitElement {
protected render() {
const data = {
...this.trigger,
for: this._wrapForValue(this.trigger.for),
};
return html`
@@ -1,5 +1,6 @@
import {
mdiCableData,
mdiFileDocumentOutline,
mdiLan,
mdiPuzzle,
mdiRefresh,
@@ -22,7 +23,10 @@ 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 } from "../../../../../data/modbus";
import type {
ModbusConnection,
ModbusConnectionSource,
} from "../../../../../data/modbus";
import {
listModbusConnections,
modbusEndpointTarget,
@@ -43,7 +47,8 @@ const isKnownTransport = (transport: string): transport is ModbusTransport =>
(TRANSPORTS as readonly string[]).includes(transport);
interface ConnectionHolder {
entryId: string;
/** A config entry ID, or a hub name on a YAML connection. */
id: string;
entry?: ConfigEntry;
units: number[];
}
@@ -51,9 +56,10 @@ interface ConnectionHolder {
interface ConnectionListItem {
icon: string;
primary: string;
transport: string;
secondary: string;
state: string;
serialDevice?: string;
source: ModbusConnectionSource;
holders: ConnectionHolder[];
connection: ModbusConnection;
}
@@ -114,22 +120,34 @@ 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),
transport: this._transportName(transport),
secondary: this._secondaryName(connection),
state: this._stateName(connection.connected, serialDevice !== undefined),
serialDevice,
holders: Object.entries(connection.units).map(([entryId, units]) => ({
entryId,
entry: entries[entryId],
source: connection.source,
holders: Object.entries(connection.units).map(([id, units]) => ({
id,
entry: connection.source === "yaml" ? undefined : entries[id],
units,
})),
connection,
@@ -161,13 +179,20 @@ export class ModbusConfigDashboard extends LitElement {
`;
}
private _renderHolder(holder: ConnectionHolder): TemplateResult {
// An entry removed while the connection was listed has nowhere to link to
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
if (!holder.entry) {
return html`
<ha-md-list-item class="holder">
<ha-svg-icon slot="start" .path=${mdiPuzzle}></ha-svg-icon>
<div slot="headline">${holder.entryId}</div>
<ha-svg-icon
slot="start"
.path=${source === "yaml" ? mdiFileDocumentOutline : mdiPuzzle}
></ha-svg-icon>
<div slot="headline">${holder.id}</div>
${this._renderUnits(holder)}
</ha-md-list-item>
`;
@@ -179,7 +204,7 @@ export class ModbusConfigDashboard extends LitElement {
<ha-md-list-item
type="link"
class="holder"
href=${`/config/integrations/integration/${domain}#config_entry=${holder.entryId}`}
href=${`/config/integrations/integration/${domain}#config_entry=${holder.id}`}
>
<img
slot="start"
@@ -234,10 +259,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.transport}</div>
<div slot="supporting-text">${item.secondary}</div>
${this._renderState(item)}
</ha-md-list-item>
${item.holders.map((holder) => this._renderHolder(holder))}
${item.holders.map((holder) => this._renderHolder(holder, item.source))}
${
item.serialDevice && isComponentLoaded(this.hass.config, "usb")
? this._renderSerialPortLink()
@@ -103,6 +103,7 @@ class HaConfigSectionNetwork extends LitElement {
max-width: 600px;
}
.discovery-card ha-md-list {
background: none;
padding-top: 0;
}
`;
@@ -2,6 +2,7 @@ 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";
@@ -105,10 +106,22 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
}
this._names = {};
this._entities.forEach((entity) => {
const stateObj = this.hass!.states[entity.entity];
this._names[entity.entity] = stateObj
? this.hass!.formatEntityName(stateObj, entity.name)
: entity.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
);
});
}
@@ -315,6 +328,7 @@ 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>
@@ -360,11 +374,8 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
.names=${this._names}
up-to-now
.hoursToShow=${this._hoursToShow}
.showNames=${
this._config.show_names !== undefined
? this._config.show_names
: true
}
.showNames=${showNames}
?inside-labels=${showNames}
.logarithmicScale=${this._config.logarithmic_scale || false}
.minYAxis=${this._config.min_y_axis}
.maxYAxis=${this._config.max_y_axis}
+24 -15
View File
@@ -1,14 +1,15 @@
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";
@@ -108,12 +109,14 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
<div class="content">
<div id="controls">
<div id="slider">
<!-- @ts-ignore Round-slider has no tag definition or exported type -->
<round-slider
min="1"
max="100"
<ha-control-circular-slider
mode="start"
.min=${1}
.max=${100}
.step=${1}
.value=${brightness}
.disabled=${stateObj.state === UNAVAILABLE}
prevent-interaction-on-scroll
@value-changing=${this._dragEvent}
@value-changed=${this._setBrightness}
style=${styleMap({
@@ -121,7 +124,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
? "visible"
: "hidden",
})}
></round-slider>
></ha-control-circular-slider>
<ha-icon-button
class="light-button ${classMap({
"slider-center": lightSupportsBrightness(stateObj),
@@ -191,9 +194,10 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
}
}
private _dragEvent(e: any): void {
this.shadowRoot!.querySelector(".brightness")!.innerHTML =
`${e.detail.value} %`;
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} %`;
this._showBrightness();
this._hideBrightness();
}
@@ -213,10 +217,14 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
}, 500);
}
private _setBrightness(e: any): void {
private _setBrightness(
ev: HASSDomEvent<HASSDomEvents["value-changed"]>
): void {
const { value } = ev.detail;
if (typeof value !== "number" || isNaN(value)) return;
this.hass!.callService("light", "turn_on", {
entity_id: this._config!.entity,
brightness_pct: e.detail.value,
brightness_pct: value,
});
}
@@ -292,10 +300,11 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
min-width: 100px;
}
round-slider {
--round-slider-path-color: var(--slider-track-color);
--round-slider-bar-color: var(--primary-color);
padding-bottom: 10%;
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;
}
.light-button {
+9 -3
View File
@@ -391,10 +391,19 @@ 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",
@@ -431,9 +440,6 @@ export const getMyRedirects = (): Redirects => ({
category: "string?",
},
},
lights: {
redirect: "/lights",
},
});
const getRedirect = (path: string): Redirect | undefined =>
+17 -3
View File
@@ -1,4 +1,6 @@
import { ContextProvider } from "@lit/context";
import type { ConditionDescriptions } from "../data/condition";
import { subscribeConditions } from "../data/condition";
import {
ConfigEntryStream,
type ConfigEntryUpdate,
@@ -34,15 +36,17 @@ 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 } from "../types";
import type {
Constructor,
HomeAssistant,
HomeAssistantInternationalization,
} from "../types";
import type { HassBaseEl } from "./hass-base-mixin";
import { LazyContextProvider } from "./lazy-context-provider";
import { RelatedContextProvider } from "./related-context-provider";
@@ -274,6 +278,16 @@ 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)) {
+11 -1
View File
@@ -1,7 +1,10 @@
import type { Auth, Connection } from "home-assistant-js-websocket";
import { LitElement } from "lit";
import { property } from "lit/decorators";
import type { HomeAssistant } from "../types";
import type {
HomeAssistant,
HomeAssistantInternationalization,
} from "../types";
export class HassBaseEl extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@@ -39,6 +42,13 @@ 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;
+2 -1
View File
@@ -7665,7 +7665,8 @@
"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.",
"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",
"state_connected": "Connected",
"state_not_connected": "Not connected",
"state_open": "Open",
@@ -1,4 +1,4 @@
import { describe, it, expect } from "vitest";
import { describe, expect, it } from "vitest";
import { createDurationData } from "../../../src/common/datetime/create_duration_data";
describe("createDurationData", () => {
@@ -17,6 +17,26 @@ 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", () => {
@@ -33,19 +53,13 @@ describe("createDurationData", () => {
expect(createDurationData(1.25)).toEqual({ seconds: 1.25 });
});
it("should parse object duration without days correctly", () => {
expect(createDurationData({ hours: 1, minutes: 30 })).toEqual({
hours: 1,
minutes: 30,
});
it("should return object duration unchanged", () => {
const duration = { hours: 1, minutes: 30 };
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,
});
it("should keep days in object duration", () => {
const duration = { days: 1, hours: 1 };
expect(createDurationData(duration)).toEqual(duration);
});
});
@@ -0,0 +1,226 @@
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,14 +18,9 @@ vi.mock("../../../src/components/ha-dialog", () => {
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-button", () => {
customElements.define("ha-button", class extends HTMLElement {});
return {};
});
vi.mock("../../../src/components/ha-dialog-footer", () => {
+248 -252
View File
@@ -91,25 +91,25 @@ __metadata:
languageName: node
linkType: hard
"@babel/compat-data@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/compat-data@npm:8.0.0"
checksum: 10/83b1776ecfdaf02559a4b4fb2f4a2c5e6ba8a2b41bf898807caaf863379ee9c8e91c163de71e79d73eb68659b58bcb18cbcff9a39aae6f88c106af680619326c
"@babel/compat-data@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/compat-data@npm:8.0.5"
checksum: 10/c1bedf2ee94c7bf8b18f7672dba651791ef0908596c4300f006804b23b5833132a16c210187848b92fd86c36a04aaff1ea2810ae20a319438763dd679704fc89
languageName: node
linkType: hard
"@babel/core@npm:8.0.1":
version: 8.0.1
resolution: "@babel/core@npm:8.0.1"
"@babel/core@npm:8.0.5":
version: 8.0.5
resolution: "@babel/core@npm:8.0.5"
dependencies:
"@babel/code-frame": "npm:^8.0.0"
"@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/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/template": "npm:^8.0.0"
"@babel/traverse": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
"@babel/traverse": "npm:^8.0.5"
"@babel/types": "npm:^8.0.5"
"@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"
semver: "npm:^7.7.3"
checksum: 10/def06f2ddcb0cf6872ccbd72742d21b16c4af1eee01b5aae800b4456e03ef50a3f8e976c09158b1a684d0c3f09b6c9a1c1bed65cc15390f0d8abbbe3c9516a28
verkit: "npm:^0.3.2"
checksum: 10/655ab58882afecbbe0fb8d6cef5a571b72b8c593b248dd9b2fd7c2b831fd6ab79c2f13451e1d2873d62cf6a6ccf626b4f6485d08ff30442a81df8b61ee02645f
languageName: node
linkType: hard
@@ -158,17 +158,17 @@ __metadata:
languageName: node
linkType: hard
"@babel/generator@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/generator@npm:8.0.0"
"@babel/generator@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/generator@npm:8.0.5"
dependencies:
"@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"
"@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"
"@types/jsesc": "npm:^2.5.0"
jsesc: "npm:^3.0.2"
checksum: 10/8d9b801886b4bbe46b101768abae0ffa1c9435601a8788358331c115b1a38a7c5acdd0e8b85b4d0c00806b0b74a0cc0e75ef50647f7322ffa3646a238e1b5420
checksum: 10/750f3f74ae05aea0978d19e80bb4b2c5343b523ef90768b3e68ab103c07dae26524d591a5195c06d6886bc7e088ba861216d08602df14a625e7b0e169a1958a2
languageName: node
linkType: hard
@@ -203,16 +203,16 @@ __metadata:
languageName: node
linkType: hard
"@babel/helper-compilation-targets@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/helper-compilation-targets@npm:8.0.0"
"@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"
dependencies:
"@babel/compat-data": "npm:^8.0.0"
"@babel/compat-data": "npm:^8.0.5"
"@babel/helper-validator-option": "npm:^8.0.0"
browserslist: "npm:^4.24.0"
lru-cache: "npm:^11.0.0"
semver: "npm:^7.7.3"
checksum: 10/2814f178f119887abe5221fb6178f62f1adfec9561a915aa67ca65f5ece8d6f1ee83ed731a3e335065d579c1f3c73fc4fdbf83a70fa4ea0113b8932f173b2262
verkit: "npm:^0.3.2"
checksum: 10/49775a5b74e84b83f99392d85016a604227894a8face3e2d9209074c8db6b9b1442c00397fc0029585de88b00bacc40302465462c68041563d0fb2d1ad9aaebb
languageName: node
linkType: hard
@@ -233,20 +233,20 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-member-expression-to-functions": "npm:^8.0.0"
"@babel/helper-member-expression-to-functions": "npm:^8.0.5"
"@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.0"
semver: "npm:^7.7.3"
"@babel/traverse": "npm:^8.0.5"
verkit: "npm:^0.3.2"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/97d111c4b06da821d4cbd4c8439b7ba9614faaf6a7e565df14660b9a2f8f39aae6b903c07c3f34288ff44ca1c8f95b782430f4ab7afce8a5a0fdd72af914d553
checksum: 10/fec84233555462d62c1c28b6683bf5ace0c93f7a6e6494945e75df5946fb0472f88a5b086cad8706941801ac06a0dc341a7d2a38a6275ba190f89e64589c3e6b
languageName: node
linkType: hard
@@ -328,13 +328,13 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
dependencies:
"@babel/traverse": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
checksum: 10/ec4ab0494f3500a69b4b85034eb03e82941e2e0140f5608b51cdccb5586426d573939e06489714d7d7c0b6cb6585cb71fde7a8d51e1c0bb82dabf917acb094ad
"@babel/traverse": "npm:^8.0.5"
"@babel/types": "npm:^8.0.5"
checksum: 10/a8e4ca0275aba747e8c26253040c8b8429e015a4065adb9dd7342b3e52bd537d986104b044b9b409a6f6dd674f9865e09b54c292b5ed0ff0630f1c714e809ae3
languageName: node
linkType: hard
@@ -564,13 +564,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/helpers@npm:^8.0.0":
version: 8.0.0
resolution: "@babel/helpers@npm:8.0.0"
"@babel/helpers@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/helpers@npm:8.0.5"
dependencies:
"@babel/template": "npm:^8.0.0"
"@babel/types": "npm:^8.0.0"
checksum: 10/129fca6e339022059028b7189c9cb6907ed813233ef335d8636a82b927282fea022970fc4da33bc575d6dbb8900ca550c5dcaaae84f7265c4808e8514ec81339
"@babel/types": "npm:^8.0.5"
checksum: 10/56adcdcfcff33adcc4ce57633a20ba4d7fac7618cdae544ce8828291ab47c936d6cda4c6f5e364385b5e525b6415ea8dda061c6a11ce7eabc2df109e4ce557c5
languageName: node
linkType: hard
@@ -585,14 +585,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/parser@npm:^8.0.0, @babel/parser@npm:^8.0.4":
version: 8.0.4
resolution: "@babel/parser@npm:8.0.4"
"@babel/parser@npm:^8.0.0, @babel/parser@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/parser@npm:8.0.5"
dependencies:
"@babel/types": "npm:^8.0.4"
"@babel/types": "npm:^8.0.5"
bin:
parser: ./bin/babel-parser.js
checksum: 10/230554794a2c296ce1fb60f57459d94903802369e14e1d83c3ea266b64a4f88ab292eadf5213823d87c04541c9c43b8b6daaae919f25551d3637800663fb25bf
checksum: 10/3e58342925f3729e1e4bd144af0718b160a337c3427608555768b6aa3319b89be9b8573dd5e0d0c0ee4c5b35f62f16036f28dd43ccdf9b181f55c3e35eb94735
languageName: node
linkType: hard
@@ -675,15 +675,15 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
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/795b63579f39b7699655c3fc90d8f855181a365db174a475c4e69fdd6ad2059ed9a9c34975c1300e52faddd2a70b332f6171936960eb7501452237a19968be31
checksum: 10/df5440172fab0c7ee2f8bd973dc947379b3b618ec7abe804282b304a807e09a6d1e67e79b5b7b841d0e79ad2de2522cb344bb3a7f4e5b9b48430ad1b72ead9db
languageName: node
linkType: hard
@@ -886,14 +886,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-block-scoping@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-block-scoping@npm:8.0.1"
"@babel/plugin-transform-block-scoping@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-block-scoping@npm:8.0.5"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/9f922f531974f8a8484a50705bc43baf69bf231afc663e6a7100a4e7c3b7c8242901a2f760dc7714dd13b986760679d33d04733c0c3c411ce2e8113b2ef4ad41
checksum: 10/26efc50c4f9042f502a929de6619ce756fe092d1b56176d1f797ab711590f6ea47f8521927821d5629889a8cc1187645d6a08ab912aa250bc3607299e4dfcf09
languageName: node
linkType: hard
@@ -933,15 +933,15 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
dependencies:
"@babel/helper-create-class-features-plugin": "npm:^8.0.1"
"@babel/helper-create-class-features-plugin": "npm:^8.0.5"
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/b927af27b34b3d3e54ce51af1af5ea47ddb2a2a1537341153556452996cf58f67e04cd27734947b197224e05c8b1b673247ad2b729b19927c911870b15f0a478
checksum: 10/cebde27ab9f26b237e34ca77bd28b4b61600dfaefcb258f132cc5589f7ee009d8ab0323fba868b29758ad865b42e4bbcc485a2646815ee6b94600e8d5945712d
languageName: node
linkType: hard
@@ -961,19 +961,19 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-classes@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-classes@npm:8.0.1"
"@babel/plugin-transform-classes@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-classes@npm:8.0.5"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.5"
"@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.0"
"@babel/traverse": "npm:^8.0.5"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/605b6d19ce75b6c40484b4ad6de49fc6ab2efaf71e56982c6b712c5d7d3598e6fd334a40c389418416425b295684763f4912af5f75a8005011200372ec23f3c1
checksum: 10/2fc6df7ef5d3c46a9cdf9a0feae69b543de16af16972d9833db04499c9a49257809a305a39a0757d8325424d1670555fa9055274a0060bccb4a07fddf4387604
languageName: node
linkType: hard
@@ -1012,14 +1012,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-destructuring@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-destructuring@npm:8.0.1"
"@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"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/0943cf0b04d532576b865f75dc96dc24474550f554bdf43d2f9d6406eae99b76c6a70cdfdeac2f206d1e42cce26a4378679e2828c5d4c5e0155fef064152612e
checksum: 10/ee5ca59cf5a9dea20bc615c305b6dffd3e195ce75dfa1dd5a7dab5fdfb28687fb27da5888d9fae320296818eb651fb8f8e54abee0512b5f85dbf035ea47269b0
languageName: node
linkType: hard
@@ -1127,15 +1127,15 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.5"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/45f849f44927ffc0e57fb2723173a0717f1458584d51f3b94f8bd6cab73d7e73e60613bf704c2358ceb4eeee9c54bb93a7bd8ca4ce064469be58f90c88d7b3d8
checksum: 10/b9bc20dff616168fe45ee1aadaa7b03cff004a19ad1d8e19d72b5920d6b4996311ce155d87f52e473743d456c599bac90bae0098210b888a06a1edbb23c11791
languageName: node
linkType: hard
@@ -1596,15 +1596,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-optional-chaining@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-optional-chaining@npm:8.0.1"
"@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"
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/0098572efbf897678ba2e58cdf53fabb699bffe7c90c6be83879e1b799e167306e406ae03721656e51d333cca037b60e643ad2fbba82c4738af09d709973cc64
checksum: 10/35561003194fcbb21fb1e24777793fed729fbfbb24670b005e450923c3af3ac4799ef7ef7bb4ce14e41aef39c0f695209656537d43174556f43bc77362d92afb
languageName: node
linkType: hard
@@ -1619,14 +1619,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-parameters@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-parameters@npm:8.0.1"
"@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"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/0ad77e2a72b9f2882983a38367b149c0abe7867cc3503ac4eec96b6f192e51e23f9e37f60daf3caf54d81d3767b85609f51a509554ed4de2982cc17bd6eb5115
checksum: 10/9c1f1ea54e5212f8d10e7f5698409da6658e8762056a70c8000266cb79feb0a6b83809cf2a897df0dc1fa14f42d5451f6059ffc050a67ad91b6b4c4bd4abb647
languageName: node
linkType: hard
@@ -1667,16 +1667,16 @@ __metadata:
languageName: node
linkType: hard
"@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"
"@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"
dependencies:
"@babel/helper-annotate-as-pure": "npm:^8.0.0"
"@babel/helper-create-class-features-plugin": "npm:^8.0.1"
"@babel/helper-create-class-features-plugin": "npm:^8.0.5"
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/70d921b70726cb68770d1dfc0b72b58c3bbeacd9b9ff06cd9b81618430cf2e312410c489c506001c78e35a069c15fff7e6bcee5531120e3d69cd6c2074eaa315
checksum: 10/55fc5edc56808125d3c2fe813f7d41cdf1287e56f7b11a0b2a2db46d01274200a3258f80c9319040e7c52c40378eeac59efde5200c6eb1bf1e70a42d098f7901
languageName: node
linkType: hard
@@ -1713,14 +1713,14 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-regenerator@npm:^8.0.2":
version: 8.0.2
resolution: "@babel/plugin-transform-regenerator@npm:8.0.2"
"@babel/plugin-transform-regenerator@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-regenerator@npm:8.0.5"
dependencies:
"@babel/helper-plugin-utils": "npm:^8.0.1"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/81b865156ef174acad44fb589f4cc01f912148a907dfa9a30a6669504e9218c40ad7bee98b33149d3a9a1dc2b5659405765bc07598ae41084b9f5258322ac153
checksum: 10/290cad28d2f9370af9b9da3a6d11454739e9630ada216dfeb390f39c20f192a567ffc96d9e6dddaab85649c71f7424c43f75a50423d39b04ad2cc17dc3924932
languageName: node
linkType: hard
@@ -1816,15 +1816,15 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-transform-spread@npm:^8.0.1":
version: 8.0.1
resolution: "@babel/plugin-transform-spread@npm:8.0.1"
"@babel/plugin-transform-spread@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/plugin-transform-spread@npm:8.0.5"
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/3487febd0eda7988f0538dd0fc683574b5c4a6551ad3625e453adec0f58617bb0b4cd93223a9659850d23d2da30d7a3ab14a94eae01771c0bcde672953595e4a
checksum: 10/502942686a85fb5536a7b44d64d3597442100132d861239541a50a5b38058c0a6d0ae0252099b20b204ad0783eefc68acf30a54c3a5c1c5e52a2ab6170e29966
languageName: node
linkType: hard
@@ -1988,35 +1988,35 @@ __metadata:
languageName: node
linkType: hard
"@babel/preset-env@npm:8.0.2":
version: 8.0.2
resolution: "@babel/preset-env@npm:8.0.2"
"@babel/preset-env@npm:8.0.5":
version: 8.0.5
resolution: "@babel/preset-env@npm:8.0.5"
dependencies:
"@babel/compat-data": "npm:^8.0.0"
"@babel/helper-compilation-targets": "npm:^8.0.0"
"@babel/compat-data": "npm:^8.0.5"
"@babel/helper-compilation-targets": "npm:^8.0.5"
"@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.1"
"@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "npm:^8.0.5"
"@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.1"
"@babel/plugin-transform-block-scoping": "npm:^8.0.5"
"@babel/plugin-transform-class-properties": "npm:^8.0.1"
"@babel/plugin-transform-class-static-block": "npm:^8.0.1"
"@babel/plugin-transform-classes": "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-computed-properties": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.1"
"@babel/plugin-transform-destructuring": "npm:^8.0.5"
"@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.1"
"@babel/plugin-transform-explicit-resource-management": "npm:^8.0.5"
"@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.1"
"@babel/plugin-transform-parameters": "npm:^8.0.1"
"@babel/plugin-transform-optional-chaining": "npm:^8.0.5"
"@babel/plugin-transform-parameters": "npm:^8.0.5"
"@babel/plugin-transform-private-methods": "npm:^8.0.1"
"@babel/plugin-transform-private-property-in-object": "npm:^8.0.1"
"@babel/plugin-transform-private-property-in-object": "npm:^8.0.5"
"@babel/plugin-transform-property-literals": "npm:^8.0.1"
"@babel/plugin-transform-regenerator": "npm:^8.0.2"
"@babel/plugin-transform-regenerator": "npm:^8.0.5"
"@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.1"
"@babel/plugin-transform-spread": "npm:^8.0.5"
"@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"
semver: "npm:^7.7.3"
verkit: "npm:^0.3.2"
peerDependencies:
"@babel/core": ^8.0.0
checksum: 10/58afb0d1c8583c27eaf1d9c6f57704cd8f58f16e7687af2b2012cea0375189f5e296132b6eb2516f96a70a999d657411adcbf8a9743b62e2f70b599be6208a44
checksum: 10/4bd1d0cebad897bbe501c299231daaa7971516da200fc47536e999212c6e49f3c82818f445afc9376302c0ee2ef1ef54f364643ed4f91a601d16e1d23cd8d294
languageName: node
linkType: hard
@@ -2172,10 +2172,10 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:8.0.0":
version: 8.0.0
resolution: "@babel/runtime@npm:8.0.0"
checksum: 10/1aa5079d7d22d0b7eab30596e85b8c7d4a1003166ff4bb5fffadbc779b24c1acf8a08007e7afadd73191ed67b8249da66c5a2b5df29396f975e58c7df952d1a7
"@babel/runtime@npm:8.0.5":
version: 8.0.5
resolution: "@babel/runtime@npm:8.0.5"
checksum: 10/f54e8051ff2c2b7b21b0c3a6b668799a6d033fb3f4edffdcb78928985b15def38b515ecabac477abb04485346328331b2cd0effd892503737773164203604d76
languageName: node
linkType: hard
@@ -2223,18 +2223,18 @@ __metadata:
languageName: node
linkType: hard
"@babel/traverse@npm:^8.0.0":
version: 8.0.4
resolution: "@babel/traverse@npm:8.0.4"
"@babel/traverse@npm:^8.0.0, @babel/traverse@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/traverse@npm:8.0.5"
dependencies:
"@babel/code-frame": "npm:^8.0.0"
"@babel/generator": "npm:^8.0.0"
"@babel/generator": "npm:^8.0.5"
"@babel/helper-globals": "npm:^8.0.0"
"@babel/parser": "npm:^8.0.4"
"@babel/parser": "npm:^8.0.5"
"@babel/template": "npm:^8.0.0"
"@babel/types": "npm:^8.0.4"
"@babel/types": "npm:^8.0.5"
obug: "npm:^2.1.1"
checksum: 10/234bc16c8c14af13e9471141bfd371186bb7fd2c347b1b416c46040e6fc1995242e3852d36181fa7a0240543b8d642a91d33261f942880584c87a7420df7247d
checksum: 10/8827cfd21c3523d370377e8e0360f76c3590a9c6c6d731699aa495697cf8f12abcf475d11130e0c962187d0b1be0d8e55f950a1c4d0ed07780d12d0af82c0ada
languageName: node
linkType: hard
@@ -2248,13 +2248,13 @@ __metadata:
languageName: node
linkType: hard
"@babel/types@npm:^8.0.0, @babel/types@npm:^8.0.4":
version: 8.0.4
resolution: "@babel/types@npm:8.0.4"
"@babel/types@npm:^8.0.0, @babel/types@npm:^8.0.5":
version: 8.0.5
resolution: "@babel/types@npm:8.0.5"
dependencies:
"@babel/helper-string-parser": "npm:^8.0.0"
"@babel/helper-validator-identifier": "npm:^8.0.4"
checksum: 10/7b58bdb4c9149fb5ea6a272912f8cd8af082939a9fc97c6de126299b38f258dd9f78717f7cad3c7fe8bfa7d1fce4cff5fa26b0e80885935255fd3a062e9296ad
checksum: 10/ef05d52ad29993af2513ba5a6d6df4187a33d366241090e5994cc139f527d1f207fdc828302f5cc2f68fc2585dfe93abd8b47941c225b70ac4317df7ce875519
languageName: node
linkType: hard
@@ -3315,6 +3315,16 @@ __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"
@@ -3352,10 +3362,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":
version: 1.5.5
resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
checksum: 10/5d9d207b462c11e322d71911e55e21a4e2772f71ffe8d6f1221b8eb5ae6774458c1d242f897fb0814e8714ca9a6b498abfa74dfe4f434493342902b1a48b33a5
"@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
languageName: node
linkType: hard
@@ -4596,10 +4606,10 @@ __metadata:
languageName: node
linkType: hard
"@oxc-project/types@npm:=0.148.0":
version: 0.148.0
resolution: "@oxc-project/types@npm:0.148.0"
checksum: 10/835b0479161cd80c7dee653b77d31f6d5239e20530cda8a10466bcbb17de08363777939c29670e82fb9d9eca89dc49030e50742051418d987ec70f62faa3317b
"@oxc-project/types@npm:=0.149.0":
version: 0.149.0
resolution: "@oxc-project/types@npm:0.149.0"
checksum: 10/6bd7b656ecdbfa96eea3ca0d79264ad367f941eaec1c47883b7c763a300ac81750de23862089b959b0c9a865abd171145d639368294a9daab0d47df07b1f8c6e
languageName: node
linkType: hard
@@ -4625,107 +4635,107 @@ __metadata:
languageName: node
linkType: hard
"@rolldown/binding-android-arm-eabi@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-android-arm-eabi@npm:1.2.7"
"@rolldown/binding-android-arm-eabi@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-android-arm-eabi@npm:1.2.8"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"@rolldown/binding-android-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-android-arm64@npm:1.2.7"
"@rolldown/binding-android-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-android-arm64@npm:1.2.8"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-darwin-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-darwin-arm64@npm:1.2.7"
"@rolldown/binding-darwin-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-darwin-arm64@npm:1.2.8"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-darwin-x64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-darwin-x64@npm:1.2.7"
"@rolldown/binding-darwin-x64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-darwin-x64@npm:1.2.8"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rolldown/binding-freebsd-x64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-freebsd-x64@npm:1.2.7"
"@rolldown/binding-freebsd-x64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-freebsd-x64@npm:1.2.8"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
"@rolldown/binding-linux-arm-gnueabihf@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.2.7"
"@rolldown/binding-linux-arm-gnueabihf@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.2.8"
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@rolldown/binding-linux-arm64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.2.7"
"@rolldown/binding-linux-arm64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.2.8"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-arm64-musl@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-arm64-musl@npm:1.2.7"
"@rolldown/binding-linux-arm64-musl@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-arm64-musl@npm:1.2.8"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rolldown/binding-linux-ppc64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.2.7"
"@rolldown/binding-linux-ppc64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.2.8"
conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-s390x-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.2.7"
"@rolldown/binding-linux-s390x-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.2.8"
conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-x64-gnu@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-x64-gnu@npm:1.2.7"
"@rolldown/binding-linux-x64-gnu@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-x64-gnu@npm:1.2.8"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rolldown/binding-linux-x64-musl@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-linux-x64-musl@npm:1.2.7"
"@rolldown/binding-linux-x64-musl@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-linux-x64-musl@npm:1.2.8"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rolldown/binding-openharmony-arm64@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-openharmony-arm64@npm:1.2.7"
"@rolldown/binding-openharmony-arm64@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-openharmony-arm64@npm:1.2.8"
conditions: os=openharmony & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-win32-arm64-msvc@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.2.7"
"@rolldown/binding-win32-arm64-msvc@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.2.8"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rolldown/binding-win32-x64-msvc@npm:1.2.7":
version: 1.2.7
resolution: "@rolldown/binding-win32-x64-msvc@npm:1.2.7"
"@rolldown/binding-win32-x64-msvc@npm:1.2.8":
version: 1.2.8
resolution: "@rolldown/binding-win32-x64-msvc@npm:1.2.8"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@@ -5645,26 +5655,6 @@ __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"
@@ -10360,11 +10350,11 @@ __metadata:
resolution: "home-assistant-frontend@workspace:."
dependencies:
"@ampproject/remapping": "npm:2.3.0"
"@babel/core": "npm:8.0.1"
"@babel/core": "npm:8.0.5"
"@babel/helper-define-polyfill-provider": "npm:1.0.0"
"@babel/plugin-transform-runtime": "npm:8.0.1"
"@babel/preset-env": "npm:8.0.2"
"@babel/runtime": "npm:8.0.0"
"@babel/preset-env": "npm:8.0.5"
"@babel/runtime": "npm:8.0.5"
"@braintree/sanitize-url": "npm:7.1.2"
"@bundle-stats/plugin-webpack-filter": "npm:4.22.3"
"@codemirror/autocomplete": "npm:6.20.3"
@@ -10421,7 +10411,6 @@ __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"
@@ -10486,12 +10475,12 @@ __metadata:
intl-messageformat: "npm:11.2.14"
js-yaml: "npm:5.4.1"
jsdom: "npm:30.0.1"
jszip: "npm:3.10.1"
jszip: "npm:3.10.2"
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.0"
lint-staged: "npm:17.5.1"
lit: "npm:3.3.3"
lit-analyzer: "npm:2.0.3"
lit-html: "npm:3.3.3"
@@ -10524,7 +10513,7 @@ __metadata:
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:6.0.3"
typescript-eslint: "npm:8.70.0"
vite: "npm:8.2.2"
vite: "npm:8.3.0"
vite-tsconfig-paths: "npm:6.1.1"
vitest: "npm:5.0.0"
webpack-stats-plugin: "npm:1.1.3"
@@ -11605,15 +11594,15 @@ __metadata:
languageName: node
linkType: hard
"jszip@npm:3.10.1":
version: 3.10.1
resolution: "jszip@npm:3.10.1"
"jszip@npm:3.10.2":
version: 3.10.2
resolution: "jszip@npm:3.10.2"
dependencies:
lie: "npm:~3.3.0"
pako: "npm:~1.0.2"
readable-stream: "npm:~2.3.6"
setimmediate: "npm:^1.0.5"
checksum: 10/bfbfbb9b0a27121330ac46ab9cdb3b4812433faa9ba4a54742c87ca441e31a6194ff70ae12acefa5fe25406c432290e68003900541d948a169b23d30c34dd984
checksum: 10/86666f57397df56a29968e5cbf25a6b50a4812ab7258e1165ae907e6d3b442e84290cd5eefa9cdd4298653009ebe4599dae17f3de30050e4bf4a5e54462fdfd6
languageName: node
linkType: hard
@@ -11893,9 +11882,9 @@ __metadata:
languageName: node
linkType: hard
"lint-staged@npm:17.5.0":
version: 17.5.0
resolution: "lint-staged@npm:17.5.0"
"lint-staged@npm:17.5.1":
version: 17.5.1
resolution: "lint-staged@npm:17.5.1"
dependencies:
picomatch: "npm:^4.0.7"
string-argv: "npm:^0.3.2"
@@ -11906,7 +11895,7 @@ __metadata:
optional: true
bin:
lint-staged: bin/lint-staged.js
checksum: 10/3ca6263488ae3e8e4915e5c6ee70bb3b54bbffcb7e84dd2fb05c02032563401e5bb41c3d216cdc43933c6d6ff3ed66319d22c5cb5c63727e00af966b95929516
checksum: 10/2e10b821214eafce576e8505d6b5cee3a83dd40d68b2d3705b0c69abe35a26e3ad3fcd9cc8379bab47c3e5b3cb8042923d8fbe42e7f72b28da54e6c7d4b4986a
languageName: node
linkType: hard
@@ -13377,7 +13366,7 @@ __metadata:
languageName: node
linkType: hard
"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4, picomatch@npm:^4.0.5, picomatch@npm:^4.0.7":
"picomatch@npm:^4.0.2, picomatch@npm:^4.0.4, picomatch@npm:^4.0.7":
version: 4.0.7
resolution: "picomatch@npm:4.0.7"
checksum: 10/66e1df34bc39c72fa3756be4069f7887ea3e35e94bba1c3f6167763007698cb04b8a0a365161d186fda6e9571a2d3efb606b2966eb6a7dea6252911224dc2f48
@@ -13478,7 +13467,7 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:^8.5.26":
"postcss@npm:^8.5.28":
version: 8.5.28
resolution: "postcss@npm:8.5.28"
dependencies:
@@ -14056,26 +14045,26 @@ __metadata:
languageName: node
linkType: hard
"rolldown@npm:~1.2.4":
version: 1.2.7
resolution: "rolldown@npm:1.2.7"
"rolldown@npm:~1.2.6":
version: 1.2.8
resolution: "rolldown@npm:1.2.8"
dependencies:
"@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"
"@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"
"@rolldown/pluginutils": "npm:^1.0.0"
dependenciesMeta:
"@rolldown/binding-android-arm-eabi":
@@ -14110,7 +14099,7 @@ __metadata:
optional: true
bin:
rolldown: ./bin/cli.mjs
checksum: 10/e3c23a65a2dbd4733d508a5464727064c7c838e3ff2a76b59c5b6f512a250e21fdc3e622af8f985d1970d0d72518afbd7117fb8f111b65a6d2c228e4b666633c
checksum: 10/7260c1f3d6ee32358f110a425174ae44df9383957cf2364195db371ab407ed3dced45afe14a86556df551fba4efbe073ef53fb994ffd8c5d517754ec55c872b0
languageName: node
linkType: hard
@@ -16012,6 +16001,13 @@ __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"
@@ -16097,19 +16093,19 @@ __metadata:
languageName: node
linkType: hard
"vite@npm:8.2.2":
version: 8.2.2
resolution: "vite@npm:8.2.2"
"vite@npm:8.3.0":
version: 8.3.0
resolution: "vite@npm:8.3.0"
dependencies:
fsevents: "npm:~2.3.3"
lightningcss: "npm:^1.33.0"
picomatch: "npm:^4.0.5"
postcss: "npm:^8.5.26"
rolldown: "npm:~1.2.4"
picomatch: "npm:^4.0.7"
postcss: "npm:^8.5.28"
rolldown: "npm:~1.2.6"
tinyglobby: "npm:^0.2.17"
peerDependencies:
"@types/node": ^20.19.0 || >=22.12.0
"@vitejs/devtools": ^0.4.0 || ^0.5.0
"@vitejs/devtools": ^0.7.1
esbuild: ^0.27.0 || ^0.28.0
jiti: ">=1.21.0"
less: ^4.0.0
@@ -16150,7 +16146,7 @@ __metadata:
optional: true
bin:
vite: bin/vite.js
checksum: 10/65cd73267ea2fd49736e51e91681ddc5cbee3af880f20ce5c8df3d4c97d811a11e3ca62d3899fc8ac98ec442b5bc6f55a5d7625ac574ab68c7e3e541e543f264
checksum: 10/7f373449d1189c6b54c24555aab260afb0863e864a7f4a0b52e59dbbe86e4166ee6e82c3b4ab82cb00b38a5f0922ab665cf2dcfb5c7fb6a31812cc71a456fe72
languageName: node
linkType: hard