mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: fractional indexing (#7359)
* Introducing fractional indices as part of `element.index` * Ensuring invalid fractional indices are always synchronized with the array order * Simplifying reconciliation based on the fractional indices * Moving reconciliation inside the `@excalidraw/excalidraw` package --------- Co-authored-by: Marcel Mraz <marcel@excalidraw.com> Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
bbdcd30a73
commit
32df5502ae
50 changed files with 3640 additions and 2047 deletions
|
@ -20,6 +20,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"groupIds": [],
|
||||
"height": 300,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -32,7 +33,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 300,
|
||||
"x": 630,
|
||||
|
@ -56,6 +57,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -68,7 +70,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"strokeWidth": 2,
|
||||
"type": "diamond",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 140,
|
||||
"x": 96,
|
||||
|
@ -93,6 +95,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"groupIds": [],
|
||||
"height": 35,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -122,7 +125,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 395,
|
||||
"x": 247,
|
||||
|
@ -147,6 +150,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -176,7 +180,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 400,
|
||||
"x": 227,
|
||||
|
@ -200,6 +204,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"groupIds": [],
|
||||
"height": 300,
|
||||
"id": Any<String>,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -212,7 +217,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 300,
|
||||
"x": -53,
|
||||
|
@ -239,6 +244,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -255,7 +261,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 70,
|
||||
|
@ -283,6 +289,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -299,7 +306,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 100,
|
||||
|
@ -330,6 +337,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -359,7 +367,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 255,
|
||||
|
@ -381,6 +389,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -397,7 +406,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
@ -428,6 +437,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -457,7 +467,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 255,
|
||||
|
@ -479,6 +489,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -495,7 +506,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
@ -520,6 +531,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -532,7 +544,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 155,
|
||||
|
@ -556,6 +568,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -568,7 +581,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 355,
|
||||
|
@ -598,6 +611,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -627,7 +641,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 255,
|
||||
|
@ -649,6 +663,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -665,7 +680,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
@ -693,6 +708,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -709,7 +725,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 70,
|
||||
|
@ -737,6 +753,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -753,7 +770,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 100,
|
||||
|
@ -773,6 +790,7 @@ exports[`Test Transform > should not allow duplicate ids 1`] = `
|
|||
"groupIds": [],
|
||||
"height": 200,
|
||||
"id": "rect-1",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -785,7 +803,7 @@ exports[`Test Transform > should not allow duplicate ids 1`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 300,
|
||||
|
@ -806,6 +824,7 @@ exports[`Test Transform > should transform linear elements 1`] = `
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -831,7 +850,7 @@ exports[`Test Transform > should transform linear elements 1`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -852,6 +871,7 @@ exports[`Test Transform > should transform linear elements 2`] = `
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -877,7 +897,7 @@ exports[`Test Transform > should transform linear elements 2`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 450,
|
||||
|
@ -898,6 +918,7 @@ exports[`Test Transform > should transform linear elements 3`] = `
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -923,7 +944,7 @@ exports[`Test Transform > should transform linear elements 3`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -944,6 +965,7 @@ exports[`Test Transform > should transform linear elements 4`] = `
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -969,7 +991,7 @@ exports[`Test Transform > should transform linear elements 4`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "line",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 450,
|
||||
|
@ -988,6 +1010,7 @@ exports[`Test Transform > should transform regular shapes 1`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1000,7 +1023,7 @@ exports[`Test Transform > should transform regular shapes 1`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1019,6 +1042,7 @@ exports[`Test Transform > should transform regular shapes 2`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1031,7 +1055,7 @@ exports[`Test Transform > should transform regular shapes 2`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1050,6 +1074,7 @@ exports[`Test Transform > should transform regular shapes 3`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1062,7 +1087,7 @@ exports[`Test Transform > should transform regular shapes 3`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "diamond",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1081,6 +1106,7 @@ exports[`Test Transform > should transform regular shapes 4`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1093,7 +1119,7 @@ exports[`Test Transform > should transform regular shapes 4`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 300,
|
||||
|
@ -1112,6 +1138,7 @@ exports[`Test Transform > should transform regular shapes 5`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1124,7 +1151,7 @@ exports[`Test Transform > should transform regular shapes 5`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 300,
|
||||
|
@ -1143,6 +1170,7 @@ exports[`Test Transform > should transform regular shapes 6`] = `
|
|||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": Any<String>,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1155,7 +1183,7 @@ exports[`Test Transform > should transform regular shapes 6`] = `
|
|||
"strokeWidth": 2,
|
||||
"type": "diamond",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 300,
|
||||
|
@ -1177,6 +1205,7 @@ exports[`Test Transform > should transform text element 1`] = `
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1193,7 +1222,7 @@ exports[`Test Transform > should transform text element 1`] = `
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 120,
|
||||
|
@ -1216,6 +1245,7 @@ exports[`Test Transform > should transform text element 2`] = `
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1232,7 +1262,7 @@ exports[`Test Transform > should transform text element 2`] = `
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 190,
|
||||
|
@ -1259,6 +1289,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -1284,7 +1315,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1310,6 +1341,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -1335,7 +1367,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1361,6 +1393,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -1386,7 +1419,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1412,6 +1445,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 0,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"lastCommittedPoint": null,
|
||||
"link": null,
|
||||
|
@ -1437,7 +1471,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "arrow",
|
||||
"updated": 1,
|
||||
"version": 1,
|
||||
"version": 2,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 100,
|
||||
"x": 100,
|
||||
|
@ -1459,6 +1493,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1475,7 +1510,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
@ -1498,6 +1533,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1514,7 +1550,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 200,
|
||||
|
@ -1537,6 +1573,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 50,
|
||||
"id": Any<String>,
|
||||
"index": "a6",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1554,7 +1591,7 @@ LABELLED ARROW",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 150,
|
||||
|
@ -1577,6 +1614,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
|
|||
"groupIds": [],
|
||||
"height": 50,
|
||||
"id": Any<String>,
|
||||
"index": "a7",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1594,7 +1632,7 @@ LABELLED ARROW",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 150,
|
||||
|
@ -1619,6 +1657,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 35,
|
||||
"id": Any<String>,
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1631,7 +1670,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"version": 4,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 250,
|
||||
"x": 100,
|
||||
|
@ -1655,6 +1694,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 85,
|
||||
"id": Any<String>,
|
||||
"index": "a1",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1667,7 +1707,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 500,
|
||||
|
@ -1691,6 +1731,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 170,
|
||||
"id": Any<String>,
|
||||
"index": "a2",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1703,7 +1744,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "diamond",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 280,
|
||||
"x": 100,
|
||||
|
@ -1727,6 +1768,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 120,
|
||||
"id": Any<String>,
|
||||
"index": "a3",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1739,7 +1781,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "diamond",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 300,
|
||||
"x": 100,
|
||||
|
@ -1763,6 +1805,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 85,
|
||||
"id": Any<String>,
|
||||
"index": "a4",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1775,7 +1818,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 500,
|
||||
|
@ -1799,6 +1842,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 120,
|
||||
"id": Any<String>,
|
||||
"index": "a5",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
|
@ -1811,7 +1855,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"strokeWidth": 2,
|
||||
"type": "ellipse",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"width": 200,
|
||||
"x": 500,
|
||||
|
@ -1833,6 +1877,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 25,
|
||||
"id": Any<String>,
|
||||
"index": "a6",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1849,7 +1894,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 240,
|
||||
|
@ -1872,6 +1917,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 50,
|
||||
"id": Any<String>,
|
||||
"index": "a7",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1889,7 +1935,7 @@ CONTAINER",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
@ -1912,6 +1958,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 75,
|
||||
"id": Any<String>,
|
||||
"index": "a8",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1931,7 +1978,7 @@ CONTAINER",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 90,
|
||||
|
@ -1954,6 +2001,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 50,
|
||||
"id": Any<String>,
|
||||
"index": "a9",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -1971,7 +2019,7 @@ TEXT CONTAINER",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 140,
|
||||
|
@ -1994,6 +2042,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 75,
|
||||
"id": Any<String>,
|
||||
"index": "aA",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -2012,7 +2061,7 @@ CONTAINER",
|
|||
"textAlign": "left",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "top",
|
||||
"width": 170,
|
||||
|
@ -2035,6 +2084,7 @@ exports[`Test Transform > should transform to text containers when label provide
|
|||
"groupIds": [],
|
||||
"height": 75,
|
||||
"id": Any<String>,
|
||||
"index": "aB",
|
||||
"isDeleted": false,
|
||||
"lineHeight": 1.25,
|
||||
"link": null,
|
||||
|
@ -2053,7 +2103,7 @@ CONTAINER",
|
|||
"textAlign": "center",
|
||||
"type": "text",
|
||||
"updated": 1,
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"versionNonce": Any<Number>,
|
||||
"verticalAlign": "middle",
|
||||
"width": 130,
|
||||
|
|
79
packages/excalidraw/data/reconcile.ts
Normal file
79
packages/excalidraw/data/reconcile.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { OrderedExcalidrawElement } from "../element/types";
|
||||
import { orderByFractionalIndex, syncInvalidIndices } from "../fractionalIndex";
|
||||
import { AppState } from "../types";
|
||||
import { MakeBrand } from "../utility-types";
|
||||
import { arrayToMap } from "../utils";
|
||||
|
||||
export type ReconciledExcalidrawElement = OrderedExcalidrawElement &
|
||||
MakeBrand<"ReconciledElement">;
|
||||
|
||||
export type RemoteExcalidrawElement = OrderedExcalidrawElement &
|
||||
MakeBrand<"RemoteExcalidrawElement">;
|
||||
|
||||
const shouldDiscardRemoteElement = (
|
||||
localAppState: AppState,
|
||||
local: OrderedExcalidrawElement | undefined,
|
||||
remote: RemoteExcalidrawElement,
|
||||
): boolean => {
|
||||
if (
|
||||
local &&
|
||||
// local element is being edited
|
||||
(local.id === localAppState.editingElement?.id ||
|
||||
local.id === localAppState.resizingElement?.id ||
|
||||
local.id === localAppState.draggingElement?.id ||
|
||||
// local element is newer
|
||||
local.version > remote.version ||
|
||||
// resolve conflicting edits deterministically by taking the one with
|
||||
// the lowest versionNonce
|
||||
(local.version === remote.version &&
|
||||
local.versionNonce < remote.versionNonce))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const reconcileElements = (
|
||||
localElements: readonly OrderedExcalidrawElement[],
|
||||
remoteElements: readonly RemoteExcalidrawElement[],
|
||||
localAppState: AppState,
|
||||
): ReconciledExcalidrawElement[] => {
|
||||
const localElementsMap = arrayToMap(localElements);
|
||||
const reconciledElements: OrderedExcalidrawElement[] = [];
|
||||
const added = new Set<string>();
|
||||
|
||||
// process remote elements
|
||||
for (const remoteElement of remoteElements) {
|
||||
if (!added.has(remoteElement.id)) {
|
||||
const localElement = localElementsMap.get(remoteElement.id);
|
||||
const discardRemoteElement = shouldDiscardRemoteElement(
|
||||
localAppState,
|
||||
localElement,
|
||||
remoteElement,
|
||||
);
|
||||
|
||||
if (localElement && discardRemoteElement) {
|
||||
reconciledElements.push(localElement);
|
||||
added.add(localElement.id);
|
||||
} else {
|
||||
reconciledElements.push(remoteElement);
|
||||
added.add(remoteElement.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process remaining local elements
|
||||
for (const localElement of localElements) {
|
||||
if (!added.has(localElement.id)) {
|
||||
reconciledElements.push(localElement);
|
||||
added.add(localElement.id);
|
||||
}
|
||||
}
|
||||
|
||||
const orderedElements = orderByFractionalIndex(reconciledElements);
|
||||
|
||||
// de-duplicate indices
|
||||
syncInvalidIndices(orderedElements);
|
||||
|
||||
return orderedElements as ReconciledExcalidrawElement[];
|
||||
};
|
|
@ -4,6 +4,7 @@ import {
|
|||
ExcalidrawSelectionElement,
|
||||
ExcalidrawTextElement,
|
||||
FontFamilyValues,
|
||||
OrderedExcalidrawElement,
|
||||
PointBinding,
|
||||
StrokeRoundness,
|
||||
} from "../element/types";
|
||||
|
@ -26,7 +27,6 @@ import {
|
|||
DEFAULT_FONT_FAMILY,
|
||||
DEFAULT_TEXT_ALIGN,
|
||||
DEFAULT_VERTICAL_ALIGN,
|
||||
PRECEDING_ELEMENT_KEY,
|
||||
FONT_FAMILY,
|
||||
ROUNDNESS,
|
||||
DEFAULT_SIDEBAR,
|
||||
|
@ -44,6 +44,7 @@ import {
|
|||
getDefaultLineHeight,
|
||||
} from "../element/textElement";
|
||||
import { normalizeLink } from "./url";
|
||||
import { syncInvalidIndices } from "../fractionalIndex";
|
||||
|
||||
type RestoredAppState = Omit<
|
||||
AppState,
|
||||
|
@ -73,7 +74,7 @@ export const AllowedExcalidrawActiveTools: Record<
|
|||
};
|
||||
|
||||
export type RestoredDataState = {
|
||||
elements: ExcalidrawElement[];
|
||||
elements: OrderedExcalidrawElement[];
|
||||
appState: RestoredAppState;
|
||||
files: BinaryFiles;
|
||||
};
|
||||
|
@ -101,8 +102,6 @@ const restoreElementWithProperties = <
|
|||
boundElementIds?: readonly ExcalidrawElement["id"][];
|
||||
/** @deprecated */
|
||||
strokeSharpness?: StrokeRoundness;
|
||||
/** metadata that may be present in elements during collaboration */
|
||||
[PRECEDING_ELEMENT_KEY]?: string;
|
||||
},
|
||||
K extends Pick<T, keyof Omit<Required<T>, keyof ExcalidrawElement>>,
|
||||
>(
|
||||
|
@ -115,14 +114,13 @@ const restoreElementWithProperties = <
|
|||
> &
|
||||
Partial<Pick<ExcalidrawElement, "type" | "x" | "y" | "customData">>,
|
||||
): T => {
|
||||
const base: Pick<T, keyof ExcalidrawElement> & {
|
||||
[PRECEDING_ELEMENT_KEY]?: string;
|
||||
} = {
|
||||
const base: Pick<T, keyof ExcalidrawElement> = {
|
||||
type: extra.type || element.type,
|
||||
// all elements must have version > 0 so getSceneVersion() will pick up
|
||||
// newly added elements
|
||||
version: element.version || 1,
|
||||
versionNonce: element.versionNonce ?? 0,
|
||||
index: element.index ?? null,
|
||||
isDeleted: element.isDeleted ?? false,
|
||||
id: element.id || randomId(),
|
||||
fillStyle: element.fillStyle || DEFAULT_ELEMENT_PROPS.fillStyle,
|
||||
|
@ -166,10 +164,6 @@ const restoreElementWithProperties = <
|
|||
"customData" in extra ? extra.customData : element.customData;
|
||||
}
|
||||
|
||||
if (PRECEDING_ELEMENT_KEY in element) {
|
||||
base[PRECEDING_ELEMENT_KEY] = element[PRECEDING_ELEMENT_KEY];
|
||||
}
|
||||
|
||||
return {
|
||||
...base,
|
||||
...getNormalizedDimensions(base),
|
||||
|
@ -407,30 +401,35 @@ export const restoreElements = (
|
|||
/** NOTE doesn't serve for reconciliation */
|
||||
localElements: readonly ExcalidrawElement[] | null | undefined,
|
||||
opts?: { refreshDimensions?: boolean; repairBindings?: boolean } | undefined,
|
||||
): ExcalidrawElement[] => {
|
||||
): OrderedExcalidrawElement[] => {
|
||||
// used to detect duplicate top-level element ids
|
||||
const existingIds = new Set<string>();
|
||||
const localElementsMap = localElements ? arrayToMap(localElements) : null;
|
||||
const restoredElements = (elements || []).reduce((elements, element) => {
|
||||
// filtering out selection, which is legacy, no longer kept in elements,
|
||||
// and causing issues if retained
|
||||
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
|
||||
let migratedElement: ExcalidrawElement | null = restoreElement(element);
|
||||
if (migratedElement) {
|
||||
const localElement = localElementsMap?.get(element.id);
|
||||
if (localElement && localElement.version > migratedElement.version) {
|
||||
migratedElement = bumpVersion(migratedElement, localElement.version);
|
||||
}
|
||||
if (existingIds.has(migratedElement.id)) {
|
||||
migratedElement = { ...migratedElement, id: randomId() };
|
||||
}
|
||||
existingIds.add(migratedElement.id);
|
||||
const restoredElements = syncInvalidIndices(
|
||||
(elements || []).reduce((elements, element) => {
|
||||
// filtering out selection, which is legacy, no longer kept in elements,
|
||||
// and causing issues if retained
|
||||
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
|
||||
let migratedElement: ExcalidrawElement | null = restoreElement(element);
|
||||
if (migratedElement) {
|
||||
const localElement = localElementsMap?.get(element.id);
|
||||
if (localElement && localElement.version > migratedElement.version) {
|
||||
migratedElement = bumpVersion(
|
||||
migratedElement,
|
||||
localElement.version,
|
||||
);
|
||||
}
|
||||
if (existingIds.has(migratedElement.id)) {
|
||||
migratedElement = { ...migratedElement, id: randomId() };
|
||||
}
|
||||
existingIds.add(migratedElement.id);
|
||||
|
||||
elements.push(migratedElement);
|
||||
elements.push(migratedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}, [] as ExcalidrawElement[]);
|
||||
return elements;
|
||||
}, [] as ExcalidrawElement[]),
|
||||
);
|
||||
|
||||
if (!opts?.repairBindings) {
|
||||
return restoredElements;
|
||||
|
|
|
@ -44,9 +44,16 @@ import {
|
|||
VerticalAlign,
|
||||
} from "../element/types";
|
||||
import { MarkOptional } from "../utility-types";
|
||||
import { assertNever, cloneJSON, getFontString, toBrandedType } from "../utils";
|
||||
import {
|
||||
arrayToMap,
|
||||
assertNever,
|
||||
cloneJSON,
|
||||
getFontString,
|
||||
toBrandedType,
|
||||
} from "../utils";
|
||||
import { getSizeFromPoints } from "../points";
|
||||
import { randomId } from "../random";
|
||||
import { syncInvalidIndices } from "../fractionalIndex";
|
||||
|
||||
export type ValidLinearElement = {
|
||||
type: "arrow" | "line";
|
||||
|
@ -457,12 +464,15 @@ class ElementStore {
|
|||
|
||||
this.excalidrawElements.set(ele.id, ele);
|
||||
};
|
||||
|
||||
getElements = () => {
|
||||
return Array.from(this.excalidrawElements.values());
|
||||
return syncInvalidIndices(Array.from(this.excalidrawElements.values()));
|
||||
};
|
||||
|
||||
getElementsMap = () => {
|
||||
return toBrandedType<NonDeletedSceneElementsMap>(this.excalidrawElements);
|
||||
return toBrandedType<NonDeletedSceneElementsMap>(
|
||||
arrayToMap(this.getElements()),
|
||||
);
|
||||
};
|
||||
|
||||
getElement = (id: string) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue