mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(runtime): the editor keeps waking during a drag on a preview it did not build (#3850)
The manual-edit gesture watch tested mutation targets with `instanceof Element`. The composition body is adopted into the preview frame, so its nodes answer to another realm's Element and the check is false for every one of them: the watch never sees a gesture, and the paused transport it gates does not wake while the user drags. Routes the check through the runtime's structural predicate, which is what the preview-guard lint added alongside it now requires. Main is red on that lint for this line, so this also unbreaks it. Test adopts an element from a second realm and asserts the marker is seen and cleared; it fails with the identity check restored.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { JSDOM } from "jsdom";
|
||||
import { STUDIO_MANUAL_EDIT_GESTURE_ATTR } from "../editing/draftMarkers";
|
||||
import { createManualEditGestureWatch } from "./manualEditGestureWatch";
|
||||
|
||||
@@ -34,6 +35,28 @@ describe("manual-edit gesture watch", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("sees a gesture on an element adopted from another realm", async () => {
|
||||
// The composition body is built in the editor window and moved into the
|
||||
// preview document, so its nodes carry another realm's prototypes and
|
||||
// `target instanceof Element` answers false for every one of them. A
|
||||
// gesture on such an element must still be seen, or a parked transport
|
||||
// never wakes while the user drags.
|
||||
const foreign = new JSDOM("<!doctype html><html><body></body></html>");
|
||||
const el = foreign.window.document.createElement("div");
|
||||
document.body.appendChild(document.adoptNode(el as unknown as Node));
|
||||
const watch = createManualEditGestureWatch(document, () => {});
|
||||
try {
|
||||
expect(el instanceof Element).toBe(false);
|
||||
(el as unknown as Element).setAttribute(STUDIO_MANUAL_EDIT_GESTURE_ATTR, "token");
|
||||
expect(watch.isActive()).toBe(true);
|
||||
await flush();
|
||||
(el as unknown as Element).removeAttribute(STUDIO_MANUAL_EDIT_GESTURE_ATTR);
|
||||
expect(watch.isActive()).toBe(false);
|
||||
} finally {
|
||||
watch.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
it("stops reporting a gesture whose element was torn out mid-drag", async () => {
|
||||
document.body.innerHTML = `<div id="a"></div>`;
|
||||
const watch = createManualEditGestureWatch(document, () => {});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { STUDIO_MANUAL_EDIT_GESTURE_ATTR } from "../editing/draftMarkers";
|
||||
import { isElementNode } from "./domRealm";
|
||||
|
||||
export interface ManualEditGestureWatch {
|
||||
/** True while any element in the document carries the gesture marker. */
|
||||
@@ -53,7 +54,10 @@ export function createManualEditGestureWatch(
|
||||
const ingest = (records: MutationRecord[]): void => {
|
||||
for (const record of records) {
|
||||
const target = record.target;
|
||||
if (!(target instanceof Element)) continue;
|
||||
// Structural, not `instanceof`: the composition body is adopted into the
|
||||
// preview frame, so its nodes answer to another realm's Element and an
|
||||
// identity check silently skips every gesture. See domRealm.ts.
|
||||
if (!isElementNode(target)) continue;
|
||||
if (target.hasAttribute(STUDIO_MANUAL_EDIT_GESTURE_ATTR)) marked.add(target);
|
||||
else marked.delete(target);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user