lint
This commit is contained in:
@@ -29,10 +29,13 @@ export const actionSelectAllElementsInFrame = register({
|
||||
elements,
|
||||
appState: {
|
||||
...appState,
|
||||
selectedElementIds: elementsInFrame.reduce((acc, element) => {
|
||||
acc[element.id] = true;
|
||||
return acc;
|
||||
}, {} as Record<ExcalidrawElement["id"], true>),
|
||||
selectedElementIds: elementsInFrame.reduce(
|
||||
(acc, element) => {
|
||||
acc[element.id] = true;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<ExcalidrawElement["id"], true>,
|
||||
),
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
|
||||
+2
-2
@@ -215,11 +215,11 @@ const _clearAppStateForStorage = <
|
||||
exportType: ExportType,
|
||||
) => {
|
||||
type ExportableKeys = {
|
||||
[K in keyof typeof APP_STATE_STORAGE_CONF]: typeof APP_STATE_STORAGE_CONF[K][ExportType] extends true
|
||||
[K in keyof typeof APP_STATE_STORAGE_CONF]: (typeof APP_STATE_STORAGE_CONF)[K][ExportType] extends true
|
||||
? K
|
||||
: never;
|
||||
}[keyof typeof APP_STATE_STORAGE_CONF];
|
||||
const stateForExport = {} as { [K in ExportableKeys]?: typeof appState[K] };
|
||||
const stateForExport = {} as { [K in ExportableKeys]?: (typeof appState)[K] };
|
||||
for (const key of Object.keys(appState) as (keyof typeof appState)[]) {
|
||||
const propConfig = APP_STATE_STORAGE_CONF[key];
|
||||
if (propConfig?.[exportType]) {
|
||||
|
||||
+9
-6
@@ -6,12 +6,15 @@ const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(
|
||||
source: R,
|
||||
keys: K,
|
||||
) => {
|
||||
return keys.reduce((acc, key: K[number]) => {
|
||||
if (key in source) {
|
||||
acc[key] = source[key];
|
||||
}
|
||||
return acc;
|
||||
}, {} as Pick<R, K[number]>) as Pick<R, K[number]>;
|
||||
return keys.reduce(
|
||||
(acc, key: K[number]) => {
|
||||
if (key in source) {
|
||||
acc[key] = source[key];
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Pick<R, K[number]>,
|
||||
) as Pick<R, K[number]>;
|
||||
};
|
||||
|
||||
export type ColorPickerColor =
|
||||
|
||||
@@ -3080,7 +3080,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
tool:
|
||||
| {
|
||||
type:
|
||||
| typeof SHAPES[number]["value"]
|
||||
| (typeof SHAPES)[number]["value"]
|
||||
| "eraser"
|
||||
| "hand"
|
||||
| "frame"
|
||||
@@ -4770,12 +4770,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
),
|
||||
// we need to duplicate because we'll be updating this state
|
||||
lastCoords: { ...origin },
|
||||
originalElements: this.scene
|
||||
.getNonDeletedElements()
|
||||
.reduce((acc, element) => {
|
||||
originalElements: this.scene.getNonDeletedElements().reduce(
|
||||
(acc, element) => {
|
||||
acc.set(element.id, deepCopyElement(element));
|
||||
return acc;
|
||||
}, new Map() as PointerDownState["originalElements"]),
|
||||
},
|
||||
new Map() as PointerDownState["originalElements"],
|
||||
),
|
||||
resize: {
|
||||
handleType: false,
|
||||
isResizing: false,
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
|
||||
border-radius: 1rem;
|
||||
background-color: var(--button-color);
|
||||
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.28),
|
||||
box-shadow:
|
||||
0 3px 5px -1px rgba(0, 0, 0, 0.28),
|
||||
0 6px 10px 0 rgba(0, 0, 0, 0.14);
|
||||
|
||||
font-family: Cascadia;
|
||||
|
||||
@@ -70,12 +70,16 @@
|
||||
font-weight: 500;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: visibility 0s linear 0s, opacity 0.5s;
|
||||
transition:
|
||||
visibility 0s linear 0s,
|
||||
opacity 0.5s;
|
||||
|
||||
&--visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: visibility 0s linear 300ms, opacity 0.5s;
|
||||
transition:
|
||||
visibility 0s linear 300ms,
|
||||
opacity 0.5s;
|
||||
transition-delay: 0.8s;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -391,13 +391,19 @@
|
||||
appearance: none;
|
||||
background-image: var(--dropdown-icon);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.7rem top 50%, 0 0;
|
||||
background-position:
|
||||
right 0.7rem top 50%,
|
||||
0 0;
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
background-position: left 0.7rem top 50%, 0 0;
|
||||
background-position:
|
||||
left 0.7rem top 50%,
|
||||
0 0;
|
||||
}
|
||||
|
||||
background-size: 0.65em auto, 100%;
|
||||
background-size:
|
||||
0.65em auto,
|
||||
100%;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px var(--focus-highlight-color);
|
||||
|
||||
+1
-1
@@ -273,7 +273,7 @@ export const resizeImageFile = async (
|
||||
file: File,
|
||||
opts: {
|
||||
/** undefined indicates auto */
|
||||
outputType?: typeof MIME_TYPES["jpg"];
|
||||
outputType?: (typeof MIME_TYPES)["jpg"];
|
||||
maxWidthOrHeight: number;
|
||||
},
|
||||
): Promise<File> => {
|
||||
|
||||
+69
-72
@@ -51,84 +51,81 @@ export type ValidLinearElement = {
|
||||
textAlign?: TextAlign;
|
||||
verticalAlign?: VerticalAlign;
|
||||
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
end?:
|
||||
end?: (
|
||||
| (
|
||||
| (
|
||||
| {
|
||||
type: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
}
|
||||
| {
|
||||
id: ExcalidrawGenericElement["id"];
|
||||
type?: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
}
|
||||
)
|
||||
| ((
|
||||
| {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type?: "text";
|
||||
id: ExcalidrawTextElement["id"];
|
||||
text: string;
|
||||
}
|
||||
) &
|
||||
Partial<ExcalidrawTextElement>)
|
||||
| {
|
||||
type: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
}
|
||||
| {
|
||||
id: ExcalidrawGenericElement["id"];
|
||||
type?: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
}
|
||||
)
|
||||
| ((
|
||||
| {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type?: "text";
|
||||
id: ExcalidrawTextElement["id"];
|
||||
text: string;
|
||||
}
|
||||
) &
|
||||
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
start?:
|
||||
Partial<ExcalidrawTextElement>)
|
||||
) &
|
||||
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
start?: (
|
||||
| (
|
||||
| (
|
||||
| {
|
||||
type: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
}
|
||||
| {
|
||||
id: ExcalidrawGenericElement["id"];
|
||||
type?: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
}
|
||||
)
|
||||
| ((
|
||||
| {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type?: "text";
|
||||
id: ExcalidrawTextElement["id"];
|
||||
text: string;
|
||||
}
|
||||
) &
|
||||
Partial<ExcalidrawTextElement>)
|
||||
| {
|
||||
type: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
}
|
||||
| {
|
||||
id: ExcalidrawGenericElement["id"];
|
||||
type?: Exclude<
|
||||
ExcalidrawBindableElement["type"],
|
||||
"image" | "text" | "frame" | "embeddable"
|
||||
>;
|
||||
}
|
||||
)
|
||||
| ((
|
||||
| {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
| {
|
||||
type?: "text";
|
||||
id: ExcalidrawTextElement["id"];
|
||||
text: string;
|
||||
}
|
||||
) &
|
||||
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
Partial<ExcalidrawTextElement>)
|
||||
) &
|
||||
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
} & Partial<ExcalidrawLinearElement>;
|
||||
|
||||
export type ValidContainer =
|
||||
| {
|
||||
type: Exclude<ExcalidrawGenericElement["type"], "selection">;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
label?: {
|
||||
text: string;
|
||||
fontSize?: number;
|
||||
fontFamily?: FontFamilyValues;
|
||||
textAlign?: TextAlign;
|
||||
verticalAlign?: VerticalAlign;
|
||||
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
} & ElementConstructorOpts;
|
||||
export type ValidContainer = {
|
||||
type: Exclude<ExcalidrawGenericElement["type"], "selection">;
|
||||
id?: ExcalidrawGenericElement["id"];
|
||||
label?: {
|
||||
text: string;
|
||||
fontSize?: number;
|
||||
fontFamily?: FontFamilyValues;
|
||||
textAlign?: TextAlign;
|
||||
verticalAlign?: VerticalAlign;
|
||||
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||
} & ElementConstructorOpts;
|
||||
|
||||
export type ExcalidrawElementSkeleton =
|
||||
| Extract<
|
||||
|
||||
@@ -31,7 +31,7 @@ const _ce = ({
|
||||
width: w,
|
||||
height: h,
|
||||
angle: a,
|
||||
} as ExcalidrawElement);
|
||||
}) as ExcalidrawElement;
|
||||
|
||||
describe("getElementAbsoluteCoords", () => {
|
||||
it("test x1 coordinate", () => {
|
||||
|
||||
@@ -404,7 +404,7 @@ export class LinearElementEditor {
|
||||
static getEditorMidPoints = (
|
||||
element: NonDeleted<ExcalidrawLinearElement>,
|
||||
appState: InteractiveCanvasAppState,
|
||||
): typeof editorMidPointsCache["points"] => {
|
||||
): (typeof editorMidPointsCache)["points"] => {
|
||||
const boundText = getBoundTextElement(element);
|
||||
|
||||
// Since its not needed outside editor unless 2 pointer lines or bound text
|
||||
@@ -501,7 +501,7 @@ export class LinearElementEditor {
|
||||
}
|
||||
}
|
||||
let index = 0;
|
||||
const midPoints: typeof editorMidPointsCache["points"] =
|
||||
const midPoints: (typeof editorMidPointsCache)["points"] =
|
||||
LinearElementEditor.getEditorMidPoints(element, appState);
|
||||
while (index < midPoints.length) {
|
||||
if (midPoints[index] !== null) {
|
||||
@@ -609,7 +609,7 @@ export class LinearElementEditor {
|
||||
hitElement: NonDeleted<ExcalidrawElement> | null;
|
||||
linearElementEditor: LinearElementEditor | null;
|
||||
} {
|
||||
const ret: ReturnType<typeof LinearElementEditor["handlePointerDown"]> = {
|
||||
const ret: ReturnType<(typeof LinearElementEditor)["handlePointerDown"]> = {
|
||||
didAddPoint: false,
|
||||
hitElement: null,
|
||||
linearElementEditor: null,
|
||||
|
||||
@@ -767,7 +767,7 @@ export const resizeMultipleElements = (
|
||||
false,
|
||||
);
|
||||
|
||||
const update: typeof elementsAndUpdates[0]["update"] = {
|
||||
const update: (typeof elementsAndUpdates)[0]["update"] = {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
|
||||
+20
-14
@@ -70,20 +70,26 @@ export const getElementWithTransformHandleType = (
|
||||
zoom: Zoom,
|
||||
pointerType: PointerType,
|
||||
) => {
|
||||
return elements.reduce((result, element) => {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
const transformHandleType = resizeTest(
|
||||
element,
|
||||
appState,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
zoom,
|
||||
pointerType,
|
||||
);
|
||||
return transformHandleType ? { element, transformHandleType } : null;
|
||||
}, null as { element: NonDeletedExcalidrawElement; transformHandleType: MaybeTransformHandleType } | null);
|
||||
return elements.reduce(
|
||||
(result, element) => {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
const transformHandleType = resizeTest(
|
||||
element,
|
||||
appState,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
zoom,
|
||||
pointerType,
|
||||
);
|
||||
return transformHandleType ? { element, transformHandleType } : null;
|
||||
},
|
||||
null as {
|
||||
element: NonDeletedExcalidrawElement;
|
||||
transformHandleType: MaybeTransformHandleType;
|
||||
} | null,
|
||||
);
|
||||
};
|
||||
|
||||
export const getTransformHandleTypeFromCoords = (
|
||||
|
||||
@@ -11,18 +11,18 @@ import { MarkNonNullable, ValueOf } from "../utility-types";
|
||||
export type ChartType = "bar" | "line";
|
||||
export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
|
||||
export type FontFamilyKeys = keyof typeof FONT_FAMILY;
|
||||
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
|
||||
export type Theme = typeof THEME[keyof typeof THEME];
|
||||
export type FontFamilyValues = (typeof FONT_FAMILY)[FontFamilyKeys];
|
||||
export type Theme = (typeof THEME)[keyof typeof THEME];
|
||||
export type FontString = string & { _brand: "fontString" };
|
||||
export type GroupId = string;
|
||||
export type PointerType = "mouse" | "pen" | "touch";
|
||||
export type StrokeRoundness = "round" | "sharp";
|
||||
export type RoundnessType = ValueOf<typeof ROUNDNESS>;
|
||||
export type StrokeStyle = "solid" | "dashed" | "dotted";
|
||||
export type TextAlign = typeof TEXT_ALIGN[keyof typeof TEXT_ALIGN];
|
||||
export type TextAlign = (typeof TEXT_ALIGN)[keyof typeof TEXT_ALIGN];
|
||||
|
||||
type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN;
|
||||
export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys];
|
||||
export type VerticalAlign = (typeof VERTICAL_ALIGN)[VerticalAlignKeys];
|
||||
|
||||
type _ExcalidrawElementBase = Readonly<{
|
||||
id: string;
|
||||
|
||||
+28
-25
@@ -104,35 +104,38 @@ class History {
|
||||
): DehydratedHistoryEntry =>
|
||||
this.dehydrateHistoryEntry({
|
||||
appState: clearAppStatePropertiesForHistory(appState),
|
||||
elements: elements.reduce((elements, element) => {
|
||||
if (
|
||||
isLinearElement(element) &&
|
||||
appState.multiElement &&
|
||||
appState.multiElement.id === element.id
|
||||
) {
|
||||
// don't store multi-point arrow if still has only one point
|
||||
elements: elements.reduce(
|
||||
(elements, element) => {
|
||||
if (
|
||||
isLinearElement(element) &&
|
||||
appState.multiElement &&
|
||||
appState.multiElement.id === element.id &&
|
||||
element.points.length < 2
|
||||
appState.multiElement.id === element.id
|
||||
) {
|
||||
return elements;
|
||||
}
|
||||
// don't store multi-point arrow if still has only one point
|
||||
if (
|
||||
appState.multiElement &&
|
||||
appState.multiElement.id === element.id &&
|
||||
element.points.length < 2
|
||||
) {
|
||||
return elements;
|
||||
}
|
||||
|
||||
elements.push({
|
||||
...element,
|
||||
// don't store last point if not committed
|
||||
points:
|
||||
element.lastCommittedPoint !==
|
||||
element.points[element.points.length - 1]
|
||||
? element.points.slice(0, -1)
|
||||
: element.points,
|
||||
});
|
||||
} else {
|
||||
elements.push(element);
|
||||
}
|
||||
return elements;
|
||||
}, [] as Mutable<typeof elements>),
|
||||
elements.push({
|
||||
...element,
|
||||
// don't store last point if not committed
|
||||
points:
|
||||
element.lastCommittedPoint !==
|
||||
element.points[element.points.length - 1]
|
||||
? element.points.slice(0, -1)
|
||||
: element.points,
|
||||
});
|
||||
} else {
|
||||
elements.push(element);
|
||||
}
|
||||
return elements;
|
||||
},
|
||||
[] as Mutable<typeof elements>,
|
||||
),
|
||||
});
|
||||
|
||||
shouldCreateEntry(nextEntry: HistoryEntry): boolean {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ const hashSelectionOpts = (
|
||||
type _ = Assert<
|
||||
SameType<
|
||||
Required<HashableKeys>,
|
||||
Pick<Required<HashableKeys>, typeof keys[number]>
|
||||
Pick<Required<HashableKeys>, (typeof keys)[number]>
|
||||
>
|
||||
>;
|
||||
|
||||
|
||||
+8
-8
@@ -167,20 +167,20 @@ export const _generateElementShape = (
|
||||
rightX - verticalRadius
|
||||
} ${rightY - horizontalRadius}
|
||||
C ${rightX} ${rightY}, ${rightX} ${rightY}, ${
|
||||
rightX - verticalRadius
|
||||
} ${rightY + horizontalRadius}
|
||||
rightX - verticalRadius
|
||||
} ${rightY + horizontalRadius}
|
||||
L ${bottomX + verticalRadius} ${bottomY - horizontalRadius}
|
||||
C ${bottomX} ${bottomY}, ${bottomX} ${bottomY}, ${
|
||||
bottomX - verticalRadius
|
||||
} ${bottomY - horizontalRadius}
|
||||
bottomX - verticalRadius
|
||||
} ${bottomY - horizontalRadius}
|
||||
L ${leftX + verticalRadius} ${leftY + horizontalRadius}
|
||||
C ${leftX} ${leftY}, ${leftX} ${leftY}, ${leftX + verticalRadius} ${
|
||||
leftY - horizontalRadius
|
||||
}
|
||||
leftY - horizontalRadius
|
||||
}
|
||||
L ${topX - verticalRadius} ${topY + horizontalRadius}
|
||||
C ${topX} ${topY}, ${topX} ${topY}, ${topX + verticalRadius} ${
|
||||
topY + horizontalRadius
|
||||
}`,
|
||||
topY + horizontalRadius
|
||||
}`,
|
||||
generateRoughOptions(element, true),
|
||||
);
|
||||
} else {
|
||||
|
||||
+9
-6
@@ -167,8 +167,8 @@ export const exportToSvg = async (
|
||||
|
||||
exportingFrameClipPath = `<clipPath id=${exportingFrame.id}>
|
||||
<rect transform="translate(${exportingFrame.x + offsetX} ${
|
||||
exportingFrame.y + offsetY
|
||||
}) rotate(${exportingFrame.angle} ${cx} ${cy})"
|
||||
exportingFrame.y + offsetY
|
||||
}) rotate(${exportingFrame.angle} ${cx} ${cy})"
|
||||
width="${exportingFrame.width}"
|
||||
height="${exportingFrame.height}"
|
||||
>
|
||||
@@ -235,10 +235,13 @@ const getCanvasSize = (
|
||||
if (!isExportingWholeCanvas || onlyExportingSingleFrame) {
|
||||
const frames = elements.filter((element) => element.type === "frame");
|
||||
|
||||
const exportedFrameIds = frames.reduce((acc, frame) => {
|
||||
acc[frame.id] = true;
|
||||
return acc;
|
||||
}, {} as Record<string, true>);
|
||||
const exportedFrameIds = frames.reduce(
|
||||
(acc, frame) => {
|
||||
acc[frame.id] = true;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, true>,
|
||||
);
|
||||
|
||||
// elements in a frame do not affect the canvas size if we're not exporting
|
||||
// the whole canvas
|
||||
|
||||
@@ -34,10 +34,13 @@ const { h } = window;
|
||||
export class API {
|
||||
static setSelectedElements = (elements: ExcalidrawElement[]) => {
|
||||
h.setState({
|
||||
selectedElementIds: elements.reduce((acc, element) => {
|
||||
acc[element.id] = true;
|
||||
return acc;
|
||||
}, {} as Record<ExcalidrawElement["id"], true>),
|
||||
selectedElementIds: elements.reduce(
|
||||
(acc, element) => {
|
||||
acc[element.id] = true;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<ExcalidrawElement["id"], true>,
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -88,7 +88,7 @@ export type BinaryFiles = Record<ExcalidrawElement["id"], BinaryFileData>;
|
||||
export type LastActiveTool =
|
||||
| {
|
||||
type:
|
||||
| typeof SHAPES[number]["value"]
|
||||
| (typeof SHAPES)[number]["value"]
|
||||
| "eraser"
|
||||
| "hand"
|
||||
| "frame"
|
||||
@@ -196,7 +196,7 @@ export type AppState = {
|
||||
} & (
|
||||
| {
|
||||
type:
|
||||
| typeof SHAPES[number]["value"]
|
||||
| (typeof SHAPES)[number]["value"]
|
||||
| "eraser"
|
||||
| "hand"
|
||||
| "frame"
|
||||
|
||||
+1
-1
@@ -372,7 +372,7 @@ export const updateActiveTool = (
|
||||
data: (
|
||||
| {
|
||||
type:
|
||||
| typeof SHAPES[number]["value"]
|
||||
| (typeof SHAPES)[number]["value"]
|
||||
| "eraser"
|
||||
| "hand"
|
||||
| "frame"
|
||||
|
||||
+8
-5
@@ -188,11 +188,14 @@ const getTargetElementsMap = <T extends ExcalidrawElement>(
|
||||
elements: readonly T[],
|
||||
indices: number[],
|
||||
) => {
|
||||
return indices.reduce((acc, index) => {
|
||||
const element = elements[index];
|
||||
acc[element.id] = element;
|
||||
return acc;
|
||||
}, {} as Record<string, ExcalidrawElement>);
|
||||
return indices.reduce(
|
||||
(acc, index) => {
|
||||
const element = elements[index];
|
||||
acc[element.id] = element;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, ExcalidrawElement>,
|
||||
);
|
||||
};
|
||||
|
||||
const _shiftElements = (
|
||||
|
||||
Reference in New Issue
Block a user