diff --git a/src/components/App.tsx b/src/components/App.tsx index c578c77d..b51c7d4c 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -476,7 +476,7 @@ class App extends React.Component { zenModeEnabled={zenModeEnabled} toggleZenMode={this.toggleZenMode} langCode={getLanguage().code} - isCollaborating={this.props.isCollaborating || false} + isCollaborating={this.props.isCollaborating} renderTopRightUI={renderTopRightUI} renderCustomFooter={renderFooter} viewModeEnabled={viewModeEnabled} @@ -1912,20 +1912,15 @@ class App extends React.Component { text: string, originalText: string, isDeleted: boolean, - isSubmit: boolean, ) => { this.scene.replaceAllElements([ ...this.scene.getElementsIncludingDeleted().map((_element) => { if (_element.id === element.id && isTextElement(_element)) { - return updateTextElement( - _element, - { - text, - isDeleted, - originalText, - }, - isSubmit, - ); + return updateTextElement(_element, { + text, + isDeleted, + originalText, + }); } return _element; }), @@ -1950,14 +1945,14 @@ class App extends React.Component { ]; }, onChange: withBatchedUpdates((text) => { - updateElement(text, text, false, false); + updateElement(text, text, false); if (isNonDeletedElement(element)) { updateBoundElements(element); } }), onSubmit: withBatchedUpdates(({ text, viaKeyboard, originalText }) => { const isDeleted = !text.trim(); - updateElement(text, originalText, isDeleted, true); + updateElement(text, originalText, isDeleted); // select the created text element only if submitting via keyboard // (when submitting via click it should act as signal to deselect) if (!isDeleted && viaKeyboard) { @@ -1997,7 +1992,7 @@ class App extends React.Component { // do an initial update to re-initialize element position since we were // modifying element's x/y for sake of editor (case: syncing to remote) - updateElement(element.text, element.originalText, false, false); + updateElement(element.text, element.originalText, false); } private deselectElements() { diff --git a/src/element/newElement.ts b/src/element/newElement.ts index cb21b85e..4ca051bb 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -21,7 +21,7 @@ import { AppState } from "../types"; import { getElementAbsoluteCoords } from "."; import { adjustXYWithRotation } from "../math"; import { getResizedElementAbsoluteCoords } from "./bounds"; -import { getContainerElement, measureText } from "./textElement"; +import { getContainerElement, measureText, wrapText } from "./textElement"; import { isBoundToContainer } from "./typeChecks"; import { BOUND_TEXT_PADDING } from "../constants"; @@ -247,17 +247,17 @@ export const updateTextElement = ( text, isDeleted, originalText, - }: { text: string; isDeleted?: boolean; originalText: string }, - - isSubmit: boolean, + }: { + text: string; + isDeleted?: boolean; + originalText: string; + }, ): ExcalidrawTextElement => { - const boundToContainer = isBoundToContainer(element); - - // Don't update dimensions and text value for bounded text unless submitted - const dimensions = - boundToContainer && !isSubmit - ? undefined - : getAdjustedDimensions(element, text); + const container = getContainerElement(element); + if (container) { + text = wrapText(text, getFontString(element), container.width); + } + const dimensions = getAdjustedDimensions(element, text); return newElementWith(element, { text, originalText, diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 45997aa7..7b862874 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -8,7 +8,11 @@ import { import Scene from "../scene/Scene"; import { isBoundToContainer, isTextElement } from "./typeChecks"; import { CLASSES, BOUND_TEXT_PADDING } from "../constants"; -import { ExcalidrawElement, ExcalidrawTextElement } from "./types"; +import { + ExcalidrawElement, + ExcalidrawTextElement, + ExcalidrawLinearElement, +} from "./types"; import { AppState } from "../types"; import { mutateElement } from "./mutateElement"; import { @@ -100,7 +104,6 @@ export const textWysiwyg = ({ let originalContainerHeight: number; let approxLineHeight = getApproxLineHeight(getFontString(element)); - const initialText = element.originalText; const updateWysiwygStyle = () => { const updatedElement = Scene.getScene(element)?.getElement(id); if (updatedElement && isTextElement(updatedElement)) { @@ -222,6 +225,7 @@ export const textWysiwyg = ({ if (isTestEnv()) { editable.style.fontFamily = getFontFamilyString(updatedElement); } + mutateElement(updatedElement, { x: coordX, y: coordY }); } }; @@ -442,61 +446,41 @@ export const textWysiwyg = ({ // it'd get stuck in an infinite loop of blur→onSubmit after we re-focus the // wysiwyg on update cleanup(); - const updateElement = Scene.getScene(element)?.getElement(element.id); + const updateElement = Scene.getScene(element)?.getElement( + element.id, + ) as ExcalidrawTextElement; if (!updateElement) { return; } - let wrappedText = ""; - if (isTextElement(updateElement) && updateElement?.containerId) { - const container = getContainerElement(updateElement); + let text = editable.value; + const container = getContainerElement(updateElement); - if (container) { - wrappedText = wrapText( - editable.value, - getFontString(updateElement), - container.width, - ); - - if (updateElement.containerId) { - const editorHeight = Number(editable.style.height.slice(0, -2)); - if (editable.value) { - // Don't mutate if text is not updated - if (initialText !== editable.value) { - mutateElement(updateElement, { - // vertically center align - y: container.y + container.height / 2 - editorHeight / 2, - height: editorHeight, - width: Number(editable.style.width.slice(0, -2)), - // preserve padding - x: container.x + BOUND_TEXT_PADDING, - angle: container.angle, - }); - } - - const boundTextElementId = getBoundTextElementId(container); - if (!boundTextElementId || boundTextElementId !== element.id) { - mutateElement(container, { - boundElements: (container.boundElements || []).concat({ - type: "text", - id: element.id, - }), - }); - } - } else { - mutateElement(container, { - boundElements: container.boundElements?.filter( - (ele) => ele.type !== "text", - ), - }); - } + if (container) { + text = updateElement.text; + if (editable.value) { + const boundTextElementId = getBoundTextElementId(container); + if (!boundTextElementId || boundTextElementId !== element.id) { + mutateElement(container, { + boundElements: (container.boundElements || []).concat({ + type: "text", + id: element.id, + }), + }); } + } else { + mutateElement(container, { + boundElements: container.boundElements?.filter( + (ele) => + !isTextElement( + ele as ExcalidrawTextElement | ExcalidrawLinearElement, + ), + ), + }); } - } else { - wrappedText = editable.value; } onSubmit({ - text: normalizeText(wrappedText), + text, viaKeyboard: submittedViaKeyboard, originalText: editable.value, }); diff --git a/src/packages/excalidraw/index.tsx b/src/packages/excalidraw/index.tsx index 060908a5..60cc4ec2 100644 --- a/src/packages/excalidraw/index.tsx +++ b/src/packages/excalidraw/index.tsx @@ -17,7 +17,7 @@ const Excalidraw = (props: ExcalidrawProps) => { initialData, excalidrawRef, onCollabButtonClick, - isCollaborating, + isCollaborating = false, onPointerUpdate, renderTopRightUI, renderFooter, diff --git a/src/tests/binding.test.tsx b/src/tests/binding.test.tsx index 90f11ed9..656d3bea 100644 --- a/src/tests/binding.test.tsx +++ b/src/tests/binding.test.tsx @@ -158,11 +158,8 @@ describe("element binding", () => { expect(editor).not.toBe(null); - // we defer binding blur event on wysiwyg, hence wait a bit - await new Promise((r) => setTimeout(r, 30)); - fireEvent.change(editor, { target: { value: "" } }); - editor.blur(); + fireEvent.keyDown(editor, { key: KEYS.ESCAPE }); expect( document.querySelector(".excalidraw-textEditorContainer > textarea"), @@ -202,11 +199,8 @@ describe("element binding", () => { expect(editor).not.toBe(null); - // we defer binding blur event on wysiwyg, hence wait a bit - await new Promise((r) => setTimeout(r, 30)); - fireEvent.change(editor, { target: { value: "asdasdasdasdas" } }); - editor.blur(); + fireEvent.keyDown(editor, { key: KEYS.ESCAPE }); expect( document.querySelector(".excalidraw-textEditorContainer > textarea"), diff --git a/src/types.ts b/src/types.ts index cd0e2ee7..c6908c04 100644 --- a/src/types.ts +++ b/src/types.ts @@ -300,6 +300,7 @@ export type AppProps = ExcalidrawProps & { }; detectScroll: boolean; handleKeyboardGlobally: boolean; + isCollaborating: boolean; }; /** A subset of App class properties that we need to use elsewhere