@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionModel.js","names":[],"sources":["../../../src/canvas/selection/SelectionModel.ts"],"sourcesContent":["import type { SelectionState } from \"../api/types.js\";\n\n/**\n * Create a DOMRect-like object. Polyfill for Node.js environments.\n */\nfunction createRect(\n x: number,\n y: number,\n width: number,\n height: number,\n): DOMRect {\n if (typeof DOMRect !== \"undefined\") {\n return new DOMRect(x, y, width, height);\n }\n // Polyfill for Node.js\n return {\n x,\n y,\n width,\n height,\n left: x,\n top: y,\n right: x + width,\n bottom: y + height,\n toJSON: () => ({ x, y, width, height }),\n } as DOMRect;\n}\n\n/**\n * Pure selection logic - semantics separate from mechanism.\n * Manages selection state and operations.\n */\nexport class SelectionModel extends EventTarget {\n private _selectedIds = new Set<string>();\n private _primaryId: string | null = null;\n private _selectionMode: SelectionState = \"none\";\n private _boxSelectStart: { x: number; y: number } | null = null;\n private _boxSelectCurrent: { x: number; y: number } | null = null;\n private _groups = new Map<string, Set<string>>();\n private _elementToGroup = new Map<string, string>();\n\n /**\n * Emit selectionchange event with current selection state.\n */\n private _emitSelectionChange(): void {\n // Convert Set to array with primary first\n const selectedIdsArray =\n this._primaryId && this._selectedIds.has(this._primaryId)\n ? [\n this._primaryId,\n ...Array.from(this._selectedIds).filter(\n (id) => id !== this._primaryId,\n ),\n ]\n : Array.from(this._selectedIds);\n\n this.dispatchEvent(\n new CustomEvent(\"selectionchange\", {\n detail: {\n selectedIds: selectedIdsArray,\n selectionMode: this._selectionMode,\n },\n bubbles: false,\n composed: false,\n }),\n );\n }\n\n /**\n * Get current selection state.\n */\n get selectedIds(): ReadonlySet<string> {\n return this._selectedIds;\n }\n\n /**\n * Get current selection mode.\n */\n get selectionMode(): SelectionState {\n return this._selectionMode;\n }\n\n /**\n * Get current box selection bounds, if active.\n */\n get boxSelectBounds(): DOMRect | null {\n if (!this._boxSelectStart || !this._boxSelectCurrent) {\n return null;\n }\n const left = Math.min(this._boxSelectStart.x, this._boxSelectCurrent.x);\n const top = Math.min(this._boxSelectStart.y, this._boxSelectCurrent.y);\n const right = Math.max(this._boxSelectStart.x, this._boxSelectCurrent.x);\n const bottom = Math.max(this._boxSelectStart.y, this._boxSelectCurrent.y);\n return createRect(left, top, right - left, bottom - top);\n }\n\n /**\n * Select a single element.\n */\n select(id: string): void {\n this._selectedIds.clear();\n this._selectedIds.add(id);\n this._primaryId = id;\n this._selectionMode = \"single\";\n this._emitSelectionChange();\n }\n\n /**\n * Select multiple elements.\n */\n selectMultiple(ids: string[]): void {\n this._selectedIds.clear();\n for (const id of ids) {\n this._selectedIds.add(id);\n }\n this._primaryId = ids.length > 0 ? (ids[0] ?? null) : null;\n this._selectionMode =\n ids.length === 0 ? \"none\" : ids.length === 1 ? \"single\" : \"multiple\";\n this._emitSelectionChange();\n }\n\n /**\n * Add element to selection (for multi-select).\n */\n addToSelection(id: string): void {\n this._selectedIds.add(id);\n if (!this._primaryId) {\n this._primaryId = id;\n }\n this._updateSelectionMode();\n this._emitSelectionChange();\n }\n\n /**\n * Remove element from selection.\n */\n deselect(id: string): void {\n this._selectedIds.delete(id);\n if (this._primaryId === id) {\n // Set primary to first remaining, or null if none\n const remaining = Array.from(this._selectedIds);\n this._primaryId = remaining.length > 0 ? (remaining[0] ?? null) : null;\n }\n this._updateSelectionMode();\n this._emitSelectionChange();\n }\n\n /**\n * Toggle element selection state.\n */\n toggle(id: string): void {\n if (this._selectedIds.has(id)) {\n this.deselect(id);\n } else {\n this.addToSelection(id);\n }\n }\n\n /**\n * Clear all selections.\n */\n clear(): void {\n this._selectedIds.clear();\n this._primaryId = null;\n this._selectionMode = \"none\";\n this._boxSelectStart = null;\n this._boxSelectCurrent = null;\n this._emitSelectionChange();\n }\n\n /**\n * Start box selection.\n */\n startBoxSelect(x: number, y: number): void {\n this._boxSelectStart = { x, y };\n this._boxSelectCurrent = { x, y };\n this._selectionMode = \"box-selecting\";\n }\n\n /**\n * Update box selection.\n */\n updateBoxSelect(x: number, y: number): void {\n if (this._selectionMode !== \"box-selecting\") {\n return;\n }\n this._boxSelectCurrent = { x, y };\n }\n\n /**\n * End box selection and select elements within bounds.\n * @param hitTest - Function to find elements within bounds\n * @param addToSelection - If true, add to existing selection; if false, replace selection\n */\n endBoxSelect(\n hitTest: (bounds: DOMRect) => string[],\n addToSelection = false,\n ): void {\n if (\n this._selectionMode !== \"box-selecting\" ||\n !this._boxSelectStart ||\n !this._boxSelectCurrent\n ) {\n return;\n }\n const bounds = this.boxSelectBounds;\n if (bounds) {\n const ids = hitTest(bounds);\n if (addToSelection) {\n // Add each element to selection\n for (const id of ids) {\n this.addToSelection(id);\n }\n } else {\n // Replace selection\n this.selectMultiple(ids);\n }\n }\n this._boxSelectStart = null;\n this._boxSelectCurrent = null;\n // Note: selectMultiple/addToSelection already emit events, so no need to emit again\n }\n\n /**\n * Create a group from selected elements.\n */\n createGroup(ids: string[]): string {\n if (ids.length === 0) {\n throw new Error(\"Cannot create group with no elements\");\n }\n const groupId = `group-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n const groupSet = new Set(ids);\n this._groups.set(groupId, groupSet);\n for (const id of ids) {\n this._elementToGroup.set(id, groupId);\n }\n return groupId;\n }\n\n /**\n * Ungroup a group.\n */\n ungroup(groupId: string): void {\n const group = this._groups.get(groupId);\n if (!group) {\n return;\n }\n for (const id of group) {\n this._elementToGroup.delete(id);\n }\n this._groups.delete(groupId);\n }\n\n /**\n * Select all elements in a group.\n */\n selectGroup(groupId: string): void {\n const group = this._groups.get(groupId);\n if (!group) {\n return;\n }\n this.selectMultiple(Array.from(group));\n // Note: selectMultiple already emits event\n }\n\n /**\n * Get group ID for an element, if any.\n */\n getGroupId(elementId: string): string | undefined {\n return this._elementToGroup.get(elementId);\n }\n\n /**\n * Get all element IDs in a group.\n */\n getGroupElements(groupId: string): string[] {\n const group = this._groups.get(groupId);\n return group ? Array.from(group) : [];\n }\n\n /**\n * Update selection mode based on current selection count.\n */\n private _updateSelectionMode(): void {\n const count = this._selectedIds.size;\n if (count === 0) {\n this._selectionMode = \"none\";\n } else if (count === 1) {\n this._selectionMode = \"single\";\n } else {\n this._selectionMode = \"multiple\";\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { SelectionState } from "../api/types.js";
2
+
3
+ //#region src/canvas/selection/selectionContext.d.ts
4
+
5
+ /**
6
+ * Selection context interface for Lit context.
7
+ */
8
+ interface SelectionContext {
9
+ selectedIds: ReadonlySet<string>;
10
+ selectionMode: SelectionState;
11
+ boxSelectBounds: DOMRect | null;
12
+ select: (id: string) => void;
13
+ selectMultiple: (ids: string[]) => void;
14
+ addToSelection: (id: string) => void;
15
+ deselect: (id: string) => void;
16
+ toggle: (id: string) => void;
17
+ clear: () => void;
18
+ startBoxSelect: (x: number, y: number) => void;
19
+ updateBoxSelect: (x: number, y: number) => void;
20
+ endBoxSelect: (hitTest: (bounds: DOMRect) => string[], addToSelection?: boolean) => void;
21
+ createGroup: (ids: string[]) => string;
22
+ ungroup: (groupId: string) => void;
23
+ selectGroup: (groupId: string) => void;
24
+ getGroupId: (elementId: string) => string | undefined;
25
+ getGroupElements: (groupId: string) => string[];
26
+ addEventListener: (type: "selectionchange", listener: (event: CustomEvent) => void) => void;
27
+ removeEventListener: (type: "selectionchange", listener: (event: CustomEvent) => void) => void;
28
+ }
29
+ //#endregion
30
+ export { SelectionContext };
31
+ //# sourceMappingURL=selectionContext.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { createContext } from "@lit/context";
2
+
3
+ //#region src/canvas/selection/selectionContext.ts
4
+ /**
5
+ * Lit context for selection state.
6
+ * Provided by EFCanvas, consumed by child elements.
7
+ */
8
+ const selectionContext = createContext(Symbol("selectionContext"));
9
+
10
+ //#endregion
11
+ export { selectionContext };
12
+ //# sourceMappingURL=selectionContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectionContext.js","names":[],"sources":["../../../src/canvas/selection/selectionContext.ts"],"sourcesContent":["import { createContext } from \"@lit/context\";\nimport type { SelectionState } from \"../api/types.js\";\n\n/**\n * Selection context interface for Lit context.\n */\nexport interface SelectionContext {\n selectedIds: ReadonlySet<string>;\n selectionMode: SelectionState;\n boxSelectBounds: DOMRect | null;\n select: (id: string) => void;\n selectMultiple: (ids: string[]) => void;\n addToSelection: (id: string) => void;\n deselect: (id: string) => void;\n toggle: (id: string) => void;\n clear: () => void;\n startBoxSelect: (x: number, y: number) => void;\n updateBoxSelect: (x: number, y: number) => void;\n endBoxSelect: (\n hitTest: (bounds: DOMRect) => string[],\n addToSelection?: boolean,\n ) => void;\n createGroup: (ids: string[]) => string;\n ungroup: (groupId: string) => void;\n selectGroup: (groupId: string) => void;\n getGroupId: (elementId: string) => string | undefined;\n getGroupElements: (groupId: string) => string[];\n addEventListener: (\n type: \"selectionchange\",\n listener: (event: CustomEvent) => void,\n ) => void;\n removeEventListener: (\n type: \"selectionchange\",\n listener: (event: CustomEvent) => void,\n ) => void;\n}\n\n/**\n * Lit context for selection state.\n * Provided by EFCanvas, consumed by child elements.\n */\nexport const selectionContext = createContext<SelectionContext>(\n Symbol(\"selectionContext\"),\n);\n"],"mappings":";;;;;;;AAyCA,MAAa,mBAAmB,cAC9B,OAAO,mBAAmB,CAC3B"}
@@ -0,0 +1,29 @@
1
+ //#region src/elements/ContainerInfo.d.ts
2
+ /**
3
+ * Container information interface for elements that can contain children.
4
+ * Provides information about container capabilities and display mode.
5
+ */
6
+ interface ContainerInfo {
7
+ /**
8
+ * Whether this element is a container that can contain children.
9
+ */
10
+ isContainer: boolean;
11
+ /**
12
+ * The display mode of the container.
13
+ * "flex" | "grid" | "block" | null
14
+ */
15
+ displayMode: "flex" | "grid" | "block" | null;
16
+ /**
17
+ * Whether this container can contain children.
18
+ * This may differ from isContainer if the container is not configured to accept children.
19
+ */
20
+ canContainChildren: boolean;
21
+ }
22
+ /**
23
+ * Helper function to get container info from any HTMLElement.
24
+ * Reads computed styles to determine display mode.
25
+ */
26
+ declare function getContainerInfoFromElement(element: HTMLElement | null): ContainerInfo;
27
+ //#endregion
28
+ export { ContainerInfo, getContainerInfoFromElement };
29
+ //# sourceMappingURL=ContainerInfo.d.ts.map
@@ -0,0 +1,30 @@
1
+ //#region src/elements/ContainerInfo.ts
2
+ /**
3
+ * Helper function to get container info from any HTMLElement.
4
+ * Reads computed styles to determine display mode.
5
+ */
6
+ function getContainerInfoFromElement(element) {
7
+ if (!element) return {
8
+ isContainer: false,
9
+ displayMode: null,
10
+ canContainChildren: false
11
+ };
12
+ const display = window.getComputedStyle(element).display;
13
+ const isGrid = display === "grid" || display === "inline-grid";
14
+ const isFlex = display === "flex" || display === "inline-flex";
15
+ const isBlock = display === "block" || display === "inline-block";
16
+ const isContainer = isGrid || isFlex || isBlock;
17
+ let displayMode = null;
18
+ if (isFlex) displayMode = "flex";
19
+ else if (isGrid) displayMode = "grid";
20
+ else if (isBlock) displayMode = "block";
21
+ return {
22
+ isContainer,
23
+ displayMode,
24
+ canContainChildren: isContainer
25
+ };
26
+ }
27
+
28
+ //#endregion
29
+ export { getContainerInfoFromElement };
30
+ //# sourceMappingURL=ContainerInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContainerInfo.js","names":["displayMode: \"flex\" | \"grid\" | \"block\" | null"],"sources":["../../src/elements/ContainerInfo.ts"],"sourcesContent":["/**\n * Container information interface for elements that can contain children.\n * Provides information about container capabilities and display mode.\n */\n\nexport interface ContainerInfo {\n /**\n * Whether this element is a container that can contain children.\n */\n isContainer: boolean;\n\n /**\n * The display mode of the container.\n * \"flex\" | \"grid\" | \"block\" | null\n */\n displayMode: \"flex\" | \"grid\" | \"block\" | null;\n\n /**\n * Whether this container can contain children.\n * This may differ from isContainer if the container is not configured to accept children.\n */\n canContainChildren: boolean;\n}\n\n/**\n * Helper function to get container info from any HTMLElement.\n * Reads computed styles to determine display mode.\n */\nexport function getContainerInfoFromElement(\n element: HTMLElement | null,\n): ContainerInfo {\n if (!element) {\n return {\n isContainer: false,\n displayMode: null,\n canContainChildren: false,\n };\n }\n\n const computedStyle = window.getComputedStyle(element);\n const display = computedStyle.display;\n\n // Determine if it's a container (grid or flex)\n const isGrid = display === \"grid\" || display === \"inline-grid\";\n const isFlex = display === \"flex\" || display === \"inline-flex\";\n const isBlock = display === \"block\" || display === \"inline-block\";\n\n const isContainer = isGrid || isFlex || isBlock;\n\n let displayMode: \"flex\" | \"grid\" | \"block\" | null = null;\n if (isFlex) {\n displayMode = \"flex\";\n } else if (isGrid) {\n displayMode = \"grid\";\n } else if (isBlock) {\n displayMode = \"block\";\n }\n\n return {\n isContainer,\n displayMode,\n canContainChildren: isContainer,\n };\n}\n"],"mappings":";;;;;AA4BA,SAAgB,4BACd,SACe;AACf,KAAI,CAAC,QACH,QAAO;EACL,aAAa;EACb,aAAa;EACb,oBAAoB;EACrB;CAIH,MAAM,UADgB,OAAO,iBAAiB,QAAQ,CACxB;CAG9B,MAAM,SAAS,YAAY,UAAU,YAAY;CACjD,MAAM,SAAS,YAAY,UAAU,YAAY;CACjD,MAAM,UAAU,YAAY,WAAW,YAAY;CAEnD,MAAM,cAAc,UAAU,UAAU;CAExC,IAAIA,cAAgD;AACpD,KAAI,OACF,eAAc;UACL,OACT,eAAc;UACL,QACT,eAAc;AAGhB,QAAO;EACL;EACA;EACA,oBAAoB;EACrB"}
@@ -2,15 +2,25 @@ import { MediaEngine } from "../transcoding/types/index.js";
2
2
  import { EFMedia } from "./EFMedia.js";
3
3
  import * as _lit_task8 from "@lit/task";
4
4
  import { Task } from "@lit/task";
5
- import * as lit_html6 from "lit-html";
5
+ import * as lit_html1 from "lit-html";
6
6
  import * as lit_html_directives_ref_js1 from "lit-html/directives/ref.js";
7
7
 
8
8
  //#region src/elements/EFAudio.d.ts
9
9
  declare const EFAudio_base: typeof EFMedia;
10
10
  declare class EFAudio extends EFAudio_base {
11
- private _propertyHack;
11
+ /**
12
+ * EFAudio only requires audio tracks - skip video track validation
13
+ * to avoid unnecessary network requests to transcoding service.
14
+ */
15
+ get requiredTracks(): "audio" | "video" | "both";
16
+ /**
17
+ * Audio volume level (0.0 to 1.0)
18
+ * @domAttribute "volume"
19
+ */
20
+ volume: number;
12
21
  audioElementRef: lit_html_directives_ref_js1.Ref<HTMLAudioElement>;
13
- render(): lit_html6.TemplateResult<1>;
22
+ protected updated(changedProperties: Map<PropertyKey, unknown>): void;
23
+ render(): lit_html1.TemplateResult<1>;
14
24
  frameTask: Task<readonly [_lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus], void>;
15
25
  /**
16
26
  * Legacy getter for fragment index task (maps to audioSegmentIdTask)
@@ -11,7 +11,7 @@ import { createRef, ref } from "lit/directives/ref.js";
11
11
  let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
12
12
  constructor(..._args) {
13
13
  super(..._args);
14
- this._propertyHack = false;
14
+ this.volume = 1;
15
15
  this.audioElementRef = createRef();
16
16
  this.frameTask = new Task(this, {
17
17
  autoRun: EF_INTERACTIVE,
@@ -21,15 +21,68 @@ let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
21
21
  this.audioSegmentFetchTask.status,
22
22
  this.mediaEngineTask.status
23
23
  ],
24
- task: async () => {
25
- await this.mediaEngineTask.taskComplete;
26
- await this.audioSegmentFetchTask.taskComplete;
27
- await this.audioSeekTask.taskComplete;
28
- await this.audioBufferTask.taskComplete;
29
- this.rootTimegroup?.requestUpdate();
24
+ onError: (error) => {
25
+ this.frameTask.taskComplete.catch(() => {});
26
+ if (error instanceof DOMException && error.name === "AbortError" || error instanceof Error && (error.name === "AbortError" || error.message?.includes("signal is aborted") || error.message?.includes("The user aborted a request"))) return;
27
+ console.error("EFAudio frameTask error", error);
28
+ },
29
+ task: async ([_audioBufferStatus, _audioSeekStatus, _audioSegmentFetchStatus, _mediaEngineStatus], { signal }) => {
30
+ try {
31
+ await this.mediaEngineTask.taskComplete;
32
+ } catch (error) {
33
+ if (error instanceof DOMException && error.name === "AbortError") {
34
+ signal?.throwIfAborted();
35
+ return;
36
+ }
37
+ throw error;
38
+ }
39
+ signal?.throwIfAborted();
40
+ try {
41
+ await this.audioSegmentFetchTask.taskComplete;
42
+ } catch (error) {
43
+ if (error instanceof DOMException && error.name === "AbortError") {
44
+ signal?.throwIfAborted();
45
+ return;
46
+ }
47
+ throw error;
48
+ }
49
+ signal?.throwIfAborted();
50
+ try {
51
+ await this.audioSeekTask.taskComplete;
52
+ } catch (error) {
53
+ if (error instanceof DOMException && error.name === "AbortError") {
54
+ signal?.throwIfAborted();
55
+ return;
56
+ }
57
+ throw error;
58
+ }
59
+ signal?.throwIfAborted();
60
+ try {
61
+ await this.audioBufferTask.taskComplete;
62
+ } catch (error) {
63
+ if (error instanceof DOMException && error.name === "AbortError") {
64
+ signal?.throwIfAborted();
65
+ return;
66
+ }
67
+ throw error;
68
+ }
69
+ signal?.throwIfAborted();
30
70
  }
31
71
  });
32
72
  }
73
+ /**
74
+ * EFAudio only requires audio tracks - skip video track validation
75
+ * to avoid unnecessary network requests to transcoding service.
76
+ */
77
+ get requiredTracks() {
78
+ return "audio";
79
+ }
80
+ updated(changedProperties) {
81
+ super.updated(changedProperties);
82
+ if (this.audioElementRef.value) {
83
+ if (changedProperties.has("volume") || changedProperties.size === 0) this.audioElementRef.value.volume = this.volume;
84
+ }
85
+ }
33
86
  render() {
34
87
  return html`<audio ${ref(this.audioElementRef)}></audio>`;
35
88
  }
@@ -42,9 +95,10 @@ let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
42
95
  }
