mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
prefer generic when mixed
This commit is contained in:
parent
31d2c0b7e9
commit
66812e5ab3
4 changed files with 101 additions and 97 deletions
|
@ -190,8 +190,7 @@ import {
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFlowchartNodeElement,
|
isFlowchartNodeElement,
|
||||||
isBindableElement,
|
isBindableElement,
|
||||||
areGenericSwitchableElements,
|
getSwitchableTypeFromElements,
|
||||||
areLinearSwitchableElements,
|
|
||||||
} from "../element/typeChecks";
|
} from "../element/typeChecks";
|
||||||
import { getCenter, getDistance } from "../gesture";
|
import { getCenter, getDistance } from "../gesture";
|
||||||
import {
|
import {
|
||||||
|
@ -4105,22 +4104,20 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
} else if (event.key === KEYS.TAB) {
|
} else if (event.key === KEYS.TAB) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const genericSwitchable =
|
const { generic, linear } =
|
||||||
areGenericSwitchableElements(selectedElements);
|
getSwitchableTypeFromElements(selectedElements);
|
||||||
const linearSwitchable =
|
|
||||||
areLinearSwitchableElements(selectedElements);
|
|
||||||
|
|
||||||
if (editorJotaiStore.get(shapeSwitchAtom)?.type === "panel") {
|
if (editorJotaiStore.get(shapeSwitchAtom)?.type === "panel") {
|
||||||
if (
|
if (
|
||||||
switchShapes(this, {
|
switchShapes(this, {
|
||||||
genericSwitchable,
|
generic,
|
||||||
linearSwitchable,
|
linear,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
this.store.shouldCaptureIncrement();
|
this.store.shouldCaptureIncrement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (genericSwitchable || linearSwitchable) {
|
if (generic || linear) {
|
||||||
editorJotaiStore.set(shapeSwitchAtom, {
|
editorJotaiStore.set(shapeSwitchAtom, {
|
||||||
type: "panel",
|
type: "panel",
|
||||||
});
|
});
|
||||||
|
@ -4130,7 +4127,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
element,
|
element,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
);
|
);
|
||||||
if (boundText && genericSwitchable && element) {
|
if (boundText && generic && element) {
|
||||||
editorJotaiStore.set(shapeSwitchFontSizeAtom, {
|
editorJotaiStore.set(shapeSwitchFontSizeAtom, {
|
||||||
...editorJotaiStore.get(shapeSwitchFontSizeAtom),
|
...editorJotaiStore.get(shapeSwitchFontSizeAtom),
|
||||||
[element.id]: {
|
[element.id]: {
|
||||||
|
|
|
@ -15,10 +15,7 @@ import {
|
||||||
import { getSelectedElements } from "../scene";
|
import { getSelectedElements } from "../scene";
|
||||||
import { trackEvent } from "../analytics";
|
import { trackEvent } from "../analytics";
|
||||||
import {
|
import {
|
||||||
areGenericSwitchableElements,
|
getSwitchableTypeFromElements,
|
||||||
areLinearSwitchableElements,
|
|
||||||
isArrowElement,
|
|
||||||
isLinearElement,
|
|
||||||
isUsingAdaptiveRadius,
|
isUsingAdaptiveRadius,
|
||||||
} from "../element/typeChecks";
|
} from "../element/typeChecks";
|
||||||
import { t } from "../i18n";
|
import { t } from "../i18n";
|
||||||
|
@ -95,18 +92,15 @@ const ShapeSwitch = ({ app }: { app: App }) => {
|
||||||
|
|
||||||
// close shape switch panel if selecting different "types" of elements
|
// close shape switch panel if selecting different "types" of elements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selectedElementsType = areGenericSwitchableElements(selectedElements)
|
const { generic, linear } = getSwitchableTypeFromElements(selectedElements);
|
||||||
? "generic"
|
const type = generic ? "generic" : linear ? "linear" : null;
|
||||||
: areLinearSwitchableElements(selectedElements)
|
|
||||||
? "linear"
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (selectedElementsType && !selectedElementsTypeRef.current) {
|
if (type && !selectedElementsTypeRef.current) {
|
||||||
selectedElementsTypeRef.current = selectedElementsType;
|
selectedElementsTypeRef.current = type;
|
||||||
} else if (
|
} else if (
|
||||||
(selectedElementsTypeRef.current && !selectedElementsType) ||
|
(selectedElementsTypeRef.current && !type) ||
|
||||||
(selectedElementsTypeRef.current &&
|
(selectedElementsTypeRef.current &&
|
||||||
selectedElementsType !== selectedElementsTypeRef.current)
|
type !== selectedElementsTypeRef.current)
|
||||||
) {
|
) {
|
||||||
setShapeSwitch(null);
|
setShapeSwitch(null);
|
||||||
selectedElementsTypeRef.current = null;
|
selectedElementsTypeRef.current = null;
|
||||||
|
@ -228,9 +222,17 @@ const Panel = ({
|
||||||
let [x1, y2, cx, cy] = [0, 0, 0, 0];
|
let [x1, y2, cx, cy] = [0, 0, 0, 0];
|
||||||
let rotatedBottomLeft = [0, 0];
|
let rotatedBottomLeft = [0, 0];
|
||||||
|
|
||||||
const sameType = elements.every(
|
const { generic, linear } = getSwitchableTypeFromElements(elements);
|
||||||
(element) => element.type === elements[0].type,
|
|
||||||
);
|
const genericElements = generic ? getGenericSwitchableElements(elements) : [];
|
||||||
|
|
||||||
|
const sameType = generic
|
||||||
|
? genericElements.every(
|
||||||
|
(element) => element.type === genericElements[0].type,
|
||||||
|
)
|
||||||
|
: linear
|
||||||
|
? elements.every((element) => element.type === elements[0].type)
|
||||||
|
: false;
|
||||||
|
|
||||||
if (elements.length === 1) {
|
if (elements.length === 1) {
|
||||||
[x1, , , y2, cx, cy] = getElementAbsoluteCoords(
|
[x1, , , y2, cx, cy] = getElementAbsoluteCoords(
|
||||||
|
@ -260,16 +262,18 @@ const Panel = ({
|
||||||
app.state,
|
app.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
const SHAPES: [string, string, ReactNode][] = isLinearElement(elements[0])
|
const SHAPES: [string, string, ReactNode][] = linear
|
||||||
? [
|
? [
|
||||||
["arrow", "5", ArrowIcon],
|
["arrow", "5", ArrowIcon],
|
||||||
["line", "6", LineIcon],
|
["line", "6", LineIcon],
|
||||||
]
|
]
|
||||||
: [
|
: generic
|
||||||
|
? [
|
||||||
["rectangle", "2", RectangleIcon],
|
["rectangle", "2", RectangleIcon],
|
||||||
["diamond", "3", DiamondIcon],
|
["diamond", "3", DiamondIcon],
|
||||||
["ellipse", "4", EllipseIcon],
|
["ellipse", "4", EllipseIcon],
|
||||||
];
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -286,17 +290,8 @@ const Panel = ({
|
||||||
{SHAPES.map(([type, shortcut, icon]) => {
|
{SHAPES.map(([type, shortcut, icon]) => {
|
||||||
const isSelected =
|
const isSelected =
|
||||||
sameType &&
|
sameType &&
|
||||||
(type === elements[0].type ||
|
((generic && genericElements[0].type === type) ||
|
||||||
(isArrowElement(elements[0]) &&
|
(linear && elements[0].type === type));
|
||||||
elements[0].elbowed &&
|
|
||||||
type === "elbow") ||
|
|
||||||
(isArrowElement(elements[0]) &&
|
|
||||||
elements[0].roundness &&
|
|
||||||
type === "curve") ||
|
|
||||||
(isArrowElement(elements[0]) &&
|
|
||||||
!elements[0].elbowed &&
|
|
||||||
!elements[0].roundness &&
|
|
||||||
type === "straight"));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
|
@ -320,8 +315,8 @@ const Panel = ({
|
||||||
trackEvent("shape-switch", type, "ui");
|
trackEvent("shape-switch", type, "ui");
|
||||||
}
|
}
|
||||||
switchShapes(app, {
|
switchShapes(app, {
|
||||||
genericSwitchable: GENERIC_SWITCHABLE_SHAPES.includes(type),
|
generic: GENERIC_SWITCHABLE_SHAPES.includes(type),
|
||||||
linearSwitchable: LINEAR_SWITCHABLE_SHAPES.includes(type),
|
linear: LINEAR_SWITCHABLE_SHAPES.includes(type),
|
||||||
nextType: type as
|
nextType: type as
|
||||||
| GenericSwitchableToolType
|
| GenericSwitchableToolType
|
||||||
| LinearSwitchableToolType,
|
| LinearSwitchableToolType,
|
||||||
|
@ -410,16 +405,16 @@ export const adjustBoundTextSize = (
|
||||||
export const switchShapes = (
|
export const switchShapes = (
|
||||||
app: App,
|
app: App,
|
||||||
{
|
{
|
||||||
genericSwitchable,
|
generic,
|
||||||
linearSwitchable,
|
linear,
|
||||||
nextType,
|
nextType,
|
||||||
}: {
|
}: {
|
||||||
genericSwitchable?: boolean;
|
generic?: boolean;
|
||||||
linearSwitchable?: boolean;
|
linear?: boolean;
|
||||||
nextType?: GenericSwitchableToolType | LinearSwitchableToolType;
|
nextType?: GenericSwitchableToolType | LinearSwitchableToolType;
|
||||||
} = {},
|
} = {},
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (!genericSwitchable && !linearSwitchable) {
|
if (!generic && !linear) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,14 +428,18 @@ export const switchShapes = (
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
const sameType = selectedElements.every(
|
if (generic) {
|
||||||
(element) => element.type === selectedElements[0].type,
|
const selectedGenericSwitchableElements =
|
||||||
);
|
getGenericSwitchableElements(selectedElements);
|
||||||
|
|
||||||
|
const sameType = selectedGenericSwitchableElements.every(
|
||||||
|
(element) => element.type === selectedGenericSwitchableElements[0].type,
|
||||||
|
);
|
||||||
|
|
||||||
if (genericSwitchable) {
|
|
||||||
// TODO: filter generic elements
|
|
||||||
const index = sameType
|
const index = sameType
|
||||||
? GENERIC_SWITCHABLE_SHAPES.indexOf(selectedElements[0].type)
|
? GENERIC_SWITCHABLE_SHAPES.indexOf(
|
||||||
|
selectedGenericSwitchableElements[0].type,
|
||||||
|
)
|
||||||
: -1;
|
: -1;
|
||||||
|
|
||||||
nextType =
|
nextType =
|
||||||
|
@ -449,7 +448,7 @@ export const switchShapes = (
|
||||||
(index + 1) % GENERIC_SWITCHABLE_SHAPES.length
|
(index + 1) % GENERIC_SWITCHABLE_SHAPES.length
|
||||||
] as GenericSwitchableToolType);
|
] as GenericSwitchableToolType);
|
||||||
|
|
||||||
selectedElements.forEach((element) => {
|
selectedGenericSwitchableElements.forEach((element) => {
|
||||||
ShapeCache.delete(element);
|
ShapeCache.delete(element);
|
||||||
|
|
||||||
mutateElement(
|
mutateElement(
|
||||||
|
@ -507,7 +506,10 @@ export const switchShapes = (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linearSwitchable) {
|
if (linear) {
|
||||||
|
const sameType = selectedElements.every(
|
||||||
|
(element) => element.type === selectedElements[0].type,
|
||||||
|
);
|
||||||
const index = sameType
|
const index = sameType
|
||||||
? LINEAR_SWITCHABLE_SHAPES.indexOf(selectedElements[0].type)
|
? LINEAR_SWITCHABLE_SHAPES.indexOf(selectedElements[0].type)
|
||||||
: -1;
|
: -1;
|
||||||
|
@ -547,6 +549,9 @@ export const switchShapes = (
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const switchLinearShapes = (app: App) => {};
|
const getGenericSwitchableElements = (elements: ExcalidrawElement[]) =>
|
||||||
|
elements.filter((element) =>
|
||||||
|
GENERIC_SWITCHABLE_SHAPES.includes(element.type),
|
||||||
|
);
|
||||||
|
|
||||||
export default ShapeSwitch;
|
export default ShapeSwitch;
|
||||||
|
|
|
@ -27,9 +27,6 @@ import type {
|
||||||
PointBinding,
|
PointBinding,
|
||||||
FixedPointBinding,
|
FixedPointBinding,
|
||||||
ExcalidrawFlowchartNodeElement,
|
ExcalidrawFlowchartNodeElement,
|
||||||
GenericSwitchableToolType,
|
|
||||||
LinearSwitchableToolType,
|
|
||||||
ExcalidrawGenericSwitchableElement,
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
export const isInitializedImageElement = (
|
export const isInitializedImageElement = (
|
||||||
|
@ -341,45 +338,54 @@ export const isBounds = (box: unknown): box is Bounds =>
|
||||||
typeof box[2] === "number" &&
|
typeof box[2] === "number" &&
|
||||||
typeof box[3] === "number";
|
typeof box[3] === "number";
|
||||||
|
|
||||||
type NonEmptyArray<T> = [T, ...T[]];
|
export const getSwitchableTypeFromElements = (
|
||||||
|
|
||||||
export const areGenericSwitchableElements = (
|
|
||||||
elements: ExcalidrawElement[],
|
elements: ExcalidrawElement[],
|
||||||
): elements is NonEmptyArray<ExcalidrawGenericSwitchableElement> => {
|
):
|
||||||
|
| {
|
||||||
|
generic: true;
|
||||||
|
linear: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
linear: true;
|
||||||
|
generic: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
generic: false;
|
||||||
|
linear: false;
|
||||||
|
} => {
|
||||||
if (elements.length === 0) {
|
if (elements.length === 0) {
|
||||||
return false;
|
return {
|
||||||
|
generic: false,
|
||||||
|
linear: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return elements.every(
|
|
||||||
(element) =>
|
let onlyLinear = true;
|
||||||
|
for (const element of elements) {
|
||||||
|
if (
|
||||||
element.type === "rectangle" ||
|
element.type === "rectangle" ||
|
||||||
element.type === "ellipse" ||
|
element.type === "ellipse" ||
|
||||||
element.type === "diamond",
|
element.type === "diamond"
|
||||||
);
|
) {
|
||||||
};
|
return {
|
||||||
|
generic: true,
|
||||||
export const isGenericSwitchableToolType = (
|
linear: false,
|
||||||
type: string,
|
};
|
||||||
): type is GenericSwitchableToolType => {
|
}
|
||||||
return type === "rectangle" || type === "ellipse" || type === "diamond";
|
if (element.type !== "arrow" && element.type !== "line") {
|
||||||
};
|
onlyLinear = false;
|
||||||
|
}
|
||||||
export const areLinearSwitchableElements = (
|
|
||||||
elements: ExcalidrawElement[],
|
|
||||||
): elements is NonEmptyArray<ExcalidrawLinearElement> => {
|
|
||||||
if (elements.length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
const firstType = elements[0].type;
|
|
||||||
return (
|
|
||||||
(firstType === "arrow" || firstType === "line") &&
|
|
||||||
elements.every(
|
|
||||||
(element) => element.type === "arrow" || element.type === "line",
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isLinearSwitchableToolType = (
|
if (onlyLinear) {
|
||||||
type: string,
|
return {
|
||||||
): type is LinearSwitchableToolType => {
|
linear: true,
|
||||||
return type === "arrow" || type === "line";
|
generic: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
generic: false,
|
||||||
|
linear: false,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -414,7 +414,3 @@ export type ElementsMapOrArray =
|
||||||
|
|
||||||
export type GenericSwitchableToolType = "rectangle" | "ellipse" | "diamond";
|
export type GenericSwitchableToolType = "rectangle" | "ellipse" | "diamond";
|
||||||
export type LinearSwitchableToolType = "line" | "arrow";
|
export type LinearSwitchableToolType = "line" | "arrow";
|
||||||
export type ExcalidrawGenericSwitchableElement =
|
|
||||||
| ExcalidrawRectangleElement
|
|
||||||
| ExcalidrawEllipseElement
|
|
||||||
| ExcalidrawDiamondElement;
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue