Automation editor: fix focus handling (#26755)

This commit is contained in:
Wendelin
2025-08-29 08:39:06 +02:00
committed by GitHub
parent a376670478
commit b86c1db83d
9 changed files with 60 additions and 54 deletions

View File

@@ -103,7 +103,9 @@ export class HaAutomationRow extends LitElement {
} }
public focus() { public focus() {
requestAnimationFrame(() => this._rowElement?.focus()); requestAnimationFrame(() => {
this._rowElement?.focus();
});
} }
static styles = css` static styles = css`

View File

@@ -558,11 +558,11 @@ export interface AutomationClipboard {
export interface BaseSidebarConfig { export interface BaseSidebarConfig {
toggleYamlMode: () => boolean; toggleYamlMode: () => boolean;
delete: () => void; delete: () => void;
close: (focus?: boolean) => void;
} }
export interface TriggerSidebarConfig extends BaseSidebarConfig { export interface TriggerSidebarConfig extends BaseSidebarConfig {
save: (value: Trigger) => void; save: (value: Trigger) => void;
close: () => void;
rename: () => void; rename: () => void;
disable: () => void; disable: () => void;
duplicate: () => void; duplicate: () => void;
@@ -575,7 +575,6 @@ export interface TriggerSidebarConfig extends BaseSidebarConfig {
export interface ConditionSidebarConfig extends BaseSidebarConfig { export interface ConditionSidebarConfig extends BaseSidebarConfig {
save: (value: Condition) => void; save: (value: Condition) => void;
close: () => void;
rename: () => void; rename: () => void;
disable: () => void; disable: () => void;
test: () => void; test: () => void;
@@ -589,7 +588,6 @@ export interface ConditionSidebarConfig extends BaseSidebarConfig {
export interface ActionSidebarConfig extends BaseSidebarConfig { export interface ActionSidebarConfig extends BaseSidebarConfig {
save: (value: Action) => void; save: (value: Action) => void;
close: () => void;
rename: () => void; rename: () => void;
disable: () => void; disable: () => void;
duplicate: () => void; duplicate: () => void;
@@ -604,7 +602,6 @@ export interface ActionSidebarConfig extends BaseSidebarConfig {
} }
export interface OptionSidebarConfig extends BaseSidebarConfig { export interface OptionSidebarConfig extends BaseSidebarConfig {
close: () => void;
rename: () => void; rename: () => void;
duplicate: () => void; duplicate: () => void;
defaultOption?: boolean; defaultOption?: boolean;
@@ -612,7 +609,6 @@ export interface OptionSidebarConfig extends BaseSidebarConfig {
export interface ScriptFieldSidebarConfig extends BaseSidebarConfig { export interface ScriptFieldSidebarConfig extends BaseSidebarConfig {
save: (value: Field) => void; save: (value: Field) => void;
close: () => void;
config: { config: {
field: Field; field: Field;
selector: boolean; selector: boolean;

View File

@@ -676,9 +676,12 @@ export default class HaAutomationActionRow extends LitElement {
save: (value) => { save: (value) => {
fireEvent(this, "value-changed", { value }); fireEvent(this, "value-changed", { value });
}, },
close: () => { close: (focus?: boolean) => {
this._selected = false; this._selected = false;
fireEvent(this, "close-sidebar"); fireEvent(this, "close-sidebar");
if (focus) {
this.focus();
}
}, },
rename: () => { rename: () => {
this._renameAction(); this._renameAction();

View File

@@ -648,9 +648,12 @@ export default class HaAutomationConditionRow extends LitElement {
save: (value) => { save: (value) => {
fireEvent(this, "value-changed", { value }); fireEvent(this, "value-changed", { value });
}, },
close: () => { close: (focus?: boolean) => {
this._selected = false; this._selected = false;
fireEvent(this, "close-sidebar"); fireEvent(this, "close-sidebar");
if (focus) {
this.focus();
}
}, },
rename: () => { rename: () => {
this._renameCondition(); this._renameCondition();

View File

@@ -193,7 +193,7 @@ export default class HaAutomationSidebar extends LitElement {
} }
private _closeSidebar() { private _closeSidebar() {
this.config?.close(); this.config?.close(true);
} }
private _toggleYamlMode = () => { private _toggleYamlMode = () => {

View File

@@ -385,9 +385,12 @@ export default class HaAutomationOptionRow extends LitElement {
public openSidebar(): void { public openSidebar(): void {
fireEvent(this, "open-sidebar", { fireEvent(this, "open-sidebar", {
close: () => { close: (focus?: boolean) => {
this._selected = false; this._selected = false;
fireEvent(this, "close-sidebar"); fireEvent(this, "close-sidebar");
if (focus) {
this.focus();
}
}, },
rename: () => { rename: () => {
this._renameOption(); this._renameOption();

View File

@@ -482,9 +482,12 @@ export default class HaAutomationTriggerRow extends LitElement {
save: (value) => { save: (value) => {
fireEvent(this, "value-changed", { value }); fireEvent(this, "value-changed", { value });
}, },
close: () => { close: (focus?: boolean) => {
this._selected = false; this._selected = false;
fireEvent(this, "close-sidebar"); fireEvent(this, "close-sidebar");
if (focus) {
this.focus();
}
}, },
rename: () => { rename: () => {
this._renameTrigger(); this._renameTrigger();

View File

@@ -1,17 +1,12 @@
import { mdiDelete } from "@mdi/js";
import type { CSSResultGroup } from "lit"; import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit"; import { LitElement, css, html, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators"; import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map"; import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../../common/dom/fire_event"; import { fireEvent } from "../../../common/dom/fire_event";
import { preventDefaultStopPropagation } from "../../../common/dom/prevent_default_stop_propagation";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import type { LocalizeKeys } from "../../../common/translations/localize"; import type { LocalizeKeys } from "../../../common/translations/localize";
import "../../../components/ha-automation-row"; import "../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../components/ha-automation-row";
import "../../../components/ha-card"; import "../../../components/ha-card";
import "../../../components/ha-icon-button";
import "../../../components/ha-md-button-menu";
import "../../../components/ha-md-menu-item";
import type { ScriptFieldSidebarConfig } from "../../../data/automation"; import type { ScriptFieldSidebarConfig } from "../../../data/automation";
import type { Field } from "../../../data/script"; import type { Field } from "../../../data/script";
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector"; import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
@@ -50,6 +45,12 @@ export default class HaScriptFieldRow extends LitElement {
@query("ha-script-field-selector-editor") @query("ha-script-field-selector-editor")
private _selectorEditor?: HaScriptFieldSelectorEditor; private _selectorEditor?: HaScriptFieldSelectorEditor;
@query("ha-automation-row:first-of-type")
private _fieldRowElement?: HaAutomationRow;
@query(".selector-row ha-automation-row")
private _selectorRowElement?: HaAutomationRow;
protected render() { protected render() {
return html` return html`
<ha-card outlined> <ha-card outlined>
@@ -64,29 +65,6 @@ export default class HaScriptFieldRow extends LitElement {
<h3 slot="header">${this.key}</h3> <h3 slot="header">${this.key}</h3>
<slot name="icons" slot="icons"></slot> <slot name="icons" slot="icons"></slot>
<ha-md-button-menu
quick
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this._onDelete}
.disabled=${this.disabled}
class="warning"
>
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
)}
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
</ha-md-menu-item>
</ha-md-button-menu>
</ha-automation-row> </ha-automation-row>
</ha-card> </ha-card>
<div <div
@@ -224,11 +202,17 @@ export default class HaScriptFieldRow extends LitElement {
save: (value) => { save: (value) => {
fireEvent(this, "value-changed", { value }); fireEvent(this, "value-changed", { value });
}, },
close: () => { close: (focus?: boolean) => {
if (selectorEditor) { if (selectorEditor) {
this._selectorRowSelected = false; this._selectorRowSelected = false;
if (focus) {
this.focusSelector();
}
} else { } else {
this._selected = false; this._selected = false;
if (focus) {
this.focus();
}
} }
fireEvent(this, "close-sidebar"); fireEvent(this, "close-sidebar");
}, },
@@ -280,15 +264,19 @@ export default class HaScriptFieldRow extends LitElement {
}); });
}; };
public focus() {
this._fieldRowElement?.focus();
}
public focusSelector() {
this._selectorRowElement?.focus();
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return [ return [
haStyle, haStyle,
indentStyle, indentStyle,
css` css`
ha-button-menu,
ha-icon-button {
--mdc-theme-text-primary-on-background: var(--primary-text-color);
}
.disabled { .disabled {
opacity: 0.5; opacity: 0.5;
pointer-events: none; pointer-events: none;
@@ -334,9 +322,6 @@ export default class HaScriptFieldRow extends LitElement {
); );
} }
ha-md-menu-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
.warning ul { .warning ul {
margin: 4px 0; margin: 4px 0;
} }
@@ -352,6 +337,10 @@ export default class HaScriptFieldRow extends LitElement {
border-color: var(--state-inactive-color); border-color: var(--state-inactive-color);
box-shadow: var(--shadow-default), var(--shadow-focus); box-shadow: var(--shadow-default), var(--shadow-focus);
} }
.selector-row {
padding: 12px 0 16px 16px;
}
`, `,
]; ];
} }

View File

@@ -38,6 +38,7 @@ import { showToast } from "../../../util/toast";
import "../automation/action/ha-automation-action"; import "../automation/action/ha-automation-action";
import type HaAutomationAction from "../automation/action/ha-automation-action"; import type HaAutomationAction from "../automation/action/ha-automation-action";
import "../automation/ha-automation-sidebar"; import "../automation/ha-automation-sidebar";
import type HaAutomationSidebar from "../automation/ha-automation-sidebar";
import { showPasteReplaceDialog } from "../automation/paste-replace-dialog/show-dialog-paste-replace"; import { showPasteReplaceDialog } from "../automation/paste-replace-dialog/show-dialog-paste-replace";
import { manualEditorStyles, saveFabStyles } from "../automation/styles"; import { manualEditorStyles, saveFabStyles } from "../automation/styles";
import "./ha-script-fields"; import "./ha-script-fields";
@@ -69,17 +70,19 @@ export class HaManualScriptEditor extends LitElement {
@property({ attribute: false }) public dirty = false; @property({ attribute: false }) public dirty = false;
@query("ha-script-fields")
private _scriptFields?: HaScriptFields;
private _openFields = false;
@state() private _pastedConfig?: ScriptConfig; @state() private _pastedConfig?: ScriptConfig;
@state() private _sidebarConfig?: SidebarConfig; @state() private _sidebarConfig?: SidebarConfig;
@query("ha-script-fields")
private _scriptFields?: HaScriptFields;
@query("ha-automation-sidebar") private _sidebarElement?: HaAutomationSidebar;
private _previousConfig?: ScriptConfig; private _previousConfig?: ScriptConfig;
private _openFields = false;
public addFields() { public addFields() {
this._openFields = true; this._openFields = true;
fireEvent(this, "value-changed", { fireEvent(this, "value-changed", {
@@ -217,6 +220,7 @@ export class HaManualScriptEditor extends LitElement {
</ha-fab> </ha-fab>
</div> </div>
<ha-automation-sidebar <ha-automation-sidebar
tabindex="-1"
class=${classMap({ class=${classMap({
sidebar: true, sidebar: true,
overlay: !this.isWide, overlay: !this.isWide,
@@ -455,10 +459,13 @@ export class HaManualScriptEditor extends LitElement {
}); });
} }
private _openSidebar(ev: CustomEvent<SidebarConfig>) { private async _openSidebar(ev: CustomEvent<SidebarConfig>) {
// deselect previous selected row // deselect previous selected row
this._sidebarConfig?.close?.(); this._sidebarConfig?.close?.();
this._sidebarConfig = ev.detail; this._sidebarConfig = ev.detail;
await this._sidebarElement?.updateComplete;
this._sidebarElement?.focus();
} }
private _sidebarConfigChanged(ev: CustomEvent<{ value: SidebarConfig }>) { private _sidebarConfigChanged(ev: CustomEvent<{ value: SidebarConfig }>) {