浏览代码

fix: restore from invalid fixedSegments & type-safer point updates (#9899)

* fix: restore from invalid fixedSegments & type-safer point updates

* fix: Type updates and throw for invalid point states

---------

Co-authored-by: Mark Tolmacs <[email protected]>
David Luzar 2 周之前
父节点
当前提交
531f3e5524
共有 2 个文件被更改,包括 34 次插入18 次删除
  1. 30 17
      packages/element/src/elbowArrow.ts
  2. 4 1
      packages/excalidraw/data/restore.ts

+ 30 - 17
packages/element/src/elbowArrow.ts

@@ -359,6 +359,12 @@ const handleSegmentRelease = (
     null,
   );
 
+  if (!restoredPoints || restoredPoints.length < 2) {
+    throw new Error(
+      "Property 'points' is required in the update returned by normalizeArrowElementUpdate()",
+    );
+  }
+
   const nextPoints: GlobalPoint[] = [];
 
   // First part of the arrow are the old points
@@ -706,7 +712,7 @@ const handleEndpointDrag = (
   endGlobalPoint: GlobalPoint,
   hoveredStartElement: ExcalidrawBindableElement | null,
   hoveredEndElement: ExcalidrawBindableElement | null,
-) => {
+): ElementUpdate<ExcalidrawElbowArrowElement> => {
   let startIsSpecial = arrow.startIsSpecial ?? null;
   let endIsSpecial = arrow.endIsSpecial ?? null;
   const globalUpdatedPoints = updatedPoints.map((p, i) =>
@@ -741,8 +747,15 @@ const handleEndpointDrag = (
 
   // Calculate the moving second point connection and add the start point
   {
-    const secondPoint = globalUpdatedPoints[startIsSpecial ? 2 : 1];
-    const thirdPoint = globalUpdatedPoints[startIsSpecial ? 3 : 2];
+    const secondPoint = globalUpdatedPoints.at(startIsSpecial ? 2 : 1);
+    const thirdPoint = globalUpdatedPoints.at(startIsSpecial ? 3 : 2);
+
+    if (!secondPoint || !thirdPoint) {
+      throw new Error(
+        `Second and third points must exist when handling endpoint drag (${startIsSpecial})`,
+      );
+    }
+
     const startIsHorizontal = headingIsHorizontal(startHeading);
     const secondIsHorizontal = headingIsHorizontal(
       vectorToHeading(vectorFromPoint(secondPoint, thirdPoint)),
@@ -801,10 +814,19 @@ const handleEndpointDrag = (
 
   // Calculate the moving second to last point connection
   {
-    const secondToLastPoint =
-      globalUpdatedPoints[globalUpdatedPoints.length - (endIsSpecial ? 3 : 2)];
-    const thirdToLastPoint =
-      globalUpdatedPoints[globalUpdatedPoints.length - (endIsSpecial ? 4 : 3)];
+    const secondToLastPoint = globalUpdatedPoints.at(
+      globalUpdatedPoints.length - (endIsSpecial ? 3 : 2),
+    );
+    const thirdToLastPoint = globalUpdatedPoints.at(
+      globalUpdatedPoints.length - (endIsSpecial ? 4 : 3),
+    );
+
+    if (!secondToLastPoint || !thirdToLastPoint) {
+      throw new Error(
+        `Second and third to last points must exist when handling endpoint drag (${endIsSpecial})`,
+      );
+    }
+
     const endIsHorizontal = headingIsHorizontal(endHeading);
     const secondIsHorizontal = headingForPointIsHorizontal(
       thirdToLastPoint,
@@ -2071,16 +2093,7 @@ const normalizeArrowElementUpdate = (
   nextFixedSegments: readonly FixedSegment[] | null,
   startIsSpecial?: ExcalidrawElbowArrowElement["startIsSpecial"],
   endIsSpecial?: ExcalidrawElbowArrowElement["startIsSpecial"],
-): {
-  points: LocalPoint[];
-  x: number;
-  y: number;
-  width: number;
-  height: number;
-  fixedSegments: readonly FixedSegment[] | null;
-  startIsSpecial?: ExcalidrawElbowArrowElement["startIsSpecial"];
-  endIsSpecial?: ExcalidrawElbowArrowElement["startIsSpecial"];
-} => {
+): ElementUpdate<ExcalidrawElbowArrowElement> => {
   const offsetX = global[0][0];
   const offsetY = global[0][1];
   let points = global.map((p) =>

+ 4 - 1
packages/excalidraw/data/restore.ts

@@ -387,7 +387,10 @@ export const restoreElement = (
             elbowed: true,
             startBinding: repairBinding(element, element.startBinding),
             endBinding: repairBinding(element, element.endBinding),
-            fixedSegments: element.fixedSegments,
+            fixedSegments:
+              element.fixedSegments?.length && base.points.length >= 4
+                ? element.fixedSegments
+                : null,
             startIsSpecial: element.startIsSpecial,
             endIsSpecial: element.endIsSpecial,
           })