43
96
  };
44
97
  __decorate([property({
45
- type: Boolean,
46
- attribute: "dummy-property"
47
- })], EFAudio.prototype, "_propertyHack", void 0);
98
+ type: Number,
99
+ attribute: "volume",
100
+ reflect: true
101
+ })], EFAudio.prototype, "volume", void 0);
48
102
  EFAudio = __decorate([customElement("ef-audio")], EFAudio);
49
103
 
50
104
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"EFAudio.js","names":["EFAudio"],"sources":["../../src/elements/EFAudio.ts"],"sourcesContent":["import { Task } from \"@lit/task\";\nimport { html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { EFMedia } from \"./EFMedia.js\";\n\n@customElement(\"ef-audio\")\nexport class EFAudio extends TWMixin(EFMedia) {\n // HACK: This dummy property is needed to activate Lit's property processing system\n // Without it, inherited properties from EFMedia don't work correctly\n // TODO: Remove this as soon as we have an audio-specific property that needs @property\n @property({ type: Boolean, attribute: \"dummy-property\" })\n // @ts-expect-error - This is a hack to activate Lit's property processing system\n // biome-ignore lint/correctness/noUnusedPrivateClassMembers: Used to activate Lit's property processing\n private _propertyHack = false;\n\n audioElementRef = createRef<HTMLAudioElement>();\n\n render() {\n return html`<audio ${ref(this.audioElementRef)}></audio>`;\n }\n\n frameTask = new Task(this, {\n autoRun: EF_INTERACTIVE,\n args: () =>\n [\n this.audioBufferTask.status,\n this.audioSeekTask.status,\n this.audioSegmentFetchTask.status,\n this.mediaEngineTask.status,\n ] as const,\n task: async () => {\n await this.mediaEngineTask.taskComplete;\n await this.audioSegmentFetchTask.taskComplete;\n await this.audioSeekTask.taskComplete;\n await this.audioBufferTask.taskComplete;\n this.rootTimegroup?.requestUpdate();\n },\n });\n\n /**\n * Legacy getter for fragment index task (maps to audioSegmentIdTask)\n * Still used by EFCaptions\n */\n get fragmentIndexTask() {\n return this.audioSegmentIdTask;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-audio\": EFAudio;\n }\n}\n"],"mappings":";;;;;;;;;;AASO,oBAAMA,kBAAgB,QAAQ,QAAQ,CAAC;;;uBAOpB;yBAEN,WAA6B;mBAMnC,IAAI,KAAK,MAAM;GACzB,SAAS;GACT,YACE;IACE,KAAK,gBAAgB;IACrB,KAAK,cAAc;IACnB,KAAK,sBAAsB;IAC3B,KAAK,gBAAgB;IACtB;GACH,MAAM,YAAY;AAChB,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,sBAAsB;AACjC,UAAM,KAAK,cAAc;AACzB,UAAM,KAAK,gBAAgB;AAC3B,SAAK,eAAe,eAAe;;GAEtC,CAAC;;CApBF,SAAS;AACP,SAAO,IAAI,UAAU,IAAI,KAAK,gBAAgB,CAAC;;;;;;CAyBjD,IAAI,oBAAoB;AACtB,SAAO,KAAK;;;YAlCb,SAAS;CAAE,MAAM;CAAS,WAAW;CAAkB,CAAC;sBAL1D,cAAc,WAAW"}
1
+ {"version":3,"file":"EFAudio.js","names":["EFAudio"],"sources":["../../src/elements/EFAudio.ts"],"sourcesContent":["import { Task } from \"@lit/task\";\nimport { html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { EFMedia } from \"./EFMedia.js\";\n\n@customElement(\"ef-audio\")\nexport class EFAudio extends TWMixin(EFMedia) {\n /**\n * EFAudio only requires audio tracks - skip video track validation\n * to avoid unnecessary network requests to transcoding service.\n */\n override get requiredTracks(): \"audio\" | \"video\" | \"both\" {\n return \"audio\";\n }\n\n /**\n * Audio volume level (0.0 to 1.0)\n * @domAttribute \"volume\"\n */\n @property({ type: Number, attribute: \"volume\", reflect: true })\n volume = 1.0;\n\n audioElementRef = createRef<HTMLAudioElement>();\n\n protected updated(\n changedProperties: Map<PropertyKey, unknown>,\n ): void {\n super.updated(changedProperties);\n \n // Sync volume property to HTMLAudioElement whenever it changes or element is first rendered\n if (this.audioElementRef.value) {\n if (changedProperties.has(\"volume\") || changedProperties.size === 0) {\n this.audioElementRef.value.volume = this.volume;\n }\n }\n }\n\n render() {\n return html`<audio ${ref(this.audioElementRef)}></audio>`;\n }\n\n frameTask = new Task(this, {\n autoRun: EF_INTERACTIVE,\n args: () =>\n [\n this.audioBufferTask.status,\n this.audioSeekTask.status,\n this.audioSegmentFetchTask.status,\n this.mediaEngineTask.status,\n ] as const,\n onError: (error) => {\n // CRITICAL: Attach .catch() handler to taskComplete BEFORE the promise is rejected.\n // This prevents unhandled rejection when hostUpdate() triggers _performTask() without awaiting.\n this.frameTask.taskComplete.catch(() => {});\n \n // Don't log AbortErrors - these are expected when tasks are cancelled\n const isAbortError = \n (error instanceof DOMException && error.name === \"AbortError\") ||\n (error instanceof Error && (\n error.name === \"AbortError\" ||\n error.message?.includes(\"signal is aborted\") ||\n error.message?.includes(\"The user aborted a request\")\n ));\n \n if (isAbortError) {\n return;\n }\n \n console.error(\"EFAudio frameTask error\", error);\n },\n task: async ([_audioBufferStatus, _audioSeekStatus, _audioSegmentFetchStatus, _mediaEngineStatus], { signal }) => {\n // Wrap all taskComplete awaits in try/catch to handle AbortErrors\n try {\n await this.mediaEngineTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioSegmentFetchTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioSeekTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioBufferTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n // REMOVED: this.rootTimegroup?.requestUpdate() was causing infinite update loops.\n // When EFAudio's frameTask ran, it would trigger root to update, which triggered\n // OwnCurrentTimeController.hostUpdated on all children, which triggered more\n // frameTask runs, creating an infinite cycle.\n // The root timegroup already updates when currentTime changes - no need to force it here.\n },\n });\n\n /**\n * Legacy getter for fragment index task (maps to audioSegmentIdTask)\n * Still used by EFCaptions\n */\n get fragmentIndexTask() {\n return this.audioSegmentIdTask;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-audio\": EFAudio;\n }\n}\n"],"mappings":";;;;;;;;;;AASO,oBAAMA,kBAAgB,QAAQ,QAAQ,CAAC;;;gBAcnC;yBAES,WAA6B;mBAmBnC,IAAI,KAAK,MAAM;GACzB,SAAS;GACT,YACE;IACE,KAAK,gBAAgB;IACrB,KAAK,cAAc;IACnB,KAAK,sBAAsB;IAC3B,KAAK,gBAAgB;IACtB;GACH,UAAU,UAAU;AAGlB,SAAK,UAAU,aAAa,YAAY,GAAG;AAW3C,QAPG,iBAAiB,gBAAgB,MAAM,SAAS,gBAChD,iBAAiB,UAChB,MAAM,SAAS,gBACf,MAAM,SAAS,SAAS,oBAAoB,IAC5C,MAAM,SAAS,SAAS,6BAA6B,EAIvD;AAGF,YAAQ,MAAM,2BAA2B,MAAM;;GAEjD,MAAM,OAAO,CAAC,oBAAoB,kBAAkB,0BAA0B,qBAAqB,EAAE,aAAa;AAEhH,QAAI;AACF,WAAM,KAAK,gBAAgB;aACpB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,sBAAsB;aAC1B,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,cAAc;aAClB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,gBAAgB;aACpB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;;GAO3B,CAAC;;;;;;CA9GF,IAAa,iBAA6C;AACxD,SAAO;;CAYT,AAAU,QACR,mBACM;AACN,QAAM,QAAQ,kBAAkB;AAGhC,MAAI,KAAK,gBAAgB,OACvB;OAAI,kBAAkB,IAAI,SAAS,IAAI,kBAAkB,SAAS,EAChE,MAAK,gBAAgB,MAAM,SAAS,KAAK;;;CAK/C,SAAS;AACP,SAAO,IAAI,UAAU,IAAI,KAAK,gBAAgB,CAAC;;;;;;CAyFjD,IAAI,oBAAoB;AACtB,SAAO,KAAK;;;YA7Gb,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAU,SAAS;CAAM,CAAC;sBAdhE,cAAc,WAAW"}
@@ -1,12 +1,12 @@
1
- import { TemporalMixinInterface } from "./EFTemporal.js";
2
1
  import { EFSourceMixinInterface } from "./EFSourceMixin.js";
