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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/dist/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 +12 -2
  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 +118 -56
  117. package/dist/elements/EFThumbnailStrip.js +522 -358
  118. package/dist/elements/EFThumbnailStrip.js.map +1 -1
  119. package/dist/elements/EFTimegroup.d.ts +223 -27
  120. package/dist/elements/EFTimegroup.js +850 -147
  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 +152 -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 +11 -5
  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 +182 -4
  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 +840 -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/sandbox/PlaybackControls.js +10 -0
  304. package/dist/sandbox/PlaybackControls.js.map +1 -0
  305. package/dist/sandbox/ScenarioRunner.js +1 -0
  306. package/dist/sandbox/index.js +2 -0
  307. package/dist/style.css +68 -67
  308. package/dist/transcoding/types/index.d.ts +2 -1
  309. package/dist/transcoding/utils/UrlGenerator.d.ts +6 -1
  310. package/dist/transcoding/utils/UrlGenerator.js +12 -3
  311. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  312. package/dist/utils/LRUCache.js +1 -375
  313. package/dist/utils/LRUCache.js.map +1 -1
  314. package/dist/utils/frameTime.js +14 -0
  315. package/dist/utils/frameTime.js.map +1 -0
  316. package/package.json +3 -3
  317. package/test/profilingPlugin.ts +223 -0
  318. package/test/recordReplayProxyPlugin.js +22 -27
  319. package/test/thumbnail-performance-test.html +116 -0
  320. package/test/visualRegressionUtils.ts +286 -0
  321. package/types.json +1 -1
  322. package/dist/elements/TimegroupController.d.ts +0 -18
  323. package/dist/msToTimeCode.js +0 -17
  324. package/dist/msToTimeCode.js.map +0 -1
@@ -1,909 +1,38 @@
1
- import { loopContext, playingContext } from "./playingContext.js";
2
1
  import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
3
2
  import { isEFTemporal } from "../elements/EFTemporal.js";
4
- import { focusContext } from "./focusContext.js";
5
- import { focusedElementContext } from "./focusedElementContext.js";
6
3
  import { targetTemporalContext } from "./ContextMixin.js";
7
4
  import { TWMixin } from "./TWMixin2.js";
8
5
  import { TargetController } from "../elements/TargetController.js";
9
- import { TimegroupController } from "../elements/TimegroupController.js";
10
- import { EFTimegroup } from "../elements/EFTimegroup.js";
11
- import { EFImage } from "../elements/EFImage.js";
12
- import { EFAudio } from "../elements/EFAudio.js";
13
- import { EFVideo } from "../elements/EFVideo.js";
14
- import { EFCaptions, EFCaptionsActiveWord } from "../elements/EFCaptions.js";
15
- import { EFText } from "../elements/EFText.js";
16
- import { EFTextSegment } from "../elements/EFTextSegment.js";
17
- import { EFWaveform } from "../elements/EFWaveform.js";
18
- import { msToTimeCode } from "../msToTimeCode.js";
6
+ import "./timeline/EFTimeline.js";
19
7
  import { consume } from "@lit/context";
20
- import { LitElement, css, html, nothing } from "lit";
21
- import { customElement, eventOptions, property, state } from "lit/decorators.js";
8
+ import { LitElement, html } from "lit";
9
+ import { customElement, property, state } from "lit/decorators.js";
22
10
  import { createRef, ref } from "lit/directives/ref.js";
23
- import { styleMap } from "lit/directives/style-map.js";
24
11
 
25
12
  //#region src/gui/EFFilmstrip.ts
