diff --git a/excalidraw-app/App.tsx b/excalidraw-app/App.tsx index a87ce1ba27..e3d3ba18cd 100644 --- a/excalidraw-app/App.tsx +++ b/excalidraw-app/App.tsx @@ -1014,7 +1014,10 @@ const ExcalidrawWrapper = () => { )} - excalidrawAPI?.refresh()} /> + excalidrawAPI?.refresh()} + /> {excalidrawAPI && } diff --git a/excalidraw-app/components/AppFooter.tsx b/excalidraw-app/components/AppFooter.tsx index 5e2cb27cb3..bac6951feb 100644 --- a/excalidraw-app/components/AppFooter.tsx +++ b/excalidraw-app/components/AppFooter.tsx @@ -1,13 +1,130 @@ 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"; +const ScrollConstraintsDebugFooter = ({ + excalidrawAPI, +}: { + excalidrawAPI: ExcalidrawImperativeAPI | null; +}) => { + const [activeLock, setActiveLock] = useState(null); + const [tolerance, setTolerance] = useState(0); + + 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, + tolerance, + }); + }, [activeLock, excalidrawAPI, setLock, tolerance]); + + const updateTolerance = useCallback( + (event: React.ChangeEvent) => { + const nextTolerance = Number(event.target.value) || 0; + setTolerance(nextTolerance); + + if (activeLock) { + setLock({ ...activeLock, tolerance: nextTolerance }); + } + }, + [activeLock, setLock], + ); + + return ( +
+ + +
+ ); +}; + export const AppFooter = React.memo( - ({ onChange }: { onChange: () => void }) => { + ({ + excalidrawAPI, + onChange, + }: { + excalidrawAPI: ExcalidrawImperativeAPI | null; + onChange: () => void; + }) => { return (