Compare commits

..

8 Commits

Author SHA1 Message Date
Aakansha Doshi 1ac4200cc0 tweak 2024-02-05 19:54:39 +05:30
Aakansha Doshi 2ca2c0f9fa fix 2024-02-05 19:34:48 +05:30
Aakansha Doshi f3b6e9b09f fix 2024-02-05 19:28:24 +05:30
Aakansha Doshi 1db2869906 persist file name to LS 2024-02-05 19:26:52 +05:30
Aakansha Doshi 1bb88cb5e9 fix 2024-02-05 15:43:44 +05:30
Aakansha Doshi 701e076cc1 fix snaps 2024-02-05 15:13:49 +05:30
Aakansha Doshi ad39506585 fix 2024-02-05 15:07:11 +05:30
Aakansha Doshi b2331ffd98 feat: remove name from appState and use in component directly 2024-02-05 15:05:01 +05:30
26 changed files with 192 additions and 381 deletions
+2 -1
View File
@@ -104,6 +104,7 @@ import { openConfirmModal } from "../packages/excalidraw/components/OverwriteCon
import { OverwriteConfirmDialog } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm";
import Trans from "../packages/excalidraw/components/Trans";
import { ShareDialog, shareDialogStateAtom } from "./share/ShareDialog";
import { getFileName } from "../packages/excalidraw/data/filename";
polyfill();
@@ -690,7 +691,6 @@ const ExcalidrawWrapper = () => {
</div>
);
}
return (
<div
style={{ height: "100%" }}
@@ -775,6 +775,7 @@ const ExcalidrawWrapper = () => {
excalidrawAPI.getSceneElements(),
excalidrawAPI.getAppState(),
excalidrawAPI.getFiles(),
getFileName(),
);
}}
>
@@ -25,11 +25,13 @@ import { MIME_TYPES } from "../../packages/excalidraw/constants";
import { trackEvent } from "../../packages/excalidraw/analytics";
import { getFrame } from "../../packages/excalidraw/utils";
import { ExcalidrawLogo } from "../../packages/excalidraw/components/ExcalidrawLogo";
import { getFileName } from "../../packages/excalidraw/data/filename";
export const exportToExcalidrawPlus = async (
elements: readonly NonDeletedExcalidrawElement[],
appState: Partial<AppState>,
files: BinaryFiles,
name: string,
) => {
const firebase = await loadFirebaseStorage();
@@ -53,7 +55,7 @@ export const exportToExcalidrawPlus = async (
.ref(`/migrations/scenes/${id}`)
.put(blob, {
customMetadata: {
data: JSON.stringify({ version: 2, name: appState.name }),
data: JSON.stringify({ version: 2, name }),
created: Date.now().toString(),
},
});
@@ -117,7 +119,12 @@ export const ExportToExcalidrawPlus: React.FC<{
onClick={async () => {
try {
trackEvent("export", "eplus", `ui (${getFrame()})`);
await exportToExcalidrawPlus(elements, appState, files);
await exportToExcalidrawPlus(
elements,
appState,
files,
getFileName(),
);
onSuccess();
} catch (error: any) {
console.error(error);
@@ -49,7 +49,7 @@ export const actionUnbindText = register({
selectedElements.forEach((element) => {
const boundTextElement = getBoundTextElement(element, elementsMap);
if (boundTextElement) {
const { width, height } = measureText(
const { width, height, baseline } = measureText(
boundTextElement.originalText,
getFontString(boundTextElement),
boundTextElement.lineHeight,
@@ -63,6 +63,7 @@ export const actionUnbindText = register({
containerId: null,
width,
height,
baseline,
text: boundTextElement.originalText,
x,
y,
@@ -13,6 +13,7 @@ import { exportCanvas, prepareElementsForExport } from "../data/index";
import { isTextElement } from "../element";
import { t } from "../i18n";
import { isFirefox } from "../constants";
import { getFileName } from "../data/filename";
export const actionCopy = register({
name: "copy",
@@ -138,6 +139,7 @@ export const actionCopyAsSvg = register({
{
...appState,
exportingFrame,
name: app.props.name || getFileName(),
},
);
return {
@@ -184,6 +186,7 @@ export const actionCopyAsPng = register({
await exportCanvas("clipboard", exportedElements, appState, app.files, {
...appState,
exportingFrame,
name: app.props.name || getFileName(),
});
return {
appState: {
+15 -3
View File
@@ -17,6 +17,7 @@ import { getNonDeletedElements } from "../element";
import { isImageFileHandle } from "../data/blob";
import { nativeFileSystemSupported } from "../data/filesystem";
import { Theme } from "../element/types";
import { getFileName } from "../data/filename";
import "../components/ToolIcon.scss";
@@ -29,7 +30,7 @@ export const actionChangeProjectName = register({
PanelComponent: ({ appState, updateData, appProps, data }) => (
<ProjectName
label={t("labels.fileTitle")}
value={appState.name || "Unnamed"}
value={appProps.name}
onChange={(name: string) => updateData(name)}
isNameEditable={
typeof appProps.name === "undefined" && !appState.viewModeEnabled
@@ -144,8 +145,18 @@ export const actionSaveToActiveFile = register({
try {
const { fileHandle } = isImageFileHandle(appState.fileHandle)
? await resaveAsImageWithScene(elements, appState, app.files)
: await saveAsJSON(elements, appState, app.files);
? await resaveAsImageWithScene(
elements,
appState,
app.files,
app.props.name || getFileName(),
)
: await saveAsJSON(
elements,
appState,
app.files,
app.props.name || getFileName(),
);
return {
commitToHistory: false,
@@ -190,6 +201,7 @@ export const actionSaveFileToDisk = register({
fileHandle: null,
},
app.files,
app.props.name || getFileName(),
);
return {
commitToHistory: false,
-4
View File
@@ -7,9 +7,7 @@ import {
EXPORT_SCALES,
THEME,
} from "./constants";
import { t } from "./i18n";
import { AppState, NormalizedZoomValue } from "./types";
import { getDateTime } from "./utils";
const defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio)
? devicePixelRatio
@@ -65,7 +63,6 @@ export const getDefaultAppState = (): Omit<
isRotating: false,
lastPointerDownWith: "mouse",
multiElement: null,
name: `${t("labels.untitled")}-${getDateTime()}`,
contextMenu: null,
openMenu: null,
openPopup: null,
@@ -175,7 +172,6 @@ const APP_STATE_STORAGE_CONF = (<
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 },
contextMenu: { browser: false, export: false, server: false },
+3 -15
View File
@@ -409,6 +409,7 @@ import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
import { getRenderOpacity } from "../renderer/renderElement";
import { textWysiwyg } from "../element/textWysiwyg";
import { isOverScrollBars } from "../scene/scrollbars";
import { getFileName } from "../data/filename";
const AppContext = React.createContext<AppClassProperties>(null!);
const AppPropsContext = React.createContext<AppProps>(null!);
@@ -619,7 +620,6 @@ class App extends React.Component<AppProps, AppState> {
gridModeEnabled = false,
objectsSnapModeEnabled = false,
theme = defaultAppState.theme,
name = defaultAppState.name,
} = props;
this.state = {
...defaultAppState,
@@ -630,7 +630,6 @@ class App extends React.Component<AppProps, AppState> {
zenModeEnabled,
objectsSnapModeEnabled,
gridSize: gridModeEnabled ? GRID_SIZE : null,
name,
width: window.innerWidth,
height: window.innerHeight,
};
@@ -1725,7 +1724,7 @@ class App extends React.Component<AppProps, AppState> {
this.files,
{
exportBackground: this.state.exportBackground,
name: this.state.name,
name: this.props.name || getFileName(),
viewBackgroundColor: this.state.viewBackgroundColor,
exportingFrame: opts.exportingFrame,
},
@@ -2124,7 +2123,7 @@ class App extends React.Component<AppProps, AppState> {
let gridSize = actionResult?.appState?.gridSize || null;
const theme =
actionResult?.appState?.theme || this.props.theme || THEME.LIGHT;
let name = actionResult?.appState?.name ?? this.state.name;
const errorMessage =
actionResult?.appState?.errorMessage ?? this.state.errorMessage;
if (typeof this.props.viewModeEnabled !== "undefined") {
@@ -2139,10 +2138,6 @@ class App extends React.Component<AppProps, AppState> {
gridSize = this.props.gridModeEnabled ? GRID_SIZE : null;
}
if (typeof this.props.name !== "undefined") {
name = this.props.name;
}
editingElement =
editingElement || actionResult.appState?.editingElement || null;
@@ -2165,7 +2160,6 @@ class App extends React.Component<AppProps, AppState> {
zenModeEnabled,
gridSize,
theme,
name,
errorMessage,
});
},
@@ -2699,12 +2693,6 @@ class App extends React.Component<AppProps, AppState> {
});
}
if (this.props.name && prevProps.name !== this.props.name) {
this.setState({
name: this.props.name,
});
}
this.excalidrawContainerRef.current?.classList.toggle(
"theme--dark",
this.state.theme === "dark",
@@ -36,6 +36,7 @@ import { useAppProps } from "./App";
import { FilledButton } from "./FilledButton";
import { cloneJSON } from "../utils";
import { prepareElementsForExport } from "../data";
import { getFileName } from "../data/filename";
const supportsContextFilters =
"filter" in document.createElement("canvas").getContext("2d")!;
@@ -73,7 +74,9 @@ const ImageExportModal = ({
);
const appProps = useAppProps();
const [projectName, setProjectName] = useState(appStateSnapshot.name);
const [projectName, setProjectName] = useState(
appProps.name || getFileName(),
);
const [exportSelectionOnly, setExportSelectionOnly] = useState(hasSelection);
const [exportWithBackground, setExportWithBackground] = useState(
appStateSnapshot.exportBackground,
@@ -109,7 +112,6 @@ const ImageExportModal = ({
elements: exportedElements,
appState: {
...appStateSnapshot,
name: projectName,
exportBackground: exportWithBackground,
exportWithDarkMode: exportDarkMode,
exportScale,
@@ -6,9 +6,12 @@ import { focusNearestParent } from "../utils";
import "./ProjectName.scss";
import { useExcalidrawContainer } from "./App";
import { KEYS } from "../keys";
import { EditorLocalStorage } from "../data/EditorLocalStorage";
import { EDITOR_LS_KEYS } from "../constants";
import { getFileName } from "../data/filename";
type Props = {
value: string;
value?: string;
onChange: (value: string) => void;
label: string;
isNameEditable: boolean;
@@ -17,9 +20,13 @@ type Props = {
export const ProjectName = (props: Props) => {
const { id } = useExcalidrawContainer();
const [fileName, setFileName] = useState<string>(props.value);
const [fileName, setFileName] = useState<string>(
props.value || getFileName(),
);
const handleBlur = (event: any) => {
EditorLocalStorage.set(EDITOR_LS_KEYS.EXCALIDRAW_FILE_NAME, fileName);
if (!props.ignoreFocus) {
focusNearestParent(event.target);
}
+1
View File
@@ -380,4 +380,5 @@ export const EDITOR_LS_KEYS = {
// legacy naming (non)scheme
MERMAID_TO_EXCALIDRAW: "mermaid-to-excalidraw",
PUBLISH_LIBRARY: "publish-library-data",
EXCALIDRAW_FILE_NAME: "excalidraw-file-name",
} as const;
@@ -219,6 +219,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [
{
"id": "id48",
@@ -262,6 +263,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [
{
"id": "id48",
@@ -363,6 +365,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id48",
"fillStyle": "solid",
@@ -459,6 +462,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id37",
"fillStyle": "solid",
@@ -625,6 +629,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id41",
"fillStyle": "solid",
@@ -663,6 +668,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [
{
"id": "id41",
@@ -706,6 +712,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [
{
"id": "id41",
@@ -1139,6 +1146,7 @@ exports[`Test Transform > should transform text element 1`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": null,
"fillStyle": "solid",
@@ -1177,6 +1185,7 @@ exports[`Test Transform > should transform text element 2`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": null,
"fillStyle": "solid",
@@ -1415,6 +1424,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id25",
"fillStyle": "solid",
@@ -1453,6 +1463,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id26",
"fillStyle": "solid",
@@ -1491,6 +1502,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id27",
"fillStyle": "solid",
@@ -1530,6 +1542,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id28",
"fillStyle": "solid",
@@ -1779,6 +1792,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id13",
"fillStyle": "solid",
@@ -1817,6 +1831,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id14",
"fillStyle": "solid",
@@ -1856,6 +1871,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id15",
"fillStyle": "solid",
@@ -1897,6 +1913,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id16",
"fillStyle": "solid",
@@ -1936,6 +1953,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id17",
"fillStyle": "solid",
@@ -1976,6 +1994,7 @@ exports[`Test Transform > should transform to text containers when label provide
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": null,
"containerId": "id18",
"fillStyle": "solid",
+11
View File
@@ -0,0 +1,11 @@
import { EDITOR_LS_KEYS } from "../constants";
import { t } from "../i18n";
import { getDateTime } from "../utils";
import { EditorLocalStorage } from "./EditorLocalStorage";
export const getFileName = () => {
return (
EditorLocalStorage.get<string>(EDITOR_LS_KEYS.EXCALIDRAW_FILE_NAME) ||
`${t("labels.untitled")}-${getDateTime()}`
);
};
+2 -1
View File
@@ -71,6 +71,7 @@ export const saveAsJSON = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
name: string,
) => {
const serialized = serializeAsJSON(elements, appState, files, "local");
const blob = new Blob([serialized], {
@@ -78,7 +79,7 @@ export const saveAsJSON = async (
});
const fileHandle = await fileSave(blob, {
name: appState.name,
name,
extension: "excalidraw",
description: "Excalidraw file",
fileHandle: isImageFileHandle(appState.fileHandle)
+2 -1
View File
@@ -7,8 +7,9 @@ export const resaveAsImageWithScene = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
name: string,
) => {
const { exportBackground, viewBackgroundColor, name, fileHandle } = appState;
const { exportBackground, viewBackgroundColor, fileHandle } = appState;
const fileHandleType = getFileHandleType(fileHandle);
+8 -1
View File
@@ -35,13 +35,14 @@ import {
import { getDefaultAppState } from "../appState";
import { LinearElementEditor } from "../element/linearElementEditor";
import { bumpVersion } from "../element/mutateElement";
import { getUpdatedTimestamp, updateActiveTool } from "../utils";
import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils";
import { arrayToMap } from "../utils";
import { MarkOptional, Mutable } from "../utility-types";
import {
detectLineHeight,
getContainerElement,
getDefaultLineHeight,
measureBaseline,
} from "../element/textElement";
import { normalizeLink } from "./url";
@@ -206,6 +207,11 @@ const restoreElement = (
: // no element height likely means programmatic use, so default
// to a fixed line height
getDefaultLineHeight(element.fontFamily));
const baseline = measureBaseline(
element.text,
getFontString(element),
lineHeight,
);
element = restoreElementWithProperties(element, {
fontSize,
fontFamily,
@@ -216,6 +222,7 @@ const restoreElement = (
originalText: element.originalText || text,
lineHeight,
baseline,
});
// if empty text, mark as deleted. We keep in array
+8 -5
View File
@@ -246,6 +246,7 @@ export const newTextElement = (
y: opts.y - offsets.y,
width: metrics.width,
height: metrics.height,
baseline: metrics.baseline,
containerId: opts.containerId || null,
originalText: text,
lineHeight,
@@ -263,12 +264,13 @@ const getAdjustedDimensions = (
y: number;
width: number;
height: number;
baseline: number;
} => {
const { width: nextWidth, height: nextHeight } = measureText(
nextText,
getFontString(element),
element.lineHeight,
);
const {
width: nextWidth,
height: nextHeight,
baseline: nextBaseline,
} = measureText(nextText, getFontString(element), element.lineHeight);
const { textAlign, verticalAlign } = element;
let x: number;
let y: number;
@@ -322,6 +324,7 @@ const getAdjustedDimensions = (
return {
width: nextWidth,
height: nextHeight,
baseline: nextBaseline,
x: Number.isFinite(x) ? x : element.x,
y: Number.isFinite(y) ? y : element.y,
};
+30 -5
View File
@@ -52,6 +52,8 @@ import {
handleBindTextResize,
getBoundTextMaxWidth,
getApproxMinLineHeight,
measureText,
getBoundTextMaxHeight,
} from "./textElement";
import { LinearElementEditor } from "./linearElementEditor";
@@ -209,7 +211,8 @@ const measureFontSizeFromWidth = (
element: NonDeleted<ExcalidrawTextElement>,
elementsMap: ElementsMap,
nextWidth: number,
): { size: number } | null => {
nextHeight: number,
): { size: number; baseline: number } | null => {
// We only use width to scale font on resize
let width = element.width;
@@ -224,9 +227,14 @@ const measureFontSizeFromWidth = (
if (nextFontSize < MIN_FONT_SIZE) {
return null;
}
const metrics = measureText(
element.text,
getFontString({ fontSize: nextFontSize, fontFamily: element.fontFamily }),
element.lineHeight,
);
return {
size: nextFontSize,
baseline: metrics.baseline + (nextHeight - metrics.height),
};
};
@@ -299,7 +307,12 @@ const resizeSingleTextElement = (
if (scale > 0) {
const nextWidth = element.width * scale;
const nextHeight = element.height * scale;
const metrics = measureFontSizeFromWidth(element, elementsMap, nextWidth);
const metrics = measureFontSizeFromWidth(
element,
elementsMap,
nextWidth,
nextHeight,
);
if (metrics === null) {
return;
}
@@ -327,6 +340,7 @@ const resizeSingleTextElement = (
fontSize: metrics.size,
width: nextWidth,
height: nextHeight,
baseline: metrics.baseline,
x: nextElementX,
y: nextElementY,
});
@@ -380,7 +394,7 @@ export const resizeSingleElement = (
let scaleX = atStartBoundsWidth / boundsCurrentWidth;
let scaleY = atStartBoundsHeight / boundsCurrentHeight;
let boundTextFont: { fontSize?: number } = {};
let boundTextFont: { fontSize?: number; baseline?: number } = {};
const boundTextElement = getBoundTextElement(element, elementsMap);
if (transformHandleDirection.includes("e")) {
@@ -432,6 +446,7 @@ export const resizeSingleElement = (
if (stateOfBoundTextElementAtResize) {
boundTextFont = {
fontSize: stateOfBoundTextElementAtResize.fontSize,
baseline: stateOfBoundTextElementAtResize.baseline,
};
}
if (shouldMaintainAspectRatio) {
@@ -445,12 +460,14 @@ export const resizeSingleElement = (
boundTextElement,
elementsMap,
getBoundTextMaxWidth(updatedElement, boundTextElement),
getBoundTextMaxHeight(updatedElement, boundTextElement),
);
if (nextFont === null) {
return;
}
boundTextFont = {
fontSize: nextFont.size,
baseline: nextFont.baseline,
};
} else {
const minWidth = getApproxMinLineWidth(
@@ -619,6 +636,7 @@ export const resizeSingleElement = (
if (boundTextElement && boundTextFont != null) {
mutateElement(boundTextElement, {
fontSize: boundTextFont.fontSize,
baseline: boundTextFont.baseline,
});
}
handleBindTextResize(
@@ -745,6 +763,7 @@ export const resizeMultipleElements = (
> & {
points?: ExcalidrawLinearElement["points"];
fontSize?: ExcalidrawTextElement["fontSize"];
baseline?: ExcalidrawTextElement["baseline"];
scale?: ExcalidrawImageElement["scale"];
boundTextFontSize?: ExcalidrawTextElement["fontSize"];
};
@@ -819,11 +838,17 @@ export const resizeMultipleElements = (
}
if (isTextElement(orig)) {
const metrics = measureFontSizeFromWidth(orig, elementsMap, width);
const metrics = measureFontSizeFromWidth(
orig,
elementsMap,
width,
height,
);
if (!metrics) {
return;
}
update.fontSize = metrics.size;
update.baseline = metrics.baseline;
}
const boundTextElement = originalElements.get(
+59 -1
View File
@@ -18,6 +18,7 @@ import {
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
FONT_FAMILY,
isSafari,
TEXT_ALIGN,
VERTICAL_ALIGN,
} from "../constants";
@@ -60,6 +61,7 @@ export const redrawTextBoundingBox = (
text: textElement.text,
width: textElement.width,
height: textElement.height,
baseline: textElement.baseline,
};
boundTextUpdates.text = textElement.text;
@@ -80,6 +82,7 @@ export const redrawTextBoundingBox = (
boundTextUpdates.width = metrics.width;
boundTextUpdates.height = metrics.height;
boundTextUpdates.baseline = metrics.baseline;
if (container) {
const maxContainerHeight = getBoundTextMaxHeight(
@@ -180,6 +183,7 @@ export const handleBindTextResize = (
const maxWidth = getBoundTextMaxWidth(container, textElement);
const maxHeight = getBoundTextMaxHeight(container, textElement);
let containerHeight = container.height;
let nextBaseLine = textElement.baseline;
if (
shouldMaintainAspectRatio ||
(transformHandleType !== "n" && transformHandleType !== "s")
@@ -198,6 +202,7 @@ export const handleBindTextResize = (
);
nextHeight = metrics.height;
nextWidth = metrics.width;
nextBaseLine = metrics.baseline;
}
// increase height in case text element height exceeds
if (nextHeight > maxHeight) {
@@ -225,6 +230,7 @@ export const handleBindTextResize = (
text,
width: nextWidth,
height: nextHeight,
baseline: nextBaseLine,
});
if (!isArrowElement(container)) {
@@ -288,7 +294,59 @@ export const measureText = (
const fontSize = parseFloat(font);
const height = getTextHeight(text, fontSize, lineHeight);
const width = getTextWidth(text, font);
return { width, height };
const baseline = measureBaseline(text, font, lineHeight);
return { width, height, baseline };
};
export const measureBaseline = (
text: string,
font: FontString,
lineHeight: ExcalidrawTextElement["lineHeight"],
wrapInContainer?: boolean,
) => {
const container = document.createElement("div");
container.style.position = "absolute";
container.style.whiteSpace = "pre";
container.style.font = font;
container.style.minHeight = "1em";
if (wrapInContainer) {
container.style.overflow = "hidden";
container.style.wordBreak = "break-word";
container.style.whiteSpace = "pre-wrap";
}
container.style.lineHeight = String(lineHeight);
container.innerText = text;
// Baseline is important for positioning text on canvas
document.body.appendChild(container);
const span = document.createElement("span");
span.style.display = "inline-block";
span.style.overflow = "hidden";
span.style.width = "1px";
span.style.height = "1px";
container.appendChild(span);
let baseline = span.offsetTop + span.offsetHeight;
const height = container.offsetHeight;
if (isSafari) {
const canvasHeight = getTextHeight(text, parseFloat(font), lineHeight);
const fontSize = parseFloat(font);
// In Safari the font size gets rounded off when rendering hence calculating the safari height and shifting the baseline if it differs
// from the actual canvas height
const domHeight = getTextHeight(text, Math.round(fontSize), lineHeight);
if (canvasHeight > height) {
baseline += canvasHeight - domHeight;
}
if (height > canvasHeight) {
baseline -= domHeight - canvasHeight;
}
}
document.body.removeChild(container);
return baseline;
};
/**
+1
View File
@@ -176,6 +176,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
fontSize: number;
fontFamily: FontFamilyValues;
text: string;
baseline: number;
textAlign: TextAlign;
verticalAlign: VerticalAlign;
containerId: ExcalidrawGenericElement["id"] | null;
-1
View File
@@ -26,7 +26,6 @@ const clearAppStatePropertiesForHistory = (appState: AppState) => {
viewBackgroundColor: appState.viewBackgroundColor,
editingLinearElement: appState.editingLinearElement,
editingGroupId: appState.editingGroupId,
name: appState.name,
};
};
+2 -14
View File
@@ -395,24 +395,12 @@ const drawElementOnCanvas = (
element.fontSize,
element.lineHeight,
);
const metrics = context.measureText(element.text);
const lineGap =
lineHeightPx -
(metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent);
/**
* Set a vertical offset to be aligned with <textarea>.
* - `fontBoundingBoxAscent` is here the font bouding box with its default line-height used in textareas
* - half of the line gap is the additional padding above and below the bounding box when line-height isn't equal to the default value
* - for details check - https://codesandbox.io/p/devbox/v4nsqz?file=%2Fsrc%2Findex.js%3A1%2C1-166%2C1
*/
context.translate(0, metrics.fontBoundingBoxAscent + lineGap / 2);
const verticalOffset = element.height - element.baseline;
for (let index = 0; index < lines.length; index++) {
context.fillText(
lines[index],
horizontalOffset,
index * lineHeightPx,
(index + 1) * lineHeightPx - verticalOffset,
);
}
context.restore();
@@ -328,7 +328,6 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -459,7 +458,6 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -529,7 +527,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -620,7 +617,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -631,7 +627,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -733,7 +728,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -854,7 +848,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -865,7 +858,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -908,7 +900,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -980,7 +971,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -1111,7 +1101,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -1232,7 +1221,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -1243,7 +1231,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -1286,7 +1273,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -1358,7 +1344,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -1489,7 +1474,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -1580,7 +1564,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -1591,7 +1574,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -1693,7 +1675,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -1780,7 +1761,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -1791,7 +1771,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -1834,7 +1813,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -1934,7 +1912,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -2055,7 +2032,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -2066,7 +2042,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -2109,7 +2084,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0_copy": true,
},
@@ -2240,7 +2214,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -2370,7 +2343,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -2381,7 +2353,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -2424,7 +2395,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -2496,7 +2466,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
"id1": true,
@@ -2634,7 +2603,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -2757,7 +2725,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -2768,7 +2735,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -2811,7 +2777,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -2883,7 +2848,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -2955,7 +2919,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3027,7 +2990,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3099,7 +3061,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3171,7 +3132,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3243,7 +3203,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3315,7 +3274,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -3446,7 +3404,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -3567,7 +3524,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -3578,7 +3534,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -3621,7 +3576,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3693,7 +3647,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -3824,7 +3777,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -3945,7 +3897,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -3956,7 +3907,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -3999,7 +3949,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -4071,7 +4020,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -4202,7 +4150,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -4326,7 +4273,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -4337,7 +4283,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -4380,7 +4325,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -4452,7 +4396,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
"id1": true,
@@ -4531,7 +4474,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
"id1": true,
@@ -4936,7 +4878,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -5060,7 +5001,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -5071,7 +5011,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -5114,7 +5053,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -5518,7 +5456,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -5648,7 +5585,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -5659,7 +5595,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -5702,7 +5637,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id1": true,
},
@@ -5774,7 +5708,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
"id1": true,
@@ -6039,7 +5972,6 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -6097,7 +6029,6 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] his
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -6440,7 +6371,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -6816,7 +6746,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
"isRotating": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
"name": "Untitled-201933152653",
"objectsSnapModeEnabled": false,
"offsetLeft": 20,
"offsetTop": 10,
@@ -6972,7 +6901,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] hi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
@@ -6983,7 +6911,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] hi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {
"id0": true,
},
@@ -7035,7 +6962,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] hi
"appState": {
"editingGroupId": null,
"editingLinearElement": null,
"name": "Untitled-201933152653",
"selectedElementIds": {},
"selectedGroupIds": {},
"viewBackgroundColor": "#ffffff",
File diff suppressed because it is too large Load Diff
@@ -289,6 +289,7 @@ exports[`restoreElements > should restore text element correctly passing value f
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [],
"containerId": null,
"fillStyle": "solid",
@@ -329,6 +330,7 @@ exports[`restoreElements > should restore text element correctly with unknown fo
{
"angle": 0,
"backgroundColor": "transparent",
"baseline": 0,
"boundElements": [],
"containerId": null,
"fillStyle": "solid",
@@ -306,12 +306,10 @@ describe("restoreAppState", () => {
const stubImportedAppState = getDefaultAppState();
stubImportedAppState.activeTool.type = "selection";
stubImportedAppState.cursorButton = "down";
stubImportedAppState.name = "imported app state";
const stubLocalAppState = getDefaultAppState();
stubLocalAppState.activeTool.type = "rectangle";
stubLocalAppState.cursorButton = "up";
stubLocalAppState.name = "local app state";
const restoredAppState = restore.restoreAppState(
stubImportedAppState,
@@ -321,7 +319,6 @@ describe("restoreAppState", () => {
stubImportedAppState.activeTool,
);
expect(restoredAppState.cursorButton).toBe("up");
expect(restoredAppState.name).toBe(stubImportedAppState.name);
});
it("should restore with current app state when imported data state is undefined", () => {
@@ -333,37 +330,31 @@ describe("restoreAppState", () => {
const stubLocalAppState = getDefaultAppState();
stubLocalAppState.cursorButton = "down";
stubLocalAppState.name = "local app state";
const restoredAppState = restore.restoreAppState(
stubImportedAppState,
stubLocalAppState,
);
expect(restoredAppState.cursorButton).toBe(stubLocalAppState.cursorButton);
expect(restoredAppState.name).toBe(stubLocalAppState.name);
});
it("should return imported data when local app state is null", () => {
const stubImportedAppState = getDefaultAppState();
stubImportedAppState.cursorButton = "down";
stubImportedAppState.name = "imported app state";
const restoredAppState = restore.restoreAppState(
stubImportedAppState,
null,
);
expect(restoredAppState.cursorButton).toBe("up");
expect(restoredAppState.name).toBe(stubImportedAppState.name);
});
it("should return local app state when imported data state is null", () => {
const stubLocalAppState = getDefaultAppState();
stubLocalAppState.cursorButton = "down";
stubLocalAppState.name = "local app state";
const restoredAppState = restore.restoreAppState(null, stubLocalAppState);
expect(restoredAppState.cursorButton).toBe(stubLocalAppState.cursorButton);
expect(restoredAppState.name).toBe(stubLocalAppState.name);
});
it("should return default app state when imported data state and local app state are undefined", () => {
@@ -492,13 +483,11 @@ describe("restore", () => {
it("when imported data state is null it should return the local app state property", () => {
const stubLocalAppState = getDefaultAppState();
stubLocalAppState.cursorButton = "down";
stubLocalAppState.name = "local app state";
const restoredData = restore.restore(null, stubLocalAppState, null);
expect(restoredData.appState.cursorButton).toBe(
stubLocalAppState.cursorButton,
);
expect(restoredData.appState.name).toBe(stubLocalAppState.name);
});
it("when imported data state has elements", () => {
@@ -522,14 +511,12 @@ describe("restore", () => {
it("when local app state is null but imported app state is supplied", () => {
const stubImportedAppState = getDefaultAppState();
stubImportedAppState.cursorButton = "down";
stubImportedAppState.name = "imported app state";
const importedDataState = {} as ImportedDataState;
importedDataState.appState = stubImportedAppState;
const restoredData = restore.restore(importedDataState, null, null);
expect(restoredData.appState.cursorButton).toBe("up");
expect(restoredData.appState.name).toBe(stubImportedAppState.name);
});
it("bump versions of local duplicate elements when supplied", () => {
-1
View File
@@ -247,7 +247,6 @@ export interface AppState {
scrollY: number;
cursorButton: "up" | "down";
scrolledOutside: boolean;
name: string;
isResizing: boolean;
isRotating: boolean;
zoom: Zoom;