mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Import and export library from/to a file (#1940)
Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
7eff6893c5
commit
ee8fa6aaad
11 changed files with 199 additions and 39 deletions
|
@ -2,17 +2,11 @@ import { getDefaultAppState, cleanAppStateForExport } from "../appState";
|
|||
import { restore } from "./restore";
|
||||
import { t } from "../i18n";
|
||||
import { AppState } from "../types";
|
||||
import { LibraryData } from "./types";
|
||||
import { calculateScrollCenter } from "../scene";
|
||||
|
||||
/**
|
||||
* @param blob
|
||||
* @param appState if provided, used for centering scroll to restored scene
|
||||
*/
|
||||
export const loadFromBlob = async (blob: any, appState?: AppState) => {
|
||||
if (blob.handle) {
|
||||
(window as any).handle = blob.handle;
|
||||
}
|
||||
let contents;
|
||||
const loadFileContents = async (blob: any) => {
|
||||
let contents: string;
|
||||
if ("text" in Blob) {
|
||||
contents = await blob.text();
|
||||
} else {
|
||||
|
@ -26,7 +20,19 @@ export const loadFromBlob = async (blob: any, appState?: AppState) => {
|
|||
};
|
||||
});
|
||||
}
|
||||
return contents;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param blob
|
||||
* @param appState if provided, used for centering scroll to restored scene
|
||||
*/
|
||||
export const loadFromBlob = async (blob: any, appState?: AppState) => {
|
||||
if (blob.handle) {
|
||||
(window as any).handle = blob.handle;
|
||||
}
|
||||
|
||||
const contents = await loadFileContents(blob);
|
||||
const defaultAppState = getDefaultAppState();
|
||||
let elements = [];
|
||||
let _appState = appState || defaultAppState;
|
||||
|
@ -47,3 +53,12 @@ export const loadFromBlob = async (blob: any, appState?: AppState) => {
|
|||
|
||||
return restore(elements, _appState);
|
||||
};
|
||||
|
||||
export const loadLibraryFromBlob = async (blob: any) => {
|
||||
const contents = await loadFileContents(blob);
|
||||
const data: LibraryData = JSON.parse(contents);
|
||||
if (data.type !== "excalidrawlib") {
|
||||
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,8 @@ import { cleanAppStateForExport } from "../appState";
|
|||
|
||||
import { fileOpen, fileSave } from "browser-nativefs";
|
||||
import { loadFromBlob } from "./blob";
|
||||
import { loadLibrary } from "./localStorage";
|
||||
import { Library } from "./library";
|
||||
|
||||
export const serializeAsJSON = (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
|
@ -50,3 +52,34 @@ export const loadFromJSON = async (appState: AppState) => {
|
|||
});
|
||||
return loadFromBlob(blob, appState);
|
||||
};
|
||||
|
||||
export const saveLibraryAsJSON = async () => {
|
||||
const library = await loadLibrary();
|
||||
const serialized = JSON.stringify(
|
||||
{
|
||||
type: "excalidrawlib",
|
||||
version: 1,
|
||||
library,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
const fileName = `library.excalidrawlib`;
|
||||
const blob = new Blob([serialized], {
|
||||
type: "application/vnd.excalidrawlib+json",
|
||||
});
|
||||
await fileSave(blob, {
|
||||
fileName,
|
||||
description: "Excalidraw library file",
|
||||
extensions: ["excalidrawlib"],
|
||||
});
|
||||
};
|
||||
|
||||
export const importLibraryFromJSON = async () => {
|
||||
const blob = await fileOpen({
|
||||
description: "Excalidraw library files",
|
||||
extensions: ["json", "excalidrawlib"],
|
||||
mimeTypes: ["application/json"],
|
||||
});
|
||||
Library.importLibrary(blob);
|
||||
};
|
||||
|
|
43
src/data/library.ts
Normal file
43
src/data/library.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { loadLibraryFromBlob } from "./blob";
|
||||
import { LibraryItems, LibraryItem } from "../types";
|
||||
import { loadLibrary, saveLibrary } from "./localStorage";
|
||||
|
||||
export class Library {
|
||||
/** imports library (currently merges, removing duplicates) */
|
||||
static async importLibrary(blob: any) {
|
||||
const libraryFile = await loadLibraryFromBlob(blob);
|
||||
if (!libraryFile || !libraryFile.library) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if library item does not exist already in current library
|
||||
*/
|
||||
const isUniqueitem = (
|
||||
existingLibraryItems: LibraryItems,
|
||||
targetLibraryItem: LibraryItem,
|
||||
) => {
|
||||
return !existingLibraryItems.find((libraryItem) => {
|
||||
if (libraryItem.length !== targetLibraryItem.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// detect z-index difference by checking the excalidraw elements
|
||||
// are in order
|
||||
return libraryItem.every((libItemExcalidrawItem, idx) => {
|
||||
return (
|
||||
libItemExcalidrawItem.id === targetLibraryItem[idx].id &&
|
||||
libItemExcalidrawItem.versionNonce ===
|
||||
targetLibraryItem[idx].versionNonce
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const existingLibraryItems = await loadLibrary();
|
||||
const filtered = libraryFile.library!.filter((libraryItem) =>
|
||||
isUniqueitem(existingLibraryItems, libraryItem),
|
||||
);
|
||||
saveLibrary([...existingLibraryItems, ...filtered]);
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ export const loadLibrary = (): Promise<LibraryItems> => {
|
|||
return resolve([]);
|
||||
}
|
||||
|
||||
const items = (JSON.parse(data) as ExcalidrawElement[][]).map(
|
||||
const items = (JSON.parse(data) as LibraryItems).map(
|
||||
(elements) => restore(elements, null).elements,
|
||||
) as Mutable<LibraryItems>;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
import { AppState, LibraryItems } from "../types";
|
||||
|
||||
export interface DataState {
|
||||
type?: string;
|
||||
|
@ -8,3 +8,10 @@ export interface DataState {
|
|||
elements: readonly ExcalidrawElement[];
|
||||
appState: MarkOptional<AppState, "offsetTop" | "offsetLeft"> | null;
|
||||
}
|
||||
|
||||
export interface LibraryData {
|
||||
type?: string;
|
||||
version?: number;
|
||||
source?: string;
|
||||
library?: LibraryItems;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue