@editframe/elements 0.30.2-beta.0 → 0.31.0-beta.1

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 (326) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +5 -0
  2. package/dist/EF_FRAMEGEN.js +20 -4
  3. package/dist/EF_FRAMEGEN.js.map +1 -1
  4. package/dist/EF_INTERACTIVE.js.map +1 -1
  5. package/dist/_virtual/rolldown_runtime.js +27 -0
  6. package/dist/canvas/EFCanvas.d.ts +311 -0
  7. package/dist/canvas/EFCanvas.js +1089 -0
  8. package/dist/canvas/EFCanvas.js.map +1 -0
  9. package/dist/canvas/EFCanvasItem.d.ts +55 -0
  10. package/dist/canvas/EFCanvasItem.js +72 -0
  11. package/dist/canvas/EFCanvasItem.js.map +1 -0
  12. package/dist/canvas/api/CanvasAPI.d.ts +115 -0
  13. package/dist/canvas/api/CanvasAPI.js +182 -0
  14. package/dist/canvas/api/CanvasAPI.js.map +1 -0
  15. package/dist/canvas/api/types.d.ts +42 -0
  16. package/dist/canvas/coordinateTransform.js +90 -0
  17. package/dist/canvas/coordinateTransform.js.map +1 -0
  18. package/dist/canvas/getElementBounds.js +40 -0
  19. package/dist/canvas/getElementBounds.js.map +1 -0
  20. package/dist/canvas/overlays/SelectionOverlay.js +265 -0
  21. package/dist/canvas/overlays/SelectionOverlay.js.map +1 -0
  22. package/dist/canvas/overlays/overlayState.js +153 -0
  23. package/dist/canvas/overlays/overlayState.js.map +1 -0
  24. package/dist/canvas/selection/SelectionController.js +105 -0
  25. package/dist/canvas/selection/SelectionController.js.map +1 -0
  26. package/dist/canvas/selection/SelectionModel.d.ts +98 -0
  27. package/dist/canvas/selection/SelectionModel.js +229 -0
  28. package/dist/canvas/selection/SelectionModel.js.map +1 -0
  29. package/dist/canvas/selection/selectionContext.d.ts +31 -0
  30. package/dist/canvas/selection/selectionContext.js +12 -0
  31. package/dist/canvas/selection/selectionContext.js.map +1 -0
  32. package/dist/elements/ContainerInfo.d.ts +29 -0
  33. package/dist/elements/ContainerInfo.js +30 -0
  34. package/dist/elements/ContainerInfo.js.map +1 -0
  35. package/dist/elements/EFAudio.d.ts +13 -3
  36. package/dist/elements/EFAudio.js +64 -10
  37. package/dist/elements/EFAudio.js.map +1 -1
  38. package/dist/elements/EFCaptions.d.ts +18 -16
  39. package/dist/elements/EFCaptions.js +110 -19
  40. package/dist/elements/EFCaptions.js.map +1 -1
  41. package/dist/elements/EFImage.d.ts +16 -6
  42. package/dist/elements/EFImage.js +79 -9
  43. package/dist/elements/EFImage.js.map +1 -1
  44. package/dist/elements/EFMedia/AssetIdMediaEngine.js +51 -4
  45. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
  46. package/dist/elements/EFMedia/AssetMediaEngine.js +125 -52
  47. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  48. package/dist/elements/EFMedia/BaseMediaEngine.js +24 -6
  49. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  50. package/dist/elements/EFMedia/JitMediaEngine.js +12 -8
  51. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  52. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +46 -7
  53. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +1 -1
  54. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +98 -73
  55. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +1 -1
  56. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +28 -5
  57. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +1 -1
  58. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +18 -6
  59. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +1 -1
  60. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +8 -2
  61. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +1 -1
  62. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +31 -6
  63. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +1 -1
  64. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +28 -5
  65. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +1 -1
  66. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +97 -72
  67. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +1 -1
  68. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -1
  69. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  70. package/dist/elements/EFMedia/shared/BufferUtils.js +1 -1
  71. package/dist/elements/EFMedia/shared/BufferUtils.js.map +1 -1
  72. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +25 -14
  73. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
  74. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +47 -16
  75. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +1 -1
  76. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +37 -19
  77. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
  78. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +65 -21
  79. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  80. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +8 -3
  81. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +1 -1
  82. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +32 -9
  83. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +1 -1
  84. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +33 -10
  85. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +1 -1
  86. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +23 -8
  87. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +1 -1
  88. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +34 -10
  89. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +1 -1
  90. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +31 -8
  91. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +1 -1
  92. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +31 -114
  93. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +1 -1
  94. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +44 -8
  95. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +1 -1
  96. package/dist/elements/EFMedia.d.ts +18 -7
  97. package/dist/elements/EFMedia.js +23 -3
  98. package/dist/elements/EFMedia.js.map +1 -1
  99. package/dist/elements/EFPanZoom.d.ts +96 -0
  100. package/dist/elements/EFPanZoom.js +290 -0
  101. package/dist/elements/EFPanZoom.js.map +1 -0
  102. package/dist/elements/EFSourceMixin.js +7 -6
  103. package/dist/elements/EFSourceMixin.js.map +1 -1
  104. package/dist/elements/EFSurface.d.ts +6 -6
  105. package/dist/elements/EFSurface.js +7 -2
  106. package/dist/elements/EFSurface.js.map +1 -1
  107. package/dist/elements/EFTemporal.d.ts +2 -1
  108. package/dist/elements/EFTemporal.js +192 -71
  109. package/dist/elements/EFTemporal.js.map +1 -1
  110. package/dist/elements/EFText.d.ts +5 -4
  111. package/dist/elements/EFText.js +102 -13
  112. package/dist/elements/EFText.js.map +1 -1
  113. package/dist/elements/EFTextSegment.d.ts +32 -6
  114. package/dist/elements/EFTextSegment.js +53 -15
  115. package/dist/elements/EFTextSegment.js.map +1 -1
  116. package/dist/elements/EFThumbnailStrip.d.ts +129 -56
  117. package/dist/elements/EFThumbnailStrip.js +605 -359
  118. package/dist/elements/EFThumbnailStrip.js.map +1 -1
  119. package/dist/elements/EFTimegroup.d.ts +233 -25
  120. package/dist/elements/EFTimegroup.js +865 -144
  121. package/dist/elements/EFTimegroup.js.map +1 -1
  122. package/dist/elements/EFVideo.d.ts +42 -5
  123. package/dist/elements/EFVideo.js +165 -11
  124. package/dist/elements/EFVideo.js.map +1 -1
  125. package/dist/elements/EFWaveform.d.ts +6 -6
  126. package/dist/elements/EFWaveform.js +2 -1
  127. package/dist/elements/EFWaveform.js.map +1 -1
  128. package/dist/elements/ElementPositionInfo.d.ts +35 -0
  129. package/dist/elements/ElementPositionInfo.js +49 -0
  130. package/dist/elements/ElementPositionInfo.js.map +1 -0
  131. package/dist/elements/FetchMixin.js +16 -1
  132. package/dist/elements/FetchMixin.js.map +1 -1
  133. package/dist/elements/SessionThumbnailCache.js +154 -0
  134. package/dist/elements/SessionThumbnailCache.js.map +1 -0
  135. package/dist/elements/TargetController.js +3 -1
  136. package/dist/elements/TargetController.js.map +1 -1
  137. package/dist/elements/TimegroupController.js +9 -3
  138. package/dist/elements/TimegroupController.js.map +1 -1
  139. package/dist/elements/findRootTemporal.js +30 -0
  140. package/dist/elements/findRootTemporal.js.map +1 -0
  141. package/dist/elements/renderTemporalAudio.js +18 -5
  142. package/dist/elements/renderTemporalAudio.js.map +1 -1
  143. package/dist/elements/updateAnimations.js +171 -28
  144. package/dist/elements/updateAnimations.js.map +1 -1
  145. package/dist/getRenderInfo.d.ts +2 -2
  146. package/dist/gui/ContextMixin.js +4 -2
  147. package/dist/gui/ContextMixin.js.map +1 -1
  148. package/dist/gui/Controllable.js +74 -1
  149. package/dist/gui/Controllable.js.map +1 -1
  150. package/dist/gui/EFActiveRootTemporal.d.ts +50 -0
  151. package/dist/gui/EFActiveRootTemporal.js +94 -0
  152. package/dist/gui/EFActiveRootTemporal.js.map +1 -0
  153. package/dist/gui/EFConfiguration.d.ts +7 -1
  154. package/dist/gui/EFConfiguration.js.map +1 -1
  155. package/dist/gui/EFControls.d.ts +2 -2
  156. package/dist/gui/EFControls.js +109 -13
  157. package/dist/gui/EFControls.js.map +1 -1
  158. package/dist/gui/EFDial.d.ts +4 -4
  159. package/dist/gui/EFFilmstrip.d.ts +11 -214
  160. package/dist/gui/EFFilmstrip.js +53 -1152
  161. package/dist/gui/EFFilmstrip.js.map +1 -1
  162. package/dist/gui/EFFitScale.d.ts +3 -3
  163. package/dist/gui/EFFitScale.js +39 -12
  164. package/dist/gui/EFFitScale.js.map +1 -1
  165. package/dist/gui/EFFocusOverlay.d.ts +4 -4
  166. package/dist/gui/EFOverlayItem.d.ts +48 -0
  167. package/dist/gui/EFOverlayItem.js +97 -0
  168. package/dist/gui/EFOverlayItem.js.map +1 -0
  169. package/dist/gui/EFOverlayLayer.d.ts +70 -0
  170. package/dist/gui/EFOverlayLayer.js +104 -0
  171. package/dist/gui/EFOverlayLayer.js.map +1 -0
  172. package/dist/gui/EFPause.d.ts +4 -4
  173. package/dist/gui/EFPlay.d.ts +4 -4
  174. package/dist/gui/EFResizableBox.d.ts +12 -16
  175. package/dist/gui/EFResizableBox.js +109 -451
  176. package/dist/gui/EFResizableBox.js.map +1 -1
  177. package/dist/gui/EFScrubber.d.ts +30 -5
  178. package/dist/gui/EFScrubber.js +224 -31
  179. package/dist/gui/EFScrubber.js.map +1 -1
  180. package/dist/gui/EFTimeDisplay.d.ts +4 -4
  181. package/dist/gui/EFTimeDisplay.js +4 -1
  182. package/dist/gui/EFTimeDisplay.js.map +1 -1
  183. package/dist/gui/EFTimelineRuler.d.ts +71 -0
  184. package/dist/gui/EFTimelineRuler.js +320 -0
  185. package/dist/gui/EFTimelineRuler.js.map +1 -0
  186. package/dist/gui/EFToggleLoop.d.ts +4 -4
  187. package/dist/gui/EFTogglePlay.d.ts +4 -4
  188. package/dist/gui/EFTransformHandles.d.ts +91 -0
  189. package/dist/gui/EFTransformHandles.js +393 -0
  190. package/dist/gui/EFTransformHandles.js.map +1 -0
  191. package/dist/gui/EFWorkbench.d.ts +178 -0
  192. package/dist/gui/EFWorkbench.js +2067 -22
  193. package/dist/gui/EFWorkbench.js.map +1 -1
  194. package/dist/gui/FitScaleHelpers.d.ts +31 -0
  195. package/dist/gui/FitScaleHelpers.js +41 -0
  196. package/dist/gui/FitScaleHelpers.js.map +1 -0
  197. package/dist/gui/PlaybackController.d.ts +2 -1
  198. package/dist/gui/PlaybackController.js +46 -15
  199. package/dist/gui/PlaybackController.js.map +1 -1
  200. package/dist/gui/TWMixin.js +1 -1
  201. package/dist/gui/TWMixin.js.map +1 -1
  202. package/dist/gui/hierarchy/EFHierarchy.d.ts +65 -0
  203. package/dist/gui/hierarchy/EFHierarchy.js +338 -0
  204. package/dist/gui/hierarchy/EFHierarchy.js.map +1 -0
  205. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +118 -0
  206. package/dist/gui/hierarchy/EFHierarchyItem.js +551 -0
  207. package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -0
  208. package/dist/gui/hierarchy/hierarchyContext.d.ts +38 -0
  209. package/dist/gui/hierarchy/hierarchyContext.js +8 -0
  210. package/dist/gui/hierarchy/hierarchyContext.js.map +1 -0
  211. package/dist/gui/icons.js +34 -0
  212. package/dist/gui/icons.js.map +1 -0
  213. package/dist/gui/panZoomTransformContext.js +12 -0
  214. package/dist/gui/panZoomTransformContext.js.map +1 -0
  215. package/dist/gui/previewSettingsContext.js +12 -0
  216. package/dist/gui/previewSettingsContext.js.map +1 -0
  217. package/dist/gui/timeline/EFTimeline.d.ts +270 -0
  218. package/dist/gui/timeline/EFTimeline.js +1369 -0
  219. package/dist/gui/timeline/EFTimeline.js.map +1 -0
  220. package/dist/gui/timeline/EFTimelineRow.js +374 -0
  221. package/dist/gui/timeline/EFTimelineRow.js.map +1 -0
  222. package/dist/gui/timeline/TrimHandles.d.ts +36 -0
  223. package/dist/gui/timeline/TrimHandles.js +204 -0
  224. package/dist/gui/timeline/TrimHandles.js.map +1 -0
  225. package/dist/gui/timeline/flattenHierarchy.js +31 -0
  226. package/dist/gui/timeline/flattenHierarchy.js.map +1 -0
  227. package/dist/gui/timeline/timelineStateContext.d.ts +26 -0
  228. package/dist/gui/timeline/timelineStateContext.js +42 -0
  229. package/dist/gui/timeline/timelineStateContext.js.map +1 -0
  230. package/dist/gui/timeline/tracks/AudioTrack.js +264 -0
  231. package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -0
  232. package/dist/gui/timeline/tracks/CaptionsTrack.js +595 -0
  233. package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -0
  234. package/dist/gui/timeline/tracks/HTMLTrack.js +19 -0
  235. package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -0
  236. package/dist/gui/timeline/tracks/ImageTrack.js +53 -0
  237. package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -0
  238. package/dist/gui/timeline/tracks/TextTrack.js +250 -0
  239. package/dist/gui/timeline/tracks/TextTrack.js.map +1 -0
  240. package/dist/gui/timeline/tracks/TimegroupTrack.js +143 -0
  241. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -0
  242. package/dist/gui/timeline/tracks/TrackItem.js +269 -0
  243. package/dist/gui/timeline/tracks/TrackItem.js.map +1 -0
  244. package/dist/gui/timeline/tracks/VideoTrack.js +265 -0
  245. package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -0
  246. package/dist/gui/timeline/tracks/WaveformTrack.js +19 -0
  247. package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -0
  248. package/dist/gui/timeline/tracks/ensureTrackItemInit.js +1 -0
  249. package/dist/gui/timeline/tracks/preloadTracks.js +9 -0
  250. package/dist/gui/timeline/tracks/renderTrackChildren.js +119 -0
  251. package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -0
  252. package/dist/gui/timeline/tracks/waveformUtils.js +80 -0
  253. package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -0
  254. package/dist/gui/transformCalculations.js +217 -0
  255. package/dist/gui/transformCalculations.js.map +1 -0
  256. package/dist/gui/transformUtils.d.ts +37 -0
  257. package/dist/gui/transformUtils.js +77 -0
  258. package/dist/gui/transformUtils.js.map +1 -0
  259. package/dist/gui/tree/EFTree.d.ts +59 -0
  260. package/dist/gui/tree/EFTree.js +174 -0
  261. package/dist/gui/tree/EFTree.js.map +1 -0
  262. package/dist/gui/tree/EFTreeItem.d.ts +38 -0
  263. package/dist/gui/tree/EFTreeItem.js +146 -0
  264. package/dist/gui/tree/EFTreeItem.js.map +1 -0
  265. package/dist/gui/tree/treeContext.d.ts +60 -0
  266. package/dist/gui/tree/treeContext.js +23 -0
  267. package/dist/gui/tree/treeContext.js.map +1 -0
  268. package/dist/index.d.ts +32 -8
  269. package/dist/index.js +30 -6
  270. package/dist/index.js.map +1 -1
  271. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +688 -0
  272. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -0
  273. package/dist/node_modules/react/cjs/react.development.js +1521 -0
  274. package/dist/node_modules/react/cjs/react.development.js.map +1 -0
  275. package/dist/node_modules/react/index.js +13 -0
  276. package/dist/node_modules/react/index.js.map +1 -0
  277. package/dist/node_modules/react/jsx-runtime.js +13 -0
  278. package/dist/node_modules/react/jsx-runtime.js.map +1 -0
  279. package/dist/preview/AdaptiveResolutionTracker.js +228 -0
  280. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -0
  281. package/dist/preview/RenderProfiler.js +135 -0
  282. package/dist/preview/RenderProfiler.js.map +1 -0
  283. package/dist/preview/previewSettings.js +131 -0
  284. package/dist/preview/previewSettings.js.map +1 -0
  285. package/dist/preview/previewTypes.js +64 -0
  286. package/dist/preview/previewTypes.js.map +1 -0
  287. package/dist/preview/renderTimegroupPreview.js +656 -0
  288. package/dist/preview/renderTimegroupPreview.js.map +1 -0
  289. package/dist/preview/renderTimegroupToCanvas.d.ts +37 -0
  290. package/dist/preview/renderTimegroupToCanvas.js +833 -0
  291. package/dist/preview/renderTimegroupToCanvas.js.map +1 -0
  292. package/dist/preview/renderTimegroupToVideo.d.ts +39 -0
  293. package/dist/preview/renderTimegroupToVideo.js +274 -0
  294. package/dist/preview/renderTimegroupToVideo.js.map +1 -0
  295. package/dist/preview/renderers.js +16 -0
  296. package/dist/preview/renderers.js.map +1 -0
  297. package/dist/preview/statsTrackingStrategy.js +201 -0
  298. package/dist/preview/statsTrackingStrategy.js.map +1 -0
  299. package/dist/preview/thumbnailCacheSettings.js +52 -0
  300. package/dist/preview/thumbnailCacheSettings.js.map +1 -0
  301. package/dist/preview/workers/WorkerPool.js +178 -0
  302. package/dist/preview/workers/WorkerPool.js.map +1 -0
  303. package/dist/preview/workers/encoderWorkerInline.js +103 -0
  304. package/dist/preview/workers/encoderWorkerInline.js.map +1 -0
  305. package/dist/sandbox/PlaybackControls.js +10 -0
  306. package/dist/sandbox/PlaybackControls.js.map +1 -0
  307. package/dist/sandbox/ScenarioRunner.js +1 -0
  308. package/dist/sandbox/index.js +2 -0
  309. package/dist/style.css +71 -67
  310. package/dist/transcoding/types/index.d.ts +2 -1
  311. package/dist/transcoding/utils/UrlGenerator.d.ts +6 -1
  312. package/dist/transcoding/utils/UrlGenerator.js +12 -3
  313. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  314. package/dist/utils/LRUCache.js +1 -375
  315. package/dist/utils/LRUCache.js.map +1 -1
  316. package/dist/utils/frameTime.js +14 -0
  317. package/dist/utils/frameTime.js.map +1 -0
  318. package/package.json +3 -3
  319. package/test/profilingPlugin.ts +223 -0
  320. package/test/recordReplayProxyPlugin.js +22 -27
  321. package/test/thumbnail-performance-test.html +116 -0
  322. package/test/visualRegressionUtils.ts +286 -0
  323. package/types.json +1 -1
  324. package/dist/elements/TimegroupController.d.ts +0 -18
  325. package/dist/msToTimeCode.js +0 -17
  326. package/dist/msToTimeCode.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EFCanvas.js","names":["EFCanvas","topmostElementId: string | null","current: HTMLElement | null","elementRect","canvasX: number","canvasY: number","rotation: number | undefined","hitIds: string[]","newActiveRootTemporal: (TemporalMixinInterface & HTMLElement) | null","parent: HTMLElement | null","shouldKeep: boolean","screenX: number","screenY: number","screenWidth: number","screenHeight: number","newBounds: TransformBounds","minX","minY","maxX","maxY"],"sources":["../../src/canvas/EFCanvas.ts"],"sourcesContent":["import { consume, provide } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { panZoomTransformContext } from \"../gui/panZoomTransformContext.js\";\nimport type { PanZoomTransform } from \"../elements/EFPanZoom.js\";\nimport { SelectionController } from \"./selection/SelectionController.js\";\nimport { selectionContext } from \"./selection/selectionContext.js\";\nimport \"./overlays/SelectionOverlay.js\";\nimport { screenToCanvas, canvasToScreen } from \"./coordinateTransform.js\";\nimport { getElementBounds } from \"./getElementBounds.js\";\nimport type { CanvasElementData } from \"./api/types.js\";\nimport \"../gui/EFOverlayLayer.js\";\nimport \"../gui/EFTransformHandles.js\";\nimport type { EFOverlayLayer } from \"../gui/EFOverlayLayer.js\";\nimport type { EFTransformHandles } from \"../gui/EFTransformHandles.js\";\nimport type { TransformBounds } from \"../gui/EFTransformHandles.js\";\nimport type { SelectionOverlay } from \"./overlays/SelectionOverlay.js\";\nimport {\n getRotatedBoundingBox,\n parseRotationFromTransform,\n} from \"../gui/transformCalculations.js\";\nimport { EFTargetable } from \"../elements/TargetController.js\";\nimport { findRootTemporal } from \"../elements/findRootTemporal.js\";\nimport type { TemporalMixinInterface } from \"../elements/EFTemporal.js\";\n\n/**\n * =============================================================================\n * COORDINATE SYSTEM AND DIMENSION CALCULATION PRINCIPLES\n * =============================================================================\n *\n * This canvas system uses a unified approach for calculating element positions\n * and dimensions that works correctly regardless of CSS transforms (rotation,\n * scale, etc.), zoom level, or nesting depth.\n *\n * TWO KEY DOM APIS WITH DIFFERENT BEHAVIORS:\n *\n * 1. offsetWidth / offsetHeight\n * - Returns the element's LAYOUT dimensions (CSS box model)\n * - These are the dimensions BEFORE any CSS transforms are applied\n * - UNAFFECTED by: rotation, scale, skew, or any other transform\n * - UNAFFECTED by: parent transforms (including zoom scale)\n * - AFFECTED by: CSS width/height properties, padding, border\n * - Units: CSS pixels in the element's own coordinate space\n *\n * Example: A 200x100px element rotated 45° still has offsetWidth=200, offsetHeight=100\n * Example: A 200x100px element in a 2x zoomed canvas still has offsetWidth=200, offsetHeight=100\n *\n * USE FOR: Getting the actual dimensions of an element in canvas coordinates\n *\n * 2. getBoundingClientRect()\n * - Returns the element's visual BOUNDING BOX on screen\n * - This is the axis-aligned rectangle that fully contains the transformed element\n * - AFFECTED by: rotation (bounding box grows), scale, all transforms\n * - AFFECTED by: parent transforms (including zoom scale)\n * - Units: Screen pixels (viewport coordinates)\n *\n * Example: A 200x100px element rotated 45° has bounding box ~212x212px\n * Example: A 200x100px element in a 2x zoomed canvas has bounding rect 400x200px\n *\n * USE FOR: Getting the visual center position (center of bounding box = element center)\n * NOT FOR: Getting actual dimensions (bounding box ≠ actual size when rotated)\n *\n * THE UNIFIED CALCULATION METHOD:\n *\n * For ANY element (rotated, scaled, nested, etc.):\n *\n * 1. DIMENSIONS: Use offsetWidth/offsetHeight\n * - These give us the true dimensions in canvas coordinates\n * - No division by scale needed - they're already in canvas space\n *\n * 2. CENTER POSITION: Use getBoundingClientRect() center\n * - screenCenterX = rect.left + rect.width / 2\n * - screenCenterY = rect.top + rect.height / 2\n * - The center of the bounding box IS the element's center\n * - This is true for ANY rotation (rotation around center keeps center fixed)\n *\n * 3. TOP-LEFT POSITION: Calculate from center and dimensions\n * - canvasX = canvasCenter.x - width / 2\n * - canvasY = canvasCenter.y - height / 2\n *\n * WHY THIS WORKS UNIVERSALLY:\n *\n * - offsetWidth/Height are defined by CSS spec to be unaffected by transforms\n * - The center of any shape is preserved under rotation around that center\n * - This mathematical relationship holds for ALL transform combinations\n * - No special cases needed for rotation, scale, or nesting\n *\n * COMMON MISTAKES TO AVOID:\n *\n * ❌ Using getBoundingClientRect().width for dimensions (wrong when rotated)\n * ❌ Dividing offsetWidth by scale (offsetWidth is already in canvas coords)\n * ❌ Using getBoundingClientRect().left/top for position (wrong when rotated)\n * ❌ Having different code paths for rotated vs non-rotated elements\n *\n * =============================================================================\n */\n\n/**\n * Main canvas container element.\n * Manages existing elements (EF* elements, divs, etc.) and provides selection functionality.\n */\n@customElement(\"ef-canvas\")\nexport class EFCanvas extends EFTargetable(TWMixin(LitElement)) {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n width: 100%;\n height: 100%;\n }\n .canvas-content {\n position: relative;\n width: 100%;\n height: 100%;\n }\n `,\n ];\n\n @consume({ context: panZoomTransformContext, subscribe: true })\n panZoomTransform?: PanZoomTransform;\n\n @property({ type: String, attribute: \"data-element-id-attribute\" })\n elementIdAttribute = \"data-element-id\";\n\n @property({ type: Boolean, attribute: \"enable-transform-handles\" })\n enableTransformHandles = true;\n\n @state()\n private elementRegistry = new Map<string, HTMLElement>();\n\n @state()\n private elementMetadata = new Map<string, CanvasElementData>();\n\n private selectionController: SelectionController;\n private overlayLayer: EFOverlayLayer | null = null;\n private selectionOverlay: SelectionOverlay | null = null;\n private transformHandlesMap = new Map<string, EFTransformHandles>();\n private overlayRafId: number | null = null;\n private isDragging = false;\n private dragStarted = false; // True once threshold is crossed\n private dragStartPos: { x: number; y: number } | null = null;\n private dragStartCanvasPos: { x: number; y: number } | null = null;\n private dragStartElementPositions = new Map<\n string,\n { x: number; y: number }\n >(); // Store initial positions for all selected elements\n private draggedElementId: string | null = null;\n private capturedPointerId: number | null = null;\n private readonly DRAG_THRESHOLD = 5; // pixels of movement before drag starts\n private isBoxSelecting = false;\n private boxSelectStart: { x: number; y: number } | null = null;\n private boxSelectModifierKeys = false; // Track if modifier keys were pressed when box select started\n private emptySpaceClickPos: { x: number; y: number } | null = null;\n private selectionChangeHandler?: () => void;\n private elementHoverHandlers = new Map<string, {\n mouseenter: () => void;\n mouseleave: () => void;\n }>();\n\n @state()\n private _activeRootTemporal: (TemporalMixinInterface & HTMLElement) | null =\n null;\n\n @provide({ context: selectionContext })\n @state()\n selectionContext!: import(\"./selection/selectionContext.js\").SelectionContext;\n\n /**\n * The currently highlighted (hovered) element.\n * This is the source of truth for highlight state across all panels\n * (canvas, hierarchy, timeline).\n */\n @state()\n highlightedElement: HTMLElement | null = null;\n\n constructor() {\n super();\n this.selectionController = new SelectionController(this);\n this.selectionController.setHitTest((bounds) => this.hitTest(bounds));\n // Initialize selectionContext after controller is created\n this.selectionContext = this.selectionController.selectionContext;\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n this.setupElementTracking();\n this.setupOverlayLayer();\n this.setupSelectionOverlay();\n this.setupSelectionListener();\n this.addEventListener(\"pointerdown\", this.handlePointerDown);\n this.addEventListener(\"pointermove\", this.handlePointerMove);\n this.addEventListener(\"pointerup\", this.handlePointerUp);\n this.addEventListener(\"pointercancel\", this.handlePointerUp);\n this.startOverlayRafLoop();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.stopOverlayRafLoop();\n this.cleanupOverlayLayer();\n this.cleanupSelectionOverlay();\n this.cleanupTransformHandles();\n this.removeSelectionListener();\n this.removeEventListener(\"pointerdown\", this.handlePointerDown);\n this.removeEventListener(\"pointermove\", this.handlePointerMove);\n this.removeEventListener(\"pointerup\", this.handlePointerUp);\n this.removeEventListener(\"pointercancel\", this.handlePointerUp);\n }\n\n /**\n * Setup mutation observer to track element additions/removals.\n */\n private setupElementTracking(): void {\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of Array.from(mutation.addedNodes)) {\n if (node instanceof HTMLElement) {\n this.tryRegisterElement(node);\n }\n }\n for (const node of Array.from(mutation.removedNodes)) {\n if (node instanceof HTMLElement) {\n this.unregisterElement(node);\n }\n }\n }\n });\n\n observer.observe(this, {\n childList: true,\n subtree: true, // Watch all descendants - any element can be selectable\n });\n\n // Register all elements in the canvas (including nested ones)\n const registerAllElements = (parent: Element) => {\n for (const child of Array.from(parent.children)) {\n if (child instanceof HTMLElement) {\n this.tryRegisterElement(child);\n // Recursively register nested elements\n if (child.children.length > 0) {\n registerAllElements(child);\n }\n }\n }\n };\n\n registerAllElements(this);\n }\n\n /**\n * Try to register an element, auto-generating an ID if needed.\n * Public method for external use (e.g., hierarchy selection).\n */\n tryRegisterElement(element: HTMLElement): void {\n // Skip if already registered\n const existingId =\n element.getAttribute(this.elementIdAttribute) || element.id;\n if (existingId && this.elementRegistry.has(existingId)) {\n return;\n }\n\n try {\n // Use existing id if available, otherwise generate one\n let elementId =\n element.id && element.id.trim() !== \"\"\n ? element.id\n : element.getAttribute(this.elementIdAttribute);\n\n if (!elementId) {\n // Generate a unique ID based on tag name and index\n const tagName = element.tagName.toLowerCase();\n const index = Array.from(element.parentElement?.children || []).indexOf(\n element,\n );\n elementId = `${tagName}-${index}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n // Set id if not already set\n if (!element.id || element.id.trim() === \"\") {\n element.id = elementId;\n }\n // Set data-element-id if not already set\n if (!element.getAttribute(this.elementIdAttribute)) {\n element.setAttribute(this.elementIdAttribute, elementId);\n }\n\n this.registerElement(element, elementId);\n } catch (error) {\n // Silently ignore registration errors (e.g., duplicate ID)\n // This allows the canvas to work with mixed content\n }\n }\n\n /**\n * Register an element for canvas management.\n * @throws Error if element does not have an ID\n */\n registerElement(element: HTMLElement, id?: string): string {\n // Determine the element ID - can come from parameter, attribute, or element.id\n const elementId =\n id ||\n element.getAttribute(this.elementIdAttribute) ||\n (element.id && element.id.trim() !== \"\" ? element.id : null);\n\n if (!elementId) {\n throw new Error(\n `Element must have an ID. Provide either the 'id' parameter, set the '${this.elementIdAttribute}' attribute, or set the 'id' attribute on the element.`,\n );\n }\n\n // Check for duplicate IDs (but allow re-registering the same element)\n if (this.elementRegistry.has(elementId)) {\n const existing = this.elementRegistry.get(elementId);\n if (existing !== element) {\n throw new Error(\n `Element with ID '${elementId}' is already registered. Each element must have a unique ID.`,\n );\n }\n // Same element, already registered - return early\n return elementId;\n }\n\n // Set the data-element-id attribute if not already set\n if (!element.getAttribute(this.elementIdAttribute)) {\n element.setAttribute(this.elementIdAttribute, elementId);\n }\n\n // Ensure element.id matches if not already set\n if (!element.id || element.id.trim() === \"\") {\n element.id = elementId;\n }\n\n this.elementRegistry.set(elementId, element);\n\n // Setup hover event listeners for cross-view hover sync\n this.setupElementHoverListeners(element, elementId);\n\n // Ensure direct children have default styling (only for direct children)\n if (element.parentElement === this) {\n if (!element.style.position) {\n element.style.position = \"absolute\";\n }\n if (!element.style.display || element.style.display === \"none\") {\n element.style.display = \"block\";\n }\n }\n\n // Update metadata immediately - if layout isn't ready, it will be updated on next frame\n this.updateElementMetadata(elementId);\n\n return elementId;\n }\n\n /**\n * Unregister an element.\n */\n unregisterElement(element: HTMLElement | string): void {\n const elementId =\n typeof element === \"string\"\n ? element\n : element.getAttribute(this.elementIdAttribute);\n\n if (elementId) {\n const elementToUnregister =\n typeof element === \"string\"\n ? this.elementRegistry.get(elementId)\n : element;\n if (elementToUnregister) {\n elementToUnregister.removeAttribute(\"data-selected\");\n elementToUnregister.removeAttribute(\"data-highlighted\");\n }\n \n // Remove hover listeners\n this.removeElementHoverListeners(elementId);\n \n this.elementRegistry.delete(elementId);\n this.elementMetadata.delete(elementId);\n this.selectionController.selectionContext.deselect(elementId);\n }\n }\n\n /**\n * Setup hover event listeners for an element to update highlightedElement.\n * The canvas is the source of truth for highlight state.\n */\n private setupElementHoverListeners(\n element: HTMLElement,\n elementId: string,\n ): void {\n // Remove existing listeners if any\n this.removeElementHoverListeners(elementId);\n\n const mouseenterHandler = () => {\n this.setHighlightedElement(element);\n };\n\n const mouseleaveHandler = () => {\n // Only clear if this element is currently highlighted\n if (this.highlightedElement === element) {\n this.setHighlightedElement(null);\n }\n };\n\n element.addEventListener(\"mouseenter\", mouseenterHandler);\n element.addEventListener(\"mouseleave\", mouseleaveHandler);\n\n this.elementHoverHandlers.set(elementId, {\n mouseenter: mouseenterHandler,\n mouseleave: mouseleaveHandler,\n });\n }\n\n /**\n * Set the highlighted element. Called by canvas hover handlers\n * and by external panels (hierarchy, timeline) when user hovers items.\n */\n setHighlightedElement(element: HTMLElement | null): void {\n if (this.highlightedElement !== element) {\n // Remove data-highlighted from previously highlighted element\n if (this.highlightedElement) {\n this.highlightedElement.removeAttribute(\"data-highlighted\");\n }\n\n // Update state\n this.highlightedElement = element;\n\n // Add data-highlighted to newly highlighted element\n if (element) {\n element.setAttribute(\"data-highlighted\", \"true\");\n }\n }\n }\n\n /**\n * Remove hover event listeners for an element.\n */\n private removeElementHoverListeners(elementId: string): void {\n const handlers = this.elementHoverHandlers.get(elementId);\n if (!handlers) return;\n\n const element = this.elementRegistry.get(elementId);\n if (element) {\n element.removeEventListener(\"mouseenter\", handlers.mouseenter);\n element.removeEventListener(\"mouseleave\", handlers.mouseleave);\n }\n\n this.elementHoverHandlers.delete(elementId);\n }\n\n /**\n * Update element metadata from DOM.\n *\n * UNIFIED APPROACH - works for ALL elements regardless of rotation, scale, or nesting:\n *\n * 1. DIMENSIONS: Always use offsetWidth/offsetHeight\n * - These are layout dimensions in the element's coordinate space\n * - Unaffected by CSS transforms (rotation, scale, etc.)\n * - Already in canvas coordinates (no scale division needed)\n *\n * 2. CENTER POSITION: Always use getBoundingClientRect() center\n * - The center of the bounding box IS the element's center (transform-origin: center)\n * - Works correctly for rotated elements (center is rotation-invariant)\n * - Convert to canvas coordinates using screenToCanvas()\n *\n * 3. TOP-LEFT POSITION: Calculate from center and dimensions\n * - x = centerX - width/2\n * - y = centerY - height/2\n */\n private updateElementMetadata(elementId: string): void {\n const element = this.elementRegistry.get(elementId);\n if (!element) {\n return;\n }\n\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n\n // STEP 1: Get dimensions from offsetWidth/offsetHeight (unified, no special cases)\n // These are layout dimensions, unaffected by ANY transforms\n let actualWidth = element.offsetWidth;\n let actualHeight = element.offsetHeight;\n\n // Fallback for elements where offsetWidth/Height are 0 (e.g., inline elements)\n if (actualWidth === 0 || actualHeight === 0) {\n const elementRect = getElementBounds(element);\n const scale = this.panZoomTransform?.scale || 1;\n actualWidth = elementRect.width / scale;\n actualHeight = elementRect.height / scale;\n }\n\n // STEP 2: Get center position from getBoundingClientRect() (unified, no special cases)\n // The center is rotation-invariant - it's always correct\n const elementRect = getElementBounds(element);\n const screenCenterX = elementRect.left + elementRect.width / 2;\n const screenCenterY = elementRect.top + elementRect.height / 2;\n\n let canvasX: number;\n let canvasY: number;\n\n if (!canvasContent) {\n const existingMetadata = this.elementMetadata.get(elementId);\n canvasX = existingMetadata?.x ?? 0;\n canvasY = existingMetadata?.y ?? 0;\n } else {\n const referenceRect = canvasContent.getBoundingClientRect();\n\n // Convert center to canvas coordinates\n const canvasCenter = screenToCanvas(\n screenCenterX,\n screenCenterY,\n referenceRect,\n this.panZoomTransform,\n );\n\n // STEP 3: Calculate top-left from center and dimensions\n canvasX = canvasCenter.x - actualWidth / 2;\n canvasY = canvasCenter.y - actualHeight / 2;\n }\n\n // Parse rotation from element's transform\n const existingMetadata = this.elementMetadata.get(elementId);\n let rotation: number | undefined = existingMetadata?.rotation;\n\n if (rotation === undefined) {\n const computedStyle = window.getComputedStyle(element);\n rotation = parseRotationFromTransform(computedStyle.transform);\n if (rotation === 0) {\n rotation = undefined;\n }\n }\n\n this.elementMetadata.set(elementId, {\n id: elementId,\n element,\n x: canvasX,\n y: canvasY,\n width: actualWidth,\n height: actualHeight,\n rotation,\n });\n }\n\n /**\n * Hit test - find elements intersecting with bounds.\n * @param bounds - DOMRect in canvas coordinate space (from SelectionModel.boxSelectBounds)\n */\n private hitTest(bounds: DOMRect): string[] {\n // bounds is already in canvas coordinates (from SelectionModel.boxSelectBounds)\n // which is created from canvas coordinates stored in _boxSelectStart and _boxSelectCurrent\n const testRect = bounds;\n const canvasRect = this.getBoundingClientRect();\n\n const hitIds: string[] = [];\n for (const [elementId, element] of this.elementRegistry.entries()) {\n const elementBounds = getElementBounds(element);\n const elementCanvasPos = screenToCanvas(\n elementBounds.left,\n elementBounds.top,\n canvasRect,\n this.panZoomTransform,\n );\n const elementCanvasWidth =\n elementBounds.width / (this.panZoomTransform?.scale || 1);\n const elementCanvasHeight =\n elementBounds.height / (this.panZoomTransform?.scale || 1);\n\n const elementRect = new DOMRect(\n elementCanvasPos.x,\n elementCanvasPos.y,\n elementCanvasWidth,\n elementCanvasHeight,\n );\n\n if (\n testRect.left < elementRect.right &&\n testRect.right > elementRect.left &&\n testRect.top < elementRect.bottom &&\n testRect.bottom > elementRect.top\n ) {\n hitIds.push(elementId);\n }\n }\n\n return hitIds;\n }\n\n /**\n * Handle pointer down events.\n * Only handles events when clicking on elements. Otherwise, lets panzoom handle it.\n */\n private handlePointerDown = (e: PointerEvent): void => {\n if (e.button !== 0) {\n return;\n }\n\n // Use elementsFromPoint to get elements in z-order (topmost first)\n // This ensures we select the element that's actually on top, not one behind it\n const elementsAtPoint = document.elementsFromPoint(e.clientX, e.clientY);\n\n // Find the topmost selectable element (not overlay/transform handles)\n let topmostElement: HTMLElement | null = null;\n let topmostElementId: string | null = null;\n\n for (const el of elementsAtPoint) {\n // Skip overlay layer and transform handles\n if (\n el.tagName === \"EF-OVERLAY-LAYER\" ||\n el.tagName === \"EF-TRANSFORM-HANDLES\" ||\n el.closest(\"ef-overlay-layer\") ||\n el.closest(\"ef-transform-handles\")\n ) {\n continue;\n }\n\n // Skip if not an HTMLElement\n if (!(el instanceof HTMLElement)) {\n continue;\n }\n\n // Skip the canvas element itself\n if (el === this) {\n continue;\n }\n\n // Check if element is within canvas\n if (!this.contains(el)) {\n continue;\n }\n\n // Try to register and get element ID (auto-generates if needed)\n try {\n this.tryRegisterElement(el);\n const elementId = el.id || el.getAttribute(this.elementIdAttribute);\n\n if (elementId && this.elementRegistry.has(elementId)) {\n topmostElement = el;\n topmostElementId = elementId;\n break;\n }\n } catch {\n // Registration failed, try parent\n }\n\n // Walk up DOM tree to find first registerable parent\n let current: HTMLElement | null = el.parentElement;\n while (current && current !== this) {\n try {\n this.tryRegisterElement(current);\n const elementId =\n current.id || current.getAttribute(this.elementIdAttribute);\n\n if (elementId && this.elementRegistry.has(elementId)) {\n topmostElement = current;\n topmostElementId = elementId;\n break;\n }\n } catch {\n // Registration failed, try next parent\n }\n\n current = current.parentElement;\n }\n\n if (topmostElementId) {\n break;\n }\n }\n\n if (topmostElementId) {\n // Clicking on an element - handle it\n const elementId = topmostElementId;\n const isSelected = this.selectionController\n .getModel()\n .selectedIds.has(elementId);\n\n if (e.shiftKey) {\n // Shift + Click: Add to selection (never remove)\n this.selectionController.selectionContext.addToSelection(elementId);\n e.stopPropagation();\n // Don't prevent default or capture pointer for multi-select clicks\n } else if (e.ctrlKey || e.metaKey) {\n // Ctrl/Cmd + Click: Toggle selection (add if not selected, remove if selected)\n this.selectionController.selectionContext.toggle(elementId);\n e.preventDefault();\n e.stopPropagation();\n // Don't capture pointer for multi-select clicks\n } else {\n // Normal click: Select single element (clear others) if not already selected\n if (!isSelected) {\n this.selectionController.selectionContext.select(elementId);\n }\n // Prepare for potential drag - store initial state but don't start dragging yet\n // Drag will only start after threshold distance is crossed\n // Store initial positions for all selected elements (for multi-selection dragging)\n // After selection change, get current selected IDs\n const selectedIds = Array.from(\n this.selectionController.getModel().selectedIds,\n );\n\n // Update metadata for all selected elements that will be dragged\n for (const id of selectedIds) {\n this.updateElementMetadata(id);\n const metadata = this.elementMetadata.get(id);\n if (metadata) {\n this.dragStartElementPositions.set(id, {\n x: metadata.x,\n y: metadata.y,\n });\n }\n }\n\n this.isDragging = false; // Not dragging yet, just preparing\n this.dragStarted = false; // Haven't crossed threshold yet\n this.dragStartPos = { x: e.clientX, y: e.clientY };\n this.draggedElementId = elementId; // Track which element was clicked (for single-element drag fallback)\n this.capturedPointerId = e.pointerId;\n\n // Capture pointer to receive all pointer events even when over the element\n // Only capture for drag operations, not multi-select\n try {\n this.setPointerCapture(e.pointerId);\n } catch (err) {\n // Ignore pointer capture errors (e.g., in test environments)\n console.warn(\"[EFCanvas] Failed to capture pointer:\", err);\n }\n\n // Calculate drag start position in canvas coordinates once\n // Use .canvas-content as reference to match metadata calculation\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n const canvasRect =\n canvasContent?.getBoundingClientRect() ||\n this.getBoundingClientRect();\n this.dragStartCanvasPos = screenToCanvas(\n e.clientX,\n e.clientY,\n canvasRect,\n this.panZoomTransform,\n );\n // Stop propagation to prevent panzoom from handling this as a pan gesture\n e.stopPropagation();\n }\n } else {\n // Clicking on empty space - start box selection by default\n // Use .canvas-content as reference to match metadata calculation\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n const canvasRect =\n canvasContent?.getBoundingClientRect() || this.getBoundingClientRect();\n const canvasPos = screenToCanvas(\n e.clientX,\n e.clientY,\n canvasRect,\n this.panZoomTransform,\n );\n\n // Track if modifier keys were pressed (for adding to selection)\n this.boxSelectModifierKeys = e.shiftKey || e.ctrlKey || e.metaKey;\n\n // Start box selection (works by default, modifier keys determine if we add to selection)\n this.isBoxSelecting = true;\n this.boxSelectStart = canvasPos;\n this.selectionController.selectionContext.startBoxSelect(\n canvasPos.x,\n canvasPos.y,\n );\n\n // Capture pointer for box selection\n this.capturedPointerId = e.pointerId;\n try {\n this.setPointerCapture(e.pointerId);\n } catch (err) {\n console.warn(\"[EFCanvas] Failed to capture pointer:\", err);\n }\n\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n /**\n * Handle pointer move events.\n */\n private handlePointerMove = (e: PointerEvent): void => {\n // If pointer is not down, clean up any drag state\n if (e.buttons === 0) {\n if (this.capturedPointerId !== null) {\n try {\n this.releasePointerCapture(e.pointerId);\n } catch (err) {\n // Ignore release errors\n }\n this.capturedPointerId = null;\n }\n if (\n this.isDragging ||\n this.dragStarted ||\n this.draggedElementId !== null\n ) {\n this.isDragging = false;\n this.dragStarted = false;\n this.dragStartPos = null;\n this.dragStartCanvasPos = null;\n this.dragStartElementPositions.clear();\n this.draggedElementId = null;\n }\n if (this.isBoxSelecting) {\n this.isBoxSelecting = false;\n this.boxSelectStart = null;\n this.boxSelectModifierKeys = false;\n }\n return;\n }\n\n // Use .canvas-content as reference to match metadata calculation\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n const canvasRect =\n canvasContent?.getBoundingClientRect() || this.getBoundingClientRect();\n\n // Check if we're preparing for a drag (pointerdown on element but threshold not crossed)\n if (\n !this.dragStarted &&\n this.draggedElementId &&\n this.dragStartPos &&\n this.dragStartCanvasPos &&\n this.dragStartElementPositions.size > 0\n ) {\n // Check if we've moved enough to start dragging\n const distance = Math.sqrt(\n Math.pow(e.clientX - this.dragStartPos.x, 2) +\n Math.pow(e.clientY - this.dragStartPos.y, 2),\n );\n\n if (distance >= this.DRAG_THRESHOLD) {\n // Threshold crossed - start dragging\n this.dragStarted = true;\n this.isDragging = true;\n // Continue to process this move event (don't return)\n } else {\n // Haven't crossed threshold yet, don't do anything\n return;\n }\n }\n\n // Process drag update (either already dragging, or just crossed threshold)\n if (\n this.isDragging &&\n this.dragStarted &&\n this.dragStartCanvasPos &&\n this.dragStartElementPositions.size > 0\n ) {\n // Drag all selected elements - use pre-calculated canvas start position to avoid quantization\n const canvasPos = screenToCanvas(\n e.clientX,\n e.clientY,\n canvasRect,\n this.panZoomTransform,\n );\n\n // Calculate delta using pre-calculated start position (avoids rounding errors)\n const deltaX = canvasPos.x - this.dragStartCanvasPos.x;\n const deltaY = canvasPos.y - this.dragStartCanvasPos.y;\n\n // Move all elements that were selected when drag started\n for (const [\n elementId,\n startPos,\n ] of this.dragStartElementPositions.entries()) {\n const newX = startPos.x + deltaX;\n const newY = startPos.y + deltaY;\n this.updateElementPosition(elementId, newX, newY);\n }\n e.stopPropagation();\n } else if (this.isBoxSelecting && this.boxSelectStart) {\n // Update box select\n const canvasPos = screenToCanvas(\n e.clientX,\n e.clientY,\n canvasRect,\n this.panZoomTransform,\n );\n this.selectionController.selectionContext.updateBoxSelect(\n canvasPos.x,\n canvasPos.y,\n );\n e.stopPropagation();\n }\n };\n\n /**\n * Handle pointer up events.\n */\n private handlePointerUp = (e: PointerEvent): void => {\n // Store state before clearing (for empty space click check)\n const wasDragging = this.isDragging || this.dragStarted;\n const wasBoxSelecting = this.isBoxSelecting;\n\n // Release pointer capture if we have it\n if (this.capturedPointerId !== null) {\n try {\n this.releasePointerCapture(e.pointerId);\n } catch (err) {\n // Ignore release errors\n }\n this.capturedPointerId = null;\n }\n\n // Always clean up drag state if we have any drag-related state set\n // This ensures drag always stops on pointer up, regardless of threshold\n if (this.draggedElementId !== null || this.dragStartPos !== null) {\n this.isDragging = false;\n this.dragStarted = false;\n this.dragStartPos = null;\n this.dragStartCanvasPos = null;\n this.dragStartElementPositions.clear();\n this.draggedElementId = null;\n }\n\n if (this.isBoxSelecting) {\n this.isBoxSelecting = false;\n // Pass modifier key state to endBoxSelect to determine if we add to selection\n this.selectionController.selectionContext.endBoxSelect(\n (bounds) => this.hitTest(bounds),\n this.boxSelectModifierKeys,\n );\n this.boxSelectStart = null;\n this.boxSelectModifierKeys = false;\n }\n\n // Clear selection if we clicked on empty space and didn't drag\n if (this.emptySpaceClickPos) {\n if (!wasDragging && !wasBoxSelecting) {\n const moved =\n Math.abs(e.clientX - this.emptySpaceClickPos.x) > 2 ||\n Math.abs(e.clientY - this.emptySpaceClickPos.y) > 2;\n if (!moved) {\n this.selectionController.selectionContext.clear();\n }\n }\n this.emptySpaceClickPos = null;\n }\n };\n\n /**\n * Setup listener for selection changes to update data-selected attributes.\n */\n private setupSelectionListener(): void {\n if (this.selectionChangeHandler) {\n return;\n }\n\n this.selectionChangeHandler = () => {\n this.updateSelectionAttributes();\n };\n\n this.selectionContext.addEventListener(\n \"selectionchange\",\n this.selectionChangeHandler,\n );\n // Update immediately to set initial state\n this.updateSelectionAttributes();\n }\n\n /**\n * Remove selection change listener.\n */\n private removeSelectionListener(): void {\n if (this.selectionChangeHandler) {\n this.selectionContext.removeEventListener(\n \"selectionchange\",\n this.selectionChangeHandler,\n );\n this.selectionChangeHandler = undefined;\n }\n }\n\n /**\n * Get the root temporal element containing the current selection.\n * Returns null if no element is selected or the selected element has no root temporal.\n */\n get activeRootTemporal(): (TemporalMixinInterface & HTMLElement) | null {\n return this._activeRootTemporal;\n }\n\n /**\n * Update data-selected attributes on elements based on current selection.\n * This enables pure CSS styling of selected elements.\n */\n private updateSelectionAttributes(): void {\n const selectedIds = Array.from(this.selectionContext.selectedIds);\n const allRegisteredIds = Array.from(this.elementRegistry.keys());\n\n // Remove data-selected from all elements\n for (const id of allRegisteredIds) {\n const element = this.elementRegistry.get(id);\n if (element) {\n element.removeAttribute(\"data-selected\");\n }\n }\n\n // Add data-selected to selected elements\n for (const id of selectedIds) {\n const element = this.elementRegistry.get(id);\n if (element) {\n element.setAttribute(\"data-selected\", \"true\");\n }\n }\n\n // Update active root temporal\n const previousActiveRootTemporal = this._activeRootTemporal;\n let newActiveRootTemporal: (TemporalMixinInterface & HTMLElement) | null =\n null;\n\n if (selectedIds.length > 0) {\n const selectedElement = document.getElementById(selectedIds[0] || \"\");\n if (selectedElement) {\n newActiveRootTemporal = findRootTemporal(selectedElement);\n }\n }\n\n this._activeRootTemporal = newActiveRootTemporal;\n\n // Dispatch event if active root temporal changed\n if (previousActiveRootTemporal !== newActiveRootTemporal) {\n this.dispatchEvent(\n new CustomEvent(\"activeroottemporalchange\", {\n detail: { activeRootTemporal: newActiveRootTemporal },\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n /**\n * Update element position in canvas coordinates.\n * Unified approach: Always calculate relative to parent (or .canvas-content for direct children).\n * For direct children, parent position is (0, 0), so relative = absolute (no-op).\n *\n * For nested elements, we read parent's current position from DOM (not metadata) to ensure\n * we're always calculating relative to the actual current position.\n */\n updateElementPosition(elementId: string, x: number, y: number): void {\n const element = this.elementRegistry.get(elementId);\n if (!element) {\n console.warn(\n \"[EFCanvas] updateElementPosition: element not found\",\n elementId,\n );\n return;\n }\n\n const metadata = this.elementMetadata.get(elementId);\n if (!metadata) {\n return;\n }\n\n metadata.x = x;\n metadata.y = y;\n\n // Unified approach: Find parent and calculate relative position\n // Uses the same unified method as updateElementMetadata for consistency\n\n let parentX = 0;\n let parentY = 0;\n let parent: HTMLElement | null = element.parentElement;\n\n // Walk up to find registered parent (or canvas itself)\n while (parent && parent !== this) {\n const parentId =\n parent.id || parent.getAttribute(this.elementIdAttribute);\n if (parentId && this.elementRegistry.has(parentId)) {\n // Use SAME unified calculation as updateElementMetadata:\n // 1. Get dimensions from offsetWidth/offsetHeight\n // 2. Get center from getBoundingClientRect()\n // 3. Calculate top-left from center - dimensions/2\n const parentWidth = parent.offsetWidth;\n const parentHeight = parent.offsetHeight;\n const parentRect = getElementBounds(parent);\n const parentScreenCenterX = parentRect.left + parentRect.width / 2;\n const parentScreenCenterY = parentRect.top + parentRect.height / 2;\n\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n if (canvasContent) {\n const referenceRect = canvasContent.getBoundingClientRect();\n const parentCanvasCenter = screenToCanvas(\n parentScreenCenterX,\n parentScreenCenterY,\n referenceRect,\n this.panZoomTransform,\n );\n parentX = parentCanvasCenter.x - parentWidth / 2;\n parentY = parentCanvasCenter.y - parentHeight / 2;\n }\n break;\n }\n parent = parent.parentElement;\n }\n\n // Calculate relative position: absolute position - parent absolute position\n // For direct children (no registered parent found), parentX/Y remain 0, so relative = absolute\n const relativeX = x - parentX;\n const relativeY = y - parentY;\n\n element.style.position = \"absolute\";\n element.style.left = `${relativeX}px`;\n element.style.top = `${relativeY}px`;\n }\n\n /**\n * Get element metadata.\n */\n getElementData(elementId: string): CanvasElementData | null {\n return this.elementMetadata.get(elementId) || null;\n }\n\n /**\n * Get all element data.\n */\n getAllElementsData(): CanvasElementData[] {\n return Array.from(this.elementMetadata.values());\n }\n\n /**\n * Convert screen coordinates to canvas coordinates (for API).\n */\n screenToCanvasCoords(\n screenX: number,\n screenY: number,\n ): { x: number; y: number } {\n const canvasRect = this.getBoundingClientRect();\n return screenToCanvas(screenX, screenY, canvasRect, this.panZoomTransform);\n }\n\n /**\n * Convert canvas coordinates to screen coordinates (for API).\n */\n canvasToScreenCoords(\n canvasX: number,\n canvasY: number,\n ): { x: number; y: number } {\n const canvasRect = this.getBoundingClientRect();\n return canvasToScreen(canvasX, canvasY, canvasRect, this.panZoomTransform);\n }\n\n /**\n * Setup overlay layer as sibling of panzoom (outside panzoom, same level as panzoom).\n */\n private setupOverlayLayer(): void {\n // Find panzoom element (canvas is inside panzoom)\n const panZoom = this.closest(\"ef-pan-zoom\") as HTMLElement | null;\n if (!panZoom) {\n return;\n }\n\n // Check if overlay layer already exists (application provided it)\n const panZoomParent = panZoom.parentElement;\n if (panZoomParent) {\n const existing = panZoomParent.querySelector(\n \"ef-overlay-layer\",\n ) as EFOverlayLayer | null;\n if (existing) {\n this.overlayLayer = existing;\n return;\n }\n }\n\n // Create overlay layer as sibling of panzoom\n if (panZoomParent) {\n const overlayLayer = document.createElement(\n \"ef-overlay-layer\",\n ) as EFOverlayLayer;\n overlayLayer.style.position = \"absolute\";\n overlayLayer.style.inset = \"0\";\n overlayLayer.style.zIndex = \"1\";\n overlayLayer.style.pointerEvents = \"none\";\n\n // Insert after panzoom (so it's a sibling of panzoom, not canvas)\n panZoomParent.insertBefore(overlayLayer, panZoom.nextSibling);\n this.overlayLayer = overlayLayer;\n }\n }\n\n /**\n * Cleanup overlay layer if we created it.\n */\n private cleanupOverlayLayer(): void {\n if (this.overlayLayer && this.overlayLayer.parentElement) {\n // Only remove if we created it (check if it's a sibling)\n const parent = this.parentElement;\n if (parent && parent.contains(this.overlayLayer)) {\n // Check if it's actually a sibling (not the canvas itself)\n if (this.overlayLayer.tagName !== \"EF-CANVAS\") {\n this.overlayLayer.remove();\n }\n }\n }\n this.overlayLayer = null;\n }\n\n /**\n * Setup selection overlay as sibling of panzoom (outside panzoom, same level as panzoom).\n * This ensures the overlay maintains 1:1 pixel ratio regardless of zoom level.\n */\n private setupSelectionOverlay(): void {\n // Find panzoom element (canvas is inside panzoom)\n const panZoom = this.closest(\"ef-pan-zoom\") as HTMLElement | null;\n if (!panZoom) {\n return;\n }\n\n // Check if selection overlay already exists (application provided it)\n const panZoomParent = panZoom.parentElement;\n if (panZoomParent) {\n const existing = panZoomParent.querySelector(\n \"ef-canvas-selection-overlay\",\n ) as SelectionOverlay | null;\n if (existing) {\n this.selectionOverlay = existing;\n return;\n }\n }\n\n // Create selection overlay as sibling of panzoom (outside transform)\n if (panZoomParent) {\n const selectionOverlay = document.createElement(\n \"ef-canvas-selection-overlay\",\n ) as SelectionOverlay;\n\n // Pass contexts and canvas element as properties since overlay is outside context providers\n selectionOverlay.selection = this.selectionContext;\n selectionOverlay.canvas = this; // Pass canvas element directly\n if (this.panZoomTransform) {\n selectionOverlay.panZoomTransform = this.panZoomTransform;\n }\n\n // Insert after panzoom (so it's a sibling of panzoom, not canvas)\n panZoomParent.insertBefore(selectionOverlay, panZoom.nextSibling);\n this.selectionOverlay = selectionOverlay;\n }\n }\n\n /**\n * Cleanup selection overlay if we created it.\n */\n private cleanupSelectionOverlay(): void {\n if (this.selectionOverlay && this.selectionOverlay.parentElement) {\n // Only remove if we created it (check if it's a sibling)\n const panZoom = this.closest(\"ef-pan-zoom\") as HTMLElement | null;\n if (panZoom && panZoom.parentElement?.contains(this.selectionOverlay)) {\n // Check if it's actually a sibling (not the canvas itself)\n this.selectionOverlay.remove();\n }\n this.selectionOverlay = null;\n }\n }\n\n /**\n * Start RAF loop for overlay layer sync and transform handles updates.\n */\n private startOverlayRafLoop(): void {\n if (this.overlayRafId !== null) {\n return;\n }\n\n const update = () => {\n // Sync overlay layer transform\n if (this.overlayLayer && this.panZoomTransform) {\n this.overlayLayer.panZoomTransform = this.panZoomTransform;\n }\n\n // Update transform handles\n if (this.enableTransformHandles) {\n this.updateTransformHandles();\n }\n\n this.overlayRafId = requestAnimationFrame(update);\n };\n\n this.overlayRafId = requestAnimationFrame(update);\n }\n\n /**\n * Stop RAF loop.\n */\n private stopOverlayRafLoop(): void {\n if (this.overlayRafId !== null) {\n cancelAnimationFrame(this.overlayRafId);\n this.overlayRafId = null;\n }\n }\n\n /**\n * Update transform handles for selected elements.\n * For multiple selections, shows a single set of handles for the bounding box.\n */\n private updateTransformHandles(): void {\n if (!this.overlayLayer) {\n return;\n }\n\n const selectedIds = Array.from(\n this.selectionController.getModel().selectedIds,\n );\n\n // Remove handles for unselected elements and old multi-selection handles\n // When switching between single/multi, we need to clean up the old handle key\n this.transformHandlesMap.forEach((handles, id) => {\n const isMultiSelectionHandle = id === \"multi-selection\";\n const isMultiSelection = selectedIds.length > 1;\n\n // Determine if we should keep this handle\n let shouldKeep: boolean;\n if (isMultiSelectionHandle) {\n // Keep multi-selection handle only if we're in multi-selection mode\n shouldKeep = isMultiSelection;\n } else {\n // Keep single element handle only if it's the selected element AND we're not in multi-selection\n shouldKeep = selectedIds.includes(id) && !isMultiSelection;\n }\n\n if (!shouldKeep) {\n handles.remove();\n this.transformHandlesMap.delete(id);\n }\n });\n\n if (selectedIds.length === 0) {\n return;\n }\n\n // Use a single handle set for multi-selection (keyed by \"multi-selection\")\n // For single selection, use the element ID as the key\n const handleKey =\n selectedIds.length > 1 ? \"multi-selection\" : (selectedIds[0] ?? \"none\");\n\n if (handleKey === \"none\") {\n return;\n }\n\n let handles = this.transformHandlesMap.get(handleKey);\n\n if (!handles) {\n // Create handles\n handles = document.createElement(\n \"ef-transform-handles\",\n ) as EFTransformHandles;\n handles.setAttribute(\"enable-rotation\", \"true\");\n handles.setAttribute(\"enable-resize\", \"true\");\n handles.setAttribute(\"enable-drag\", \"false\");\n // Multi-selection: always lock aspect ratio for proportional scaling\n if (selectedIds.length > 1) {\n handles.setAttribute(\"lock-aspect-ratio\", \"true\");\n }\n handles.style.pointerEvents = \"none\";\n\n // Listen for bounds-change events\n handles.addEventListener(\"bounds-change\", (e: Event) => {\n const customEvent = e as CustomEvent<{ bounds: TransformBounds }>;\n const bounds = customEvent.detail.bounds;\n // Get current selection (not from closure)\n const currentSelectedIds = Array.from(\n this.selectionController.getModel().selectedIds,\n );\n if (currentSelectedIds.length > 1) {\n this.handleMultiSelectionTransformHandlesBoundsChange(\n currentSelectedIds,\n bounds,\n );\n } else if (currentSelectedIds[0]) {\n this.handleTransformHandlesBoundsChange(\n currentSelectedIds[0],\n bounds,\n );\n }\n });\n\n // Listen for rotation-change events\n handles.addEventListener(\"rotation-change\", (e: Event) => {\n const customEvent = e as CustomEvent<{ rotation: number }>;\n const rotation = customEvent.detail.rotation;\n // Get current selection (not from closure)\n const currentSelectedIds = Array.from(\n this.selectionController.getModel().selectedIds,\n );\n if (currentSelectedIds.length > 1) {\n this.handleMultiSelectionTransformHandlesRotationChange(\n currentSelectedIds,\n rotation,\n );\n } else if (currentSelectedIds[0]) {\n this.handleTransformHandlesRotationChange(\n currentSelectedIds[0],\n rotation,\n );\n }\n });\n\n this.overlayLayer.appendChild(handles);\n this.transformHandlesMap.set(handleKey, handles);\n }\n\n // Calculate bounding box for all selected elements\n if (selectedIds.length > 1) {\n // Multi-selection: calculate bounding box from element metadata\n // Account for rotation - use rotated bounding box for each element\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let hasElements = false;\n\n for (const id of selectedIds) {\n // Refresh metadata first\n this.updateElementMetadata(id);\n const metadata = this.elementMetadata.get(id);\n if (metadata) {\n // Get the axis-aligned bounding box that contains the rotated element\n const rotatedBounds = getRotatedBoundingBox(\n metadata.x,\n metadata.y,\n metadata.width,\n metadata.height,\n metadata.rotation ?? 0,\n );\n minX = Math.min(minX, rotatedBounds.minX);\n minY = Math.min(minY, rotatedBounds.minY);\n maxX = Math.max(maxX, rotatedBounds.maxX);\n maxY = Math.max(maxY, rotatedBounds.maxY);\n hasElements = true;\n }\n }\n\n if (hasElements && this.overlayLayer) {\n // For multi-selection, we need a target element for rotation calculation\n // Use the first selected element as the target (EFTransformHandles will calculate rotation\n // relative to that element's center, but our handler will apply it around bounding box center)\n const firstElementId = selectedIds[0];\n if (firstElementId) {\n const firstElement = this.elementRegistry.get(firstElementId);\n if (firstElement) {\n // Pass element directly to avoid shadow DOM selector issues\n handles.target = firstElement as any;\n }\n }\n\n // Calculate screen coordinates for the bounding box\n const panZoomElement = this.closest(\"ef-pan-zoom\") as any;\n const overlayRect = this.overlayLayer.getBoundingClientRect();\n\n let screenX: number;\n let screenY: number;\n let screenWidth: number;\n let screenHeight: number;\n\n if (\n panZoomElement &&\n typeof panZoomElement.canvasToScreen === \"function\" &&\n this.panZoomTransform\n ) {\n // Use EFPanZoom.canvasToScreen for consistency\n const topLeft = panZoomElement.canvasToScreen(minX, minY);\n const bottomRight = panZoomElement.canvasToScreen(maxX, maxY);\n screenX = topLeft.x;\n screenY = topLeft.y;\n screenWidth = bottomRight.x - topLeft.x;\n screenHeight = bottomRight.y - topLeft.y;\n } else {\n // Fallback: use canvasToScreen helper\n const canvasRect = this.getBoundingClientRect();\n const topLeft = canvasToScreen(\n minX,\n minY,\n canvasRect,\n this.panZoomTransform,\n );\n const bottomRight = canvasToScreen(\n maxX,\n maxY,\n canvasRect,\n this.panZoomTransform,\n );\n screenX = topLeft.x;\n screenY = topLeft.y;\n screenWidth = bottomRight.x - topLeft.x;\n screenHeight = bottomRight.y - topLeft.y;\n }\n\n // During rotation or resize, don't recalculate bounds from elements\n // (the interaction handler manages bounds directly to avoid feedback loops)\n if (\n handles.interactionMode === \"rotating\" ||\n handles.interactionMode === \"resizing\"\n ) {\n // Just update canvas scale if needed\n const newScale = this.panZoomTransform?.scale || 1;\n if (handles.canvasScale !== newScale) {\n handles.canvasScale = newScale;\n }\n } else {\n // EFTransformHandles renders bounds.width/height directly as CSS pixels, so it expects screen pixels.\n // Calculate relative position to overlay layer\n // Multi-selection always uses rotation: 0 when idle (rotation is baked into element positions)\n const currentBounds = handles.bounds;\n const newBounds: TransformBounds = {\n x: screenX - overlayRect.left,\n y: screenY - overlayRect.top,\n width: screenWidth,\n height: screenHeight,\n rotation: 0,\n };\n\n // Only update if bounds actually changed (including rotation)\n if (\n !currentBounds ||\n Math.abs(currentBounds.x - newBounds.x) > 0.1 ||\n Math.abs(currentBounds.y - newBounds.y) > 0.1 ||\n Math.abs(currentBounds.width - newBounds.width) > 0.1 ||\n Math.abs(currentBounds.height - newBounds.height) > 0.1 ||\n Math.abs(\n (currentBounds.rotation ?? 0) - (newBounds.rotation ?? 0),\n ) > 0.1\n ) {\n handles.bounds = newBounds;\n }\n\n // Set canvas scale\n const newScale = this.panZoomTransform?.scale || 1;\n if (handles.canvasScale !== newScale) {\n handles.canvasScale = newScale;\n }\n\n // Reset tracking when handle is idle (interaction ended)\n if (handles.interactionMode === \"idle\") {\n this.lastMultiSelectionRotation = null;\n this.multiSelectionRotationCenter = null;\n this.multiSelectionResizeInitial = null;\n // Re-enable resize handles after rotation ends\n handles.enableResize = true;\n }\n }\n }\n } else if (selectedIds[0]) {\n // Single selection: use element data directly\n // Refresh metadata to ensure it's up-to-date (especially after rotation)\n this.updateElementMetadata(selectedIds[0]);\n const elementData = this.elementMetadata.get(selectedIds[0]);\n if (elementData && elementData.element) {\n // Set target for rotation calculation\n // Use the element directly instead of a selector since it might be in shadow DOM\n // EFTransformHandles accepts either a string selector or an HTMLElement\n handles.target = elementData.element as any;\n this.updateTransformHandlesBounds(selectedIds[0], handles, elementData);\n }\n }\n }\n\n /**\n * Update transform handles bounds for an element.\n */\n private updateTransformHandlesBounds(\n _elementId: string,\n handles: EFTransformHandles,\n elementData: CanvasElementData,\n ): void {\n if (!this.overlayLayer) {\n return;\n }\n\n const overlayRect = this.overlayLayer.getBoundingClientRect();\n // Use .canvas-content as reference to match metadata calculation\n const shadowRoot = this.shadowRoot;\n const canvasContent = shadowRoot?.querySelector(\n \".canvas-content\",\n ) as HTMLElement;\n if (!canvasContent) {\n return;\n }\n const canvasRect = canvasContent.getBoundingClientRect();\n const scale = this.panZoomTransform?.scale || 1;\n\n // Calculate element's CENTER in canvas coordinates (center is stable during rotation)\n const centerCanvasX = elementData.x + elementData.width / 2;\n const centerCanvasY = elementData.y + elementData.height / 2;\n\n // Convert center to screen coordinates\n const centerScreen = canvasToScreen(\n centerCanvasX,\n centerCanvasY,\n canvasRect,\n this.panZoomTransform,\n );\n\n // Overlay size in screen pixels (use actual element size, NOT bounding box)\n const screenWidth = elementData.width * scale;\n const screenHeight = elementData.height * scale;\n\n // Overlay position: center minus half size (overlay-relative)\n const newBounds: TransformBounds = {\n x: centerScreen.x - overlayRect.left - screenWidth / 2,\n y: centerScreen.y - overlayRect.top - screenHeight / 2,\n width: screenWidth,\n height: screenHeight,\n rotation: elementData.rotation || 0,\n };\n\n // Only update if bounds actually changed (to avoid unnecessary renders)\n const currentBounds = handles.bounds;\n if (\n !currentBounds ||\n Math.abs(currentBounds.x - newBounds.x) > 0.1 ||\n Math.abs(currentBounds.y - newBounds.y) > 0.1 ||\n Math.abs(currentBounds.width - newBounds.width) > 0.1 ||\n Math.abs(currentBounds.height - newBounds.height) > 0.1 ||\n (currentBounds.rotation || 0) !== (newBounds.rotation || 0)\n ) {\n handles.bounds = newBounds;\n }\n\n // Set canvas scale so handles know the zoom level\n if (handles.canvasScale !== scale) {\n handles.canvasScale = scale;\n }\n }\n\n /**\n * Handle transform handles bounds-change event for multi-selection.\n * Updates all selected elements proportionally.\n */\n private handleMultiSelectionTransformHandlesBoundsChange(\n elementIds: string[],\n bounds: TransformBounds,\n ): void {\n if (!this.overlayLayer) {\n return;\n }\n\n // Bounds are already in canvas coordinates (dispatched by EFTransformHandles)\n const newCanvasPos = { x: bounds.x, y: bounds.y };\n const newCanvasWidth = bounds.width;\n const newCanvasHeight = bounds.height;\n\n // On first call, capture INITIAL element positions\n // This prevents feedback loops from re-reading updated positions\n // Use getRotatedBoundingBox to match how the overlay calculates bounds\n if (!this.multiSelectionResizeInitial) {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n const elements = new Map<\n string,\n {\n x: number;\n y: number;\n width: number;\n height: number;\n rotation: number;\n }\n >();\n\n for (const id of elementIds) {\n const metadata = this.elementMetadata.get(id);\n if (metadata) {\n elements.set(id, {\n x: metadata.x,\n y: metadata.y,\n width: metadata.width,\n height: metadata.height,\n rotation: metadata.rotation ?? 0,\n });\n\n // Use rotated bounding box to match overlay calculation\n const rotatedBounds = getRotatedBoundingBox(\n metadata.x,\n metadata.y,\n metadata.width,\n metadata.height,\n metadata.rotation ?? 0,\n );\n minX = Math.min(minX, rotatedBounds.minX);\n minY = Math.min(minY, rotatedBounds.minY);\n maxX = Math.max(maxX, rotatedBounds.maxX);\n maxY = Math.max(maxY, rotatedBounds.maxY);\n }\n }\n\n this.multiSelectionResizeInitial = { elements, minX, minY, maxX, maxY };\n }\n\n // Use INITIAL positions for all calculations (prevents feedback loops)\n const {\n elements: initialElements,\n minX,\n minY,\n maxX,\n maxY,\n } = this.multiSelectionResizeInitial;\n const oldWidth = maxX - minX;\n const oldHeight = maxY - minY;\n\n if (oldWidth === 0 || oldHeight === 0) {\n return;\n }\n\n // Calculate scale factors for each dimension\n const scaleX = newCanvasWidth / oldWidth;\n const scaleY = newCanvasHeight / oldHeight;\n\n // Ensure scales are positive (no flipping)\n const safeScaleX = Math.max(0.01, scaleX);\n const safeScaleY = Math.max(0.01, scaleY);\n\n // The bounds position (newCanvasPos) represents where the fixed corner should be\n // For proper corner pinning, use the position from bounds directly\n // Update all elements proportionally using INITIAL positions\n for (const [id, initialData] of initialElements.entries()) {\n // Calculate relative position within the INITIAL bounding box (0-1 range)\n const relX = (initialData.x - minX) / oldWidth;\n const relY = (initialData.y - minY) / oldHeight;\n\n // Apply new position and size\n // Position relative to the new bounds position\n const newX = newCanvasPos.x + relX * newCanvasWidth;\n const newY = newCanvasPos.y + relY * newCanvasHeight;\n const newWidth = initialData.width * safeScaleX;\n const newHeight = initialData.height * safeScaleY;\n\n // Update element position\n this.updateElementPosition(id, newX, newY);\n\n // Update element size\n const element = this.elementRegistry.get(id);\n if (!element) {\n console.warn(\n \"[EFCanvas] handleMultiSelectionTransformHandlesBoundsChange: element not found\",\n id,\n );\n continue;\n }\n\n // Set size in canvas coordinates (parent transform handles scaling)\n element.style.width = `${newWidth}px`;\n element.style.height = `${newHeight}px`;\n\n // Update metadata\n const metadata = this.elementMetadata.get(id);\n if (metadata) {\n this.elementMetadata.set(id, {\n ...metadata,\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight,\n });\n }\n }\n\n // Update handle overlay to match elements in real-time\n const handles = this.transformHandlesMap.get(\"multi-selection\");\n if (handles && this.overlayLayer) {\n const overlayRect = this.overlayLayer.getBoundingClientRect();\n const canvasRect = this.getBoundingClientRect();\n const scale = this.panZoomTransform?.scale || 1;\n\n // Calculate center of new bounding box\n const centerCanvasX = newCanvasPos.x + newCanvasWidth / 2;\n const centerCanvasY = newCanvasPos.y + newCanvasHeight / 2;\n\n // Convert center to screen coordinates\n const centerScreen = canvasToScreen(\n centerCanvasX,\n centerCanvasY,\n canvasRect,\n this.panZoomTransform,\n );\n\n // Overlay size in screen pixels\n const screenWidth = newCanvasWidth * scale;\n const screenHeight = newCanvasHeight * scale;\n\n // Overlay position: center minus half size (overlay-relative)\n const newBounds: TransformBounds = {\n x: centerScreen.x - overlayRect.left - screenWidth / 2,\n y: centerScreen.y - overlayRect.top - screenHeight / 2,\n width: screenWidth,\n height: screenHeight,\n rotation: 0,\n };\n\n handles.bounds = newBounds;\n }\n }\n\n // Track multi-selection rotation state (only during active rotation drag)\n private lastMultiSelectionRotation: number | null = null;\n private multiSelectionRotationCenter: { x: number; y: number } | null = null;\n\n // Track multi-selection resize state (initial positions at start of resize)\n private multiSelectionResizeInitial: {\n elements: Map<\n string,\n { x: number; y: number; width: number; height: number; rotation: number }\n >;\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n } | null = null;\n\n /**\n * Handle transform handles rotation-change event for multiple selected elements.\n * Rotates all elements around the center of the bounding box.\n */\n private handleMultiSelectionTransformHandlesRotationChange(\n elementIds: string[],\n rotation: number,\n ): void {\n // On first call, calculate and store the initial group center\n // This ensures we always rotate around the same point (no drift)\n const isFirstCall = this.lastMultiSelectionRotation === null;\n\n if (isFirstCall) {\n // Calculate initial bounding box center\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const id of elementIds) {\n const metadata = this.elementMetadata.get(id);\n if (metadata) {\n minX = Math.min(minX, metadata.x);\n minY = Math.min(minY, metadata.y);\n maxX = Math.max(maxX, metadata.x + metadata.width);\n maxY = Math.max(maxY, metadata.y + metadata.height);\n }\n }\n\n this.multiSelectionRotationCenter = {\n x: (minX + maxX) / 2,\n y: (minY + maxY) / 2,\n };\n }\n\n // Calculate delta rotation\n const deltaRotation = isFirstCall\n ? 0\n : rotation - this.lastMultiSelectionRotation!;\n this.lastMultiSelectionRotation = rotation;\n\n // Use the fixed center (calculated at start of rotation)\n const groupCenterX = this.multiSelectionRotationCenter!.x;\n const groupCenterY = this.multiSelectionRotationCenter!.y;\n\n // Rotate each element around the group center\n const deltaRadians = (deltaRotation * Math.PI) / 180;\n const cos = Math.cos(deltaRadians);\n const sin = Math.sin(deltaRadians);\n\n for (const id of elementIds) {\n const metadata = this.elementMetadata.get(id);\n const element = this.elementRegistry.get(id);\n if (!metadata || !element) continue;\n\n const data = {\n id,\n element,\n x: metadata.x,\n y: metadata.y,\n width: metadata.width,\n height: metadata.height,\n rotation: metadata.rotation ?? 0,\n };\n\n // Skip position updates if no actual rotation delta\n if (Math.abs(deltaRotation) < 0.001) continue;\n // Calculate element's center relative to group center\n const elementCenterX = data.x + data.width / 2;\n const elementCenterY = data.y + data.height / 2;\n const relX = elementCenterX - groupCenterX;\n const relY = elementCenterY - groupCenterY;\n\n // Rotate the relative position by delta\n const rotatedRelX = relX * cos - relY * sin;\n const rotatedRelY = relX * sin + relY * cos;\n\n // Calculate new top-left position from rotated center\n const newX = groupCenterX + rotatedRelX - data.width / 2;\n const newY = groupCenterY + rotatedRelY - data.height / 2;\n\n // Update element position\n this.updateElementPosition(data.id, newX, newY);\n\n // Update element's individual rotation\n const newRotation = data.rotation + deltaRotation;\n data.element.style.transform = `rotate(${newRotation}deg)`;\n data.element.style.transformOrigin = \"center\";\n\n // Update metadata\n this.elementMetadata.set(data.id, {\n id: data.id,\n element: data.element,\n x: newX,\n y: newY,\n width: data.width,\n height: data.height,\n rotation: newRotation,\n });\n }\n\n // Update handles to show current rotation during drag\n // On release, rotation resets to 0 (rotation is \"baked\" into element positions)\n const handles = this.transformHandlesMap.get(\"multi-selection\");\n if (handles) {\n // Hide resize handles during rotation (only show rotation handle)\n handles.enableResize = false;\n\n const currentBounds = handles.bounds;\n if (currentBounds) {\n // Show rotation during drag (will reset to 0 on release via updateTransformHandles)\n handles.bounds = {\n ...currentBounds,\n rotation: this.lastMultiSelectionRotation ?? 0,\n };\n handles.requestUpdate();\n }\n }\n }\n\n /**\n * Handle transform handles bounds-change event for single element.\n * Converts bounds from overlay-relative screen coordinates to canvas coordinates.\n */\n private handleTransformHandlesBoundsChange(\n elementId: string,\n bounds: TransformBounds,\n ): void {\n if (!this.overlayLayer) {\n return;\n }\n\n // Bounds are now in canvas coordinates (one-way data flow: resize calculates in canvas, updates element, handles read from element)\n const canvasPos = { x: bounds.x, y: bounds.y };\n const canvasWidth = bounds.width;\n const canvasHeight = bounds.height;\n\n // Update element directly in canvas coordinates\n const element = this.elementRegistry.get(elementId);\n if (element) {\n // Update position\n this.updateElementPosition(elementId, canvasPos.x, canvasPos.y);\n\n // Update size - set in canvas coordinates (parent transform handles scaling)\n const metadata = this.elementMetadata.get(elementId);\n if (metadata) {\n element.style.width = `${canvasWidth}px`;\n element.style.height = `${canvasHeight}px`;\n metadata.width = canvasWidth;\n metadata.height = canvasHeight;\n }\n\n // Note: Rotation is handled separately via rotation-change event\n // Only update rotation here if it's explicitly set (for initial sync)\n if (\n bounds.rotation !== undefined &&\n bounds.rotation !== (metadata?.rotation || 0)\n ) {\n element.style.transform = `rotate(${bounds.rotation}deg)`;\n if (metadata) {\n metadata.rotation = bounds.rotation;\n }\n }\n }\n\n // Element is now updated. Immediately update handle bounds prop (one-way flow: element → bounds prop)\n // Use the SAME calculation as updateTransformHandlesBounds for consistency\n const handles = this.transformHandlesMap.get(elementId);\n if (handles && this.overlayLayer) {\n const overlayRect = this.overlayLayer.getBoundingClientRect();\n const canvasRect = this.getBoundingClientRect();\n const scale = this.panZoomTransform?.scale || 1;\n\n // Calculate element's CENTER from the canvas coordinates we just applied\n const centerCanvasX = canvasPos.x + canvasWidth / 2;\n const centerCanvasY = canvasPos.y + canvasHeight / 2;\n\n // Convert center to screen coordinates\n const centerScreen = canvasToScreen(\n centerCanvasX,\n centerCanvasY,\n canvasRect,\n this.panZoomTransform,\n );\n\n // Overlay size in screen pixels (use actual element size, NOT bounding box)\n const screenWidth = canvasWidth * scale;\n const screenHeight = canvasHeight * scale;\n\n // Overlay position: center minus half size (overlay-relative)\n const newBounds: TransformBounds = {\n x: centerScreen.x - overlayRect.left - screenWidth / 2,\n y: centerScreen.y - overlayRect.top - screenHeight / 2,\n width: screenWidth,\n height: screenHeight,\n rotation: bounds.rotation || 0,\n };\n\n handles.bounds = newBounds;\n handles.requestUpdate();\n }\n }\n\n /**\n * Handle transform handles rotation-change event for single element.\n */\n private handleTransformHandlesRotationChange(\n elementId: string,\n rotation: number,\n ): void {\n const element = this.elementRegistry.get(elementId);\n if (!element) {\n console.warn(\n \"[EFCanvas] handleTransformHandlesRotationChange: element not found\",\n elementId,\n );\n return;\n }\n\n // Apply rotation transform\n // Elements use left/top for positioning, so transform is safe to use for rotation\n element.style.transform = `rotate(${rotation}deg)`;\n element.style.transformOrigin = \"center\";\n\n // Update metadata to preserve rotation\n const metadata = this.elementMetadata.get(elementId);\n if (metadata) {\n this.elementMetadata.set(elementId, {\n ...metadata,\n rotation,\n });\n } else {\n // If metadata doesn't exist, create it (shouldn't happen, but be safe)\n this.updateElementMetadata(elementId);\n const updatedMetadata = this.elementMetadata.get(elementId);\n if (updatedMetadata) {\n this.elementMetadata.set(elementId, {\n ...updatedMetadata,\n rotation,\n });\n }\n }\n }\n\n /**\n * Cleanup transform handles.\n */\n private cleanupTransformHandles(): void {\n this.transformHandlesMap.forEach((handles) => {\n handles.remove();\n });\n this.transformHandlesMap.clear();\n }\n\n render() {\n return html`\n <div class=\"canvas-content\">\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-canvas\": EFCanvas;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import * as lit34 from "lit";
