Skip to content

Commit a517bbe

Browse files
committed
Merge master
2 parents bec0322 + 14d512f commit a517bbe

25 files changed

+857
-135
lines changed

.env.development

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
MODE="development"
2+
13
VITE_APP_BACKEND_V2_GET_URL=https://json-dev.excalidraw.com/api/v2/
24
VITE_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/
35

.env.production

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
MODE="production"
2+
13
VITE_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/
24
VITE_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
35

packages/element/src/delta.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,12 @@ export class Delta<T> {
187187
return;
188188
}
189189

190-
if (
191-
typeof deleted[property] === "object" ||
192-
typeof inserted[property] === "object"
193-
) {
190+
const isDeletedObject =
191+
deleted[property] !== null && typeof deleted[property] === "object";
192+
const isInsertedObject =
193+
inserted[property] !== null && typeof inserted[property] === "object";
194+
195+
if (isDeletedObject || isInsertedObject) {
194196
type RecordLike = Record<string, V | undefined>;
195197

196198
const deletedObject: RecordLike = deleted[property] ?? {};
@@ -222,6 +224,9 @@ export class Delta<T> {
222224
Reflect.deleteProperty(deleted, property);
223225
Reflect.deleteProperty(inserted, property);
224226
}
227+
} else if (deleted[property] === inserted[property]) {
228+
Reflect.deleteProperty(deleted, property);
229+
Reflect.deleteProperty(inserted, property);
225230
}
226231
}
227232

@@ -658,6 +663,24 @@ export class AppStateDelta implements DeltaContainer<AppState> {
658663
}
659664

660665
break;
666+
case "lockedMultiSelections": {
667+
const prevLockedUnits = prevAppState[key] || {};
668+
const nextLockedUnits = nextAppState[key] || {};
669+
670+
if (!isShallowEqual(prevLockedUnits, nextLockedUnits)) {
671+
visibleDifferenceFlag.value = true;
672+
}
673+
break;
674+
}
675+
case "activeLockedId": {
676+
const prevHitLockedId = prevAppState[key] || null;
677+
const nextHitLockedId = nextAppState[key] || null;
678+
679+
if (prevHitLockedId !== nextHitLockedId) {
680+
visibleDifferenceFlag.value = true;
681+
}
682+
break;
683+
}
661684
default: {
662685
assertNever(
663686
key,
@@ -753,6 +776,8 @@ export class AppStateDelta implements DeltaContainer<AppState> {
753776
editingLinearElementId,
754777
selectedLinearElementId,
755778
croppingElementId,
779+
lockedMultiSelections,
780+
activeLockedId,
756781
...standaloneProps
757782
} = delta as ObservedAppState;
758783

@@ -797,6 +822,18 @@ export class AppStateDelta implements DeltaContainer<AppState> {
797822
"selectedGroupIds",
798823
(prevValue) => (prevValue ?? false) as ValueOf<T["selectedGroupIds"]>,
799824
);
825+
Delta.diffObjects(
826+
deleted,
827+
inserted,
828+
"lockedMultiSelections",
829+
(prevValue) => (prevValue ?? {}) as ValueOf<T["lockedMultiSelections"]>,
830+
);
831+
Delta.diffObjects(
832+
deleted,
833+
inserted,
834+
"activeLockedId",
835+
(prevValue) => (prevValue ?? null) as ValueOf<T["activeLockedId"]>,
836+
);
800837
} catch (e) {
801838
// if postprocessing fails it does not make sense to bubble up, but let's make sure we know about it
802839
console.error(`Couldn't postprocess appstate change deltas.`);

packages/element/src/elbowArrow.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,25 @@ export const updateElbowArrowPoints = (
974974
),
975975
"Elbow arrow segments must be either horizontal or vertical",
976976
);
977+
978+
invariant(
979+
updates.fixedSegments?.find(
980+
(segment) =>
981+
segment.index === 1 &&
982+
pointsEqual(segment.start, (updates.points ?? arrow.points)[0]),
983+
) == null &&
984+
updates.fixedSegments?.find(
985+
(segment) =>
986+
segment.index === (updates.points ?? arrow.points).length - 1 &&
987+
pointsEqual(
988+
segment.end,
989+
(updates.points ?? arrow.points)[
990+
(updates.points ?? arrow.points).length - 1
991+
],
992+
),
993+
) == null,
994+
"The first and last segments cannot be fixed",
995+
);
977996
}
978997

979998
const fixedSegments = updates.fixedSegments ?? arrow.fixedSegments ?? [];

packages/element/src/linearElementEditor.ts

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ import type {
8585
PointsPositionUpdates,
8686
} from "./types";
8787

88-
const editorMidPointsCache: {
89-
version: number | null;
90-
points: (GlobalPoint | null)[];
91-
zoom: number | null;
92-
} = { version: null, points: [], zoom: null };
9388
export class LinearElementEditor {
9489
public readonly elementId: ExcalidrawElement["id"] & {
9590
_brand: "excalidrawLinearElementId";
@@ -536,7 +531,7 @@ export class LinearElementEditor {
536531
element: NonDeleted<ExcalidrawLinearElement>,
537532
elementsMap: ElementsMap,
538533
appState: InteractiveCanvasAppState,
539-
): typeof editorMidPointsCache["points"] => {
534+
): (GlobalPoint | null)[] => {
540535
const boundText = getBoundTextElement(element, elementsMap);
541536

542537
// Since its not needed outside editor unless 2 pointer lines or bound text
@@ -548,25 +543,7 @@ export class LinearElementEditor {
548543
) {
549544
return [];
550545
}
551-
if (
552-
editorMidPointsCache.version === element.version &&
553-
editorMidPointsCache.zoom === appState.zoom.value
554-
) {
555-
return editorMidPointsCache.points;
556-
}
557-
LinearElementEditor.updateEditorMidPointsCache(
558-
element,
559-
elementsMap,
560-
appState,
561-
);
562-
return editorMidPointsCache.points!;
563-
};
564546

565-
static updateEditorMidPointsCache = (
566-
element: NonDeleted<ExcalidrawLinearElement>,
567-
elementsMap: ElementsMap,
568-
appState: InteractiveCanvasAppState,
569-
) => {
570547
const points = LinearElementEditor.getPointsGlobalCoordinates(
571548
element,
572549
elementsMap,
@@ -598,9 +575,8 @@ export class LinearElementEditor {
598575
midpoints.push(segmentMidPoint);
599576
index++;
600577
}
601-
editorMidPointsCache.points = midpoints;
602-
editorMidPointsCache.version = element.version;
603-
editorMidPointsCache.zoom = appState.zoom.value;
578+
579+
return midpoints;
604580
};
605581

606582
static getSegmentMidpointHitCoords = (
@@ -654,8 +630,11 @@ export class LinearElementEditor {
654630
}
655631
}
656632
let index = 0;
657-
const midPoints: typeof editorMidPointsCache["points"] =
658-
LinearElementEditor.getEditorMidPoints(element, elementsMap, appState);
633+
const midPoints = LinearElementEditor.getEditorMidPoints(
634+
element,
635+
elementsMap,
636+
appState,
637+
);
659638

660639
while (index < midPoints.length) {
661640
if (midPoints[index] !== null) {
@@ -1611,23 +1590,14 @@ export class LinearElementEditor {
16111590
y = midPoint[1] - boundTextElement.height / 2;
16121591
} else {
16131592
const index = element.points.length / 2 - 1;
1593+
const midSegmentMidpoint = LinearElementEditor.getSegmentMidPoint(
1594+
element,
1595+
points[index],
1596+
points[index + 1],
1597+
index + 1,
1598+
elementsMap,
1599+
);
16141600

1615-
let midSegmentMidpoint = editorMidPointsCache.points[index];
1616-
if (element.points.length === 2) {
1617-
midSegmentMidpoint = pointCenter(points[0], points[1]);
1618-
}
1619-
if (
1620-
!midSegmentMidpoint ||
1621-
editorMidPointsCache.version !== element.version
1622-
) {
1623-
midSegmentMidpoint = LinearElementEditor.getSegmentMidPoint(
1624-
element,
1625-
points[index],
1626-
points[index + 1],
1627-
index + 1,
1628-
elementsMap,
1629-
);
1630-
}
16311601
x = midSegmentMidpoint[0] - boundTextElement.width / 2;
16321602
y = midSegmentMidpoint[1] - boundTextElement.height / 2;
16331603
}

packages/element/src/store.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,8 @@ const getDefaultObservedAppState = (): ObservedAppState => {
939939
editingLinearElementId: null,
940940
selectedLinearElementId: null,
941941
croppingElementId: null,
942+
activeLockedId: null,
943+
lockedMultiSelections: {},
942944
};
943945
};
944946

@@ -952,6 +954,8 @@ export const getObservedAppState = (appState: AppState): ObservedAppState => {
952954
editingLinearElementId: appState.editingLinearElement?.elementId || null,
953955
selectedLinearElementId: appState.selectedLinearElement?.elementId || null,
954956
croppingElementId: appState.croppingElementId,
957+
activeLockedId: appState.activeLockedId,
958+
lockedMultiSelections: appState.lockedMultiSelections,
955959
};
956960

957961
Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {

packages/element/tests/delta.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ describe("AppStateDelta", () => {
1616
editingGroupId: null,
1717
croppingElementId: null,
1818
editingLinearElementId: null,
19+
lockedMultiSelections: {},
20+
activeLockedId: null,
1921
};
2022

2123
const prevAppState1: ObservedAppState = {
@@ -57,6 +59,8 @@ describe("AppStateDelta", () => {
5759
croppingElementId: null,
5860
selectedLinearElementId: null,
5961
editingLinearElementId: null,
62+
activeLockedId: null,
63+
lockedMultiSelections: {},
6064
};
6165

6266
const prevAppState1: ObservedAppState = {
@@ -102,6 +106,8 @@ describe("AppStateDelta", () => {
102106
croppingElementId: null,
103107
selectedLinearElementId: null,
104108
editingLinearElementId: null,
109+
activeLockedId: null,
110+
lockedMultiSelections: {},
105111
};
106112

107113
const prevAppState1: ObservedAppState = {

0 commit comments

Comments
 (0)