@tldraw/editor 4.6.0-next.30b99cd52fc8 → 4.6.0-next.35cf541abcf9

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 (284) hide show
  1. package/dist-cjs/index.d.ts +758 -96
  2. package/dist-cjs/index.js +18 -3
  3. package/dist-cjs/index.js.map +3 -3
  4. package/dist-cjs/lib/TldrawEditor.js +55 -12
  5. package/dist-cjs/lib/TldrawEditor.js.map +3 -3
  6. package/dist-cjs/lib/components/LiveCollaborators.js +1 -0
  7. package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
  8. package/dist-cjs/lib/components/MenuClickCapture.js +99 -38
  9. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +10 -3
  11. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +3 -3
  12. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +5 -2
  13. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  14. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +1 -0
  17. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
  18. package/dist-cjs/lib/config/createTLStore.js +7 -0
  19. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  20. package/dist-cjs/lib/config/defaultAssets.js +36 -0
  21. package/dist-cjs/lib/config/defaultAssets.js.map +7 -0
  22. package/dist-cjs/lib/editor/Editor.js +279 -10
  23. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  24. package/dist-cjs/lib/editor/assets/AssetUtil.js +67 -0
  25. package/dist-cjs/lib/editor/assets/AssetUtil.js.map +7 -0
  26. package/dist-cjs/lib/editor/bindings/BindingUtil.js +1 -0
  27. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +1 -1
  28. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -0
  29. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +1 -1
  30. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +1 -0
  31. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +1 -1
  32. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -0
  33. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +1 -1
  34. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -0
  35. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  36. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +2 -0
  37. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +1 -1
  38. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +12 -0
  39. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  40. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.js +80 -0
  41. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.js.map +7 -0
  42. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js +466 -0
  43. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js.map +7 -0
  44. package/dist-cjs/lib/editor/managers/PerformanceManager/perf-types.js +17 -0
  45. package/dist-cjs/lib/editor/managers/PerformanceManager/perf-types.js.map +7 -0
  46. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -0
  47. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +1 -1
  48. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +1 -0
  49. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
  50. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +1 -0
  51. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
  52. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +2 -1
  53. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  54. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +1 -0
  55. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +1 -1
  56. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -0
  57. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +1 -1
  58. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +107 -0
  59. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +7 -0
  60. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +586 -0
  61. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +7 -0
  62. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -0
  63. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
  64. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +8 -4
  65. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  66. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +76 -0
  67. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +7 -0
  68. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +22 -2
  69. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  70. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -1
  71. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  72. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +6 -0
  73. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  74. package/dist-cjs/lib/editor/tools/StateNode.js +15 -17
  75. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  76. package/dist-cjs/lib/editor/types/SvgExportContext.js.map +2 -2
  77. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  78. package/dist-cjs/lib/exports/ExportDelay.js +1 -0
  79. package/dist-cjs/lib/exports/ExportDelay.js.map +1 -1
  80. package/dist-cjs/lib/exports/StyleEmbedder.js +1 -0
  81. package/dist-cjs/lib/exports/StyleEmbedder.js.map +1 -1
  82. package/dist-cjs/lib/exports/getSvgJsx.js +14 -8
  83. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  84. package/dist-cjs/lib/globals/environment.js +18 -1
  85. package/dist-cjs/lib/globals/environment.js.map +2 -2
  86. package/dist-cjs/lib/hooks/useCanvasEvents.js +25 -4
  87. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  88. package/dist-cjs/lib/hooks/{useIsDarkMode.js → useColorMode.js} +14 -10
  89. package/dist-cjs/lib/hooks/useColorMode.js.map +7 -0
  90. package/dist-cjs/lib/hooks/useCursor.js +3 -7
  91. package/dist-cjs/lib/hooks/useCursor.js.map +2 -2
  92. package/dist-cjs/lib/hooks/useDarkMode.js +4 -4
  93. package/dist-cjs/lib/hooks/useDarkMode.js.map +2 -2
  94. package/dist-cjs/lib/options.js +2 -0
  95. package/dist-cjs/lib/options.js.map +2 -2
  96. package/dist-cjs/lib/primitives/Vec.js +3 -0
  97. package/dist-cjs/lib/primitives/Vec.js.map +1 -1
  98. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -0
  99. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +1 -1
  100. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -0
  101. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +1 -1
  102. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -0
  103. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +1 -1
  104. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +1 -0
  105. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +1 -1
  106. package/dist-cjs/lib/utils/EditorAtom.js +2 -0
  107. package/dist-cjs/lib/utils/EditorAtom.js.map +1 -1
  108. package/dist-cjs/lib/utils/reparenting.js +2 -1
  109. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  110. package/dist-cjs/lib/utils/richText.js.map +2 -2
  111. package/dist-cjs/lib/utils/runtime.js +2 -1
  112. package/dist-cjs/lib/utils/runtime.js.map +2 -2
  113. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +2 -0
  114. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +1 -1
  115. package/dist-cjs/lib/utils/sync/hardReset.js +0 -8
  116. package/dist-cjs/lib/utils/sync/hardReset.js.map +2 -2
  117. package/dist-cjs/version.js +3 -3
  118. package/dist-cjs/version.js.map +1 -1
  119. package/dist-esm/index.d.mts +758 -96
  120. package/dist-esm/index.mjs +19 -6
  121. package/dist-esm/index.mjs.map +2 -2
  122. package/dist-esm/lib/TldrawEditor.mjs +58 -12
  123. package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
  124. package/dist-esm/lib/components/LiveCollaborators.mjs +1 -0
  125. package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
  126. package/dist-esm/lib/components/MenuClickCapture.mjs +100 -39
  127. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  128. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +10 -3
  129. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +3 -3
  130. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -2
  131. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  132. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -1
  133. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  134. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +1 -0
  135. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
  136. package/dist-esm/lib/config/createTLStore.mjs +10 -1
  137. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  138. package/dist-esm/lib/config/defaultAssets.mjs +16 -0
  139. package/dist-esm/lib/config/defaultAssets.mjs.map +7 -0
  140. package/dist-esm/lib/editor/Editor.mjs +279 -10
  141. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  142. package/dist-esm/lib/editor/assets/AssetUtil.mjs +47 -0
  143. package/dist-esm/lib/editor/assets/AssetUtil.mjs.map +7 -0
  144. package/dist-esm/lib/editor/bindings/BindingUtil.mjs +1 -0
  145. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +1 -1
  146. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -0
  147. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +1 -1
  148. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +1 -0
  149. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +1 -1
  150. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -0
  151. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +1 -1
  152. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -0
  153. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  154. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +2 -0
  155. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +1 -1
  156. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +12 -0
  157. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  158. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.mjs +60 -0
  159. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.mjs.map +7 -0
  160. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs +438 -0
  161. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs.map +7 -0
  162. package/dist-esm/lib/editor/managers/PerformanceManager/perf-types.mjs +1 -0
  163. package/dist-esm/lib/editor/managers/PerformanceManager/perf-types.mjs.map +7 -0
  164. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -0
  165. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +1 -1
  166. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +1 -0
  167. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
  168. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +1 -0
  169. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
  170. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +2 -1
  171. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  172. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +1 -0
  173. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +1 -1
  174. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +1 -0
  175. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +1 -1
  176. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +89 -0
  177. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +7 -0
  178. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +568 -0
  179. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +7 -0
  180. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -0
  181. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
  182. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +8 -4
  183. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  184. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +56 -0
  185. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +7 -0
  186. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +22 -2
  187. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  188. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -1
  189. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  190. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +6 -0
  191. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  192. package/dist-esm/lib/editor/tools/StateNode.mjs +15 -17
  193. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  194. package/dist-esm/lib/editor/types/SvgExportContext.mjs.map +2 -2
  195. package/dist-esm/lib/exports/ExportDelay.mjs +1 -0
  196. package/dist-esm/lib/exports/ExportDelay.mjs.map +1 -1
  197. package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -0
  198. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +1 -1
  199. package/dist-esm/lib/exports/getSvgJsx.mjs +14 -11
  200. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  201. package/dist-esm/lib/globals/environment.mjs +18 -1
  202. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  203. package/dist-esm/lib/hooks/useCanvasEvents.mjs +25 -4
  204. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  205. package/dist-esm/lib/hooks/useColorMode.mjs +19 -0
  206. package/dist-esm/lib/hooks/useColorMode.mjs.map +7 -0
  207. package/dist-esm/lib/hooks/useCursor.mjs +3 -7
  208. package/dist-esm/lib/hooks/useCursor.mjs.map +2 -2
  209. package/dist-esm/lib/hooks/useDarkMode.mjs +4 -4
  210. package/dist-esm/lib/hooks/useDarkMode.mjs.map +2 -2
  211. package/dist-esm/lib/options.mjs +2 -0
  212. package/dist-esm/lib/options.mjs.map +2 -2
  213. package/dist-esm/lib/primitives/Vec.mjs +3 -0
  214. package/dist-esm/lib/primitives/Vec.mjs.map +1 -1
  215. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -0
  216. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +1 -1
  217. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +1 -0
  218. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +1 -1
  219. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -0
  220. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +1 -1
  221. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +1 -0
  222. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +1 -1
  223. package/dist-esm/lib/utils/EditorAtom.mjs +2 -0
  224. package/dist-esm/lib/utils/EditorAtom.mjs.map +1 -1
  225. package/dist-esm/lib/utils/reparenting.mjs +2 -1
  226. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  227. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  228. package/dist-esm/lib/utils/runtime.mjs +2 -1
  229. package/dist-esm/lib/utils/runtime.mjs.map +2 -2
  230. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +2 -0
  231. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +1 -1
  232. package/dist-esm/lib/utils/sync/hardReset.mjs +0 -8
  233. package/dist-esm/lib/utils/sync/hardReset.mjs.map +2 -2
  234. package/dist-esm/version.mjs +3 -3
  235. package/dist-esm/version.mjs.map +1 -1
  236. package/editor.css +0 -37
  237. package/package.json +7 -7
  238. package/src/index.ts +24 -6
  239. package/src/lib/TldrawEditor.tsx +90 -13
  240. package/src/lib/components/LiveCollaborators.tsx +8 -2
  241. package/src/lib/components/MenuClickCapture.tsx +129 -49
  242. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +14 -3
  243. package/src/lib/components/default-components/DefaultCanvas.tsx +6 -2
  244. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +2 -2
  245. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +2 -0
  246. package/src/lib/config/createTLStore.ts +22 -1
  247. package/src/lib/config/defaultAssets.ts +19 -0
  248. package/src/lib/editor/Editor.ts +387 -40
  249. package/src/lib/editor/assets/AssetUtil.ts +85 -0
  250. package/src/lib/editor/managers/FontManager/FontManager.test.ts +9 -2
  251. package/src/lib/editor/managers/FontManager/FontManager.ts +1 -67
  252. package/src/lib/editor/managers/InputsManager/InputsManager.ts +12 -0
  253. package/src/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.ts +82 -0
  254. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.test.ts +522 -0
  255. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.ts +583 -0
  256. package/src/lib/editor/managers/PerformanceManager/perf-types.ts +196 -0
  257. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -2
  258. package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
  259. package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +116 -0
  260. package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +605 -0
  261. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +23 -29
  262. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +5 -3
  263. package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +121 -0
  264. package/src/lib/editor/shapes/ShapeUtil.ts +39 -3
  265. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -1
  266. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +7 -0
  267. package/src/lib/editor/tools/StateNode.ts +16 -18
  268. package/src/lib/editor/types/SvgExportContext.tsx +5 -0
  269. package/src/lib/editor/types/external-content.ts +1 -0
  270. package/src/lib/exports/getSvgJsx.tsx +23 -16
  271. package/src/lib/globals/environment.ts +18 -0
  272. package/src/lib/hooks/useCanvasEvents.ts +40 -3
  273. package/src/lib/hooks/{useIsDarkMode.ts → useColorMode.ts} +9 -5
  274. package/src/lib/hooks/useCursor.ts +3 -7
  275. package/src/lib/hooks/useDarkMode.ts +4 -4
  276. package/src/lib/options.ts +14 -0
  277. package/src/lib/utils/reparenting.ts +6 -2
  278. package/src/lib/utils/richText.ts +1 -1
  279. package/src/lib/utils/runtime.ts +3 -1
  280. package/src/lib/utils/sync/hardReset.ts +0 -8
  281. package/src/version.ts +3 -3
  282. package/dist-cjs/lib/hooks/useIsDarkMode.js.map +0 -7
  283. package/dist-esm/lib/hooks/useIsDarkMode.mjs +0 -15
  284. package/dist-esm/lib/hooks/useIsDarkMode.mjs.map +0 -7
