@tldraw/editor 4.6.0-next.fecc64eee134 → 5.0.0

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 (324) hide show
  1. package/dist-cjs/index.d.ts +493 -170
  2. package/dist-cjs/index.js +14 -23
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +3 -0
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +93 -47
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/CanvasOverlays.js +180 -0
  9. package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +7 -0
  10. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +46 -248
  11. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +3 -3
  12. package/dist-cjs/lib/editor/Editor.js +142 -33
  13. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  14. package/dist-cjs/lib/editor/assets/AssetUtil.js +1 -0
  15. package/dist-cjs/lib/editor/assets/AssetUtil.js.map +1 -1
  16. package/dist-cjs/lib/editor/bindings/BindingUtil.js +1 -0
  17. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +1 -1
  18. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -0
  19. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +1 -1
  20. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +98 -0
  21. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +7 -0
  22. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +1 -0
  23. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +1 -1
  24. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -0
  25. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +1 -1
  26. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -0
  27. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +1 -1
  28. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +2 -0
  29. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +1 -1
  30. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +12 -0
  31. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  32. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -0
  33. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +1 -1
  34. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +1 -0
  35. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
  36. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +1 -0
  37. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
  38. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +2 -1
  39. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  40. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +1 -0
  41. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +1 -1
  42. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -0
  43. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +1 -1
  44. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +1 -0
  45. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +1 -1
  46. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +14 -0
  47. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +2 -2
  48. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -0
  49. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
  50. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +2 -0
  51. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +1 -1
  52. package/dist-cjs/lib/editor/overlays/OverlayManager.js +154 -0
  53. package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +7 -0
  54. package/dist-cjs/lib/editor/overlays/OverlayUtil.js +92 -0
  55. package/dist-cjs/lib/editor/overlays/OverlayUtil.js.map +7 -0
  56. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +161 -0
  57. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
  58. package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js +39 -0
  59. package/dist-cjs/lib/editor/overlays/getOverlayDisplayValues.js.map +7 -0
  60. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +79 -0
  61. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +7 -0
  62. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +36 -23
  63. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  64. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +32 -2
  65. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  66. package/dist-cjs/lib/editor/tools/StateNode.js +1 -0
  67. package/dist-cjs/lib/editor/tools/StateNode.js.map +1 -1
  68. package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
  69. package/dist-cjs/lib/exports/ExportDelay.js +1 -0
  70. package/dist-cjs/lib/exports/ExportDelay.js.map +1 -1
  71. package/dist-cjs/lib/exports/StyleEmbedder.js +1 -0
  72. package/dist-cjs/lib/exports/StyleEmbedder.js.map +1 -1
  73. package/dist-cjs/lib/exports/fetchCache.js +1 -1
  74. package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
  75. package/dist-cjs/lib/exports/getSvgJsx.js +2 -1
  76. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  77. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
  78. package/dist-cjs/lib/hooks/useCanvasEvents.js +25 -4
  79. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  80. package/dist-cjs/lib/hooks/useEditorComponents.js +0 -28
  81. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  82. package/dist-cjs/lib/hooks/usePeerIds.js +1 -36
  83. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  84. package/dist-cjs/lib/hooks/useShapeCulling.js +2 -1
  85. package/dist-cjs/lib/hooks/useShapeCulling.js.map +2 -2
  86. package/dist-cjs/lib/options.js +1 -0
  87. package/dist-cjs/lib/options.js.map +2 -2
  88. package/dist-cjs/lib/primitives/Vec.js +3 -0
  89. package/dist-cjs/lib/primitives/Vec.js.map +1 -1
  90. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -0
  91. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +1 -1
  92. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -0
  93. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +1 -1
  94. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -0
  95. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +1 -1
  96. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +1 -0
  97. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +1 -1
  98. package/dist-cjs/lib/utils/EditorAtom.js +2 -0
  99. package/dist-cjs/lib/utils/EditorAtom.js.map +1 -1
  100. package/dist-cjs/lib/utils/reparenting.js +20 -7
  101. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  102. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +5 -0
  103. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  104. package/dist-cjs/version.js +4 -4
  105. package/dist-cjs/version.js.map +1 -1
  106. package/dist-esm/index.d.mts +493 -170
  107. package/dist-esm/index.mjs +21 -41
  108. package/dist-esm/index.mjs.map +2 -2
  109. package/dist-esm/lib/TldrawEditor.mjs +3 -0
  110. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  111. package/dist-esm/lib/components/MenuClickCapture.mjs +94 -48
  112. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  113. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +160 -0
  114. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +7 -0
  115. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +47 -249
  116. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +3 -3
  117. package/dist-esm/lib/editor/Editor.mjs +143 -35
  118. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  119. package/dist-esm/lib/editor/assets/AssetUtil.mjs +1 -0
  120. package/dist-esm/lib/editor/assets/AssetUtil.mjs.map +1 -1
  121. package/dist-esm/lib/editor/bindings/BindingUtil.mjs +1 -0
  122. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +1 -1
  123. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -0
  124. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +1 -1
  125. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +83 -0
  126. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +7 -0
  127. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +1 -0
  128. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +1 -1
  129. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -0
  130. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +1 -1
  131. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -0
  132. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +1 -1
  133. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +2 -0
  134. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +1 -1
  135. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +12 -0
  136. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  137. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -0
  138. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +1 -1
  139. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +1 -0
  140. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
  141. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +1 -0
  142. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
  143. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +2 -1
  144. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  145. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +1 -0
  146. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +1 -1
  147. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +1 -0
  148. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +1 -1
  149. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +1 -0
  150. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +1 -1
  151. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +14 -0
  152. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +2 -2
  153. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -0
  154. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
  155. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +2 -0
  156. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +1 -1
  157. package/dist-esm/lib/editor/overlays/OverlayManager.mjs +136 -0
  158. package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +7 -0
  159. package/dist-esm/lib/editor/overlays/OverlayUtil.mjs +72 -0
  160. package/dist-esm/lib/editor/overlays/OverlayUtil.mjs.map +7 -0
  161. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +141 -0
  162. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
  163. package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs +19 -0
  164. package/dist-esm/lib/editor/overlays/getOverlayDisplayValues.mjs.map +7 -0
  165. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +59 -0
  166. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +7 -0
  167. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +36 -23
  168. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  169. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +32 -2
  170. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  171. package/dist-esm/lib/editor/tools/StateNode.mjs +1 -0
  172. package/dist-esm/lib/editor/tools/StateNode.mjs.map +1 -1
  173. package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
  174. package/dist-esm/lib/exports/ExportDelay.mjs +1 -0
  175. package/dist-esm/lib/exports/ExportDelay.mjs.map +1 -1
  176. package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -0
  177. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +1 -1
  178. package/dist-esm/lib/exports/fetchCache.mjs +2 -2
  179. package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
  180. package/dist-esm/lib/exports/getSvgJsx.mjs +2 -1
  181. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  182. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
  183. package/dist-esm/lib/hooks/useCanvasEvents.mjs +25 -4
  184. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  185. package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -28
  186. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  187. package/dist-esm/lib/hooks/usePeerIds.mjs +2 -40
  188. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  189. package/dist-esm/lib/hooks/useShapeCulling.mjs +2 -1
  190. package/dist-esm/lib/hooks/useShapeCulling.mjs.map +2 -2
  191. package/dist-esm/lib/options.mjs +1 -0
  192. package/dist-esm/lib/options.mjs.map +2 -2
  193. package/dist-esm/lib/primitives/Vec.mjs +3 -0
  194. package/dist-esm/lib/primitives/Vec.mjs.map +1 -1
  195. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -0
  196. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +1 -1
  197. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +1 -0
  198. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +1 -1
  199. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -0
  200. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +1 -1
  201. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +1 -0
  202. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +1 -1
  203. package/dist-esm/lib/utils/EditorAtom.mjs +2 -0
  204. package/dist-esm/lib/utils/EditorAtom.mjs.map +1 -1
  205. package/dist-esm/lib/utils/reparenting.mjs +20 -7
  206. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  207. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +5 -0
  208. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  209. package/dist-esm/version.mjs +4 -4
  210. package/dist-esm/version.mjs.map +1 -1
  211. package/editor.css +4 -243
  212. package/package.json +7 -7
  213. package/src/index.ts +18 -39
  214. package/src/lib/TldrawEditor.tsx +9 -0
  215. package/src/lib/components/MenuClickCapture.tsx +124 -64
  216. package/src/lib/components/default-components/CanvasOverlays.tsx +208 -0
  217. package/src/lib/components/default-components/DefaultCanvas.tsx +51 -322
  218. package/src/lib/editor/Editor.test.ts +3 -1
  219. package/src/lib/editor/Editor.ts +167 -38
  220. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +98 -0
  221. package/src/lib/editor/managers/InputsManager/InputsManager.ts +12 -0
  222. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -2
  223. package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
  224. package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +14 -0
  225. package/src/lib/editor/overlays/OverlayManager.ts +183 -0
  226. package/src/lib/editor/overlays/OverlayUtil.ts +143 -0
  227. package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +216 -0
  228. package/src/lib/editor/overlays/getOverlayDisplayValues.ts +51 -0
  229. package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +128 -0
  230. package/src/lib/editor/shapes/ShapeUtil.ts +45 -26
  231. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +40 -3
  232. package/src/lib/editor/types/event-types.ts +2 -0
  233. package/src/lib/exports/fetchCache.ts +2 -4
  234. package/src/lib/exports/getSvgJsx.test.ts +3 -1
  235. package/src/lib/exports/getSvgJsx.tsx +2 -1
  236. package/src/lib/hooks/EditorComponentsContext.tsx +0 -27
  237. package/src/lib/hooks/useCanvasEvents.ts +45 -3
  238. package/src/lib/hooks/useEditorComponents.tsx +0 -28
  239. package/src/lib/hooks/usePeerIds.ts +6 -55
  240. package/src/lib/hooks/useShapeCulling.tsx +3 -1
  241. package/src/lib/options.ts +7 -0
  242. package/src/lib/utils/reparenting.ts +22 -9
  243. package/src/lib/utils/sync/TLLocalSyncClient.ts +3 -0
  244. package/src/version.ts +4 -4
  245. package/dist-cjs/lib/components/GeometryDebuggingView.js +0 -115
  246. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +0 -7
  247. package/dist-cjs/lib/components/LiveCollaborators.js +0 -151
  248. package/dist-cjs/lib/components/LiveCollaborators.js.map +0 -7
  249. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +0 -227
  250. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +0 -7
  251. package/dist-cjs/lib/components/default-components/DefaultBrush.js +0 -38
  252. package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +0 -7
  253. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +0 -71
  254. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +0 -7
  255. package/dist-cjs/lib/components/default-components/DefaultCursor.js +0 -59
  256. package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +0 -7
  257. package/dist-cjs/lib/components/default-components/DefaultHandle.js +0 -56
  258. package/dist-cjs/lib/components/default-components/DefaultHandle.js.map +0 -7
  259. package/dist-cjs/lib/components/default-components/DefaultHandles.js +0 -28
  260. package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +0 -7
  261. package/dist-cjs/lib/components/default-components/DefaultScribble.js +0 -51
  262. package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +0 -7
  263. package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js +0 -69
  264. package/dist-cjs/lib/components/default-components/DefaultSelectionForeground.js.map +0 -7
  265. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +0 -107
  266. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +0 -7
  267. package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js +0 -28
  268. package/dist-cjs/lib/components/default-components/DefaultShapeIndicatorErrorFallback.js.map +0 -7
  269. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +0 -101
  270. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +0 -7
  271. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +0 -170
  272. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +0 -7
  273. package/dist-cjs/lib/hooks/useHandleEvents.js +0 -100
  274. package/dist-cjs/lib/hooks/useHandleEvents.js.map +0 -7
  275. package/dist-cjs/lib/hooks/useSelectionEvents.js +0 -98
  276. package/dist-cjs/lib/hooks/useSelectionEvents.js.map +0 -7
  277. package/dist-esm/lib/components/GeometryDebuggingView.mjs +0 -95
  278. package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +0 -7
  279. package/dist-esm/lib/components/LiveCollaborators.mjs +0 -134
  280. package/dist-esm/lib/components/LiveCollaborators.mjs.map +0 -7
  281. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +0 -207
  282. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +0 -7
  283. package/dist-esm/lib/components/default-components/DefaultBrush.mjs +0 -18
  284. package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +0 -7
  285. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +0 -41
  286. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +0 -7
  287. package/dist-esm/lib/components/default-components/DefaultCursor.mjs +0 -29
  288. package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +0 -7
  289. package/dist-esm/lib/components/default-components/DefaultHandle.mjs +0 -26
  290. package/dist-esm/lib/components/default-components/DefaultHandle.mjs.map +0 -7
  291. package/dist-esm/lib/components/default-components/DefaultHandles.mjs +0 -8
  292. package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +0 -7
  293. package/dist-esm/lib/components/default-components/DefaultScribble.mjs +0 -21
  294. package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +0 -7
  295. package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs +0 -39
  296. package/dist-esm/lib/components/default-components/DefaultSelectionForeground.mjs.map +0 -7
  297. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +0 -77
  298. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +0 -7
  299. package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs +0 -8
  300. package/dist-esm/lib/components/default-components/DefaultShapeIndicatorErrorFallback.mjs.map +0 -7
  301. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +0 -81
  302. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +0 -7
  303. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +0 -142
  304. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +0 -7
  305. package/dist-esm/lib/hooks/useHandleEvents.mjs +0 -70
  306. package/dist-esm/lib/hooks/useHandleEvents.mjs.map +0 -7
  307. package/dist-esm/lib/hooks/useSelectionEvents.mjs +0 -78
  308. package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +0 -7
  309. package/src/lib/components/GeometryDebuggingView.tsx +0 -108
  310. package/src/lib/components/LiveCollaborators.tsx +0 -174
  311. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +0 -289
  312. package/src/lib/components/default-components/DefaultBrush.tsx +0 -35
  313. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +0 -52
  314. package/src/lib/components/default-components/DefaultCursor.tsx +0 -59
  315. package/src/lib/components/default-components/DefaultHandle.tsx +0 -42
  316. package/src/lib/components/default-components/DefaultHandles.tsx +0 -15
  317. package/src/lib/components/default-components/DefaultScribble.tsx +0 -31
  318. package/src/lib/components/default-components/DefaultSelectionForeground.tsx +0 -50
  319. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +0 -104
  320. package/src/lib/components/default-components/DefaultShapeIndicatorErrorFallback.tsx +0 -9
  321. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +0 -116
  322. package/src/lib/components/default-components/DefaultSnapIndictor.tsx +0 -174
  323. package/src/lib/hooks/useHandleEvents.ts +0 -88
  324. package/src/lib/hooks/useSelectionEvents.ts +0 -97