2
+ import { LitElement } from "lit";
3
+ import * as lit_html33 from "lit-html";
4
+
5
+ //#region src/canvas/EFCanvasItem.d.ts
6
+
7
+ /**
8
+ * Canvas item wrapper component.
9
+ *
10
+ * @deprecated This component is deprecated. All DOM nodes in ef-canvas are now automatically
11
+ * treated as canvas elements. Use plain HTML elements (div, etc.) instead.
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <!-- Old way (deprecated) -->
16
+ * <ef-canvas>
17
+ * <ef-canvas-item id="item-1" style="left: 100px; top: 100px;">
18
+ * <div>My content</div>
19
+ * </ef-canvas-item>
20
+ * </ef-canvas>
21
+ *
22
+ * <!-- New way -->
23
+ * <ef-canvas>
24
+ * <div id="item-1" style="left: 100px; top: 100px;">
25
+ * <div>My content</div>
26
+ * </div>
27
+ * </ef-canvas>
28
+ * ```
29
+ */
30
+ declare class EFCanvasItem extends LitElement {
31
+ static styles: lit34.CSSResult;
32
+ id: string;
33
+ private canvas;
34
+ private api;
35
+ private registeredId;
36
+ connectedCallback(): void;
37
+ disconnectedCallback(): void;
38
+ /**
39
+ * Find parent ef-canvas and register this element.
40
+ */
41
+ private findAndRegister;
42
+ /**
43
+ * Unregister this element from the canvas.
44
+ */
45
+ private unregister;
46
+ render(): lit_html33.TemplateResult<1>;
47
+ }
48
+ declare global {
49
+ interface HTMLElementTagNameMap {
50
+ "ef-canvas-item": EFCanvasItem;
51
+ }
52
+ }
53
+ //#endregion
54
+ export { EFCanvasItem };
55
+ //# sourceMappingURL=EFCanvasItem.d.ts.map
@@ -0,0 +1,72 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
2
+ import { CanvasAPI } from "./api/CanvasAPI.js";
3
+ import { LitElement, css, html } from "lit";
4
+ import { customElement, property } from "lit/decorators.js";
5
+
6
+ //#region src/canvas/EFCanvasItem.ts
7
+ let EFCanvasItem = class EFCanvasItem$1 extends LitElement {
8
+ constructor(..._args) {
9
+ super(..._args);
10
+ this.id = "";
11
+ this.canvas = null;
12
+ this.api = null;
13
+ this.registeredId = null;
14
+ }
15
+ static {
16
+ this.styles = css`
17
+ :host {
18
+ display: block;
19
+ position: absolute;
20
+ }
21
+ `;
22
+ }
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+ this.findAndRegister();
26
+ }
27
+ disconnectedCallback() {
28
+ super.disconnectedCallback();
29
+ this.unregister();
30
+ }
31
+ /**
32
+ * Find parent ef-canvas and register this element.
33
+ */
34
+ findAndRegister() {
35
+ this.canvas = this.closest("ef-canvas");
36
+ if (!this.canvas) {
37
+ console.warn("[EFCanvasItem] No parent ef-canvas found. Element will not be registered.");
38
+ return;
39
+ }
40
+ this.canvas.updateComplete.then(() => {
41
+ this.api = new CanvasAPI(this.canvas);
42
+ if (!this.id) {
43
+ console.error("[EFCanvasItem] Element must have an 'id' attribute. Set it before adding to canvas.");
44
+ return;
45
+ }
46
+ this.registeredId = this.api.registerElement(this, this.id);
47
+ });
48
+ }
49
+ /**
50
+ * Unregister this element from the canvas.
51
+ */
52
+ unregister() {
53
+ if (this.api && this.registeredId) {
54
+ this.api.unregisterElement(this.registeredId);
55
+ this.registeredId = null;
56
+ }
57
+ this.api = null;
58
+ this.canvas = null;
59
+ }
60
+ render() {
61
+ return html`<slot></slot>`;
62
+ }
63
+ };
64
+ __decorate([property({
65
+ type: String,
66
+ reflect: true
67
+ })], EFCanvasItem.prototype, "id", void 0);
68
+ EFCanvasItem = __decorate([customElement("ef-canvas-item")], EFCanvasItem);
69
+
70
+ //#endregion
71
+ export { EFCanvasItem };
72
+ //# sourceMappingURL=EFCanvasItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EFCanvasItem.js","names":["EFCanvasItem"],"sources":["../../src/canvas/EFCanvasItem.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport type { EFCanvas } from \"./EFCanvas.js\";\nimport { CanvasAPI } from \"./api/CanvasAPI.js\";\n\n/**\n * Canvas item wrapper component.\n *\n * @deprecated This component is deprecated. All DOM nodes in ef-canvas are now automatically\n * treated as canvas elements. Use plain HTML elements (div, etc.) instead.\n *\n * @example\n * ```html\n * <!-- Old way (deprecated) -->\n * <ef-canvas>\n * <ef-canvas-item id=\"item-1\" style=\"left: 100px; top: 100px;\">\n * <div>My content</div>\n * </ef-canvas-item>\n * </ef-canvas>\n *\n * <!-- New way -->\n * <ef-canvas>\n * <div id=\"item-1\" style=\"left: 100px; top: 100px;\">\n * <div>My content</div>\n * </div>\n * </ef-canvas>\n * ```\n */\n@customElement(\"ef-canvas-item\")\nexport class EFCanvasItem extends LitElement {\n static styles = css`\n :host {\n display: block;\n position: absolute;\n }\n `;\n\n @property({ type: String, reflect: true })\n id = \"\";\n\n private canvas: EFCanvas | null = null;\n private api: CanvasAPI | null = null;\n private registeredId: string | null = null;\n\n connectedCallback() {\n super.connectedCallback();\n this.findAndRegister();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.unregister();\n }\n\n /**\n * Find parent ef-canvas and register this element.\n */\n private findAndRegister() {\n // Find parent ef-canvas\n this.canvas = this.closest(\"ef-canvas\") as EFCanvas | null;\n if (!this.canvas) {\n console.warn(\n \"[EFCanvasItem] No parent ef-canvas found. Element will not be registered.\",\n );\n return;\n }\n\n // Wait for canvas to be ready\n this.canvas.updateComplete.then(() => {\n // Create API instance\n this.api = new CanvasAPI(this.canvas!);\n\n // Element must have an ID - check before registering\n if (!this.id) {\n console.error(\n \"[EFCanvasItem] Element must have an 'id' attribute. Set it before adding to canvas.\",\n );\n return;\n }\n\n // Register this element with the canvas\n // Pass the id explicitly - canvas will throw if it's missing or duplicate\n this.registeredId = this.api.registerElement(this, this.id);\n });\n }\n\n /**\n * Unregister this element from the canvas.\n */\n private unregister() {\n if (this.api && this.registeredId) {\n this.api.unregisterElement(this.registeredId);\n this.registeredId = null;\n }\n this.api = null;\n this.canvas = null;\n }\n\n render() {\n return html`<slot></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-canvas-item\": EFCanvasItem;\n }\n}\n"],"mappings":";;;;;;AA6BO,yBAAMA,uBAAqB,WAAW;;;YAStC;gBAE6B;aACF;sBACM;;;gBAZtB,GAAG;;;;;;;CAcnB,oBAAoB;AAClB,QAAM,mBAAmB;AACzB,OAAK,iBAAiB;;CAGxB,uBAAuB;AACrB,QAAM,sBAAsB;AAC5B,OAAK,YAAY;;;;;CAMnB,AAAQ,kBAAkB;AAExB,OAAK,SAAS,KAAK,QAAQ,YAAY;AACvC,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAQ,KACN,4EACD;AACD;;AAIF,OAAK,OAAO,eAAe,WAAW;AAEpC,QAAK,MAAM,IAAI,UAAU,KAAK,OAAQ;AAGtC,OAAI,CAAC,KAAK,IAAI;AACZ,YAAQ,MACN,sFACD;AACD;;AAKF,QAAK,eAAe,KAAK,IAAI,gBAAgB,MAAM,KAAK,GAAG;IAC3D;;;;;CAMJ,AAAQ,aAAa;AACnB,MAAI,KAAK,OAAO,KAAK,cAAc;AACjC,QAAK,IAAI,kBAAkB,KAAK,aAAa;AAC7C,QAAK,eAAe;;AAEtB,OAAK,MAAM;AACX,OAAK,SAAS;;CAGhB,SAAS;AACP,SAAO,IAAI;;;YA9DZ,SAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,CAAC;2BAT3C,cAAc,iBAAiB"}
@@ -0,0 +1,115 @@
1
+ import { CanvasData, CanvasElementData } from "./types.js";
2
+ import { EFCanvas } from "../EFCanvas.js";
3
+
4
+ //#region src/canvas/api/CanvasAPI.d.ts
5
+
6
+ /**
7
+ * Programmatic API/SDK for canvas operations.
8
+ */
9
+ declare class CanvasAPI {
10
+ private canvas;
11
+ constructor(canvas: EFCanvas);
12
+ /**
13
+ * Register an existing element for canvas management.
14
+ * @param element - The HTML element to register
15
+ * @param id - Optional custom ID, otherwise auto-generated
16
+ * @returns The element ID
17
+ */
18
+ registerElement(element: HTMLElement, id?: string): string;
19
+ /**
20
+ * Unregister an element from canvas management.
21
+ * @param id - Element ID or element itself
22
+ */
23
+ unregisterElement(id: string | HTMLElement): void;
24
+ /**
25
+ * Update element position/transform in canvas coordinates.
26
+ * @param id - Element ID
27
+ * @param updates - Partial element data to update
28
+ */
29
+ updateElement(id: string, updates: Partial<CanvasElementData>): void;
30
+ /**
31
+ * Get element data by ID.
32
+ * @param id - Element ID
33
+ * @returns Element data or null if not found
34
+ */
35
+ getElement(id: string): CanvasElementData | null;
36
+ /**
37
+ * Get all registered elements.
38
+ * @returns Array of all element data
39
+ */
40
+ getAllElements(): CanvasElementData[];
41
+ /**
42
+ * Get the number of registered elements.
43
+ * @returns The count of registered elements
44
+ */
45
+ get elementCount(): number;
46
+ /**
47
+ * Get all registered elements (getter alias for getAllElements).
48
+ * @returns Array of all element data
49
+ */
50
+ get elements(): CanvasElementData[];
51
+ /**
52
+ * Convert screen coordinates to canvas coordinates.
53
+ * @param screenX - X coordinate in screen space
54
+ * @param screenY - Y coordinate in screen space
55
+ * @returns Canvas coordinates
56
+ */
57
+ screenToCanvas(screenX: number, screenY: number): {
58
+ x: number;
59
+ y: number;
60
+ };
61
+ /**
62
+ * Convert canvas coordinates to screen coordinates.
63
+ * @param canvasX - X coordinate in canvas space
64
+ * @param canvasY - Y coordinate in canvas space
65
+ * @returns Screen coordinates
66
+ */
67
+ canvasToScreen(canvasX: number, canvasY: number): {
68
+ x: number;
69
+ y: number;
70
+ };
71
+ /**
72
+ * Select an element.
73
+ * @param id - Element ID
74
+ */
75
+ select(id: string): void;
76
+ /**
77
+ * Select multiple elements.
78
+ * @param ids - Array of element IDs
79
+ */
80
+ selectMultiple(ids: string[]): void;
81
+ /**
82
+ * Deselect an element.
83
+ * @param id - Element ID
84
+ */
85
+ deselect(id: string): void;
86
+ /**
87
+ * Get currently selected element IDs.
88
+ * @returns Set of selected IDs
89
+ */
90
+ getSelectedIds(): string[];
91
+ /**
92
+ * Create a group from element IDs.
93
+ * @param ids - Array of element IDs to group
94
+ * @returns Group ID
95
+ */
96
+ group(ids: string[]): string;
97
+ /**
98
+ * Ungroup a group.
99
+ * @param groupId - Group ID
100
+ */
101
+ ungroup(groupId: string): void;
102
+ /**
103
+ * Export canvas data.
104
+ * @returns Canvas data structure
105
+ */
106
+ export(): CanvasData;
107
+ /**
108
+ * Import canvas data.
109
+ * @param data - Canvas data structure
110
+ */
111
+ import(data: CanvasData): void;
112
+ }
113
+ //#endregion
114
+ export { CanvasAPI };
115
+ //# sourceMappingURL=CanvasAPI.d.ts.map