limit which linear elements can be switched

This commit is contained in:
Ryan Di 2025-04-16 18:04:16 +10:00
parent beb0bd1528
commit 8e9e0e2709
2 changed files with 48 additions and 14 deletions

View file

@ -379,8 +379,29 @@ export const getSwitchableTypeFromElements = (
} }
if (onlyLinear) { if (onlyLinear) {
// check at least some linear element is switchable
// for a linear to be swtichable:
// - no labels
// - not bound to anything
let linear = true;
for (const element of elements) {
if (
isArrowElement(element) &&
(element.startBinding !== null || element.endBinding !== null)
) {
linear = false;
} else if (element.boundElements && element.boundElements.length > 0) {
linear = false;
} else {
linear = true;
break;
}
}
return { return {
linear: true, linear,
generic: false, generic: false,
}; };
} }

View file

@ -6,6 +6,7 @@ import { pointFrom, pointRotateRads } from "@excalidraw/math";
import { import {
getSwitchableTypeFromElements, getSwitchableTypeFromElements,
isArrowElement,
isUsingAdaptiveRadius, isUsingAdaptiveRadius,
} from "@excalidraw/element/typeChecks"; } from "@excalidraw/element/typeChecks";
import { import {
@ -223,13 +224,14 @@ const Panel = ({
const { generic, linear } = getSwitchableTypeFromElements(elements); const { generic, linear } = getSwitchableTypeFromElements(elements);
const genericElements = generic ? getGenericSwitchableElements(elements) : []; const genericElements = generic ? getGenericSwitchableElements(elements) : [];
const linearElements = linear ? getLinearSwitchableElements(elements) : [];
const sameType = generic const sameType = generic
? genericElements.every( ? genericElements.every(
(element) => element.type === genericElements[0].type, (element) => element.type === genericElements[0].type,
) )
: linear : linear
? elements.every((element) => element.type === elements[0].type) ? linearElements.every((element) => element.type === linearElements[0].type)
: false; : false;
if (elements.length === 1) { if (elements.length === 1) {
@ -289,7 +291,7 @@ const Panel = ({
const isSelected = const isSelected =
sameType && sameType &&
((generic && genericElements[0].type === type) || ((generic && genericElements[0].type === type) ||
(linear && elements[0].type === type)); (linear && linearElements[0].type === type));
return ( return (
<ToolButton <ToolButton
@ -303,11 +305,6 @@ const Panel = ({
keyBindingLabel={""} keyBindingLabel={""}
aria-label={type} aria-label={type}
data-testid={`toolbar-${type}`} data-testid={`toolbar-${type}`}
onPointerDown={({ pointerType }) => {
if (!app.state.penDetected && pointerType === "pen") {
app.togglePenMode(true);
}
}}
onChange={() => { onChange={() => {
if (app.state.activeTool.type !== type) { if (app.state.activeTool.type !== type) {
trackEvent("shape-switch", type, "ui"); trackEvent("shape-switch", type, "ui");
@ -487,11 +484,16 @@ export const switchShapes = (
} }
if (linear) { if (linear) {
const sameType = selectedElements.every( const selectedLinearSwitchableElements =
(element) => element.type === selectedElements[0].type, getLinearSwitchableElements(selectedElements);
const sameType = selectedLinearSwitchableElements.every(
(element) => element.type === selectedLinearSwitchableElements[0].type,
); );
const index = sameType const index = sameType
? LINEAR_SWITCHABLE_SHAPES.indexOf(selectedElements[0].type) ? LINEAR_SWITCHABLE_SHAPES.indexOf(
selectedLinearSwitchableElements[0].type,
)
: -1; : -1;
nextType = nextType =
nextType ?? nextType ??
@ -500,7 +502,7 @@ export const switchShapes = (
LINEAR_SWITCHABLE_SHAPES.length LINEAR_SWITCHABLE_SHAPES.length
] as LinearSwitchableToolType); ] as LinearSwitchableToolType);
selectedElements.forEach((element) => { selectedLinearSwitchableElements.forEach((element) => {
ShapeCache.delete(element); ShapeCache.delete(element);
mutateElement( mutateElement(
@ -513,12 +515,12 @@ export const switchShapes = (
false, false,
); );
}); });
const firstElement = selectedElements[0]; const firstElement = selectedLinearSwitchableElements[0];
app.setState((prevState) => ({ app.setState((prevState) => ({
selectedElementIds, selectedElementIds,
selectedLinearElement: selectedLinearElement:
selectedElements.length === 1 selectedLinearSwitchableElements.length === 1
? new LinearElementEditor(firstElement as ExcalidrawLinearElement) ? new LinearElementEditor(firstElement as ExcalidrawLinearElement)
: null, : null,
activeTool: updateActiveTool(prevState, { activeTool: updateActiveTool(prevState, {
@ -535,4 +537,15 @@ const getGenericSwitchableElements = (elements: ExcalidrawElement[]) =>
GENERIC_SWITCHABLE_SHAPES.includes(element.type), GENERIC_SWITCHABLE_SHAPES.includes(element.type),
); );
const getLinearSwitchableElements = (elements: ExcalidrawElement[]) =>
elements.filter(
(element) =>
LINEAR_SWITCHABLE_SHAPES.includes(element.type) &&
!(
isArrowElement(element) &&
(element.startBinding !== null || element.endBinding !== null)
) &&
(!element.boundElements || element.boundElements.length === 0),
);
export default ShapeSwitch; export default ShapeSwitch;