From 88dc25865b64e70d4afbf58bc9b707551a28d0f2 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:21:56 +0200 Subject: [PATCH] wip2 --- packages/excalidraw/components/App.tsx | 4 + packages/excalidraw/tests/embeddable.test.tsx | 138 +++++++++++++++++- 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 56dbff5a3a..18dc06eb0c 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -5746,6 +5746,10 @@ class App extends React.Component { selectedElementIds: makeNextSelectedElementIds({}, this.state), activeEmbeddable: null, }); + } else if (this.state.activeEmbeddable) { + this.setState({ + activeEmbeddable: null, + }); } gesture.initialScale = this.state.zoom.value; }); diff --git a/packages/excalidraw/tests/embeddable.test.tsx b/packages/excalidraw/tests/embeddable.test.tsx index cf4e075119..eca89193dc 100644 --- a/packages/excalidraw/tests/embeddable.test.tsx +++ b/packages/excalidraw/tests/embeddable.test.tsx @@ -1,7 +1,7 @@ import { Excalidraw } from "../index"; import { Pointer } from "./helpers/ui"; -import { act, fireEvent, render, waitFor } from "./test-utils"; +import { act, fireEvent, GlobalTestState, render, waitFor } from "./test-utils"; import type { ExcalidrawProps } from "../types"; @@ -68,6 +68,61 @@ describe("embeddable interactions", () => { }; }; + const renderYouTubeEmbeddable = async ( + excalidrawProps: Partial = {}, + ) => { + const renderResult = await render(); + let embeddable!: NonNullable< + ReturnType + >; + + act(() => { + const insertedEmbeddable = h.app.insertEmbeddableElement({ + sceneX: 40, + sceneY: 40, + link: "https://www.youtube.com/watch?v=gkGMXY0wekg", + }); + + if (!insertedEmbeddable) { + throw new Error("YouTube embeddable not inserted"); + } + + embeddable = insertedEmbeddable; + }); + + ( + h.app as unknown as { + embedsValidationStatus: Map; + } + ).embedsValidationStatus.set(embeddable.id, true); + + act(() => { + h.setState({ width: 1000, height: 1000 }); + h.app.scene.triggerUpdate(); + }); + + await waitFor(() => { + expect( + renderResult.container.querySelector("iframe.excalidraw__embeddable"), + ).not.toBeNull(); + }); + + return { + ...renderResult, + embeddable, + }; + }; + + const setActiveEmbeddable = ( + embeddable: NonNullable>, + ) => { + act(() => { + h.setState({ + activeEmbeddable: { element: embeddable, state: "active" }, + }); + }); + }; + it("lets the initial Google Drive video click land in the iframe center", async () => { const { container, embeddable, getIframe, src } = await renderGoogleDriveEmbeddable(); @@ -176,4 +231,85 @@ describe("embeddable interactions", () => { expect(h.state.zoom.value).toBeGreaterThan(prevZoom); }); }); + + it("deactivates a non-Drive interactive embeddable on Ctrl/Cmd keydown", async () => { + const { container, embeddable } = await renderYouTubeEmbeddable({ + handleKeyboardGlobally: true, + }); + + setActiveEmbeddable(embeddable); + + await waitFor(() => { + expect( + container.querySelector( + ".excalidraw__embeddable-container__inner", + )?.style.pointerEvents, + ).toBe("all"); + expect( + container.querySelectorAll(".excalidraw__embeddable-canvas-guard"), + ).toHaveLength(0); + }); + + fireEvent.keyDown(document, { + key: "Control", + ctrlKey: true, + }); + + await waitFor(() => { + expect(h.state.activeEmbeddable).toBeNull(); + expect( + container.querySelector( + ".excalidraw__embeddable-container__inner", + )?.style.pointerEvents, + ).toBe("none"); + }); + }); + + it("deactivates a non-Drive interactive embeddable on parent-observed pinch", async () => { + const { embeddable } = await renderYouTubeEmbeddable(); + + setActiveEmbeddable(embeddable); + + fireEvent.pointerDown(GlobalTestState.interactiveCanvas, { + clientX: embeddable.x + 10, + clientY: embeddable.y + 10, + pointerId: 1, + pointerType: "touch", + }); + fireEvent.pointerDown(GlobalTestState.interactiveCanvas, { + clientX: embeddable.x + 30, + clientY: embeddable.y + 30, + pointerId: 2, + pointerType: "touch", + }); + + await waitFor(() => { + expect(h.state.activeEmbeddable).toBeNull(); + }); + + fireEvent.pointerUp(GlobalTestState.interactiveCanvas, { + pointerId: 1, + pointerType: "touch", + }); + fireEvent.pointerUp(GlobalTestState.interactiveCanvas, { + pointerId: 2, + pointerType: "touch", + }); + }); + + it("deactivates a non-Drive interactive embeddable on Safari gesturestart", async () => { + const { embeddable } = await renderYouTubeEmbeddable(); + + setActiveEmbeddable(embeddable); + + act(() => { + document.dispatchEvent( + new Event("gesturestart", { bubbles: true, cancelable: true }), + ); + }); + + await waitFor(() => { + expect(h.state.activeEmbeddable).toBeNull(); + }); + }); });