diff --git a/src/appState.ts b/src/appState.ts index 879d0590f..75a359aa5 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -101,90 +101,228 @@ const APP_STATE_STORAGE_CONF = (< Values extends { /** whether to keep when storing to browser storage (localStorage/IDB) */ browser: boolean; - /** whether to keep when exporting to file/database */ - export: boolean; + /** whether to keep when exporting to text file */ + text: boolean; + /** whether to keep when exporting to an image file */ + image: boolean; /** server (shareLink/collab/...) */ server: boolean; }, T extends Record, >(config: { [K in keyof T]: K extends keyof AppState ? T[K] : never }) => config)({ - theme: { browser: true, export: false, server: false }, - collaborators: { browser: false, export: false, server: false }, - currentChartType: { browser: true, export: false, server: false }, - currentItemBackgroundColor: { browser: true, export: false, server: false }, - currentItemEndArrowhead: { browser: true, export: false, server: false }, - currentItemFillStyle: { browser: true, export: false, server: false }, - currentItemFontFamily: { browser: true, export: false, server: false }, - currentItemFontSize: { browser: true, export: false, server: false }, - currentItemLinearStrokeSharpness: { + theme: { browser: true, text: false, image: false, server: false }, + collaborators: { browser: false, text: false, image: false, server: false }, + currentChartType: { browser: true, text: false, image: false, server: false }, + currentItemBackgroundColor: { browser: true, - export: false, + text: false, + image: false, + server: false, + }, + currentItemEndArrowhead: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemFillStyle: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemFontFamily: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemFontSize: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemLinearStrokeSharpness: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemOpacity: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemRoughness: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemStartArrowhead: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemStrokeColor: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemStrokeSharpness: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemStrokeStyle: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemStrokeWidth: { + browser: true, + text: false, + image: false, + server: false, + }, + currentItemTextAlign: { + browser: true, + text: false, + image: false, + server: false, + }, + cursorButton: { browser: true, text: false, image: false, server: false }, + draggingElement: { browser: false, text: false, image: false, server: false }, + editingElement: { browser: false, text: false, image: false, server: false }, + editingGroupId: { browser: true, text: false, image: false, server: false }, + editingLinearElement: { + browser: false, + text: false, + image: false, + server: false, + }, + activeTool: { browser: true, text: false, image: false, server: false }, + penMode: { browser: true, text: false, image: false, server: false }, + penDetected: { browser: true, text: false, image: false, server: false }, + errorMessage: { browser: false, text: false, image: false, server: false }, + exportBackground: { browser: true, text: false, image: true, server: false }, + exportEmbedScene: { browser: true, text: false, image: true, server: false }, + exportScale: { browser: true, text: false, image: true, server: false }, + exportWithDarkMode: { + browser: true, + text: false, + image: true, + server: false, + }, + fileHandle: { browser: false, text: false, image: false, server: false }, + gridSize: { browser: true, text: true, image: true, server: true }, + height: { browser: false, text: false, image: false, server: false }, + isBindingEnabled: { + browser: false, + text: false, + image: false, + server: false, + }, + isLibraryOpen: { browser: true, text: false, image: false, server: false }, + isLibraryMenuDocked: { + browser: true, + text: false, + image: false, + server: false, + }, + isLoading: { browser: false, text: false, image: false, server: false }, + isResizing: { browser: false, text: false, image: false, server: false }, + isRotating: { browser: false, text: false, image: false, server: false }, + lastPointerDownWith: { + browser: true, + text: false, + image: false, + server: false, + }, + multiElement: { browser: false, text: false, image: false, server: false }, + name: { browser: true, text: false, image: false, server: false }, + offsetLeft: { browser: false, text: false, image: false, server: false }, + offsetTop: { browser: false, text: false, image: false, server: false }, + openMenu: { browser: true, text: false, image: false, server: false }, + openPopup: { browser: false, text: false, image: false, server: false }, + pasteDialog: { browser: false, text: false, image: false, server: false }, + previousSelectedElementIds: { + browser: true, + text: false, + image: false, + server: false, + }, + resizingElement: { browser: false, text: false, image: false, server: false }, + scrolledOutside: { browser: true, text: false, image: false, server: false }, + scrollX: { browser: true, text: false, image: false, server: false }, + scrollY: { browser: true, text: false, image: false, server: false }, + selectedElementIds: { + browser: true, + text: false, + image: false, + server: false, + }, + selectedGroupIds: { browser: true, text: false, image: false, server: false }, + selectionElement: { + browser: false, + text: false, + image: false, + server: false, + }, + shouldCacheIgnoreZoom: { + browser: true, + text: false, + image: false, + server: false, + }, + showHelpDialog: { browser: false, text: false, image: false, server: false }, + showStats: { browser: true, text: false, image: false, server: false }, + startBoundElement: { + browser: false, + text: false, + image: false, + server: false, + }, + suggestedBindings: { + browser: false, + text: false, + image: false, + server: false, + }, + toastMessage: { browser: false, text: false, image: false, server: false }, + viewBackgroundColor: { + browser: true, + text: true, + image: true, + server: true, + }, + width: { browser: false, text: false, image: false, server: false }, + zenModeEnabled: { browser: true, text: false, image: false, server: false }, + zoom: { browser: true, text: false, image: false, server: false }, + viewModeEnabled: { browser: false, text: false, image: false, server: false }, + pendingImageElementId: { + browser: false, + text: false, + image: false, + server: false, + }, + showHyperlinkPopup: { + browser: false, + text: false, + image: false, server: false, }, - currentItemOpacity: { browser: true, export: false, server: false }, - currentItemRoughness: { browser: true, export: false, server: false }, - currentItemStartArrowhead: { browser: true, export: false, server: false }, - currentItemStrokeColor: { browser: true, export: false, server: false }, - currentItemStrokeSharpness: { browser: true, export: false, server: false }, - currentItemStrokeStyle: { browser: true, export: false, server: false }, - currentItemStrokeWidth: { browser: true, export: false, server: false }, - currentItemTextAlign: { browser: true, export: false, server: false }, - cursorButton: { browser: true, export: false, server: false }, - draggingElement: { browser: false, export: false, server: false }, - editingElement: { browser: false, export: false, server: false }, - editingGroupId: { browser: true, export: false, server: false }, - editingLinearElement: { browser: false, export: false, server: false }, - activeTool: { browser: true, export: false, server: false }, - penMode: { browser: true, export: false, server: false }, - penDetected: { browser: true, export: false, server: false }, - errorMessage: { browser: false, export: false, server: false }, - exportBackground: { browser: true, export: false, server: false }, - exportEmbedScene: { browser: true, export: false, server: false }, - exportScale: { browser: true, export: false, server: false }, - exportWithDarkMode: { browser: true, export: false, server: false }, - fileHandle: { browser: false, export: false, server: false }, - gridSize: { browser: true, export: true, server: true }, - height: { browser: false, export: false, server: false }, - isBindingEnabled: { browser: false, export: false, server: false }, - isLibraryOpen: { browser: true, export: false, server: false }, - isLibraryMenuDocked: { browser: true, export: false, server: false }, - isLoading: { browser: false, export: false, server: false }, - isResizing: { browser: false, export: false, server: false }, - isRotating: { browser: false, export: false, server: false }, - lastPointerDownWith: { browser: true, export: false, server: false }, - multiElement: { browser: false, export: false, server: false }, - name: { browser: true, export: false, server: false }, - offsetLeft: { browser: false, export: false, server: false }, - offsetTop: { browser: false, export: false, server: false }, - openMenu: { browser: true, export: false, server: false }, - openPopup: { browser: false, export: false, server: false }, - pasteDialog: { browser: false, export: false, server: false }, - previousSelectedElementIds: { browser: true, export: false, server: false }, - resizingElement: { browser: false, export: false, server: false }, - scrolledOutside: { browser: true, export: false, server: false }, - scrollX: { browser: true, export: false, server: false }, - scrollY: { browser: true, export: false, server: false }, - selectedElementIds: { browser: true, export: false, server: false }, - selectedGroupIds: { browser: true, export: false, server: false }, - selectionElement: { browser: false, export: false, server: false }, - shouldCacheIgnoreZoom: { browser: true, export: false, server: false }, - showHelpDialog: { browser: false, export: false, server: false }, - showStats: { browser: true, export: false, server: false }, - startBoundElement: { browser: false, export: false, server: false }, - suggestedBindings: { browser: false, export: false, server: false }, - toastMessage: { browser: false, export: false, server: false }, - viewBackgroundColor: { browser: true, export: true, server: true }, - width: { browser: false, export: false, server: false }, - zenModeEnabled: { browser: true, export: false, server: false }, - zoom: { browser: true, export: false, server: false }, - viewModeEnabled: { browser: false, export: false, server: false }, - pendingImageElementId: { browser: false, export: false, server: false }, - showHyperlinkPopup: { browser: false, export: false, server: false }, }); const _clearAppStateForStorage = < - ExportType extends "export" | "browser" | "server", + ExportType extends "image" | "text" | "browser" | "server", >( appState: Partial, exportType: ExportType, @@ -211,8 +349,12 @@ export const clearAppStateForLocalStorage = (appState: Partial) => { return _clearAppStateForStorage(appState, "browser"); }; -export const cleanAppStateForExport = (appState: Partial) => { - return _clearAppStateForStorage(appState, "export"); +export const cleanAppStateForTextExport = (appState: Partial) => { + return _clearAppStateForStorage(appState, "text"); +}; + +export const cleanAppStateForImageExport = (appState: Partial) => { + return _clearAppStateForStorage(appState, "image"); }; export const clearAppStateForDatabase = (appState: Partial) => { diff --git a/src/data/blob.ts b/src/data/blob.ts index ceecd9345..19336cac6 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -1,5 +1,5 @@ import { nanoid } from "nanoid"; -import { cleanAppStateForExport } from "../appState"; +import { cleanAppStateForTextExport } from "../appState"; import { ALLOWED_IMAGE_MIME_TYPES, MIME_TYPES } from "../constants"; import { clearElementsForExport } from "../element"; import { ExcalidrawElement, FileId } from "../element/types"; @@ -143,7 +143,7 @@ export const loadSceneOrLibraryFromBlob = async ( appState: { theme: localAppState?.theme, fileHandle: fileHandle || blob.handle || null, - ...cleanAppStateForExport(data.appState || {}), + ...cleanAppStateForTextExport(data.appState || {}), ...(localAppState ? calculateScrollCenter( data.elements || [], diff --git a/src/data/index.ts b/src/data/index.ts index 8ea90adf6..f7e91af5b 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -82,7 +82,7 @@ export const exportCanvas = async ( await import(/* webpackChunkName: "image" */ "./image") ).encodePngMetadata({ blob, - metadata: serializeAsJSON(elements, appState, files, "local"), + metadata: serializeAsJSON(elements, appState, files, "image"), }); } diff --git a/src/data/json.ts b/src/data/json.ts index 958cbe239..f930f7282 100644 --- a/src/data/json.ts +++ b/src/data/json.ts @@ -1,5 +1,9 @@ import { fileOpen, fileSave } from "./filesystem"; -import { cleanAppStateForExport, clearAppStateForDatabase } from "../appState"; +import { + cleanAppStateForImageExport, + cleanAppStateForTextExport, + clearAppStateForDatabase, +} from "../appState"; import { EXPORT_DATA_TYPES, EXPORT_SOURCE, @@ -43,25 +47,32 @@ export const serializeAsJSON = ( elements: readonly ExcalidrawElement[], appState: Partial, files: BinaryFiles, - type: "local" | "database", + destination: "text" | "image" | "database", ): string => { + const cleanAppState = () => { + switch (destination) { + case "database": + return clearAppStateForDatabase(appState); + case "text": + return cleanAppStateForTextExport(appState); + case "image": + return cleanAppStateForImageExport(appState); + } + }; const data: ExportedDataState = { type: EXPORT_DATA_TYPES.excalidraw, version: VERSIONS.excalidraw, source: EXPORT_SOURCE, elements: - type === "local" - ? clearElementsForExport(elements) - : clearElementsForDatabase(elements), - appState: - type === "local" - ? cleanAppStateForExport(appState) - : clearAppStateForDatabase(appState), + destination === "database" + ? clearElementsForDatabase(elements) + : clearElementsForExport(elements), + appState: cleanAppState(), files: - type === "local" - ? filterOutDeletedFiles(elements, files) - : // will be stripped from JSON - undefined, + destination === "database" + ? // will be stripped from JSON + undefined + : filterOutDeletedFiles(elements, files), }; return JSON.stringify(data, null, 2); @@ -72,7 +83,7 @@ export const saveAsJSON = async ( appState: AppState, files: BinaryFiles, ) => { - const serialized = serializeAsJSON(elements, appState, files, "local"); + const serialized = serializeAsJSON(elements, appState, files, "text"); const blob = new Blob([serialized], { type: MIME_TYPES.excalidraw, }); diff --git a/src/data/types.ts b/src/data/types.ts index 413e81836..059c9b5eb 100644 --- a/src/data/types.ts +++ b/src/data/types.ts @@ -5,7 +5,7 @@ import { LibraryItems, LibraryItems_anyVersion, } from "../types"; -import type { cleanAppStateForExport } from "../appState"; +import type { cleanAppStateForTextExport } from "../appState"; import { VERSIONS } from "../constants"; export interface ExportedDataState { @@ -13,7 +13,7 @@ export interface ExportedDataState { version: number; source: string; elements: readonly ExcalidrawElement[]; - appState: ReturnType; + appState: ReturnType; files: BinaryFiles | undefined; } diff --git a/src/packages/utils.ts b/src/packages/utils.ts index 4d9a8af17..b2de18a11 100644 --- a/src/packages/utils.ts +++ b/src/packages/utils.ts @@ -131,7 +131,7 @@ export const exportToBlob = async ( opts.elements, opts.appState, opts.files || {}, - "local", + "image", ), }); } diff --git a/src/scene/export.ts b/src/scene/export.ts index 9dacc755b..0424614f5 100644 --- a/src/scene/export.ts +++ b/src/scene/export.ts @@ -96,7 +96,7 @@ export const exportToSvg = async ( metadata = await ( await import(/* webpackChunkName: "image" */ "../../src/data/image") ).encodeSvgMetadata({ - text: serializeAsJSON(elements, appState, files || {}, "local"), + text: serializeAsJSON(elements, appState, files || {}, "image"), }); } catch (error: any) { console.error(error);