From b9b0b4c0d483e022042b3dfd937e0adb3ebe1ed6 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:20:04 +0200 Subject: [PATCH] debug --- .../page-2026-06-26T08-26-20-195Z.yml | 124 +++++++++++++ .../page-2026-06-26T08-26-34-790Z.yml | 126 +++++++++++++ excalidraw-app/App.tsx | 5 +- excalidraw-app/components/AppFooter.tsx | 170 +++++++++++++++++- vercel.json | 1 - 5 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 .playwright-mcp/page-2026-06-26T08-26-20-195Z.yml create mode 100644 .playwright-mcp/page-2026-06-26T08-26-34-790Z.yml diff --git a/.playwright-mcp/page-2026-06-26T08-26-20-195Z.yml b/.playwright-mcp/page-2026-06-26T08-26-20-195Z.yml new file mode 100644 index 0000000000..ec48b57d08 --- /dev/null +++ b/.playwright-mcp/page-2026-06-26T08-26-20-195Z.yml @@ -0,0 +1,124 @@ +- generic [ref=e1]: + - banner: + - heading "Excalidraw" [level=1] [ref=e2] + - generic [active] [ref=e5]: + - generic: + - generic: + - generic: + - button [ref=e9] [cursor=pointer]: + - img [ref=e10] + - region "Shapes": + - generic [ref=e16]: + - generic: + - generic: + - text: To move canvas, hold + - generic: Scroll wheel + - text: or + - generic: Space + - text: while dragging, or use the hand tool + - heading "Shapes" [level=2] [ref=e17] + - generic [ref=e18]: + - generic "Keep selected tool active after drawing — Q" [ref=e19] [cursor=pointer]: + - checkbox "Keep selected tool active after drawing" + - img [ref=e21] + - generic "Hand (panning tool) — H or null" [ref=e29] [cursor=pointer]: + - radio "Hand (panning tool)" + - img [ref=e31] + - generic "Selection — V or 1" [ref=e38] [cursor=pointer]: + - radio "Selection" [checked] + - generic [ref=e39]: + - img [ref=e40] + - generic [ref=e45]: "1" + - generic "Rectangle — R or 2" [ref=e46] [cursor=pointer]: + - radio "Rectangle" + - generic [ref=e47]: + - img [ref=e48] + - generic [ref=e52]: "2" + - generic "Diamond — D or 3" [ref=e53] [cursor=pointer]: + - radio "Diamond" + - generic [ref=e54]: + - img [ref=e55] + - generic [ref=e59]: "3" + - generic "Ellipse — O or 4" [ref=e60] [cursor=pointer]: + - radio "Ellipse" + - generic [ref=e61]: + - img [ref=e62] + - generic [ref=e66]: "4" + - generic "Arrow — A or 5" [ref=e67] [cursor=pointer]: + - radio "Arrow" + - generic [ref=e68]: + - img [ref=e69] + - generic [ref=e74]: "5" + - generic "Line — L or 6" [ref=e75] [cursor=pointer]: + - radio "Line" + - generic [ref=e76]: + - img [ref=e77] + - generic [ref=e78]: "6" + - generic "Draw — P or 7" [ref=e79] [cursor=pointer]: + - radio "Draw" + - generic [ref=e80]: + - img [ref=e81] + - generic [ref=e85]: "7" + - generic "Text — T or 8" [ref=e86] [cursor=pointer]: + - radio "Text" + - generic [ref=e87]: + - img [ref=e88] + - generic [ref=e93]: "8" + - generic "Insert image — 9" [ref=e94] [cursor=pointer]: + - radio "Insert image" + - generic [ref=e95]: + - img [ref=e96] + - generic [ref=e101]: "9" + - generic "Eraser — E or 0" [ref=e102] [cursor=pointer]: + - radio "Eraser" + - generic [ref=e103]: + - img [ref=e104] + - generic [ref=e109]: "0" + - button "More tools" [ref=e112] [cursor=pointer]: + - img [ref=e113] + - generic: + - generic [ref=e119]: + - link "Excalidraw+" [ref=e120] [cursor=pointer]: + - /url: https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=app&utm_content=guestBanner#excalidraw-redirect + - button "Live collaboration..." [ref=e121] [cursor=pointer]: + - img [ref=e122] + - generic "Library" [ref=e124]: + - checkbox "Library" + - img [ref=e127] [cursor=pointer] + - contentinfo: + - region "Canvas actions" [ref=e132]: + - heading "Canvas actions" [level=2] [ref=e133] + - generic [ref=e135]: + - button "Zoom out" [ref=e136] [cursor=pointer]: + - img [ref=e138] + - button "Reset zoom" [ref=e140] [cursor=pointer]: 100% + - button "Zoom in" [ref=e141] [cursor=pointer]: + - img [ref=e143] + - generic [ref=e145]: + - button "Undo" [disabled] [ref=e148]: + - img [ref=e150] + - button "Redo" [disabled] [ref=e154]: + - img [ref=e156] + - generic [ref=e158]: + - generic [ref=e159]: + - button "lock scroll" [ref=e160] [cursor=pointer] + - generic [ref=e161]: + - text: overscroll + - spinbutton "overscroll" [ref=e162]: "0.2" + - generic [ref=e163]: + - text: zoom factor + - spinbutton "zoom factor" [ref=e164]: "0.2" + - generic [ref=e165]: + - checkbox "lock zoom" [ref=e166] + - text: lock zoom + - generic [ref=e167]: + - checkbox "animate" [ref=e168] + - text: animate + - link "Blog post on end-to-end encryption in Excalidraw" [ref=e169] [cursor=pointer]: + - /url: https://plus.excalidraw.com/blog/end-to-end-encryption + - img [ref=e171] + - button "Help" [ref=e174] [cursor=pointer]: + - img [ref=e175] + - generic: + - img + - generic [ref=e180]: Drawing canvas \ No newline at end of file diff --git a/.playwright-mcp/page-2026-06-26T08-26-34-790Z.yml b/.playwright-mcp/page-2026-06-26T08-26-34-790Z.yml new file mode 100644 index 0000000000..25f5a9d12f --- /dev/null +++ b/.playwright-mcp/page-2026-06-26T08-26-34-790Z.yml @@ -0,0 +1,126 @@ +- generic [ref=e1]: + - banner: + - heading "Excalidraw" [level=1] [ref=e2] + - generic [ref=e5]: + - generic: + - generic: + - generic: + - generic: + - img + - img + - generic: + - text: Your drawings are saved in your browser's storage. + - text: Browser storage can be cleared unexpectedly. + - text: Save your work to a file regularly to avoid losing it. + - generic: + - button "Open Ctrl+O" [ref=e181] [cursor=pointer]: + - img [ref=e183] + - generic [ref=e185]: Open + - generic [ref=e186]: Ctrl+O + - button "Help ?" [ref=e187] [cursor=pointer]: + - img [ref=e189] + - generic [ref=e194]: Help + - generic [ref=e195]: "?" + - button "Live collaboration..." [ref=e196] [cursor=pointer]: + - img [ref=e198] + - generic [ref=e205]: Live collaboration... + - link "Sign up" [ref=e206] [cursor=pointer]: + - /url: https://plus.excalidraw.com/plus?utm_source=excalidraw&utm_medium=app&utm_content=welcomeScreenGuest + - img [ref=e208] + - generic [ref=e214]: Sign up + - generic: + - generic: + - button [ref=e9] [cursor=pointer]: + - img [ref=e10] + - region "Shapes": + - generic [ref=e16]: + - generic: + - generic: + - text: To move canvas, hold + - generic: Scroll wheel + - text: or + - generic: Space + - text: while dragging, or use the hand tool + - heading "Shapes" [level=2] [ref=e17] + - generic [ref=e18]: + - generic "Keep selected tool active after drawing — Q" [ref=e19] [cursor=pointer]: + - checkbox "Keep selected tool active after drawing" + - img [ref=e21] + - generic "Hand (panning tool) — H or null" [ref=e29] [cursor=pointer]: + - radio "Hand (panning tool)" + - img [ref=e31] + - generic "Selection" [ref=e215] [cursor=pointer]: + - radio "Selection" [checked] + - img [ref=e217] + - generic "Rectangle — R or 2" [ref=e46] [cursor=pointer]: + - radio "Rectangle" + - img [ref=e48] + - generic "Diamond — D or 3" [ref=e53] [cursor=pointer]: + - radio "Diamond" + - img [ref=e55] + - generic "Ellipse — O or 4" [ref=e60] [cursor=pointer]: + - radio "Ellipse" + - img [ref=e62] + - generic "Arrow — A or 5" [ref=e67] [cursor=pointer]: + - radio "Arrow" + - img [ref=e69] + - generic "Line — L or 6" [ref=e75] [cursor=pointer]: + - radio "Line" + - img [ref=e77] + - generic "Draw — P or 7" [ref=e79] [cursor=pointer]: + - radio "Draw" + - img [ref=e81] + - generic "Text — T or 8" [ref=e86] [cursor=pointer]: + - radio "Text" + - img [ref=e88] + - generic "Insert image — 9" [ref=e94] [cursor=pointer]: + - radio "Insert image" + - img [ref=e96] + - generic "Eraser — E or 0" [ref=e102] [cursor=pointer]: + - radio "Eraser" + - img [ref=e104] + - button "More tools" [ref=e112] [cursor=pointer]: + - img [ref=e113] + - generic: + - button "Live collaboration..." [ref=e121] [cursor=pointer]: + - img [ref=e122] + - generic "Library" [ref=e124]: + - checkbox "Library" + - img [ref=e127] [cursor=pointer] + - contentinfo: + - region "Canvas actions" [ref=e132]: + - heading "Canvas actions" [level=2] [ref=e133] + - generic [ref=e135]: + - button "Zoom out" [ref=e136] [cursor=pointer]: + - img [ref=e138] + - button "Reset zoom" [disabled] [ref=e140]: 100% + - button "Zoom in" [ref=e141] [cursor=pointer]: + - img [ref=e143] + - generic [ref=e145]: + - button "Undo" [disabled] [ref=e148]: + - img [ref=e150] + - button "Redo" [disabled] [ref=e154]: + - img [ref=e156] + - generic [ref=e158]: + - generic [ref=e159]: + - button "disable scroll lock" [active] [ref=e222] [cursor=pointer] + - generic [ref=e161]: + - text: overscroll + - spinbutton "overscroll" [ref=e162]: "0.2" + - generic [ref=e163]: + - text: zoom factor + - spinbutton "zoom factor" [ref=e164]: "0.2" + - generic [ref=e165]: + - checkbox "lock zoom" [ref=e166] + - text: lock zoom + - generic [ref=e167]: + - checkbox "animate" [ref=e168] + - text: animate + - link "Blog post on end-to-end encryption in Excalidraw" [ref=e169] [cursor=pointer]: + - /url: https://plus.excalidraw.com/blog/end-to-end-encryption + - img [ref=e171] + - button "Help" [ref=e174] [cursor=pointer]: + - img [ref=e175] + - generic: + - img + - generic [ref=e180]: Drawing canvas \ No newline at end of file diff --git a/excalidraw-app/App.tsx b/excalidraw-app/App.tsx index 011379a4c1..e532c9492e 100644 --- a/excalidraw-app/App.tsx +++ b/excalidraw-app/App.tsx @@ -1015,7 +1015,10 @@ const ExcalidrawWrapper = () => { )} - excalidrawAPI?.refresh()} /> + excalidrawAPI?.refresh()} + /> {excalidrawAPI && } diff --git a/excalidraw-app/components/AppFooter.tsx b/excalidraw-app/components/AppFooter.tsx index 5e2cb27cb3..a67f316401 100644 --- a/excalidraw-app/components/AppFooter.tsx +++ b/excalidraw-app/components/AppFooter.tsx @@ -1,13 +1,178 @@ import { Footer } from "@excalidraw/excalidraw/index"; -import React from "react"; +import { + getCommonBounds, + getSelectedElements, + getVisibleSceneBounds, +} from "@excalidraw/element"; +import React, { useCallback, useState } from "react"; + +import type { + ExcalidrawImperativeAPI, + ScrollConstraints, +} from "@excalidraw/excalidraw/types"; import { isExcalidrawPlusSignedUser } from "../app_constants"; import { DebugFooter, isVisualDebuggerEnabled } from "./DebugCanvas"; import { EncryptedIcon } from "./EncryptedIcon"; +type ScrollConstraintOptions = Pick< + ScrollConstraints, + "lockZoom" | "overscrollAllowance" | "viewportZoomFactor" +>; + +const ScrollConstraintsDebugFooter = ({ + excalidrawAPI, +}: { + excalidrawAPI: ExcalidrawImperativeAPI | null; +}) => { + const [activeLock, setActiveLock] = useState(null); + const [options, setOptions] = useState({ + lockZoom: false, + overscrollAllowance: 0.2, + viewportZoomFactor: 0.2, + }); + + const setLock = useCallback( + (nextLock: ScrollConstraints) => { + excalidrawAPI?.setScrollConstraints(nextLock); + setActiveLock(nextLock); + }, + [excalidrawAPI], + ); + + const toggleScrollLock = useCallback(() => { + if (!excalidrawAPI) { + return; + } + + if (activeLock) { + excalidrawAPI.setScrollConstraints(null); + setActiveLock(null); + return; + } + + const selectedElements = getSelectedElements( + excalidrawAPI.getSceneElements(), + excalidrawAPI.getAppState(), + { + includeBoundTextElement: true, + includeElementsInFrames: true, + }, + ); + const [x1, y1, x2, y2] = selectedElements.length + ? getCommonBounds( + selectedElements, + excalidrawAPI.getSceneElementsMapIncludingDeleted(), + ) + : getVisibleSceneBounds(excalidrawAPI.getAppState()); + + setLock({ + x: x1, + y: y1, + width: x2 - x1, + height: y2 - y1, + ...options, + }); + }, [activeLock, excalidrawAPI, options, setLock]); + + const updateOptions = useCallback( + (nextOptions: ScrollConstraintOptions) => { + setOptions(nextOptions); + + if (activeLock) { + setLock({ ...activeLock, ...nextOptions }); + } + }, + [activeLock, setLock], + ); + + const updateNumberOption = useCallback( + (option: "overscrollAllowance" | "viewportZoomFactor", value: string) => { + updateOptions({ + ...options, + [option]: value === "" ? undefined : Number(value), + }); + }, + [options, updateOptions], + ); + + const updateBooleanOption = useCallback( + (option: "lockZoom", value: boolean) => { + updateOptions({ + ...options, + [option]: value, + }); + }, + [options, updateOptions], + ); + + return ( +
+ + + + +
+ ); +}; + export const AppFooter = React.memo( - ({ onChange }: { onChange: () => void }) => { + ({ + excalidrawAPI, + onChange, + }: { + excalidrawAPI: ExcalidrawImperativeAPI | null; + onChange: () => void; + }) => { return (