Action duplication binding fix 1st iter

This commit is contained in:
Mark Tolmacs 2025-03-11 11:20:12 +01:00
parent 99d8bff175
commit 9cc4ea6ba6
2 changed files with 107 additions and 8 deletions

View file

@ -2,7 +2,6 @@ import { ToolButton } from "../components/ToolButton";
import { DuplicateIcon } from "../components/icons";
import { DEFAULT_GRID_SIZE } from "../constants";
import { duplicateElement, getNonDeletedElements } from "../element";
import { fixBindingsAfterDuplication } from "../element/binding";
import {
bindTextToShapeAfterDuplication,
getBoundTextElement,
@ -10,6 +9,8 @@ import {
} from "../element/textElement";
import {
hasBoundTextElement,
isArrowElement,
isBindableElement,
isBoundToContainer,
isFrameLikeElement,
} from "../element/typeChecks";
@ -40,11 +41,18 @@ import {
invariant,
} from "../utils";
import { type ElementUpdate, mutateElement } from "../element/mutateElement";
import { register } from "./register";
import type { ActionResult } from "./types";
import type { ExcalidrawElement } from "../element/types";
import type {
BoundElement,
ExcalidrawArrowElement,
ExcalidrawElement,
} from "../element/types";
import type { AppState } from "../types";
import type { Mutable } from "../utility-types";
export const actionDuplicateSelection = register({
name: "duplicateSelection",
@ -325,11 +333,103 @@ const duplicateElements = (
oldElements,
oldIdToDuplicatedId,
);
fixBindingsAfterDuplication(
elementsWithClones,
oldElements,
oldIdToDuplicatedId,
);
// fixBindingsAfterDuplication(
// elementsWithClones,
// oldElements,
// oldIdToDuplicatedId,
// );
newElements
.map((element) => {
oldElements.includes(element) && console.error("oldElements", element);
if (isArrowElement(element)) {
const updates: Mutable<ElementUpdate<ExcalidrawArrowElement>> = {};
if (element.startBinding) {
const startCloneElementId = oldIdToDuplicatedId.get(
element.startBinding.elementId,
);
if (startCloneElementId) {
// The connected element was duplicated, so we need to update the binding
updates.startBinding = {
...element.startBinding,
elementId: startCloneElementId,
};
} else {
// The connected element was not duplicated, so we need to remove the binding
updates.startBinding = null;
}
}
if (element.endBinding) {
const endCloneElementId = oldIdToDuplicatedId.get(
element.endBinding.elementId,
);
if (endCloneElementId) {
// The connected element was duplicated, so we need to update the binding
updates.endBinding = {
...element.endBinding,
elementId: endCloneElementId,
};
} else {
// The connected element was not duplicated, so we need to remove the binding
updates.endBinding = null;
}
}
if (Object.keys(updates).length > 0) {
// Only update the element if there are updates to apply
return {
element,
updates,
};
}
} else if (isBindableElement(element)) {
if (element.boundElements?.length) {
const clonedBoundElements = element.boundElements
?.map((definition) => {
const clonedBoundElementId = oldIdToDuplicatedId.get(
definition.id,
);
if (clonedBoundElementId) {
// The connected element was duplicated, so we need to update the binding
return {
...definition,
id: clonedBoundElementId,
};
}
// The connected element was not duplicated, so we need to remove the binding
return null;
})
.filter(
(definition): definition is BoundElement => definition !== null,
);
if (clonedBoundElements?.length) {
return {
element,
updates: {
boundElements: clonedBoundElements,
},
};
}
}
}
return null;
})
.forEach((change) => {
if (!change) {
return;
}
mutateElement(change.element, change.updates);
});
bindElementsToFramesAfterDuplication(
elementsWithClones,
oldElements,

View file

@ -658,7 +658,6 @@ export const duplicateElement = <TElement extends ExcalidrawElement>(
}
copy.id = regenerateId();
copy.boundElements = null;
copy.updated = getUpdatedTimestamp();
copy.seed = randomInteger();
copy.groupIds = getNewGroupIdsForDuplication(