Kaynağa Gözat

feat: expose `applyTo` options, don't commit empty text element (#9744)

* Expose applyTo options, skip re-draw for empty text

* Don't commit empty text elements
Marcel Mraz 1 ay önce
ebeveyn
işleme
e46f038132

+ 10 - 2
packages/element/src/store.ts

@@ -27,6 +27,8 @@ import {
   isImageElement,
 } from "./index";
 
+import type { ApplyToOptions } from "./delta";
+
 import type {
   ExcalidrawElement,
   OrderedExcalidrawElement,
@@ -570,9 +572,15 @@ export class StoreDelta {
     delta: StoreDelta,
     elements: SceneElementsMap,
     appState: AppState,
+    options: ApplyToOptions = {
+      excludedProperties: new Set(),
+    },
   ): [SceneElementsMap, AppState, boolean] {
-    const [nextElements, elementsContainVisibleChange] =
-      delta.elements.applyTo(elements);
+    const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(
+      elements,
+      StoreSnapshot.empty().elements,
+      options,
+    );
 
     const [nextAppState, appStateContainsVisibleChange] =
       delta.appState.applyTo(appState, nextElements);

+ 15 - 4
packages/excalidraw/components/App.tsx

@@ -4925,7 +4925,17 @@ class App extends React.Component<AppProps, AppState> {
       }),
       onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
         const isDeleted = !nextOriginalText.trim();
-        updateElement(nextOriginalText, isDeleted);
+
+        if (isDeleted && !isExistingElement) {
+          // let's just remove the element from the scene, as it's an empty just created text element
+          this.scene.replaceAllElements(
+            this.scene
+              .getElementsIncludingDeleted()
+              .filter((x) => x.id !== element.id),
+          );
+        } else {
+          updateElement(nextOriginalText, 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) {
@@ -4954,9 +4964,10 @@ class App extends React.Component<AppProps, AppState> {
             element,
           ]);
         }
-        if (!isDeleted || isExistingElement) {
-          this.store.scheduleCapture();
-        }
+
+        // we need to record either way, whether the text element was added or removed
+        // since we need to sync this delta to other clients, otherwise it would end up with inconsistencies
+        this.store.scheduleCapture();
 
         flushSync(() => {
           this.setState({

+ 2 - 2
packages/excalidraw/wysiwyg/textWysiwyg.test.tsx

@@ -704,7 +704,7 @@ describe("textWysiwyg", () => {
         rectangle.x + rectangle.width / 2,
         rectangle.y + rectangle.height / 2,
       );
-      expect(h.elements.length).toBe(3);
+      expect(h.elements.length).toBe(2);
 
       text = h.elements[1] as ExcalidrawTextElementWithContainer;
       expect(text.type).toBe("text");
@@ -1198,7 +1198,7 @@ describe("textWysiwyg", () => {
       updateTextEditor(editor, "   ");
       Keyboard.exitTextEditor(editor);
       expect(rectangle.boundElements).toStrictEqual([]);
-      expect(h.elements[1].isDeleted).toBe(true);
+      expect(h.elements[1]).toBeUndefined();
     });
 
     it("should restore original container height and clear cache once text is unbind", async () => {