snapshot of https://github.com/excalidraw/excalidraw.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Tests / test (push) Failing after 15s
Some checks failed
Tests / test (push) Failing after 15s
This commit is contained in:
91
packages/excalidraw/components/UnlockPopup.tsx
Normal file
91
packages/excalidraw/components/UnlockPopup.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
getCommonBounds,
|
||||
getElementsInGroup,
|
||||
isNonDeletedElement,
|
||||
selectGroupsFromGivenElements,
|
||||
} from "@excalidraw/element";
|
||||
import { sceneCoordsToViewportCoords } from "@excalidraw/common";
|
||||
|
||||
import { flushSync } from "react-dom";
|
||||
|
||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||
|
||||
import { actionToggleElementLock } from "../actions";
|
||||
import { t } from "../i18n";
|
||||
|
||||
import "./UnlockPopup.scss";
|
||||
|
||||
import { LockedIconFilled } from "./icons";
|
||||
|
||||
import type App from "./App";
|
||||
|
||||
import type { AppState } from "../types";
|
||||
|
||||
const UnlockPopup = ({
|
||||
app,
|
||||
activeLockedId,
|
||||
}: {
|
||||
app: App;
|
||||
activeLockedId: NonNullable<AppState["activeLockedId"]>;
|
||||
}) => {
|
||||
const candidateElement = app.scene.getElement(activeLockedId);
|
||||
// SAFETY: This should never happen, but log it just in case
|
||||
if (candidateElement && !isNonDeletedElement(candidateElement)) {
|
||||
console.error(
|
||||
"[NONDELETED][INVARIANT] UnlockPopup: activeLockedId points to a deleted element",
|
||||
);
|
||||
}
|
||||
const element: NonDeletedExcalidrawElement | null =
|
||||
candidateElement && isNonDeletedElement(candidateElement)
|
||||
? candidateElement
|
||||
: null;
|
||||
|
||||
const elements = element
|
||||
? [element]
|
||||
: getElementsInGroup<NonDeletedExcalidrawElement>(
|
||||
app.scene.getNonDeletedElementsMap(),
|
||||
activeLockedId,
|
||||
);
|
||||
|
||||
if (elements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [x, y] = getCommonBounds(elements);
|
||||
const { x: viewX, y: viewY } = sceneCoordsToViewportCoords(
|
||||
{ sceneX: x, sceneY: y },
|
||||
app.state,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="UnlockPopup"
|
||||
style={{
|
||||
bottom: `${app.state.height + 12 - viewY + app.state.offsetTop}px`,
|
||||
left: `${viewX - app.state.offsetLeft}px`,
|
||||
}}
|
||||
onClick={() => {
|
||||
flushSync(() => {
|
||||
const groupIds = selectGroupsFromGivenElements(elements, app.state);
|
||||
app.setState({
|
||||
selectedElementIds: elements.reduce(
|
||||
(acc, element) => ({
|
||||
...acc,
|
||||
[element.id]: true,
|
||||
}),
|
||||
{},
|
||||
),
|
||||
selectedGroupIds: groupIds,
|
||||
activeLockedId: null,
|
||||
});
|
||||
});
|
||||
app.actionManager.executeAction(actionToggleElementLock);
|
||||
}}
|
||||
title={t("labels.elementLock.unlock")}
|
||||
>
|
||||
{LockedIconFilled}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UnlockPopup;
|
||||
Reference in New Issue
Block a user