This commit is contained in:
dwelle
2026-06-26 11:09:38 +02:00
parent 63fce9a40c
commit a2303cb121
2 changed files with 124 additions and 3 deletions
+4 -1
View File
@@ -1014,7 +1014,10 @@ const ExcalidrawWrapper = () => {
</OverwriteConfirmDialog.Action> </OverwriteConfirmDialog.Action>
)} )}
</OverwriteConfirmDialog> </OverwriteConfirmDialog>
<AppFooter onChange={() => excalidrawAPI?.refresh()} /> <AppFooter
excalidrawAPI={excalidrawAPI}
onChange={() => excalidrawAPI?.refresh()}
/>
{excalidrawAPI && <AIComponents excalidrawAPI={excalidrawAPI} />} {excalidrawAPI && <AIComponents excalidrawAPI={excalidrawAPI} />}
<TTDDialogTrigger /> <TTDDialogTrigger />
+120 -2
View File
@@ -1,13 +1,130 @@
import { Footer } from "@excalidraw/excalidraw/index"; 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 { isExcalidrawPlusSignedUser } from "../app_constants";
import { DebugFooter, isVisualDebuggerEnabled } from "./DebugCanvas"; import { DebugFooter, isVisualDebuggerEnabled } from "./DebugCanvas";
import { EncryptedIcon } from "./EncryptedIcon"; import { EncryptedIcon } from "./EncryptedIcon";
const ScrollConstraintsDebugFooter = ({
excalidrawAPI,
}: {
excalidrawAPI: ExcalidrawImperativeAPI | null;
}) => {
const [activeLock, setActiveLock] = useState<ScrollConstraints | null>(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<HTMLInputElement>) => {
const nextTolerance = Number(event.target.value) || 0;
setTolerance(nextTolerance);
if (activeLock) {
setLock({ ...activeLock, tolerance: nextTolerance });
}
},
[activeLock, setLock],
);
return (
<div
style={{
display: "flex",
gap: ".35rem",
alignItems: "center",
padding: "0 .35rem",
fontSize: 12,
}}
>
<button
className="ToolIcon_type_button"
type="button"
onClick={toggleScrollLock}
>
{activeLock ? "disable scroll lock" : "lock scroll"}
</button>
<label
style={{
display: "flex",
gap: ".25rem",
alignItems: "center",
}}
>
tolerance
<input
type="number"
min={0}
step={1}
value={tolerance}
onChange={updateTolerance}
style={{ width: 56 }}
/>
</label>
</div>
);
};
export const AppFooter = React.memo( export const AppFooter = React.memo(
({ onChange }: { onChange: () => void }) => { ({
excalidrawAPI,
onChange,
}: {
excalidrawAPI: ExcalidrawImperativeAPI | null;
onChange: () => void;
}) => {
return ( return (
<Footer> <Footer>
<div <div
@@ -17,6 +134,7 @@ export const AppFooter = React.memo(
alignItems: "center", alignItems: "center",
}} }}
> >
<ScrollConstraintsDebugFooter excalidrawAPI={excalidrawAPI} />
{isVisualDebuggerEnabled() && <DebugFooter onChange={onChange} />} {isVisualDebuggerEnabled() && <DebugFooter onChange={onChange} />}
{!isExcalidrawPlusSignedUser && <EncryptedIcon />} {!isExcalidrawPlusSignedUser && <EncryptedIcon />}
</div> </div>