mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
fix single text element, unique id and tests
This commit is contained in:
parent
6c41e507db
commit
1c291f8b3d
4 changed files with 60 additions and 23 deletions
|
@ -135,23 +135,20 @@ 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(
|
||||||
|
data.elements || [],
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
type: MIME_TYPES.excalidraw,
|
type: MIME_TYPES.excalidraw,
|
||||||
data: restore(
|
data: restore(
|
||||||
{
|
{
|
||||||
elements: clearElementsForExport(
|
elements: clearElementsForExport(excaldrawElements),
|
||||||
convertToExcalidrawElements(data.elements || []),
|
|
||||||
),
|
|
||||||
appState: {
|
appState: {
|
||||||
theme: localAppState?.theme,
|
theme: localAppState?.theme,
|
||||||
fileHandle: fileHandle || blob.handle || null,
|
fileHandle: fileHandle || blob.handle || null,
|
||||||
...cleanAppStateForExport(data.appState || {}),
|
...cleanAppStateForExport(data.appState || {}),
|
||||||
...(localAppState
|
...(localAppState
|
||||||
? calculateScrollCenter(
|
? calculateScrollCenter(excaldrawElements, localAppState, null)
|
||||||
convertToExcalidrawElements(data.elements || []),
|
|
||||||
localAppState,
|
|
||||||
null,
|
|
||||||
)
|
|
||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
files: data.files,
|
files: data.files,
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { TEXT_ALIGN, VERTICAL_ALIGN } from "../constants";
|
import {
|
||||||
|
DEFAULT_FONT_FAMILY,
|
||||||
|
DEFAULT_FONT_SIZE,
|
||||||
|
TEXT_ALIGN,
|
||||||
|
VERTICAL_ALIGN,
|
||||||
|
} from "../constants";
|
||||||
import {
|
import {
|
||||||
newElement,
|
newElement,
|
||||||
newLinearElement,
|
newLinearElement,
|
||||||
|
@ -6,8 +11,17 @@ import {
|
||||||
} from "../element";
|
} from "../element";
|
||||||
import { bindLinearElement } from "../element/binding";
|
import { bindLinearElement } from "../element/binding";
|
||||||
import { mutateElement } from "../element/mutateElement";
|
import { mutateElement } from "../element/mutateElement";
|
||||||
import { ElementConstructorOpts, newTextElement } from "../element/newElement";
|
import {
|
||||||
import { VALID_CONTAINER_TYPES } from "../element/textElement";
|
ElementConstructorOpts,
|
||||||
|
newTextElement,
|
||||||
|
regenerateId,
|
||||||
|
} from "../element/newElement";
|
||||||
|
import {
|
||||||
|
VALID_CONTAINER_TYPES,
|
||||||
|
getDefaultLineHeight,
|
||||||
|
measureText,
|
||||||
|
normalizeText,
|
||||||
|
} from "../element/textElement";
|
||||||
import {
|
import {
|
||||||
ExcalidrawBindableElement,
|
ExcalidrawBindableElement,
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
|
@ -18,8 +32,8 @@ import {
|
||||||
TextAlign,
|
TextAlign,
|
||||||
VerticalAlign,
|
VerticalAlign,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { randomId } from "../random";
|
|
||||||
import { MarkOptional } from "../utility-types";
|
import { MarkOptional } from "../utility-types";
|
||||||
|
import { getFontString } from "../utils";
|
||||||
import { ImportedDataState } from "./types";
|
import { ImportedDataState } from "./types";
|
||||||
|
|
||||||
export const ELEMENTS_SUPPORTING_PROGRAMMATIC_API = [
|
export const ELEMENTS_SUPPORTING_PROGRAMMATIC_API = [
|
||||||
|
@ -212,14 +226,20 @@ const excalidrawElements = (() => {
|
||||||
};
|
};
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
res.length = 0;
|
res.length = 0;
|
||||||
|
elementMap.clear();
|
||||||
};
|
};
|
||||||
const get = () => {
|
const get = () => {
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
const hasElementWithId = (id: string) => {
|
||||||
|
const index = elementMap.get(id);
|
||||||
|
return index !== undefined && index >= 0;
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
push,
|
push,
|
||||||
clear,
|
clear,
|
||||||
get,
|
get,
|
||||||
|
hasElementWithId,
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -234,6 +254,15 @@ export const convertToExcalidrawElements = (
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let elementId = element.id || regenerateId(null);
|
||||||
|
|
||||||
|
// To make sure every element has a unique id
|
||||||
|
while (excalidrawElements.hasElementWithId(elementId)) {
|
||||||
|
elementId = regenerateId(elementId);
|
||||||
|
}
|
||||||
|
const elementWithid = { ...element, id: elementId };
|
||||||
|
|
||||||
if (!ELEMENTS_SUPPORTING_PROGRAMMATIC_API.includes(element.type)) {
|
if (!ELEMENTS_SUPPORTING_PROGRAMMATIC_API.includes(element.type)) {
|
||||||
excalidrawElements.push(element as ExcalidrawElement);
|
excalidrawElements.push(element as ExcalidrawElement);
|
||||||
|
|
||||||
|
@ -242,7 +271,7 @@ export const convertToExcalidrawElements = (
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (VALID_CONTAINER_TYPES.has(element.type) && element?.label?.text) {
|
if (VALID_CONTAINER_TYPES.has(element.type) && element?.label?.text) {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
let [container, text] = bindTextToContainer(element, element.label);
|
let [container, text] = bindTextToContainer(elementWithid, element.label);
|
||||||
excalidrawElements.push(container);
|
excalidrawElements.push(container);
|
||||||
excalidrawElements.push(text);
|
excalidrawElements.push(text);
|
||||||
|
|
||||||
|
@ -263,15 +292,28 @@ export const convertToExcalidrawElements = (
|
||||||
} else {
|
} else {
|
||||||
let excalidrawElement;
|
let excalidrawElement;
|
||||||
if (element.type === "text") {
|
if (element.type === "text") {
|
||||||
excalidrawElement = newTextElement({
|
const fontFamily = element?.fontFamily || DEFAULT_FONT_FAMILY;
|
||||||
...element,
|
const fontSize = element?.fontSize || DEFAULT_FONT_SIZE;
|
||||||
});
|
const lineHeight =
|
||||||
|
element?.lineHeight || getDefaultLineHeight(fontFamily);
|
||||||
|
const text = element.text ?? "";
|
||||||
|
const normalizedText = normalizeText(text);
|
||||||
|
const metrics = measureText(
|
||||||
|
normalizedText,
|
||||||
|
getFontString({ fontFamily, fontSize }),
|
||||||
|
lineHeight,
|
||||||
|
);
|
||||||
|
excalidrawElement = {
|
||||||
|
width: metrics.width,
|
||||||
|
height: metrics.height,
|
||||||
|
...elementWithid,
|
||||||
|
};
|
||||||
|
|
||||||
excalidrawElements.push(excalidrawElement);
|
excalidrawElements.push(excalidrawElement as ExcalidrawTextElement);
|
||||||
} else if (element.type === "arrow" || element.type === "line") {
|
} else if (element.type === "arrow" || element.type === "line") {
|
||||||
const { linearElement, startBoundElement, endBoundElement } =
|
const { linearElement, startBoundElement, endBoundElement } =
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
bindLinearElementToElement(element);
|
bindLinearElementToElement(elementWithid);
|
||||||
excalidrawElements.push(linearElement);
|
excalidrawElements.push(linearElement);
|
||||||
excalidrawElements.push(startBoundElement);
|
excalidrawElements.push(startBoundElement);
|
||||||
excalidrawElements.push(endBoundElement);
|
excalidrawElements.push(endBoundElement);
|
||||||
|
@ -287,8 +329,7 @@ export const convertToExcalidrawElements = (
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
excalidrawElement = {
|
excalidrawElement = {
|
||||||
...element,
|
...elementWithid,
|
||||||
id: element.id || randomId(),
|
|
||||||
width:
|
width:
|
||||||
element?.width ||
|
element?.width ||
|
||||||
(ELEMENTS_SUPPORTING_PROGRAMMATIC_API.includes(element.type)
|
(ELEMENTS_SUPPORTING_PROGRAMMATIC_API.includes(element.type)
|
||||||
|
|
|
@ -18,7 +18,6 @@ import type { cleanAppStateForExport } from "../appState";
|
||||||
import { VERSIONS } from "../constants";
|
import { VERSIONS } from "../constants";
|
||||||
import { MarkOptional } from "../utility-types";
|
import { MarkOptional } from "../utility-types";
|
||||||
import { ElementConstructorOpts } from "../element/newElement";
|
import { ElementConstructorOpts } from "../element/newElement";
|
||||||
import { ELEMENTS_SUPPORTING_PROGRAMMATIC_API } from "./transform";
|
|
||||||
|
|
||||||
export interface ExportedDataState {
|
export interface ExportedDataState {
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -62,7 +61,7 @@ export interface ImportedDataState {
|
||||||
type: "text";
|
type: "text";
|
||||||
text: string;
|
text: string;
|
||||||
id?: ExcalidrawTextElement["id"];
|
id?: ExcalidrawTextElement["id"];
|
||||||
} & ElementConstructorOpts)
|
} & Partial<ExcalidrawTextElement>)
|
||||||
| ({
|
| ({
|
||||||
type: ExcalidrawLinearElement["type"];
|
type: ExcalidrawLinearElement["type"];
|
||||||
x: number;
|
x: number;
|
||||||
|
|
|
@ -471,7 +471,7 @@ export const deepCopyElement = <T extends ExcalidrawElement>(
|
||||||
* utility wrapper to generate new id. In test env it reuses the old + postfix
|
* utility wrapper to generate new id. In test env it reuses the old + postfix
|
||||||
* for test assertions.
|
* for test assertions.
|
||||||
*/
|
*/
|
||||||
const regenerateId = (
|
export const regenerateId = (
|
||||||
/** supply null if no previous id exists */
|
/** supply null if no previous id exists */
|
||||||
previousId: string | null,
|
previousId: string | null,
|
||||||
) => {
|
) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue