Fix single selected arrow highlight after delete, undo, redo

This commit is contained in:
Mark Tolmacs 2025-03-15 11:33:45 +01:00
parent 4619e88b98
commit 689179f428
2 changed files with 56 additions and 18 deletions

View file

@ -96,6 +96,7 @@ export const actionDuplicateSelection = register({
elements: nextElements,
appState: {
...appState,
...updateLinearElementEditors(nextElements),
...selectGroupsForSelectedElements(
{
editingGroupId: appState.editingGroupId,
@ -131,3 +132,24 @@ export const actionDuplicateSelection = register({
/>
),
});
const updateLinearElementEditors = (clonedElements: ExcalidrawElement[]) => {
const linears = clonedElements.filter(isLinearElement);
if (linears.length === 1) {
const linear = linears[0];
const boundElements = linear.boundElements?.map((def) => def.id) ?? [];
const onlySingleLinearSelected = clonedElements.every(
(el) => el.id === linear.id || boundElements.includes(el.id),
);
if (onlySingleLinearSelected) {
return {
selectedLinearElement: new LinearElementEditor(linear),
};
}
}
return {
selectedLinearElement: null,
};
};

View file

@ -51,7 +51,13 @@ import {
} from "../scene/scrollbars";
import { getCornerRadius } from "../shapes";
import { type InteractiveCanvasAppState } from "../types";
import { arrayToMap, invariant, throttleRAF } from "../utils";
import {
arrayToMap,
invariant,
isDevEnv,
isTestEnv,
throttleRAF,
} from "../utils";
import {
bootstrapCanvas,
@ -886,23 +892,33 @@ const _renderInteractiveScene = ({
);
}
if (
isElbowArrow(selectedElements[0]) &&
appState.selectedLinearElement &&
appState.selectedLinearElement.segmentMidPointHoveredCoords
) {
renderElbowArrowMidPointHighlight(context, appState);
} else if (
appState.selectedLinearElement &&
appState.selectedLinearElement.hoverPointIndex >= 0 &&
!(
isElbowArrow(selectedElements[0]) &&
appState.selectedLinearElement.hoverPointIndex > 0 &&
appState.selectedLinearElement.hoverPointIndex <
selectedElements[0].points.length - 1
)
) {
renderLinearElementPointHighlight(context, appState, elementsMap);
// Arrows have a different highlight behavior when
// they are the only selected element
if (appState.selectedLinearElement) {
if (isTestEnv() || isDevEnv()) {
invariant(
selectedElements.length <= 1,
`There is an active selectedLinearElement on app state but the selectedElements length is ${selectedElements?.length} not 1`,
);
}
const editor = appState.selectedLinearElement;
const firstSelectedLinear = selectedElements.find(
(el) => el.id === editor.elementId, // Don't forget bound text elements!
);
if (isElbowArrow(firstSelectedLinear)) {
if (editor.segmentMidPointHoveredCoords) {
renderElbowArrowMidPointHighlight(context, appState);
} else if (
editor.hoverPointIndex !== 0 &&
editor.hoverPointIndex !== firstSelectedLinear.points.length - 1
) {
renderLinearElementPointHighlight(context, appState, elementsMap);
}
} else if (editor.hoverPointIndex >= 0) {
renderLinearElementPointHighlight(context, appState, elementsMap);
}
}
// Paint selected elements