mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
remove convertToExcalidrawElements call from restore
This commit is contained in:
parent
2ff0528a4f
commit
d3361f910b
8 changed files with 128 additions and 151 deletions
|
@ -13,7 +13,6 @@ import { FileSystemHandle, nativeFileSystemSupported } from "./filesystem";
|
||||||
import { isValidExcalidrawData, isValidLibrary } from "./json";
|
import { isValidExcalidrawData, isValidLibrary } from "./json";
|
||||||
import { restore, restoreLibraryItems } from "./restore";
|
import { restore, restoreLibraryItems } from "./restore";
|
||||||
import { ImportedLibraryData } from "./types";
|
import { ImportedLibraryData } from "./types";
|
||||||
import { convertToExcalidrawElements } from "../data/transform";
|
|
||||||
|
|
||||||
const parseFileContents = async (blob: Blob | File) => {
|
const parseFileContents = async (blob: Blob | File) => {
|
||||||
let contents: string;
|
let contents: string;
|
||||||
|
@ -135,9 +134,7 @@ export const loadSceneOrLibraryFromBlob = async (
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(contents);
|
const data = JSON.parse(contents);
|
||||||
if (isValidExcalidrawData(data)) {
|
if (isValidExcalidrawData(data)) {
|
||||||
const excaldrawElements = convertToExcalidrawElements(
|
const excaldrawElements = data.elements || [];
|
||||||
data.elements || [],
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
type: MIME_TYPES.excalidraw,
|
type: MIME_TYPES.excalidraw,
|
||||||
data: restore(
|
data: restore(
|
||||||
|
|
|
@ -41,10 +41,7 @@ import {
|
||||||
getDefaultLineHeight,
|
getDefaultLineHeight,
|
||||||
measureBaseline,
|
measureBaseline,
|
||||||
} from "../element/textElement";
|
} from "../element/textElement";
|
||||||
import {
|
|
||||||
ExcalidrawProgrammaticAPI,
|
|
||||||
convertToExcalidrawElements,
|
|
||||||
} from "../data/transform";
|
|
||||||
import { normalizeLink } from "./url";
|
import { normalizeLink } from "./url";
|
||||||
|
|
||||||
type RestoredAppState = Omit<
|
type RestoredAppState = Omit<
|
||||||
|
@ -394,44 +391,37 @@ const repairFrameMembership = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const restoreElements = (
|
export const restoreElements = (
|
||||||
elements: ExcalidrawProgrammaticAPI["elements"],
|
elements: ImportedDataState["elements"],
|
||||||
/** NOTE doesn't serve for reconciliation */
|
/** NOTE doesn't serve for reconciliation */
|
||||||
localElements: readonly ExcalidrawElement[] | null | undefined,
|
localElements: readonly ExcalidrawElement[] | null | undefined,
|
||||||
opts?: { refreshDimensions?: boolean; repairBindings?: boolean } | undefined,
|
opts?: { refreshDimensions?: boolean; repairBindings?: boolean } | undefined,
|
||||||
): ExcalidrawElement[] => {
|
): ExcalidrawElement[] => {
|
||||||
// used to detect duplicate top-level element ids
|
// used to detect duplicate top-level element ids
|
||||||
const existingIds = new Set<string>();
|
const existingIds = new Set<string>();
|
||||||
const excalidrawElements = convertToExcalidrawElements(elements);
|
|
||||||
const localElementsMap = localElements ? arrayToMap(localElements) : null;
|
const localElementsMap = localElements ? arrayToMap(localElements) : null;
|
||||||
const restoredElements = (excalidrawElements || []).reduce(
|
const restoredElements = (elements || []).reduce((elements, element) => {
|
||||||
(elements, element) => {
|
// filtering out selection, which is legacy, no longer kept in elements,
|
||||||
// filtering out selection, which is legacy, no longer kept in elements,
|
// and causing issues if retained
|
||||||
// and causing issues if retained
|
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
|
||||||
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
|
let migratedElement: ExcalidrawElement | null = restoreElement(
|
||||||
let migratedElement: ExcalidrawElement | null = restoreElement(
|
element,
|
||||||
element,
|
opts?.refreshDimensions,
|
||||||
opts?.refreshDimensions,
|
);
|
||||||
);
|
if (migratedElement) {
|
||||||
if (migratedElement) {
|
const localElement = localElementsMap?.get(element.id);
|
||||||
const localElement = localElementsMap?.get(element.id);
|
if (localElement && localElement.version > migratedElement.version) {
|
||||||
if (localElement && localElement.version > migratedElement.version) {
|
migratedElement = bumpVersion(migratedElement, localElement.version);
|
||||||
migratedElement = bumpVersion(
|
|
||||||
migratedElement,
|
|
||||||
localElement.version,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (existingIds.has(migratedElement.id)) {
|
|
||||||
migratedElement = { ...migratedElement, id: randomId() };
|
|
||||||
}
|
|
||||||
existingIds.add(migratedElement.id);
|
|
||||||
|
|
||||||
elements.push(migratedElement);
|
|
||||||
}
|
}
|
||||||
|
if (existingIds.has(migratedElement.id)) {
|
||||||
|
migratedElement = { ...migratedElement, id: randomId() };
|
||||||
|
}
|
||||||
|
existingIds.add(migratedElement.id);
|
||||||
|
|
||||||
|
elements.push(migratedElement);
|
||||||
}
|
}
|
||||||
return elements;
|
}
|
||||||
},
|
return elements;
|
||||||
[] as ExcalidrawElement[],
|
}, [] as ExcalidrawElement[]);
|
||||||
);
|
|
||||||
|
|
||||||
if (!opts?.repairBindings) {
|
if (!opts?.repairBindings) {
|
||||||
return restoredElements;
|
return restoredElements;
|
||||||
|
|
|
@ -24,16 +24,109 @@ import {
|
||||||
import {
|
import {
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
|
ExcalidrawFrameElement,
|
||||||
ExcalidrawFreeDrawElement,
|
ExcalidrawFreeDrawElement,
|
||||||
ExcalidrawGenericElement,
|
ExcalidrawGenericElement,
|
||||||
ExcalidrawImageElement,
|
ExcalidrawImageElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
ExcalidrawSelectionElement,
|
ExcalidrawSelectionElement,
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
|
FontFamilyValues,
|
||||||
|
TextAlign,
|
||||||
|
VerticalAlign,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { MarkOptional } from "../utility-types";
|
import { MarkOptional } from "../utility-types";
|
||||||
import { getFontString } from "../utils";
|
import { getFontString } from "../utils";
|
||||||
import { ValidContainer, ValidLinearElement } from "./types";
|
|
||||||
|
export type ValidLinearElement = {
|
||||||
|
type: "arrow" | "line";
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
label?: {
|
||||||
|
text: string;
|
||||||
|
fontSize?: number;
|
||||||
|
fontFamily?: FontFamilyValues;
|
||||||
|
textAlign?: TextAlign;
|
||||||
|
verticalAlign?: VerticalAlign;
|
||||||
|
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||||
|
end?:
|
||||||
|
| (
|
||||||
|
| (
|
||||||
|
| {
|
||||||
|
type: Exclude<
|
||||||
|
ExcalidrawBindableElement["type"],
|
||||||
|
"image" | "selection" | "text" | "frame"
|
||||||
|
>;
|
||||||
|
id?: ExcalidrawGenericElement["id"];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: ExcalidrawGenericElement["id"];
|
||||||
|
type?: Exclude<
|
||||||
|
ExcalidrawBindableElement["type"],
|
||||||
|
"image" | "selection" | "text" | "frame"
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| ((
|
||||||
|
| {
|
||||||
|
type: "text";
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type?: "text";
|
||||||
|
id: ExcalidrawTextElement["id"];
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
) &
|
||||||
|
Partial<ExcalidrawTextElement>)
|
||||||
|
) &
|
||||||
|
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
||||||
|
start?:
|
||||||
|
| (
|
||||||
|
| (
|
||||||
|
| {
|
||||||
|
type: Exclude<
|
||||||
|
ExcalidrawBindableElement["type"],
|
||||||
|
"image" | "selection" | "text" | "frame"
|
||||||
|
>;
|
||||||
|
id?: ExcalidrawGenericElement["id"];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: ExcalidrawGenericElement["id"];
|
||||||
|
type?: Exclude<
|
||||||
|
ExcalidrawBindableElement["type"],
|
||||||
|
"image" | "selection" | "text" | "frame"
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
| ((
|
||||||
|
| {
|
||||||
|
type: "text";
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type?: "text";
|
||||||
|
id: ExcalidrawTextElement["id"];
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
) &
|
||||||
|
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 interface ExcalidrawProgrammaticAPI {
|
export interface ExcalidrawProgrammaticAPI {
|
||||||
elements?:
|
elements?:
|
||||||
|
@ -168,7 +261,7 @@ const bindLinearElementToElement = (
|
||||||
.get()
|
.get()
|
||||||
.find((ele) => ele?.id === start.id) as Exclude<
|
.find((ele) => ele?.id === start.id) as Exclude<
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawImageElement
|
ExcalidrawImageElement | ExcalidrawFrameElement
|
||||||
>;
|
>;
|
||||||
if (!existingElement) {
|
if (!existingElement) {
|
||||||
console.error(`No element for start binding with id ${start.id} found`);
|
console.error(`No element for start binding with id ${start.id} found`);
|
||||||
|
@ -235,7 +328,7 @@ const bindLinearElementToElement = (
|
||||||
.get()
|
.get()
|
||||||
.find((ele) => ele?.id === end.id) as Exclude<
|
.find((ele) => ele?.id === end.id) as Exclude<
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawImageElement
|
ExcalidrawImageElement | ExcalidrawFrameElement
|
||||||
>;
|
>;
|
||||||
if (!existingElement) {
|
if (!existingElement) {
|
||||||
console.error(`No element for end binding with id ${end.id} found`);
|
console.error(`No element for end binding with id ${end.id} found`);
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
import {
|
import { ExcalidrawElement } from "../element/types";
|
||||||
ExcalidrawBindableElement,
|
|
||||||
ExcalidrawElement,
|
|
||||||
ExcalidrawGenericElement,
|
|
||||||
ExcalidrawLinearElement,
|
|
||||||
ExcalidrawTextElement,
|
|
||||||
FontFamilyValues,
|
|
||||||
TextAlign,
|
|
||||||
VerticalAlign,
|
|
||||||
} from "../element/types";
|
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
BinaryFiles,
|
BinaryFiles,
|
||||||
|
@ -16,8 +7,6 @@ import {
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import type { cleanAppStateForExport } from "../appState";
|
import type { cleanAppStateForExport } from "../appState";
|
||||||
import { VERSIONS } from "../constants";
|
import { VERSIONS } from "../constants";
|
||||||
import { MarkOptional } from "../utility-types";
|
|
||||||
import { ElementConstructorOpts } from "../element/newElement";
|
|
||||||
|
|
||||||
export interface ExportedDataState {
|
export interface ExportedDataState {
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -40,96 +29,6 @@ export type LegacyAppState = {
|
||||||
isSidebarDocked: [boolean, "defaultSidebarDockedPreference"];
|
isSidebarDocked: [boolean, "defaultSidebarDockedPreference"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ValidLinearElement = {
|
|
||||||
type: "arrow" | "line";
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
label?: {
|
|
||||||
text: string;
|
|
||||||
fontSize?: number;
|
|
||||||
fontFamily?: FontFamilyValues;
|
|
||||||
textAlign?: TextAlign;
|
|
||||||
verticalAlign?: VerticalAlign;
|
|
||||||
} & MarkOptional<ElementConstructorOpts, "x" | "y">;
|
|
||||||
end?:
|
|
||||||
| (
|
|
||||||
| (
|
|
||||||
| {
|
|
||||||
type: Exclude<
|
|
||||||
ExcalidrawBindableElement["type"],
|
|
||||||
"image" | "selection" | "text"
|
|
||||||
>;
|
|
||||||
id?: ExcalidrawGenericElement["id"];
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
id: ExcalidrawGenericElement["id"];
|
|
||||||
type?: Exclude<
|
|
||||||
ExcalidrawBindableElement["type"],
|
|
||||||
"image" | "selection" | "text"
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
| ((
|
|
||||||
| {
|
|
||||||
type: "text";
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type?: "text";
|
|
||||||
id: ExcalidrawTextElement["id"];
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
) &
|
|
||||||
Partial<ExcalidrawTextElement>)
|
|
||||||
) &
|
|
||||||
MarkOptional<ElementConstructorOpts, "x" | "y">;
|
|
||||||
start?:
|
|
||||||
| (
|
|
||||||
| (
|
|
||||||
| {
|
|
||||||
type: Exclude<
|
|
||||||
ExcalidrawBindableElement["type"],
|
|
||||||
"image" | "selection" | "text"
|
|
||||||
>;
|
|
||||||
id?: ExcalidrawGenericElement["id"];
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
id: ExcalidrawGenericElement["id"];
|
|
||||||
type?: Exclude<
|
|
||||||
ExcalidrawBindableElement["type"],
|
|
||||||
"image" | "selection" | "text"
|
|
||||||
>;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
| ((
|
|
||||||
| {
|
|
||||||
type: "text";
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type?: "text";
|
|
||||||
id: ExcalidrawTextElement["id"];
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
) &
|
|
||||||
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 interface ImportedDataState {
|
export interface ImportedDataState {
|
||||||
type?: string;
|
type?: string;
|
||||||
version?: number;
|
version?: number;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
import { serializeAsJSON } from "../../data/json";
|
import { serializeAsJSON } from "../../data/json";
|
||||||
import { restore } from "../../data/restore";
|
import { restore } from "../../data/restore";
|
||||||
import { ImportedDataState } from "../../data/types";
|
import { ImportedDataState } from "../../data/types";
|
||||||
import { convertToExcalidrawElements } from "../../data/transform";
|
|
||||||
import { isInvisiblySmallElement } from "../../element/sizeHelpers";
|
import { isInvisiblySmallElement } from "../../element/sizeHelpers";
|
||||||
import { isInitializedImageElement } from "../../element/typeChecks";
|
import { isInitializedImageElement } from "../../element/typeChecks";
|
||||||
import { ExcalidrawElement, FileId } from "../../element/types";
|
import { ExcalidrawElement, FileId } from "../../element/types";
|
||||||
|
|
|
@ -91,7 +91,6 @@ import { appJotaiStore } from "./app-jotai";
|
||||||
|
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
import { ResolutionType } from "../utility-types";
|
import { ResolutionType } from "../utility-types";
|
||||||
import { convertToExcalidrawElements } from "../data/transform";
|
|
||||||
import { ShareableLinkDialog } from "../components/ShareableLinkDialog";
|
import { ShareableLinkDialog } from "../components/ShareableLinkDialog";
|
||||||
import { openConfirmModal } from "../components/OverwriteConfirm/OverwriteConfirmState";
|
import { openConfirmModal } from "../components/OverwriteConfirm/OverwriteConfirmState";
|
||||||
import { OverwriteConfirmDialog } from "../components/OverwriteConfirm/OverwriteConfirm";
|
import { OverwriteConfirmDialog } from "../components/OverwriteConfirm/OverwriteConfirm";
|
||||||
|
@ -229,7 +228,7 @@ const initializeScene = async (opts: {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
},
|
},
|
||||||
elements: reconcileElements(
|
elements: reconcileElements(
|
||||||
convertToExcalidrawElements(scene?.elements || []),
|
scene?.elements || [],
|
||||||
excalidrawAPI.getSceneElementsIncludingDeleted(),
|
excalidrawAPI.getSceneElementsIncludingDeleted(),
|
||||||
excalidrawAPI.getAppState(),
|
excalidrawAPI.getAppState(),
|
||||||
),
|
),
|
||||||
|
@ -310,7 +309,7 @@ const ExcalidrawWrapper = () => {
|
||||||
if (data.scene.elements) {
|
if (data.scene.elements) {
|
||||||
collabAPI
|
collabAPI
|
||||||
.fetchImageFilesFromFirebase({
|
.fetchImageFilesFromFirebase({
|
||||||
elements: convertToExcalidrawElements(data.scene.elements),
|
elements: data.scene.elements,
|
||||||
forceFetchFiles: true,
|
forceFetchFiles: true,
|
||||||
})
|
})
|
||||||
.then(({ loadedFiles, erroredFiles }) => {
|
.then(({ loadedFiles, erroredFiles }) => {
|
||||||
|
@ -323,7 +322,7 @@ const ExcalidrawWrapper = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const sceneElements = convertToExcalidrawElements(data.scene.elements);
|
const sceneElements = data.scene.elements;
|
||||||
const fileIds =
|
const fileIds =
|
||||||
sceneElements?.reduce((acc, element) => {
|
sceneElements?.reduce((acc, element) => {
|
||||||
if (isInitializedImageElement(element)) {
|
if (isInitializedImageElement(element)) {
|
||||||
|
|
|
@ -189,7 +189,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
||||||
const updateScene = () => {
|
const updateScene = () => {
|
||||||
const sceneData = {
|
const sceneData = {
|
||||||
elements: restoreElements(
|
elements: restoreElements(
|
||||||
[
|
convertToExcalidrawElements([
|
||||||
{
|
{
|
||||||
type: "rectangle",
|
type: "rectangle",
|
||||||
id: "rect-1",
|
id: "rect-1",
|
||||||
|
@ -222,7 +222,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
|
||||||
y: 100,
|
y: 100,
|
||||||
text: "HELLO WORLD!",
|
text: "HELLO WORLD!",
|
||||||
},
|
},
|
||||||
],
|
]),
|
||||||
null,
|
null,
|
||||||
),
|
),
|
||||||
appState: {
|
appState: {
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe("embedding scene data", () => {
|
||||||
const importedData: ImportedDataState = JSON.parse(parsedString);
|
const importedData: ImportedDataState = JSON.parse(parsedString);
|
||||||
|
|
||||||
expect(sourceElements.map((x) => x.id)).toEqual(
|
expect(sourceElements.map((x) => x.id)).toEqual(
|
||||||
convertToExcalidrawElements(importedData.elements)?.map((el) => el.id),
|
importedData.elements?.map((el) => el.id),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -61,7 +61,7 @@ describe("embedding scene data", () => {
|
||||||
const importedData: ImportedDataState = JSON.parse(parsedString);
|
const importedData: ImportedDataState = JSON.parse(parsedString);
|
||||||
|
|
||||||
expect(sourceElements.map((x) => x.id)).toEqual(
|
expect(sourceElements.map((x) => x.id)).toEqual(
|
||||||
convertToExcalidrawElements(importedData.elements)?.map((el) => el.id),
|
importedData.elements?.map((el) => el.id),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue