From 6aeb18b784d19bdcbbc438ed604603a78c1d5899 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 14 Mar 2023 17:08:23 +0530 Subject: [PATCH 1/5] fix: refresh dimensions when elements loaded from shareable link and blob (#6333) * fix: refresh dimensions when elements loaded from shareable link * refresh text dimensions when loading from file * remove log --- src/data/blob.ts | 2 +- src/excalidraw-app/data/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/blob.ts b/src/data/blob.ts index 35c040ef3..47cff293f 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -157,7 +157,7 @@ export const loadSceneOrLibraryFromBlob = async ( }, localAppState, localElements, - { repairBindings: true }, + { repairBindings: true, refreshDimensions: true }, ), }; } else if (isValidLibrary(data)) { diff --git a/src/excalidraw-app/data/index.ts b/src/excalidraw-app/data/index.ts index 393c51580..7f13bc615 100644 --- a/src/excalidraw-app/data/index.ts +++ b/src/excalidraw-app/data/index.ts @@ -263,7 +263,7 @@ export const loadScene = async ( await importFromBackend(id, privateKey), localDataState?.appState, localDataState?.elements, - { repairBindings: true }, + { repairBindings: true, refreshDimensions: true }, ); } else { data = restore(localDataState || null, null, null, { From ab49cad6b1e84db512c12d9b030c0d615c402b58 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 14 Mar 2023 17:18:16 +0530 Subject: [PATCH 2/5] perf: break early if the line width <= max width of the container (#6347) * fix: break early if the line width <= max width of the container * Remove dead code * remove dead code * lint * remove --- src/element/textElement.test.ts | 13 ++++++-- src/element/textElement.ts | 54 ++++++++++++++++----------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/element/textElement.test.ts b/src/element/textElement.test.ts index 7bc361b4d..3de960375 100644 --- a/src/element/textElement.test.ts +++ b/src/element/textElement.test.ts @@ -16,7 +16,7 @@ describe("Test wrapText", () => { const text = "Hello whats up "; const maxWidth = 200 - BOUND_TEXT_PADDING * 2; const res = wrapText(text, font, maxWidth); - expect(res).toBe("Hello whats up "); + expect(res).toBe(text); }); it("should work with emojis", () => { @@ -26,7 +26,7 @@ describe("Test wrapText", () => { expect(res).toBe("๐Ÿ˜€"); }); - it("should show the text correctly when min width reached", () => { + it("should show the text correctly when max width reached", () => { const text = "Hello๐Ÿ˜€"; const maxWidth = 10; const res = wrapText(text, font, maxWidth); @@ -136,6 +136,7 @@ whats up`, }); }); }); + describe("When text is long", () => { const text = `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg break it now`; [ @@ -175,6 +176,14 @@ break it now`, }); }); }); + + it("should wrap the text correctly when word length is exactly equal to max width", () => { + const text = "Hello Excalidraw"; + // Length of "Excalidraw" is 100 and exacty equal to max width + const res = wrapText(text, font, 100); + expect(res).toEqual(`Hello +Excalidraw`); + }); }); describe("Test measureText", () => { diff --git a/src/element/textElement.ts b/src/element/textElement.ts index bdb11c9ac..068d4a820 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -327,25 +327,38 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { const lines: Array = []; const originalLines = text.split("\n"); const spaceWidth = getLineWidth(" ", font); + + let currentLine = ""; + let currentLineWidthTillNow = 0; + const push = (str: string) => { if (str.trim()) { lines.push(str); } }; + + const resetParams = () => { + currentLine = ""; + currentLineWidthTillNow = 0; + }; + originalLines.forEach((originalLine) => { - const words = originalLine.split(" "); - // This means its newline so push it - if (words.length === 1 && words[0] === "") { - lines.push(words[0]); + const currentLineWidth = getTextWidth(originalLine, font); + + //Push the line if its <= maxWidth + if (currentLineWidth <= maxWidth) { + lines.push(originalLine); return; // continue } - let currentLine = ""; - let currentLineWidthTillNow = 0; + const words = originalLine.split(" "); + + resetParams(); let index = 0; while (index < words.length) { const currentWordWidth = getLineWidth(words[index], font); + // This will only happen when single word takes entire width if (currentWordWidth === maxWidth) { push(words[index]); @@ -357,8 +370,8 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { // push current line since the current word exceeds the max width // so will be appended in next line push(currentLine); - currentLine = ""; - currentLineWidthTillNow = 0; + + resetParams(); while (words[index].length > 0) { const currentChar = String.fromCodePoint( @@ -369,10 +382,6 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { words[index] = words[index].slice(currentChar.length); if (currentLineWidthTillNow >= maxWidth) { - // only remove last trailing space which we have added when joining words - if (currentLine.slice(-1) === " ") { - currentLine = currentLine.slice(0, -1); - } push(currentLine); currentLine = currentChar; currentLineWidthTillNow = width; @@ -380,11 +389,11 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { currentLine += currentChar; } } + // push current line if appending space exceeds max width if (currentLineWidthTillNow + spaceWidth >= maxWidth) { push(currentLine); - currentLine = ""; - currentLineWidthTillNow = 0; + resetParams(); } else { // space needs to be appended before next word // as currentLine contains chars which couldn't be appended @@ -392,7 +401,6 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { currentLine += " "; currentLineWidthTillNow += spaceWidth; } - index++; } else { // Start appending words in a line till max width reached @@ -402,8 +410,7 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { if (currentLineWidthTillNow > maxWidth) { push(currentLine); - currentLineWidthTillNow = 0; - currentLine = ""; + resetParams(); break; } @@ -414,22 +421,15 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => { if (currentLineWidthTillNow + spaceWidth >= maxWidth) { const word = currentLine.slice(0, -1); push(word); - currentLine = ""; - currentLineWidthTillNow = 0; + resetParams(); break; } } - if (currentLineWidthTillNow === maxWidth) { - currentLine = ""; - currentLineWidthTillNow = 0; - } } } - if (currentLine) { + if (currentLine.slice(-1) === " ") { // only remove last trailing space which we have added when joining words - if (currentLine.slice(-1) === " ") { - currentLine = currentLine.slice(0, -1); - } + currentLine = currentLine.slice(0, -1); push(currentLine); } }); From f6e8be399e55f39c9858f510d67cbe7fd68f8d47 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 14 Mar 2023 17:21:46 +0530 Subject: [PATCH 3/5] fix: hide text align for labelled arrows (#6339) * fix: hide text align for labelled arrows * lintttt * since we fetch seledcted Elements including the bound text hence this block can be removed * fix --- src/actions/actionProperties.tsx | 3 +++ src/components/Actions.tsx | 8 ++++++-- src/element/textElement.ts | 18 ++++++++++++++---- src/tests/linearElementEditor.test.tsx | 12 ++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index 4e6f0d587..309e46bdc 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -745,16 +745,19 @@ export const actionChangeTextAlign = register({ value: "left", text: t("labels.left"), icon: TextAlignLeftIcon, + testId: "align-left", }, { value: "center", text: t("labels.center"), icon: TextAlignCenterIcon, + testId: "align-horizontal-center", }, { value: "right", text: t("labels.right"), icon: TextAlignRightIcon, + testId: "align-right", }, ]} value={getFormValue( diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index 2ee9babfc..3bbc0ff1a 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -30,7 +30,10 @@ import clsx from "clsx"; import { actionToggleZenMode } from "../actions"; import "./Actions.scss"; import { Tooltip } from "./Tooltip"; -import { shouldAllowVerticalAlign } from "../element/textElement"; +import { + shouldAllowVerticalAlign, + suppportsHorizontalAlign, +} from "../element/textElement"; export const SelectedShapeActions = ({ appState, @@ -122,7 +125,8 @@ export const SelectedShapeActions = ({ {renderAction("changeFontFamily")} - {renderAction("changeTextAlign")} + {suppportsHorizontalAlign(targetElements) && + renderAction("changeTextAlign")} )} diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 068d4a820..7dc11c9a7 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -668,14 +668,24 @@ export const shouldAllowVerticalAlign = ( } return true; } - const boundTextElement = getBoundTextElement(element); - if (boundTextElement) { - if (isArrowElement(element)) { + return false; + }); +}; + +export const suppportsHorizontalAlign = ( + selectedElements: NonDeletedExcalidrawElement[], +) => { + return selectedElements.some((element) => { + const hasBoundContainer = isBoundToContainer(element); + if (hasBoundContainer) { + const container = getContainerElement(element); + if (isTextElement(element) && isArrowElement(container)) { return false; } return true; } - return false; + + return isTextElement(element); }); }; diff --git a/src/tests/linearElementEditor.test.tsx b/src/tests/linearElementEditor.test.tsx index a606fb384..8c1d29325 100644 --- a/src/tests/linearElementEditor.test.tsx +++ b/src/tests/linearElementEditor.test.tsx @@ -1179,5 +1179,17 @@ describe("Test Linear Elements", () => { easy" `); }); + + it("should not render horizontal align tool when element selected", () => { + createTwoPointerLinearElement("arrow"); + const arrow = h.elements[0] as ExcalidrawLinearElement; + + createBoundTextElement(DEFAULT_TEXT, arrow); + API.setSelectedElements([arrow]); + + expect(queryByTestId(container, "align-left")).toBeNull(); + expect(queryByTestId(container, "align-horizontal-center")).toBeNull(); + expect(queryByTestId(container, "align-right")).toBeNull(); + }); }); }); From 20edddcd4efa3d784cd2a4295e03e1fbeaf1d1d6 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Tue, 14 Mar 2023 13:03:55 +0100 Subject: [PATCH 4/5] fix: ensure export preview is centered (#6337) --- src/components/ExportDialog.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ExportDialog.scss b/src/components/ExportDialog.scss index 7bc0c808e..3cb31c484 100644 --- a/src/components/ExportDialog.scss +++ b/src/components/ExportDialog.scss @@ -9,6 +9,10 @@ text-align: center; padding: var(--preview-padding); margin-bottom: calc(var(--space-factor) * 3); + + display: flex; + justify-content: center; + align-items: center; } .ExportDialog__preview canvas { From fe83e2922ddca078bc4b63d491a846b3a824813d Mon Sep 17 00:00:00 2001 From: Salah Eddine Daci Date: Tue, 14 Mar 2023 13:06:57 +0100 Subject: [PATCH 5/5] build: move TS and types to devDependencies (#6346) --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a19b2fb89..5816786e3 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,6 @@ "@testing-library/jest-dom": "5.16.2", "@testing-library/react": "12.1.5", "@tldraw/vec": "1.7.1", - "@types/jest": "27.4.0", - "@types/pica": "5.1.3", - "@types/react": "18.0.15", - "@types/react-dom": "18.0.6", - "@types/socket.io-client": "1.4.36", "browser-fs-access": "0.29.1", "clsx": "1.1.1", "cross-env": "7.0.3", @@ -57,7 +52,6 @@ "sass": "1.51.0", "socket.io-client": "2.3.1", "tunnel-rat": "0.1.0", - "typescript": "4.9.4", "workbox-background-sync": "^6.5.4", "workbox-broadcast-update": "^6.5.4", "workbox-cacheable-response": "^6.5.4", @@ -75,9 +69,14 @@ "@excalidraw/eslint-config": "1.0.0", "@excalidraw/prettier-config": "1.0.2", "@types/chai": "4.3.0", + "@types/jest": "27.4.0", "@types/lodash.throttle": "4.1.7", "@types/pako": "1.0.3", + "@types/pica": "5.1.3", + "@types/react": "18.0.15", + "@types/react-dom": "18.0.6", "@types/resize-observer-browser": "0.1.7", + "@types/socket.io-client": "1.4.36", "chai": "4.3.6", "dotenv": "16.0.1", "eslint-config-prettier": "8.5.0", @@ -88,7 +87,8 @@ "lint-staged": "12.3.7", "pepjs": "0.5.3", "prettier": "2.6.2", - "rewire": "6.0.0" + "rewire": "6.0.0", + "typescript": "4.9.4" }, "engines": { "node": ">=14.0.0"