mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
simpler types, tidy up code
This commit is contained in:
parent
d890ed090c
commit
721f5ec0f4
4 changed files with 57 additions and 98 deletions
|
@ -419,3 +419,4 @@ export type ConvertibleLinearTypes =
|
||||||
| "sharpArrow"
|
| "sharpArrow"
|
||||||
| "curvedArrow"
|
| "curvedArrow"
|
||||||
| "elbowArrow";
|
| "elbowArrow";
|
||||||
|
export type ConvertibleTypes = ConvertibleGenericTypes | ConvertibleLinearTypes;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getSwitchableTypeFromElements,
|
getSwitchCategoryFromElements,
|
||||||
shapeSwitchAtom,
|
shapeSwitchAtom,
|
||||||
} from "../components/ShapeSwitch";
|
} from "../components/ShapeSwitch";
|
||||||
import { editorJotaiStore } from "../editor-jotai";
|
import { editorJotaiStore } from "../editor-jotai";
|
||||||
|
@ -31,11 +31,6 @@ export const actionToggleShapeSwitch = register({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
checked: (appState) => appState.gridModeEnabled,
|
checked: (appState) => appState.gridModeEnabled,
|
||||||
predicate: (elements, appState, props) => {
|
predicate: (elements, appState, props) =>
|
||||||
const { generic, linear } = getSwitchableTypeFromElements(
|
getSwitchCategoryFromElements(elements as ExcalidrawElement[]) !== null,
|
||||||
elements as ExcalidrawElement[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return generic || linear;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -468,7 +468,7 @@ import { LassoTrail } from "../lasso";
|
||||||
import { EraserTrail } from "../eraser";
|
import { EraserTrail } from "../eraser";
|
||||||
|
|
||||||
import ShapeSwitch, {
|
import ShapeSwitch, {
|
||||||
getSwitchableTypeFromElements,
|
getSwitchCategoryFromElements,
|
||||||
SHAPE_SWITCH_PANEL_CLASSNAME,
|
SHAPE_SWITCH_PANEL_CLASSNAME,
|
||||||
shapeSwitchAtom,
|
shapeSwitchAtom,
|
||||||
switchShapes,
|
switchShapes,
|
||||||
|
@ -4179,21 +4179,20 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const { generic, linear } =
|
const switchCategory =
|
||||||
getSwitchableTypeFromElements(selectedElements);
|
getSwitchCategoryFromElements(selectedElements);
|
||||||
|
|
||||||
if (editorJotaiStore.get(shapeSwitchAtom)?.type === "panel") {
|
if (editorJotaiStore.get(shapeSwitchAtom)?.type === "panel") {
|
||||||
if (
|
if (
|
||||||
switchShapes(this, {
|
switchShapes(this, {
|
||||||
generic,
|
switchCategory,
|
||||||
linear,
|
|
||||||
direction: event.shiftKey ? "left" : "right",
|
direction: event.shiftKey ? "left" : "right",
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
this.store.shouldCaptureIncrement();
|
this.store.shouldCaptureIncrement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (generic || linear) {
|
if (switchCategory) {
|
||||||
editorJotaiStore.set(shapeSwitchAtom, {
|
editorJotaiStore.set(shapeSwitchAtom, {
|
||||||
type: "panel",
|
type: "panel",
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { updateElbowArrowPoints } from "@excalidraw/element/elbowArrow";
|
||||||
import { pointFrom, pointRotateRads, type LocalPoint } from "@excalidraw/math";
|
import { pointFrom, pointRotateRads, type LocalPoint } from "@excalidraw/math";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
isArrowBoundToElement,
|
||||||
isArrowElement,
|
isArrowElement,
|
||||||
isCurvedArrow,
|
isCurvedArrow,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
|
@ -44,6 +45,7 @@ import { ShapeCache } from "@excalidraw/element/ShapeCache";
|
||||||
import type {
|
import type {
|
||||||
ConvertibleGenericTypes,
|
ConvertibleGenericTypes,
|
||||||
ConvertibleLinearTypes,
|
ConvertibleLinearTypes,
|
||||||
|
ConvertibleTypes,
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
ExcalidrawDiamondElement,
|
ExcalidrawDiamondElement,
|
||||||
ExcalidrawElbowArrowElement,
|
ExcalidrawElbowArrowElement,
|
||||||
|
@ -117,22 +119,21 @@ const ShapeSwitch = ({ app }: { app: App }) => {
|
||||||
() => app.scene.getSelectedElements(app.state),
|
() => app.scene.getSelectedElements(app.state),
|
||||||
[app.scene, app.state],
|
[app.scene, app.state],
|
||||||
);
|
);
|
||||||
const selectedElementsTypeRef = useRef<"generic" | "linear">(null);
|
const elementsCategoryRef = useRef<SwitchShapeCategory>(null);
|
||||||
|
|
||||||
// close shape switch panel if selecting different "types" of elements
|
// close shape switch panel if selecting different "types" of elements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { generic, linear } = getSwitchableTypeFromElements(selectedElements);
|
const switchCategory = getSwitchCategoryFromElements(selectedElements);
|
||||||
const type = generic ? "generic" : linear ? "linear" : null;
|
|
||||||
|
|
||||||
if (type && !selectedElementsTypeRef.current) {
|
if (switchCategory && !elementsCategoryRef.current) {
|
||||||
selectedElementsTypeRef.current = type;
|
elementsCategoryRef.current = switchCategory;
|
||||||
} else if (
|
} else if (
|
||||||
(selectedElementsTypeRef.current && !type) ||
|
(elementsCategoryRef.current && !switchCategory) ||
|
||||||
(selectedElementsTypeRef.current &&
|
(elementsCategoryRef.current &&
|
||||||
type !== selectedElementsTypeRef.current)
|
switchCategory !== elementsCategoryRef.current)
|
||||||
) {
|
) {
|
||||||
setShapeSwitch(null);
|
setShapeSwitch(null);
|
||||||
selectedElementsTypeRef.current = null;
|
elementsCategoryRef.current = null;
|
||||||
}
|
}
|
||||||
}, [selectedElements, app.state.selectedElementIds, setShapeSwitch]);
|
}, [selectedElements, app.state.selectedElementIds, setShapeSwitch]);
|
||||||
|
|
||||||
|
@ -158,7 +159,9 @@ const Panel = ({
|
||||||
app: App;
|
app: App;
|
||||||
elements: ExcalidrawElement[];
|
elements: ExcalidrawElement[];
|
||||||
}) => {
|
}) => {
|
||||||
const { generic, linear } = getSwitchableTypeFromElements(elements);
|
const switchCategory = getSwitchCategoryFromElements(elements);
|
||||||
|
const generic = switchCategory === "generic";
|
||||||
|
const linear = switchCategory === "linear";
|
||||||
|
|
||||||
const genericElements = useMemo(() => {
|
const genericElements = useMemo(() => {
|
||||||
return generic ? getGenericSwitchableElements(elements) : [];
|
return generic ? getGenericSwitchableElements(elements) : [];
|
||||||
|
@ -325,8 +328,7 @@ const Panel = ({
|
||||||
trackEvent("shape-switch", type, "ui");
|
trackEvent("shape-switch", type, "ui");
|
||||||
}
|
}
|
||||||
switchShapes(app, {
|
switchShapes(app, {
|
||||||
generic,
|
switchCategory,
|
||||||
linear,
|
|
||||||
nextType: type as
|
nextType: type as
|
||||||
| ConvertibleGenericTypes
|
| ConvertibleGenericTypes
|
||||||
| ConvertibleLinearTypes,
|
| ConvertibleLinearTypes,
|
||||||
|
@ -386,21 +388,21 @@ export const adjustBoundTextSize = (
|
||||||
redrawTextBoundingBox(boundText, container, scene);
|
redrawTextBoundingBox(boundText, container, scene);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SwitchShapeCategory = "generic" | "linear" | null;
|
||||||
|
|
||||||
export const switchShapes = (
|
export const switchShapes = (
|
||||||
app: App,
|
app: App,
|
||||||
{
|
{
|
||||||
generic,
|
switchCategory,
|
||||||
linear,
|
|
||||||
nextType,
|
nextType,
|
||||||
direction = "right",
|
direction = "right",
|
||||||
}: {
|
}: {
|
||||||
generic?: boolean;
|
switchCategory: SwitchShapeCategory;
|
||||||
linear?: boolean;
|
nextType?: ConvertibleTypes;
|
||||||
nextType?: ConvertibleGenericTypes | ConvertibleLinearTypes;
|
|
||||||
direction?: "left" | "right";
|
direction?: "left" | "right";
|
||||||
} = {},
|
},
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (!generic && !linear) {
|
if (!switchCategory) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +415,7 @@ export const switchShapes = (
|
||||||
|
|
||||||
const advancement = direction === "right" ? 1 : -1;
|
const advancement = direction === "right" ? 1 : -1;
|
||||||
|
|
||||||
if (generic) {
|
if (switchCategory === "generic") {
|
||||||
const selectedGenericSwitchableElements =
|
const selectedGenericSwitchableElements =
|
||||||
getGenericSwitchableElements(selectedElements);
|
getGenericSwitchableElements(selectedElements);
|
||||||
|
|
||||||
|
@ -490,7 +492,7 @@ export const switchShapes = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linear) {
|
if (switchCategory === "linear") {
|
||||||
const selectedLinearSwitchableElements = getLinearSwitchableElements(
|
const selectedLinearSwitchableElements = getLinearSwitchableElements(
|
||||||
selectedElements,
|
selectedElements,
|
||||||
) as ExcalidrawLinearElement[];
|
) as ExcalidrawLinearElement[];
|
||||||
|
@ -634,77 +636,47 @@ export const switchShapes = (
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSwitchableTypeFromElements = (
|
export const getSwitchCategoryFromElements = (
|
||||||
elements: ExcalidrawElement[],
|
elements: ExcalidrawElement[],
|
||||||
):
|
): SwitchShapeCategory => {
|
||||||
| {
|
|
||||||
generic: true;
|
|
||||||
linear: false;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
linear: true;
|
|
||||||
generic: false;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
generic: false;
|
|
||||||
linear: false;
|
|
||||||
} => {
|
|
||||||
if (elements.length === 0) {
|
if (elements.length === 0) {
|
||||||
return {
|
return null;
|
||||||
generic: false,
|
|
||||||
linear: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let onlyLinear = true;
|
let onlyLinear = true;
|
||||||
|
let canBeLinear = false;
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
if (
|
if (
|
||||||
element.type === "rectangle" ||
|
element.type === "rectangle" ||
|
||||||
element.type === "ellipse" ||
|
element.type === "ellipse" ||
|
||||||
element.type === "diamond"
|
element.type === "diamond"
|
||||||
) {
|
) {
|
||||||
return {
|
return "generic";
|
||||||
generic: true,
|
|
||||||
linear: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (element.type !== "arrow" && element.type !== "line") {
|
if (element.type !== "arrow" && element.type !== "line") {
|
||||||
onlyLinear = false;
|
onlyLinear = false;
|
||||||
|
canBeLinear = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (onlyLinear) {
|
if (onlyLinear) {
|
||||||
// check at least some linear element is switchable
|
if (isLinearElement(element) && isLinearElementElligible(element)) {
|
||||||
// for a linear to be swtichable:
|
canBeLinear = true;
|
||||||
// - 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 {
|
|
||||||
linear,
|
|
||||||
generic: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
if (canBeLinear) {
|
||||||
generic: false,
|
return "linear";
|
||||||
linear: false,
|
}
|
||||||
};
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isLinearElementElligible = (linear: ExcalidrawLinearElement) => {
|
||||||
|
return (
|
||||||
|
!(isArrowElement(linear) && isArrowBoundToElement(linear)) &&
|
||||||
|
!(linear.boundElements && linear.boundElements.length > 0)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getArrowType = (element: ExcalidrawLinearElement) => {
|
const getArrowType = (element: ExcalidrawLinearElement) => {
|
||||||
|
@ -795,13 +767,7 @@ const getGenericSwitchableElements = (elements: ExcalidrawElement[]) =>
|
||||||
|
|
||||||
const getLinearSwitchableElements = (elements: ExcalidrawElement[]) =>
|
const getLinearSwitchableElements = (elements: ExcalidrawElement[]) =>
|
||||||
elements.filter(
|
elements.filter(
|
||||||
(element) =>
|
(element) => isLinearElement(element) && isLinearElementElligible(element),
|
||||||
isLinearElement(element) &&
|
|
||||||
!(
|
|
||||||
isArrowElement(element) &&
|
|
||||||
(element.startBinding !== null || element.endBinding !== null)
|
|
||||||
) &&
|
|
||||||
(!element.boundElements || element.boundElements.length === 0),
|
|
||||||
) as ExcalidrawLinearElement[];
|
) as ExcalidrawLinearElement[];
|
||||||
|
|
||||||
const THRESHOLD = 20;
|
const THRESHOLD = 20;
|
||||||
|
@ -935,8 +901,6 @@ const CONVERTIBLE_LINEAR_TYPES: readonly ConvertibleLinearTypes[] = [
|
||||||
"elbowArrow",
|
"elbowArrow",
|
||||||
];
|
];
|
||||||
|
|
||||||
type ConvertibleType = ConvertibleGenericTypes | ConvertibleLinearTypes;
|
|
||||||
|
|
||||||
const isConvertibleGenericType = (
|
const isConvertibleGenericType = (
|
||||||
elementType: string,
|
elementType: string,
|
||||||
): elementType is ConvertibleGenericTypes =>
|
): elementType is ConvertibleGenericTypes =>
|
||||||
|
@ -962,7 +926,7 @@ export const convertElementType = <
|
||||||
TElement extends Exclude<ExcalidrawElement, ExcalidrawSelectionElement>,
|
TElement extends Exclude<ExcalidrawElement, ExcalidrawSelectionElement>,
|
||||||
>(
|
>(
|
||||||
element: TElement,
|
element: TElement,
|
||||||
newType: ConvertibleType,
|
newType: ConvertibleTypes,
|
||||||
app: AppClassProperties,
|
app: AppClassProperties,
|
||||||
): ExcalidrawElement => {
|
): ExcalidrawElement => {
|
||||||
if (!isValidConversion(element.type, newType)) {
|
if (!isValidConversion(element.type, newType)) {
|
||||||
|
@ -1071,8 +1035,8 @@ export const convertElementType = <
|
||||||
|
|
||||||
const isValidConversion = (
|
const isValidConversion = (
|
||||||
startType: string,
|
startType: string,
|
||||||
targetType: ConvertibleType,
|
targetType: ConvertibleTypes,
|
||||||
): startType is ConvertibleType => {
|
): startType is ConvertibleTypes => {
|
||||||
if (
|
if (
|
||||||
isConvertibleGenericType(startType) &&
|
isConvertibleGenericType(startType) &&
|
||||||
isConvertibleGenericType(targetType)
|
isConvertibleGenericType(targetType)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue