@editframe/elements 0.37.3-beta → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/dist/EF_FRAMEGEN.js +17 -14
  2. package/dist/EF_FRAMEGEN.js.map +1 -1
  3. package/dist/EF_RENDERING.js.map +1 -1
  4. package/dist/canvas/EFCanvas.d.ts +9 -2
  5. package/dist/canvas/EFCanvas.js +14 -4
  6. package/dist/canvas/EFCanvas.js.map +1 -1
  7. package/dist/canvas/EFCanvasItem.d.ts +2 -2
  8. package/dist/canvas/overlays/SelectionOverlay.d.ts +10 -2
  9. package/dist/canvas/overlays/SelectionOverlay.js +5 -12
  10. package/dist/canvas/overlays/SelectionOverlay.js.map +1 -1
  11. package/dist/canvas/overlays/overlayState.js.map +1 -1
  12. package/dist/canvas/selection/SelectionController.js.map +1 -1
  13. package/dist/elements/EFAudio.d.ts +1 -11
  14. package/dist/elements/EFAudio.js +2 -10
  15. package/dist/elements/EFAudio.js.map +1 -1
  16. package/dist/elements/EFCaptions.d.ts +5 -9
  17. package/dist/elements/EFCaptions.js +34 -11
  18. package/dist/elements/EFCaptions.js.map +1 -1
  19. package/dist/elements/EFImage.d.ts +10 -8
  20. package/dist/elements/EFImage.js +117 -32
  21. package/dist/elements/EFImage.js.map +1 -1
  22. package/dist/elements/EFMedia/AssetMediaEngine.js +2 -2
  23. package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
  24. package/dist/elements/EFMedia/BaseMediaEngine.js +15 -92
  25. package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
  26. package/dist/elements/EFMedia/BufferedSeekingInput.js +10 -11
  27. package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
  28. package/dist/elements/EFMedia/{AssetIdMediaEngine.js → FileMediaEngine.js} +44 -24
  29. package/dist/elements/EFMedia/FileMediaEngine.js.map +1 -0
  30. package/dist/elements/EFMedia/JitMediaEngine.js +14 -13
  31. package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
  32. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
  33. package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
  34. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +12 -7
  35. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
  36. package/dist/elements/EFMedia/shared/timeoutUtils.js +44 -0
  37. package/dist/elements/EFMedia/shared/timeoutUtils.js.map +1 -0
  38. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +1 -1
  39. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
  40. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +4 -4
  41. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
  42. package/dist/elements/EFMedia.d.ts +14 -8
  43. package/dist/elements/EFMedia.js +52 -19
  44. package/dist/elements/EFMedia.js.map +1 -1
  45. package/dist/elements/EFPanZoom.d.ts +2 -2
  46. package/dist/elements/EFPanZoom.js +1 -1
  47. package/dist/elements/EFPanZoom.js.map +1 -1
  48. package/dist/elements/EFSourceMixin.js +16 -8
  49. package/dist/elements/EFSourceMixin.js.map +1 -1
  50. package/dist/elements/EFSurface.d.ts +5 -8
  51. package/dist/elements/EFSurface.js +4 -43
  52. package/dist/elements/EFSurface.js.map +1 -1
  53. package/dist/elements/EFTemporal.d.ts +33 -8
  54. package/dist/elements/EFTemporal.js +92 -40
  55. package/dist/elements/EFTemporal.js.map +1 -1
  56. package/dist/elements/EFText.d.ts +3 -0
  57. package/dist/elements/EFText.js +54 -21
  58. package/dist/elements/EFText.js.map +1 -1
  59. package/dist/elements/EFTextSegment.js +8 -4
  60. package/dist/elements/EFTextSegment.js.map +1 -1
  61. package/dist/elements/EFTimegroup.d.ts +26 -43
  62. package/dist/elements/EFTimegroup.js +295 -314
  63. package/dist/elements/EFTimegroup.js.map +1 -1
  64. package/dist/elements/EFVideo.d.ts +44 -42
  65. package/dist/elements/EFVideo.js +259 -172
  66. package/dist/elements/EFVideo.js.map +1 -1
  67. package/dist/elements/EFWaveform.d.ts +3 -8
  68. package/dist/elements/EFWaveform.js +18 -13
  69. package/dist/elements/EFWaveform.js.map +1 -1
  70. package/dist/elements/ElementPositionInfo.js.map +1 -1
  71. package/dist/elements/FetchMixin.js.map +1 -1
  72. package/dist/elements/TargetController.d.ts +0 -3
  73. package/dist/elements/TargetController.js +12 -35
  74. package/dist/elements/TargetController.js.map +1 -1
  75. package/dist/elements/TimegroupController.js.map +1 -1
  76. package/dist/elements/cloneFactoryRegistry.d.ts +14 -0
  77. package/dist/elements/cloneFactoryRegistry.js +15 -0
  78. package/dist/elements/cloneFactoryRegistry.js.map +1 -0
  79. package/dist/elements/renderTemporalAudio.js +8 -6
  80. package/dist/elements/renderTemporalAudio.js.map +1 -1
  81. package/dist/elements/setupTemporalHierarchy.js +62 -0
  82. package/dist/elements/setupTemporalHierarchy.js.map +1 -0
  83. package/dist/elements/updateAnimations.js +62 -87
  84. package/dist/elements/updateAnimations.js.map +1 -1
  85. package/dist/getRenderInfo.d.ts +3 -2
  86. package/dist/getRenderInfo.js +20 -4
  87. package/dist/getRenderInfo.js.map +1 -1
  88. package/dist/gui/ContextMixin.js +68 -12
  89. package/dist/gui/ContextMixin.js.map +1 -1
  90. package/dist/gui/Controllable.js +1 -1
  91. package/dist/gui/Controllable.js.map +1 -1
  92. package/dist/gui/EFActiveRootTemporal.d.ts +2 -2
  93. package/dist/gui/EFActiveRootTemporal.js.map +1 -1
  94. package/dist/gui/EFControls.d.ts +2 -2
  95. package/dist/gui/EFControls.js +2 -2
  96. package/dist/gui/EFControls.js.map +1 -1
  97. package/dist/gui/EFDial.d.ts +2 -2
  98. package/dist/gui/EFDial.js +12 -9
  99. package/dist/gui/EFDial.js.map +1 -1
  100. package/dist/gui/EFFilmstrip.d.ts +2 -0
  101. package/dist/gui/EFFilmstrip.js +18 -10
  102. package/dist/gui/EFFilmstrip.js.map +1 -1
  103. package/dist/gui/EFFitScale.d.ts +28 -4
  104. package/dist/gui/EFFitScale.js +88 -26
  105. package/dist/gui/EFFitScale.js.map +1 -1
  106. package/dist/gui/EFFocusOverlay.d.ts +2 -2
  107. package/dist/gui/EFFocusOverlay.js +3 -3
  108. package/dist/gui/EFFocusOverlay.js.map +1 -1
  109. package/dist/gui/EFOverlayItem.d.ts +2 -2
  110. package/dist/gui/EFOverlayLayer.d.ts +2 -2
  111. package/dist/gui/EFPause.d.ts +2 -2
  112. package/dist/gui/EFPause.js +1 -1
  113. package/dist/gui/EFPlay.d.ts +2 -2
  114. package/dist/gui/EFPlay.js +1 -1
  115. package/dist/gui/EFPreview.js +1 -1
  116. package/dist/gui/EFResizableBox.d.ts +2 -2
  117. package/dist/gui/EFResizableBox.js +5 -5
  118. package/dist/gui/EFResizableBox.js.map +1 -1
  119. package/dist/gui/EFScrubber.d.ts +2 -2
  120. package/dist/gui/EFScrubber.js +8 -13
  121. package/dist/gui/EFScrubber.js.map +1 -1
  122. package/dist/gui/EFTimeDisplay.d.ts +6 -2
  123. package/dist/gui/EFTimeDisplay.js +25 -7
  124. package/dist/gui/EFTimeDisplay.js.map +1 -1
  125. package/dist/gui/EFTimelineRuler.d.ts +2 -2
  126. package/dist/gui/EFTimelineRuler.js +3 -3
  127. package/dist/gui/EFTimelineRuler.js.map +1 -1
  128. package/dist/gui/EFToggleLoop.d.ts +2 -2
  129. package/dist/gui/EFToggleLoop.js +1 -1
  130. package/dist/gui/EFTogglePlay.d.ts +2 -2
  131. package/dist/gui/EFTogglePlay.js +1 -1
  132. package/dist/gui/EFTransformHandles.d.ts +2 -2
  133. package/dist/gui/EFTransformHandles.js +6 -6
  134. package/dist/gui/EFTransformHandles.js.map +1 -1
  135. package/dist/gui/EFWorkbench.d.ts +40 -36
  136. package/dist/gui/EFWorkbench.js +436 -822
  137. package/dist/gui/EFWorkbench.js.map +1 -1
  138. package/dist/gui/FitScaleHelpers.js.map +1 -1
  139. package/dist/gui/PlaybackController.d.ts +3 -8
  140. package/dist/gui/PlaybackController.js +59 -56
  141. package/dist/gui/PlaybackController.js.map +1 -1
  142. package/dist/gui/TWMixin.js +1 -1
  143. package/dist/gui/TWMixin.js.map +1 -1
  144. package/dist/gui/TargetOrContextMixin.js +43 -6
  145. package/dist/gui/TargetOrContextMixin.js.map +1 -1
  146. package/dist/gui/ef-theme.css +136 -0
  147. package/dist/gui/hierarchy/EFHierarchy.d.ts +2 -2
  148. package/dist/gui/hierarchy/EFHierarchy.js +14 -24
  149. package/dist/gui/hierarchy/EFHierarchy.js.map +1 -1
  150. package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
  151. package/dist/gui/hierarchy/EFHierarchyItem.js +22 -10
  152. package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -1
  153. package/dist/gui/icons.js.map +1 -1
  154. package/dist/gui/previewSettingsContext.d.ts +18 -0
  155. package/dist/gui/previewSettingsContext.js.map +1 -1
  156. package/dist/gui/theme.js +34 -0
  157. package/dist/gui/theme.js.map +1 -0
  158. package/dist/gui/timeline/EFTimeline.d.ts +2 -2
  159. package/dist/gui/timeline/EFTimeline.js +70 -52
  160. package/dist/gui/timeline/EFTimeline.js.map +1 -1
  161. package/dist/gui/timeline/EFTimelineRow.d.ts +5 -3
  162. package/dist/gui/timeline/EFTimelineRow.js +55 -32
  163. package/dist/gui/timeline/EFTimelineRow.js.map +1 -1
  164. package/dist/gui/timeline/TrimHandles.d.ts +23 -9
  165. package/dist/gui/timeline/TrimHandles.js +224 -51
  166. package/dist/gui/timeline/TrimHandles.js.map +1 -1
  167. package/dist/gui/timeline/flattenHierarchy.js.map +1 -1
  168. package/dist/gui/timeline/timelineEditingContext.d.ts +34 -0
  169. package/dist/gui/timeline/timelineEditingContext.js +24 -0
  170. package/dist/gui/timeline/timelineEditingContext.js.map +1 -0
  171. package/dist/gui/timeline/timelineStateContext.js.map +1 -1
  172. package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
  173. package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -1
  174. package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +2 -3
  175. package/dist/gui/timeline/tracks/CaptionsTrack.js +17 -75
  176. package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -1
  177. package/dist/gui/timeline/tracks/EFThumbnailStrip.d.ts +52 -0
  178. package/dist/gui/timeline/tracks/EFThumbnailStrip.js +596 -0
  179. package/dist/gui/timeline/tracks/EFThumbnailStrip.js.map +1 -0
  180. package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -1
  181. package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -1
  182. package/dist/gui/timeline/tracks/TextTrack.d.ts +3 -2
  183. package/dist/gui/timeline/tracks/TextTrack.js +17 -43
  184. package/dist/gui/timeline/tracks/TextTrack.js.map +1 -1
  185. package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +3 -4
  186. package/dist/gui/timeline/tracks/TimegroupTrack.js +33 -23
  187. package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
  188. package/dist/gui/timeline/tracks/TrackItem.d.ts +7 -9
  189. package/dist/gui/timeline/tracks/TrackItem.js +18 -17
  190. package/dist/gui/timeline/tracks/TrackItem.js.map +1 -1
  191. package/dist/gui/timeline/tracks/VideoTrack.d.ts +3 -3
  192. package/dist/gui/timeline/tracks/VideoTrack.js +11 -14
  193. package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -1
  194. package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -1
  195. package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -1
  196. package/dist/gui/timeline/tracks/waveformUtils.js +1 -1
  197. package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -1
  198. package/dist/gui/tree/EFTree.d.ts +2 -2
  199. package/dist/gui/tree/EFTree.js +8 -14
  200. package/dist/gui/tree/EFTree.js.map +1 -1
  201. package/dist/gui/tree/EFTreeItem.d.ts +2 -2
  202. package/dist/gui/tree/EFTreeItem.js +3 -3
  203. package/dist/gui/tree/EFTreeItem.js.map +1 -1
  204. package/dist/gui/tree/treeContext.js.map +1 -1
  205. package/dist/index.d.ts +10 -8
  206. package/dist/index.js +6 -5
  207. package/dist/index.js.map +1 -1
  208. package/dist/node.d.ts +2 -2
  209. package/dist/node.js +2 -2
  210. package/dist/preview/AdaptiveResolutionTracker.js +3 -3
  211. package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
  212. package/dist/preview/FrameController.d.ts +2 -17
  213. package/dist/preview/FrameController.js +40 -63
  214. package/dist/preview/FrameController.js.map +1 -1
  215. package/dist/preview/QualityUpgradeScheduler.d.ts +76 -0
  216. package/dist/preview/QualityUpgradeScheduler.js +158 -0
  217. package/dist/preview/QualityUpgradeScheduler.js.map +1 -0
  218. package/dist/preview/RenderContext.d.ts +119 -1
  219. package/dist/preview/RenderContext.js +21 -3
  220. package/dist/preview/RenderContext.js.map +1 -1
  221. package/dist/preview/RenderProfiler.js.map +1 -1
  222. package/dist/preview/RenderStats.js +85 -0
  223. package/dist/preview/RenderStats.js.map +1 -0
  224. package/dist/preview/encoding/canvasEncoder.js +2 -52
  225. package/dist/preview/encoding/canvasEncoder.js.map +1 -1
  226. package/dist/preview/encoding/mainThreadEncoder.js.map +1 -1
  227. package/dist/preview/encoding/workerEncoder.js.map +1 -1
  228. package/dist/preview/logger.js.map +1 -1
  229. package/dist/preview/previewSettings.d.ts +34 -0
  230. package/dist/preview/previewSettings.js +29 -17
  231. package/dist/preview/previewSettings.js.map +1 -1
  232. package/dist/preview/previewTypes.js +4 -4
  233. package/dist/preview/previewTypes.js.map +1 -1
  234. package/dist/preview/renderElementToCanvas.d.ts +44 -0
  235. package/dist/preview/renderElementToCanvas.js +72 -0
  236. package/dist/preview/renderElementToCanvas.js.map +1 -0
  237. package/dist/preview/renderTimegroupToCanvas.d.ts +134 -32
  238. package/dist/preview/renderTimegroupToCanvas.js +321 -146
  239. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  240. package/dist/preview/renderTimegroupToCanvas.types.d.ts +51 -0
  241. package/dist/preview/renderTimegroupToVideo.d.ts +20 -35
  242. package/dist/preview/renderTimegroupToVideo.js +94 -106
  243. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  244. package/dist/preview/renderTimegroupToVideo.types.d.ts +42 -0
  245. package/dist/preview/renderVideoToVideo.js +286 -0
  246. package/dist/preview/renderVideoToVideo.js.map +1 -0
  247. package/dist/preview/renderers.d.ts +56 -0
  248. package/dist/preview/renderers.js +13 -1
  249. package/dist/preview/renderers.js.map +1 -1
  250. package/dist/preview/rendering/ScaleConfig.js +74 -0
  251. package/dist/preview/rendering/ScaleConfig.js.map +1 -0
  252. package/dist/preview/rendering/inlineImages.d.ts +13 -0
  253. package/dist/preview/rendering/inlineImages.js +7 -44
  254. package/dist/preview/rendering/inlineImages.js.map +1 -1
  255. package/dist/preview/rendering/loadImage.d.ts +8 -0
  256. package/dist/preview/rendering/loadImage.js +22 -0
  257. package/dist/preview/rendering/loadImage.js.map +1 -0
  258. package/dist/preview/rendering/renderToImageNative.js +3 -3
  259. package/dist/preview/rendering/renderToImageNative.js.map +1 -1
  260. package/dist/preview/rendering/serializeTimelineDirect.js +224 -68
  261. package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
  262. package/dist/preview/statsTrackingStrategy.js +1 -101
  263. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  264. package/dist/preview/workers/WorkerPool.js +0 -1
  265. package/dist/preview/workers/WorkerPool.js.map +1 -1
  266. package/dist/preview/workers/encoderWorkerInline.js +21 -54
  267. package/dist/preview/workers/encoderWorkerInline.js.map +1 -1
  268. package/dist/render/EFRenderAPI.d.ts +2 -1
  269. package/dist/render/EFRenderAPI.js +12 -36
  270. package/dist/render/EFRenderAPI.js.map +1 -1
  271. package/dist/render/getRenderData.js +4 -4
  272. package/dist/render/getRenderData.js.map +1 -1
  273. package/dist/style.css +114 -163
  274. package/dist/transcoding/cache/RequestDeduplicator.js +1 -0
  275. package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
  276. package/dist/transcoding/types/index.d.ts +1 -1
  277. package/dist/transcoding/utils/UrlGenerator.js +10 -3
  278. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  279. package/dist/utils/LRUCache.js +1 -0
  280. package/dist/utils/LRUCache.js.map +1 -1
  281. package/dist/utils/frameTime.js +23 -1
  282. package/dist/utils/frameTime.js.map +1 -1
  283. package/package.json +45 -8
  284. package/scripts/build-css.js +8 -1
  285. package/test/setup.ts +0 -1
  286. package/test/useAssetMSW.ts +50 -0
  287. package/test/visualRegressionUtils.ts +23 -9
  288. package/tsdown.config.ts +6 -1
  289. package/dist/_virtual/rolldown_runtime.js +0 -27
  290. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +0 -1
  291. package/dist/elements/EFThumbnailStrip.d.ts +0 -167
  292. package/dist/elements/EFThumbnailStrip.js +0 -731
  293. package/dist/elements/EFThumbnailStrip.js.map +0 -1
  294. package/dist/elements/SessionThumbnailCache.js +0 -154
  295. package/dist/elements/SessionThumbnailCache.js.map +0 -1
  296. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -688
  297. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +0 -1
  298. package/dist/node_modules/react/cjs/react.development.js +0 -1521
  299. package/dist/node_modules/react/cjs/react.development.js.map +0 -1
  300. package/dist/node_modules/react/index.js +0 -13
  301. package/dist/node_modules/react/index.js.map +0 -1
  302. package/dist/node_modules/react/jsx-runtime.js +0 -13
  303. package/dist/node_modules/react/jsx-runtime.js.map +0 -1
  304. package/dist/preview/encoding/types.d.ts +0 -1
  305. package/dist/preview/renderTimegroupPreview.js +0 -686
  306. package/dist/preview/renderTimegroupPreview.js.map +0 -1
  307. package/dist/preview/rendering/renderToImage.d.ts +0 -2
  308. package/dist/preview/rendering/renderToImage.js +0 -95
  309. package/dist/preview/rendering/renderToImage.js.map +0 -1
  310. package/dist/preview/rendering/renderToImageForeignObject.js +0 -163
  311. package/dist/preview/rendering/renderToImageForeignObject.js.map +0 -1
  312. package/dist/preview/rendering/renderToImageNative.d.ts +0 -1
  313. package/dist/preview/rendering/svgSerializer.js +0 -43
  314. package/dist/preview/rendering/svgSerializer.js.map +0 -1
  315. package/dist/preview/rendering/types.d.ts +0 -2
  316. package/dist/preview/thumbnailCacheSettings.js +0 -52
  317. package/dist/preview/thumbnailCacheSettings.js.map +0 -1
  318. package/dist/sandbox/PlaybackControls.d.ts +0 -1
  319. package/dist/sandbox/PlaybackControls.js +0 -10
  320. package/dist/sandbox/PlaybackControls.js.map +0 -1
  321. package/dist/sandbox/ScenarioRunner.d.ts +0 -1
  322. package/dist/sandbox/ScenarioRunner.js +0 -1
  323. package/dist/sandbox/defineSandbox.d.ts +0 -1
  324. package/dist/sandbox/index.d.ts +0 -3
  325. package/dist/sandbox/index.js +0 -2
  326. package/test/EFVideo.framegen.browsertest.ts +0 -80
  327. package/test/thumbnail-performance-test.html +0 -116
