feat: support adding multiple library items on canvas (#5116)

This commit is contained in:
David Luzar 2022-05-11 15:51:02 +02:00 committed by GitHub
parent cad6097d60
commit d2cc76e52e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 275 additions and 34 deletions

View file

@ -74,7 +74,7 @@ import {
ZOOM_STEP,
} from "../constants";
import { loadFromBlob } from "../data";
import Library from "../data/library";
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
import { restore, restoreElements } from "../data/restore";
import {
dragNewElement,
@ -232,6 +232,7 @@ import {
isSupportedImageFile,
loadSceneOrLibraryFromBlob,
normalizeFile,
parseLibraryJSON,
resizeImageFile,
SVGStringToFile,
} from "../data/blob";
@ -5212,13 +5213,18 @@ class App extends React.Component<AppProps, AppState> {
});
}
const libraryShapes = event.dataTransfer.getData(MIME_TYPES.excalidrawlib);
if (libraryShapes !== "") {
this.addElementsFromPasteOrLibrary({
elements: JSON.parse(libraryShapes),
position: event,
files: null,
});
const libraryJSON = event.dataTransfer.getData(MIME_TYPES.excalidrawlib);
if (libraryJSON && typeof libraryJSON === "string") {
try {
const libraryItems = parseLibraryJSON(libraryJSON);
this.addElementsFromPasteOrLibrary({
elements: distributeLibraryItemsOnSquareGrid(libraryItems),
position: event,
files: null,
});
} catch (error: any) {
this.setState({ errorMessage: error.message });
}
return;
}

View file

@ -27,7 +27,7 @@ import { HelpDialog } from "./HelpDialog";
import Stack from "./Stack";
import { Tooltip } from "./Tooltip";
import { UserList } from "./UserList";
import Library from "../data/library";
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
import { JSONExportDialog } from "./JSONExportDialog";
import { LibraryButton } from "./LibraryButton";
import { isImageFileHandle } from "../data/blob";
@ -277,7 +277,9 @@ const LayerUI = ({
<LibraryMenu
pendingElements={getSelectedElements(elements, appState, true)}
onClose={closeLibrary}
onInsertShape={onInsertElements}
onInsertLibraryItems={(libraryItems) => {
onInsertElements(distributeLibraryItemsOnSquareGrid(libraryItems));
}}
onAddToLibrary={deselectItems}
setAppState={setAppState}
libraryReturnUrl={libraryReturnUrl}

View file

@ -76,7 +76,7 @@ const LibraryMenuWrapper = forwardRef<
export const LibraryMenu = ({
onClose,
onInsertShape,
onInsertLibraryItems,
pendingElements,
onAddToLibrary,
theme,
@ -90,7 +90,7 @@ export const LibraryMenu = ({
}: {
pendingElements: LibraryItem["elements"];
onClose: () => void;
onInsertShape: (elements: LibraryItem["elements"]) => void;
onInsertLibraryItems: (libraryItems: LibraryItems) => void;
onAddToLibrary: () => void;
theme: AppState["theme"];
files: BinaryFiles;
@ -270,7 +270,7 @@ export const LibraryMenu = ({
onAddToLibrary={(elements) =>
addToLibrary(elements, libraryItemsData.libraryItems)
}
onInsertShape={onInsertShape}
onInsertLibraryItems={onInsertLibraryItems}
pendingElements={pendingElements}
setAppState={setAppState}
libraryReturnUrl={libraryReturnUrl}

View file

@ -1,6 +1,6 @@
import { chunk } from "lodash";
import React, { useCallback, useState } from "react";
import { saveLibraryAsJSON } from "../data/json";
import { saveLibraryAsJSON, serializeLibraryAsJSON } from "../data/json";
import Library from "../data/library";
import { ExcalidrawElement, NonDeleted } from "../element/types";
import { t } from "../i18n";
@ -21,7 +21,7 @@ import { ToolButton } from "./ToolButton";
import { Tooltip } from "./Tooltip";
import "./LibraryMenuItems.scss";
import { VERSIONS } from "../constants";
import { MIME_TYPES, VERSIONS } from "../constants";
import Spinner from "./Spinner";
import { fileOpen } from "../data/filesystem";
@ -30,7 +30,7 @@ const LibraryMenuItems = ({
libraryItems,
onRemoveFromLibrary,
onAddToLibrary,
onInsertShape,
onInsertLibraryItems,
pendingElements,
theme,
setAppState,
@ -47,7 +47,7 @@ const LibraryMenuItems = ({
libraryItems: LibraryItems;
pendingElements: LibraryItem["elements"];
onRemoveFromLibrary: () => void;
onInsertShape: (elements: LibraryItem["elements"]) => void;
onInsertLibraryItems: (libraryItems: LibraryItems) => void;
onAddToLibrary: (elements: LibraryItem["elements"]) => void;
theme: AppState["theme"];
files: BinaryFiles;
@ -252,6 +252,18 @@ const LibraryMenuItems = ({
}
};
const getInsertedElements = (id: string) => {
let targetElements;
if (selectedItems.includes(id)) {
targetElements = libraryItems.filter((item) =>
selectedItems.includes(item.id),
);
} else {
targetElements = libraryItems.filter((item) => item.id === id);
}
return targetElements;
};
const createLibraryItemCompo = (params: {
item:
| LibraryItem
@ -273,6 +285,12 @@ const LibraryMenuItems = ({
id={params.item?.id || null}
selected={!!params.item?.id && selectedItems.includes(params.item.id)}
onToggle={onItemSelectToggle}
onDrag={(id, event) => {
event.dataTransfer.setData(
MIME_TYPES.excalidrawlib,
serializeLibraryAsJSON(getInsertedElements(id)),
);
}}
/>
</Stack.Col>
);
@ -291,7 +309,7 @@ const LibraryMenuItems = ({
if (item.id) {
return createLibraryItemCompo({
item,
onClick: () => onInsertShape(item.elements),
onClick: () => onInsertLibraryItems(getInsertedElements(item.id)),
key: item.id,
});
}

View file

@ -1,7 +1,6 @@
import clsx from "clsx";
import oc from "open-color";
import { useEffect, useRef, useState } from "react";
import { MIME_TYPES } from "../constants";
import { useDeviceType } from "../components/App";
import { exportToSvg } from "../scene/export";
import { BinaryFiles, LibraryItem } from "../types";
@ -29,6 +28,7 @@ export const LibraryUnit = ({
onClick,
selected,
onToggle,
onDrag,
}: {
id: LibraryItem["id"] | /** for pending item */ null;
elements?: LibraryItem["elements"];
@ -37,6 +37,7 @@ export const LibraryUnit = ({
onClick: () => void;
selected: boolean;
onToggle: (id: string, event: React.MouseEvent) => void;
onDrag: (id: string, event: React.DragEvent) => void;
}) => {
const ref = useRef<HTMLDivElement | null>(null);
useEffect(() => {
@ -99,11 +100,12 @@ export const LibraryUnit = ({
: undefined
}
onDragStart={(event) => {
if (!id) {
event.preventDefault();
return;
}
setIsHovered(false);
event.dataTransfer.setData(
MIME_TYPES.excalidrawlib,
JSON.stringify(elements),
);
onDrag(id, event);
}}
/>
{adder}