2
+ import { TemporalMixinInterface } from "./EFTemporal.js";
3
3
  import { FetchMixinInterface } from "./FetchMixin.js";
4
- import { EFAudio } from "./EFAudio.js";
5
4
  import { EFVideo } from "./EFVideo.js";
5
+ import { EFAudio } from "./EFAudio.js";
6
6
  import { Task, TaskStatus } from "@lit/task";
7
- import * as lit1 from "lit";
7
+ import * as lit3 from "lit";
8
8
  import { LitElement, PropertyValueMap } from "lit";
9
- import * as lit_html1 from "lit-html";
9
+ import * as lit_html3 from "lit-html";
10
10
 
11
11
  //#region src/elements/EFCaptions.d.ts
12
12
  interface WordSegment {
@@ -25,8 +25,8 @@ interface Caption {
25
25
  }
26
26
  declare const EFCaptionsActiveWord_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
27
27
  declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
28
- static styles: lit1.CSSResult[];
29
- render(): lit_html1.TemplateResult<1> | undefined;
28
+ static styles: lit3.CSSResult[];
29
+ render(): lit_html3.TemplateResult<1> | undefined;
30
30
  wordStartMs: number;
31
31
  wordEndMs: number;
32
32
  wordText: string;
@@ -38,8 +38,8 @@ declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
38
38
  }
