Compare commits

..

1 Commits

Author SHA1 Message Date
Aidan Timson
138738431b Fix esc closing all dialogs or sheets (close one after another) 2026-02-19 15:59:26 +00:00
11 changed files with 126 additions and 171 deletions

View File

@@ -210,7 +210,7 @@
"rspack-manifest-plugin": "5.2.1",
"serve": "14.2.5",
"sinon": "21.0.1",
"tar": "7.5.8",
"tar": "7.5.7",
"terser-webpack-plugin": "5.3.16",
"ts-lit-plugin": "2.0.2",
"typescript": "5.9.3",

View File

@@ -117,25 +117,27 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
};
private _handleHide = (ev: CustomEvent<{ source: Element }>) => {
const sourceIsDrawer = ev.detail.source === (ev.target as WaDrawer).drawer;
if (this._sliderInteractionActive) {
ev.preventDefault();
this._drawerOpen = true;
this.open = true;
this._escapePressed = false;
return;
}
if (
this.preventScrimClose &&
this._escapePressed &&
ev.detail.source === (ev.target as WaDrawer).drawer
) {
if (this.preventScrimClose && this._escapePressed && sourceIsDrawer) {
ev.preventDefault();
}
this._escapePressed = false;
};
private _handleKeyDown = (ev: KeyboardEvent) => {
if (ev.key === "Escape") {
this._escapePressed = true;
ev.stopPropagation();
(ev.currentTarget as WaDrawer).open = false;
}
};

View File

@@ -237,17 +237,18 @@ export class HaDialog extends ScrollableFadeMixin(LitElement) {
private _handleKeyDown(ev: KeyboardEvent) {
if (ev.key === "Escape") {
this._escapePressed = true;
ev.stopPropagation();
(ev.currentTarget as WaDialog).open = false;
}
}
private _handleHide(ev: CustomEvent<{ source: Element }>) {
if (
this.preventScrimClose &&
this._escapePressed &&
ev.detail.source === (ev.target as WaDialog).dialog
) {
const sourceIsDialog = ev.detail.source === (ev.target as WaDialog).dialog;
if (this.preventScrimClose && this._escapePressed && sourceIsDialog) {
ev.preventDefault();
}
this._escapePressed = false;
}

View File

@@ -194,6 +194,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
.image=${this.image}
.label=${label}
.placeholder=${this.placeholder}
.helper=${this.helper}
.value=${this.value}
.valueRenderer=${this.valueRenderer}
.required=${this.required}

View File

@@ -126,7 +126,6 @@ export class HaPickerField extends PickerMixin(LitElement) {
);
}
ha-combo-box-item {
position: relative;
background-color: var(--mdc-text-field-fill-color, whitesmoke);
border-radius: var(--ha-border-radius-sm);
border-end-end-radius: 0;

View File

@@ -5,7 +5,6 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import "./ha-dropdown";
import "./ha-dropdown-item";
import "./ha-input-helper-text";
import "./ha-picker-field";
import type { HaPickerField } from "./ha-picker-field";
import "./ha-svg-icon";
@@ -76,7 +75,7 @@ export class HaSelect extends LitElement {
protected override render() {
if (this.disabled) {
return html`${this._renderField()}${this._renderHelper()}`;
return this._renderField();
}
return html`
@@ -117,7 +116,6 @@ export class HaSelect extends LitElement {
)
: html`<slot></slot>`}
</ha-dropdown>
${this._renderHelper()}
`;
}
@@ -133,6 +131,7 @@ export class HaSelect extends LitElement {
aria-label=${ifDefined(this.label)}
@clear=${this._clearValue}
.label=${this.label}
.helper=${this.helper}
.value=${valueLabel}
.required=${this.required}
.disabled=${this.disabled}
@@ -145,14 +144,6 @@ export class HaSelect extends LitElement {
`;
}
private _renderHelper() {
return this.helper
? html`<ha-input-helper-text .disabled=${this.disabled}
>${this.helper}</ha-input-helper-text
>`
: nothing;
}
private _handleSelect(ev: CustomEvent<{ item: { value: string } }>) {
ev.stopPropagation();
const value = ev.detail.item.value;
@@ -203,11 +194,6 @@ export class HaSelect extends LitElement {
ha-dropdown::part(menu) {
min-width: var(--select-menu-width);
}
ha-input-helper-text {
display: block;
margin: var(--ha-space-2) 0 0;
}
`;
}
declare global {

View File

@@ -36,7 +36,7 @@ import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar";
import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart";
import { showShortcutsDialog } from "../../../dialogs/shortcuts/show-shortcuts-dialog";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle, haStyleScrollbar } from "../../../resources/styles";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { documentationUrl } from "../../../util/documentation-url";
import { isMac } from "../../../util/is_mac";
@@ -255,90 +255,88 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
</ha-dropdown-item>
</ha-dropdown>
<div class="content ha-scrollbar">
<ha-config-section
.narrow=${this.narrow}
.isWide=${this.isWide}
full-width
>
${repairsIssues.length || canInstallUpdates.length
? html`<ha-card outlined>
${repairsIssues.length
? html`
<ha-config-repairs
.hass=${this.hass}
.narrow=${this.narrow}
.total=${totalRepairIssues}
.repairsIssues=${repairsIssues}
></ha-config-repairs>
${totalRepairIssues > repairsIssues.length
? html`
<ha-assist-chip
href="/config/repairs"
.label=${this.hass.localize(
"ui.panel.config.repairs.more_repairs",
{
count:
totalRepairIssues - repairsIssues.length,
}
)}
>
</ha-assist-chip>
`
: ""}
`
: ""}
${repairsIssues.length && canInstallUpdates.length
? html`<hr />`
: ""}
${canInstallUpdates.length
? html`
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.total=${totalUpdates}
.updateEntities=${canInstallUpdates}
.isInstallable=${true}
></ha-config-updates>
${totalUpdates > canInstallUpdates.length
? html`
<ha-assist-chip
href="/config/updates"
label=${this.hass.localize(
"ui.panel.config.updates.more_updates",
{
count:
totalUpdates - canInstallUpdates.length,
}
)}
>
</ha-assist-chip>
`
: ""}
`
: ""}
</ha-card>`
: ""}
${this._pages(
this.cloudStatus,
isComponentLoaded(this.hass, "cloud"),
this.hass.auth.external?.config.hasSettingsScreen
).map((categoryPages) =>
categoryPages.length === 0
? nothing
: html`
<ha-card outlined>
<ha-config-navigation
<ha-config-section
.narrow=${this.narrow}
.isWide=${this.isWide}
full-width
>
${repairsIssues.length || canInstallUpdates.length
? html`<ha-card outlined>
${repairsIssues.length
? html`
<ha-config-repairs
.hass=${this.hass}
.narrow=${this.narrow}
.pages=${categoryPages}
></ha-config-navigation>
</ha-card>
`
)}
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
</ha-config-section>
</div>
.total=${totalRepairIssues}
.repairsIssues=${repairsIssues}
></ha-config-repairs>
${totalRepairIssues > repairsIssues.length
? html`
<ha-assist-chip
href="/config/repairs"
.label=${this.hass.localize(
"ui.panel.config.repairs.more_repairs",
{
count:
totalRepairIssues - repairsIssues.length,
}
)}
>
</ha-assist-chip>
`
: ""}
`
: ""}
${repairsIssues.length && canInstallUpdates.length
? html`<hr />`
: ""}
${canInstallUpdates.length
? html`
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.total=${totalUpdates}
.updateEntities=${canInstallUpdates}
.isInstallable=${true}
></ha-config-updates>
${totalUpdates > canInstallUpdates.length
? html`
<ha-assist-chip
href="/config/updates"
label=${this.hass.localize(
"ui.panel.config.updates.more_updates",
{
count:
totalUpdates - canInstallUpdates.length,
}
)}
>
</ha-assist-chip>
`
: ""}
`
: ""}
</ha-card>`
: ""}
${this._pages(
this.cloudStatus,
isComponentLoaded(this.hass, "cloud"),
this.hass.auth.external?.config.hasSettingsScreen
).map((categoryPages) =>
categoryPages.length === 0
? nothing
: html`
<ha-card outlined>
<ha-config-navigation
.hass=${this.hass}
.narrow=${this.narrow}
.pages=${categoryPages}
></ha-config-navigation>
</ha-card>
`
)}
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
</ha-config-section>
</ha-top-app-bar-fixed>
`;
}
@@ -394,36 +392,7 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
static get styles(): CSSResultGroup {
return [
haStyle,
haStyleScrollbar,
css`
:host {
display: block;
height: 100%;
}
ha-top-app-bar-fixed {
height: 100%;
overflow: hidden;
}
.content {
height: calc(
100vh - var(--header-height, 0px) - var(
--safe-area-inset-top,
0px
) - var(--safe-area-inset-bottom, 0px)
);
height: calc(
100dvh - var(--header-height, 0px) - var(
--safe-area-inset-top,
0px
) - var(--safe-area-inset-bottom, 0px)
);
padding-bottom: var(--ha-space-5);
box-sizing: border-box;
overflow-x: hidden;
}
:host(:not([narrow])) ha-card:last-child {
margin-bottom: 24px;
}

View File

@@ -62,7 +62,6 @@ const cardConfigStruct = assign(
literal("day"),
literal("week"),
literal("month"),
literal("year"),
])
),
chart_type: optional(union([literal("bar"), literal("line")])),
@@ -76,7 +75,7 @@ const cardConfigStruct = assign(
})
);
const periods = ["5minute", "hour", "day", "week", "month", "year"] as const;
const periods = ["5minute", "hour", "day", "week", "month"] as const;
const stat_types = [
"mean",
"min",

View File

@@ -1419,7 +1419,6 @@ class HUIRoot extends LitElement {
}
ha-tab-group-tab {
--ha-tab-group-tab-height: var(--header-height, 56px);
height: var(--ha-tab-group-tab-height);
}
.tab-bar ha-tab-group-tab {
--ha-tab-group-tab-height: var(--tab-bar-height, 56px);

View File

@@ -5122,7 +5122,7 @@
"and": {
"label": "And",
"description": {
"picker": "Tests if multiple conditions are true.",
"picker": "Test if multiple conditions are true.",
"no_conditions": "If multiple conditions match",
"full": "If {count} {count, plural,\n one {condition matches}\n other {conditions match}\n}"
}
@@ -5137,7 +5137,7 @@
"not": {
"label": "Not",
"description": {
"picker": "Tests if a condition is not true.",
"picker": "Test if a condition is not true.",
"no_conditions": "If no condition matches",
"one_condition": "If 1 condition does not match",
"full": "If none of {count} conditions match"
@@ -5162,7 +5162,7 @@
"or": {
"label": "Or",
"description": {
"picker": "Tests if any condition is true.",
"picker": "Test if any condition is true.",
"no_conditions": "If any condition matches",
"full": "If any of {count} {count, plural,\n one {condition}\n other {conditions}\n} matches"
}
@@ -5316,7 +5316,7 @@
"play_media": {
"label": "Play media",
"description": {
"picker": "Plays media on a media player.",
"picker": "Play media on a media player.",
"full": "Play {hasMedia, select, \n true {{media}} \n other {media}\n } on {hasMediaPlayer, select, \n true {{mediaPlayer}} \n other {a media player}\n }"
}
},
@@ -5324,7 +5324,7 @@
"label": "Wait for time to pass (delay)",
"delay": "Duration",
"description": {
"picker": "Waits some time before continuing the sequence of actions.",
"picker": "Wait some time before continuing the sequence of actions.",
"full": "Delay {duration}",
"duration_string": "for {string}",
"duration_template": "based on a template",
@@ -5337,7 +5337,7 @@
"timeout": "Timeout (optional)",
"continue_timeout": "Continue on timeout",
"description": {
"picker": "Waits for a template to be evaluated to true to perform a sequence of actions.",
"picker": "Wait for a template to be evaluated to true to perform a sequence of actions.",
"full": "Wait for a template to evaluate to true"
}
},
@@ -5346,7 +5346,7 @@
"timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::timeout%]",
"continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]",
"description": {
"picker": "Waits for a trigger to perform a sequence of actions.",
"picker": "Wait for a trigger to perform a sequence of actions.",
"wait_for_a_trigger": "Wait for a trigger",
"wait_for_triggers": "Wait for {count} {count, plural,\n one {trigger}\n other {triggers}\n}"
}
@@ -5354,7 +5354,7 @@
"condition": {
"label": "Condition",
"description": {
"picker": "Tests a condition (and stops the sequence if the condition is not met)."
"picker": "Test a condition (and stop the sequence if the condition is not met)."
}
},
"event": {
@@ -5362,7 +5362,7 @@
"event": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_type%]",
"event_data": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_data%]",
"description": {
"picker": "Fires an event manually (event is an advanced concept in Home Assistant).",
"picker": "Fire an event manually (event is an advanced concept in Home Assistant).",
"full": "Manually fire event {name}",
"template": "based on a template"
}
@@ -5371,7 +5371,7 @@
"label": "Device",
"action": "Action",
"description": {
"picker": "Does something on a device. Great way to start.",
"picker": "Do something on a device. Great way to start.",
"no_device": "Device action",
"perform_device_action": "Perform action with {device}"
}
@@ -5397,7 +5397,7 @@
},
"sequence": "Actions",
"description": {
"picker": "Repeats a sequence of actions.",
"picker": "Repeat a sequence of actions.",
"full": "Repeat an action {chosenAction}",
"count": "{count} {count, plural,\n one {time}\n other {times}\n}",
"while_count": "while {count} {count, plural,\n one {condition matches}\n other {conditions match}\n} ",
@@ -5408,25 +5408,25 @@
"repeat_count": {
"label": "Repeat multiple times",
"description": {
"picker": "Repeats a sequence of actions a fixed number of times."
"picker": "Repeat a sequence of actions a fixed number of times."
}
},
"repeat_while": {
"label": "Repeat while",
"description": {
"picker": "Repeats a sequence of actions as long as a condition is satisfied. The condition is checked before each run of the sequence."
"picker": "Repeat a sequence of actions as long as a condition is satisfied. The condition is checked before each run of the sequence."
}
},
"repeat_until": {
"label": "Repeat until",
"description": {
"picker": "Repeats a sequence of actions until a condition is satisfied. The condition is checked after each run of the sequence."
"picker": "Repeat a sequence of actions until a condition is satisfied. The condition is checked after each run of the sequence."
}
},
"repeat_for_each": {
"label": "Repeat for each",
"description": {
"picker": "Repeats a sequence for each element of a list."
"picker": "Repeat a sequence for each element of a list."
}
},
"choose": {
@@ -5448,7 +5448,7 @@
"option_description": "Choose actions based on conditions",
"default_option_description": "Optional actions to run if no other options match",
"description": {
"picker": "Chooses what to do based on conditions (Similar to If-then, but more powerful).",
"picker": "Choose what to do based on conditions (Similar to If-then, but more powerful).",
"full": "Choose {number, plural,\n one {an option}\n other{between {number} options}\n}",
"no_action": "Choose an option"
}
@@ -5460,7 +5460,7 @@
"else": "Else",
"add_else": "Add else",
"description": {
"picker": "Does something conditionally.",
"picker": "Do something conditionally.",
"if": "Conditionally execute an action",
"if_else": "Conditionally execute an action and default to another action"
}
@@ -5471,28 +5471,28 @@
"response_variable": "The name of the variable to use as response",
"error": "Stop because of an unexpected error",
"description": {
"picker": "Stops the sequence of actions.",
"picker": "Stop the sequence of actions.",
"full": "Stop {hasReason, select, \n true { because: {reason}} \n other {}\n }"
}
},
"sequence": {
"label": "Run in sequence",
"description": {
"picker": "Runs a group of actions in sequence.",
"picker": "Run a group of actions in sequence.",
"full": "Run {number} {number, plural,\n one {action}\n other {actions}\n} in sequence"
}
},
"parallel": {
"label": "Run in parallel",
"description": {
"picker": "Performs actions in parallel.",
"picker": "Perform actions in parallel.",
"full": "Run {number} {number, plural,\n one {action}\n other {actions}\n} in parallel"
}
},
"variables": {
"label": "Define variables",
"description": {
"picker": "Defines variables to be used later in the sequence.",
"picker": "Define variables to be used later in the sequence.",
"full": "Define variables {names}"
}
},
@@ -5504,7 +5504,7 @@
"set_conversation_response": {
"label": "Set conversation response",
"description": {
"picker": "Sets the response of a conversation if the automation was triggered by conversation trigger.",
"picker": "Set response of conversation if automation was triggered by conversation trigger.",
"template": "Set response of conversation to a template",
"full": "Set response of conversation to ''{response}''"
}
@@ -8797,7 +8797,6 @@
"day": "Day",
"month": "Month",
"week": "Week",
"year": "Year",
"5minute": "5 minutes"
},
"pick_statistic": "Add a statistic",

View File

@@ -9302,7 +9302,7 @@ __metadata:
sortablejs: "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch"
stacktrace-js: "npm:2.0.2"
superstruct: "npm:2.0.2"
tar: "npm:7.5.8"
tar: "npm:7.5.7"
terser-webpack-plugin: "npm:5.3.16"
tinykeys: "npm:3.0.0"
ts-lit-plugin: "npm:2.0.2"
@@ -13722,16 +13722,16 @@ __metadata:
languageName: node
linkType: hard
"tar@npm:7.5.8, tar@npm:^7.5.2":
version: 7.5.8
resolution: "tar@npm:7.5.8"
"tar@npm:7.5.7, tar@npm:^7.5.2":
version: 7.5.7
resolution: "tar@npm:7.5.7"
dependencies:
"@isaacs/fs-minipass": "npm:^4.0.0"
chownr: "npm:^3.0.0"
minipass: "npm:^7.1.2"
minizlib: "npm:^3.1.0"
yallist: "npm:^5.0.0"
checksum: 10/5fddc22e0fd03e73d5e9e922e71d8681f85443dee4f21403059a757e186ae4004abc9a709cdc7f4143d7d75758a2935f7306b3cc193123d46b6f786dd2b99c2a
checksum: 10/0d6938dd32fe5c0f17c8098d92bd9889ee0ed9d11f12381b8146b6e8c87bb5aa49feec7abc42463f0597503d8e89e4c4c0b42bff1a5a38444e918b4878b7fd21
languageName: node
linkType: hard