@@ -0,0 +1,183 @@
1
+ import { atom, computed } from '@tldraw/state'
2
+ import { Geometry2d } from '../../primitives/geometry/Geometry2d'
3
+ import { VecLike } from '../../primitives/Vec'
4
+ import type { Editor } from '../Editor'
5
+ import { OverlayUtil, TLOverlay } from './OverlayUtil'
6
+
7
+ /**
8
+ * An active overlay util paired with the overlays it produced for the current
9
+ * editor state. Returned by {@link OverlayManager.getActiveOverlayEntries} so
10
+ * hit-test, render, and debug paths share a single scan per reactive tick.
11
+ *
12
+ * @public
13
+ */
14
+ export interface TLOverlayEntry {
15
+ util: OverlayUtil
16
+ overlays: TLOverlay[]
17
+ }
18
+
19
+ /** @public */
20
+ export class OverlayManager {
21
+ constructor(public readonly editor: Editor) {}
22
+
23
+ /** @internal */
24
+ readonly _overlayUtils = new Map<string, OverlayUtil>()
25
+
26
+ /**
27
+ * Register an overlay util instance. Called during editor construction.
28
+ * @internal
29
+ */
30
+ registerUtil(util: OverlayUtil) {
31
+ const type = (util.constructor as typeof OverlayUtil).type
32
+ if (!type) {
33
+ throw new Error(`Overlay util ${util.constructor.name} is missing a static 'type' property.`)
34
+ }
35
+ if (this._overlayUtils.has(type)) {
36
+ throw new Error(`Duplicate overlay util type: "${type}"`)
37
+ }
38
+ this._overlayUtils.set(type, util)
39
+ }
40
+
41
+ /**
42
+ * Get an overlay util by type string, overlay instance, or by passing
43
+ * a util class as a generic parameter for type-safe lookup.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const util = editor.overlays.getOverlayUtil('brush')
48
+ * const util = editor.overlays.getOverlayUtil<BrushOverlayUtil>('brush')
49
+ * const util = editor.overlays.getOverlayUtil(myOverlay)
50
+ * ```
51
+ *
52
+ * @public
53
+ */
54
+ getOverlayUtil<T extends OverlayUtil>(
55
+ type: T extends OverlayUtil<infer O> ? O['type'] : string
56
+ ): T
57
+ getOverlayUtil<O extends TLOverlay>(overlay: O): OverlayUtil<O>
58
+ getOverlayUtil(arg: string | TLOverlay): OverlayUtil {
59
+ const type = typeof arg === 'string' ? arg : arg.type
60
+ const util = this._overlayUtils.get(type)
61
+ if (!util) throw new Error(`No overlay util found for type: "${type}"`)
62
+ return util
63
+ }
64
+
65
+ /**
66
+ * Returns all registered overlay utils in paint order (ascending zIndex).
67
+ * Utils with the same zIndex preserve their registration order.
68
+ *
69
+ * @public
70
+ */
71
+ @computed getOverlayUtilsInZOrder(): OverlayUtil[] {
72
+ const utils = Array.from(this._overlayUtils.values())
73
+ // Stable sort by zIndex (registration order breaks ties).
74
+ return utils
75
+ .map((util, i) => ({ util, i, z: util.options.zIndex ?? 0 }))
76
+ .sort((a, b) => a.z - b.z || a.i - b.i)
77
+ .map((entry) => entry.util)
78
+ }
79
+
80
+ /**
81
+ * Reactive list of active overlay utils paired with the overlays they
82
+ * produced for the current editor state, in paint order (ascending
83
+ * zIndex). Both the hit-test and render paths read from this single
84
+ * cached scan instead of each re-deriving the active set. Active utils
85
+ * are included even when their `getOverlays()` returns an empty array,
86
+ * since `render()` may still draw non-interactive UI (e.g. the selection
87
+ * bounding box during brushing).
88
+ *
89
+ * @public
90
+ */
91
+ @computed getActiveOverlayEntries(): TLOverlayEntry[] {
92
+ const entries: TLOverlayEntry[] = []
93
+ for (const util of this.getOverlayUtilsInZOrder()) {
94
+ if (!util.isActive()) continue
95
+ entries.push({ util, overlays: util.getOverlays() })
96
+ }
97
+ return entries
98
+ }
99
+
100
+ /**
101
+ * Reactively computed list of all currently active overlays, in paint order.
102
+ * @public
103
+ */
104
+ @computed getCurrentOverlays(): TLOverlay[] {
105
+ const all: TLOverlay[] = []
106
+ for (const { overlays } of this.getActiveOverlayEntries()) {
107
+ all.push(...overlays)
108
+ }
109
+ return all
110
+ }
111
+
112
+ // Hit-test geometry cache keyed by overlay identity. Entries remain valid
113
+ // while getActiveOverlayEntries() keeps returning the same overlay
114
+ // instances; when its reactive deps change, getOverlays() emits fresh
115
+ // objects and stale entries fall out by GC.
116
+ private _geometryCache = new WeakMap<TLOverlay, Geometry2d | null>()
117
+
118
+ /**
119
+ * Get hit-test geometry for an overlay, cached by overlay identity. Lets
120
+ * hit-testing on a pointermove storm skip the per-overlay geometry
121
+ * allocation that {@link OverlayUtil.getGeometry} would otherwise do on
122
+ * every call.
123
+ *
124
+ * @public
125
+ */
126
+ getOverlayGeometry(overlay: TLOverlay): Geometry2d | null {
127
+ const cached = this._geometryCache.get(overlay)
128
+ if (cached !== undefined) return cached
129
+ const util = this.getOverlayUtil(overlay)
130
+ const geometry = util.getGeometry(overlay)
131
+ this._geometryCache.set(overlay, geometry)
132
+ return geometry
133
+ }
134
+
135
+ /**
136
+ * The currently hovered overlay id.
137
+ * @public
138
+ */
139
+ private _hoveredOverlayId = atom<string | null>('hoveredOverlayId', null)
140
+
141
+ getHoveredOverlayId(): string | null {
142
+ return this._hoveredOverlayId.get()
143
+ }
144
+
145
+ getHoveredOverlay(): TLOverlay | null {
146
+ const id = this._hoveredOverlayId.get()
147
+ if (!id) return null
148
+ return this.getCurrentOverlays().find((o) => o.id === id) ?? null
149
+ }
150
+
151
+ setHoveredOverlay(id: string | null) {
152
+ if (id === this._hoveredOverlayId.get()) return
153
+ this._hoveredOverlayId.set(id)
154
+ }
155
+
156
+ /**
157
+ * Hit test all active overlays at a given page point.
158
+ * Returns the topmost overlay whose geometry contains the point, or null.
159
+ * Utils are walked from highest zIndex to lowest so the overlay painted on
160
+ * top also wins the hit test. Within a util, overlays are walked in
161
+ * array order: the first overlay whose geometry contains the point wins,
162
+ * so utils should place highest-priority overlays first in `getOverlays`.
163
+ * Interactive overlays (those with geometry) are checked; non-interactive are skipped.
164
+ *
165
+ * @param point - Point in page coordinates
166
+ * @param margin - Hit test margin
167
+ * @public
168
+ */
169
+ getOverlayAtPoint(point: VecLike, margin = 0): TLOverlay | null {
170
+ const entries = this.getActiveOverlayEntries()
171
+ for (let i = entries.length - 1; i >= 0; i--) {
172
+ const { overlays } = entries[i]
173
+ for (const overlay of overlays) {
174
+ const geometry = this.getOverlayGeometry(overlay)
175
+ if (!geometry) continue
176
+ if (geometry.hitTestPoint(point, geometry.isFilled ? 0 : margin, true)) {
177
+ return overlay
178
+ }
179
+ }
180
+ }
181
+ return null
182
+ }
183
+ }
@@ -0,0 +1,143 @@
1
+ import { TLCursorType } from '@tldraw/tlschema'
2
+ import { Geometry2d } from '../../primitives/geometry/Geometry2d'
3
+ import type { Editor } from '../Editor'
4
+ import { TLPointerEventInfo } from '../types/event-types'
5
+
6
+ /** @public */
7
+ export interface TLOverlay<Props = Record<string, unknown>> {
8
+ /**
9
+ * Globally unique id for this overlay instance across all overlay utils.
10
+ * Hit-test and hover lookup key on `id` alone, so utils must namespace their
11
+ * ids (e.g. `'selection_fg:top_left'`, `'handle:<shapeId>:<handleId>'`) to
12
+ * avoid colliding with overlays from other utils.
13
+ */
14
+ id: string
15
+ /** The overlay util type that owns this instance */
16
+ type: string
17
+ /** Arbitrary props for the overlay (handle id, corner name, etc.) */
18
+ props: Props
19
+ }
20
+
21
+ /** @public */
22
+ export interface TLOverlayUtilConstructor<U extends OverlayUtil = OverlayUtil> {
23
+ new (editor: Editor): U
24
+ type: string
25
+ configure<T extends TLOverlayUtilConstructor<any>>(
26
+ this: T,
27
+ options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
28
+ ): T
29
+ }
30
+
31
+ /** @public */
32
+ export type TLAnyOverlayUtilConstructor = TLOverlayUtilConstructor<any>
33
+
34
+ /**
35
+ * Base class for overlay utilities. Overlays are ephemeral UI elements rendered
36
+ * on top of the canvas (selection handles, rotation corners, shape handles, etc.).
37
+ *
38
+ * Each OverlayUtil defines a type of overlay and knows how to:
39
+ * - Determine when its overlays should be active (predicate)
40
+ * - Produce overlay instances from current editor state
41
+ * - Provide hit-test geometry for interactive overlays
42
+ * - Provide cursor style on hover
43
+ * - Render into a canvas 2D context
44
+ *
45
+ * @public
46
+ */
47
+ export abstract class OverlayUtil<T extends TLOverlay = TLOverlay> {
48
+ constructor(public editor: Editor) {}
49
+ static type: string
50
+
51
+ /**
52
+ * Options for this overlay util. Override this to provide customization options.
53
+ * Use {@link OverlayUtil.configure} to customize existing overlay utils.
54
+ *
55
+ * `zIndex` controls paint and hit-test order across utils — higher numbers
56
+ * paint on top and are hit-tested first. Ties resolve by registration order.
57
+ * Defaults to `0`; built-in utils use larger integers (100, 200, …) with
58
+ * gaps so custom utils can slot between.
59
+ *
60
+ * @public
61
+ */
62
+ options: { zIndex?: number } = {}
63
+
64
+ /**
65
+ * Create a new overlay util class with the given options merged in.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const MyBrush = BrushOverlayUtil.configure({ fill: 'rgba(0,0,255,0.1)' })
70
+ * ```
71
+ *
72
+ * @public
73
+ */
74
+ static configure<T extends TLOverlayUtilConstructor<any>>(
75
+ this: T,
76
+ options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
77
+ ): T {
78
+ // @ts-expect-error -- typescript has no idea what's going on here but it's fine
79
+ return class extends this {
80
+ // @ts-expect-error
81
+ options = { ...this.options, ...options }
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Whether this overlay util's overlays should currently be active.
87
+ * Checked reactively to determine which overlays exist at any given time.
88
+ */
89
+ abstract isActive(): boolean
90
+
91
+ /**
92
+ * Returns the overlay instances that currently exist.
93
+ * Called only when `isActive()` returns true.
94
+ */
95
+ abstract getOverlays(): T[]
96
+
97
+ /**
98
+ * Returns hit-test geometry for an overlay instance, in page coordinates.
99
+ * Return null for non-interactive overlays (e.g. snap indicators, scribbles).
100
+ */
101
+ getGeometry(_overlay: T): Geometry2d | null {
102
+ return null
103
+ }
104
+
105
+ /**
106
+ * Returns the cursor type to show when hovering this overlay.
107
+ */
108
+ getCursor(_overlay: T): TLCursorType | undefined {
109
+ return undefined
110
+ }
111
+
112
+ /**
113
+ * Called when the user points down on this overlay, before the default
114
+ * routing runs. Acts as an interrupt: define it to take over the event.
115
+ *
116
+ * Return `false` to continue with the default behavior (e.g. the
117
+ * built-in rotate/resize handle transitions or shape-handle dispatch).
118
+ * Return `true` — or nothing at all — to skip the default. In other
119
+ * words, once you override this method you own the event unless you
120
+ * explicitly opt back in by returning `false`.
121
+ */
122
+ onPointerDown?(overlay: T, info: TLPointerEventInfo): boolean | void
123
+
124
+ /**
125
+ * Render all active overlays into the canvas context.
126
+ * The context is already transformed to page space (camera transform applied).
127
+ * Called reactively when overlays or editor state changes.
128
+ */
129
+ render(_ctx: CanvasRenderingContext2D, _overlays: T[]): void {}
130
+
131
+ /**
132
+ * Optional: render all active overlays into the minimap canvas.
133
+ * The context is already transformed to page space (minimap camera applied),
134
+ * so overlays can use the same page-space coordinates as in {@link OverlayUtil.render}.
135
+ *
136
+ * `zoom` is the minimap's screen-pixels-per-page-unit, analogous to
137
+ * `editor.getCamera().z`; use `1 / zoom` for one-minimap-pixel line widths.
138
+ *
139
+ * Most overlays should leave this blank — only overlays that are meaningful
140
+ * at minimap scale (e.g. brushes, collaborator cursors) should opt in.
141
+ */
142
+ renderMinimap(_ctx: CanvasRenderingContext2D, _overlays: T[], _zoom: number): void {}
143
+ }
@@ -0,0 +1,216 @@
1
+ import { computed } from '@tldraw/state'
2
+ import { createComputedCache } from '@tldraw/store'
3
+ import { TLShape, TLShapeId } from '@tldraw/tlschema'
4
+ import type { Editor } from '../Editor'
5
+ import { OverlayUtil, TLOverlay } from './OverlayUtil'
6
+
7
+ interface RelevantInstanceFlags {
8
+ isChangingStyle: boolean
9
+ isHoveringCanvas: boolean | null
10
+ isCoarsePointer: boolean
11
+ }
12
+
13
+ /** @public */
14
+ export interface TLShapeIndicatorOverlay extends TLOverlay {
15
+ props: {
16
+ idsToDisplay: TLShapeId[]
17
+ hintingShapeIds: TLShapeId[]
18
+ }
19
+ }
20
+
21
+ const indicatorPathCache = createComputedCache(
22
+ 'shapeIndicatorPath',
23
+ (editor: Editor, shape: TLShape) => {
24
+ const util = editor.getShapeUtil(shape)
25
+ return util.getIndicatorPath(shape)
26
+ },
27
+ {
28
+ areRecordsEqual(a, b) {
29
+ return a.props === b.props
30
+ },
31
+ }
32
+ )
33
+
34
+ /**
35
+ * Combine every batchable shape indicator into a single page-space `Path2D` and
36
+ * emit one stroke call. Shapes whose indicator needs an evenodd clip (e.g.
37
+ * arrows with labels or complex arrowheads) can't be batched — they still
38
+ * stroke individually inside a save/restore with `ctx.clip` applied.
39
+ *
40
+ * Shared by {@link ShapeIndicatorOverlayUtil} and any overlay util that paints
41
+ * shape indicators (e.g. collaborator selections).
42
+ *
43
+ * @public
44
+ */
45
+ export function strokeShapeIndicators(
46
+ editor: Editor,
47
+ ctx: CanvasRenderingContext2D,
48
+ shapeIds: TLShapeId[]
49
+ ): void {
50
+ if (shapeIds.length === 0) return
51
+
52
+ const batched = new Path2D()
53
+
54
+ for (const shapeId of shapeIds) {
55
+ const shape = editor.getShape(shapeId)
56
+ if (!shape || shape.isLocked) continue
57
+
58
+ const pageTransform = editor.getShapePageTransform(shape)
59
+ if (!pageTransform) continue
60
+
61
+ const indicatorPath = indicatorPathCache.get(editor, shape.id)
62
+ if (!indicatorPath) continue
63
+
64
+ if (indicatorPath instanceof Path2D) {
65
+ batched.addPath(indicatorPath, pageTransform)
66
+ continue
67
+ }
68
+
69
+ const { path, clipPath, additionalPaths } = indicatorPath
70
+
71
+ if (!clipPath) {
72
+ batched.addPath(path, pageTransform)
73
+ if (additionalPaths) {
74
+ for (const p of additionalPaths) batched.addPath(p, pageTransform)
75
+ }
76
+ continue
77
+ }
78
+
79
+ // Clipped case: fall back to an individual stroke. Rare (arrows with
80
+ // labels / complex arrowheads), so the extra save/restore/stroke
81
+ // pair per such shape isn't worth batching away.
82
+ ctx.save()
83
+ ctx.transform(
84
+ pageTransform.a,
85
+ pageTransform.b,
86
+ pageTransform.c,
87
+ pageTransform.d,
88
+ pageTransform.e,
89
+ pageTransform.f
90
+ )
91
+ ctx.save()
92
+ ctx.clip(clipPath, 'evenodd')
93
+ ctx.stroke(path)
94
+ ctx.restore()
95
+ if (additionalPaths) {
96
+ for (const p of additionalPaths) ctx.stroke(p)
97
+ }
98
+ ctx.restore()
99
+ }
100
+
101
+ ctx.stroke(batched)
102
+ }
103
+
104
+ /**
105
+ * Overlay util for shape indicators — the selection / hover / hint outlines drawn
106
+ * under the selection foreground. Paints local indicators in the theme's
107
+ * selection color.
108
+ *
109
+ * Remote collaborator selection indicators are drawn by a separate overlay util
110
+ * (e.g. `CollaboratorShapeIndicatorOverlayUtil` from `tldraw`) that runs at a
111
+ * lower z-index so peer selections appear under the local indicators.
112
+ *
113
+ * Non-interactive: contributes no hit-test geometry.
114
+ *
115
+ * @public
116
+ */
117
+ export class ShapeIndicatorOverlayUtil extends OverlayUtil<TLShapeIndicatorOverlay> {
118
+ static override type = 'shape_indicator'
119
+ override options = { zIndex: 50, lineWidth: 1.5, hintedLineWidth: 2.5 }
120
+
121
+ // Narrow projection of instance state. Reading the full record would
122
+ // re-fire getOverlays on every cursor move / brush update; gating on these
123
+ // three booleans means we only re-fire when one of them actually flips.
124
+ private _instanceFlags$ = computed<RelevantInstanceFlags>(
125
+ 'shape indicator instance flags',
126
+ () => {
127
+ const i = this.editor.getInstanceState()
128
+ return {
129
+ isChangingStyle: i.isChangingStyle,
130
+ isHoveringCanvas: i.isHoveringCanvas,
131
+ isCoarsePointer: i.isCoarsePointer,
132
+ }
133
+ },
134
+ {
135
+ isEqual: (a, b) =>
136
+ a.isChangingStyle === b.isChangingStyle &&
137
+ a.isHoveringCanvas === b.isHoveringCanvas &&
138
+ a.isCoarsePointer === b.isCoarsePointer,
139
+ }
140
+ )
141
+
142
+ override isActive(): boolean {
143
+ return true
144
+ }
145
+
146
+ override getOverlays(): TLShapeIndicatorOverlay[] {
147
+ const editor = this.editor
148
+ const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id))
149
+
150
+ // Local selected / hovered indicators.
151
+ const idsToDisplay: TLShapeId[] = []
152
+ const { isChangingStyle, isHoveringCanvas, isCoarsePointer } = this._instanceFlags$.get()
153
+ const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
154
+ const isInSelectState = editor.isInAny(
155
+ 'select.brushing',
156
+ 'select.scribble_brushing',
157
+ 'select.pointing_shape',
158
+ 'select.pointing_selection',
159
+ 'select.pointing_handle'
160
+ )
161
+
162
+ if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) {
163
+ for (const id of editor.getSelectedShapeIds()) {
164
+ if (renderingShapeIds.has(id)) idsToDisplay.push(id)
165
+ }
166
+ if (isIdleOrEditing && isHoveringCanvas && !isCoarsePointer) {
167
+ const hovered = editor.getHoveredShapeId()
168
+ if (hovered && renderingShapeIds.has(hovered) && !idsToDisplay.includes(hovered)) {
169
+ idsToDisplay.push(hovered)
170
+ }
171
+ }
172
+ }
173
+
174
+ // Hinted shapes (drawn thicker). Already deduped at write time in
175
+ // `updateHintingShapeIds`, so no need to dedupe again here.
176
+ const hintingShapeIds: TLShapeId[] = []
177
+ for (const id of editor.getHintingShapeIds()) {
178
+ if (renderingShapeIds.has(id)) hintingShapeIds.push(id)
179
+ }
180
+
181
+ if (idsToDisplay.length === 0 && hintingShapeIds.length === 0) {
182
+ return []
183
+ }
184
+
185
+ return [
186
+ {
187
+ id: 'shape_indicator',
188
+ type: 'shape_indicator',
189
+ props: { idsToDisplay, hintingShapeIds },
190
+ },
191
+ ]
192
+ }
193
+
194
+ override render(ctx: CanvasRenderingContext2D, overlays: TLShapeIndicatorOverlay[]): void {
195
+ const overlay = overlays[0]
196
+ if (!overlay) return
197
+
198
+ const editor = this.editor
199
+ const zoom = editor.getZoomLevel()
200
+ const { idsToDisplay, hintingShapeIds } = overlay.props
201
+
202
+ ctx.lineCap = 'round'
203
+ ctx.lineJoin = 'round'
204
+
205
+ // Local selected / hovered indicators — one stroke call for the whole batch.
206
+ ctx.strokeStyle = editor.getCurrentTheme().colors[editor.getColorMode()].selectionStroke
207
+ ctx.lineWidth = this.options.lineWidth / zoom
208
+ strokeShapeIndicators(editor, ctx, idsToDisplay)
209
+
210
+ // Hinted shapes — thicker stroke, one call for the whole batch.
211
+ if (hintingShapeIds.length > 0) {
212
+ ctx.lineWidth = this.options.hintedLineWidth / zoom
213
+ strokeShapeIndicators(editor, ctx, hintingShapeIds)
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,51 @@
1
+ import { TLTheme } from '@tldraw/tlschema'
2
+ import type { Editor } from '../Editor'
3
+ import { TLOverlay } from './OverlayUtil'
4
+
5
+ /** @public */
6
+ export interface OverlayOptionsWithDisplayValues<
7
+ Overlay extends TLOverlay,
8
+ DisplayValues extends object,
9
+ > {
10
+ getDefaultDisplayValues(
11
+ editor: Editor,
12
+ overlay: Overlay,
13
+ theme: TLTheme,
14
+ colorMode: 'light' | 'dark'
15
+ ): DisplayValues
16
+ getCustomDisplayValues(
17
+ editor: Editor,
18
+ overlay: Overlay,
19
+ theme: TLTheme,
20
+ colorMode: 'light' | 'dark'
21
+ ): Partial<DisplayValues>
22
+ }
23
+
24
+ const dvCache = new WeakMap<
25
+ TLOverlay,
26
+ { theme: TLTheme; colorMode: 'light' | 'dark'; values: object }
27
+ >()
28
+
29
+ /**
30
+ * Get the resolved display values for an overlay, merging the base values with any overrides.
31
+ *
32
+ * @public
33
+ */
34
+ export function getOverlayDisplayValues<Overlay extends TLOverlay, DisplayValues extends object>(
35
+ util: { editor: Editor; options: OverlayOptionsWithDisplayValues<Overlay, DisplayValues> },
36
+ overlay: Overlay,
37
+ colorMode?: 'light' | 'dark'
38
+ ): DisplayValues {
39
+ const theme = util.editor.getCurrentTheme()
40
+ const resolvedColorMode = colorMode ?? util.editor.getColorMode()
41
+ const cached = dvCache.get(overlay)
42
+ if (cached && cached.theme === theme && cached.colorMode === resolvedColorMode) {
43
+ return cached.values as DisplayValues
44
+ }
45
+ const values = {
46
+ ...util.options.getDefaultDisplayValues(util.editor, overlay, theme, resolvedColorMode),
47
+ ...util.options.getCustomDisplayValues(util.editor, overlay, theme, resolvedColorMode),
48
+ }
49
+ dvCache.set(overlay, { theme, colorMode: resolvedColorMode, values })
50
+ return values
51
+ }