First iter

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs 2025-04-29 18:15:14 +02:00
parent 195a743874
commit 14bd9d3829
No known key found for this signature in database
2 changed files with 53 additions and 46 deletions

View file

@ -16,6 +16,12 @@ import { isPathALoop } from "@excalidraw/element/shapes";
import { isInvisiblySmallElement } from "@excalidraw/element/sizeHelpers"; import { isInvisiblySmallElement } from "@excalidraw/element/sizeHelpers";
import type {
ExcalidrawElement,
ExcalidrawLinearElement,
NonDeleted,
} from "@excalidraw/element/types";
import { t } from "../i18n"; import { t } from "../i18n";
import { resetCursor } from "../cursor"; import { resetCursor } from "../cursor";
import { done } from "../components/icons"; import { done } from "../components/icons";
@ -82,48 +88,55 @@ export const actionFinalize = register({
focusContainer(); focusContainer();
} }
const multiPointElement = appState.multiElement let element: NonDeleted<ExcalidrawElement> | null = null;
? appState.multiElement if (appState.multiElement) {
: appState.newElement?.type === "freedraw" element = appState.multiElement;
? appState.newElement } else if (
: null; appState.newElement?.type === "freedraw" ||
isBindingElement(appState.newElement)
) {
element = appState.newElement;
} else if (Object.keys(appState.selectedElementIds).length === 1) {
const candidate = elementsMap.get(
Object.keys(appState.selectedElementIds)[0],
) as NonDeleted<ExcalidrawLinearElement> | undefined;
if (candidate) {
element = candidate;
}
}
if (multiPointElement) { if (element) {
// pen and mouse have hover // pen and mouse have hover
if ( if (
multiPointElement.type !== "freedraw" && appState.multiElement &&
element.type !== "freedraw" &&
appState.lastPointerDownWith !== "touch" appState.lastPointerDownWith !== "touch"
) { ) {
const { points, lastCommittedPoint } = multiPointElement; const { points, lastCommittedPoint } = element;
if ( if (
!lastCommittedPoint || !lastCommittedPoint ||
points[points.length - 1] !== lastCommittedPoint points[points.length - 1] !== lastCommittedPoint
) { ) {
scene.mutateElement(multiPointElement, { scene.mutateElement(element, {
points: multiPointElement.points.slice(0, -1), points: element.points.slice(0, -1),
}); });
} }
} }
if (isInvisiblySmallElement(multiPointElement)) { if (isInvisiblySmallElement(element)) {
// TODO: #7348 in theory this gets recorded by the store, so the invisible elements could be restored by the undo/redo, which might be not what we would want // TODO: #7348 in theory this gets recorded by the store, so the invisible elements could be restored by the undo/redo, which might be not what we would want
newElements = newElements.filter( newElements = newElements.filter((el) => el.id !== element.id);
(el) => el.id !== multiPointElement.id,
);
} }
// If the multi point line closes the loop, // If the multi point line closes the loop,
// set the last point to first point. // set the last point to first point.
// This ensures that loop remains closed at different scales. // This ensures that loop remains closed at different scales.
const isLoop = isPathALoop(multiPointElement.points, appState.zoom.value); const isLoop = isPathALoop(element.points, appState.zoom.value);
if ( if (element.type === "line" || element.type === "freedraw") {
multiPointElement.type === "line" ||
multiPointElement.type === "freedraw"
) {
if (isLoop) { if (isLoop) {
const linePoints = multiPointElement.points; const linePoints = element.points;
const firstPoint = linePoints[0]; const firstPoint = linePoints[0];
scene.mutateElement(multiPointElement, { scene.mutateElement(element, {
points: linePoints.map((p, index) => points: linePoints.map((p, index) =>
index === linePoints.length - 1 index === linePoints.length - 1
? pointFrom(firstPoint[0], firstPoint[1]) ? pointFrom(firstPoint[0], firstPoint[1])
@ -134,23 +147,24 @@ export const actionFinalize = register({
} }
if ( if (
isBindingElement(multiPointElement) && isBindingElement(element) &&
!isLoop && !isLoop &&
multiPointElement.points.length > 1 element.points.length > 1 &&
!appState.selectedElementIds[element.id]
) { ) {
const [x, y] = LinearElementEditor.getPointAtIndexGlobalCoordinates( const [x, y] = LinearElementEditor.getPointAtIndexGlobalCoordinates(
multiPointElement, element,
-1, -1,
arrayToMap(elements), arrayToMap(elements),
); );
maybeBindLinearElement(multiPointElement, appState, { x, y }, scene); maybeBindLinearElement(element, appState, { x, y }, scene);
} }
} }
if ( if (
(!appState.activeTool.locked && (!appState.activeTool.locked &&
appState.activeTool.type !== "freedraw") || appState.activeTool.type !== "freedraw") ||
!multiPointElement !element
) { ) {
resetCursor(interactiveCanvas); resetCursor(interactiveCanvas);
} }
@ -177,7 +191,7 @@ export const actionFinalize = register({
activeTool: activeTool:
(appState.activeTool.locked || (appState.activeTool.locked ||
appState.activeTool.type === "freedraw") && appState.activeTool.type === "freedraw") &&
multiPointElement element
? appState.activeTool ? appState.activeTool
: activeTool, : activeTool,
activeEmbeddable: null, activeEmbeddable: null,
@ -188,21 +202,18 @@ export const actionFinalize = register({
startBoundElement: null, startBoundElement: null,
suggestedBindings: [], suggestedBindings: [],
selectedElementIds: selectedElementIds:
multiPointElement && element &&
!appState.activeTool.locked && !appState.activeTool.locked &&
appState.activeTool.type !== "freedraw" appState.activeTool.type !== "freedraw"
? { ? {
...appState.selectedElementIds, ...appState.selectedElementIds,
[multiPointElement.id]: true, [element.id]: true,
} }
: appState.selectedElementIds, : appState.selectedElementIds,
// To select the linear element when user has finished mutipoint editing // To select the linear element when user has finished mutipoint editing
selectedLinearElement: selectedLinearElement:
multiPointElement && isLinearElement(multiPointElement) element && isLinearElement(element)
? new LinearElementEditor( ? new LinearElementEditor(element, arrayToMap(newElements))
multiPointElement,
arrayToMap(newElements),
)
: appState.selectedLinearElement, : appState.selectedLinearElement,
pendingImageElementId: null, pendingImageElementId: null,
}, },

View file

@ -9022,12 +9022,13 @@ class App extends React.Component<AppProps, AppState> {
linearElementEditor; linearElementEditor;
const element = this.scene.getElement(linearElementEditor.elementId); const element = this.scene.getElement(linearElementEditor.elementId);
if (isBindingElement(element)) { if (isBindingElement(element)) {
bindOrUnbindLinearElement( this.actionManager.executeAction(actionFinalize);
element, // bindOrUnbindLinearElement(
startBindingElement, // element,
endBindingElement, // startBindingElement,
this.scene, // endBindingElement,
); // this.scene,
// );
} }
if (linearElementEditor !== this.state.selectedLinearElement) { if (linearElementEditor !== this.state.selectedLinearElement) {
@ -9162,12 +9163,7 @@ class App extends React.Component<AppProps, AppState> {
isBindingEnabled(this.state) && isBindingEnabled(this.state) &&
isBindingElement(newElement, false) isBindingElement(newElement, false)
) { ) {
maybeBindLinearElement( this.actionManager.executeAction(actionFinalize);
newElement,
this.state,
pointerCoords,
this.scene,
);
} }
this.setState({ suggestedBindings: [], startBoundElement: null }); this.setState({ suggestedBindings: [], startBoundElement: null });
if (!activeTool.locked) { if (!activeTool.locked) {