39
39
  declare const EFCaptionsSegment_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
40
40
  declare class EFCaptionsSegment extends EFCaptionsSegment_base {
41
- static styles: lit1.CSSResult[];
42
- render(): lit_html1.TemplateResult<1> | undefined;
41
+ static styles: lit3.CSSResult[];
42
+ render(): lit_html3.TemplateResult<1> | undefined;
43
43
  segmentStartMs: number;
44
44
  segmentEndMs: number;
45
45
  segmentText: string;
@@ -49,8 +49,8 @@ declare class EFCaptionsSegment extends EFCaptionsSegment_base {
49
49
  get durationMs(): number;
50
50
  }
51
51
  declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
52
- static styles: lit1.CSSResult[];
53
- render(): lit_html1.TemplateResult<1> | undefined;
52
+ static styles: lit3.CSSResult[];
53
+ render(): lit_html3.TemplateResult<1> | undefined;
54
54
  hidden: boolean;
55
55
  segmentText: string;
56
56
  segmentStartMs: number;
@@ -60,8 +60,8 @@ declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
60
60
  get durationMs(): number;
61
61
  }
62
62
  declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
63
- static styles: lit1.CSSResult[];
64
- render(): lit_html1.TemplateResult<1> | undefined;
63
+ static styles: lit3.CSSResult[];
64
+ render(): lit_html3.TemplateResult<1> | undefined;
65
65
  hidden: boolean;
