fix: сохранить клавиатурную подсказку (#565)

Issue: #565
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-14 07:06:16 +00:00
committed by claude[bot]
parent c23c7927de
commit dded4fbd5c
57 changed files with 486 additions and 390 deletions
+3 -3
View File
@@ -5744,10 +5744,8 @@ export class HouseplanCard extends LitElement {
if (this._liveRt) this._liveRt.deviceFocusTip(target, d);
else void this._ensureLiveRuntime().then(() => this._liveRt?.deviceFocusTip(target, d));
}
private _hideDeviceFocusTip(deviceId: string): void { this._liveRt?.deviceBlur(deviceId); }
private _clearPointerHover(): void { this._liveRt?.pointerLeave() ?? this._clearTransientHover(); }
private _clearPointerHover(): void { this._liveRt ? this._liveRt.pointerLeave() : this._clearTransientHover(); }
/** Right click in VIEW mode always opens HA's more-info (owner's decision). */
private _ctxDevice(ev: MouseEvent, d: DevItem): void {
@@ -7303,6 +7301,7 @@ export class HouseplanCard extends LitElement {
/** Remove visual state that can only be owned by a live mouse hover. */
private _clearTransientHover(suspend = false): void {
if (suspend) this._pointerModality.suspend();
this._liveRt?.clearDeviceFocus();
this._deviceHits.hover(this.renderRoot, null);
if (this._tip) this._tip = null;
if (this._hoverRoom) this._hoverRoom = null;
@@ -7432,6 +7431,7 @@ export class HouseplanCard extends LitElement {
this._notePointer(ev);
if (!this._pointerModality.hoverEnabled) return;
if (this._drag || this._deviceDrag) return;
if (room && this._liveRt?.deviceFocusActive()) return;
this._tip = { x: ev.clientX, y: ev.clientY, title, meta, lqi, temp, hum, room, source: 'pointer' };
this._syncLiveHover();
}
+16 -8
View File
@@ -45,6 +45,7 @@ interface DeviceTipHost extends LiveHoverHost {
}
const states = new WeakMap<object, HoverState>();
const focusTips = new WeakMap<object, LiveTip>();
const deviceTipContent = (host: DeviceTipHost, device: DevItem): { title: string; meta: string } => {
const showLqi = host._spaceDisplayForRender().showLqi ?? host._config?.show_signal ?? true;
@@ -67,7 +68,6 @@ export function showDevicePointerTip(value: object, event: PointerEvent, device:
host._deviceHits.hover(host.renderRoot, null);
return;
}
if (host._tip?.source === 'focus') return;
const tip = deviceTipContent(host, device);
host._deviceHits.hover(host.renderRoot, device.id);
host._showTip(event, tip.title, tip.meta);
@@ -78,37 +78,45 @@ export function showDeviceFocusTip(value: object, target: HTMLElement | null, de
if (host._mode !== 'view' || host._drag || host._deviceDrag
|| !target?.matches(':focus-visible')) return;
const rect = target.getBoundingClientRect();
host._tip = {
const tip: LiveTip = {
x: rect.right, y: rect.top, ...deviceTipContent(host, device),
source: 'focus', deviceId: device.id,
};
focusTips.set(value, tip);
host._tip = tip;
syncHouseplanHover(host);
}
export function hideDeviceFocusTip(value: object, deviceId: string): void {
const host = value as DeviceTipHost;
if (host._tip?.source !== 'focus' || host._tip.deviceId !== deviceId) return;
host._tip = null;
if (focusTips.get(value)?.deviceId !== deviceId) return;
focusTips.delete(value);
if (host._tip?.source === 'focus') host._tip = null;
syncHouseplanHover(host);
}
export function clearPointerHover(value: object): void {
const host = value as DeviceTipHost;
host._deviceHits.hover(host.renderRoot, null);
if (host._tip?.source !== 'focus') host._tip = null;
host._tip = focusTips.get(value) || null;
host._hoverRoom = null;
syncHouseplanHover(host);
}
export function reconcileDeviceFocusTip(value: object): void {
const host = value as DeviceTipHost;
if (host._tip?.source !== 'focus') return;
const tip = focusTips.get(value);
if (!tip) return;
const marker = [...host.renderRoot.querySelectorAll<HTMLElement>('[data-hp="device"]')]
.find((node) => node.dataset.id === host._tip?.deviceId);
.find((node) => node.dataset.id === tip.deviceId);
if (marker?.matches(':focus-visible')) return;
host._tip = null;
focusTips.delete(value);
if (host._tip?.source === 'focus') host._tip = null;
}
export const deviceFocusTipActive = (value: object): boolean => focusTips.has(value);
export const clearDeviceFocusTip = (value: object): void => { focusTips.delete(value); };
const appendMeta = (tip: HTMLElement, label: string, value?: string, color?: string): void => {
if (!value) return;
const row = document.createElement('span');
+6 -2
View File
@@ -2,8 +2,9 @@ import {
commitHouseplanViewport, disposeHouseplanViewport, scheduleHouseplanViewport,
} from './live-viewport';
import {
clearPointerHover, hideDeviceFocusTip, reconcileDeviceFocusTip, resetHouseplanHover,
showDeviceFocusTip, showDevicePointerTip, syncHouseplanHover,
clearDeviceFocusTip, clearPointerHover, deviceFocusTipActive, hideDeviceFocusTip,
reconcileDeviceFocusTip, resetHouseplanHover, showDeviceFocusTip, showDevicePointerTip,
syncHouseplanHover,
} from './live-hover';
import {
classifyHassRenderChange, type HassRenderDependencies, type HassRenderSnapshot,
@@ -65,6 +66,8 @@ export class LiveRuntime {
}
public deviceBlur(deviceId: string): void { hideDeviceFocusTip(this.host, deviceId); }
public pointerLeave(): void { clearPointerHover(this.host); }
public deviceFocusActive(): boolean { return deviceFocusTipActive(this.host); }
public clearDeviceFocus(): void { clearDeviceFocusTip(this.host); }
public active(): boolean {
const host = this.host as LiveRuntimeHost;
return host._pointers.size > 0 || host._cameraTransition.active || !!host._deviceDrag
@@ -80,6 +83,7 @@ export class LiveRuntime {
}
public dispose(): void {
disposeHouseplanViewport(this.host);
clearDeviceFocusTip(this.host);
resetHouseplanHover(this.host);
}
}