@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
@@ -1 +1 @@
1
- {"version":3,"file":"EFResizableBox.js","names":["movementValue: number","newBounds: BoxBounds","EFResizableBox","context: ResizeContext","idealBounds: BoxBounds","result: BoxBounds"],"sources":["../../src/gui/EFResizableBox.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\n\n// Constants\nconst DEFAULT_MIN_SIZE = 10;\nconst CENTER_RESIZE_MULTIPLIER = 2;\n\nexport interface BoxBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ntype ResizeCorner = \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\ntype ResizeSide = \"top\" | \"right\" | \"bottom\" | \"left\";\ntype ResizeHandle = ResizeCorner | ResizeSide;\n\ninterface Dimensions {\n width: number;\n height: number;\n}\n\ninterface ResizeContext {\n readonly initialBounds: BoxBounds;\n readonly container: Dimensions;\n readonly constraints: {\n minSize: number;\n aspectRatio?: number;\n };\n readonly movement: {\n deltaX: number;\n deltaY: number;\n };\n readonly modifiers: {\n centerResize: boolean;\n preserveAspectRatio: boolean;\n };\n}\n\n// Pure calculation functions\nfunction constrainMovementDeltas(\n initialBounds: BoxBounds,\n deltaX: number,\n deltaY: number,\n container: Dimensions,\n): { deltaX: number; deltaY: number } {\n const maxLeftMovement = -initialBounds.x;\n const maxRightMovement =\n container.width - (initialBounds.x + initialBounds.width);\n const maxUpMovement = -initialBounds.y;\n const maxDownMovement =\n container.height - (initialBounds.y + initialBounds.height);\n\n return {\n deltaX: Math.max(maxLeftMovement, Math.min(maxRightMovement, deltaX)),\n deltaY: Math.max(maxUpMovement, Math.min(maxDownMovement, deltaY)),\n };\n}\n\nfunction calculateNormalResize(\n context: ResizeContext,\n handle: ResizeHandle,\n): BoxBounds {\n const { initialBounds, movement } = context;\n const { deltaX, deltaY } = movement;\n\n switch (handle) {\n case \"bottom-right\":\n return {\n ...initialBounds,\n width: initialBounds.width + deltaX,\n height: initialBounds.height + deltaY,\n };\n\n case \"top-left\": {\n const rightEdge = initialBounds.x + initialBounds.width;\n const bottomEdge = initialBounds.y + initialBounds.height;\n const newX = initialBounds.x + deltaX;\n const newY = initialBounds.y + deltaY;\n\n return {\n x: newX,\n y: newY,\n width: rightEdge - newX,\n height: bottomEdge - newY,\n };\n }\n\n case \"top-right\": {\n const bottomEdge = initialBounds.y + initialBounds.height;\n const newY = initialBounds.y + deltaY;\n\n return {\n ...initialBounds,\n y: newY,\n width: initialBounds.width + deltaX,\n height: bottomEdge - newY,\n };\n }\n\n case \"bottom-left\": {\n const rightEdge = initialBounds.x + initialBounds.width;\n const newX = initialBounds.x + deltaX;\n\n return {\n ...initialBounds,\n x: newX,\n width: rightEdge - newX,\n height: initialBounds.height + deltaY,\n };\n }\n\n case \"top\": {\n const bottomEdge = initialBounds.y + initialBounds.height;\n const newY = initialBounds.y + deltaY;\n\n return {\n ...initialBounds,\n y: newY,\n height: bottomEdge - newY,\n };\n }\n\n case \"right\":\n return {\n ...initialBounds,\n width: initialBounds.width + deltaX,\n };\n\n case \"bottom\":\n return {\n ...initialBounds,\n height: initialBounds.height + deltaY,\n };\n\n case \"left\": {\n const rightEdge = initialBounds.x + initialBounds.width;\n const newX = initialBounds.x + deltaX;\n\n return {\n ...initialBounds,\n x: newX,\n width: rightEdge - newX,\n };\n }\n\n default:\n return initialBounds;\n }\n}\n\nfunction calculateAspectRatioResize(\n context: ResizeContext,\n handle: ResizeHandle,\n): BoxBounds {\n const { initialBounds, movement, constraints } = context;\n const { deltaX, deltaY } = movement;\n if (!constraints.aspectRatio) {\n return initialBounds;\n }\n const aspectRatio = constraints.aspectRatio;\n\n const widthMovement = deltaX;\n const heightMovement = deltaY * aspectRatio;\n\n let movementValue: number;\n switch (handle) {\n case \"bottom-right\":\n case \"top-left\":\n movementValue = (widthMovement + heightMovement) / 2;\n break;\n case \"top-right\":\n case \"bottom-left\":\n movementValue = (widthMovement - heightMovement) / 2;\n break;\n default:\n movementValue = widthMovement;\n }\n\n const baseWidth =\n handle === \"top-left\" || handle === \"bottom-left\"\n ? initialBounds.width - movementValue\n : initialBounds.width + movementValue;\n\n const width = Math.max(constraints.minSize, baseWidth);\n const height = width / aspectRatio;\n\n const newBounds: BoxBounds = { ...initialBounds, width, height };\n\n // Adjust position for handles that move the origin\n switch (handle) {\n case \"top-left\":\n newBounds.x = initialBounds.x + initialBounds.width - width;\n newBounds.y = initialBounds.y + initialBounds.height - height;\n break;\n case \"top-right\":\n newBounds.y = initialBounds.y + initialBounds.height - height;\n break;\n case \"bottom-left\":\n newBounds.x = initialBounds.x + initialBounds.width - width;\n break;\n }\n\n return newBounds;\n}\n\nfunction calculateCenterResize(\n context: ResizeContext,\n handle: ResizeHandle,\n): BoxBounds {\n const { initialBounds, movement } = context;\n const { deltaX, deltaY } = movement;\n\n const centerX = initialBounds.x + initialBounds.width / 2;\n const centerY = initialBounds.y + initialBounds.height / 2;\n\n let widthChange = 0;\n let heightChange = 0;\n\n switch (handle) {\n case \"bottom-right\":\n widthChange = deltaX * CENTER_RESIZE_MULTIPLIER;\n heightChange = deltaY * CENTER_RESIZE_MULTIPLIER;\n break;\n case \"top-left\":\n widthChange = -deltaX * CENTER_RESIZE_MULTIPLIER;\n heightChange = -deltaY * CENTER_RESIZE_MULTIPLIER;\n break;\n case \"top-right\":\n widthChange = deltaX * CENTER_RESIZE_MULTIPLIER;\n heightChange = -deltaY * CENTER_RESIZE_MULTIPLIER;\n break;\n case \"bottom-left\":\n widthChange = -deltaX * CENTER_RESIZE_MULTIPLIER;\n heightChange = deltaY * CENTER_RESIZE_MULTIPLIER;\n break;\n case \"top\":\n case \"bottom\":\n heightChange =\n (handle === \"bottom\" ? deltaY : -deltaY) * CENTER_RESIZE_MULTIPLIER;\n break;\n case \"left\":\n case \"right\":\n widthChange =\n (handle === \"right\" ? deltaX : -deltaX) * CENTER_RESIZE_MULTIPLIER;\n break;\n }\n\n const newWidth = initialBounds.width + widthChange;\n const newHeight = initialBounds.height + heightChange;\n\n return {\n x: centerX - newWidth / 2,\n y: centerY - newHeight / 2,\n width: newWidth,\n height: newHeight,\n };\n}\n\nfunction calculateCenterResizeWithAspectRatio(\n context: ResizeContext,\n handle: ResizeHandle,\n): BoxBounds {\n const { initialBounds, movement, constraints } = context;\n const { deltaX, deltaY } = movement;\n if (!constraints.aspectRatio) {\n return initialBounds;\n }\n const aspectRatio = constraints.aspectRatio;\n\n const centerX = initialBounds.x + initialBounds.width / 2;\n const centerY = initialBounds.y + initialBounds.height / 2;\n\n let movementValue: number;\n switch (handle) {\n case \"bottom-right\":\n movementValue = Math.max(deltaX, deltaY);\n break;\n case \"top-left\":\n movementValue = -Math.max(-deltaX, -deltaY);\n break;\n case \"top-right\":\n movementValue = Math.max(deltaX, -deltaY);\n break;\n case \"bottom-left\":\n movementValue = Math.max(-deltaX, deltaY);\n break;\n case \"top\":\n case \"bottom\":\n movementValue = handle === \"bottom\" ? deltaY : -deltaY;\n break;\n case \"left\":\n case \"right\":\n movementValue = handle === \"right\" ? deltaX : -deltaX;\n break;\n default:\n movementValue = Math.max(deltaX, deltaY);\n }\n\n const newWidth = Math.max(\n constraints.minSize,\n initialBounds.width + movementValue * CENTER_RESIZE_MULTIPLIER,\n );\n const newHeight = newWidth / aspectRatio;\n\n return {\n x: centerX - newWidth / 2,\n y: centerY - newHeight / 2,\n width: newWidth,\n height: newHeight,\n };\n}\n\n@customElement(\"ef-resizable-box\")\nexport class EFResizableBox extends LitElement {\n @property({ type: Object })\n bounds: BoxBounds = { x: 0, y: 0, width: 100, height: 100 };\n\n @state()\n private containerWidth = 0;\n\n @state()\n private containerHeight = 0;\n\n @property({ type: Number })\n minSize = DEFAULT_MIN_SIZE;\n\n @state()\n private isDragging = false;\n\n @state()\n private dragMode: \"move\" | \"resize\" | null = null;\n\n private interaction: {\n startPoint: { x: number; y: number };\n target: { mode: \"move\" | \"resize\"; handle?: ResizeHandle };\n initialBounds: BoxBounds;\n pointerId: number;\n } | null = null;\n\n private modifiers = { shift: false, alt: false };\n\n static styles = css`\n .box {\n position: absolute;\n border: 2px solid var(--ef-resizable-box-border-color, #3b82f6);\n background-color: var(--ef-resizable-box-bg-color, rgba(59, 130, 246, 0.2));\n cursor: grab;\n }\n .box.dragging {\n border-color: var(--ef-resizable-box-dragging-border-color, #2563eb);\n background-color: var(--ef-resizable-box-dragging-bg-color, rgba(37, 99, 235, 0.3));\n }\n .handle {\n position: absolute;\n background-color: var(--ef-resizable-box-handle-color, #3b82f6);\n touch-action: none;\n }\n .top-left { top: -4px; left: -4px; width: 8px; height: 8px; cursor: nwse-resize; }\n .top-right { top: -4px; right: -4px; width: 8px; height: 8px; cursor: nesw-resize; }\n .bottom-left { bottom: -4px; left: -4px; width: 8px; height: 8px; cursor: nesw-resize; }\n .bottom-right { bottom: -4px; right: -4px; width: 8px; height: 8px; cursor: nwse-resize; }\n .top { top: -4px; left: 4px; right: 4px; height: 8px; cursor: ns-resize; }\n .right { top: 4px; bottom: 4px; right: -4px; width: 8px; cursor: ew-resize; }\n .bottom { bottom: -4px; left: 4px; right: 4px; height: 8px; cursor: ns-resize; }\n .left { top: 4px; bottom: 4px; left: -4px; width: 8px; cursor: ew-resize; }\n `;\n\n private resizeObserver?: ResizeObserver;\n\n connectedCallback() {\n super.connectedCallback();\n if (this.offsetParent) {\n this.containerWidth = this.offsetParent.clientWidth;\n this.containerHeight = this.offsetParent.clientHeight;\n }\n this.resizeObserver = new ResizeObserver(() => {\n if (this.offsetParent) {\n this.containerWidth = this.offsetParent.clientWidth;\n this.containerHeight = this.offsetParent.clientHeight;\n }\n });\n if (this.offsetParent) {\n this.resizeObserver.observe(this.offsetParent);\n }\n }\n\n private handlePointerDown(\n e: PointerEvent,\n mode: \"move\" | \"resize\",\n handle?: ResizeHandle,\n ) {\n e.preventDefault();\n e.stopPropagation();\n this.isDragging = true;\n this.dragMode = mode;\n\n this.interaction = {\n startPoint: { x: e.clientX, y: e.clientY },\n target: { mode, handle },\n initialBounds: { ...this.bounds },\n pointerId: e.pointerId,\n };\n this.modifiers = { shift: e.shiftKey, alt: e.altKey };\n\n document.addEventListener(\"pointermove\", this.handlePointerMove, {\n passive: false,\n });\n document.addEventListener(\"pointerup\", this.handlePointerUp, {\n passive: false,\n });\n }\n\n private handlePointerMove = (e: PointerEvent) => {\n if (\n !this.isDragging ||\n !this.interaction ||\n e.pointerId !== this.interaction.pointerId\n )\n return;\n\n e.preventDefault();\n\n const deltaX = e.clientX - this.interaction.startPoint.x;\n const deltaY = e.clientY - this.interaction.startPoint.y;\n\n this.modifiers = { shift: e.shiftKey, alt: e.altKey };\n\n if (this.dragMode === \"move\") {\n const constrainedMovement = constrainMovementDeltas(\n this.interaction.initialBounds,\n deltaX,\n deltaY,\n { width: this.containerWidth, height: this.containerHeight },\n );\n this.bounds = {\n ...this.interaction.initialBounds,\n x: this.interaction.initialBounds.x + constrainedMovement.deltaX,\n y: this.interaction.initialBounds.y + constrainedMovement.deltaY,\n };\n } else if (this.dragMode === \"resize\" && this.interaction.target.handle) {\n const context: ResizeContext = {\n initialBounds: this.interaction.initialBounds,\n container: { width: this.containerWidth, height: this.containerHeight },\n constraints: {\n minSize: this.minSize,\n aspectRatio: this.modifiers.shift\n ? this.interaction.initialBounds.width /\n this.interaction.initialBounds.height\n : undefined,\n },\n movement: { deltaX, deltaY },\n modifiers: {\n centerResize: this.modifiers.alt,\n preserveAspectRatio: this.modifiers.shift,\n },\n };\n this.bounds = this.calculateBoundsWithModeAwareConstraints(\n context,\n this.interaction.target.handle,\n );\n }\n\n this.dispatchBoundsChange();\n };\n\n private handlePointerUp = (e: PointerEvent) => {\n if (this.interaction && e.pointerId !== this.interaction.pointerId) {\n return;\n }\n e.preventDefault();\n this.isDragging = false;\n this.dragMode = null;\n this.interaction = null;\n document.removeEventListener(\"pointermove\", this.handlePointerMove);\n document.removeEventListener(\"pointerup\", this.handlePointerUp);\n };\n\n private calculateBoundsWithModeAwareConstraints(\n context: ResizeContext,\n handle: ResizeHandle,\n ): BoxBounds {\n const { modifiers, constraints, container, initialBounds } = context;\n\n // For normal resize, use the simple delta constraint approach\n if (!modifiers.centerResize && !modifiers.preserveAspectRatio) {\n const constrainedMovement = this.constrainResizeDeltas(\n initialBounds,\n context.movement.deltaX,\n context.movement.deltaY,\n handle,\n container,\n constraints.minSize,\n );\n\n return calculateNormalResize(\n {\n ...context,\n movement: constrainedMovement,\n },\n handle,\n );\n }\n\n // For modifier-based resizes, calculate ideal bounds then constrain smartly\n let idealBounds: BoxBounds;\n\n if (modifiers.centerResize && modifiers.preserveAspectRatio) {\n idealBounds = calculateCenterResizeWithAspectRatio(context, handle);\n } else if (modifiers.centerResize) {\n idealBounds = calculateCenterResize(context, handle);\n } else {\n idealBounds = calculateAspectRatioResize(context, handle);\n }\n\n // Smart constraint that preserves the resize mode's behavior\n return this.constrainBoundsForMode(idealBounds, context, handle);\n }\n\n private constrainBoundsForMode(\n idealBounds: BoxBounds,\n context: ResizeContext,\n handle: ResizeHandle,\n ): BoxBounds {\n const { container, constraints, modifiers } = context;\n\n // Check if bounds are already valid\n if (this.isValidBounds(idealBounds, container, constraints.minSize)) {\n return idealBounds;\n }\n\n // For combined center + aspect ratio, need special handling\n if (\n modifiers.centerResize &&\n modifiers.preserveAspectRatio &&\n constraints.aspectRatio\n ) {\n return this.constrainCenterResizeWithAspectRatio(idealBounds, context);\n }\n\n // For aspect ratio modes, we need to scale the bounds proportionally\n if (modifiers.preserveAspectRatio && constraints.aspectRatio) {\n return this.constrainWithAspectRatio(idealBounds, context, handle);\n }\n\n // For center resize, we need to adjust from the center\n if (modifiers.centerResize) {\n return this.constrainCenterResize(idealBounds, context);\n }\n\n // Fallback to simple constraint\n return this.simpleConstrainBounds(\n idealBounds,\n container,\n constraints.minSize,\n );\n }\n\n private isValidBounds(\n bounds: BoxBounds,\n container: Dimensions,\n minSize: number,\n ): boolean {\n return (\n bounds.x >= 0 &&\n bounds.y >= 0 &&\n bounds.width >= minSize &&\n bounds.height >= minSize &&\n bounds.x + bounds.width <= container.width &&\n bounds.y + bounds.height <= container.height\n );\n }\n\n private constrainWithAspectRatio(\n idealBounds: BoxBounds,\n context: ResizeContext,\n handle: ResizeHandle,\n ): BoxBounds {\n const { container, constraints, initialBounds } = context;\n if (!constraints.aspectRatio) {\n return initialBounds;\n }\n const aspectRatio = constraints.aspectRatio;\n\n // Calculate maximum allowed dimensions\n const maxWidth = container.width - Math.max(0, idealBounds.x);\n const maxHeight = container.height - Math.max(0, idealBounds.y);\n\n // Find the largest size that fits both constraints\n let constrainedWidth = Math.max(\n constraints.minSize,\n Math.min(maxWidth, idealBounds.width),\n );\n let constrainedHeight = constrainedWidth / aspectRatio;\n\n // If height is too big, constrain by height instead\n if (constrainedHeight > maxHeight) {\n constrainedHeight = Math.max(constraints.minSize, maxHeight);\n constrainedWidth = constrainedHeight * aspectRatio;\n }\n\n // Ensure we don't go smaller than minimum\n if (constrainedWidth < constraints.minSize) {\n constrainedWidth = constraints.minSize;\n constrainedHeight = constrainedWidth / aspectRatio;\n }\n\n const result: BoxBounds = {\n ...idealBounds,\n width: constrainedWidth,\n height: constrainedHeight,\n };\n\n // Adjust position for handles that move the origin\n switch (handle) {\n case \"top-left\":\n result.x = initialBounds.x + initialBounds.width - constrainedWidth;\n result.y = initialBounds.y + initialBounds.height - constrainedHeight;\n break;\n case \"top-right\":\n result.y = initialBounds.y + initialBounds.height - constrainedHeight;\n break;\n case \"bottom-left\":\n result.x = initialBounds.x + initialBounds.width - constrainedWidth;\n break;\n }\n\n // Ensure position is within bounds\n result.x = Math.max(0, Math.min(container.width - result.width, result.x));\n result.y = Math.max(\n 0,\n Math.min(container.height - result.height, result.y),\n );\n\n return result;\n }\n\n private constrainCenterResize(\n idealBounds: BoxBounds,\n context: ResizeContext,\n ): BoxBounds {\n const { container, constraints, initialBounds } = context;\n\n const centerX = initialBounds.x + initialBounds.width / 2;\n const centerY = initialBounds.y + initialBounds.height / 2;\n\n // Calculate maximum dimensions from center\n const maxWidthFromCenter = Math.min(\n centerX * 2,\n (container.width - centerX) * 2,\n );\n const maxHeightFromCenter = Math.min(\n centerY * 2,\n (container.height - centerY) * 2,\n );\n\n const constrainedWidth = Math.max(\n constraints.minSize,\n Math.min(maxWidthFromCenter, idealBounds.width),\n );\n const constrainedHeight = Math.max(\n constraints.minSize,\n Math.min(maxHeightFromCenter, idealBounds.height),\n );\n\n return {\n x: centerX - constrainedWidth / 2,\n y: centerY - constrainedHeight / 2,\n width: constrainedWidth,\n height: constrainedHeight,\n };\n }\n\n private constrainCenterResizeWithAspectRatio(\n idealBounds: BoxBounds,\n context: ResizeContext,\n ): BoxBounds {\n const { container, constraints, initialBounds } = context;\n if (!constraints.aspectRatio) {\n return initialBounds;\n }\n const aspectRatio = constraints.aspectRatio;\n\n const centerX = initialBounds.x + initialBounds.width / 2;\n const centerY = initialBounds.y + initialBounds.height / 2;\n\n // Calculate maximum dimensions from center while maintaining aspect ratio\n const maxWidthFromCenter = Math.min(\n centerX * 2,\n (container.width - centerX) * 2,\n );\n const maxHeightFromCenter = Math.min(\n centerY * 2,\n (container.height - centerY) * 2,\n );\n\n // Start with the ideal width, then constrain\n let constrainedWidth = Math.max(\n constraints.minSize,\n Math.min(maxWidthFromCenter, idealBounds.width),\n );\n let constrainedHeight = constrainedWidth / aspectRatio;\n\n // If height doesn't fit, constrain by height instead\n if (constrainedHeight > maxHeightFromCenter) {\n constrainedHeight = Math.max(constraints.minSize, maxHeightFromCenter);\n constrainedWidth = constrainedHeight * aspectRatio;\n }\n\n // Ensure minimum size\n if (constrainedWidth < constraints.minSize) {\n constrainedWidth = constraints.minSize;\n constrainedHeight = constrainedWidth / aspectRatio;\n }\n\n if (constrainedHeight < constraints.minSize) {\n constrainedHeight = constraints.minSize;\n constrainedWidth = constrainedHeight * aspectRatio;\n }\n\n return {\n x: centerX - constrainedWidth / 2,\n y: centerY - constrainedHeight / 2,\n width: constrainedWidth,\n height: constrainedHeight,\n };\n }\n\n private simpleConstrainBounds(\n bounds: BoxBounds,\n container: Dimensions,\n minSize: number,\n ): BoxBounds {\n return {\n x: Math.max(0, Math.min(container.width - bounds.width, bounds.x)),\n y: Math.max(0, Math.min(container.height - bounds.height, bounds.y)),\n width: Math.max(\n minSize,\n Math.min(container.width - bounds.x, bounds.width),\n ),\n height: Math.max(\n minSize,\n Math.min(container.height - bounds.y, bounds.height),\n ),\n };\n }\n\n private constrainResizeDeltas(\n initialBounds: BoxBounds,\n deltaX: number,\n deltaY: number,\n handle: ResizeHandle,\n container: Dimensions,\n minSize: number,\n ): { deltaX: number; deltaY: number } {\n let constrainedDeltaX = deltaX;\n let constrainedDeltaY = deltaY;\n\n switch (handle) {\n case \"bottom-right\":\n // Can't make smaller than minSize, can't go beyond container\n constrainedDeltaX = Math.max(\n minSize - initialBounds.width,\n Math.min(\n container.width - initialBounds.x - initialBounds.width,\n deltaX,\n ),\n );\n constrainedDeltaY = Math.max(\n minSize - initialBounds.height,\n Math.min(\n container.height - initialBounds.y - initialBounds.height,\n deltaY,\n ),\n );\n break;\n\n case \"top-left\":\n // Can't make smaller than minSize, can't go beyond 0\n constrainedDeltaX = Math.max(\n -initialBounds.x,\n Math.min(initialBounds.width - minSize, deltaX),\n );\n constrainedDeltaY = Math.max(\n -initialBounds.y,\n Math.min(initialBounds.height - minSize, deltaY),\n );\n break;\n\n case \"top-right\":\n constrainedDeltaX = Math.max(\n minSize - initialBounds.width,\n Math.min(\n container.width - initialBounds.x - initialBounds.width,\n deltaX,\n ),\n );\n constrainedDeltaY = Math.max(\n -initialBounds.y,\n Math.min(initialBounds.height - minSize, deltaY),\n );\n break;\n\n case \"bottom-left\":\n constrainedDeltaX = Math.max(\n -initialBounds.x,\n Math.min(initialBounds.width - minSize, deltaX),\n );\n constrainedDeltaY = Math.max(\n minSize - initialBounds.height,\n Math.min(\n container.height - initialBounds.y - initialBounds.height,\n deltaY,\n ),\n );\n break;\n\n case \"right\":\n constrainedDeltaX = Math.max(\n minSize - initialBounds.width,\n Math.min(\n container.width - initialBounds.x - initialBounds.width,\n deltaX,\n ),\n );\n break;\n\n case \"left\":\n constrainedDeltaX = Math.max(\n -initialBounds.x,\n Math.min(initialBounds.width - minSize, deltaX),\n );\n break;\n\n case \"bottom\":\n constrainedDeltaY = Math.max(\n minSize - initialBounds.height,\n Math.min(\n container.height - initialBounds.y - initialBounds.height,\n deltaY,\n ),\n );\n break;\n\n case \"top\":\n constrainedDeltaY = Math.max(\n -initialBounds.y,\n Math.min(initialBounds.height - minSize, deltaY),\n );\n break;\n }\n\n return { deltaX: constrainedDeltaX, deltaY: constrainedDeltaY };\n }\n\n private dispatchBoundsChange() {\n this.dispatchEvent(\n new CustomEvent(\"bounds-change\", {\n detail: { bounds: this.bounds },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render() {\n const boxStyles = {\n left: `${this.bounds.x}px`,\n top: `${this.bounds.y}px`,\n width: `${this.bounds.width}px`,\n height: `${this.bounds.height}px`,\n };\n\n return html`\n <div\n class=\"box ${this.isDragging ? \"dragging\" : \"\"}\"\n style=${styleMap(boxStyles)}\n @pointerdown=${(e: PointerEvent) => this.handlePointerDown(e, \"move\")}\n >\n ${this.renderHandles()}\n <slot></slot>\n </div>\n `;\n }\n\n private renderHandles() {\n const handles: ResizeHandle[] = [\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n ];\n return handles.map(\n (handle) => html`\n <div\n class=\"handle ${handle}\"\n @pointerdown=${(e: PointerEvent) => this.handlePointerDown(e, \"resize\", handle)}\n ></div>\n `,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EFResizableBox.js","names":["EFResizableBox"],"sources":["../../src/gui/EFResizableBox.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { getCornerPoint, getOppositeCorner } from \"./transformUtils.js\";\n\nconst DEFAULT_MIN_SIZE = 10;\n\nexport interface BoxBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ntype ResizeHandle = \"nw\" | \"n\" | \"ne\" | \"e\" | \"se\" | \"s\" | \"sw\" | \"w\";\n\nfunction mapHandleToLegacy(handle: ResizeHandle): string {\n const map: Record<ResizeHandle, string> = {\n nw: \"top-left\",\n n: \"top\",\n ne: \"top-right\",\n e: \"right\",\n se: \"bottom-right\",\n s: \"bottom\",\n sw: \"bottom-left\",\n w: \"left\",\n };\n return map[handle];\n}\n\n@customElement(\"ef-resizable-box\")\nexport class EFResizableBox extends LitElement {\n @property({ type: Object })\n bounds: BoxBounds = { x: 0, y: 0, width: 100, height: 100 };\n\n @state()\n private containerWidth = 0;\n\n @state()\n private containerHeight = 0;\n\n @property({ type: Number })\n minSize = DEFAULT_MIN_SIZE;\n\n @state()\n private isDragging = false;\n\n @state()\n private isResizing: ResizeHandle | null = null;\n\n private dragStart: { x: number; y: number } | null = null;\n private dragStartPosition: { x: number; y: number } = { x: 0, y: 0 };\n private resizeStartCorner: { x: number; y: number } | null = null;\n private resizeStartSize: { width: number; height: number } | null = null;\n private resizeStartPosition: { x: number; y: number } | null = null;\n\n static styles = css`\n .box {\n position: absolute;\n border: 2px solid var(--ef-resizable-box-border-color, #3b82f6);\n background-color: var(--ef-resizable-box-bg-color, rgba(59, 130, 246, 0.2));\n cursor: grab;\n }\n .box.dragging {\n border-color: var(--ef-resizable-box-dragging-border-color, #2563eb);\n background-color: var(--ef-resizable-box-dragging-bg-color, rgba(37, 99, 235, 0.3));\n }\n .handle {\n position: absolute;\n background-color: var(--ef-resizable-box-handle-color, #3b82f6);\n touch-action: none;\n }\n .handle.nw { top: -4px; left: -4px; width: 8px; height: 8px; cursor: nwse-resize; }\n .handle.ne { top: -4px; right: -4px; width: 8px; height: 8px; cursor: nesw-resize; }\n .handle.sw { bottom: -4px; left: -4px; width: 8px; height: 8px; cursor: nesw-resize; }\n .handle.se { bottom: -4px; right: -4px; width: 8px; height: 8px; cursor: nwse-resize; }\n .handle.n { top: -4px; left: 4px; right: 4px; height: 8px; cursor: ns-resize; }\n .handle.e { top: 4px; bottom: 4px; right: -4px; width: 8px; cursor: ew-resize; }\n .handle.s { bottom: -4px; left: 4px; right: 4px; height: 8px; cursor: ns-resize; }\n .handle.w { top: 4px; bottom: 4px; left: -4px; width: 8px; cursor: ew-resize; }\n `;\n\n private resizeObserver?: ResizeObserver;\n\n connectedCallback() {\n super.connectedCallback();\n if (this.offsetParent) {\n this.containerWidth = this.offsetParent.clientWidth;\n this.containerHeight = this.offsetParent.clientHeight;\n }\n this.resizeObserver = new ResizeObserver(() => {\n if (this.offsetParent) {\n this.containerWidth = this.offsetParent.clientWidth;\n this.containerHeight = this.offsetParent.clientHeight;\n }\n });\n if (this.offsetParent) {\n this.resizeObserver.observe(this.offsetParent);\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.cleanup();\n }\n\n private handlePointerDown = (\n e: PointerEvent,\n mode: \"move\" | \"resize\",\n handle?: ResizeHandle,\n ) => {\n e.preventDefault();\n e.stopPropagation();\n this.isDragging = true;\n this.isResizing = mode === \"resize\" ? handle || null : null;\n\n this.dragStart = { x: e.clientX, y: e.clientY };\n this.dragStartPosition = { x: this.bounds.x, y: this.bounds.y };\n\n if (mode === \"resize\" && handle) {\n const oppositeCorner = getOppositeCorner(handle);\n const rotationRadians = 0;\n const initialCorner = getCornerPoint(\n this.bounds.x,\n this.bounds.y,\n this.bounds.width,\n this.bounds.height,\n rotationRadians,\n oppositeCorner.x,\n oppositeCorner.y,\n );\n this.resizeStartCorner = initialCorner;\n this.resizeStartSize = {\n width: this.bounds.width,\n height: this.bounds.height,\n };\n this.resizeStartPosition = { x: this.bounds.x, y: this.bounds.y };\n }\n\n document.addEventListener(\"pointermove\", this.handlePointerMove, {\n passive: false,\n });\n document.addEventListener(\"pointerup\", this.handlePointerUp, {\n passive: false,\n });\n };\n\n private handlePointerMove = (e: PointerEvent) => {\n if (!this.isDragging || !this.dragStart) return;\n\n e.preventDefault();\n\n const deltaX = e.clientX - this.dragStart.x;\n const deltaY = e.clientY - this.dragStart.y;\n\n if (\n this.isResizing &&\n this.resizeStartCorner &&\n this.resizeStartSize &&\n this.resizeStartPosition\n ) {\n const oppositeCorner = getOppositeCorner(this.isResizing);\n const rotationRadians = 0;\n\n let newWidth = this.resizeStartSize.width;\n let newHeight = this.resizeStartSize.height;\n\n if (this.isResizing.includes(\"e\")) {\n newWidth = this.resizeStartSize.width + deltaX;\n } else if (this.isResizing.includes(\"w\")) {\n newWidth = this.resizeStartSize.width - deltaX;\n }\n\n if (this.isResizing.includes(\"s\")) {\n newHeight = this.resizeStartSize.height + deltaY;\n } else if (this.isResizing.includes(\"n\")) {\n newHeight = this.resizeStartSize.height - deltaY;\n }\n\n newWidth = Math.max(\n this.minSize,\n Math.min(this.containerWidth - this.bounds.x, newWidth),\n );\n newHeight = Math.max(\n this.minSize,\n Math.min(this.containerHeight - this.bounds.y, newHeight),\n );\n\n const newOppositeCorner = getCornerPoint(\n this.resizeStartPosition.x,\n this.resizeStartPosition.y,\n newWidth,\n newHeight,\n rotationRadians,\n oppositeCorner.x,\n oppositeCorner.y,\n );\n\n const offsetX = this.resizeStartCorner.x - newOppositeCorner.x;\n const offsetY = this.resizeStartCorner.y - newOppositeCorner.y;\n\n const newX = Math.max(\n 0,\n Math.min(\n this.containerWidth - newWidth,\n this.resizeStartPosition.x + offsetX,\n ),\n );\n const newY = Math.max(\n 0,\n Math.min(\n this.containerHeight - newHeight,\n this.resizeStartPosition.y + offsetY,\n ),\n );\n\n this.bounds = {\n x: newX,\n y: newY,\n width: newWidth,\n height: newHeight,\n };\n } else {\n const constrainedX = Math.max(\n 0,\n Math.min(\n this.containerWidth - this.bounds.width,\n this.dragStartPosition.x + deltaX,\n ),\n );\n const constrainedY = Math.max(\n 0,\n Math.min(\n this.containerHeight - this.bounds.height,\n this.dragStartPosition.y + deltaY,\n ),\n );\n\n this.bounds = {\n ...this.bounds,\n x: constrainedX,\n y: constrainedY,\n };\n }\n\n this.dispatchBoundsChange();\n };\n\n private handlePointerUp = (e: PointerEvent) => {\n e.preventDefault();\n this.cleanup();\n };\n\n private cleanup() {\n this.isDragging = false;\n this.isResizing = null;\n this.dragStart = null;\n this.dragStartPosition = { x: 0, y: 0 };\n this.resizeStartCorner = null;\n this.resizeStartSize = null;\n this.resizeStartPosition = null;\n document.removeEventListener(\"pointermove\", this.handlePointerMove);\n document.removeEventListener(\"pointerup\", this.handlePointerUp);\n }\n\n private dispatchBoundsChange() {\n this.dispatchEvent(\n new CustomEvent(\"bounds-change\", {\n detail: { bounds: this.bounds },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render() {\n const boxStyles = {\n left: `${this.bounds.x}px`,\n top: `${this.bounds.y}px`,\n width: `${this.bounds.width}px`,\n height: `${this.bounds.height}px`,\n };\n\n const handles: ResizeHandle[] = [\n \"nw\",\n \"n\",\n \"ne\",\n \"e\",\n \"se\",\n \"s\",\n \"sw\",\n \"w\",\n ];\n\n return html`\n <div\n class=\"box ${this.isDragging ? \"dragging\" : \"\"}\"\n style=${styleMap(boxStyles)}\n @pointerdown=${(e: PointerEvent) => this.handlePointerDown(e, \"move\")}\n >\n ${handles.map(\n (handle) => html`\n <div\n class=\"handle ${handle}\"\n @pointerdown=${(e: PointerEvent) => {\n e.stopPropagation();\n this.handlePointerDown(e, \"resize\", handle);\n }}\n ></div>\n `,\n )}\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit20 from "lit";
2
+ import * as lit22 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html18 from "lit-html";
4
+ import * as lit_html22 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFScrubber.d.ts
7
7
  declare const EFScrubber_base: (new (...args: any[]) => {
@@ -10,14 +10,39 @@ declare const EFScrubber_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFScrubber extends EFScrubber_base {
13
- static styles: lit20.CSSResult[];
13
+ static styles: lit22.CSSResult[];
14
14
  playing: boolean;
15
+ contextCurrentTimeMs: number;
16
+ contextDurationMs: number;
17
+ orientation: "horizontal" | "vertical";
15
18
  currentTimeMs: number;
16
19
  durationMs: number;
20
+ zoomScale: number;
21
+ containerWidth: number;
22
+ fps?: number;
23
+ rawScrubTimeMs?: number | null;
24
+ scrollContainerRef?: {
25
+ current: HTMLElement | null;
26
+ };
27
+ /**
28
+ * Reference to the element that represents the actual track content area.
29
+ * Used to calculate the offset between the scroll container and where tracks begin.
30
+ */
31
+ trackContentRef?: {
32
+ current: HTMLElement | null;
33
+ };
34
+ onSeek?: (time: number) => void;
35
+ isScrubbingRef?: {
36
+ current: boolean;
37
+ };
17
38
  get context(): ControllableInterface | null;
39
+ get effectiveCurrentTimeMs(): number;
40
+ get effectiveDurationMs(): number;
41
+ get isTimelineMode(): boolean;
18
42
  private scrubProgress;
19
43
  private isMoving;
20
- private scrubberRef?;
44
+ private scrubberRef;
45
+ private _scrubberElement?;
21
46
  private capturedPointerId;
22
47
  private updateProgress;
23
48
  private handlePointerDown;
@@ -25,7 +50,7 @@ declare class EFScrubber extends EFScrubber_base {
25
50
  private boundHandlePointerUp;
26
51
  private boundHandlePointerCancel;
27
52
  private boundHandleContextMenu;
28
- render(): lit_html18.TemplateResult<1>;
53
+ render(): lit_html22.TemplateResult<1>;
29
54
  connectedCallback(): void;
30
55
  disconnectedCallback(): void;
31
56
  }
@@ -3,21 +3,38 @@ import { durationContext } from "./durationContext.js";
3
3
  import { playingContext } from "./playingContext.js";
4
4
  import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
5
5
  import { efContext } from "./efContext.js";
6
+ import { quantizeToFrameTimeMs } from "./EFTimelineRuler.js";
6
7
  import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
7
8
  import { consume } from "@lit/context";
8
9
  import { LitElement, css, html } from "lit";
9
- import { customElement, eventOptions, state } from "lit/decorators.js";
10
- import { ref } from "lit/directives/ref.js";
10
+ import { customElement, eventOptions, property, state } from "lit/decorators.js";
11
+ import { createRef, ref } from "lit/directives/ref.js";
11
12
 
12
13
  //#region src/gui/EFScrubber.ts
14
+ const BASE_PIXELS_PER_SECOND = 100;
15
+ function timeToPixels(timeMs, durationMs, containerWidth, zoomScale) {
16
+ if (durationMs <= 0) return 0;
17
+ const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;
18
+ return timeMs / 1e3 * pixelsPerSecond;
19
+ }
20
+ function pixelsToTime(pixels, durationMs, containerWidth, zoomScale) {
21
+ if (durationMs <= 0) return 0;
22
+ return pixels / (BASE_PIXELS_PER_SECOND * zoomScale) * 1e3;
23
+ }
13
24
  let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efContext) {
14
25
  constructor(..._args) {
15
26
  super(..._args);
16
27
  this.playing = false;
28
+ this.contextCurrentTimeMs = NaN;
29
+ this.contextDurationMs = 0;
30
+ this.orientation = "horizontal";
17
31
  this.currentTimeMs = NaN;
18
32
  this.durationMs = 0;
33
+ this.zoomScale = 1;
34
+ this.containerWidth = 0;
19
35
  this.scrubProgress = 0;
20
36
  this.isMoving = false;
37
+ this.scrubberRef = createRef();
21
38
  this.capturedPointerId = null;
22
39
  this.boundHandlePointerMove = (e) => {
23
40
  if (this.isMoving && e.pointerId === this.capturedPointerId) {
@@ -27,23 +44,27 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
27
44
  }
28
45
  };
29
46
  this.boundHandlePointerUp = (e) => {
30
- if (e.pointerId === this.capturedPointerId && this.scrubberRef) {
47
+ const scrubberEl = this.scrubberRef.value || this._scrubberElement;
48
+ if (e.pointerId === this.capturedPointerId && scrubberEl) {
31
49
  e.preventDefault();
32
50
  e.stopPropagation();
33
51
  try {
34
- this.scrubberRef.releasePointerCapture(e.pointerId);
52
+ scrubberEl.releasePointerCapture(e.pointerId);
35
53
  } catch (_err) {}
36
54
  this.capturedPointerId = null;
37
55
  this.isMoving = false;
56
+ if (this.isScrubbingRef) this.isScrubbingRef.current = false;
38
57
  }
39
58
  };
40
59
  this.boundHandlePointerCancel = (e) => {
41
- if (e.pointerId === this.capturedPointerId && this.scrubberRef) {
60
+ const scrubberEl = this.scrubberRef.value || this._scrubberElement;
61
+ if (e.pointerId === this.capturedPointerId && scrubberEl) {
42
62
  try {
43
- this.scrubberRef.releasePointerCapture(e.pointerId);
63
+ scrubberEl.releasePointerCapture(e.pointerId);
44
64
  } catch (_err) {}
45
65
  this.capturedPointerId = null;
46
66
  this.isMoving = false;
67
+ if (this.isScrubbingRef) this.isScrubbingRef.current = false;
47
68
  }
48
69
  };
49
70
  this.boundHandleContextMenu = (e) => {
@@ -71,6 +92,14 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
71
92
  --ef-scrubber-progress-color: rgb(96 165 250);
72
93
  }
73
94
 
95
+ :host([orientation="vertical"]) {
96
+ width: 100%;
97
+ height: 100%;
98
+ position: absolute;
99
+ inset: 0;
100
+ pointer-events: auto;
101
+ }
102
+
74
103
  .scrubber {
75
104
  width: 100%;
76
105
  height: var(--ef-scrubber-height);
@@ -82,6 +111,13 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
82
111
  user-select: none;
83
112
  }
84
113
 
114
+ :host([orientation="vertical"]) .scrubber {
115
+ width: 100%;
116
+ height: 100%;
117
+ background: transparent;
118
+ cursor: ew-resize;
119
+ }
120
+
85
121
  .progress {
86
122
  position: absolute;
87
123
  height: 100%;
@@ -89,6 +125,10 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
89
125
  border-radius: 2px;
90
126
  }
91
127
 
128
+ :host([orientation="vertical"]) .progress {
129
+ display: none;
130
+ }
131
+
92
132
  .handle {
93
133
  position: absolute;
94
134
  width: var(--ef-scrubber-handle-size);
@@ -100,6 +140,46 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
100
140
  cursor: grab;
101
141
  }
102
142
 
143
+ :host([orientation="vertical"]) .handle {
144
+ display: none;
145
+ }
146
+
147
+ .playhead {
148
+ position: absolute;
149
+ top: 0;
150
+ bottom: 0;
151
+ width: 2px;
152
+ background: var(--ef-scrubber-progress-color);
153
+ pointer-events: auto;
154
+ cursor: ew-resize;
155
+ z-index: 30;
156
+ }
157
+
158
+ ::part(playhead) {
159
+ z-index: 30;
160
+ }
161
+
162
+ .playhead-handle {
163
+ position: absolute;
164
+ top: 0;
165
+ left: 50%;
166
+ transform: translate(-50%, -50%);
167
+ width: 12px;
168
+ height: 12px;
169
+ background: var(--ef-scrubber-progress-color);
170
+ border-radius: 50%;
171
+ }
172
+
173
+ .raw-preview {
174
+ position: absolute;
175
+ top: 0;
176
+ bottom: 0;
177
+ width: 2px;
178
+ background: rgba(37, 99, 235, 0.2);
179
+ pointer-events: none;
180
+ z-index: 20;
181
+ }
182
+
103
183
  /* Add CSS Shadow Parts */
104
184
  ::part(scrubber) { }
105
185
  ::part(progress) { }
@@ -109,44 +189,125 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
109
189
  get context() {
110
190
  return this.effectiveContext;
111
191
  }
192
+ get effectiveCurrentTimeMs() {
193
+ if (!Number.isNaN(this.currentTimeMs)) return this.currentTimeMs;
194
+ if (!Number.isNaN(this.contextCurrentTimeMs)) return this.contextCurrentTimeMs;
195
+ return 0;
196
+ }
197
+ get effectiveDurationMs() {
198
+ return this.durationMs || this.contextDurationMs || 0;
199
+ }
200
+ get isTimelineMode() {
201
+ return this.orientation === "vertical" && this.zoomScale > 0;
202
+ }
112
203
  updateProgress(e) {
113
- if (!this.context || !this.scrubberRef) return;
114
- const rect = this.scrubberRef.getBoundingClientRect();
115
- const x = e.clientX - rect.left;
116
- const progress = Math.max(0, Math.min(1, x / rect.width));
117
- this.scrubProgress = progress;
118
- this.context.currentTimeMs = progress * this.durationMs;
204
+ const scrubberEl = this.scrubberRef.value || this._scrubberElement;
205
+ if (!scrubberEl) return;
206
+ const duration = this.effectiveDurationMs;
207
+ if (duration <= 0) return;
208
+ if (this.isTimelineMode) {
209
+ const scrollContainer = this.scrollContainerRef?.current || scrubberEl.parentElement;
210
+ if (!scrollContainer) return;
211
+ const scrollContainerRect = scrollContainer.getBoundingClientRect();
212
+ const scrollLeft = scrollContainer.scrollLeft || 0;
213
+ let pixelOffset = 0;
214
+ if (this.trackContentRef?.current) pixelOffset = this.trackContentRef.current.getBoundingClientRect().left - scrollContainerRect.left + scrollContainer.scrollLeft;
215
+ const pixelPosition = scrollLeft + (e.clientX - scrollContainerRect.left - pixelOffset);
216
+ const effectiveWidth = this.containerWidth > 0 ? this.containerWidth : scrollContainerRect.width;
217
+ if (effectiveWidth <= 0) return;
218
+ let rawTime = pixelsToTime(pixelPosition, duration, effectiveWidth, this.zoomScale);
219
+ rawTime = Math.max(0, Math.min(rawTime, duration));
220
+ let quantizedTime = this.fps && this.fps > 0 ? quantizeToFrameTimeMs(rawTime, this.fps) : rawTime;
221
+ quantizedTime = Math.max(0, Math.min(quantizedTime, duration));
222
+ this.scrubProgress = quantizedTime / duration;
223
+ if (this.onSeek) this.onSeek(quantizedTime);
224
+ else {
225
+ this.dispatchEvent(new CustomEvent("seek", {
226
+ detail: quantizedTime,
227
+ bubbles: true,
228
+ composed: true
229
+ }));
230
+ if (this.context) this.context.currentTimeMs = quantizedTime;
231
+ }
232
+ } else {
233
+ const rect = scrubberEl.getBoundingClientRect();
234
+ const x = e.clientX - rect.left;
235
+ const progress = Math.max(0, Math.min(1, x / rect.width));
236
+ this.scrubProgress = progress;
237
+ const timeMs = progress * duration;
238
+ if (this.onSeek) this.onSeek(timeMs);
239
+ else {
240
+ this.dispatchEvent(new CustomEvent("seek", {
241
+ detail: timeMs,
242
+ bubbles: true,
243
+ composed: true
244
+ }));
245
+ if (this.context) this.context.currentTimeMs = timeMs;
246
+ }
247
+ }
119
248
  }
120
249
  handlePointerDown(e) {
121
- if (!this.scrubberRef) return;
250
+ const scrubberEl = this.scrubberRef.value || this._scrubberElement;
251
+ if (!scrubberEl) return;
122
252
  this.isMoving = true;
253
+ if (this.isScrubbingRef) this.isScrubbingRef.current = true;
123
254
  e.preventDefault();
124
255
  e.stopPropagation();
125
256
  this.capturedPointerId = e.pointerId;
126
257
  try {
127
- this.scrubberRef.setPointerCapture(e.pointerId);
258
+ scrubberEl.setPointerCapture(e.pointerId);
128
259
  } catch (err) {
129
260
  console.warn("Failed to set pointer capture:", err);
130
261
  }
131
262
  this.updateProgress(e);
132
263
  }
133
264
  render() {
134
- const currentProgress = this.durationMs > 0 ? (this.currentTimeMs ?? 0) / this.durationMs : 0;
135
- const displayProgress = this.isMoving ? this.scrubProgress : currentProgress;
136
- return html`
137
- <div
138
- ${ref((el) => {
139
- this.scrubberRef = el;
140
- })}
141
- part="scrubber"
142
- class="scrubber"
143
- @pointerdown=${this.handlePointerDown}
144
- @contextmenu=${this.boundHandleContextMenu}
145
- >
146
- <div class="progress" style="width: ${displayProgress * 100}%"></div>
147
- <div class="handle" style="left: ${displayProgress * 100}%"></div>
148
- </div>
149
- `;
265
+ const duration = this.effectiveDurationMs;
266
+ const currentTime = this.effectiveCurrentTimeMs;
267
+ if (duration <= 0) return html``;
268
+ if (this.isTimelineMode) {
269
+ const scrubberEl = this.scrubberRef.value || this._scrubberElement;
270
+ const effectiveWidth = this.containerWidth > 0 ? this.containerWidth : scrubberEl?.parentElement?.getBoundingClientRect().width || 0;
271
+ const positionPixels = effectiveWidth > 0 ? timeToPixels(currentTime, duration, effectiveWidth, this.zoomScale) : 0;
272
+ const rawScrubPositionPixels = this.rawScrubTimeMs !== null && this.rawScrubTimeMs !== void 0 && effectiveWidth > 0 ? timeToPixels(this.rawScrubTimeMs, duration, effectiveWidth, this.zoomScale) : null;
273
+ return html`
274
+ ${rawScrubPositionPixels !== null && rawScrubPositionPixels !== positionPixels ? html`<div
275
+ class="raw-preview"
276
+ style="left: ${rawScrubPositionPixels}px"
277
+ ></div>` : html``}
278
+ <div
279
+ ${ref(this.scrubberRef)}
280
+ part="scrubber"
281
+ class="scrubber"
282
+ @pointerdown=${this.handlePointerDown}
283
+ @contextmenu=${this.boundHandleContextMenu}
284
+ >
285
+ <div
286
+ part="playhead"
287
+ class="playhead"
288
+ style="left: ${positionPixels}px"
289
+ @pointerdown=${this.handlePointerDown}
290
+ >
291
+ <div class="playhead-handle"></div>
292
+ </div>
293
+ </div>
294
+ `;
295
+ } else {
296
+ const currentProgress = duration > 0 ? currentTime / duration : 0;
297
+ const displayProgress = this.isMoving ? this.scrubProgress : currentProgress;
298
+ return html`
299
+ <div
300
+ ${ref(this.scrubberRef)}
301
+ part="scrubber"
302
+ class="scrubber"
303
+ @pointerdown=${this.handlePointerDown}
304
+ @contextmenu=${this.boundHandleContextMenu}
305
+ >
306
+ <div class="progress" style="width: ${displayProgress * 100}%"></div>
307
+ <div class="handle" style="left: ${displayProgress * 100}%"></div>
308
+ </div>
309
+ `;
310
+ }
150
311
  }
151
312
  connectedCallback() {
152
313
  super.connectedCallback();
@@ -170,11 +331,43 @@ __decorate([consume({
170
331
  __decorate([consume({
171
332
  context: currentTimeContext,
172
333
  subscribe: true
173
- })], EFScrubber.prototype, "currentTimeMs", void 0);
334
+ })], EFScrubber.prototype, "contextCurrentTimeMs", void 0);
174
335
  __decorate([consume({
175
336
  context: durationContext,
176
337
  subscribe: true
338
+ })], EFScrubber.prototype, "contextDurationMs", void 0);
339
+ __decorate([property({
340
+ type: String,
341
+ attribute: "orientation"
342
+ })], EFScrubber.prototype, "orientation", void 0);
343
+ __decorate([property({
344
+ type: Number,
345
+ attribute: "current-time-ms"
346
+ })], EFScrubber.prototype, "currentTimeMs", void 0);
347
+ __decorate([property({
348
+ type: Number,
349
+ attribute: "duration-ms"
177
350
  })], EFScrubber.prototype, "durationMs", void 0);
351
+ __decorate([property({
352
+ type: Number,
353
+ attribute: "zoom-scale"
354
+ })], EFScrubber.prototype, "zoomScale", void 0);
355
+ __decorate([property({
356
+ type: Number,
357
+ attribute: "container-width"
358
+ })], EFScrubber.prototype, "containerWidth", void 0);
359
+ __decorate([property({
360
+ type: Number,
361
+ attribute: "fps"
362
+ })], EFScrubber.prototype, "fps", void 0);
363
+ __decorate([property({
364
+ type: Number,
365
+ attribute: "raw-scrub-time-ms"
366
+ })], EFScrubber.prototype, "rawScrubTimeMs", void 0);
367
+ __decorate([property({ attribute: false })], EFScrubber.prototype, "scrollContainerRef", void 0);
368
+ __decorate([property({ attribute: false })], EFScrubber.prototype, "trackContentRef", void 0);
369
+ __decorate([property({ attribute: false })], EFScrubber.prototype, "onSeek", void 0);
370
+ __decorate([property({ attribute: false })], EFScrubber.prototype, "isScrubbingRef", void 0);
178
371
  __decorate([state()], EFScrubber.prototype, "scrubProgress", void 0);
179
372
  __decorate([state()], EFScrubber.prototype, "isMoving", void 0);
180
373
  __decorate([eventOptions({
@@ -1 +1 @@
1
- {"version":3,"file":"EFScrubber.js","names":["EFScrubber"],"sources":["../../src/gui/EFScrubber.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, eventOptions, state } from \"lit/decorators.js\";\n\nimport { ref } from \"lit/directives/ref.js\";\nimport type { ControllableInterface } from \"./Controllable.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { playingContext } from \"./playingContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\n\n@customElement(\"ef-scrubber\")\nexport class EFScrubber extends TargetOrContextMixin(LitElement, efContext) {\n static styles = [\n css`\n :host {\n --ef-scrubber-height: 4px;\n --ef-scrubber-background: rgb(209 213 219);\n --ef-scrubber-progress-color: rgb(37 99 235);\n --ef-scrubber-handle-size: 12px;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n :host(.dark), :host-context(.dark) {\n --ef-scrubber-background: rgb(75 85 99);\n --ef-scrubber-progress-color: rgb(96 165 250);\n }\n \n .scrubber {\n width: 100%;\n height: var(--ef-scrubber-height);\n background: var(--ef-scrubber-background);\n position: relative;\n cursor: pointer;\n border-radius: 2px;\n touch-action: none;\n user-select: none;\n }\n\n .progress {\n position: absolute;\n height: 100%;\n background: var(--ef-scrubber-progress-color);\n border-radius: 2px;\n }\n\n .handle {\n position: absolute;\n width: var(--ef-scrubber-handle-size);\n height: var(--ef-scrubber-handle-size);\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n }\n\n /* Add CSS Shadow Parts */\n ::part(scrubber) { }\n ::part(progress) { }\n ::part(handle) { }\n `,\n ];\n\n @consume({ context: playingContext, subscribe: true })\n playing = false;\n\n @consume({ context: currentTimeContext, subscribe: true })\n currentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n durationMs = 0;\n\n get context(): ControllableInterface | null {\n return this.effectiveContext;\n }\n\n @state()\n private scrubProgress = 0;\n\n @state()\n private isMoving = false;\n\n private scrubberRef?: HTMLElement;\n private capturedPointerId: number | null = null;\n\n private updateProgress(e: PointerEvent) {\n if (!this.context || !this.scrubberRef) return;\n\n const rect = this.scrubberRef.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const progress = Math.max(0, Math.min(1, x / rect.width));\n\n this.scrubProgress = progress;\n this.context.currentTimeMs = progress * this.durationMs;\n }\n\n @eventOptions({ passive: false, capture: false })\n private handlePointerDown(e: PointerEvent) {\n if (!this.scrubberRef) return;\n\n this.isMoving = true;\n e.preventDefault();\n e.stopPropagation();\n this.capturedPointerId = e.pointerId;\n try {\n this.scrubberRef.setPointerCapture(e.pointerId);\n } catch (err) {\n // setPointerCapture may fail in some cases, continue anyway\n console.warn(\"Failed to set pointer capture:\", err);\n }\n this.updateProgress(e);\n }\n\n private boundHandlePointerMove = (e: PointerEvent) => {\n if (this.isMoving && e.pointerId === this.capturedPointerId) {\n e.preventDefault();\n e.stopPropagation();\n this.updateProgress(e);\n }\n };\n\n private boundHandlePointerUp = (e: PointerEvent) => {\n if (e.pointerId === this.capturedPointerId && this.scrubberRef) {\n e.preventDefault();\n e.stopPropagation();\n try {\n this.scrubberRef.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n }\n };\n\n private boundHandlePointerCancel = (e: PointerEvent) => {\n if (e.pointerId === this.capturedPointerId && this.scrubberRef) {\n try {\n this.scrubberRef.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n }\n };\n\n private boundHandleContextMenu = (e: Event) => {\n if (this.isMoving) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n render() {\n // Calculate progress from currentTimeMs and duration\n const currentProgress =\n this.durationMs > 0 ? (this.currentTimeMs ?? 0) / this.durationMs : 0;\n\n const displayProgress = this.isMoving\n ? this.scrubProgress\n : currentProgress;\n\n return html`\n <div \n ${ref((el) => {\n this.scrubberRef = el as HTMLElement;\n })}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div class=\"progress\" style=\"width: ${displayProgress * 100}%\"></div>\n <div class=\"handle\" style=\"left: ${displayProgress * 100}%\"></div>\n </div>\n `;\n }\n\n connectedCallback() {\n super.connectedCallback();\n window.addEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n { passive: false },\n );\n window.addEventListener(\"pointermove\", this.boundHandlePointerMove, {\n passive: false,\n });\n window.addEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n { passive: false },\n );\n this.addEventListener(\"contextmenu\", this.boundHandleContextMenu, {\n passive: false,\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n window.removeEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n );\n window.removeEventListener(\"pointermove\", this.boundHandlePointerMove);\n window.removeEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n );\n this.removeEventListener(\"contextmenu\", this.boundHandleContextMenu);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-scrubber\": EFScrubber;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EFScrubber.js","names":["EFScrubber"],"sources":["../../src/gui/EFScrubber.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport {\n customElement,\n eventOptions,\n property,\n state,\n} from \"lit/decorators.js\";\n\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport type { ControllableInterface } from \"./Controllable.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { playingContext } from \"./playingContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\nimport { quantizeToFrameTimeMs } from \"./EFTimelineRuler.js\";\n\nconst BASE_PIXELS_PER_SECOND = 100;\n\nfunction timeToPixels(\n timeMs: number,\n durationMs: number,\n containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (timeMs / 1000) * pixelsPerSecond;\n}\n\nfunction pixelsToTime(\n pixels: number,\n durationMs: number,\n containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (pixels / pixelsPerSecond) * 1000;\n}\n\n@customElement(\"ef-scrubber\")\nexport class EFScrubber extends TargetOrContextMixin(LitElement, efContext) {\n static styles = [\n css`\n :host {\n --ef-scrubber-height: 4px;\n --ef-scrubber-background: rgb(209 213 219);\n --ef-scrubber-progress-color: rgb(37 99 235);\n --ef-scrubber-handle-size: 12px;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n :host(.dark), :host-context(.dark) {\n --ef-scrubber-background: rgb(75 85 99);\n --ef-scrubber-progress-color: rgb(96 165 250);\n }\n \n :host([orientation=\"vertical\"]) {\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n pointer-events: auto;\n }\n\n .scrubber {\n width: 100%;\n height: var(--ef-scrubber-height);\n background: var(--ef-scrubber-background);\n position: relative;\n cursor: pointer;\n border-radius: 2px;\n touch-action: none;\n user-select: none;\n }\n\n :host([orientation=\"vertical\"]) .scrubber {\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: ew-resize;\n }\n\n .progress {\n position: absolute;\n height: 100%;\n background: var(--ef-scrubber-progress-color);\n border-radius: 2px;\n }\n\n :host([orientation=\"vertical\"]) .progress {\n display: none;\n }\n\n .handle {\n position: absolute;\n width: var(--ef-scrubber-handle-size);\n height: var(--ef-scrubber-handle-size);\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n }\n\n :host([orientation=\"vertical\"]) .handle {\n display: none;\n }\n\n .playhead {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--ef-scrubber-progress-color);\n pointer-events: auto;\n cursor: ew-resize;\n z-index: 30;\n }\n\n ::part(playhead) {\n z-index: 30;\n }\n\n .playhead-handle {\n position: absolute;\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 12px;\n height: 12px;\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n }\n\n .raw-preview {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: rgba(37, 99, 235, 0.2);\n pointer-events: none;\n z-index: 20;\n }\n\n /* Add CSS Shadow Parts */\n ::part(scrubber) { }\n ::part(progress) { }\n ::part(handle) { }\n `,\n ];\n\n @consume({ context: playingContext, subscribe: true })\n playing = false;\n\n @consume({ context: currentTimeContext, subscribe: true })\n contextCurrentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n @property({ type: String, attribute: \"orientation\" })\n orientation: \"horizontal\" | \"vertical\" = \"horizontal\";\n\n @property({ type: Number, attribute: \"current-time-ms\" })\n currentTimeMs = Number.NaN;\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @property({ type: Number, attribute: \"zoom-scale\" })\n zoomScale = 1.0;\n\n @property({ type: Number, attribute: \"container-width\" })\n containerWidth = 0;\n\n @property({ type: Number, attribute: \"fps\" })\n fps?: number;\n\n @property({ type: Number, attribute: \"raw-scrub-time-ms\" })\n rawScrubTimeMs?: number | null;\n\n @property({ attribute: false })\n scrollContainerRef?: { current: HTMLElement | null };\n\n /**\n * Reference to the element that represents the actual track content area.\n * Used to calculate the offset between the scroll container and where tracks begin.\n */\n @property({ attribute: false })\n trackContentRef?: { current: HTMLElement | null };\n\n @property({ attribute: false })\n onSeek?: (time: number) => void;\n\n @property({ attribute: false })\n isScrubbingRef?: { current: boolean };\n\n get context(): ControllableInterface | null {\n return this.effectiveContext;\n }\n\n get effectiveCurrentTimeMs(): number {\n if (!Number.isNaN(this.currentTimeMs)) {\n return this.currentTimeMs;\n }\n if (!Number.isNaN(this.contextCurrentTimeMs)) {\n return this.contextCurrentTimeMs;\n }\n return 0;\n }\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n get isTimelineMode(): boolean {\n return this.orientation === \"vertical\" && this.zoomScale > 0;\n }\n\n @state()\n private scrubProgress = 0;\n\n @state()\n private isMoving = false;\n\n private scrubberRef = createRef<HTMLElement>();\n private _scrubberElement?: HTMLElement;\n private capturedPointerId: number | null = null;\n\n private updateProgress(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n const duration = this.effectiveDurationMs;\n if (duration <= 0) return;\n\n if (this.isTimelineMode) {\n // Timeline mode: use pixel-based positioning with zoom\n const scrollContainer =\n this.scrollContainerRef?.current || scrubberEl.parentElement;\n if (!scrollContainer) return;\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const scrollLeft = scrollContainer.scrollLeft || 0;\n\n // Calculate pixel offset dynamically from the track content element\n // This accounts for any hierarchy panel or other elements before the tracks\n let pixelOffset = 0;\n if (this.trackContentRef?.current) {\n const trackRect = this.trackContentRef.current.getBoundingClientRect();\n pixelOffset =\n trackRect.left -\n scrollContainerRect.left +\n scrollContainer.scrollLeft;\n }\n\n const x = e.clientX - scrollContainerRect.left - pixelOffset;\n const pixelPosition = scrollLeft + x;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrollContainerRect.width;\n if (effectiveWidth <= 0) return;\n\n let rawTime = pixelsToTime(\n pixelPosition,\n duration,\n effectiveWidth,\n this.zoomScale,\n );\n rawTime = Math.max(0, Math.min(rawTime, duration));\n\n // Quantize to frame boundaries if FPS is provided, then clamp to duration\n let quantizedTime =\n this.fps && this.fps > 0\n ? quantizeToFrameTimeMs(rawTime, this.fps)\n : rawTime;\n quantizedTime = Math.max(0, Math.min(quantizedTime, duration));\n\n this.scrubProgress = quantizedTime / duration;\n\n if (this.onSeek) {\n this.onSeek(quantizedTime);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: quantizedTime,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = quantizedTime;\n }\n }\n } else {\n // Horizontal mode: simple progress calculation\n const rect = scrubberEl.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const progress = Math.max(0, Math.min(1, x / rect.width));\n\n this.scrubProgress = progress;\n const timeMs = progress * duration;\n\n if (this.onSeek) {\n this.onSeek(timeMs);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: timeMs,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = timeMs;\n }\n }\n }\n }\n\n @eventOptions({ passive: false, capture: false })\n private handlePointerDown(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n this.isMoving = true;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = true;\n }\n e.preventDefault();\n e.stopPropagation();\n this.capturedPointerId = e.pointerId;\n try {\n scrubberEl.setPointerCapture(e.pointerId);\n } catch (err) {\n // setPointerCapture may fail in some cases, continue anyway\n console.warn(\"Failed to set pointer capture:\", err);\n }\n this.updateProgress(e);\n }\n\n private boundHandlePointerMove = (e: PointerEvent) => {\n if (this.isMoving && e.pointerId === this.capturedPointerId) {\n e.preventDefault();\n e.stopPropagation();\n this.updateProgress(e);\n }\n };\n\n private boundHandlePointerUp = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n e.preventDefault();\n e.stopPropagation();\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandlePointerCancel = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandleContextMenu = (e: Event) => {\n if (this.isMoving) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n render() {\n const duration = this.effectiveDurationMs;\n const currentTime = this.effectiveCurrentTimeMs;\n\n if (duration <= 0) {\n return html``;\n }\n\n if (this.isTimelineMode) {\n // Vertical timeline mode: render playhead line\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrubberEl?.parentElement?.getBoundingClientRect().width || 0;\n\n const positionPixels =\n effectiveWidth > 0\n ? timeToPixels(currentTime, duration, effectiveWidth, this.zoomScale)\n : 0;\n\n const rawScrubPositionPixels =\n this.rawScrubTimeMs !== null &&\n this.rawScrubTimeMs !== undefined &&\n effectiveWidth > 0\n ? timeToPixels(\n this.rawScrubTimeMs,\n duration,\n effectiveWidth,\n this.zoomScale,\n )\n : null;\n\n return html`\n ${\n rawScrubPositionPixels !== null &&\n rawScrubPositionPixels !== positionPixels\n ? html`<div\n class=\"raw-preview\"\n style=\"left: ${rawScrubPositionPixels}px\"\n ></div>`\n : html``\n }\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div\n part=\"playhead\"\n class=\"playhead\"\n style=\"left: ${positionPixels}px\"\n @pointerdown=${this.handlePointerDown}\n >\n <div class=\"playhead-handle\"></div>\n </div>\n </div>\n `;\n } else {\n // Horizontal mode: render progress bar\n const currentProgress = duration > 0 ? currentTime / duration : 0;\n const displayProgress = this.isMoving\n ? this.scrubProgress\n : currentProgress;\n\n return html`\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div class=\"progress\" style=\"width: ${displayProgress * 100}%\"></div>\n <div class=\"handle\" style=\"left: ${displayProgress * 100}%\"></div>\n </div>\n `;\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n window.addEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n { passive: false },\n );\n window.addEventListener(\"pointermove\", this.boundHandlePointerMove, {\n passive: false,\n });\n window.addEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n { passive: false },\n );\n this.addEventListener(\"contextmenu\", this.boundHandleContextMenu, {\n passive: false,\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n window.removeEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n );\n window.removeEventListener(\"pointermove\", this.boundHandlePointerMove);\n window.removeEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n );\n this.removeEventListener(\"contextmenu\", this.boundHandleContextMenu);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-scrubber\": EFScrubber;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,MAAM,yBAAyB;AAE/B,SAAS,aACP,QACA,YACA,gBACA,WACQ;AACR,KAAI,cAAc,EAAG,QAAO;CAC5B,MAAM,kBAAkB,yBAAyB;AACjD,QAAQ,SAAS,MAAQ;;AAG3B,SAAS,aACP,QACA,YACA,gBACA,WACQ;AACR,KAAI,cAAc,EAAG,QAAO;AAE5B,QAAQ,UADgB,yBAAyB,aACb;;AAI/B,uBAAMA,qBAAmB,qBAAqB,YAAY,UAAU,CAAC;;;iBAmHhE;8BAGa;2BAGH;qBAGqB;uBAGzB;oBAGH;mBAGD;wBAGK;uBA+CO;kBAGL;qBAEG,WAAwB;2BAEH;iCAqHT,MAAoB;AACpD,OAAI,KAAK,YAAY,EAAE,cAAc,KAAK,mBAAmB;AAC3D,MAAE,gBAAgB;AAClB,MAAE,iBAAiB;AACnB,SAAK,eAAe,EAAE;;;+BAIM,MAAoB;GAClD,MAAM,aAAa,KAAK,YAAY,SAAS,KAAK;AAClD,OAAI,EAAE,cAAc,KAAK,qBAAqB,YAAY;AACxD,MAAE,gBAAgB;AAClB,MAAE,iBAAiB;AACnB,QAAI;AACF,gBAAW,sBAAsB,EAAE,UAAU;aACtC,MAAM;AAGf,SAAK,oBAAoB;AACzB,SAAK,WAAW;AAChB,QAAI,KAAK,eACP,MAAK,eAAe,UAAU;;;mCAKA,MAAoB;GACtD,MAAM,aAAa,KAAK,YAAY,SAAS,KAAK;AAClD,OAAI,EAAE,cAAc,KAAK,qBAAqB,YAAY;AACxD,QAAI;AACF,gBAAW,sBAAsB,EAAE,UAAU;aACtC,MAAM;AAGf,SAAK,oBAAoB;AACzB,SAAK,WAAW;AAChB,QAAI,KAAK,eACP,MAAK,eAAe,UAAU;;;iCAKF,MAAa;AAC7C,OAAI,KAAK,UAAU;AACjB,MAAE,gBAAgB;AAClB,MAAE,iBAAiB;;;;;gBA/VP,CACd,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8GJ;;CAgDD,IAAI,UAAwC;AAC1C,SAAO,KAAK;;CAGd,IAAI,yBAAiC;AACnC,MAAI,CAAC,OAAO,MAAM,KAAK,cAAc,CACnC,QAAO,KAAK;AAEd,MAAI,CAAC,OAAO,MAAM,KAAK,qBAAqB,CAC1C,QAAO,KAAK;AAEd,SAAO;;CAGT,IAAI,sBAA8B;AAChC,SAAO,KAAK,cAAc,KAAK,qBAAqB;;CAGtD,IAAI,iBAA0B;AAC5B,SAAO,KAAK,gBAAgB,cAAc,KAAK,YAAY;;CAa7D,AAAQ,eAAe,GAAiB;EACtC,MAAM,aAAa,KAAK,YAAY,SAAS,KAAK;AAClD,MAAI,CAAC,WAAY;EAEjB,MAAM,WAAW,KAAK;AACtB,MAAI,YAAY,EAAG;AAEnB,MAAI,KAAK,gBAAgB;GAEvB,MAAM,kBACJ,KAAK,oBAAoB,WAAW,WAAW;AACjD,OAAI,CAAC,gBAAiB;GAEtB,MAAM,sBAAsB,gBAAgB,uBAAuB;GACnE,MAAM,aAAa,gBAAgB,cAAc;GAIjD,IAAI,cAAc;AAClB,OAAI,KAAK,iBAAiB,QAExB,eADkB,KAAK,gBAAgB,QAAQ,uBAAuB,CAE1D,OACV,oBAAoB,OACpB,gBAAgB;GAIpB,MAAM,gBAAgB,cADZ,EAAE,UAAU,oBAAoB,OAAO;GAEjD,MAAM,iBACJ,KAAK,iBAAiB,IAClB,KAAK,iBACL,oBAAoB;AAC1B,OAAI,kBAAkB,EAAG;GAEzB,IAAI,UAAU,aACZ,eACA,UACA,gBACA,KAAK,UACN;AACD,aAAU,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,SAAS,CAAC;GAGlD,IAAI,gBACF,KAAK,OAAO,KAAK,MAAM,IACnB,sBAAsB,SAAS,KAAK,IAAI,GACxC;AACN,mBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,eAAe,SAAS,CAAC;AAE9D,QAAK,gBAAgB,gBAAgB;AAErC,OAAI,KAAK,OACP,MAAK,OAAO,cAAc;QACrB;AAEL,SAAK,cACH,IAAI,YAAY,QAAQ;KACtB,QAAQ;KACR,SAAS;KACT,UAAU;KACX,CAAC,CACH;AACD,QAAI,KAAK,QACP,MAAK,QAAQ,gBAAgB;;SAG5B;GAEL,MAAM,OAAO,WAAW,uBAAuB;GAC/C,MAAM,IAAI,EAAE,UAAU,KAAK;GAC3B,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,KAAK,MAAM,CAAC;AAEzD,QAAK,gBAAgB;GACrB,MAAM,SAAS,WAAW;AAE1B,OAAI,KAAK,OACP,MAAK,OAAO,OAAO;QACd;AAEL,SAAK,cACH,IAAI,YAAY,QAAQ;KACtB,QAAQ;KACR,SAAS;KACT,UAAU;KACX,CAAC,CACH;AACD,QAAI,KAAK,QACP,MAAK,QAAQ,gBAAgB;;;;CAMrC,AACQ,kBAAkB,GAAiB;EACzC,MAAM,aAAa,KAAK,YAAY,SAAS,KAAK;AAClD,MAAI,CAAC,WAAY;AAEjB,OAAK,WAAW;AAChB,MAAI,KAAK,eACP,MAAK,eAAe,UAAU;AAEhC,IAAE,gBAAgB;AAClB,IAAE,iBAAiB;AACnB,OAAK,oBAAoB,EAAE;AAC3B,MAAI;AACF,cAAW,kBAAkB,EAAE,UAAU;WAClC,KAAK;AAEZ,WAAQ,KAAK,kCAAkC,IAAI;;AAErD,OAAK,eAAe,EAAE;;CAoDxB,SAAS;EACP,MAAM,WAAW,KAAK;EACtB,MAAM,cAAc,KAAK;AAEzB,MAAI,YAAY,EACd,QAAO,IAAI;AAGb,MAAI,KAAK,gBAAgB;GAEvB,MAAM,aAAa,KAAK,YAAY,SAAS,KAAK;GAClD,MAAM,iBACJ,KAAK,iBAAiB,IAClB,KAAK,iBACL,YAAY,eAAe,uBAAuB,CAAC,SAAS;GAElE,MAAM,iBACJ,iBAAiB,IACb,aAAa,aAAa,UAAU,gBAAgB,KAAK,UAAU,GACnE;GAEN,MAAM,yBACJ,KAAK,mBAAmB,QACxB,KAAK,mBAAmB,UACxB,iBAAiB,IACb,aACE,KAAK,gBACL,UACA,gBACA,KAAK,UACN,GACD;AAEN,UAAO,IAAI;UAEP,2BAA2B,QAC3B,2BAA2B,iBACvB,IAAI;;6BAEW,uBAAuB;uBAEtC,IAAI,GACT;;YAEG,IAAI,KAAK,YAAY,CAAC;;;yBAGT,KAAK,kBAAkB;yBACvB,KAAK,uBAAuB;;;;;2BAK1B,eAAe;2BACf,KAAK,kBAAkB;;;;;;SAMvC;GAEL,MAAM,kBAAkB,WAAW,IAAI,cAAc,WAAW;GAChE,MAAM,kBAAkB,KAAK,WACzB,KAAK,gBACL;AAEJ,UAAO,IAAI;;YAEL,IAAI,KAAK,YAAY,CAAC;;;yBAGT,KAAK,kBAAkB;yBACvB,KAAK,uBAAuB;;gDAEL,kBAAkB,IAAI;6CACzB,kBAAkB,IAAI;;;;;CAMjE,oBAAoB;AAClB,QAAM,mBAAmB;AACzB,SAAO,iBACL,aACA,KAAK,sBACL,EAAE,SAAS,OAAO,CACnB;AACD,SAAO,iBAAiB,eAAe,KAAK,wBAAwB,EAClE,SAAS,OACV,CAAC;AACF,SAAO,iBACL,iBACA,KAAK,0BACL,EAAE,SAAS,OAAO,CACnB;AACD,OAAK,iBAAiB,eAAe,KAAK,wBAAwB,EAChE,SAAS,OACV,CAAC;;CAGJ,uBAAuB;AACrB,QAAM,sBAAsB;AAC5B,SAAO,oBACL,aACA,KAAK,qBACN;AACD,SAAO,oBAAoB,eAAe,KAAK,uBAAuB;AACtE,SAAO,oBACL,iBACA,KAAK,yBACN;AACD,OAAK,oBAAoB,eAAe,KAAK,uBAAuB;;;YAnWrE,QAAQ;CAAE,SAAS;CAAgB,WAAW;CAAM,CAAC;YAGrD,QAAQ;CAAE,SAAS;CAAoB,WAAW;CAAM,CAAC;YAGzD,QAAQ;CAAE,SAAS;CAAiB,WAAW;CAAM,CAAC;YAGtD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAe,CAAC;YAGpD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAmB,CAAC;YAGxD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAe,CAAC;YAGpD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAc,CAAC;YAGnD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAmB,CAAC;YAGxD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAG5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAqB,CAAC;YAG1D,SAAS,EAAE,WAAW,OAAO,CAAC;YAO9B,SAAS,EAAE,WAAW,OAAO,CAAC;YAG9B,SAAS,EAAE,WAAW,OAAO,CAAC;YAG9B,SAAS,EAAE,WAAW,OAAO,CAAC;YAyB9B,OAAO;YAGP,OAAO;YAqGP,aAAa;CAAE,SAAS;CAAO,SAAS;CAAO,CAAC;yBA/RlD,cAAc,cAAc"}
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit21 from "lit";
2
+ import * as lit23 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html19 from "lit-html";
4
+ import * as lit_html23 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTimeDisplay.d.ts
7
7
  declare const EFTimeDisplay_base: (new (...args: any[]) => {
@@ -10,11 +10,11 @@ declare const EFTimeDisplay_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFTimeDisplay extends EFTimeDisplay_base {
13
- static styles: lit21.CSSResult;
13
+ static styles: lit23.CSSResult;
14
14
  currentTimeMs: number;
15
15
  durationMs: number;
16
16
  private formatTime;
17
- render(): lit_html19.TemplateResult<1>;
17
+ render(): lit_html23.TemplateResult<1>;
18
18
  }
19
19
  declare global {
20
20
  interface HTMLElementTagNameMap {
@@ -17,12 +17,15 @@ let EFTimeDisplay = class EFTimeDisplay$1 extends TargetOrContextMixin(LitElemen
17
17
  static {
18
18
  this.styles = css`
19
19
  :host {
20
- display: inline-block;
20
+ display: inline-flex;
21
+ align-items: center;
21
22
  font-family: var(--ef-font-family, system-ui);
22
23
  font-size: var(--ef-font-size-xs, 0.75rem);
23
24
  color: var(--ef-text-color, rgb(75 85 99));
24
25
  white-space: nowrap;
25
26
  }
27
+
28
+ ::part(time) {}
26
29
  `;
27
30
  }
28
31
  formatTime(ms) {