Files
houseplan-card/src/live-interaction-runtime.ts
T
2026-09-04 22:04:17 +03:00

73 lines
2.7 KiB
TypeScript

import {
commitHouseplanViewport, disposeHouseplanViewport, scheduleHouseplanViewport,
} from './live-viewport';
import { resetHouseplanHover, syncHouseplanHover } from './live-hover';
import {
classifyHassRenderChange, type HassRenderDependencies, type HassRenderSnapshot,
} from './render-invalidation';
import type { RenderLifecycle } from './houseplan-render-lifecycle';
interface LiveRuntimeHost {
_renderLife: RenderLifecycle;
_pointers: { size: number };
_cameraTransition: { active: boolean };
_deviceDrag?: unknown;
_physicalDrag?: unknown;
_physicalRotate?: unknown;
_decorMove?: unknown;
_decorDraft?: unknown;
_dtDrag?: unknown;
_bdDrag?: unknown;
_opDrag?: unknown;
_resize?: { dragging: boolean };
}
/** Lazily loaded DOM-only fast paths; the card keeps a full-render fallback. */
export class LiveRuntime {
private deferredHass = false;
public constructor(private readonly host: object) {}
public hass(
before: HassRenderSnapshot | null | undefined,
after: HassRenderSnapshot | null | undefined,
dependencies: HassRenderDependencies | null,
intake: () => void,
): boolean {
const change = classifyHassRenderChange(before, after, dependencies);
const defer = change === 'state' && this.active();
if (defer) this.deferredHass = true;
const render = change !== 'none' && !defer;
// Preserve ReactiveElement's ordering for snapshots which are about to
// render: willUpdate owns their intake. Tests, config editors and HA can
// legitimately finish other same-turn mutations after assigning `hass`.
// Only a deliberately skipped update needs operational intake here.
if (!render) {
(this.host as LiveRuntimeHost)._renderLife.observe(before, after, dependencies, intake);
}
return render;
}
public clear(): void { this.deferredHass = false; }
public take(): boolean {
const pending = this.deferredHass;
this.deferredHass = false;
return pending;
}
public viewport(now = false): void { scheduleHouseplanViewport(this.host, now); }
public hover(): void { syncHouseplanHover(this.host); }
public active(): boolean {
const host = this.host as LiveRuntimeHost;
return host._pointers.size > 0 || host._cameraTransition.active || !!host._deviceDrag
|| !!host._physicalDrag || !!host._physicalRotate || !!host._decorMove
|| !!host._decorDraft || !!host._dtDrag || !!host._bdDrag || !!host._opDrag
|| !!host._resize?.dragging;
}
public commit(): void {
commitHouseplanViewport(this.host);
resetHouseplanHover(this.host);
syncHouseplanHover(this.host);
}
public dispose(): void {
disposeHouseplanViewport(this.host);
resetHouseplanHover(this.host);
}
}