@@ -0,0 +1,522 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import { PerformanceManager } from './PerformanceManager'
3
+
4
+ function createMockEditor() {
5
+ const listeners: Record<string, ((...args: any[]) => void)[]> = {}
6
+ return {
7
+ on(event: string, handler: (...args: any[]) => void) {
8
+ ;(listeners[event] ??= []).push(handler)
9
+ },
10
+ off(event: string, handler: (...args: any[]) => void) {
11
+ const arr = listeners[event]
12
+ if (arr) {
13
+ const idx = arr.indexOf(handler)
14
+ if (idx !== -1) arr.splice(idx, 1)
15
+ }
16
+ },
17
+ emit(event: string, ...args: any[]) {
18
+ for (const handler of listeners[event] ?? []) {
19
+ handler(...args)
20
+ }
21
+ },
22
+ getSelectedShapes: () => [
23
+ { type: 'geo', id: '1' },
24
+ { type: 'geo', id: '2' },
25
+ { type: 'draw', id: '3' },
26
+ ],
27
+ getCurrentPageShapeIds: () => ({ size: 10 }),
28
+ getCulledShapes: () => ({ size: 3 }),
29
+ getCamera: () => ({ x: 0, y: 0, z: 1 }),
30
+ getShape: (id: string) => {
31
+ const shapes: Record<string, { type: string }> = {
32
+ 'shape:1': { type: 'geo' },
33
+ 'shape:2': { type: 'draw' },
34
+ 'shape:3': { type: 'geo' },
35
+ }
36
+ return shapes[id]
37
+ },
38
+ getViewportScreenBounds: () => ({ w: 1920, h: 1080 }),
39
+ timers: {
40
+ setTimeout: (fn: () => void, ms: number) => setTimeout(fn, ms),
41
+ },
42
+ _listeners: listeners,
43
+ } as any
44
+ }
45
+
46
+ describe('PerformanceManager', () => {
47
+ describe('listener management', () => {
48
+ it('returns an unsubscribe function from on()', () => {
49
+ const editor = createMockEditor()
50
+ const pm = new PerformanceManager(editor)
51
+ const fn = vi.fn()
52
+ const unsub = pm.on('interaction-end', fn)
53
+ expect(typeof unsub).toBe('function')
54
+ unsub()
55
+ })
56
+
57
+ it('attaches frame listener lazily when interaction listener subscribes', () => {
58
+ const editor = createMockEditor()
59
+ const pm = new PerformanceManager(editor)
60
+ expect(editor._listeners['frame'] ?? []).toHaveLength(0)
61
+
62
+ const unsub = pm.on('interaction-end', vi.fn())
63
+ expect(editor._listeners['frame']).toHaveLength(1)
64
+
65
+ unsub()
66
+ expect(editor._listeners['frame'] ?? []).toHaveLength(0)
67
+ })
68
+
69
+ it('attaches shape listeners lazily', () => {
70
+ const editor = createMockEditor()
71
+ const pm = new PerformanceManager(editor)
72
+
73
+ const unsub = pm.on('shapes-created', vi.fn())
74
+ expect(editor._listeners['created-shapes']).toHaveLength(1)
75
+
76
+ unsub()
77
+ expect(editor._listeners['created-shapes'] ?? []).toHaveLength(0)
78
+ })
79
+
80
+ it('does not double-attach frame listener', () => {
81
+ const editor = createMockEditor()
82
+ const pm = new PerformanceManager(editor)
83
+
84
+ const unsub1 = pm.on('interaction-end', vi.fn())
85
+ const unsub2 = pm.on('camera-end', vi.fn())
86
+ expect(editor._listeners['frame']).toHaveLength(1)
87
+
88
+ unsub1()
89
+ // still one camera-end listener
90
+ expect(editor._listeners['frame']).toHaveLength(1)
91
+
92
+ unsub2()
93
+ expect(editor._listeners['frame'] ?? []).toHaveLength(0)
94
+ })
95
+ })
96
+
97
+ describe('interaction tracking', () => {
98
+ it('emits interaction-start when notified', () => {
99
+ const editor = createMockEditor()
100
+ const pm = new PerformanceManager(editor)
101
+ const fn = vi.fn()
102
+ pm.on('interaction-start', fn)
103
+
104
+ pm._notifyInteractionStart('translating', 'select.translating')
105
+
106
+ expect(fn).toHaveBeenCalledTimes(1)
107
+ expect(fn.mock.calls[0][0]).toMatchObject({
108
+ name: 'translating',
109
+ path: 'select.translating',
110
+ })
111
+ expect(fn.mock.calls[0][0].timestamp).toBeGreaterThan(0)
112
+ })
113
+
114
+ it('emits interaction-end with frame stats', () => {
115
+ const editor = createMockEditor()
116
+ const pm = new PerformanceManager(editor)
117
+ const fn = vi.fn()
118
+ pm.on('interaction-end', fn)
119
+
120
+ pm._notifyInteractionStart('resizing', 'select.resizing')
121
+
122
+ // Simulate frames
123
+ editor.emit('frame', 16)
124
+ editor.emit('frame', 16)
125
+ editor.emit('frame', 32)
126
+ editor.emit('frame', 16)
127
+ editor.emit('frame', 50)
128
+
129
+ pm._notifyInteractionEnd()
130
+
131
+ expect(fn).toHaveBeenCalledTimes(1)
132
+ const event = fn.mock.calls[0][0]
133
+ expect(event.name).toBe('resizing')
134
+ expect(event.path).toBe('select.resizing')
135
+ expect(event.frameCount).toBe(5)
136
+ expect(event.frameTimes).toEqual([16, 16, 32, 16, 50])
137
+ expect(event.shapeCount).toBe(10)
138
+ expect(event.selectedShapeTypes).toEqual({ geo: 2, draw: 1 })
139
+ expect(event.avgFrameTime).toBe(26)
140
+ expect(event.duration).toBeGreaterThan(0)
141
+ })
142
+
143
+ it('does not emit when no listeners', () => {
144
+ const editor = createMockEditor()
145
+ const pm = new PerformanceManager(editor)
146
+
147
+ // Should not throw
148
+ pm._notifyInteractionStart('resizing', 'select.resizing')
149
+ pm._notifyInteractionEnd()
150
+ })
151
+
152
+ it('handles end without start gracefully', () => {
153
+ const editor = createMockEditor()
154
+ const pm = new PerformanceManager(editor)
155
+ const fn = vi.fn()
156
+ pm.on('interaction-end', fn)
157
+
158
+ pm._notifyInteractionEnd()
159
+ expect(fn).not.toHaveBeenCalled()
160
+ })
161
+ })
162
+
163
+ describe('camera tracking', () => {
164
+ it('emits camera-start and camera-end', () => {
165
+ vi.useFakeTimers()
166
+ const editor = createMockEditor()
167
+ // Override timers.setTimeout to use fake timers
168
+ editor.timers.setTimeout = (fn: () => void, ms: number) => setTimeout(fn, ms) as any
169
+ const pm = new PerformanceManager(editor)
170
+ const startFn = vi.fn()
171
+ const endFn = vi.fn()
172
+ pm.on('camera-start', startFn)
173
+ pm.on('camera-end', endFn)
174
+
175
+ pm._notifyCameraOperation('panning')
176
+ expect(startFn).toHaveBeenCalledTimes(1)
177
+ expect(startFn.mock.calls[0][0].type).toBe('panning')
178
+
179
+ // Simulate frames during camera operation
180
+ editor.emit('frame', 16)
181
+ editor.emit('frame', 16)
182
+
183
+ // Wait for debounce timeout
184
+ vi.advanceTimersByTime(100)
185
+
186
+ expect(endFn).toHaveBeenCalledTimes(1)
187
+ const event = endFn.mock.calls[0][0]
188
+ expect(event.type).toBe('panning')
189
+ expect(event.frameCount).toBe(2)
190
+ expect(event.viewportWidth).toBe(1920)
191
+ expect(event.viewportHeight).toBe(1080)
192
+
193
+ vi.useRealTimers()
194
+ })
195
+
196
+ it('extends camera session on repeated operations', () => {
197
+ vi.useFakeTimers()
198
+ const editor = createMockEditor()
199
+ editor.timers.setTimeout = (fn: () => void, ms: number) => setTimeout(fn, ms) as any
200
+ const pm = new PerformanceManager(editor)
201
+ const endFn = vi.fn()
202
+ pm.on('camera-end', endFn)
203
+
204
+ pm._notifyCameraOperation('panning')
205
+ editor.emit('frame', 16)
206
+ vi.advanceTimersByTime(30)
207
+
208
+ pm._notifyCameraOperation('panning')
209
+ editor.emit('frame', 16)
210
+ vi.advanceTimersByTime(30)
211
+
212
+ // Should not have ended yet
213
+ expect(endFn).not.toHaveBeenCalled()
214
+
215
+ vi.advanceTimersByTime(100)
216
+ expect(endFn).toHaveBeenCalledTimes(1)
217
+ expect(endFn.mock.calls[0][0].frameCount).toBe(2)
218
+
219
+ vi.useRealTimers()
220
+ })
221
+
222
+ it('ends old session and starts new on type change', () => {
223
+ vi.useFakeTimers()
224
+ const editor = createMockEditor()
225
+ editor.timers.setTimeout = (fn: () => void, ms: number) => setTimeout(fn, ms) as any
226
+ const pm = new PerformanceManager(editor)
227
+ const startFn = vi.fn()
228
+ const endFn = vi.fn()
229
+ pm.on('camera-start', startFn)
230
+ pm.on('camera-end', endFn)
231
+
232
+ pm._notifyCameraOperation('panning')
233
+ editor.emit('frame', 16)
234
+
235
+ pm._notifyCameraOperation('zooming')
236
+ // Panning session should have ended
237
+ expect(endFn).toHaveBeenCalledTimes(1)
238
+ expect(endFn.mock.calls[0][0].type).toBe('panning')
239
+ // Zooming session should have started
240
+ expect(startFn).toHaveBeenCalledTimes(2)
241
+
242
+ vi.advanceTimersByTime(100)
243
+ expect(endFn).toHaveBeenCalledTimes(2)
244
+ expect(endFn.mock.calls[1][0].type).toBe('zooming')
245
+
246
+ vi.useRealTimers()
247
+ })
248
+ })
249
+
250
+ describe('frame time stats', () => {
251
+ it('computes correct percentiles', () => {
252
+ const editor = createMockEditor()
253
+ const pm = new PerformanceManager(editor)
254
+ const fn = vi.fn()
255
+ pm.on('interaction-end', fn)
256
+
257
+ pm._notifyInteractionStart('translating', 'select.translating')
258
+
259
+ // 10 frames: 10, 11, 12, 13, 14, 15, 16, 17, 18, 100
260
+ for (let i = 10; i <= 18; i++) editor.emit('frame', i)
261
+ editor.emit('frame', 100)
262
+
263
+ pm._notifyInteractionEnd()
264
+
265
+ const event = fn.mock.calls[0][0]
266
+ expect(event.minFrameTime).toBe(10)
267
+ expect(event.maxFrameTime).toBe(100)
268
+ expect(event.medianFrameTime).toBe(14)
269
+ })
270
+
271
+ it('handles single frame', () => {
272
+ const editor = createMockEditor()
273
+ const pm = new PerformanceManager(editor)
274
+ const fn = vi.fn()
275
+ pm.on('interaction-end', fn)
276
+
277
+ pm._notifyInteractionStart('translating', 'select.translating')
278
+ editor.emit('frame', 42)
279
+ pm._notifyInteractionEnd()
280
+
281
+ const event = fn.mock.calls[0][0]
282
+ expect(event.avgFrameTime).toBe(42)
283
+ expect(event.medianFrameTime).toBe(42)
284
+ expect(event.p95FrameTime).toBe(42)
285
+ expect(event.p99FrameTime).toBe(42)
286
+ expect(event.minFrameTime).toBe(42)
287
+ expect(event.maxFrameTime).toBe(42)
288
+ })
289
+
290
+ it('handles zero frames', () => {
291
+ const editor = createMockEditor()
292
+ const pm = new PerformanceManager(editor)
293
+ const fn = vi.fn()
294
+ pm.on('interaction-end', fn)
295
+
296
+ pm._notifyInteractionStart('translating', 'select.translating')
297
+ pm._notifyInteractionEnd()
298
+
299
+ const event = fn.mock.calls[0][0]
300
+ expect(event.avgFrameTime).toBe(0)
301
+ expect(event.frameCount).toBe(0)
302
+ })
303
+ })
304
+
305
+ describe('undo/redo tracking', () => {
306
+ it('emits undo events', () => {
307
+ const editor = createMockEditor()
308
+ const pm = new PerformanceManager(editor)
309
+ const fn = vi.fn()
310
+ pm.on('undo', fn)
311
+
312
+ pm._notifyUndoRedo('undo', 5, 2)
313
+
314
+ expect(fn).toHaveBeenCalledWith({ type: 'undo', undoDepth: 5, redoDepth: 2 })
315
+ })
316
+
317
+ it('emits redo events', () => {
318
+ const editor = createMockEditor()
319
+ const pm = new PerformanceManager(editor)
320
+ const fn = vi.fn()
321
+ pm.on('redo', fn)
322
+
323
+ pm._notifyUndoRedo('redo', 4, 3)
324
+
325
+ expect(fn).toHaveBeenCalledWith({ type: 'redo', undoDepth: 4, redoDepth: 3 })
326
+ })
327
+
328
+ it('skips when no listeners', () => {
329
+ const editor = createMockEditor()
330
+ const pm = new PerformanceManager(editor)
331
+ // Should not throw
332
+ pm._notifyUndoRedo('undo', 1, 0)
333
+ })
334
+ })
335
+
336
+ describe('shape operation tracking', () => {
337
+ it('emits shapes-created events', () => {
338
+ const editor = createMockEditor()
339
+ const pm = new PerformanceManager(editor)
340
+ const fn = vi.fn()
341
+ pm.on('shapes-created', fn)
342
+
343
+ editor.emit('created-shapes', [
344
+ { typeName: 'shape', type: 'geo' },
345
+ { typeName: 'shape', type: 'geo' },
346
+ { typeName: 'shape', type: 'draw' },
347
+ ])
348
+
349
+ expect(fn).toHaveBeenCalledTimes(1)
350
+ expect(fn.mock.calls[0][0]).toMatchObject({
351
+ operation: 'create',
352
+ count: 3,
353
+ shapeTypes: { geo: 2, draw: 1 },
354
+ })
355
+ })
356
+
357
+ it('ignores non-shape records', () => {
358
+ const editor = createMockEditor()
359
+ const pm = new PerformanceManager(editor)
360
+ const fn = vi.fn()
361
+ pm.on('shapes-created', fn)
362
+
363
+ editor.emit('created-shapes', [{ typeName: 'page', type: 'page' }])
364
+
365
+ expect(fn).not.toHaveBeenCalled()
366
+ })
367
+
368
+ it('emits shapes-deleted with shape types', () => {
369
+ const editor = createMockEditor()
370
+ const pm = new PerformanceManager(editor)
371
+ const fn = vi.fn()
372
+ pm.on('shapes-deleted', fn)
373
+
374
+ editor.emit('deleted-shapes', ['shape:1', 'shape:2'])
375
+
376
+ expect(fn).toHaveBeenCalledTimes(1)
377
+ expect(fn.mock.calls[0][0]).toMatchObject({
378
+ operation: 'delete',
379
+ count: 2,
380
+ shapeTypes: { geo: 1, draw: 1 },
381
+ })
382
+ })
383
+ })
384
+
385
+ describe('frame event', () => {
386
+ it('emits frame events with shape counts', () => {
387
+ const editor = createMockEditor()
388
+ const pm = new PerformanceManager(editor)
389
+ const fn = vi.fn()
390
+ pm.on('frame', fn)
391
+
392
+ editor.emit('frame', 16)
393
+
394
+ expect(fn).toHaveBeenCalledWith({
395
+ elapsed: 16,
396
+ shapeCount: 10,
397
+ culledShapeCount: 3,
398
+ visibleShapeCount: 7,
399
+ })
400
+ })
401
+ })
402
+
403
+ describe('once()', () => {
404
+ it('fires callback only once', () => {
405
+ const editor = createMockEditor()
406
+ const pm = new PerformanceManager(editor)
407
+ const fn = vi.fn()
408
+ pm.once('interaction-start', fn)
409
+
410
+ pm._notifyInteractionStart('resizing', 'select.resizing')
411
+ pm._notifyInteractionEnd()
412
+ pm._notifyInteractionStart('resizing', 'select.resizing')
413
+
414
+ expect(fn).toHaveBeenCalledTimes(1)
415
+ })
416
+
417
+ it('detaches frame listener after once fires', () => {
418
+ const editor = createMockEditor()
419
+ const pm = new PerformanceManager(editor)
420
+
421
+ pm.once('interaction-start', vi.fn())
422
+ expect(editor._listeners['frame']).toHaveLength(1)
423
+
424
+ pm._notifyInteractionStart('resizing', 'select.resizing')
425
+ // frame listener should be detached after once fires
426
+ expect(editor._listeners['frame'] ?? []).toHaveLength(0)
427
+ })
428
+ })
429
+
430
+ describe('LoAF integration', () => {
431
+ it('attaches LoAF entries to interaction-end events', () => {
432
+ let observerCallback: ((list: any) => void) | null = null
433
+ const mockDisconnect = vi.fn()
434
+
435
+ const origPO = globalThis.PerformanceObserver
436
+ globalThis.PerformanceObserver = class MockPO {
437
+ constructor(cb: (list: any) => void) {
438
+ observerCallback = cb
439
+ }
440
+ observe() {}
441
+ disconnect = mockDisconnect
442
+ static supportedEntryTypes = ['long-animation-frame']
443
+ } as any
444
+
445
+ const editor = createMockEditor()
446
+ const pm = new PerformanceManager(editor)
447
+ const fn = vi.fn()
448
+ pm.on('interaction-end', fn)
449
+
450
+ pm._notifyInteractionStart('resizing', 'select.resizing')
451
+ editor.emit('frame', 16)
452
+
453
+ // Simulate a LoAF entry
454
+ observerCallback!({
455
+ getEntries: () => [
456
+ {
457
+ startTime: 100,
458
+ duration: 80,
459
+ blockingDuration: 60,
460
+ scripts: [{ sourceURL: 'app.js', invoker: 'onPointerMove', duration: 55 }],
461
+ },
462
+ ],
463
+ })
464
+
465
+ editor.emit('frame', 16)
466
+ pm._notifyInteractionEnd()
467
+
468
+ expect(fn).toHaveBeenCalledTimes(1)
469
+ const event = fn.mock.calls[0][0]
470
+ expect(event.longAnimationFrames).toHaveLength(1)
471
+ expect(event.longAnimationFrames[0]).toEqual({
472
+ startTime: 100,
473
+ duration: 80,
474
+ blockingDuration: 60,
475
+ scripts: [{ sourceURL: 'app.js', invoker: 'onPointerMove', duration: 55 }],
476
+ })
477
+
478
+ // Cleanup
479
+ pm.on('interaction-end', vi.fn())() // subscribe + unsub to trigger detach check
480
+ globalThis.PerformanceObserver = origPO
481
+ })
482
+
483
+ it('omits longAnimationFrames when none collected', () => {
484
+ const editor = createMockEditor()
485
+ const pm = new PerformanceManager(editor)
486
+ const fn = vi.fn()
487
+ pm.on('interaction-end', fn)
488
+
489
+ pm._notifyInteractionStart('resizing', 'select.resizing')
490
+ editor.emit('frame', 16)
491
+ pm._notifyInteractionEnd()
492
+
493
+ expect(fn.mock.calls[0][0].longAnimationFrames).toBeUndefined()
494
+ })
495
+
496
+ it('starts LoAF observer only when interaction-end or camera-end listeners exist', () => {
497
+ const origPO = globalThis.PerformanceObserver
498
+ const mockObserve = vi.fn()
499
+ globalThis.PerformanceObserver = class MockPO {
500
+ constructor(_cb: any) {}
501
+ observe = mockObserve
502
+ disconnect = vi.fn()
503
+ static supportedEntryTypes = ['long-animation-frame']
504
+ } as any
505
+
506
+ const editor = createMockEditor()
507
+ const pm = new PerformanceManager(editor)
508
+
509
+ // interaction-start alone should NOT start LoAF observer
510
+ const unsub1 = pm.on('interaction-start', vi.fn())
511
+ expect(mockObserve).not.toHaveBeenCalled()
512
+ unsub1()
513
+
514
+ // interaction-end should start LoAF observer
515
+ const unsub2 = pm.on('interaction-end', vi.fn())
516
+ expect(mockObserve).toHaveBeenCalledTimes(1)
517
+ unsub2()
518
+
519
+ globalThis.PerformanceObserver = origPO
520
+ })
521
+ })
522
+ })