26
- var ElementFilmstripController = class {
27
- constructor(host, filmstrip) {
28
- this.host = host;
29
- this.filmstrip = filmstrip;
30
- this.host.addController(this);
31
- }
32
- remove() {
33
- this.host.removeController(this);
34
- }
35
- hostDisconnected() {
36
- this.host.removeController(this);
37
- }
38
- hostUpdated() {
39
- this.filmstrip.requestUpdate();
40
- }
41
- };
42
- const CommonEffectKeys = new Set([
43
- "offset",
44
- "easing",
45
- "composite",
46
- "computedOffset"
47
- ]);
48
- var FilmstripItem = class extends TWMixin(LitElement) {
13
+ let EFFilmstrip = class EFFilmstrip$1 extends TWMixin(LitElement) {
49
14
  constructor(..._args) {
50
15
  super(..._args);
51
- this.element = new EFTimegroup();
52
- this.pixelsPerMs = .04;
53
- }
54
- static {
55
- this.styles = [css`
56
- :host {
57
- display: block;
58
- }
59
- `];
60
- }
61
- get isFocused() {
62
- return this.element && this.focusContext?.focusedElement === this.element;
63
- }
64
- get gutterStyles() {
65
- return {
66
- position: "relative",
67
- left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.sourceStartMs)}px`,
68
- width: `${this.pixelsPerMs * (this.element.intrinsicDurationMs ?? this.element.durationMs)}px`
69
- };
70
- }
71
- get trimPortionStyles() {
72
- return {
73
- width: `${this.pixelsPerMs * this.element.durationMs}px`,
74
- left: `${this.pixelsPerMs * this.element.sourceStartMs}px`
75
- };
76
- }
77
- render() {
78
- return html`<div style=${styleMap(this.gutterStyles)}>
79
- <div
80
- style="background-color: var(--filmstrip-bg);"
81
- ?data-focused=${this.isFocused}
82
- @mouseenter=${() => {
83
- if (this.focusContext) this.focusContext.focusedElement = this.element;
84
- }}
85
- @mouseleave=${() => {
86
- if (this.focusContext) this.focusContext.focusedElement = null;
87
- }}
88
- >
89
- <div
90
- ?data-focused=${this.isFocused}
91
- class="border-outset relative mb-[1px] block h-[1.1rem] text-nowrap border text-sm"
92
- style=${styleMap({
93
- ...this.trimPortionStyles,
94
- backgroundColor: this.isFocused ? "var(--filmstrip-item-focused)" : "var(--filmstrip-item-bg)",
95
- borderColor: "var(--filmstrip-border)"
96
- })}
97
- >
98
- ${this.animations()}
99
- </div>
100
- </div>
101
- ${this.renderChildren()}
102
- </div>`;
103
- }
104
- renderChildren() {
105
- return renderFilmstripChildren(Array.from(this.element.children), this.pixelsPerMs, this.hideSelectors, this.showSelectors);
106
- }
107
- contents() {
108
- return html``;
109
- }
110
- animations() {
111
- return this.element.getAnimations().map((animation) => {
112
- const effect = animation.effect;
113
- if (!(effect instanceof KeyframeEffect)) return nothing;
114
- const start = effect.getTiming().delay ?? 0;
115
- const duration = effect.getTiming().duration;
116
- if (duration === null) return nothing;
117
- const firstKeyframe = effect.getKeyframes()[0];
118
- if (!firstKeyframe) return nothing;
119
- const properties = new Set(Object.keys(firstKeyframe));
120
- for (const key of CommonEffectKeys) properties.delete(key);
121
- return html`<div
122
- class="relative h-[5px] opacity-50"
123
- label="animation"
124
- style=${styleMap({
125
- left: `${this.pixelsPerMs * start}px`,
126
- width: `${this.pixelsPerMs * Number(duration)}px`,
127
- backgroundColor: "var(--filmstrip-animation-bg)"
128
- })}
129
- >
130
- <!-- <div class="text-nowrap">${Array.from(properties).join(" ")}</div> -->
131
- ${effect.getKeyframes().map((keyframe) => {
132
- return html`<div
133
- class="absolute top-0 h-full w-1"
134
- style=${styleMap({
135
- left: `${this.pixelsPerMs * keyframe.computedOffset * Number(duration)}px`,
136
- backgroundColor: "var(--filmstrip-keyframe-bg)"
137
- })}
138
- ></div>`;
139
- })}
140
- </div>`;
141
- });
142
- }
143
- update(changedProperties) {
144
- if (changedProperties.has("element") && this.element instanceof LitElement) {
145
- this.filmstripController?.remove();
146
- this.filmstripController = new ElementFilmstripController(this.element, this);
147
- }
148
- super.update(changedProperties);
149
- }
150
- };
151
- __decorate([consume({
152
- context: focusContext,
153
- subscribe: true
154
- })], FilmstripItem.prototype, "focusContext", void 0);
155
- __decorate([consume({
156
- context: focusedElementContext,
157
- subscribe: true
158
- })], FilmstripItem.prototype, "focusedElement", void 0);
159
- __decorate([property({
160
- type: Object,
161
- attribute: false
162
- })], FilmstripItem.prototype, "element", void 0);
163
- __decorate([property({ type: Number })], FilmstripItem.prototype, "pixelsPerMs", void 0);
164
- __decorate([property({
165
- type: Array,
166
- attribute: false
167
- })], FilmstripItem.prototype, "hideSelectors", void 0);
168
- __decorate([property({
169
- type: Array,
170
- attribute: false
171
- })], FilmstripItem.prototype, "showSelectors", void 0);
172
- let EFAudioFilmstrip = class EFAudioFilmstrip$1 extends FilmstripItem {
173
- contents() {
174
- return html``;
175
- }
176
- };
177
- EFAudioFilmstrip = __decorate([customElement("ef-audio-filmstrip")], EFAudioFilmstrip);
178
- let EFVideoFilmstrip = class EFVideoFilmstrip$1 extends FilmstripItem {
179
- contents() {
180
- return html` 📼 `;
181
- }
182
- };
183
- EFVideoFilmstrip = __decorate([customElement("ef-video-filmstrip")], EFVideoFilmstrip);
184
- let EFCaptionsFilmstrip = class EFCaptionsFilmstrip$1 extends FilmstripItem {
185
- render() {
186
- const captionsData = this.element.unifiedCaptionsDataTask.value;
187
- return html`<div style=${styleMap(this.gutterStyles)}>
188
- <div
189
- class="relative"
190
- style="background-color: var(--filmstrip-bg);"
191
- ?data-focused=${this.isFocused}
192
- @mouseenter=${() => {
193
- if (this.focusContext) this.focusContext.focusedElement = this.element;
194
- }}
195
- @mouseleave=${() => {
196
- if (this.focusContext) this.focusContext.focusedElement = null;
197
- }}
198
- >
199
- <div
200
- ?data-focused=${this.isFocused}
201
- class="border-outset relative mb-[1px] block h-[1.1rem] text-nowrap border text-sm overflow-hidden"
202
- style=${styleMap({
203
- ...this.trimPortionStyles,
204
- backgroundColor: this.isFocused ? "var(--filmstrip-item-focused)" : "var(--filmstrip-item-bg)",
205
- borderColor: "var(--filmstrip-border)"
206
- })}
207
- >
208
- 📝 ${this.renderCaptionsData(captionsData)}
209
- </div>
210
- </div>
211
- ${this.renderChildren()}
212
- </div>`;
213
- }
214
- renderCaptionsData(captionsData) {
215
- if (!captionsData) return html``;
216
- const captions = this.element;
217
- const captionsLocalTimeSec = ((captions.rootTimegroup?.currentTimeMs || 0) - captions.startTimeMs) / 1e3;
218
- return html`${captionsData.segments.map((segment) => {
219
- const isActive = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
220
- return html`<div
221
- class="absolute border text-xs overflow-hidden flex items-center ${isActive ? "font-bold z-[5]" : ""}"
222
- style=${styleMap({
223
- left: `${this.pixelsPerMs * segment.start * 1e3}px`,
224
- width: `${this.pixelsPerMs * (segment.end - segment.start) * 1e3}px`,
225
- height: "100%",
226
- top: "0px",
227
- backgroundColor: isActive ? "var(--filmstrip-segment-bg)" : "var(--filmstrip-item-bg)",
228
- borderColor: isActive ? "var(--filmstrip-segment-border)" : "var(--filmstrip-border)"
229
- })}
230
- title="Segment: '${segment.text}' (${segment.start}s - ${segment.end}s)"
231
- >
232
- <span class="px-0.5 text-[8px] ${isActive ? "font-bold" : ""}">${segment.text}</span>
233
- </div>`;
234
- })}`;
235
- }
236
- renderChildren() {
237
- return renderFilmstripChildren(Array.from(this.element.children), this.pixelsPerMs, this.hideSelectors, this.showSelectors);
238
- }
239
- };
240
- EFCaptionsFilmstrip = __decorate([customElement("ef-captions-filmstrip")], EFCaptionsFilmstrip);
241
- let EFCaptionsActiveWordFilmstrip = class EFCaptionsActiveWordFilmstrip$1 extends FilmstripItem {
242
- get captionsTrackStyles() {
243
- const parentCaptions = this.element.closest("ef-captions");
244
- return {
245
- position: "relative",
246
- left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
247
- width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
248
- };
249
- }
250
- render() {
251
- const parentCaptions = this.element.closest("ef-captions");
252
- const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
253
- if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
254
- <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
255
- 🗣️ Active Word
256
- </div>
257
- </div>`;
258
- const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
259
- return html`<div style=${styleMap(this.captionsTrackStyles)}>
260
- <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
261
- ${captionsData.word_segments.map((word) => {
262
- const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
263
- return html`<div
264
- class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
265
- style=${styleMap({
266
- left: `${this.pixelsPerMs * word.start * 1e3}px`,
267
- width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
268
- height: "100%",
269
- top: "0px",
270
- backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-item-bg)",
271
- borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-border)"
272
- })}
273
- title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
274
- >
275
- ${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap" style="background-color: var(--filmstrip-caption-bg);">${word.text.trim()}</span>` : ""}
276
- </div>`;
277
- })}
278
- </div>
279
- </div>`;
280
- }
281
- };
282
- EFCaptionsActiveWordFilmstrip = __decorate([customElement("ef-captions-active-word-filmstrip")], EFCaptionsActiveWordFilmstrip);
283
- let EFCaptionsSegmentFilmstrip = class EFCaptionsSegmentFilmstrip$1 extends FilmstripItem {
284
- get captionsTrackStyles() {
285
- const parentCaptions = this.element.closest("ef-captions");
286
- return {
287
- position: "relative",
288
- left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
289
- width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
290
- };
291
- }
292
- render() {
293
- const parentCaptions = this.element.closest("ef-captions");
294
- const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
295
- if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
296
- <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
297
- 📄 Segment
298
- </div>
299
- </div>`;
300
- const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
301
- return html`<div style=${styleMap(this.captionsTrackStyles)}>
302
- <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
303
- ${captionsData.segments.map((segment) => {
304
- const isCurrentlyActive = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
305
- return html`<div
306
- class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
307
- style=${styleMap({
308
- left: `${this.pixelsPerMs * segment.start * 1e3}px`,
309
- width: `${this.pixelsPerMs * (segment.end - segment.start) * 1e3}px`,
310
- height: "100%",
311
- top: "0px",
312
- backgroundColor: isCurrentlyActive ? "var(--filmstrip-segment-bg)" : "var(--filmstrip-item-bg)",
313
- borderColor: isCurrentlyActive ? "var(--filmstrip-segment-border)" : "var(--filmstrip-border)"
314
- })}
315
- title="Segment: '${segment.text}' (${segment.start}s - ${segment.end}s)"
316
- >
317
- ${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap" style="background-color: var(--filmstrip-segment-bg);">${segment.text}</span>` : ""}
318
- </div>`;
319
- })}
320
- </div>
321
- </div>`;
322
- }
323
- };
324
- EFCaptionsSegmentFilmstrip = __decorate([customElement("ef-captions-segment-filmstrip")], EFCaptionsSegmentFilmstrip);
325
- let EFCaptionsBeforeWordFilmstrip = class EFCaptionsBeforeWordFilmstrip$1 extends FilmstripItem {
326
- get captionsTrackStyles() {
327
- const parentCaptions = this.element.closest("ef-captions");
328
- return {
329
- position: "relative",
330
- left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
331
- width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
332
- };
333
- }
334
- render() {
335
- const parentCaptions = this.element.closest("ef-captions");
336
- const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
337
- if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
338
- <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
339
- ⬅️ Before
340
- </div>
341
- </div>`;
342
- const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
343
- return html`<div style=${styleMap(this.captionsTrackStyles)}>
344
- <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
345
- ${captionsData.word_segments.map((word) => {
346
- const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
347
- return html`<div
348
- class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
349
- style=${styleMap({
350
- left: `${this.pixelsPerMs * word.start * 1e3}px`,
351
- width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
352
- height: "100%",
353
- top: "0px",
354
- backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-waveform-bg)",
355
- borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-waveform-border)"
356
- })}
357
- title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
358
- >
359
- <!-- No text for before tracks - they're redundant -->
360
- </div>`;
361
- })}
362
- </div>
363
- </div>`;
364
- }
365
- };
366
- EFCaptionsBeforeWordFilmstrip = __decorate([customElement("ef-captions-before-word-filmstrip")], EFCaptionsBeforeWordFilmstrip);
367
- let EFCaptionsAfterWordFilmstrip = class EFCaptionsAfterWordFilmstrip$1 extends FilmstripItem {
368
- get captionsTrackStyles() {
369
- const parentCaptions = this.element.closest("ef-captions");
370
- return {
371
- position: "relative",
372
- left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
373
- width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
374
- };
375
- }
376
- render() {
377
- const parentCaptions = this.element.closest("ef-captions");
378
- const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
379
- if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
380
- <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
381
- ➡️ After
382
- </div>
383
- </div>`;
384
- const captionsLocalTimeSec = ((parentCaptions.rootTimegroup?.currentTimeMs || 0) - parentCaptions.startTimeMs) / 1e3;
385
- return html`<div style=${styleMap(this.captionsTrackStyles)}>
386
- <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
387
- ${captionsData.word_segments.map((word) => {
388
- const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
389
- return html`<div
390
- class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
391
- style=${styleMap({
392
- left: `${this.pixelsPerMs * word.start * 1e3}px`,
393
- width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
394
- height: "100%",
395
- top: "0px",
396
- backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-waveform-bg)",
397
- borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-waveform-border)"
398
- })}
399
- title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
400
- >
401
- <!-- No text for after tracks - they're redundant -->
402
- </div>`;
403
- })}
404
- </div>
405
- </div>`;
406
- }
407
- };
408
- EFCaptionsAfterWordFilmstrip = __decorate([customElement("ef-captions-after-word-filmstrip")], EFCaptionsAfterWordFilmstrip);
409
- let EFWaveformFilmstrip = class EFWaveformFilmstrip$1 extends FilmstripItem {
410
- contents() {
411
- return html` 🌊 `;
412
- }
413
- renderChildren() {
414
- return nothing;
415
- }
416
- };
417
- EFWaveformFilmstrip = __decorate([customElement("ef-waveform-filmstrip")], EFWaveformFilmstrip);
418
- let EFTextFilmstrip = class EFTextFilmstrip$1 extends FilmstripItem {
419
- render() {
420
- const text = this.element;
421
- const segments = Array.from(text.querySelectorAll("ef-text-segment"));
422
- return html`<div style=${styleMap(this.gutterStyles)}>
423
- <div
424
- class="relative"
425
- style="background-color: var(--filmstrip-bg);"
426
- ?data-focused=${this.isFocused}
427
- @mouseenter=${() => {
428
- if (this.focusContext) this.focusContext.focusedElement = this.element;
429
- }}
430
- @mouseleave=${() => {
431
- if (this.focusContext) this.focusContext.focusedElement = null;
432
- }}
433
- >
434
- <div
435
- ?data-focused=${this.isFocused}
436
- class="border-outset relative mb-[1px] block h-[1.1rem] text-nowrap border text-sm overflow-hidden"
437
- style=${styleMap({
438
- ...this.trimPortionStyles,
439
- backgroundColor: this.isFocused ? "var(--filmstrip-item-focused)" : "var(--filmstrip-item-bg)",
440
- borderColor: "var(--filmstrip-border)"
441
- })}
442
- >
443
- 📄 ${this.renderTextSegments(segments)}
444
- </div>
445
- </div>
446
- ${this.renderChildren()}
447
- </div>`;
448
- }
449
- renderTextSegments(segments) {
450
- if (segments.length === 0) return html``;
451
- const text = this.element;
452
- const textLocalTimeMs = (text.rootTimegroup?.currentTimeMs || 0) - text.startTimeMs;
453
- return segments.map((segment) => {
454
- const isActive = textLocalTimeMs >= segment.segmentStartMs && textLocalTimeMs < segment.segmentEndMs;
455
- return html`<div
456
- class="absolute border text-xs overflow-hidden flex items-center ${isActive ? "font-bold z-[5]" : ""}"
457
- style=${styleMap({
458
- left: `${this.pixelsPerMs * segment.segmentStartMs}px`,
459
- width: `${this.pixelsPerMs * (segment.segmentEndMs - segment.segmentStartMs)}px`,
460
- height: "100%",
461
- top: "0px",
462
- backgroundColor: isActive ? "var(--filmstrip-segment-bg)" : "var(--filmstrip-item-bg)",
463
- borderColor: isActive ? "var(--filmstrip-segment-border)" : "var(--filmstrip-border)"
464
- })}
465
- title="Segment: '${segment.segmentText}' (${segment.segmentStartMs}ms - ${segment.segmentEndMs}ms)"
466
- >
467
- <span class="px-0.5 text-[8px] ${isActive ? "font-bold" : ""}">${segment.segmentText}</span>
468
- </div>`;
469
- });
470
- }
471
- renderChildren() {
472
- return renderFilmstripChildren(Array.from(this.element.children), this.pixelsPerMs, this.hideSelectors, this.showSelectors);
473
- }
474
- };
475
- EFTextFilmstrip = __decorate([customElement("ef-text-filmstrip")], EFTextFilmstrip);
476
- let EFTextSegmentFilmstrip = class EFTextSegmentFilmstrip$1 extends FilmstripItem {
477
- get textTrackStyles() {
478
- const parentText = this.element.closest("ef-text");
479
- return {
480
- position: "relative",
481
- left: `${this.pixelsPerMs * (parentText?.startTimeWithinParentMs || 0)}px`,
482
- width: `${this.pixelsPerMs * (parentText?.durationMs || 0)}px`
483
- };
484
- }
485
- render() {
486
- const segment = this.element;
487
- const parentText = segment.closest("ef-text");
488
- if (!parentText) return html`<div style=${styleMap(this.textTrackStyles)}>
489
- <div class="border h-[1.1rem] mb-[1px] text-xs" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
490
- 📄 Text Segment
491
- </div>
492
- </div>`;
493
- const textLocalTimeMs = (parentText.rootTimegroup?.currentTimeMs || 0) - parentText.startTimeMs;
494
- const isCurrentlyActive = textLocalTimeMs >= segment.segmentStartMs && textLocalTimeMs < segment.segmentEndMs;
495
- return html`<div style=${styleMap(this.textTrackStyles)}>
496
- <div class="relative border h-[1.1rem] mb-[1px] w-full" style="background-color: var(--filmstrip-bg); border-color: var(--filmstrip-border);">
497
- <div
498
- class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "font-bold z-[5]" : ""}"
499
- style=${styleMap({
500
- left: `${this.pixelsPerMs * segment.segmentStartMs}px`,
501
- width: `${this.pixelsPerMs * (segment.segmentEndMs - segment.segmentStartMs)}px`,
502
- height: "100%",
503
- top: "0px",
504
- backgroundColor: isCurrentlyActive ? "var(--filmstrip-caption-bg)" : "var(--filmstrip-item-bg)",
505
- borderColor: isCurrentlyActive ? "var(--filmstrip-caption-border)" : "var(--filmstrip-border)"
506
- })}
507
- title="Segment: '${segment.segmentText}' (${segment.segmentStartMs}ms - ${segment.segmentEndMs}ms)"
508
- >
509
- ${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap" style="background-color: var(--filmstrip-caption-bg);">${segment.segmentText}</span>` : ""}
510
- </div>
511
- </div>
512
- </div>`;
513
- }
514
- };
515
- EFTextSegmentFilmstrip = __decorate([customElement("ef-text-segment-filmstrip")], EFTextSegmentFilmstrip);
516
- let EFImageFilmstrip = class EFImageFilmstrip$1 extends FilmstripItem {
517
- contents() {
518
- return html` 🖼️ `;
519
- }
520
- };
521
- EFImageFilmstrip = __decorate([customElement("ef-image-filmstrip")], EFImageFilmstrip);
522
- let EFTimegroupFilmstrip = class EFTimegroupFilmstrip$1 extends FilmstripItem {
523
- contents() {
524
- return html`
525
- <span>TIME GROUP</span>
526
- ${renderFilmstripChildren(Array.from(this.element.children || []), this.pixelsPerMs, this.hideSelectors, this.showSelectors)}
527
- </div>
528
- `;
529
- }
530
- };
531
- EFTimegroupFilmstrip = __decorate([customElement("ef-timegroup-filmstrip")], EFTimegroupFilmstrip);
532
- let EFHTMLFilmstrip = class EFHTMLFilmstrip$1 extends FilmstripItem {
533
- contents() {
534
- return html`
535
- <span>${this.element.tagName}</span>
536
- ${renderFilmstripChildren(Array.from(this.element.children || []), this.pixelsPerMs, this.hideSelectors, this.showSelectors)}
537
- `;
538
- }
539
- };
540
- EFHTMLFilmstrip = __decorate([customElement("ef-html-filmstrip")], EFHTMLFilmstrip);
541
- let EFHierarchyItem = class EFHierarchyItem$1 extends TWMixin(LitElement) {
542
- constructor(..._args2) {
543
- super(..._args2);
544
- this.element = new EFTimegroup();
545
- }
546
- get icon() {
547
- return "📼";
548
- }
549
- get isFocused() {
550
- return this.element && this.focusContext?.focusedElement === this.element;
551
- }
552
- displayLabel() {
553
- return nothing;
554
- }
555
- render() {
556
- return html`
557
- <div>
558
- <div
559
- class="peer flex h-[1.1rem] items-center overflow-hidden text-nowrap border pl-2 text-xs font-mono"
560
- style=${styleMap({
561
- backgroundColor: this.isFocused ? "var(--filmstrip-timegroup-focused)" : "var(--filmstrip-timegroup-bg)",
562
- borderColor: "var(--filmstrip-border)"
563
- })}
564
- ?data-focused=${this.isFocused}
565
- @mouseenter=${() => {
566
- if (this.focusContext) this.focusContext.focusedElement = this.element;
567
- }}
568
- @mouseleave=${() => {
569
- if (this.focusContext) this.focusContext.focusedElement = null;
570
- }}
571
- >
572
- ${this.icon} ${this.displayLabel()}
573
- </div>
574
- <div
575
- class="p-[1px] pb-0 pl-2 pr-0 peer-hover-container peer-data-container"
576
- style=${styleMap({ backgroundColor: this.isFocused ? "var(--filmstrip-bg)" : "transparent" })}
577
- >
578
- ${this.renderChildren()}
579
- </div>
580
- </div>`;
581
- }
582
- renderChildren() {
583
- return renderHierarchyChildren(Array.from(this.element.children), this.hideSelectors, this.showSelectors);
584
- }
585
- };
586
- __decorate([property({
587
- type: Object,
588
- attribute: false
589
- })], EFHierarchyItem.prototype, "element", void 0);
590
- __decorate([consume({ context: focusContext })], EFHierarchyItem.prototype, "focusContext", void 0);
591
- __decorate([consume({
592
- context: focusedElementContext,
593
- subscribe: true
594
- })], EFHierarchyItem.prototype, "focusedElement", void 0);
595
- __decorate([property({
596
- type: Array,
597
- attribute: false
598
- })], EFHierarchyItem.prototype, "hideSelectors", void 0);
599
- __decorate([property({
600
- type: Array,
601
- attribute: false
602
- })], EFHierarchyItem.prototype, "showSelectors", void 0);
603
- EFHierarchyItem = __decorate([customElement("ef-hierarchy-item")], EFHierarchyItem);
604
- let EFTimegroupHierarchyItem = class EFTimegroupHierarchyItem$1 extends EFHierarchyItem {
605
- get icon() {
606
- return "🕒";
607
- }
608
- displayLabel() {
609
- return this.element.mode ?? "(no mode)";
610
- }
611
- };
612
- EFTimegroupHierarchyItem = __decorate([customElement("ef-timegroup-hierarchy-item")], EFTimegroupHierarchyItem);
613
- let EFAudioHierarchyItem = class EFAudioHierarchyItem$1 extends EFHierarchyItem {
614
- get icon() {
615
- return "🔊";
616
- }
617
- displayLabel() {
618
- return this.element.src ?? "(no src)";
619
- }
620
- };
621
- EFAudioHierarchyItem = __decorate([customElement("ef-audio-hierarchy-item")], EFAudioHierarchyItem);
622
- let EFVideoHierarchyItem = class EFVideoHierarchyItem$1 extends EFHierarchyItem {
623
- get icon() {
624
- return "📼";
625
- }
626
- displayLabel() {
627
- return this.element.src ?? "(no src)";
628
- }
629
- };
630
- EFVideoHierarchyItem = __decorate([customElement("ef-video-hierarchy-item")], EFVideoHierarchyItem);
631
- let EFCaptionsHierarchyItem = class EFCaptionsHierarchyItem$1 extends EFHierarchyItem {
632
- get icon() {
633
- return "📝 Captions";
634
- }
635
- };
636
- EFCaptionsHierarchyItem = __decorate([customElement("ef-captions-hierarchy-item")], EFCaptionsHierarchyItem);
637
- let EFCaptionsActiveWordHierarchyItem = class EFCaptionsActiveWordHierarchyItem$1 extends EFHierarchyItem {
638
- get icon() {
639
- return "🗣️ Active Word";
640
- }
641
- };
642
- EFCaptionsActiveWordHierarchyItem = __decorate([customElement("ef-captions-active-word-hierarchy-item")], EFCaptionsActiveWordHierarchyItem);
643
- let EFTextHierarchyItem = class EFTextHierarchyItem$1 extends EFHierarchyItem {
644
- get icon() {
645
- return "📄 Text";
646
- }
647
- };
648
- EFTextHierarchyItem = __decorate([customElement("ef-text-hierarchy-item")], EFTextHierarchyItem);
649
- let EFTextSegmentHierarchyItem = class EFTextSegmentHierarchyItem$1 extends EFHierarchyItem {
650
- get icon() {
651
- return "📄 Segment";
652
- }
653
- };
654
- EFTextSegmentHierarchyItem = __decorate([customElement("ef-text-segment-hierarchy-item")], EFTextSegmentHierarchyItem);
655
- let EFWaveformHierarchyItem = class EFWaveformHierarchyItem$1 extends EFHierarchyItem {
656
- get icon() {
657
- return "🌊";
658
- }
659
- renderChildren() {
660
- return nothing;
661
- }
662
- };
663
- EFWaveformHierarchyItem = __decorate([customElement("ef-waveform-hierarchy-item")], EFWaveformHierarchyItem);
664
- let EFImageHierarchyItem = class EFImageHierarchyItem$1 extends EFHierarchyItem {
665
- get icon() {
666
- return "🖼️";
667
- }
668
- displayLabel() {
669
- return this.element.src ?? "(no src)";
670
- }
671
- };
672
- EFImageHierarchyItem = __decorate([customElement("ef-image-hierarchy-item")], EFImageHierarchyItem);
673
- let EFHTMLHierarchyItem = class EFHTMLHierarchyItem$1 extends EFHierarchyItem {
674
- get icon() {
675
- return html`<code>${`<${this.element.tagName.toLowerCase()}>`}</code>`;
676
- }
677
- };
678
- EFHTMLHierarchyItem = __decorate([customElement("ef-html-hierarchy-item")], EFHTMLHierarchyItem);
679
- const shouldRenderElement = (element, hideSelectors, showSelectors) => {
680
- if (element instanceof HTMLElement && element.dataset?.efHidden) return false;
681
- if (showSelectors && showSelectors.length > 0) return showSelectors.some((selector) => {
682
- try {
683
- return element.matches(selector);
684
- } catch {
685
- return false;
686
- }
687
- });
688
- if (hideSelectors && hideSelectors.length > 0) return !hideSelectors.some((selector) => {
689
- try {
690
- return element.matches(selector);
691
- } catch {
692
- return false;
693
- }
694
- });
695
- return true;
696
- };
697
- const renderHierarchyChildren = (children, hideSelectors, showSelectors, skipRootFiltering = false) => {
698
- return children.map((child) => {
699
- if (!skipRootFiltering && !shouldRenderElement(child, hideSelectors, showSelectors)) return nothing;
700
- if (child instanceof EFTimegroup) return html`<ef-timegroup-hierarchy-item
701
- .element=${child}
702
- .hideSelectors=${hideSelectors}
703
- .showSelectors=${showSelectors}
704
- ></ef-timegroup-hierarchy-item>`;
705
- if (child instanceof EFImage) return html`<ef-image-hierarchy-item
706
- .element=${child}
707
- .hideSelectors=${hideSelectors}
708
- .showSelectors=${showSelectors}
709
- ></ef-image-hierarchy-item>`;
710
- if (child instanceof EFAudio) return html`<ef-audio-hierarchy-item
711
- .element=${child}
712
- .hideSelectors=${hideSelectors}
713
- .showSelectors=${showSelectors}
714
- ></ef-audio-hierarchy-item>`;
715
- if (child instanceof EFVideo) return html`<ef-video-hierarchy-item
716
- .element=${child}
717
- .hideSelectors=${hideSelectors}
718
- .showSelectors=${showSelectors}
719
- ></ef-video-hierarchy-item>`;
720
- if (child instanceof EFCaptions) return html`<ef-captions-hierarchy-item
721
- .element=${child}
722
- .hideSelectors=${hideSelectors}
723
- .showSelectors=${showSelectors}
724
- ></ef-captions-hierarchy-item>`;
725
- if (child instanceof EFCaptionsActiveWord) return html`<ef-captions-active-word-hierarchy-item
726
- .element=${child}
727
- .hideSelectors=${hideSelectors}
728
- .showSelectors=${showSelectors}
729
- ></ef-captions-active-word-hierarchy-item>`;
730
- if (child instanceof EFText) return html`<ef-text-hierarchy-item
731
- .element=${child}
732
- .hideSelectors=${hideSelectors}
733
- .showSelectors=${showSelectors}
734
- ></ef-text-hierarchy-item>`;
735
- if (child instanceof EFTextSegment) return html`<ef-text-segment-hierarchy-item
736
- .element=${child}
737
- .hideSelectors=${hideSelectors}
738
- .showSelectors=${showSelectors}
739
- ></ef-text-segment-hierarchy-item>`;
740
- if (child instanceof EFWaveform) return html`<ef-waveform-hierarchy-item
741
- .element=${child}
742
- .hideSelectors=${hideSelectors}
743
- .showSelectors=${showSelectors}
744
- ></ef-waveform-hierarchy-item>`;
745
- return html`<ef-html-hierarchy-item
746
- .element=${child}
747
- .hideSelectors=${hideSelectors}
748
- .showSelectors=${showSelectors}
749
- ></ef-html-hierarchy-item>`;
750
- });
751
- };
752
- const renderFilmstripChildren = (children, pixelsPerMs, hideSelectors, showSelectors, skipRootFiltering = false) => {
753
- return children.map((child) => {
754
- if (!skipRootFiltering && !shouldRenderElement(child, hideSelectors, showSelectors)) return nothing;
755
- if (child instanceof EFTimegroup) return html`<ef-timegroup-filmstrip
756
- .element=${child}
757
- .pixelsPerMs=${pixelsPerMs}
758
- .hideSelectors=${hideSelectors}
759
- .showSelectors=${showSelectors}
760
- >
761
- </ef-timegroup-filmstrip>`;
762
- if (child instanceof EFImage) return html`<ef-image-filmstrip
763
- .element=${child}
764
- .pixelsPerMs=${pixelsPerMs}
765
- .hideSelectors=${hideSelectors}
766
- .showSelectors=${showSelectors}
767
- ></ef-image-filmstrip>`;
768
- if (child instanceof EFAudio) return html`<ef-audio-filmstrip
769
- .element=${child}
770
- .pixelsPerMs=${pixelsPerMs}
771
- .hideSelectors=${hideSelectors}
772
- .showSelectors=${showSelectors}
773
- ></ef-audio-filmstrip>`;
774
- if (child instanceof EFVideo) return html`<ef-video-filmstrip
775
- .element=${child}
776
- .pixelsPerMs=${pixelsPerMs}
777
- .hideSelectors=${hideSelectors}
778
- .showSelectors=${showSelectors}
779
- ></ef-video-filmstrip>`;
780
- if (child instanceof EFCaptions) return html`<ef-captions-filmstrip
781
- .element=${child}
782
- .pixelsPerMs=${pixelsPerMs}
783
- .hideSelectors=${hideSelectors}
784
- .showSelectors=${showSelectors}
785
- ></ef-captions-filmstrip>`;
786
- if (child instanceof EFCaptionsActiveWord) return html`<ef-captions-active-word-filmstrip
787
- .element=${child}
788
- .pixelsPerMs=${pixelsPerMs}
789
- .hideSelectors=${hideSelectors}
790
- .showSelectors=${showSelectors}
791
- ></ef-captions-active-word-filmstrip>`;
792
- if (child instanceof EFText) return html`<ef-text-filmstrip
793
- .element=${child}
794
- .pixelsPerMs=${pixelsPerMs}
795
- .hideSelectors=${hideSelectors}
796
- .showSelectors=${showSelectors}
797
- ></ef-text-filmstrip>`;
798
- if (child instanceof EFTextSegment) return html`<ef-text-segment-filmstrip
799
- .element=${child}
800
- .pixelsPerMs=${pixelsPerMs}
801
- .hideSelectors=${hideSelectors}
802
- .showSelectors=${showSelectors}
803
- ></ef-text-segment-filmstrip>`;
804
- if (child.tagName === "EF-CAPTIONS-SEGMENT") return html`<ef-captions-segment-filmstrip
805
- .element=${child}
806
- .pixelsPerMs=${pixelsPerMs}
807
- .hideSelectors=${hideSelectors}
808
- .showSelectors=${showSelectors}
809
- ></ef-captions-segment-filmstrip>`;
810
- if (child.tagName === "EF-CAPTIONS-BEFORE-ACTIVE-WORD") return html`<ef-captions-before-word-filmstrip
811
- .element=${child}
812
- .pixelsPerMs=${pixelsPerMs}
813
- .hideSelectors=${hideSelectors}
814
- .showSelectors=${showSelectors}
815
- ></ef-captions-before-word-filmstrip>`;
816
- if (child.tagName === "EF-CAPTIONS-AFTER-ACTIVE-WORD") return html`<ef-captions-after-word-filmstrip
817
- .element=${child}
818
- .pixelsPerMs=${pixelsPerMs}
819
- .hideSelectors=${hideSelectors}
820
- .showSelectors=${showSelectors}
821
- ></ef-captions-after-word-filmstrip>`;
822
- if (child instanceof EFWaveform) return html`<ef-waveform-filmstrip
823
- .element=${child}
824
- .pixelsPerMs=${pixelsPerMs}
825
- .hideSelectors=${hideSelectors}
826
- .showSelectors=${showSelectors}
827
- ></ef-waveform-filmstrip>`;
828
- return html`<ef-html-filmstrip
829
- .element=${child}
830
- .pixelsPerMs=${pixelsPerMs}
831
- .hideSelectors=${hideSelectors}
832
- .showSelectors=${showSelectors}
833
- ></ef-html-filmstrip>`;
834
- });
835
- };
836
- let EFFilmstrip = class EFFilmstrip$1 extends TWMixin(LitElement) {
837
- constructor(..._args3) {
838
- super(..._args3);
16
+ this.target = "";
839
17
  this.pixelsPerMs = .04;
18
+ this.hidePlayhead = false;
19
+ this.disableInternalScroll = false;
840
20
  this.hide = "";
841
21
  this.show = "";
842
- this.scrubbing = false;
843
- this.capturedPointerId = null;
844
- this.timelineScrolltop = 0;
845
- this.currentTimeMs = 0;
846
- this.autoScale = false;
847
- this.resizeObserver = new ResizeObserver(() => {
848
- if (this.autoScale) this.updatePixelsPerMs();
849
- });
850
- this.gutterRef = createRef();
851
- this.hierarchyRef = createRef();
852
- this.playheadRef = createRef();
853
- this.target = "";
854
22
  this.targetElement = null;
23
+ this.timelineRef = createRef();
855
24
  }
856
- static {
857
- this.styles = [css`
858
- :host {
859
- display: block;
860
- overflow: hidden;
861
- width: 100%;
862
- height: 100%;
863
-
864
- /* Light mode colors */
865
- --filmstrip-bg: rgb(203 213 225); /* slate-300 */
866
- --filmstrip-border: rgb(100 116 139); /* slate-500 */
867
- --filmstrip-item-bg: rgb(191 219 254); /* blue-200 */
868
- --filmstrip-item-focused: rgb(148 163 184); /* slate-400 */
869
- --filmstrip-animation-bg: rgb(59 130 246); /* blue-500 */
870
- --filmstrip-keyframe-bg: rgb(239 68 68); /* red-500 */
871
- --filmstrip-caption-bg: rgb(254 240 138); /* yellow-200 */
872
- --filmstrip-caption-border: rgb(234 179 8); /* yellow-500 */
873
- --filmstrip-segment-bg: rgb(187 247 208); /* green-200 */
874
- --filmstrip-segment-border: rgb(34 197 94); /* green-500 */
875
- --filmstrip-waveform-bg: rgb(250 245 255); /* purple-50 */
876
- --filmstrip-waveform-border: rgb(233 213 255); /* purple-200 */
877
- --filmstrip-timegroup-bg: rgb(226 232 240); /* slate-200 */
878
- --filmstrip-timegroup-hover: rgb(148 163 184); /* slate-400 */
879
- --filmstrip-timegroup-focused: rgb(148 163 184); /* slate-400 */
880
- --filmstrip-gutter-bg: rgb(241 245 249); /* slate-100 */
881
- --filmstrip-timeline-bg: rgb(226 232 240); /* slate-200 */
882
- --filmstrip-playhead: rgb(185 28 28); /* red-700 */
883
- }
884
-
885
- :host(.dark), :host-context(.dark) {
886
- /* Dark mode colors */
887
- --filmstrip-bg: rgb(71 85 105); /* slate-600 */
888
- --filmstrip-border: rgb(148 163 184); /* slate-400 */
889
- --filmstrip-item-bg: rgb(30 64 175); /* blue-800 */
890
- --filmstrip-item-focused: rgb(100 116 139); /* slate-500 */
891
- --filmstrip-animation-bg: rgb(96 165 250); /* blue-400 */
892
- --filmstrip-keyframe-bg: rgb(248 113 113); /* red-400 */
893
- --filmstrip-caption-bg: rgb(133 77 14); /* yellow-800 */
894
- --filmstrip-caption-border: rgb(250 204 21); /* yellow-400 */
895
- --filmstrip-segment-bg: rgb(22 101 52); /* green-800 */
896
- --filmstrip-segment-border: rgb(74 222 128); /* green-400 */
897
- --filmstrip-waveform-bg: rgb(88 28 135); /* purple-900 */
898
- --filmstrip-waveform-border: rgb(126 34 206); /* purple-700 */
899
- --filmstrip-timegroup-bg: rgb(51 65 85); /* slate-700 */
900
- --filmstrip-timegroup-hover: rgb(100 116 139); /* slate-500 */
901
- --filmstrip-timegroup-focused: rgb(100 116 139); /* slate-500 */
902
- --filmstrip-gutter-bg: rgb(30 41 59); /* slate-800 */
903
- --filmstrip-timeline-bg: rgb(51 65 85); /* slate-700 */
904
- --filmstrip-playhead: rgb(239 68 68); /* red-500 */
905
- }
906
- `];
25
+ #targetController;
26
+ #lastTargetTemporal;
27
+ get targetTemporal() {
28
+ const fromTarget = this.targetElement && isEFTemporal(this.targetElement) ? this.targetElement : null;
29
+ const fromContext = this._contextProvidedTemporal;
30
+ if (fromTarget && fromContext && fromTarget !== fromContext) console.warn("EFFilmstrip: Both target attribute and parent context found. Using target attribute.", {
31
+ target: this.target,
32
+ fromTarget,
33
+ fromContext
34
+ });
35
+ return fromTarget ?? fromContext ?? null;
907
36
  }
908
37
  get hideSelectors() {
909
38
  if (!this.hide) return void 0;
@@ -915,280 +44,52 @@ let EFFilmstrip = class EFFilmstrip$1 extends TWMixin(LitElement) {
915
44
  }
916
45
  connectedCallback() {
917
46
  super.connectedCallback();
918
- this.#bindToTargetTimegroup();
919
- window.addEventListener("keypress", this.#handleKeyPress);
920
- this.resizeObserver.observe(this);
921
47
  if (this.target) this.#targetController = new TargetController(this);
922
48
  }
923
- disconnectedCallback() {
924
- super.disconnectedCallback();
925
- window.removeEventListener("keypress", this.#handleKeyPress);
926
- this.resizeObserver.disconnect();
927
- }
928
- updatePixelsPerMs() {
929
- const target = this.targetTemporal;
930
- const gutter = this.gutterRef.value;
931
- if (target && gutter && gutter.clientWidth > 0) this.pixelsPerMs = gutter.clientWidth / (target.durationMs || 1);
932
- }
933
- #bindToTargetTimegroup() {
934
- if (this.timegroupController) this.timegroupController.remove();
935
- const target = this.targetTemporal;
936
- if (target) {
937
- this.timegroupController = new TimegroupController(target, this);
938
- this.currentTimeMs = target.currentTimeMs;
939
- }
940
- }
941
- #handleKeyPress = (event) => {
942
- if (event.key === " ") {
943
- const [target] = event.composedPath();
944
- if (target?.closest("input, textarea, button, select, a, [contenteditable]")) return;
945
- event.preventDefault();
946
- if (this.#contextElement) this.#contextElement.playing = !this.#contextElement.playing;
947
- }
948
- };
949
- syncGutterScroll() {
950
- if (this.gutter && this.hierarchyRef.value) {
951
- this.hierarchyRef.value.scrollTop = this.gutter.scrollTop;
952
- this.timelineScrolltop = this.gutter.scrollTop;
953
- }
954
- }
955
- syncHierarchyScroll() {
956
- if (this.gutter && this.hierarchyRef.value) {
957
- this.gutter.scrollTop = this.hierarchyRef.value.scrollTop;
958
- this.timelineScrolltop = this.hierarchyRef.value.scrollTop;
959
- }
960
- }
961
- scrub(e) {
962
- if (this.playing) return;
963
- if (!this.scrubbing) return;
964
- if (this.capturedPointerId !== null && e.pointerId !== this.capturedPointerId) return;
965
- e.preventDefault();
966
- e.stopPropagation();
967
- this.applyScrub(e);
968
- }
969
- startScrub(e) {
970
- e.preventDefault();
971
- e.stopPropagation();
972
- this.scrubbing = true;
973
- this.capturedPointerId = e.pointerId;
974
- const target = e.currentTarget;
975
- if (target) try {
976
- target.setPointerCapture(e.pointerId);
977
- } catch (err) {
978
- console.warn("Failed to set pointer capture:", err);
979
- }
980
- queueMicrotask(() => {
981
- this.applyScrub(e);
982
- });
983
- const handlePointerUp = (upEvent) => {
984
- if (upEvent.pointerId === this.capturedPointerId) {
985
- upEvent.preventDefault();
986
- upEvent.stopPropagation();
987
- if (target) try {
988
- target.releasePointerCapture(upEvent.pointerId);
989
- } catch (_err) {}
990
- this.capturedPointerId = null;
991
- this.scrubbing = false;
992
- removeEventListener("pointerup", handlePointerUp);
993
- }
994
- };
995
- const handlePointerCancel = (cancelEvent) => {
996
- if (cancelEvent.pointerId === this.capturedPointerId) {
997
- if (target) try {
998
- target.releasePointerCapture(cancelEvent.pointerId);
999
- } catch (_err) {}
1000
- this.capturedPointerId = null;
1001
- this.scrubbing = false;
1002
- removeEventListener("pointercancel", handlePointerCancel);
1003
- }
1004
- };
1005
- addEventListener("pointerup", handlePointerUp, {
1006
- once: true,
1007
- passive: false
1008
- });
1009
- addEventListener("pointercancel", handlePointerCancel, {
1010
- once: true,
1011
- passive: false
1012
- });
1013
- }
1014
- handleContextMenu(e) {
1015
- if (this.scrubbing) {
1016
- e.preventDefault();
1017
- e.stopPropagation();
1018
- }
1019
- }
1020
- applyScrub(e) {
1021
- const gutter = this.shadowRoot?.querySelector("#gutter");
1022
- if (!gutter) return;
1023
- const rect = gutter.getBoundingClientRect();
1024
- if (this.targetTemporal) {
1025
- const scrubTimeMs = (e.pageX - rect.left + gutter.scrollLeft) / this.pixelsPerMs;
1026
- this.targetTemporal.currentTimeMs = scrubTimeMs;
1027
- }
1028
- }
1029
- scrollScrub(e) {
1030
- if (this.targetTemporal && this.gutter && !this.playing) {
1031
- if (e.deltaX !== 0) e.preventDefault();
1032
- if (this.gutterRef.value && this.gutterRef.value.scrollLeft === 0 && e.deltaX < 0) {
1033
- this.gutter.scrollBy(0, e.deltaY);
1034
- return;
1035
- }
1036
- if (this.gutter.scrollWidth - this.gutter.scrollLeft === this.gutter.clientWidth && e.deltaX > 0) {
1037
- this.gutter.scrollBy(0, e.deltaY);
1038
- return;
1039
- }
1040
- if (this) {
1041
- this.gutter.scrollBy(e.deltaX, e.deltaY);
1042
- this.targetTemporal.currentTimeMs += e.deltaX / this.pixelsPerMs;
1043
- }
1044
- }
1045
- }
1046
- get gutter() {
1047
- return this.gutterRef.value;
1048
- }
1049
- render() {
1050
- const target = this.targetTemporal;
1051
- return html` <div
1052
- class="grid h-full"
1053
- style=${styleMap({
1054
- gridTemplateColumns: "200px 1fr",
1055
- gridTemplateRows: "1.5rem 1fr",
1056
- backgroundColor: "var(--filmstrip-gutter-bg)"
1057
- })}
1058
- >
1059
- <div
1060
- class="z-20 col-span-2 shadow"
1061
- style="background-color: var(--filmstrip-gutter-bg); border-bottom-color: var(--filmstrip-border);"
1062
- >
1063
- ${!this.autoScale ? html`<input
1064
- type="range"
1065
- .value=${this.pixelsPerMs}
1066
- min="0.01"
1067
- max="0.1"
1068
- step="0.001"
1069
- @input=${(e) => {
1070
- const target$1 = e.target;
1071
- this.pixelsPerMs = Number.parseFloat(target$1.value);
1072
- }}
1073
- />` : nothing}
1074
- <code>${msToTimeCode(this.currentTimeMs, true)} </code> /
1075
- <code>${msToTimeCode(target?.durationMs ?? 0, true)}</code>
1076
- <ef-toggle-play class="inline-block mx-2">
1077
- <div slot="pause">
1078
- <button>⏸️</button>
1079
- </div>
1080
- <div slot="play">
1081
- <button>▶️</button>
1082
- </div>
1083
- </ef-toggle-play>
1084
- <ef-toggle-loop><button>${this.loop ? "🔁" : html`<span class="opacity-50 line-through">🔁</span>`}</button></ef-toggle-loop>
1085
- </div>
1086
- <div
1087
- class="z-10 pl-1 pr-1 pt-[8px] shadow overflow-auto"
1088
- ${ref(this.hierarchyRef)}
1089
- @scroll=${this.syncHierarchyScroll}
1090
- >
1091
- ${renderHierarchyChildren(target ? [target] : [], this.hideSelectors, this.showSelectors, true)}
1092
- </div>
1093
- <div
1094
- class="flex h-full w-full cursor-crosshair overflow-auto pt-[8px] touch-pan-x"
1095
- style="background-color: var(--filmstrip-timeline-bg);"
1096
- id="gutter"
1097
- ${ref(this.gutterRef)}
1098
- @scroll=${this.syncGutterScroll}
1099
- @wheel=${this.scrollScrub}
1100
- >
1101
- <div
1102
- class="relative h-full w-full touch-none"
1103
- style="width: ${this.pixelsPerMs * (target?.durationMs ?? 0)}px; touch-action: none; user-select: none;"
1104
- @pointermove=${this.scrub}
1105
- @pointerdown=${this.startScrub}
1106
- @contextmenu=${this.handleContextMenu}
1107
- >
1108
- <div
1109
- class="border-red pointer-events-none absolute z-[20] h-full w-[2px] border-r-2"
1110
- style=${styleMap({
1111
- left: `${this.pixelsPerMs * this.currentTimeMs}px`,
1112
- top: `${this.timelineScrolltop}px`,
1113
- borderColor: "var(--filmstrip-playhead)"
1114
- })}
1115
- ${ref(this.playheadRef)}
1116
- ></div>
1117
-
1118
- ${renderFilmstripChildren(target ? [target] : [], this.pixelsPerMs, this.hideSelectors, this.showSelectors, true)}
1119
- </div>
1120
- </div>
1121
- </div>`;
1122
- }
1123
- updated(changes) {
1124
- if (!this.targetTemporal) return;
1125
- if (changes.has("currentTimeMs")) {
1126
- if (this.targetTemporal.currentTimeMs !== this.currentTimeMs) this.targetTemporal.currentTimeMs = this.currentTimeMs;
1127
- }
1128
- }
1129
- get #contextElement() {
1130
- return this.closest("ef-workbench, ef-preview");
1131
- }
1132
- #targetController;
1133
- #lastTargetTemporal;
1134
- get targetTemporal() {
1135
- const fromTarget = this.targetElement && isEFTemporal(this.targetElement) ? this.targetElement : null;
1136
- const fromContext = this._contextProvidedTemporal;
1137
- if (fromTarget && fromContext && fromTarget !== fromContext) console.warn("EFFilmstrip: Both target attribute and parent context found. Using target attribute.", {
1138
- target: this.target,
1139
- fromTarget,
1140
- fromContext
1141
- });
1142
- return fromTarget ?? fromContext ?? null;
1143
- }
1144
49
  willUpdate(changedProperties) {
1145
50
  if (changedProperties.has("target")) {
1146
51
  if (this.target && !this.#targetController) this.#targetController = new TargetController(this);
1147
52
  }
1148
53
  const currentTargetTemporal = this.targetTemporal;
1149
- if (this.#lastTargetTemporal !== currentTargetTemporal) {
1150
- this.#bindToTargetTimegroup();
1151
- this.#lastTargetTemporal = currentTargetTemporal;
1152
- }
1153
- if (this.autoScale) this.updatePixelsPerMs();
54
+ if (this.#lastTargetTemporal !== currentTargetTemporal) this.#lastTargetTemporal = currentTargetTemporal;
1154
55
  super.willUpdate(changedProperties);
1155
56
  }
57
+ render() {
58
+ const targetId = this.targetTemporal ? this.targetTemporal.id || this.target : this.target;
59
+ return html`
60
+ <ef-timeline
61
+ ${ref(this.timelineRef)}
62
+ target=${targetId}
63
+ control-target=${targetId}
64
+ pixels-per-ms=${this.pixelsPerMs}
65
+ ?show-playhead=${!this.hidePlayhead}
66
+ ?show-controls=${false}
67
+ ?show-ruler=${false}
68
+ ?show-hierarchy=${true}
69
+ ?show-playback-controls=${false}
70
+ ?show-zoom-controls=${false}
71
+ ?show-time-display=${false}
72
+ hide=${this.hide}
73
+ show=${this.show}
74
+ ></ef-timeline>
75
+ `;
76
+ }
1156
77
  };
1157
- __decorate([property({ type: Number })], EFFilmstrip.prototype, "pixelsPerMs", void 0);
1158
- __decorate([property({ type: String })], EFFilmstrip.prototype, "hide", void 0);
1159
- __decorate([property({ type: String })], EFFilmstrip.prototype, "show", void 0);
1160
- __decorate([state()], EFFilmstrip.prototype, "scrubbing", void 0);
1161
- __decorate([state()], EFFilmstrip.prototype, "timelineScrolltop", void 0);
1162
- __decorate([consume({
1163
- context: playingContext,
1164
- subscribe: true
1165
- }), state()], EFFilmstrip.prototype, "playing", void 0);
1166
- __decorate([consume({
1167
- context: loopContext,
1168
- subscribe: true
1169
- }), state()], EFFilmstrip.prototype, "loop", void 0);
1170
- __decorate([state()], EFFilmstrip.prototype, "currentTimeMs", void 0);
78
+ __decorate([property({ type: String })], EFFilmstrip.prototype, "target", void 0);
79
+ __decorate([property({
80
+ type: Number,
81
+ attribute: "pixels-per-ms"
82
+ })], EFFilmstrip.prototype, "pixelsPerMs", void 0);
1171
83
  __decorate([property({
1172
84
  type: Boolean,
1173
- reflect: true,
1174
- attribute: "auto-scale"
1175
- })], EFFilmstrip.prototype, "autoScale", void 0);
1176
- __decorate([eventOptions({ passive: false })], EFFilmstrip.prototype, "syncGutterScroll", null);
1177
- __decorate([eventOptions({ passive: false })], EFFilmstrip.prototype, "syncHierarchyScroll", null);
1178
- __decorate([eventOptions({
1179
- capture: false,
1180
- passive: false
1181
- })], EFFilmstrip.prototype, "scrub", null);
1182
- __decorate([eventOptions({
1183
- capture: false,
1184
- passive: false
1185
- })], EFFilmstrip.prototype, "startScrub", null);
1186
- __decorate([eventOptions({
1187
- passive: false,
1188
- capture: false
1189
- })], EFFilmstrip.prototype, "handleContextMenu", null);
1190
- __decorate([eventOptions({ passive: false })], EFFilmstrip.prototype, "scrollScrub", null);
1191
- __decorate([property({ type: String })], EFFilmstrip.prototype, "target", void 0);
85
+ attribute: "hide-playhead"
86
+ })], EFFilmstrip.prototype, "hidePlayhead", void 0);
87
+ __decorate([property({
88
+ type: Boolean,
89
+ attribute: "disable-internal-scroll"
90
+ })], EFFilmstrip.prototype, "disableInternalScroll", void 0);
91
+ __decorate([property({ type: String })], EFFilmstrip.prototype, "hide", void 0);
92
+ __decorate([property({ type: String })], EFFilmstrip.prototype, "show", void 0);
1192
93
  __decorate([state()], EFFilmstrip.prototype, "targetElement", void 0);
1193
94
  __decorate([consume({
1194
95
  context: targetTemporalContext,