66
66
  segmentText: string;
67
67
  segmentStartMs: number;
@@ -72,7 +72,8 @@ declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
72
72
  }
73
73
  declare const EFCaptions_base: (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
74
74
  declare class EFCaptions extends EFCaptions_base {
75
- static styles: lit1.CSSResult[];
75
+ #private;
76
+ static styles: lit3.CSSResult[];
76
77
  targetSelector: string;
77
78
  set target(value: string);
78
79
  wordStyle: string;
@@ -95,10 +96,10 @@ declare class EFCaptions extends EFCaptions_base {
95
96
  segmentContainers: HTMLCollectionOf<EFCaptionsSegment>;
96
97
  beforeActiveWordContainers: HTMLCollectionOf<EFCaptionsBeforeActiveWord>;
97
98
  afterActiveWordContainers: HTMLCollectionOf<EFCaptionsAfterActiveWord>;
98
- render(): lit_html1.TemplateResult<1>;
99
+ render(): lit_html3.TemplateResult<1>;
99
100
  transcriptionsPath(): string | null;
100
101
  captionsPath(): string | null;
101
- protected md5SumLoader: Task<readonly [string, typeof fetch], string | null | undefined>;
102
+ protected md5SumLoader: Task<readonly [string, typeof fetch], any>;
102
103
  private transcriptionDataTask;
103
104
  private transcriptionFragmentPath;
104
105
  private fragmentIndexTask;
@@ -107,6 +108,7 @@ declare class EFCaptions extends EFCaptions_base {
107
108
  unifiedCaptionsDataTask: Task<readonly [Caption | null | undefined, Caption | null | undefined], Caption | null | undefined>;
108
109
  frameTask: Task<readonly [TaskStatus, number], void>;
109
110
  connectedCallback(): void;
111
+ disconnectedCallback(): void;
110
112
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
111
113
  updateTextContainers(): void;
112
114
  get targetElement(): EFAudio | EFVideo | null;
@@ -124,5 +126,5 @@ declare global {
124
126
  }
125
127
  }
126
128
  //#endregion
127
- export { Caption, EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment };
129
+ export { EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment };
128
130
  //# sourceMappingURL=EFCaptions.d.ts.map
@@ -3,10 +3,10 @@ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/dec
3
3
  import { EFTemporal, flushStartTimeMsCache } from "./EFTemporal.js";
4
4
  import { EFSourceMixin } from "./EFSourceMixin.js";
5
5
  import { FetchMixin } from "./FetchMixin.js";
6
- import { flushSequenceDurationCache } from "./EFTimegroup.js";
7
6
  import { EFAudio } from "./EFAudio.js";
8
- import { EFVideo } from "./EFVideo.js";
9
7
  import { CrossUpdateController } from "./CrossUpdateController.js";
8
+ import { EFVideo } from "./EFVideo.js";
9
+ import { flushSequenceDurationCache } from "./EFTimegroup.js";
10
10
  import { Task, TaskStatus } from "@lit/task";
11
11
  import { LitElement, css, html } from "lit";
12
12
  import { customElement, property } from "lit/decorators.js";
@@ -266,10 +266,12 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
266
266
  args: () => [this.target, this.fetch],
267
267
  task: async ([_target, fetch], { signal }) => {
268
268
  if (!this.targetElement) return null;
269
- return (await fetch(`/@ef-asset/${this.targetElement.src ?? ""}`, {
270
- method: "HEAD",
271
- signal
272
- })).headers.get("etag") ?? void 0;
269
+ const src = this.targetElement.src ?? "";
270
+ let normalizedSrc = src.startsWith("/") ? src.slice(1) : src;
271
+ normalizedSrc = normalizedSrc.replace(/^\/+/, "");
272
+ const response = await fetch(`/api/v1/isobmff_files/local/md5?src=${encodeURIComponent(normalizedSrc)}`, { signal });
273
+ if (!response.ok) return;
274
+ return (await response.json()).md5 ?? void 0;
273
275
  }
274
276
  });
275
277
  this.transcriptionDataTask = new Task(this, {
@@ -287,7 +289,8 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
287
289
  this.fragmentIndexTask = new Task(this, {
288
290
  autoRun: EF_INTERACTIVE,
289
291
  args: () => [this.transcriptionDataTask.value, this.ownCurrentTimeMs],
290
- task: async ([transcription, ownCurrentTimeMs]) => {
292
+ task: async ([transcription, ownCurrentTimeMs], { signal }) => {
293
+ signal?.throwIfAborted();
291
294
  if (!transcription) return null;
292
295
  return Math.floor(ownCurrentTimeMs / transcription.work_slice_ms);
293
296
  }
@@ -335,17 +338,38 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
335
338
  this.unifiedCaptionsDataTask = new Task(this, {
336
339
  autoRun: EF_INTERACTIVE,
337
340
  args: () => [this.customCaptionsDataTask.value, this.transcriptionFragmentDataTask.value],
338
- task: async ([_customData, _transcriptionData]) => {
339
- if (this.customCaptionsDataTask.status === TaskStatus.PENDING) await this.customCaptionsDataTask.taskComplete;
340
- if (this.transcriptionFragmentDataTask.status === TaskStatus.PENDING) await this.transcriptionFragmentDataTask.taskComplete;
341
+ task: async ([_customData, _transcriptionData], { signal }) => {
342
+ signal?.throwIfAborted();
343
+ if (this.customCaptionsDataTask.status === TaskStatus.PENDING) {
344
+ await this.customCaptionsDataTask.taskComplete;
345
+ signal?.throwIfAborted();
346
+ }
347
+ if (this.transcriptionFragmentDataTask.status === TaskStatus.PENDING) {
348
+ await this.transcriptionFragmentDataTask.taskComplete;
349
+ signal?.throwIfAborted();
350
+ }
341
351
  return this.customCaptionsDataTask.value || this.transcriptionFragmentDataTask.value;
342
352
  }
343
353
  });
344
354
  this.frameTask = new Task(this, {
345
355
  autoRun: EF_INTERACTIVE,
346
356
  args: () => [this.unifiedCaptionsDataTask.status, this.ownCurrentTimeMs],
347
- task: async () => {
348
- await this.unifiedCaptionsDataTask.taskComplete;
357
+ onError: (error) => {
358
+ this.frameTask.taskComplete.catch(() => {});
359
+ if (error instanceof DOMException && error.name === "AbortError" || error instanceof Error && (error.name === "AbortError" || error.message?.includes("signal is aborted") || error.message?.includes("The user aborted a request"))) return;
360
+ console.error("EFCaptions frameTask error", error);
361
+ },
362
+ task: async ([_status, _ownCurrentTimeMs], { signal }) => {
363
+ try {
364
+ await this.unifiedCaptionsDataTask.taskComplete;
365
+ } catch (error) {
366
+ if (error instanceof DOMException && error.name === "AbortError") {
367
+ signal?.throwIfAborted();
368
+ return;
369
+ }
370
+ throw error;
371
+ }
372
+ signal?.throwIfAborted();
349
373
  this.updateTextContainers();
350
374
  }
351
375
  });
@@ -368,6 +392,7 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
368
392
  set target(value) {
369
393
  this.targetSelector = value;
370
394
  }
395
+ #cachedIntrinsicDurationMs = null;
371
396
  render() {
372
397
  return html`<slot></slot>`;
373
398
  }
@@ -379,30 +404,78 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
379
404
  captionsPath() {
380
405
  if (!this.targetElement) return null;
381
406
  if (this.targetElement.assetId) return `${this.apiHost}/api/v1/caption_files/${this.targetElement.assetId}`;
382
- return `/@ef-captions/${this.targetElement.src}`;
407
+ const targetSrc = this.targetElement.src;
408
+ let normalizedSrc = targetSrc.startsWith("/") ? targetSrc.slice(1) : targetSrc;
409
+ normalizedSrc = normalizedSrc.replace(/^\/+/, "");
410
+ return `/api/v1/assets/local/captions?src=${encodeURIComponent(normalizedSrc)}`;
383
411
  }
384
412
  transcriptionFragmentPath(transcriptionId, fragmentIndex) {
385
413
  return `${this.apiHost}/api/v1/transcriptions/${transcriptionId}/fragments/${fragmentIndex}`;
386
414
  }
415
+ #rootTimegroupUpdateController;
387
416
  connectedCallback() {
388
417
  super.connectedCallback();
389
418
  const target = this.targetSelector ? document.getElementById(this.targetSelector) : null;
390
419
  if (target && (target instanceof EFAudio || target instanceof EFVideo)) new CrossUpdateController(target, this);
391
420
  else if (this.hasCustomCaptionsData && this.rootTimegroup) new CrossUpdateController(this.rootTimegroup, this);
421
+ if (this.rootTimegroup) {
422
+ this.#rootTimegroupUpdateController = {
423
+ hostUpdated: () => {
424
+ Promise.resolve().then(() => {
425
+ this.updateTextContainers();
426
+ });
427
+ },
428
+ hostDisconnected: () => {
429
+ this.#rootTimegroupUpdateController = void 0;
430
+ }
431
+ };
432
+ this.rootTimegroup.addController(this.#rootTimegroupUpdateController);
433
+ }
392
434
  new MutationObserver(() => {
393
435
  if (this.style.display === "none") {
394
436
  this.style.removeProperty("display");
395
437
  this.style.opacity = "0";
396
438
  this.style.pointerEvents = "none";
439
+ } else if (!this.style.display || this.style.display === "") {
440
+ this.style.removeProperty("opacity");
441
+ this.style.removeProperty("pointer-events");
397
442
  }
398
443
  }).observe(this, {
399
444
  attributes: true,
400
445
  attributeFilter: ["style"]
401
446
  });
402
447
  }
448
+ disconnectedCallback() {
449
+ super.disconnectedCallback();
450
+ if (this.#rootTimegroupUpdateController && this.rootTimegroup) {
451
+ this.rootTimegroup.removeController(this.#rootTimegroupUpdateController);
452
+ this.#rootTimegroupUpdateController = void 0;
453
+ }
454
+ }
403
455
  updated(changedProperties) {
456
+ if (this.rootTimegroup && !this.#rootTimegroupUpdateController) {
457
+ this.#rootTimegroupUpdateController = {
458
+ hostUpdated: () => {
459
+ Promise.resolve().then(() => {
460
+ this.updateTextContainers();
461
+ });
462
+ },
463
+ hostDisconnected: () => {
464
+ this.#rootTimegroupUpdateController = void 0;
465
+ }
466
+ };
467
+ this.rootTimegroup.addController(this.#rootTimegroupUpdateController);
468
+ }
469
+ if (changedProperties.has("rootTimegroup") && this.#rootTimegroupUpdateController) {
470
+ const oldRootTimegroup = changedProperties.get("rootTimegroup");
471
+ if (oldRootTimegroup && oldRootTimegroup !== this.rootTimegroup) {
472
+ oldRootTimegroup.removeController(this.#rootTimegroupUpdateController);
473
+ this.#rootTimegroupUpdateController = void 0;
474
+ }
475
+ }
404
476
  this.updateTextContainers();
405
477
  if (changedProperties.has("captionsData") || changedProperties.has("captionsSrc") || changedProperties.has("captionsScript")) {
478
+ this.#cachedIntrinsicDurationMs = null;
406
479
  this.requestUpdate("intrinsicDurationMs");
407
480
  flushSequenceDurationCache();
408
481
  flushStartTimeMsCache();
@@ -416,7 +489,16 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
416
489
  updateTextContainers() {
417
490
  const captionsData = this.unifiedCaptionsDataTask.value;
418
491
  if (!captionsData) return;
419
- const currentTimeSec = this.ownCurrentTimeMs / 1e3;
492
+ let currentTimeMs = this.ownCurrentTimeMs;
493
+ if (this.hasCustomCaptionsData && this.parentTimegroup) {
494
+ const videoElement = Array.from(this.parentTimegroup.children).find((child) => child instanceof EFVideo);
495
+ if (videoElement) {
496
+ const sourceInMs = videoElement.sourceInMs ?? 0;
497
+ currentTimeMs = videoElement.currentSourceTimeMs - sourceInMs;
498
+ currentTimeMs = Math.max(0, Math.min(currentTimeMs, this.durationMs));
499
+ }
500
+ }
501
+ const currentTimeSec = currentTimeMs / 1e3;
420
502
  const currentWord = captionsData.word_segments.find((word) => currentTimeSec >= word.start && currentTimeSec < word.end);
421
503
  const currentSegment = captionsData.segments.find((segment) => currentTimeSec >= segment.start && currentTimeSec < segment.end);
422
504
  for (const wordContainer of this.activeWordContainers) if (currentWord) {
@@ -520,6 +602,7 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
520
602
  return !!(this.captionsData || this.captionsSrc || this.captionsScript);
521
603
  }
522
604
  get intrinsicDurationMs() {
605
+ if (this.#cachedIntrinsicDurationMs !== null) return this.#cachedIntrinsicDurationMs;
523
606
  let captionsData = null;
524
607
  if (this.captionsData) captionsData = this.captionsData;
525
608
  else if (this.captionsScript) {
@@ -528,11 +611,19 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
528
611
  captionsData = JSON.parse(scriptElement.textContent);
529
612
  } catch {}
530
613
  } else if (this.customCaptionsDataTask.value) captionsData = this.customCaptionsDataTask.value;
531
- if (!captionsData) return;
532
- if (captionsData.segments.length === 0 && captionsData.word_segments.length === 0) return 0;
533
- const maxSegmentEnd = captionsData.segments.length > 0 ? Math.max(...captionsData.segments.map((s) => s.end)) : 0;
534
- const maxWordEnd = captionsData.word_segments.length > 0 ? Math.max(...captionsData.word_segments.map((w) => w.end)) : 0;
535
- return Math.max(maxSegmentEnd, maxWordEnd) * 1e3;
614
+ if (!captionsData) {
615
+ if (!this.captionsData && !this.captionsScript && !this.captionsSrc) this.#cachedIntrinsicDurationMs = void 0;
616
+ return;
617
+ }
618
+ let result;
619
+ if (captionsData.segments.length === 0 && captionsData.word_segments.length === 0) result = 0;
620
+ else {
621
+ const maxSegmentEnd = captionsData.segments.length > 0 ? captionsData.segments.reduce((max, s) => s.end > max ? s.end : max, 0) : 0;
622
+ const maxWordEnd = captionsData.word_segments.length > 0 ? captionsData.word_segments.reduce((max, w) => w.end > max ? w.end : max, 0) : 0;
623
+ result = Math.max(maxSegmentEnd, maxWordEnd) * 1e3;
624
+ }
625
+ this.#cachedIntrinsicDurationMs = result;
626
+ return result;
536
627
  }
537
628
  get hasOwnDuration() {
538
629
  return !!(this.captionsData || this.captionsScript || this.customCaptionsDataTask.value);