@@ -1 +1 @@
1
- {"version":3,"file":"EFSourceMixin.js","names":["#md5Value","#md5Promise","#md5LastSrc","#doLoadMd5"],"sources":["../../src/elements/EFSourceMixin.ts"],"sourcesContent":["import type { LitElement } from \"lit\";\nimport { property } from \"lit/decorators/property.js\";\n\nexport declare class EFSourceMixinInterface {\n apiHost?: string;\n productionSrc(): string;\n src: string;\n}\n\ninterface EFSourceMixinOptions {\n assetType: string;\n}\ntype Constructor<T = {}> = new (...args: any[]) => T;\nexport function EFSourceMixin<T extends Constructor<LitElement>>(\n superClass: T,\n options: EFSourceMixinOptions,\n) {\n class EFSourceElement extends superClass {\n get apiHost() {\n const apiHost =\n this.closest(\"ef-configuration\")?.apiHost ??\n this.closest(\"ef-workbench\")?.apiHost ??\n this.closest(\"ef-preview\")?.apiHost;\n\n // Return undefined instead of defaulting to external URL\n // This allows components to use current origin when apiHost is not set\n return apiHost;\n }\n\n @property({ type: String })\n src = \"\";\n\n #md5Value: string | undefined = undefined;\n #md5Promise: Promise<string | undefined> | null = null;\n #md5LastSrc: string | null = null;\n\n productionSrc() {\n if (!this.#md5Value) {\n throw new Error(\n `MD5 sum not available for ${this}. Cannot generate production URL`,\n );\n }\n\n if (!this.apiHost) {\n throw new Error(\n `apiHost not available for ${this}. Cannot generate production URL`,\n );\n }\n\n return `${this.apiHost}/api/v1/${options.assetType}/${this.#md5Value}`;\n }\n\n /**\n * Load MD5 sum for the current source\n */\n async loadMd5Sum(signal?: AbortSignal): Promise<string | undefined> {\n if (this.#md5LastSrc === this.src && this.#md5Value) {\n return this.#md5Value;\n }\n\n if (this.#md5Promise && this.#md5LastSrc === this.src) {\n return this.#md5Promise;\n }\n\n this.#md5LastSrc = this.src;\n this.#md5Promise = this.#doLoadMd5(this.src, signal);\n\n try {\n this.#md5Value = await this.#md5Promise;\n return this.#md5Value;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw error;\n }\n console.error(\"EFSourceMixin md5Sum error\", error);\n return undefined;\n } finally {\n this.#md5Promise = null;\n }\n }\n\n async #doLoadMd5(src: string, signal?: AbortSignal): Promise<string | undefined> {\n // Normalize the path: remove leading slash and any double slashes\n let normalizedSrc = src.startsWith(\"/\")\n ? src.slice(1)\n : src;\n normalizedSrc = normalizedSrc.replace(/^\\/+/, \"\");\n // Use production API format for local files\n const md5Path = `/api/v1/isobmff_files/local/md5?src=${encodeURIComponent(normalizedSrc)}`;\n const response = await fetch(md5Path, { signal });\n if (!response.ok) {\n return undefined;\n }\n const data = await response.json();\n return data.md5 ?? undefined;\n }\n\n /**\n * Compatibility wrapper for code expecting md5SumLoader.value\n */\n md5SumLoader = new Proxy({\n run: () => this.loadMd5Sum(),\n _host: this,\n } as {\n run: () => Promise<string | undefined>;\n value: string | undefined;\n taskComplete: Promise<string | undefined>;\n _host: typeof this;\n }, {\n get(target, prop) {\n if (prop === 'value') {\n return (target._host as any).#md5Value;\n }\n if (prop === 'taskComplete') {\n const host = target._host as any;\n return host.#md5Promise || Promise.resolve(host.#md5Value);\n }\n return (target as any)[prop];\n },\n });\n }\n\n return EFSourceElement as Constructor<EFSourceMixinInterface> & T;\n}\n"],"mappings":";;;;AAaA,SAAgB,cACd,YACA,SACA;CACA,MAAM,wBAAwB,WAAW;;;cAajC;uBAsES,IAAI,MAAM;IACvB,WAAW,KAAK,YAAY;IAC5B,OAAO;IACR,EAKE,EACD,IAAI,QAAQ,MAAM;AAChB,QAAI,SAAS,QACX,QAAQ,OAAO,OAAcA;AAE/B,QAAI,SAAS,gBAAgB;KAC3B,MAAM,OAAO,OAAO;AACpB,YAAO,MAAKC,cAAe,QAAQ,QAAQ,MAAKD,SAAU;;AAE5D,WAAQ,OAAe;MAE1B,CAAC;;EArGF,IAAI,UAAU;AAQZ,UANE,KAAK,QAAQ,mBAAmB,EAAE,WAClC,KAAK,QAAQ,eAAe,EAAE,WAC9B,KAAK,QAAQ,aAAa,EAAE;;EAUhC,YAAgC;EAChC,cAAkD;EAClD,cAA6B;EAE7B,gBAAgB;AACd,OAAI,CAAC,MAAKA,SACR,OAAM,IAAI,MACR,6BAA6B,KAAK,kCACnC;AAGH,OAAI,CAAC,KAAK,QACR,OAAM,IAAI,MACR,6BAA6B,KAAK,kCACnC;AAGH,UAAO,GAAG,KAAK,QAAQ,UAAU,QAAQ,UAAU,GAAG,MAAKA;;;;;EAM7D,MAAM,WAAW,QAAmD;AAClE,OAAI,MAAKE,eAAgB,KAAK,OAAO,MAAKF,SACxC,QAAO,MAAKA;AAGd,OAAI,MAAKC,cAAe,MAAKC,eAAgB,KAAK,IAChD,QAAO,MAAKD;AAGd,SAAKC,aAAc,KAAK;AACxB,SAAKD,aAAc,MAAKE,UAAW,KAAK,KAAK,OAAO;AAEpD,OAAI;AACF,UAAKH,WAAY,MAAM,MAAKC;AAC5B,WAAO,MAAKD;YACL,OAAO;AACd,QAAI,iBAAiB,gBAAgB,MAAM,SAAS,aAClD,OAAM;AAER,YAAQ,MAAM,8BAA8B,MAAM;AAClD;aACQ;AACR,UAAKC,aAAc;;;EAIvB,OAAME,UAAW,KAAa,QAAmD;GAE/E,IAAI,gBAAgB,IAAI,WAAW,IAAI,GACnC,IAAI,MAAM,EAAE,GACZ;AACJ,mBAAgB,cAAc,QAAQ,QAAQ,GAAG;GAEjD,MAAM,UAAU,uCAAuC,mBAAmB,cAAc;GACxF,MAAM,WAAW,MAAM,MAAM,SAAS,EAAE,QAAQ,CAAC;AACjD,OAAI,CAAC,SAAS,GACZ;AAGF,WADa,MAAM,SAAS,MAAM,EACtB,OAAO;;;aAjEpB,SAAS,EAAE,MAAM,QAAQ,CAAC;AA6F7B,QAAO"}
1
+ {"version":3,"file":"EFSourceMixin.js","names":["#md5Value","#md5LastSrc","#md5Promise","#doLoadMd5"],"sources":["../../src/elements/EFSourceMixin.ts"],"sourcesContent":["import type { LitElement } from \"lit\";\nimport { property } from \"lit/decorators/property.js\";\n\nexport declare class EFSourceMixinInterface {\n apiHost?: string;\n productionSrc(): string;\n src: string;\n}\n\ninterface EFSourceMixinOptions {\n assetType: string;\n}\ntype Constructor<T = {}> = new (...args: any[]) => T;\nexport function EFSourceMixin<T extends Constructor<LitElement>>(\n superClass: T,\n options: EFSourceMixinOptions,\n) {\n class EFSourceElement extends superClass {\n get apiHost() {\n const apiHost =\n (this.closest(\"ef-configuration\") as any)?.apiHost ??\n (this.closest(\"ef-workbench\") as any)?.apiHost ??\n (this.closest(\"ef-preview\") as any)?.apiHost;\n\n // Return undefined instead of defaulting to external URL\n // This allows components to use current origin when apiHost is not set\n return apiHost;\n }\n\n @property({ type: String, reflect: true })\n src = \"\";\n\n #md5Value: string | undefined = undefined;\n #md5Promise: Promise<string | undefined> | null = null;\n #md5LastSrc: string | null = null;\n\n productionSrc() {\n if (!this.#md5Value) {\n throw new Error(\n `MD5 sum not available for ${this}. Cannot generate production URL`,\n );\n }\n\n if (!this.apiHost) {\n throw new Error(\n `apiHost not available for ${this}. Cannot generate production URL`,\n );\n }\n\n return `${this.apiHost}/api/v1/${options.assetType}/${this.#md5Value}`;\n }\n\n /**\n * Load MD5 sum for the current source\n */\n async loadMd5Sum(signal?: AbortSignal): Promise<string | undefined> {\n if (this.#md5LastSrc === this.src && this.#md5Value) {\n return this.#md5Value;\n }\n\n if (this.#md5Promise && this.#md5LastSrc === this.src) {\n return this.#md5Promise;\n }\n\n this.#md5LastSrc = this.src;\n this.#md5Promise = this.#doLoadMd5(this.src, signal);\n\n try {\n this.#md5Value = await this.#md5Promise;\n return this.#md5Value;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n throw error;\n }\n console.error(\"EFSourceMixin md5Sum error\", error);\n return undefined;\n } finally {\n this.#md5Promise = null;\n }\n }\n\n async #doLoadMd5(\n src: string,\n signal?: AbortSignal,\n ): Promise<string | undefined> {\n // Normalize the path: remove leading slash and any double slashes\n let normalizedSrc = src.startsWith(\"/\") ? src.slice(1) : src;\n normalizedSrc = normalizedSrc.replace(/^\\/+/, \"\");\n // Use production API format for local files\n const md5Path = `/api/v1/files/local/md5?src=${encodeURIComponent(normalizedSrc)}`;\n const response = await fetch(md5Path, { signal });\n if (!response.ok) {\n return undefined;\n }\n const data = await response.json();\n return data.md5 ?? undefined;\n }\n\n /** @internal Exposes md5 state for md5SumLoader proxy without private field access in handler */\n _getMd5Value(): string | undefined {\n return this.#md5Value;\n }\n\n /** @internal Exposes md5 promise state for md5SumLoader proxy */\n _getMd5Promise(): Promise<string | undefined> | null {\n return this.#md5Promise;\n }\n\n /**\n * Compatibility wrapper for code expecting md5SumLoader.value\n */\n md5SumLoader = new Proxy(\n {\n run: () => this.loadMd5Sum(),\n host: this,\n } as unknown as {\n run: () => Promise<string | undefined>;\n host: {\n _getMd5Value: () => string | undefined;\n _getMd5Promise: () => Promise<string | undefined> | null;\n };\n value: string | undefined;\n taskComplete: Promise<string | undefined>;\n },\n {\n get(target, prop) {\n if (prop === \"value\") {\n return target.host._getMd5Value();\n }\n if (prop === \"taskComplete\") {\n const p = target.host._getMd5Promise();\n return p || Promise.resolve(target.host._getMd5Value());\n }\n return (target as any)[prop];\n },\n },\n );\n }\n\n return EFSourceElement as Constructor<EFSourceMixinInterface> & T;\n}\n"],"mappings":";;;;AAaA,SAAgB,cACd,YACA,SACA;CACA,MAAM,wBAAwB,WAAW;;;cAajC;uBAiFS,IAAI,MACjB;IACE,WAAW,KAAK,YAAY;IAC5B,MAAM;IACP,EASD,EACE,IAAI,QAAQ,MAAM;AAChB,QAAI,SAAS,QACX,QAAO,OAAO,KAAK,cAAc;AAEnC,QAAI,SAAS,eAEX,QADU,OAAO,KAAK,gBAAgB,IAC1B,QAAQ,QAAQ,OAAO,KAAK,cAAc,CAAC;AAEzD,WAAQ,OAAe;MAE1B,CACF;;EAtHD,IAAI,UAAU;AAQZ,UANG,KAAK,QAAQ,mBAAmB,EAAU,WAC1C,KAAK,QAAQ,eAAe,EAAU,WACtC,KAAK,QAAQ,aAAa,EAAU;;EAUzC,YAAgC;EAChC,cAAkD;EAClD,cAA6B;EAE7B,gBAAgB;AACd,OAAI,CAAC,MAAKA,SACR,OAAM,IAAI,MACR,6BAA6B,KAAK,kCACnC;AAGH,OAAI,CAAC,KAAK,QACR,OAAM,IAAI,MACR,6BAA6B,KAAK,kCACnC;AAGH,UAAO,GAAG,KAAK,QAAQ,UAAU,QAAQ,UAAU,GAAG,MAAKA;;;;;EAM7D,MAAM,WAAW,QAAmD;AAClE,OAAI,MAAKC,eAAgB,KAAK,OAAO,MAAKD,SACxC,QAAO,MAAKA;AAGd,OAAI,MAAKE,cAAe,MAAKD,eAAgB,KAAK,IAChD,QAAO,MAAKC;AAGd,SAAKD,aAAc,KAAK;AACxB,SAAKC,aAAc,MAAKC,UAAW,KAAK,KAAK,OAAO;AAEpD,OAAI;AACF,UAAKH,WAAY,MAAM,MAAKE;AAC5B,WAAO,MAAKF;YACL,OAAO;AACd,QAAI,iBAAiB,gBAAgB,MAAM,SAAS,aAClD,OAAM;AAER,YAAQ,MAAM,8BAA8B,MAAM;AAClD;aACQ;AACR,UAAKE,aAAc;;;EAIvB,OAAMC,UACJ,KACA,QAC6B;GAE7B,IAAI,gBAAgB,IAAI,WAAW,IAAI,GAAG,IAAI,MAAM,EAAE,GAAG;AACzD,mBAAgB,cAAc,QAAQ,QAAQ,GAAG;GAEjD,MAAM,UAAU,+BAA+B,mBAAmB,cAAc;GAChF,MAAM,WAAW,MAAM,MAAM,SAAS,EAAE,QAAQ,CAAC;AACjD,OAAI,CAAC,SAAS,GACZ;AAGF,WADa,MAAM,SAAS,MAAM,EACtB,OAAO;;;EAIrB,eAAmC;AACjC,UAAO,MAAKH;;;EAId,iBAAqD;AACnD,UAAO,MAAKE;;;aA5Eb,SAAS;EAAE,MAAM;EAAQ,SAAS;EAAM,CAAC;AA8G5C,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import { FrameRenderable, FrameState } from "../preview/FrameController.js";
2
2
  import { ContextMixinInterface } from "../gui/ContextMixin.js";
3
- import * as lit26 from "lit";
3
+ import * as lit27 from "lit";
4
4
  import { LitElement } from "lit";
5
5
  import * as lit_html25 from "lit-html";
6
6
  import * as lit_html_directives_ref3 from "lit-html/directives/ref";
@@ -8,7 +8,7 @@ import * as lit_html_directives_ref3 from "lit-html/directives/ref";
8
8
  //#region src/elements/EFSurface.d.ts
9
9
  declare class EFSurface extends LitElement implements FrameRenderable {
10
10
  #private;
11
- static styles: lit26.CSSResult[];
11
+ static styles: lit27.CSSResult[];
12
12
  canvasRef: lit_html_directives_ref3.Ref<HTMLCanvasElement>;
13
13
  targetElement: ContextMixinInterface | null;
14
14
  target: string;
@@ -18,20 +18,17 @@ declare class EFSurface extends LitElement implements FrameRenderable {
18
18
  get durationMs(): number;
19
19
  get startTimeMs(): number;
20
20
  get endTimeMs(): number;
21
- frameTask: {
22
- run(): void | Promise<void>;
23
- taskComplete: Promise<void>;
24
- };
25
21
  /**
26
22
  * Query readiness state for a given time.
27
23
  * @implements FrameRenderable
28
24
  */
29
25
  getFrameState(_timeMs: number): FrameState;
30
26
  /**
31
- * Async preparation - waits for target element's frameTask.
27
+ * Async preparation - no preparation needed.
28
+ * FrameController's priority system ensures dependencies render first.
32
29
  * @implements FrameRenderable
33
30
  */
34
- prepareFrame(_timeMs: number, signal: AbortSignal): Promise<void>;
31
+ prepareFrame(_timeMs: number, _signal: AbortSignal): Promise<void>;
35
32
  /**
36
33
  * Synchronous render - copies canvas from target element.
37
34
  * @implements FrameRenderable
@@ -11,28 +11,6 @@ let EFSurface = class EFSurface$1 extends LitElement {
11
11
  this.canvasRef = createRef();
12
12
  this.targetElement = null;
13
13
  this.target = "";
14
- this.frameTask = (() => {
15
- const self = this;
16
- const taskObj = {
17
- run: () => {
18
- const abortController = new AbortController();
19
- const timeMs = self.currentTimeMs;
20
- self.#frameTaskPromise = (async () => {
21
- try {
22
- await self.prepareFrame(timeMs, abortController.signal);
23
- self.renderFrame(timeMs);
24
- } catch (error) {
25
- if (error instanceof DOMException && error.name === "AbortError") return;
26
- throw error;
27
- }
28
- })();
29
- taskObj.taskComplete = self.#frameTaskPromise;
30
- return self.#frameTaskPromise;
31
- },
32
- taskComplete: Promise.resolve()
33
- };
34
- return taskObj;
35
- })();
36
14
  }
37
15
  static {
38
16
  this.styles = [css`
@@ -72,11 +50,6 @@ let EFSurface = class EFSurface$1 extends LitElement {
72
50
  return this.startTimeMs + this.durationMs;
73
51
  }
74
52
  /**
75
- * @deprecated Use FrameRenderable methods (prepareFrame, renderFrame) via FrameController instead.
76
- * This is a compatibility wrapper that delegates to the new system.
77
- */
78
- #frameTaskPromise = Promise.resolve();
79
- /**
80
53
  * Query readiness state for a given time.
81
54
  * @implements FrameRenderable
82
55
  */
@@ -88,23 +61,11 @@ let EFSurface = class EFSurface$1 extends LitElement {
88
61
  };
89
62
  }
90
63
  /**
91
- * Async preparation - waits for target element's frameTask.
64
+ * Async preparation - no preparation needed.
65
+ * FrameController's priority system ensures dependencies render first.
92
66
  * @implements FrameRenderable
93
67
  */
94
- async prepareFrame(_timeMs, signal) {
95
- if (!this.targetElement) return;
96
- const maybeTask = this.targetElement.frameTask;
97
- if (maybeTask && typeof maybeTask.run === "function") try {
98
- maybeTask.run().catch(() => {});
99
- await maybeTask.taskComplete;
100
- } catch (error) {
101
- if (error instanceof DOMException && error.name === "AbortError") {
102
- signal.throwIfAborted();
103
- return;
104
- }
105
- }
106
- signal.throwIfAborted();
107
- }
68
+ async prepareFrame(_timeMs, _signal) {}
108
69
  /**
109
70
  * Synchronous render - copies canvas from target element.
110
71
  * @implements FrameRenderable
@@ -131,7 +92,7 @@ let EFSurface = class EFSurface$1 extends LitElement {
131
92
  dst.width = src.width;
132
93
  dst.height = src.height;
133
94
  }
134
- const ctx = dst.getContext("2d");
95
+ const ctx = dst.getContext("2d", { willReadFrequently: true });
135
96
  if (!ctx) return;
136
97
  ctx.drawImage(src, 0, 0, dst.width, dst.height);
137
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EFSurface.js","names":["EFSurface","taskObj: { run(): void | Promise<void>; taskComplete: Promise<void> }","#frameTaskPromise","target: any","root: any"],"sources":["../../src/elements/EFSurface.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport type { ContextMixinInterface } from \"../gui/ContextMixin.ts\";\nimport type { FrameRenderable, FrameState } from \"../preview/FrameController.js\";\nimport { TargetController } from \"./TargetController.ts\";\n\n@customElement(\"ef-surface\")\nexport class EFSurface extends LitElement implements FrameRenderable {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n }\n canvas {\n all: inherit;\n width: 100%;\n height: 100%;\n display: block;\n }\n `,\n ];\n\n canvasRef = createRef<HTMLCanvasElement>();\n\n // @ts-expect-error controller is intentionally not referenced directly\n // biome-ignore lint/correctness/noUnusedPrivateClassMembers: Used for side effects\n #targetController: TargetController = new TargetController(this);\n\n @state()\n targetElement: ContextMixinInterface | null = null;\n\n @property({ type: String })\n target = \"\";\n\n render() {\n return html`<canvas ${ref(this.canvasRef)}></canvas>`;\n }\n\n // Provide minimal temporal-like properties so EFTimegroup can schedule us\n get rootTimegroup(): any {\n // Prefer the target element's root timegroup if available\n const target: any = this.targetElement;\n if (target && \"rootTimegroup\" in target) {\n return target.rootTimegroup;\n }\n // Fallback: nearest containing timegroup if any\n let root: any = this.closest(\"ef-timegroup\");\n while (root?.parentTimegroup) {\n root = root.parentTimegroup;\n }\n return root;\n }\n\n get currentTimeMs(): number {\n return this.rootTimegroup?.currentTimeMs ?? 0;\n }\n\n get durationMs(): number {\n return this.rootTimegroup?.durationMs ?? 0;\n }\n\n get startTimeMs(): number {\n return this.rootTimegroup?.startTimeMs ?? 0;\n }\n\n get endTimeMs(): number {\n return this.startTimeMs + this.durationMs;\n }\n\n /**\n * @deprecated Use FrameRenderable methods (prepareFrame, renderFrame) via FrameController instead.\n * This is a compatibility wrapper that delegates to the new system.\n */\n #frameTaskPromise: Promise<void> = Promise.resolve();\n \n frameTask = (() => {\n const self = this;\n const taskObj: { run(): void | Promise<void>; taskComplete: Promise<void> } = {\n run: () => {\n const abortController = new AbortController();\n const timeMs = self.currentTimeMs;\n self.#frameTaskPromise = (async () => {\n try {\n await self.prepareFrame(timeMs, abortController.signal);\n self.renderFrame(timeMs);\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n return;\n }\n throw error;\n }\n })();\n taskObj.taskComplete = self.#frameTaskPromise;\n return self.#frameTaskPromise;\n },\n taskComplete: Promise.resolve(),\n };\n return taskObj;\n })();\n\n // ============================================================================\n // FrameRenderable Implementation\n // Centralized frame control - replaces distributed Lit Task system\n // ============================================================================\n\n /**\n * Query readiness state for a given time.\n * @implements FrameRenderable\n */\n getFrameState(_timeMs: number): FrameState {\n // Surface is ready when target element exists\n const hasTarget = !!this.targetElement;\n\n return {\n needsPreparation: false, // Surface just copies, no async prep needed\n isReady: hasTarget,\n priority: 10, // Surface renders last (depends on other elements)\n };\n }\n\n /**\n * Async preparation - waits for target element's frameTask.\n * @implements FrameRenderable\n */\n async prepareFrame(_timeMs: number, signal: AbortSignal): Promise<void> {\n if (!this.targetElement) return;\n\n // Wait for target's frame to be ready\n const maybeTask = (this.targetElement as any).frameTask;\n if (maybeTask && typeof maybeTask.run === \"function\") {\n try {\n maybeTask.run().catch(() => {});\n await maybeTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal.throwIfAborted();\n return;\n }\n // Best-effort; continue to copy for other errors\n }\n }\n signal.throwIfAborted();\n }\n\n /**\n * Synchronous render - copies canvas from target element.\n * @implements FrameRenderable\n */\n renderFrame(_timeMs: number): void {\n if (this.targetElement) {\n this.copyFromTarget(this.targetElement);\n }\n }\n\n // ============================================================================\n // End FrameRenderable Implementation\n // ============================================================================\n\n protected updated(): void {\n if (this.targetElement) {\n this.copyFromTarget(this.targetElement);\n }\n }\n\n // Target resolution is handled by TargetController. No implicit discovery.\n\n private getSourceCanvas(from: Element): HTMLCanvasElement | null {\n const anyEl = from as any;\n if (\"canvasElement\" in anyEl) {\n return anyEl.canvasElement ?? null;\n }\n const sr = (from as HTMLElement).shadowRoot;\n if (sr) {\n const c = sr.querySelector(\"canvas\");\n return (c as HTMLCanvasElement) ?? null;\n }\n return null;\n }\n\n private copyFromTarget(target: Element) {\n const dst = this.canvasRef.value;\n const src = this.getSourceCanvas(target);\n if (!dst || !src) return;\n if (!src.width || !src.height) return;\n\n // Match source pixel size for a faithful mirror; layout scaling is handled by CSS\n if (dst.width !== src.width || dst.height !== src.height) {\n dst.width = src.width;\n dst.height = src.height;\n }\n\n const ctx = dst.getContext(\"2d\");\n if (!ctx) return;\n ctx.drawImage(src, 0, 0, dst.width, dst.height);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-surface\": EFSurface;\n }\n}\n"],"mappings":";;;;;;;AAQO,sBAAMA,oBAAkB,WAAsC;;;mBAgBvD,WAA8B;uBAOI;gBAGrC;0BA2CU;GACjB,MAAM,OAAO;GACb,MAAMC,UAAwE;IAC5E,WAAW;KACT,MAAM,kBAAkB,IAAI,iBAAiB;KAC7C,MAAM,SAAS,KAAK;AACpB,WAAKC,oBAAqB,YAAY;AACpC,UAAI;AACF,aAAM,KAAK,aAAa,QAAQ,gBAAgB,OAAO;AACvD,YAAK,YAAY,OAAO;eACjB,OAAO;AACd,WAAI,iBAAiB,gBAAgB,MAAM,SAAS,aAClD;AAEF,aAAM;;SAEN;AACJ,aAAQ,eAAe,MAAKA;AAC5B,YAAO,MAAKA;;IAEd,cAAc,QAAQ,SAAS;IAChC;AACD,UAAO;MACL;;;gBA3FY,CACd,GAAG;;;;;;;;;;;MAYJ;;CAMD,oBAAsC,IAAI,iBAAiB,KAAK;CAQhE,SAAS;AACP,SAAO,IAAI,WAAW,IAAI,KAAK,UAAU,CAAC;;CAI5C,IAAI,gBAAqB;EAEvB,MAAMC,SAAc,KAAK;AACzB,MAAI,UAAU,mBAAmB,OAC/B,QAAO,OAAO;EAGhB,IAAIC,OAAY,KAAK,QAAQ,eAAe;AAC5C,SAAO,MAAM,gBACX,QAAO,KAAK;AAEd,SAAO;;CAGT,IAAI,gBAAwB;AAC1B,SAAO,KAAK,eAAe,iBAAiB;;CAG9C,IAAI,aAAqB;AACvB,SAAO,KAAK,eAAe,cAAc;;CAG3C,IAAI,cAAsB;AACxB,SAAO,KAAK,eAAe,eAAe;;CAG5C,IAAI,YAAoB;AACtB,SAAO,KAAK,cAAc,KAAK;;;;;;CAOjC,oBAAmC,QAAQ,SAAS;;;;;CAoCpD,cAAc,SAA6B;AAIzC,SAAO;GACL,kBAAkB;GAClB,SAJgB,CAAC,CAAC,KAAK;GAKvB,UAAU;GACX;;;;;;CAOH,MAAM,aAAa,SAAiB,QAAoC;AACtE,MAAI,CAAC,KAAK,cAAe;EAGzB,MAAM,YAAa,KAAK,cAAsB;AAC9C,MAAI,aAAa,OAAO,UAAU,QAAQ,WACxC,KAAI;AACF,aAAU,KAAK,CAAC,YAAY,GAAG;AAC/B,SAAM,UAAU;WACT,OAAO;AACd,OAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,WAAO,gBAAgB;AACvB;;;AAKN,SAAO,gBAAgB;;;;;;CAOzB,YAAY,SAAuB;AACjC,MAAI,KAAK,cACP,MAAK,eAAe,KAAK,cAAc;;CAQ3C,AAAU,UAAgB;AACxB,MAAI,KAAK,cACP,MAAK,eAAe,KAAK,cAAc;;CAM3C,AAAQ,gBAAgB,MAAyC;EAC/D,MAAM,QAAQ;AACd,MAAI,mBAAmB,MACrB,QAAO,MAAM,iBAAiB;EAEhC,MAAM,KAAM,KAAqB;AACjC,MAAI,GAEF,QADU,GAAG,cAAc,SAAS,IACD;AAErC,SAAO;;CAGT,AAAQ,eAAe,QAAiB;EACtC,MAAM,MAAM,KAAK,UAAU;EAC3B,MAAM,MAAM,KAAK,gBAAgB,OAAO;AACxC,MAAI,CAAC,OAAO,CAAC,IAAK;AAClB,MAAI,CAAC,IAAI,SAAS,CAAC,IAAI,OAAQ;AAG/B,MAAI,IAAI,UAAU,IAAI,SAAS,IAAI,WAAW,IAAI,QAAQ;AACxD,OAAI,QAAQ,IAAI;AAChB,OAAI,SAAS,IAAI;;EAGnB,MAAM,MAAM,IAAI,WAAW,KAAK;AAChC,MAAI,CAAC,IAAK;AACV,MAAI,UAAU,KAAK,GAAG,GAAG,IAAI,OAAO,IAAI,OAAO;;;YArKhD,OAAO;YAGP,SAAS,EAAE,MAAM,QAAQ,CAAC;wBA1B5B,cAAc,aAAa"}
1
+ {"version":3,"file":"EFSurface.js","names":["EFSurface","target: any","root: any"],"sources":["../../src/elements/EFSurface.ts"],"sourcesContent":["import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport type { ContextMixinInterface } from \"../gui/ContextMixin.ts\";\nimport type {\n FrameRenderable,\n FrameState,\n} from \"../preview/FrameController.js\";\nimport { TargetController } from \"./TargetController.ts\";\n\n@customElement(\"ef-surface\")\nexport class EFSurface extends LitElement implements FrameRenderable {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n }\n canvas {\n all: inherit;\n width: 100%;\n height: 100%;\n display: block;\n }\n `,\n ];\n\n canvasRef = createRef<HTMLCanvasElement>();\n\n // @ts-expect-error controller is intentionally not referenced directly\n // biome-ignore lint/correctness/noUnusedPrivateClassMembers: Used for side effects\n #targetController: TargetController = new TargetController(this);\n\n @state()\n targetElement: ContextMixinInterface | null = null;\n\n @property({ type: String })\n target = \"\";\n\n render() {\n return html`<canvas ${ref(this.canvasRef)}></canvas>`;\n }\n\n // Provide minimal temporal-like properties so EFTimegroup can schedule us\n get rootTimegroup(): any {\n // Prefer the target element's root timegroup if available\n const target: any = this.targetElement;\n if (target && \"rootTimegroup\" in target) {\n return target.rootTimegroup;\n }\n // Fallback: nearest containing timegroup if any\n let root: any = this.closest(\"ef-timegroup\");\n while (root?.parentTimegroup) {\n root = root.parentTimegroup;\n }\n return root;\n }\n\n get currentTimeMs(): number {\n return this.rootTimegroup?.currentTimeMs ?? 0;\n }\n\n get durationMs(): number {\n return this.rootTimegroup?.durationMs ?? 0;\n }\n\n get startTimeMs(): number {\n return this.rootTimegroup?.startTimeMs ?? 0;\n }\n\n get endTimeMs(): number {\n return this.startTimeMs + this.durationMs;\n }\n\n // ============================================================================\n // FrameRenderable Implementation\n // ============================================================================\n\n /**\n * Query readiness state for a given time.\n * @implements FrameRenderable\n */\n getFrameState(_timeMs: number): FrameState {\n // Surface is ready when target element exists\n const hasTarget = !!this.targetElement;\n\n return {\n needsPreparation: false, // Surface just copies, no async prep needed\n isReady: hasTarget,\n priority: 10, // Surface renders last (depends on other elements)\n };\n }\n\n /**\n * Async preparation - no preparation needed.\n * FrameController's priority system ensures dependencies render first.\n * @implements FrameRenderable\n */\n async prepareFrame(_timeMs: number, _signal: AbortSignal): Promise<void> {\n // No preparation needed - FrameController handles dependencies via priority\n }\n\n /**\n * Synchronous render - copies canvas from target element.\n * @implements FrameRenderable\n */\n renderFrame(_timeMs: number): void {\n if (this.targetElement) {\n this.copyFromTarget(this.targetElement);\n }\n }\n\n // ============================================================================\n // End FrameRenderable Implementation\n // ============================================================================\n\n protected updated(): void {\n if (this.targetElement) {\n this.copyFromTarget(this.targetElement);\n }\n }\n\n // Target resolution is handled by TargetController. No implicit discovery.\n\n private getSourceCanvas(from: Element): HTMLCanvasElement | null {\n const anyEl = from as any;\n if (\"canvasElement\" in anyEl) {\n return anyEl.canvasElement ?? null;\n }\n const sr = (from as HTMLElement).shadowRoot;\n if (sr) {\n const c = sr.querySelector(\"canvas\");\n return (c as HTMLCanvasElement) ?? null;\n }\n return null;\n }\n\n private copyFromTarget(target: Element) {\n const dst = this.canvasRef.value;\n const src = this.getSourceCanvas(target);\n if (!dst || !src) return;\n if (!src.width || !src.height) return;\n\n // Match source pixel size for a faithful mirror; layout scaling is handled by CSS\n if (dst.width !== src.width || dst.height !== src.height) {\n dst.width = src.width;\n dst.height = src.height;\n }\n\n const ctx = dst.getContext(\"2d\", { willReadFrequently: true });\n if (!ctx) return;\n ctx.drawImage(src, 0, 0, dst.width, dst.height);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-surface\": EFSurface;\n }\n}\n"],"mappings":";;;;;;;AAWO,sBAAMA,oBAAkB,WAAsC;;;mBAgBvD,WAA8B;uBAOI;gBAGrC;;;gBAzBO,CACd,GAAG;;;;;;;;;;;MAYJ;;CAMD,oBAAsC,IAAI,iBAAiB,KAAK;CAQhE,SAAS;AACP,SAAO,IAAI,WAAW,IAAI,KAAK,UAAU,CAAC;;CAI5C,IAAI,gBAAqB;EAEvB,MAAMC,SAAc,KAAK;AACzB,MAAI,UAAU,mBAAmB,OAC/B,QAAO,OAAO;EAGhB,IAAIC,OAAY,KAAK,QAAQ,eAAe;AAC5C,SAAO,MAAM,gBACX,QAAO,KAAK;AAEd,SAAO;;CAGT,IAAI,gBAAwB;AAC1B,SAAO,KAAK,eAAe,iBAAiB;;CAG9C,IAAI,aAAqB;AACvB,SAAO,KAAK,eAAe,cAAc;;CAG3C,IAAI,cAAsB;AACxB,SAAO,KAAK,eAAe,eAAe;;CAG5C,IAAI,YAAoB;AACtB,SAAO,KAAK,cAAc,KAAK;;;;;;CAWjC,cAAc,SAA6B;AAIzC,SAAO;GACL,kBAAkB;GAClB,SAJgB,CAAC,CAAC,KAAK;GAKvB,UAAU;GACX;;;;;;;CAQH,MAAM,aAAa,SAAiB,SAAqC;;;;;CAQzE,YAAY,SAAuB;AACjC,MAAI,KAAK,cACP,MAAK,eAAe,KAAK,cAAc;;CAQ3C,AAAU,UAAgB;AACxB,MAAI,KAAK,cACP,MAAK,eAAe,KAAK,cAAc;;CAM3C,AAAQ,gBAAgB,MAAyC;EAC/D,MAAM,QAAQ;AACd,MAAI,mBAAmB,MACrB,QAAO,MAAM,iBAAiB;EAEhC,MAAM,KAAM,KAAqB;AACjC,MAAI,GAEF,QADU,GAAG,cAAc,SAAS,IACD;AAErC,SAAO;;CAGT,AAAQ,eAAe,QAAiB;EACtC,MAAM,MAAM,KAAK,UAAU;EAC3B,MAAM,MAAM,KAAK,gBAAgB,OAAO;AACxC,MAAI,CAAC,OAAO,CAAC,IAAK;AAClB,MAAI,CAAC,IAAI,SAAS,CAAC,IAAI,OAAQ;AAG/B,MAAI,IAAI,UAAU,IAAI,SAAS,IAAI,WAAW,IAAI,QAAQ;AACxD,OAAI,QAAQ,IAAI;AAChB,OAAI,SAAS,IAAI;;EAGnB,MAAM,MAAM,IAAI,WAAW,MAAM,EAAE,oBAAoB,MAAM,CAAC;AAC9D,MAAI,CAAC,IAAK;AACV,MAAI,UAAU,KAAK,GAAG,GAAG,IAAI,OAAO,IAAI,OAAO;;;YAtHhD,OAAO;YAGP,SAAS,EAAE,MAAM,QAAQ,CAAC;wBA1B5B,cAAc,aAAa"}
@@ -4,6 +4,8 @@ import { LitElement, ReactiveController } from "lit";
4
4
 
5
5
  //#region src/elements/EFTemporal.d.ts
6
6
 
7
+ type ContentReadyState = "idle" | "loading" | "ready" | "error";
8
+ type ContentChangeReason = "source" | "bounds" | "structure" | "content";
7
9
  declare class TemporalMixinInterface {
8
10
  playbackController?: PlaybackController;
9
11
  playing: boolean;
@@ -136,6 +138,12 @@ declare class TemporalMixinInterface {
136
138
  * played.
137
139
  */
138
140
  get ownCurrentTimeMs(): number;
141
+ /**
142
+ * Set the base local time (ms) used by ownCurrentTimeMs when no playback
143
+ * controller is present. Used by seekForRender() on render clones.
144
+ * @internal
145
+ */
146
+ _setLocalTimeMs(value: number): void;
139
147
  /**
140
148
  * Element's current time for progress calculation.
141
149
  * For timegroups: their timeline currentTimeMs
@@ -190,16 +198,33 @@ declare class TemporalMixinInterface {
190
198
  * A convenience property for getting the root timegroup of the media element.
191
199
  */
192
200
  rootTimegroup?: EFTimegroup;
193
- /**
194
- * Frame task interface. Can be a Lit Task or a simple object with run() and taskComplete.
195
- * @deprecated Prefer using FrameRenderable interface via FrameController.
196
- */
197
- frameTask: {
198
- run(): void | Promise<void>;
199
- taskComplete: Promise<unknown>;
200
- };
201
201
  didBecomeRoot(): void;
202
202
  didBecomeChild(): void;
203
+ /**
204
+ * The readiness state of this element's content.
205
+ * "idle" — no content / not connected
206
+ * "loading" — async resources are loading
207
+ * "ready" — element can render / extract frames
208
+ * "error" — resource loading failed
209
+ *
210
+ * @domAttribute "content-ready-state"
211
+ */
212
+ contentReadyState: ContentReadyState;
213
+ /**
214
+ * Transition to a new readiness state.
215
+ * Dispatches a non-bubbling `readystatechange` CustomEvent if the state changed.
216
+ */
217
+ setContentReadyState(state: ContentReadyState): void;
218
+ /**
219
+ * Dispatch a non-bubbling `contentchange` CustomEvent.
220
+ * Signals that cached renderable output is stale.
221
+ */
222
+ emitContentChange(reason: ContentChangeReason): void;
223
+ /**
224
+ * Whether this element should auto-transition to "ready" after first update.
225
+ * Override to return false for elements with async loading (EFMedia, EFCaptions).
226
+ */
227
+ shouldAutoReady(): boolean;
203
228
  updateComplete: Promise<boolean>;
204
229
  }
205
230
  declare const isEFTemporal: (obj: any) => obj is TemporalMixinInterface;
@@ -121,13 +121,32 @@ function determineCurrentTimeSource(playbackController, rootTimegroup, isRootTim
121
121
  }
122
122
  const isEFTemporal = (obj) => obj[EF_TEMPORAL];
123
123
  const EF_TEMPORAL = Symbol("EF_TEMPORAL");
124
- const deepGetTemporalElements = (element, temporals = []) => {
125
- const children = getChildrenIncludingSlotted(element);
126
- for (const child of children) {
127
- if (isEFTemporal(child)) temporals.push(child);
128
- deepGetTemporalElements(child, temporals);
129
- }
130
- return temporals;
124
+ const deepGetTemporalElements = (element, timeMs) => {
125
+ const elements = [];
126
+ const pruned = /* @__PURE__ */ new Set();
127
+ const walk = (el) => {
128
+ const children = getChildrenIncludingSlotted(el);
129
+ for (const child of children) {
130
+ if (isEFTemporal(child)) {
131
+ const temporal = child;
132
+ elements.push(temporal);
133
+ if (timeMs !== void 0) {
134
+ const startMs = temporal.startTimeMs;
135
+ const endMs = temporal.endTimeMs;
136
+ if (endMs > startMs && (timeMs < startMs || timeMs >= endMs)) {
137
+ pruned.add(temporal);
138
+ continue;
139
+ }
140
+ }
141
+ }
142
+ walk(child);
143
+ }
144
+ };
145
+ walk(element);
146
+ return {
147
+ elements,
148
+ pruned
149
+ };
131
150
  };
132
151
  /**
133
152
  * Gets all child elements including slotted content for shadow DOM elements.
@@ -146,14 +165,6 @@ const getChildrenIncludingSlotted = (element) => {
146
165
  }
147
166
  return Array.from(element.children);
148
167
  };
149
- const deepGetElementsWithFrameTasks = (element, elements = []) => {
150
- const children = getChildrenIncludingSlotted(element);
151
- for (const child of children) {
152
- if ("frameTask" in child && child.frameTask != null && typeof child.frameTask.run === "function") elements.push(child);
153
- deepGetElementsWithFrameTasks(child, elements);
154
- }
155
- return elements;
156
- };
157
168
  let temporalCache;
158
169
  let temporalCacheResetScheduled = false;
159
170
  const resetTemporalCache = () => {
@@ -187,9 +198,9 @@ var OwnCurrentTimeController = class {
187
198
  const currentTimeMs = this.host.currentTimeMs;
188
199
  if (this.#lastKnownTimeMs === currentTimeMs) return;
189
200
  this.#lastKnownTimeMs = currentTimeMs;
190
- setTimeout(() => {
201
+ queueMicrotask(() => {
191
202
  this.temporal.requestUpdate("ownCurrentTimeMs");
192
- }, 0);
203
+ });
193
204
  }
194
205
  remove() {
195
206
  this.host.removeController(this);
@@ -222,18 +233,34 @@ const EFTemporal = (superClass) => {
222
233
  this._sourceOutMs = void 0;
223
234
  this._startOffsetMs = 0;
224
235
  this.rootTimegroup = this.getRootTimegroup();
225
- this.frameTask = (() => {
226
- const self = this;
227
- const taskObj = {
228
- run: () => {
229
- self.#frameTaskPromise = self.updateComplete.then(() => {});
230
- taskObj.taskComplete = self.#frameTaskPromise;
231
- return self.#frameTaskPromise;
232
- },
233
- taskComplete: Promise.resolve()
234
- };
235
- return taskObj;
236
- })();
236
+ }
237
+ #contentReadyState = "idle";
238
+ get contentReadyState() {
239
+ return this.#contentReadyState;
240
+ }
241
+ set contentReadyState(value) {
242
+ this.setContentReadyState(value);
243
+ }
244
+ setContentReadyState(state$1) {
245
+ if (state$1 === this.#contentReadyState) return;
246
+ const old = this.#contentReadyState;
247
+ this.#contentReadyState = state$1;
248
+ this.requestUpdate("contentReadyState", old);
249
+ this.dispatchEvent(new CustomEvent("readystatechange", {
250
+ detail: { state: state$1 },
251
+ bubbles: false,
252
+ composed: false
253
+ }));
254
+ }
255
+ emitContentChange(reason) {
256
+ this.dispatchEvent(new CustomEvent("contentchange", {
257
+ detail: { reason },
258
+ bubbles: false,
259
+ composed: false
260
+ }));
261
+ }
262
+ shouldAutoReady() {
263
+ return true;
237
264
  }
238
265
  #ownCurrentTimeController;
239
266
  #parentTimegroup;
@@ -259,6 +286,7 @@ const EFTemporal = (superClass) => {
259
286
  }
260
287
  disconnectedCallback() {
261
288
  super.disconnectedCallback();
289
+ if (this.canvasPreviewActive) return;
262
290
  this.#ownCurrentTimeController?.remove();
263
291
  if (this.playbackController) {
264
292
  this.playbackController.remove();
@@ -270,11 +298,16 @@ const EFTemporal = (superClass) => {
270
298
  }
271
299
  connectedCallback() {
272
300
  super.connectedCallback();
301
+ if (this.canvasPreviewActive) return;
273
302
  this.#ownCurrentTimeController?.remove();
274
303
  if (!(this.parentElement?.closest("ef-timegroup") != null) && !this.playbackController) this.updateComplete.then(() => {
275
304
  if (!this.isConnected) return;
276
305
  if (!this.playbackController) this.didBecomeRoot();
277
306
  });
307
+ if (this.shouldAutoReady()) this.updateComplete.then(() => {
308
+ if (!this.isConnected) return;
309
+ if (this.#contentReadyState === "idle") this.setContentReadyState("ready");
310
+ });
278
311
  }
279
312
  get parentTimegroup() {
280
313
  return this.#parentTimegroup;
@@ -346,6 +379,16 @@ const EFTemporal = (superClass) => {
346
379
  set sourceOutMs(value) {
347
380
  this._sourceOutMs = value;
348
381
  }
382
+ updated(changedProperties) {
383
+ super.updated?.(changedProperties);
384
+ const sourceChanged = changedProperties.has("_sourceInMs") || changedProperties.has("_sourceOutMs");
385
+ const trimChanged = changedProperties.has("_trimStartMs") || changedProperties.has("_trimEndMs");
386
+ const becameReady = changedProperties.has("contentReadyState") && changedProperties.get("contentReadyState") !== "ready" && this.contentReadyState === "ready";
387
+ if (sourceChanged || trimChanged || becameReady) {
388
+ if (this.rootTimegroup) this.rootTimegroup.requestFrameRender();
389
+ else if (this.playbackController) this.playbackController.runThrottledFrameTask();
390
+ }
391
+ }
349
392
  get startOffsetMs() {
350
393
  return this._startOffsetMs;
351
394
  }
@@ -402,6 +445,15 @@ const EFTemporal = (superClass) => {
402
445
  }
403
446
  #currentTimeMs = 0;
404
447
  /**
448
+ * Set the base local time (ms) used by ownCurrentTimeMs when no playback
449
+ * controller is present. Called by EFTimegroup.seekForRender() to keep the
450
+ * mixin's internal time in sync with the timegroup's own time state.
451
+ * @internal
452
+ */
453
+ _setLocalTimeMs(value) {
454
+ this.#currentTimeMs = value;
455
+ }
456
+ /**
405
457
  * The current time of the element within itself.
406
458
  * Compare with `currentTimeMs` to see the current time with respect to the root timegroup
407
459
  */
@@ -441,17 +493,12 @@ const EFTemporal = (superClass) => {
441
493
  const leadingTrimMs = this.sourceInMs || this.trimStartMs || 0;
442
494
  return this.ownCurrentTimeMs + leadingTrimMs;
443
495
  }
444
- /**
445
- * @deprecated Use FrameRenderable interface via FrameController instead.
446
- * This is a compatibility wrapper - base class just waits for updateComplete.
447
- */
448
- #frameTaskPromise = Promise.resolve();
449
496
  didBecomeRoot() {
450
- if (this.closest?.(".ef-render-clone-container")) return;
451
- if (!this.playbackController) {
452
- this.playbackController = new PlaybackController(this);
453
- if (this.#loop) this.playbackController.setLoop(this.#loop);
454
- }
497
+ const noPlayback = this.hasAttribute?.("data-no-playback-controller");
498
+ const isRendering = typeof window !== "undefined" && "FRAMEGEN_BRIDGE" in window;
499
+ if (noPlayback || this.playbackController || isRendering) return;
500
+ this.playbackController = new PlaybackController(this);
501
+ if (this.#loop) this.playbackController.setLoop(this.#loop);
455
502
  }
456
503
  didBecomeChild() {
457
504
  if (this.playbackController) {
@@ -460,6 +507,11 @@ const EFTemporal = (superClass) => {
460
507
  }
461
508
  }
462
509
  }
510
+ __decorate([property({
511
+ type: String,
512
+ reflect: true,
513
+ attribute: "content-ready-state"
514
+ })], TemporalMixinClass.prototype, "contentReadyState", null);
463
515
  __decorate([consume({
464
516
  context: timegroupContext,
465
517
  subscribe: true
@@ -510,5 +562,5 @@ const EFTemporal = (superClass) => {
510
562
  };
511
563
 
512
564
  //#endregion
513
- export { EFTemporal, deepGetElementsWithFrameTasks, deepGetTemporalElements, flushStartTimeMsCache, isEFTemporal, registerIsTimegroupCalculatingDuration, resetTemporalCache, shallowGetTemporalElements, timegroupContext };
565
+ export { EFTemporal, deepGetTemporalElements, flushStartTimeMsCache, isEFTemporal, registerIsTimegroupCalculatingDuration, resetTemporalCache, shallowGetTemporalElements, timegroupContext };
514
566
  //# sourceMappingURL=EFTemporal.js.map