@tldraw/editor 3.14.0-canary.fd2ad122b803 → 3.14.0-canary.ff61ab6deaa2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist-cjs/index.d.ts +59 -63
  2. package/dist-cjs/index.js +10 -8
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +21 -58
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/derivations/bindingsIndex.js +22 -22
  7. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  8. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +16 -20
  9. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
  10. package/dist-cjs/lib/editor/derivations/parentsToChildren.js +16 -16
  11. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  12. package/dist-cjs/lib/editor/managers/{ClickManager.js → ClickManager/ClickManager.js} +1 -1
  13. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +7 -0
  14. package/dist-cjs/lib/editor/managers/{EdgeScrollManager.js → EdgeScrollManager/EdgeScrollManager.js} +2 -2
  15. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +7 -0
  16. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +7 -0
  17. package/dist-cjs/lib/editor/managers/{FontManager.js → FontManager/FontManager.js} +5 -1
  18. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +7 -0
  19. package/dist-cjs/lib/editor/managers/{HistoryManager.js → HistoryManager/HistoryManager.js} +64 -6
  20. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +7 -0
  21. package/dist-cjs/lib/editor/managers/{ScribbleManager.js → ScribbleManager/ScribbleManager.js} +1 -1
  22. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +7 -0
  23. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +7 -0
  24. package/dist-cjs/lib/editor/managers/{TickManager.js → TickManager/TickManager.js} +1 -1
  25. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +7 -0
  26. package/dist-cjs/lib/editor/managers/{UserPreferencesManager.js → UserPreferencesManager/UserPreferencesManager.js} +1 -1
  27. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +7 -0
  28. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +8 -0
  29. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +6 -0
  31. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  32. package/dist-cjs/lib/exports/getSvgJsx.js.map +1 -1
  33. package/dist-cjs/lib/primitives/Box.js +39 -33
  34. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  35. package/dist-cjs/lib/primitives/Vec.js +13 -8
  36. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  37. package/dist-cjs/lib/primitives/geometry/Arc2d.js +41 -21
  38. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  39. package/dist-cjs/lib/primitives/geometry/Circle2d.js +11 -11
  40. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  41. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +13 -16
  42. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  43. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +4 -4
  44. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  45. package/dist-cjs/lib/primitives/geometry/Edge2d.js +14 -17
  46. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  47. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +10 -10
  48. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  49. package/dist-cjs/lib/primitives/geometry/Point2d.js +6 -6
  50. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  51. package/dist-cjs/lib/primitives/geometry/Polygon2d.js +3 -0
  52. package/dist-cjs/lib/primitives/geometry/Polygon2d.js.map +2 -2
  53. package/dist-cjs/lib/primitives/geometry/Polyline2d.js +8 -5
  54. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  55. package/dist-cjs/lib/primitives/geometry/Rectangle2d.js +22 -11
  56. package/dist-cjs/lib/primitives/geometry/Rectangle2d.js.map +2 -2
  57. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +22 -22
  58. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  59. package/dist-cjs/lib/utils/areShapesContentEqual.js +1 -1
  60. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +2 -2
  61. package/dist-cjs/lib/utils/reorderShapes.js +11 -10
  62. package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
  63. package/dist-cjs/lib/utils/richText.js.map +1 -1
  64. package/dist-cjs/version.js +3 -3
  65. package/dist-cjs/version.js.map +1 -1
  66. package/dist-esm/index.d.mts +59 -63
  67. package/dist-esm/index.mjs +14 -8
  68. package/dist-esm/index.mjs.map +2 -2
  69. package/dist-esm/lib/editor/Editor.mjs +21 -58
  70. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  71. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +22 -22
  72. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  73. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +16 -20
  74. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +3 -3
  75. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +16 -16
  76. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  77. package/dist-esm/lib/editor/managers/{ClickManager.mjs → ClickManager/ClickManager.mjs} +1 -1
  78. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +7 -0
  79. package/dist-esm/lib/editor/managers/{EdgeScrollManager.mjs → EdgeScrollManager/EdgeScrollManager.mjs} +2 -2
  80. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +7 -0
  81. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +7 -0
  82. package/dist-esm/lib/editor/managers/{FontManager.mjs → FontManager/FontManager.mjs} +5 -1
  83. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +7 -0
  84. package/dist-esm/lib/editor/managers/{HistoryManager.mjs → HistoryManager/HistoryManager.mjs} +60 -2
  85. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +7 -0
  86. package/dist-esm/lib/editor/managers/{ScribbleManager.mjs → ScribbleManager/ScribbleManager.mjs} +1 -1
  87. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +7 -0
  88. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +7 -0
  89. package/dist-esm/lib/editor/managers/{TickManager.mjs → TickManager/TickManager.mjs} +1 -1
  90. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +7 -0
  91. package/dist-esm/lib/editor/managers/{UserPreferencesManager.mjs → UserPreferencesManager/UserPreferencesManager.mjs} +1 -1
  92. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +7 -0
  93. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +8 -0
  94. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  95. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +6 -0
  96. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  97. package/dist-esm/lib/exports/getSvgJsx.mjs.map +1 -1
  98. package/dist-esm/lib/primitives/Box.mjs +39 -33
  99. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  100. package/dist-esm/lib/primitives/Vec.mjs +13 -8
  101. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  102. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +41 -21
  103. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  104. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +11 -11
  105. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  106. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +13 -16
  107. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  108. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +4 -4
  109. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  110. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +14 -17
  111. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  112. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +11 -11
  113. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  114. package/dist-esm/lib/primitives/geometry/Point2d.mjs +6 -6
  115. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  116. package/dist-esm/lib/primitives/geometry/Polygon2d.mjs +3 -0
  117. package/dist-esm/lib/primitives/geometry/Polygon2d.mjs.map +2 -2
  118. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +8 -5
  119. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  120. package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs +22 -11
  121. package/dist-esm/lib/primitives/geometry/Rectangle2d.mjs.map +2 -2
  122. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +22 -22
  123. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  124. package/dist-esm/lib/utils/areShapesContentEqual.mjs +1 -1
  125. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +2 -2
  126. package/dist-esm/lib/utils/reorderShapes.mjs +11 -10
  127. package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
  128. package/dist-esm/lib/utils/richText.mjs.map +1 -1
  129. package/dist-esm/version.mjs +3 -3
  130. package/dist-esm/version.mjs.map +1 -1
  131. package/package.json +7 -7
  132. package/src/index.ts +14 -7
  133. package/src/lib/editor/Editor.ts +24 -60
  134. package/src/lib/editor/derivations/bindingsIndex.ts +27 -26
  135. package/src/lib/editor/derivations/notVisibleShapes.ts +24 -25
  136. package/src/lib/editor/derivations/parentsToChildren.ts +28 -25
  137. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +442 -0
  138. package/src/lib/editor/managers/{ClickManager.ts → ClickManager/ClickManager.ts} +3 -3
  139. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +374 -0
  140. package/src/lib/editor/managers/{EdgeScrollManager.ts → EdgeScrollManager/EdgeScrollManager.ts} +3 -3
  141. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +455 -0
  142. package/src/lib/editor/managers/{FocusManager.ts → FocusManager/FocusManager.ts} +1 -1
  143. package/src/lib/editor/managers/FontManager/FontManager.test.ts +263 -0
  144. package/src/lib/editor/managers/{FontManager.ts → FontManager/FontManager.ts} +6 -2
  145. package/src/lib/editor/managers/{HistoryManager.test.ts → HistoryManager/HistoryManager.test.ts} +388 -1
  146. package/src/lib/editor/managers/{HistoryManager.ts → HistoryManager/HistoryManager.ts} +73 -2
  147. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +624 -0
  148. package/src/lib/editor/managers/{ScribbleManager.ts → ScribbleManager/ScribbleManager.ts} +2 -2
  149. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +485 -0
  150. package/src/lib/editor/managers/TextManager/TextManager.test.ts +411 -0
  151. package/src/lib/editor/managers/{TextManager.ts → TextManager/TextManager.ts} +1 -1
  152. package/src/lib/editor/managers/TickManager/TickManager.test.ts +314 -0
  153. package/src/lib/editor/managers/{TickManager.ts → TickManager/TickManager.ts} +2 -2
  154. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +591 -0
  155. package/src/lib/editor/managers/{UserPreferencesManager.ts → UserPreferencesManager/UserPreferencesManager.ts} +2 -2
  156. package/src/lib/editor/shapes/ShapeUtil.ts +10 -1
  157. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +8 -0
  158. package/src/lib/exports/getSvgJsx.tsx +1 -1
  159. package/src/lib/primitives/Box.test.ts +588 -7
  160. package/src/lib/primitives/Box.ts +41 -33
  161. package/src/lib/primitives/Vec.test.ts +2 -2
  162. package/src/lib/primitives/Vec.ts +13 -8
  163. package/src/lib/primitives/geometry/Arc2d.ts +42 -23
  164. package/src/lib/primitives/geometry/Circle2d.ts +12 -12
  165. package/src/lib/primitives/geometry/CubicBezier2d.test.ts +5 -0
  166. package/src/lib/primitives/geometry/CubicBezier2d.ts +13 -17
  167. package/src/lib/primitives/geometry/CubicSpline2d.ts +5 -5
  168. package/src/lib/primitives/geometry/Edge2d.ts +14 -18
  169. package/src/lib/primitives/geometry/Ellipse2d.ts +12 -13
  170. package/src/lib/primitives/geometry/Point2d.ts +6 -6
  171. package/src/lib/primitives/geometry/Polygon2d.ts +4 -0
  172. package/src/lib/primitives/geometry/Polyline2d.ts +10 -7
  173. package/src/lib/primitives/geometry/Rectangle2d.ts +24 -11
  174. package/src/lib/primitives/geometry/Stadium2d.ts +22 -23
  175. package/src/lib/utils/areShapesContentEqual.ts +2 -1
  176. package/src/lib/utils/reorderShapes.ts +10 -13
  177. package/src/lib/utils/richText.ts +1 -1
  178. package/src/version.ts +3 -3
  179. package/dist-cjs/lib/editor/managers/ClickManager.js.map +0 -7
  180. package/dist-cjs/lib/editor/managers/EdgeScrollManager.js.map +0 -7
  181. package/dist-cjs/lib/editor/managers/FocusManager.js.map +0 -7
  182. package/dist-cjs/lib/editor/managers/FontManager.js.map +0 -7
  183. package/dist-cjs/lib/editor/managers/HistoryManager.js.map +0 -7
  184. package/dist-cjs/lib/editor/managers/ScribbleManager.js.map +0 -7
  185. package/dist-cjs/lib/editor/managers/Stack.js +0 -82
  186. package/dist-cjs/lib/editor/managers/Stack.js.map +0 -7
  187. package/dist-cjs/lib/editor/managers/TextManager.js.map +0 -7
  188. package/dist-cjs/lib/editor/managers/TickManager.js.map +0 -7
  189. package/dist-cjs/lib/editor/managers/UserPreferencesManager.js.map +0 -7
  190. package/dist-esm/lib/editor/managers/ClickManager.mjs.map +0 -7
  191. package/dist-esm/lib/editor/managers/EdgeScrollManager.mjs.map +0 -7
  192. package/dist-esm/lib/editor/managers/FocusManager.mjs.map +0 -7
  193. package/dist-esm/lib/editor/managers/FontManager.mjs.map +0 -7
  194. package/dist-esm/lib/editor/managers/HistoryManager.mjs.map +0 -7
  195. package/dist-esm/lib/editor/managers/ScribbleManager.mjs.map +0 -7
  196. package/dist-esm/lib/editor/managers/Stack.mjs +0 -62
  197. package/dist-esm/lib/editor/managers/Stack.mjs.map +0 -7
  198. package/dist-esm/lib/editor/managers/TextManager.mjs.map +0 -7
  199. package/dist-esm/lib/editor/managers/TickManager.mjs.map +0 -7
  200. package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs.map +0 -7
  201. package/src/lib/editor/managers/ScribbleManager.test.ts +0 -32
  202. package/src/lib/editor/managers/Stack.ts +0 -71
  203. /package/dist-cjs/lib/editor/managers/{FocusManager.js → FocusManager/FocusManager.js} +0 -0
  204. /package/dist-cjs/lib/editor/managers/{TextManager.js → TextManager/TextManager.js} +0 -0
  205. /package/dist-esm/lib/editor/managers/{FocusManager.mjs → FocusManager/FocusManager.mjs} +0 -0
  206. /package/dist-esm/lib/editor/managers/{TextManager.mjs → TextManager/TextManager.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- const areShapesContentEqual = (a, b) => a.props === b.props && a.meta === b.meta;
1
+ const areShapesContentEqual = (a, b) => a.parentId === b.parentId && a.props === b.props && a.meta === b.meta;
2
2
  export {
3
3
  areShapesContentEqual
4
4
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/areShapesContentEqual.ts"],
4
- "sourcesContent": ["import { TLShape } from '@tldraw/tlschema'\n\nexport const areShapesContentEqual = (a: TLShape, b: TLShape) =>\n\ta.props === b.props && a.meta === b.meta\n"],
5
- "mappings": "AAEO,MAAM,wBAAwB,CAAC,GAAY,MACjD,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE;",
4
+ "sourcesContent": ["import { TLShape } from '@tldraw/tlschema'\n\n/** @public */\nexport const areShapesContentEqual = (a: TLShape, b: TLShape) =>\n\ta.parentId === b.parentId && a.props === b.props && a.meta === b.meta\n"],
5
+ "mappings": "AAGO,MAAM,wBAAwB,CAAC,GAAY,MACjD,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,4 @@
1
1
  import { compact, getIndicesBetween, sortByIndex } from "@tldraw/utils";
2
- import { polygonsIntersect } from "../primitives/intersect.mjs";
3
2
  function getReorderingShapesChanges(editor, operation, ids, opts) {
4
3
  if (ids.length === 0) return [];
5
4
  const parents = /* @__PURE__ */ new Map();
@@ -89,16 +88,18 @@ function reorderToFront(moving, children, changes) {
89
88
  }
90
89
  }
91
90
  function getOverlapChecker(editor, moving) {
92
- const movingVertices = Array.from(moving).map((shape) => {
93
- const vertices = editor.getShapePageGeometry(shape).vertices;
94
- if (!vertices) return null;
95
- return { shape, vertices };
96
- }).filter(Boolean);
91
+ const movingBounds = compact(
92
+ Array.from(moving).map((shape) => {
93
+ const bounds = editor.getShapePageBounds(shape);
94
+ if (!bounds) return null;
95
+ return { shape, bounds };
96
+ })
97
+ );
97
98
  const isOverlapping = (child) => {
98
- const vertices = editor.getShapePageGeometry(child).vertices;
99
- if (!vertices) return false;
100
- return movingVertices.some((other) => {
101
- return polygonsIntersect(other.vertices, vertices);
99
+ const bounds = editor.getShapePageBounds(child);
100
+ if (!bounds) return false;
101
+ return movingBounds.some((other) => {
102
+ return other.bounds.includes(bounds);
102
103
  });
103
104
  };
104
105
  return isOverlapping;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/reorderShapes.ts"],
4
- "sourcesContent": ["import { TLParentId, TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndicesBetween, sortByIndex } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { Vec } from '../primitives/Vec'\nimport { polygonsIntersect } from '../primitives/intersect'\n\nexport function getReorderingShapesChanges(\n\teditor: Editor,\n\toperation: 'toBack' | 'toFront' | 'forward' | 'backward',\n\tids: TLShapeId[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tif (ids.length === 0) return []\n\n\t// From the ids that are moving, collect the parents, their children, and which of those children are moving\n\tconst parents = new Map<TLParentId, { moving: Set<TLShape>; children: TLShape[] }>()\n\n\tfor (const shape of compact(ids.map((id) => editor.getShape(id)))) {\n\t\tconst { parentId } = shape\n\t\tif (!parents.has(parentId)) {\n\t\t\tparents.set(parentId, {\n\t\t\t\tchildren: compact(\n\t\t\t\t\teditor.getSortedChildIdsForParent(parentId).map((id) => editor.getShape(id))\n\t\t\t\t),\n\t\t\t\tmoving: new Set(),\n\t\t\t})\n\t\t}\n\t\tparents.get(parentId)!.moving.add(shape)\n\t}\n\n\tconst changes: TLShapePartial[] = []\n\n\tswitch (operation) {\n\t\tcase 'toBack': {\n\t\t\tparents.forEach(({ moving, children }) => reorderToBack(moving, children, changes))\n\t\t\tbreak\n\t\t}\n\t\tcase 'toFront': {\n\t\t\tparents.forEach(({ moving, children }) => reorderToFront(moving, children, changes))\n\t\t\tbreak\n\t\t}\n\t\tcase 'forward': {\n\t\t\tparents.forEach(({ moving, children }) =>\n\t\t\t\treorderForward(editor, moving, children, changes, opts)\n\t\t\t)\n\t\t\tbreak\n\t\t}\n\t\tcase 'backward': {\n\t\t\tparents.forEach(({ moving, children }) =>\n\t\t\t\treorderBackward(editor, moving, children, changes, opts)\n\t\t\t)\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn changes\n}\n\n/**\n * Reorders the moving shapes to the back of the parent's children.\n *\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n */\nfunction reorderToBack(moving: Set<TLShape>, children: TLShape[], changes: TLShapePartial[]) {\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet below: IndexKey | undefined\n\tlet above: IndexKey | undefined\n\n\t// Starting at the bottom of this parent's children...\n\tfor (let i = 0; i < len; i++) {\n\t\tconst shape = children[i]\n\n\t\tif (moving.has(shape)) {\n\t\t\t// If we've found a moving shape before we've found a non-moving shape,\n\t\t\t// then that shape is already at the back; we can remove it from the\n\t\t\t// moving set and mark it as the shape that will be below the moved shapes.\n\t\t\tbelow = shape.index\n\t\t\tmoving.delete(shape)\n\t\t} else {\n\t\t\t// The first non-moving shape we find will be above our moved shapes; we'll\n\t\t\t// put our moving shapes between it and the shape marked as below (if any).\n\t\t\tabove = shape.index\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (moving.size === 0) {\n\t\t// If our moving set is empty, there's nothing to do; all of our shapes were\n\t\t// already at the back of the parent's children.\n\t\treturn\n\t} else {\n\t\t// Sort the moving shapes by their current index, then apply the new indices\n\t\tconst indices = getIndicesBetween(below, above, moving.size)\n\t\tchanges.push(\n\t\t\t...Array.from(moving.values())\n\t\t\t\t.sort(sortByIndex)\n\t\t\t\t.map((shape, i) => ({ ...shape, index: indices[i] }))\n\t\t)\n\t}\n}\n\n/**\n * Reorders the moving shapes to the front of the parent's children.\n *\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n */\nfunction reorderToFront(moving: Set<TLShape>, children: TLShape[], changes: TLShapePartial[]) {\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet below: IndexKey | undefined\n\tlet above: IndexKey | undefined\n\n\t// Starting at the top of this parent's children...\n\tfor (let i = len - 1; i > -1; i--) {\n\t\tconst shape = children[i]\n\n\t\tif (moving.has(shape)) {\n\t\t\t// If we've found a moving shape before we've found a non-moving shape,\n\t\t\t// then that shape is already at the front; we can remove it from the\n\t\t\t// moving set and mark it as the shape that will be above the moved shapes.\n\t\t\tabove = shape.index\n\t\t\tmoving.delete(shape)\n\t\t} else {\n\t\t\t// The first non-moving shape we find will be below our moved shapes; we'll\n\t\t\t// put our moving shapes between it and the shape marked as above (if any).\n\t\t\tbelow = shape.index\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (moving.size === 0) {\n\t\t// If our moving set is empty, there's nothing to do; all of our shapes were\n\t\t// already at the front of the parent's children.\n\t\treturn\n\t} else {\n\t\t// Sort the moving shapes by their current index, then apply the new indices\n\t\tconst indices = getIndicesBetween(below, above, moving.size)\n\t\tchanges.push(\n\t\t\t...Array.from(moving.values())\n\t\t\t\t.sort(sortByIndex)\n\t\t\t\t.map((shape, i) => ({ ...shape, index: indices[i] }))\n\t\t)\n\t}\n}\n\nfunction getOverlapChecker(editor: Editor, moving: Set<TLShape>) {\n\tconst movingVertices = Array.from(moving)\n\t\t.map((shape) => {\n\t\t\tconst vertices = editor.getShapePageGeometry(shape).vertices\n\t\t\tif (!vertices) return null\n\t\t\treturn { shape, vertices }\n\t\t})\n\t\t.filter(Boolean) as { shape: TLShape; vertices: Vec[] }[]\n\n\tconst isOverlapping = (child: TLShape) => {\n\t\tconst vertices = editor.getShapePageGeometry(child).vertices\n\t\tif (!vertices) return false\n\t\treturn movingVertices.some((other) => {\n\t\t\treturn polygonsIntersect(other.vertices, vertices)\n\t\t})\n\t}\n\n\treturn isOverlapping\n}\n\n/**\n * Reorders the moving shapes forward in the parent's children.\n *\n * @param editor The editor\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n * @param opts The options\n */\nfunction reorderForward(\n\teditor: Editor,\n\tmoving: Set<TLShape>,\n\tchildren: TLShape[],\n\tchanges: TLShapePartial[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tconst isOverlapping = getOverlapChecker(editor, moving)\n\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet state = { name: 'skipping' } as\n\t\t| { name: 'skipping' }\n\t\t| { name: 'selecting'; selectIndex: number }\n\n\t// Starting at the bottom of this parent's children...\n\tfor (let i = 0; i < len; i++) {\n\t\tconst isMoving = moving.has(children[i])\n\n\t\tswitch (state.name) {\n\t\t\tcase 'skipping': {\n\t\t\t\tif (!isMoving) continue\n\t\t\t\t// If we find a moving shape while skipping, start selecting\n\t\t\t\tstate = { name: 'selecting', selectIndex: i }\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'selecting': {\n\t\t\t\tif (isMoving) continue\n\t\t\t\tif (!opts?.considerAllShapes && !isOverlapping(children[i])) continue\n\t\t\t\t// if we find a non-moving and overlapping shape while selecting, move all selected\n\t\t\t\t// shapes in front of the not moving shape; and start skipping\n\t\t\t\tconst { selectIndex } = state\n\t\t\t\tgetIndicesBetween(children[i].index, children[i + 1]?.index, i - selectIndex).forEach(\n\t\t\t\t\t(index, k) => {\n\t\t\t\t\t\tconst child = children[selectIndex + k]\n\t\t\t\t\t\t// If the shape is not moving (therefore also not overlapping), skip it\n\t\t\t\t\t\tif (!moving.has(child)) return\n\t\t\t\t\t\tchanges.push({ ...child, index })\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\tstate = { name: 'skipping' }\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Reorders the moving shapes backward in the parent's children.\n *\n * @param editor The editor\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n * @param opts The options\n */\nfunction reorderBackward(\n\teditor: Editor,\n\tmoving: Set<TLShape>,\n\tchildren: TLShape[],\n\tchanges: TLShapePartial[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tconst isOverlapping = getOverlapChecker(editor, moving)\n\n\tconst len = children.length\n\n\tif (moving.size === len) return\n\n\tlet state = { name: 'skipping' } as\n\t\t| { name: 'skipping' }\n\t\t| { name: 'selecting'; selectIndex: number }\n\n\t// Starting at the top of this parent's children...\n\tfor (let i = len - 1; i > -1; i--) {\n\t\tconst isMoving = moving.has(children[i])\n\n\t\tswitch (state.name) {\n\t\t\tcase 'skipping': {\n\t\t\t\tif (!isMoving) continue\n\t\t\t\t// If we find a moving shape while skipping, start selecting\n\t\t\t\tstate = { name: 'selecting', selectIndex: i }\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'selecting': {\n\t\t\t\tif (isMoving) continue\n\t\t\t\tif (!opts?.considerAllShapes && !isOverlapping(children[i])) continue\n\t\t\t\t// if we find a non-moving and overlapping shape while selecting, move all selected\n\t\t\t\t// shapes in behind of the not moving shape; and start skipping\n\t\t\t\tgetIndicesBetween(children[i - 1]?.index, children[i].index, state.selectIndex - i).forEach(\n\t\t\t\t\t(index, k) => {\n\t\t\t\t\t\tconst child = children[i + k + 1]\n\t\t\t\t\t\t// If the shape is not moving (therefore also not overlapping), skip it\n\t\t\t\t\t\tif (!moving.has(child)) return\n\t\t\t\t\t\tchanges.push({ ...child, index })\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\tstate = { name: 'skipping' }\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { TLParentId, TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndicesBetween, sortByIndex } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\n\nexport function getReorderingShapesChanges(\n\teditor: Editor,\n\toperation: 'toBack' | 'toFront' | 'forward' | 'backward',\n\tids: TLShapeId[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tif (ids.length === 0) return []\n\n\t// From the ids that are moving, collect the parents, their children, and which of those children are moving\n\tconst parents = new Map<TLParentId, { moving: Set<TLShape>; children: TLShape[] }>()\n\n\tfor (const shape of compact(ids.map((id) => editor.getShape(id)))) {\n\t\tconst { parentId } = shape\n\t\tif (!parents.has(parentId)) {\n\t\t\tparents.set(parentId, {\n\t\t\t\tchildren: compact(\n\t\t\t\t\teditor.getSortedChildIdsForParent(parentId).map((id) => editor.getShape(id))\n\t\t\t\t),\n\t\t\t\tmoving: new Set(),\n\t\t\t})\n\t\t}\n\t\tparents.get(parentId)!.moving.add(shape)\n\t}\n\n\tconst changes: TLShapePartial[] = []\n\n\tswitch (operation) {\n\t\tcase 'toBack': {\n\t\t\tparents.forEach(({ moving, children }) => reorderToBack(moving, children, changes))\n\t\t\tbreak\n\t\t}\n\t\tcase 'toFront': {\n\t\t\tparents.forEach(({ moving, children }) => reorderToFront(moving, children, changes))\n\t\t\tbreak\n\t\t}\n\t\tcase 'forward': {\n\t\t\tparents.forEach(({ moving, children }) =>\n\t\t\t\treorderForward(editor, moving, children, changes, opts)\n\t\t\t)\n\t\t\tbreak\n\t\t}\n\t\tcase 'backward': {\n\t\t\tparents.forEach(({ moving, children }) =>\n\t\t\t\treorderBackward(editor, moving, children, changes, opts)\n\t\t\t)\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn changes\n}\n\n/**\n * Reorders the moving shapes to the back of the parent's children.\n *\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n */\nfunction reorderToBack(moving: Set<TLShape>, children: TLShape[], changes: TLShapePartial[]) {\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet below: IndexKey | undefined\n\tlet above: IndexKey | undefined\n\n\t// Starting at the bottom of this parent's children...\n\tfor (let i = 0; i < len; i++) {\n\t\tconst shape = children[i]\n\n\t\tif (moving.has(shape)) {\n\t\t\t// If we've found a moving shape before we've found a non-moving shape,\n\t\t\t// then that shape is already at the back; we can remove it from the\n\t\t\t// moving set and mark it as the shape that will be below the moved shapes.\n\t\t\tbelow = shape.index\n\t\t\tmoving.delete(shape)\n\t\t} else {\n\t\t\t// The first non-moving shape we find will be above our moved shapes; we'll\n\t\t\t// put our moving shapes between it and the shape marked as below (if any).\n\t\t\tabove = shape.index\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (moving.size === 0) {\n\t\t// If our moving set is empty, there's nothing to do; all of our shapes were\n\t\t// already at the back of the parent's children.\n\t\treturn\n\t} else {\n\t\t// Sort the moving shapes by their current index, then apply the new indices\n\t\tconst indices = getIndicesBetween(below, above, moving.size)\n\t\tchanges.push(\n\t\t\t...Array.from(moving.values())\n\t\t\t\t.sort(sortByIndex)\n\t\t\t\t.map((shape, i) => ({ ...shape, index: indices[i] }))\n\t\t)\n\t}\n}\n\n/**\n * Reorders the moving shapes to the front of the parent's children.\n *\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n */\nfunction reorderToFront(moving: Set<TLShape>, children: TLShape[], changes: TLShapePartial[]) {\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet below: IndexKey | undefined\n\tlet above: IndexKey | undefined\n\n\t// Starting at the top of this parent's children...\n\tfor (let i = len - 1; i > -1; i--) {\n\t\tconst shape = children[i]\n\n\t\tif (moving.has(shape)) {\n\t\t\t// If we've found a moving shape before we've found a non-moving shape,\n\t\t\t// then that shape is already at the front; we can remove it from the\n\t\t\t// moving set and mark it as the shape that will be above the moved shapes.\n\t\t\tabove = shape.index\n\t\t\tmoving.delete(shape)\n\t\t} else {\n\t\t\t// The first non-moving shape we find will be below our moved shapes; we'll\n\t\t\t// put our moving shapes between it and the shape marked as above (if any).\n\t\t\tbelow = shape.index\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (moving.size === 0) {\n\t\t// If our moving set is empty, there's nothing to do; all of our shapes were\n\t\t// already at the front of the parent's children.\n\t\treturn\n\t} else {\n\t\t// Sort the moving shapes by their current index, then apply the new indices\n\t\tconst indices = getIndicesBetween(below, above, moving.size)\n\t\tchanges.push(\n\t\t\t...Array.from(moving.values())\n\t\t\t\t.sort(sortByIndex)\n\t\t\t\t.map((shape, i) => ({ ...shape, index: indices[i] }))\n\t\t)\n\t}\n}\n\nfunction getOverlapChecker(editor: Editor, moving: Set<TLShape>) {\n\tconst movingBounds = compact(\n\t\tArray.from(moving).map((shape) => {\n\t\t\tconst bounds = editor.getShapePageBounds(shape)\n\t\t\tif (!bounds) return null\n\t\t\treturn { shape, bounds }\n\t\t})\n\t)\n\tconst isOverlapping = (child: TLShape) => {\n\t\tconst bounds = editor.getShapePageBounds(child)\n\t\tif (!bounds) return false\n\t\treturn movingBounds.some((other) => {\n\t\t\treturn other.bounds.includes(bounds)\n\t\t})\n\t}\n\n\treturn isOverlapping\n}\n\n/**\n * Reorders the moving shapes forward in the parent's children.\n *\n * @param editor The editor\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n * @param opts The options\n */\nfunction reorderForward(\n\teditor: Editor,\n\tmoving: Set<TLShape>,\n\tchildren: TLShape[],\n\tchanges: TLShapePartial[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tconst isOverlapping = getOverlapChecker(editor, moving)\n\n\tconst len = children.length\n\n\t// If all of the children are moving, there's nothing to do\n\tif (moving.size === len) return\n\n\tlet state = { name: 'skipping' } as\n\t\t| { name: 'skipping' }\n\t\t| { name: 'selecting'; selectIndex: number }\n\n\t// Starting at the bottom of this parent's children...\n\tfor (let i = 0; i < len; i++) {\n\t\tconst isMoving = moving.has(children[i])\n\n\t\tswitch (state.name) {\n\t\t\tcase 'skipping': {\n\t\t\t\tif (!isMoving) continue\n\t\t\t\t// If we find a moving shape while skipping, start selecting\n\t\t\t\tstate = { name: 'selecting', selectIndex: i }\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'selecting': {\n\t\t\t\tif (isMoving) continue\n\t\t\t\tif (!opts?.considerAllShapes && !isOverlapping(children[i])) continue\n\t\t\t\t// if we find a non-moving and overlapping shape while selecting, move all selected\n\t\t\t\t// shapes in front of the not moving shape; and start skipping\n\t\t\t\tconst { selectIndex } = state\n\t\t\t\tgetIndicesBetween(children[i].index, children[i + 1]?.index, i - selectIndex).forEach(\n\t\t\t\t\t(index, k) => {\n\t\t\t\t\t\tconst child = children[selectIndex + k]\n\t\t\t\t\t\t// If the shape is not moving (therefore also not overlapping), skip it\n\t\t\t\t\t\tif (!moving.has(child)) return\n\t\t\t\t\t\tchanges.push({ ...child, index })\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\tstate = { name: 'skipping' }\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Reorders the moving shapes backward in the parent's children.\n *\n * @param editor The editor\n * @param moving The set of shapes that are moving\n * @param children The parent's children\n * @param changes The changes array to push changes to\n * @param opts The options\n */\nfunction reorderBackward(\n\teditor: Editor,\n\tmoving: Set<TLShape>,\n\tchildren: TLShape[],\n\tchanges: TLShapePartial[],\n\topts?: { considerAllShapes?: boolean }\n) {\n\tconst isOverlapping = getOverlapChecker(editor, moving)\n\n\tconst len = children.length\n\n\tif (moving.size === len) return\n\n\tlet state = { name: 'skipping' } as\n\t\t| { name: 'skipping' }\n\t\t| { name: 'selecting'; selectIndex: number }\n\n\t// Starting at the top of this parent's children...\n\tfor (let i = len - 1; i > -1; i--) {\n\t\tconst isMoving = moving.has(children[i])\n\n\t\tswitch (state.name) {\n\t\t\tcase 'skipping': {\n\t\t\t\tif (!isMoving) continue\n\t\t\t\t// If we find a moving shape while skipping, start selecting\n\t\t\t\tstate = { name: 'selecting', selectIndex: i }\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'selecting': {\n\t\t\t\tif (isMoving) continue\n\t\t\t\tif (!opts?.considerAllShapes && !isOverlapping(children[i])) continue\n\t\t\t\t// if we find a non-moving and overlapping shape while selecting, move all selected\n\t\t\t\t// shapes in behind of the not moving shape; and start skipping\n\t\t\t\tgetIndicesBetween(children[i - 1]?.index, children[i].index, state.selectIndex - i).forEach(\n\t\t\t\t\t(index, k) => {\n\t\t\t\t\t\tconst child = children[i + k + 1]\n\t\t\t\t\t\t// If the shape is not moving (therefore also not overlapping), skip it\n\t\t\t\t\t\tif (!moving.has(child)) return\n\t\t\t\t\t\tchanges.push({ ...child, index })\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\tstate = { name: 'skipping' }\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/richText.ts"],
4
- "sourcesContent": ["import { getSchema, JSONContent, Editor as TTEditor } from '@tiptap/core'\nimport { Node } from '@tiptap/pm/model'\nimport { EditorProviderProps } from '@tiptap/react'\nimport { TLRichText } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { TLFontFace } from '../editor/managers/FontManager'\n\n/**\n * This is the TipTap editor! Docs are {@link https://tiptap.dev/docs}.\n *\n * @public\n */\nexport type TiptapEditor = TTEditor\n\n/**\n * A TipTap node. See {@link https://tiptap.dev/docs}.\n * @public\n */\nexport type TiptapNode = Node\n\n/** @public */\nexport interface TLTextOptions {\n\ttipTapConfig?: EditorProviderProps\n\taddFontsFromNode?: RichTextFontVisitor\n}\n\n/** @public */\nexport interface RichTextFontVisitorState {\n\treadonly family: string\n\treadonly weight: string\n\treadonly style: string\n}\n\n/** @public */\nexport type RichTextFontVisitor = (\n\tnode: TiptapNode,\n\tstate: RichTextFontVisitorState,\n\taddFont: (font: TLFontFace) => void\n) => RichTextFontVisitorState\n\n/** @public */\nexport function getFontsFromRichText(\n\teditor: Editor,\n\trichText: TLRichText,\n\tinitialState: RichTextFontVisitorState\n) {\n\tconst { tipTapConfig, addFontsFromNode } = editor.getTextOptions()\n\tassert(tipTapConfig, 'textOptions.tipTapConfig must be set to use rich text')\n\tassert(addFontsFromNode, 'textOptions.addFontsFromNode must be set to use rich text')\n\n\tconst schema = getSchema(tipTapConfig.extensions ?? [])\n\tconst rootNode = Node.fromJSON(schema, richText as JSONContent)\n\n\tconst fonts = new Set<TLFontFace>()\n\n\tfunction addFont(font: TLFontFace) {\n\t\tfonts.add(font)\n\t}\n\n\tfunction visit(node: TiptapNode, state: RichTextFontVisitorState) {\n\t\tstate = addFontsFromNode!(node, state, addFont)\n\n\t\tfor (const child of node.children) {\n\t\t\tvisit(child, state)\n\t\t}\n\t}\n\n\tvisit(rootNode, initialState)\n\n\treturn Array.from(fonts)\n}\n"],
4
+ "sourcesContent": ["import { getSchema, JSONContent, Editor as TTEditor } from '@tiptap/core'\nimport { Node } from '@tiptap/pm/model'\nimport { EditorProviderProps } from '@tiptap/react'\nimport { TLRichText } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { TLFontFace } from '../editor/managers/FontManager/FontManager'\n\n/**\n * This is the TipTap editor! Docs are {@link https://tiptap.dev/docs}.\n *\n * @public\n */\nexport type TiptapEditor = TTEditor\n\n/**\n * A TipTap node. See {@link https://tiptap.dev/docs}.\n * @public\n */\nexport type TiptapNode = Node\n\n/** @public */\nexport interface TLTextOptions {\n\ttipTapConfig?: EditorProviderProps\n\taddFontsFromNode?: RichTextFontVisitor\n}\n\n/** @public */\nexport interface RichTextFontVisitorState {\n\treadonly family: string\n\treadonly weight: string\n\treadonly style: string\n}\n\n/** @public */\nexport type RichTextFontVisitor = (\n\tnode: TiptapNode,\n\tstate: RichTextFontVisitorState,\n\taddFont: (font: TLFontFace) => void\n) => RichTextFontVisitorState\n\n/** @public */\nexport function getFontsFromRichText(\n\teditor: Editor,\n\trichText: TLRichText,\n\tinitialState: RichTextFontVisitorState\n) {\n\tconst { tipTapConfig, addFontsFromNode } = editor.getTextOptions()\n\tassert(tipTapConfig, 'textOptions.tipTapConfig must be set to use rich text')\n\tassert(addFontsFromNode, 'textOptions.addFontsFromNode must be set to use rich text')\n\n\tconst schema = getSchema(tipTapConfig.extensions ?? [])\n\tconst rootNode = Node.fromJSON(schema, richText as JSONContent)\n\n\tconst fonts = new Set<TLFontFace>()\n\n\tfunction addFont(font: TLFontFace) {\n\t\tfonts.add(font)\n\t}\n\n\tfunction visit(node: TiptapNode, state: RichTextFontVisitorState) {\n\t\tstate = addFontsFromNode!(node, state, addFont)\n\n\t\tfor (const child of node.children) {\n\t\t\tvisit(child, state)\n\t\t}\n\t}\n\n\tvisit(rootNode, initialState)\n\n\treturn Array.from(fonts)\n}\n"],
5
5
  "mappings": "AAAA,SAAS,iBAAkD;AAC3D,SAAS,YAAY;AAGrB,SAAS,cAAc;AAsChB,SAAS,qBACf,QACA,UACA,cACC;AACD,QAAM,EAAE,cAAc,iBAAiB,IAAI,OAAO,eAAe;AACjE,SAAO,cAAc,uDAAuD;AAC5E,SAAO,kBAAkB,2DAA2D;AAEpF,QAAM,SAAS,UAAU,aAAa,cAAc,CAAC,CAAC;AACtD,QAAM,WAAW,KAAK,SAAS,QAAQ,QAAuB;AAE9D,QAAM,QAAQ,oBAAI,IAAgB;AAElC,WAAS,QAAQ,MAAkB;AAClC,UAAM,IAAI,IAAI;AAAA,EACf;AAEA,WAAS,MAAM,MAAkB,OAAiC;AACjE,YAAQ,iBAAkB,MAAM,OAAO,OAAO;AAE9C,eAAW,SAAS,KAAK,UAAU;AAClC,YAAM,OAAO,KAAK;AAAA,IACnB;AAAA,EACD;AAEA,QAAM,UAAU,YAAY;AAE5B,SAAO,MAAM,KAAK,KAAK;AACxB;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "3.14.0-canary.fd2ad122b803";
1
+ const version = "3.14.0-canary.ff61ab6deaa2";
2
2
  const publishDates = {
3
3
  major: "2024-09-13T14:36:29.063Z",
4
- minor: "2025-05-26T05:55:58.982Z",
5
- patch: "2025-05-26T05:55:58.982Z"
4
+ minor: "2025-06-07T17:49:04.145Z",
5
+ patch: "2025-06-07T17:49:04.145Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.fd2ad122b803'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-05-26T05:55:58.982Z',\n\tpatch: '2025-05-26T05:55:58.982Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.ff61ab6deaa2'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-06-07T17:49:04.145Z',\n\tpatch: '2025-06-07T17:49:04.145Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "A tiny little drawing app (editor).",
4
- "version": "3.14.0-canary.fd2ad122b803",
4
+ "version": "3.14.0-canary.ff61ab6deaa2",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -48,12 +48,12 @@
48
48
  "@tiptap/core": "^2.9.1",
49
49
  "@tiptap/pm": "^2.9.1",
50
50
  "@tiptap/react": "^2.9.1",
51
- "@tldraw/state": "3.14.0-canary.fd2ad122b803",
52
- "@tldraw/state-react": "3.14.0-canary.fd2ad122b803",
53
- "@tldraw/store": "3.14.0-canary.fd2ad122b803",
54
- "@tldraw/tlschema": "3.14.0-canary.fd2ad122b803",
55
- "@tldraw/utils": "3.14.0-canary.fd2ad122b803",
56
- "@tldraw/validate": "3.14.0-canary.fd2ad122b803",
51
+ "@tldraw/state": "3.14.0-canary.ff61ab6deaa2",
52
+ "@tldraw/state-react": "3.14.0-canary.ff61ab6deaa2",
53
+ "@tldraw/store": "3.14.0-canary.ff61ab6deaa2",
54
+ "@tldraw/tlschema": "3.14.0-canary.ff61ab6deaa2",
55
+ "@tldraw/utils": "3.14.0-canary.ff61ab6deaa2",
56
+ "@tldraw/validate": "3.14.0-canary.ff61ab6deaa2",
57
57
  "@types/core-js": "^2.5.8",
58
58
  "@use-gesture/react": "^10.3.1",
59
59
  "classnames": "^2.5.1",
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import 'core-js/stable/array/flat-map.js'
4
4
  import 'core-js/stable/array/flat.js'
5
5
  import 'core-js/stable/string/at.js'
6
6
  import 'core-js/stable/string/replace-all.js'
7
+ export { areShapesContentEqual } from './lib/utils/areShapesContentEqual'
7
8
 
8
9
  // eslint-disable-next-line local/no-export-star
9
10
  export * from '@tldraw/state'
@@ -147,15 +148,18 @@ export {
147
148
  type BindingOnShapeIsolateOptions,
148
149
  type TLBindingUtilConstructor,
149
150
  } from './lib/editor/bindings/BindingUtil'
150
- export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager'
151
- export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager'
151
+ export { ClickManager, type TLClickState } from './lib/editor/managers/ClickManager/ClickManager'
152
+ export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager/EdgeScrollManager'
152
153
  export {
153
154
  FontManager,
154
155
  type TLFontFace,
155
156
  type TLFontFaceSource,
156
- } from './lib/editor/managers/FontManager'
157
- export { HistoryManager } from './lib/editor/managers/HistoryManager'
158
- export { ScribbleManager, type ScribbleItem } from './lib/editor/managers/ScribbleManager'
157
+ } from './lib/editor/managers/FontManager/FontManager'
158
+ export { HistoryManager } from './lib/editor/managers/HistoryManager/HistoryManager'
159
+ export {
160
+ ScribbleManager,
161
+ type ScribbleItem,
162
+ } from './lib/editor/managers/ScribbleManager/ScribbleManager'
159
163
  export {
160
164
  BoundsSnaps,
161
165
  type BoundsSnapGeometry,
@@ -169,8 +173,11 @@ export {
169
173
  type SnapData,
170
174
  type SnapIndicator,
171
175
  } from './lib/editor/managers/SnapManager/SnapManager'
172
- export { TextManager, type TLMeasureTextSpanOpts } from './lib/editor/managers/TextManager'
173
- export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesManager'
176
+ export {
177
+ TextManager,
178
+ type TLMeasureTextSpanOpts,
179
+ } from './lib/editor/managers/TextManager/TextManager'
180
+ export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesManager/UserPreferencesManager'
174
181
  export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
175
182
  export {
176
183
  ShapeUtil,
@@ -148,16 +148,16 @@ import { bindingsIndex } from './derivations/bindingsIndex'
148
148
  import { notVisibleShapes } from './derivations/notVisibleShapes'
149
149
  import { parentsToChildren } from './derivations/parentsToChildren'
150
150
  import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
151
- import { ClickManager } from './managers/ClickManager'
152
- import { EdgeScrollManager } from './managers/EdgeScrollManager'
153
- import { FocusManager } from './managers/FocusManager'
154
- import { FontManager } from './managers/FontManager'
155
- import { HistoryManager } from './managers/HistoryManager'
156
- import { ScribbleManager } from './managers/ScribbleManager'
151
+ import { ClickManager } from './managers/ClickManager/ClickManager'
152
+ import { EdgeScrollManager } from './managers/EdgeScrollManager/EdgeScrollManager'
153
+ import { FocusManager } from './managers/FocusManager/FocusManager'
154
+ import { FontManager } from './managers/FontManager/FontManager'
155
+ import { HistoryManager } from './managers/HistoryManager/HistoryManager'
156
+ import { ScribbleManager } from './managers/ScribbleManager/ScribbleManager'
157
157
  import { SnapManager } from './managers/SnapManager/SnapManager'
158
- import { TextManager } from './managers/TextManager'
159
- import { TickManager } from './managers/TickManager'
160
- import { UserPreferencesManager } from './managers/UserPreferencesManager'
158
+ import { TextManager } from './managers/TextManager/TextManager'
159
+ import { TickManager } from './managers/TickManager/TickManager'
160
+ import { UserPreferencesManager } from './managers/UserPreferencesManager/UserPreferencesManager'
161
161
  import { ShapeUtil, TLGeometryOpts, TLResizeMode } from './shapes/ShapeUtil'
162
162
  import { RootState } from './tools/RootState'
163
163
  import { StateNode, TLStateNodeConstructor } from './tools/StateNode'
@@ -328,7 +328,7 @@ export class Editor extends EventEmitter<TLEventMap> {
328
328
  this.store = store
329
329
  this.history = new HistoryManager<TLRecord>({
330
330
  store,
331
- annotateError: (error) => {
331
+ annotateError: (error: any) => {
332
332
  this.annotateError(error, { origin: 'history.batch', willCrashApp: true })
333
333
  this.crash(error)
334
334
  },
@@ -506,6 +506,8 @@ export class Editor extends EventEmitter<TLEventMap> {
506
506
  shape: {
507
507
  afterChange: (shapeBefore, shapeAfter) => {
508
508
  for (const binding of this.getBindingsInvolvingShape(shapeAfter)) {
509
+ if (areShapesContentEqual(shapeBefore, shapeAfter)) continue
510
+
509
511
  invalidBindingTypes.add(binding.type)
510
512
  if (binding.fromId === shapeAfter.id) {
511
513
  this.getBindingUtil(binding).onAfterChangeFromShape?.({
@@ -3715,10 +3717,7 @@ export class Editor extends EventEmitter<TLEventMap> {
3715
3717
  */
3716
3718
  @computed getViewportScreenCenter() {
3717
3719
  const viewportScreenBounds = this.getViewportScreenBounds()
3718
- return new Vec(
3719
- viewportScreenBounds.midX - viewportScreenBounds.minX,
3720
- viewportScreenBounds.midY - viewportScreenBounds.minY
3721
- )
3720
+ return new Vec(viewportScreenBounds.w / 2, viewportScreenBounds.h / 2)
3722
3721
  }
3723
3722
 
3724
3723
  /**
@@ -4644,44 +4643,6 @@ export class Editor extends EventEmitter<TLEventMap> {
4644
4643
  )! as T
4645
4644
  }
4646
4645
 
4647
- private _shapePageGeometryCaches: Record<string, ComputedCache<Geometry2d, TLShape>> = {}
4648
-
4649
- /**
4650
- * Get the geometry of a shape in page-space.
4651
- *
4652
- * @example
4653
- * ```ts
4654
- * editor.getShapePageGeometry(myShape)
4655
- * editor.getShapePageGeometry(myShapeId)
4656
- * editor.getShapePageGeometry(myShapeId, { context: "arrow" })
4657
- * ```
4658
- *
4659
- * @param shape - The shape (or shape id) to get the geometry for.
4660
- * @param opts - Additional options about the request for geometry. Passed to {@link ShapeUtil.getGeometry}.
4661
- *
4662
- * @public
4663
- */
4664
- getShapePageGeometry<T extends Geometry2d>(shape: TLShape | TLShapeId, opts?: TLGeometryOpts): T {
4665
- const context = opts?.context ?? 'none'
4666
- if (!this._shapePageGeometryCaches[context]) {
4667
- this._shapePageGeometryCaches[context] = this.store.createComputedCache(
4668
- 'bounds',
4669
- (shape) => {
4670
- const geometry = this.getShapeGeometry(shape.id, opts)
4671
- const pageTransform = this.getShapePageTransform(shape.id)
4672
- return geometry.transform(pageTransform)
4673
- },
4674
- {
4675
- // we only depend directly on the shape id, and changing geometry/transform will update us anyway
4676
- areRecordsEqual: () => true,
4677
- }
4678
- )
4679
- }
4680
- return this._shapePageGeometryCaches[context].get(
4681
- typeof shape === 'string' ? shape : shape.id
4682
- )! as T
4683
- }
4684
-
4685
4646
  /** @internal */
4686
4647
  @computed private _getShapeHandlesCache(): ComputedCache<TLHandle[] | undefined, TLShape> {
4687
4648
  return this.store.createComputedCache(
@@ -4794,7 +4755,10 @@ export class Editor extends EventEmitter<TLEventMap> {
4794
4755
  /** @internal */
4795
4756
  @computed private _getShapePageBoundsCache(): ComputedCache<Box, TLShape> {
4796
4757
  return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
4797
- return this.getShapePageGeometry(shape).bounds
4758
+ const pageTransform = this.getShapePageTransform(shape)
4759
+ if (!pageTransform) return undefined
4760
+ const geometry = this.getShapeGeometry(shape)
4761
+ return Box.FromPoints(pageTransform.applyToPoints(geometry.vertices))
4798
4762
  })
4799
4763
  }
4800
4764
 
@@ -4868,11 +4832,12 @@ export class Editor extends EventEmitter<TLEventMap> {
4868
4832
  if (frameAncestors.length === 0) return undefined
4869
4833
 
4870
4834
  const pageMask = frameAncestors
4871
- .map<Vec[] | undefined>(
4872
- (s) =>
4873
- // Apply the frame transform to the frame outline to get the frame outline in the current page space
4874
- this.getShapePageGeometry(s.id).vertices
4875
- )
4835
+ .map<Vec[] | undefined>((s) => {
4836
+ // Apply the frame transform to the frame outline to get the frame outline in the current page space
4837
+ const geometry = this.getShapeGeometry(s.id)
4838
+ const pageTransform = this.getShapePageTransform(s.id)
4839
+ return pageTransform.applyToPoints(geometry.vertices)
4840
+ })
4876
4841
  .reduce((acc, b) => {
4877
4842
  if (!(b && acc)) return undefined
4878
4843
  const intersection = intersectPolygonPolygon(acc, b)
@@ -5796,8 +5761,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5796
5761
  parent: TLParentId | TLPage | TLShape,
5797
5762
  visitor: (id: TLShapeId) => void | false
5798
5763
  ): this {
5799
- const parentId = typeof parent === 'string' ? parent : parent.id
5800
- const children = this.getSortedChildIdsForParent(parentId)
5764
+ const children = this.getSortedChildIdsForParent(parent)
5801
5765
  for (const id of children) {
5802
5766
  if (visitor(id) === false) continue
5803
5767
  this.visitDescendants(id, visitor)
@@ -1,41 +1,42 @@
1
1
  import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
2
- import { TLBinding, TLShapeId } from '@tldraw/tlschema'
2
+ import { TLArrowBinding, TLBinding, TLShapeId, TLUnknownBinding } from '@tldraw/tlschema'
3
3
  import { objectMapValues } from '@tldraw/utils'
4
4
  import { Editor } from '../Editor'
5
5
 
6
6
  type TLBindingsIndex = Map<TLShapeId, TLBinding[]>
7
7
 
8
- export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
9
- const { store } = editor
10
- const bindingsHistory = store.query.filterHistory('binding')
11
- const bindingsQuery = store.query.records('binding')
12
- function fromScratch() {
13
- const allBindings = bindingsQuery.get() as TLBinding[]
8
+ function fromScratch(bindingsQuery: Computed<(TLArrowBinding | TLUnknownBinding)[], unknown>) {
9
+ const allBindings = bindingsQuery.get() as TLBinding[]
14
10
 
15
- const shape2Binding: TLBindingsIndex = new Map()
11
+ const shapesToBindings: TLBindingsIndex = new Map()
16
12
 
17
- for (const binding of allBindings) {
18
- const { fromId, toId } = binding
19
- const bindingsForFromShape = shape2Binding.get(fromId)
20
- if (!bindingsForFromShape) {
21
- shape2Binding.set(fromId, [binding])
22
- } else {
23
- bindingsForFromShape.push(binding)
24
- }
25
- const bindingsForToShape = shape2Binding.get(toId)
26
- if (!bindingsForToShape) {
27
- shape2Binding.set(toId, [binding])
28
- } else {
29
- bindingsForToShape.push(binding)
30
- }
13
+ for (const binding of allBindings) {
14
+ const { fromId, toId } = binding
15
+ const bindingsForFromShape = shapesToBindings.get(fromId)
16
+ if (!bindingsForFromShape) {
17
+ shapesToBindings.set(fromId, [binding])
18
+ } else {
19
+ bindingsForFromShape.push(binding)
20
+ }
21
+ const bindingsForToShape = shapesToBindings.get(toId)
22
+ if (!bindingsForToShape) {
23
+ shapesToBindings.set(toId, [binding])
24
+ } else {
25
+ bindingsForToShape.push(binding)
31
26
  }
32
-
33
- return shape2Binding
34
27
  }
35
28
 
29
+ return shapesToBindings
30
+ }
31
+
32
+ export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
33
+ const { store } = editor
34
+ const bindingsHistory = store.query.filterHistory('binding')
35
+ const bindingsQuery = store.query.records('binding')
36
+
36
37
  return computed<TLBindingsIndex>('arrowBindingsIndex', (_lastValue, lastComputedEpoch) => {
37
38
  if (isUninitialized(_lastValue)) {
38
- return fromScratch()
39
+ return fromScratch(bindingsQuery)
39
40
  }
40
41
 
41
42
  const lastValue = _lastValue
@@ -43,7 +44,7 @@ export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
43
44
  const diff = bindingsHistory.getDiffSince(lastComputedEpoch)
44
45
 
45
46
  if (diff === RESET_VALUE) {
46
- return fromScratch()
47
+ return fromScratch(bindingsQuery)
47
48
  }
48
49
 
49
50
  let nextValue: TLBindingsIndex | undefined = undefined
@@ -1,49 +1,48 @@
1
1
  import { computed, isUninitialized } from '@tldraw/state'
2
2
  import { TLShapeId } from '@tldraw/tlschema'
3
- import { Box } from '../../primitives/Box'
4
3
  import { Editor } from '../Editor'
5
4
 
6
- function isShapeNotVisible(editor: Editor, id: TLShapeId, viewportPageBounds: Box): boolean {
7
- const maskedPageBounds = editor.getShapeMaskedPageBounds(id)
8
- // if the shape is fully outside of its parent's clipping bounds...
9
- if (maskedPageBounds === undefined) return true
10
-
11
- // if the shape is fully outside of the viewport page bounds...
12
- return !viewportPageBounds.includes(maskedPageBounds)
5
+ function fromScratch(editor: Editor): Set<TLShapeId> {
6
+ const shapesIds = editor.getCurrentPageShapeIds()
7
+ const viewportPageBounds = editor.getViewportPageBounds()
8
+ const notVisibleShapes = new Set<TLShapeId>()
9
+ shapesIds.forEach((id) => {
10
+ // If the shape is fully outside of the viewport page bounds, add it to the set.
11
+ // We'll ignore masks here, since they're more expensive to compute and the overhead is not worth it.
12
+ const pageBounds = editor.getShapePageBounds(id)
13
+ if (pageBounds === undefined || !viewportPageBounds.includes(pageBounds)) {
14
+ notVisibleShapes.add(id)
15
+ }
16
+ })
17
+ return notVisibleShapes
13
18
  }
14
19
 
15
20
  /**
16
21
  * Incremental derivation of not visible shapes.
17
- * Non visible shapes are shapes outside of the viewport page bounds and shapes outside of parent's clipping bounds.
22
+ * Non visible shapes are shapes outside of the viewport page bounds.
18
23
  *
19
24
  * @param editor - Instance of the tldraw Editor.
20
25
  * @returns Incremental derivation of non visible shapes.
21
26
  */
22
- export const notVisibleShapes = (editor: Editor) => {
23
- function fromScratch(editor: Editor): Set<TLShapeId> {
24
- const shapes = editor.getCurrentPageShapeIds()
25
- const viewportPageBounds = editor.getViewportPageBounds()
26
- const notVisibleShapes = new Set<TLShapeId>()
27
- shapes.forEach((id) => {
28
- if (isShapeNotVisible(editor, id, viewportPageBounds)) {
29
- notVisibleShapes.add(id)
30
- }
31
- })
32
- return notVisibleShapes
33
- }
34
- return computed<Set<TLShapeId>>('notVisibleShapes', (prevValue) => {
27
+ export function notVisibleShapes(editor: Editor) {
28
+ return computed<Set<TLShapeId>>('notVisibleShapes', function updateNotVisibleShapes(prevValue) {
29
+ const nextValue = fromScratch(editor)
30
+
35
31
  if (isUninitialized(prevValue)) {
36
- return fromScratch(editor)
32
+ return nextValue
37
33
  }
38
34
 
39
- const nextValue = fromScratch(editor)
40
-
35
+ // If there are more or less shapes, we know there's a change
41
36
  if (prevValue.size !== nextValue.size) return nextValue
37
+
38
+ // If any of the old shapes are not in the new set, we know there's a change
42
39
  for (const prev of prevValue) {
43
40
  if (!nextValue.has(prev)) {
44
41
  return nextValue
45
42
  }
46
43
  }
44
+
45
+ // If we've made it here, we know that the set is the same
47
46
  return prevValue
48
47
  })
49
48
  }
@@ -1,45 +1,48 @@
1
- import { computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
2
- import { RecordsDiff } from '@tldraw/store'
1
+ import { Computed, computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
2
+ import { CollectionDiff, RecordsDiff } from '@tldraw/store'
3
3
  import { isShape, TLParentId, TLRecord, TLShape, TLShapeId, TLStore } from '@tldraw/tlschema'
4
4
  import { compact, sortByIndex } from '@tldraw/utils'
5
5
 
6
- type Parents2Children = Record<TLParentId, TLShapeId[]>
6
+ type ParentShapeIdsToChildShapeIds = Record<TLParentId, TLShapeId[]>
7
7
 
8
- export const parentsToChildren = (store: TLStore) => {
9
- const shapeIdsQuery = store.query.ids<'shape'>('shape')
10
- const shapeHistory = store.query.filterHistory('shape')
8
+ function fromScratch(
9
+ shapeIdsQuery: Computed<Set<TLShapeId>, CollectionDiff<TLShapeId>>,
10
+ store: TLStore
11
+ ) {
12
+ const result: ParentShapeIdsToChildShapeIds = {}
13
+ const shapeIds = shapeIdsQuery.get()
14
+ const shapes = Array(shapeIds.size) as TLShape[]
15
+ shapeIds.forEach((id) => shapes.push(store.get(id)!))
11
16
 
12
- function fromScratch() {
13
- const result: Parents2Children = {}
14
- const shapeIds = shapeIdsQuery.get()
15
- const shapes = Array(shapeIds.size) as TLShape[]
16
- shapeIds.forEach((id) => shapes.push(store.get(id)!))
17
+ // Sort the shapes by index
18
+ shapes.sort(sortByIndex)
17
19
 
18
- // Sort the shapes by index
19
- shapes.sort(sortByIndex)
20
+ // Populate the result object with an array for each parent.
21
+ shapes.forEach((shape) => {
22
+ if (!result[shape.parentId]) {
23
+ result[shape.parentId] = []
24
+ }
25
+ result[shape.parentId].push(shape.id)
26
+ })
20
27
 
21
- // Populate the result object with an array for each parent.
22
- shapes.forEach((shape) => {
23
- if (!result[shape.parentId]) {
24
- result[shape.parentId] = []
25
- }
26
- result[shape.parentId].push(shape.id)
27
- })
28
+ return result
29
+ }
28
30
 
29
- return result
30
- }
31
+ export const parentsToChildren = (store: TLStore) => {
32
+ const shapeIdsQuery = store.query.ids<'shape'>('shape')
33
+ const shapeHistory = store.query.filterHistory('shape')
31
34
 
32
- return computed<Parents2Children>(
35
+ return computed<ParentShapeIdsToChildShapeIds>(
33
36
  'parentsToChildrenWithIndexes',
34
37
  (lastValue, lastComputedEpoch) => {
35
38
  if (isUninitialized(lastValue)) {
36
- return fromScratch()
39
+ return fromScratch(shapeIdsQuery, store)
37
40
  }
38
41
 
39
42
  const diff = shapeHistory.getDiffSince(lastComputedEpoch)
40
43
 
41
44
  if (diff === RESET_VALUE) {
42
- return fromScratch()
45
+ return fromScratch(shapeIdsQuery, store)
43
46
  }
44
47
 
45
48
  if (diff.length === 0) return lastValue