@editframe/elements 0.37.2-beta → 0.38.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 (321) 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 +4 -4
  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 +7 -10
  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 +4 -4
  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 +4 -4
  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 +4 -4
  107. package/dist/gui/EFFocusOverlay.js +3 -3
  108. package/dist/gui/EFFocusOverlay.js.map +1 -1
  109. package/dist/gui/EFOverlayItem.d.ts +4 -4
  110. package/dist/gui/EFOverlayLayer.d.ts +4 -4
  111. package/dist/gui/EFPause.d.ts +4 -4
  112. package/dist/gui/EFPause.js +1 -1
  113. package/dist/gui/EFPlay.d.ts +4 -4
  114. package/dist/gui/EFPlay.js +1 -1
  115. package/dist/gui/EFPreview.js +1 -1
  116. package/dist/gui/EFResizableBox.d.ts +4 -4
  117. package/dist/gui/EFResizableBox.js +5 -5
  118. package/dist/gui/EFResizableBox.js.map +1 -1
  119. package/dist/gui/EFScrubber.d.ts +4 -4
  120. package/dist/gui/EFScrubber.js +8 -13
  121. package/dist/gui/EFScrubber.js.map +1 -1
  122. package/dist/gui/EFTimeDisplay.d.ts +8 -4
  123. package/dist/gui/EFTimeDisplay.js +25 -7
  124. package/dist/gui/EFTimeDisplay.js.map +1 -1
  125. package/dist/gui/EFTimelineRuler.d.ts +4 -4
  126. package/dist/gui/EFTimelineRuler.js +3 -3
  127. package/dist/gui/EFTimelineRuler.js.map +1 -1
  128. package/dist/gui/EFToggleLoop.d.ts +4 -4
  129. package/dist/gui/EFToggleLoop.js +1 -1
  130. package/dist/gui/EFTogglePlay.d.ts +4 -4
  131. package/dist/gui/EFTogglePlay.js +1 -1
  132. package/dist/gui/EFTransformHandles.d.ts +4 -4
  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 +3 -1
  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 +5 -6
  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 +4 -4
  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 +4 -4
  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.js +267 -145
  238. package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
  239. package/dist/preview/renderTimegroupToCanvas.types.d.ts +30 -0
  240. package/dist/preview/renderTimegroupToVideo.js +85 -105
  241. package/dist/preview/renderTimegroupToVideo.js.map +1 -1
  242. package/dist/preview/{renderTimegroupToVideo.d.ts → renderTimegroupToVideo.types.d.ts} +9 -9
  243. package/dist/preview/renderVideoToVideo.js +286 -0
  244. package/dist/preview/renderVideoToVideo.js.map +1 -0
  245. package/dist/preview/renderers.js.map +1 -1
  246. package/dist/preview/rendering/ScaleConfig.js +74 -0
  247. package/dist/preview/rendering/ScaleConfig.js.map +1 -0
  248. package/dist/preview/rendering/inlineImages.js +1 -44
  249. package/dist/preview/rendering/inlineImages.js.map +1 -1
  250. package/dist/preview/rendering/loadImage.js +22 -0
  251. package/dist/preview/rendering/loadImage.js.map +1 -0
  252. package/dist/preview/rendering/renderToImageNative.js +3 -3
  253. package/dist/preview/rendering/renderToImageNative.js.map +1 -1
  254. package/dist/preview/rendering/serializeTimelineDirect.js +224 -68
  255. package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
  256. package/dist/preview/statsTrackingStrategy.js +1 -101
  257. package/dist/preview/statsTrackingStrategy.js.map +1 -1
  258. package/dist/preview/workers/WorkerPool.js +0 -1
  259. package/dist/preview/workers/WorkerPool.js.map +1 -1
  260. package/dist/preview/workers/encoderWorkerInline.js +21 -54
  261. package/dist/preview/workers/encoderWorkerInline.js.map +1 -1
  262. package/dist/render/EFRenderAPI.d.ts +2 -1
  263. package/dist/render/EFRenderAPI.js +12 -36
  264. package/dist/render/EFRenderAPI.js.map +1 -1
  265. package/dist/render/getRenderData.js +4 -4
  266. package/dist/render/getRenderData.js.map +1 -1
  267. package/dist/style.css +114 -163
  268. package/dist/transcoding/cache/RequestDeduplicator.js +1 -0
  269. package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
  270. package/dist/transcoding/types/index.d.ts +1 -1
  271. package/dist/transcoding/utils/UrlGenerator.js +10 -3
  272. package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
  273. package/dist/utils/LRUCache.js +1 -0
  274. package/dist/utils/LRUCache.js.map +1 -1
  275. package/dist/utils/frameTime.js +23 -1
  276. package/dist/utils/frameTime.js.map +1 -1
  277. package/package.json +21 -8
  278. package/scripts/build-css.js +8 -1
  279. package/test/setup.ts +0 -1
  280. package/test/useAssetMSW.ts +50 -0
  281. package/test/visualRegressionUtils.ts +23 -9
  282. package/dist/_virtual/rolldown_runtime.js +0 -27
  283. package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +0 -1
  284. package/dist/elements/EFThumbnailStrip.d.ts +0 -167
  285. package/dist/elements/EFThumbnailStrip.js +0 -731
  286. package/dist/elements/EFThumbnailStrip.js.map +0 -1
  287. package/dist/elements/SessionThumbnailCache.js +0 -154
  288. package/dist/elements/SessionThumbnailCache.js.map +0 -1
  289. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -688
  290. package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +0 -1
  291. package/dist/node_modules/react/cjs/react.development.js +0 -1521
  292. package/dist/node_modules/react/cjs/react.development.js.map +0 -1
  293. package/dist/node_modules/react/index.js +0 -13
  294. package/dist/node_modules/react/index.js.map +0 -1
  295. package/dist/node_modules/react/jsx-runtime.js +0 -13
  296. package/dist/node_modules/react/jsx-runtime.js.map +0 -1
  297. package/dist/preview/encoding/types.d.ts +0 -1
  298. package/dist/preview/renderTimegroupPreview.js +0 -686
  299. package/dist/preview/renderTimegroupPreview.js.map +0 -1
  300. package/dist/preview/renderTimegroupToCanvas.d.ts +0 -42
  301. package/dist/preview/rendering/renderToImage.d.ts +0 -2
  302. package/dist/preview/rendering/renderToImage.js +0 -95
  303. package/dist/preview/rendering/renderToImage.js.map +0 -1
  304. package/dist/preview/rendering/renderToImageForeignObject.js +0 -163
  305. package/dist/preview/rendering/renderToImageForeignObject.js.map +0 -1
  306. package/dist/preview/rendering/renderToImageNative.d.ts +0 -1
  307. package/dist/preview/rendering/svgSerializer.js +0 -43
  308. package/dist/preview/rendering/svgSerializer.js.map +0 -1
  309. package/dist/preview/rendering/types.d.ts +0 -2
  310. package/dist/preview/thumbnailCacheSettings.js +0 -52
  311. package/dist/preview/thumbnailCacheSettings.js.map +0 -1
  312. package/dist/sandbox/PlaybackControls.d.ts +0 -1
  313. package/dist/sandbox/PlaybackControls.js +0 -10
  314. package/dist/sandbox/PlaybackControls.js.map +0 -1
  315. package/dist/sandbox/ScenarioRunner.d.ts +0 -1
  316. package/dist/sandbox/ScenarioRunner.js +0 -1
  317. package/dist/sandbox/defineSandbox.d.ts +0 -1
  318. package/dist/sandbox/index.d.ts +0 -3
  319. package/dist/sandbox/index.js +0 -2
  320. package/test/EFVideo.framegen.browsertest.ts +0 -80
  321. package/test/thumbnail-performance-test.html +0 -116
@@ -1,8 +1,8 @@
1
+ import { efContext } from "./efContext.js";
1
2
  import { currentTimeContext } from "./currentTimeContext.js";
2
3
  import { durationContext } from "./durationContext.js";
3
4
  import { playingContext } from "./playingContext.js";
4
5
  import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
5
- import { efContext } from "./efContext.js";
6
6
  import { quantizeToFrameTimeMs } from "./EFTimelineRuler.js";
7
7
  import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
8
8
  import { consume } from "@lit/context";
@@ -12,12 +12,12 @@ import { createRef, ref } from "lit/directives/ref.js";
12
12
 
13
13
  //#region src/gui/EFScrubber.ts
14
14
  const BASE_PIXELS_PER_SECOND = 100;
15
- function timeToPixels(timeMs, durationMs, containerWidth, zoomScale) {
15
+ function timeToPixels(timeMs, durationMs, _containerWidth, zoomScale) {
16
16
  if (durationMs <= 0) return 0;
17
17
  const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;
18
18
  return timeMs / 1e3 * pixelsPerSecond;
19
19
  }
20
- function pixelsToTime(pixels, durationMs, containerWidth, zoomScale) {
20
+ function pixelsToTime(pixels, durationMs, _containerWidth, zoomScale) {
21
21
  if (durationMs <= 0) return 0;
22
22
  return pixels / (BASE_PIXELS_PER_SECOND * zoomScale) * 1e3;
23
23
  }
@@ -78,8 +78,8 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
78
78
  this.styles = [css`
79
79
  :host {
80
80
  --ef-scrubber-height: 4px;
81
- --ef-scrubber-background: rgb(209 213 219);
82
- --ef-scrubber-progress-color: rgb(37 99 235);
81
+ --ef-scrubber-background: var(--ef-color-border, rgba(255, 255, 255, 0.2));
82
+ --ef-scrubber-progress-color: var(--ef-color-primary, #fff);
83
83
  --ef-scrubber-handle-size: 12px;
84
84
  width: 100%;
85
85
  display: flex;
@@ -87,11 +87,6 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
87
87
  justify-content: center;
88
88
  }
89
89
 
90
- :host(.dark), :host-context(.dark) {
91
- --ef-scrubber-background: rgb(75 85 99);
92
- --ef-scrubber-progress-color: rgb(96 165 250);
93
- }
94
-
95
90
  :host([orientation="vertical"]) {
96
91
  width: 100%;
97
92
  height: 100%;
@@ -175,7 +170,7 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
175
170
  top: 0;
176
171
  bottom: 0;
177
172
  width: 2px;
178
- background: rgba(37, 99, 235, 0.2);
173
+ background: color-mix(in srgb, var(--ef-color-primary) 20%, transparent);
179
174
  pointer-events: none;
180
175
  z-index: 20;
181
176
  }
@@ -303,8 +298,8 @@ let EFScrubber = class EFScrubber$1 extends TargetOrContextMixin(LitElement, efC
303
298
  @pointerdown=${this.handlePointerDown}
304
299
  @contextmenu=${this.boundHandleContextMenu}
305
300
  >
306
- <div class="progress" style="width: ${displayProgress * 100}%"></div>
307
- <div class="handle" style="left: ${displayProgress * 100}%"></div>
301
+ <div part="progress" class="progress" style="width: ${displayProgress * 100}%"></div>
302
+ <div part="handle" class="handle" style="left: ${displayProgress * 100}%"></div>
308
303
  </div>
309
304
  `;
310
305
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EFScrubber.js","names":["EFScrubber"],"sources":["../../src/gui/EFScrubber.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport {\n customElement,\n eventOptions,\n property,\n state,\n} from \"lit/decorators.js\";\n\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport type { ControllableInterface } from \"./Controllable.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { playingContext } from \"./playingContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\nimport { quantizeToFrameTimeMs } from \"./EFTimelineRuler.js\";\n\nconst BASE_PIXELS_PER_SECOND = 100;\n\nfunction timeToPixels(\n timeMs: number,\n durationMs: number,\n containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (timeMs / 1000) * pixelsPerSecond;\n}\n\nfunction pixelsToTime(\n pixels: number,\n durationMs: number,\n containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (pixels / pixelsPerSecond) * 1000;\n}\n\n@customElement(\"ef-scrubber\")\nexport class EFScrubber extends TargetOrContextMixin(LitElement, efContext) {\n static styles = [\n css`\n :host {\n --ef-scrubber-height: 4px;\n --ef-scrubber-background: rgb(209 213 219);\n --ef-scrubber-progress-color: rgb(37 99 235);\n --ef-scrubber-handle-size: 12px;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n :host(.dark), :host-context(.dark) {\n --ef-scrubber-background: rgb(75 85 99);\n --ef-scrubber-progress-color: rgb(96 165 250);\n }\n \n :host([orientation=\"vertical\"]) {\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n pointer-events: auto;\n }\n\n .scrubber {\n width: 100%;\n height: var(--ef-scrubber-height);\n background: var(--ef-scrubber-background);\n position: relative;\n cursor: pointer;\n border-radius: 2px;\n touch-action: none;\n user-select: none;\n }\n\n :host([orientation=\"vertical\"]) .scrubber {\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: ew-resize;\n }\n\n .progress {\n position: absolute;\n height: 100%;\n background: var(--ef-scrubber-progress-color);\n border-radius: 2px;\n }\n\n :host([orientation=\"vertical\"]) .progress {\n display: none;\n }\n\n .handle {\n position: absolute;\n width: var(--ef-scrubber-handle-size);\n height: var(--ef-scrubber-handle-size);\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n }\n\n :host([orientation=\"vertical\"]) .handle {\n display: none;\n }\n\n .playhead {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--ef-scrubber-progress-color);\n pointer-events: auto;\n cursor: ew-resize;\n z-index: 30;\n }\n\n ::part(playhead) {\n z-index: 30;\n }\n\n .playhead-handle {\n position: absolute;\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 12px;\n height: 12px;\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n }\n\n .raw-preview {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: rgba(37, 99, 235, 0.2);\n pointer-events: none;\n z-index: 20;\n }\n\n /* Add CSS Shadow Parts */\n ::part(scrubber) { }\n ::part(progress) { }\n ::part(handle) { }\n `,\n ];\n\n @consume({ context: playingContext, subscribe: true })\n playing = false;\n\n @consume({ context: currentTimeContext, subscribe: true })\n contextCurrentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n @property({ type: String, attribute: \"orientation\" })\n orientation: \"horizontal\" | \"vertical\" = \"horizontal\";\n\n @property({ type: Number, attribute: \"current-time-ms\" })\n currentTimeMs = Number.NaN;\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @property({ type: Number, attribute: \"zoom-scale\" })\n zoomScale = 1.0;\n\n @property({ type: Number, attribute: \"container-width\" })\n containerWidth = 0;\n\n @property({ type: Number, attribute: \"fps\" })\n fps?: number;\n\n @property({ type: Number, attribute: \"raw-scrub-time-ms\" })\n rawScrubTimeMs?: number | null;\n\n @property({ attribute: false })\n scrollContainerRef?: { current: HTMLElement | null };\n\n /**\n * Reference to the element that represents the actual track content area.\n * Used to calculate the offset between the scroll container and where tracks begin.\n */\n @property({ attribute: false })\n trackContentRef?: { current: HTMLElement | null };\n\n @property({ attribute: false })\n onSeek?: (time: number) => void;\n\n @property({ attribute: false })\n isScrubbingRef?: { current: boolean };\n\n get context(): ControllableInterface | null {\n return this.effectiveContext;\n }\n\n get effectiveCurrentTimeMs(): number {\n if (!Number.isNaN(this.currentTimeMs)) {\n return this.currentTimeMs;\n }\n if (!Number.isNaN(this.contextCurrentTimeMs)) {\n return this.contextCurrentTimeMs;\n }\n return 0;\n }\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n get isTimelineMode(): boolean {\n return this.orientation === \"vertical\" && this.zoomScale > 0;\n }\n\n @state()\n private scrubProgress = 0;\n\n @state()\n private isMoving = false;\n\n private scrubberRef = createRef<HTMLElement>();\n private _scrubberElement?: HTMLElement;\n private capturedPointerId: number | null = null;\n\n private updateProgress(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n const duration = this.effectiveDurationMs;\n if (duration <= 0) return;\n\n if (this.isTimelineMode) {\n // Timeline mode: use pixel-based positioning with zoom\n const scrollContainer =\n this.scrollContainerRef?.current || scrubberEl.parentElement;\n if (!scrollContainer) return;\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const scrollLeft = scrollContainer.scrollLeft || 0;\n\n // Calculate pixel offset dynamically from the track content element\n // This accounts for any hierarchy panel or other elements before the tracks\n let pixelOffset = 0;\n if (this.trackContentRef?.current) {\n const trackRect = this.trackContentRef.current.getBoundingClientRect();\n pixelOffset =\n trackRect.left -\n scrollContainerRect.left +\n scrollContainer.scrollLeft;\n }\n\n const x = e.clientX - scrollContainerRect.left - pixelOffset;\n const pixelPosition = scrollLeft + x;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrollContainerRect.width;\n if (effectiveWidth <= 0) return;\n\n let rawTime = pixelsToTime(\n pixelPosition,\n duration,\n effectiveWidth,\n this.zoomScale,\n );\n rawTime = Math.max(0, Math.min(rawTime, duration));\n\n // Quantize to frame boundaries if FPS is provided, then clamp to duration\n let quantizedTime =\n this.fps && this.fps > 0\n ? quantizeToFrameTimeMs(rawTime, this.fps)\n : rawTime;\n quantizedTime = Math.max(0, Math.min(quantizedTime, duration));\n\n this.scrubProgress = quantizedTime / duration;\n\n if (this.onSeek) {\n this.onSeek(quantizedTime);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: quantizedTime,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = quantizedTime;\n }\n }\n } else {\n // Horizontal mode: simple progress calculation\n const rect = scrubberEl.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const progress = Math.max(0, Math.min(1, x / rect.width));\n\n this.scrubProgress = progress;\n const timeMs = progress * duration;\n\n if (this.onSeek) {\n this.onSeek(timeMs);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: timeMs,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = timeMs;\n }\n }\n }\n }\n\n @eventOptions({ passive: false, capture: false })\n private handlePointerDown(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n this.isMoving = true;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = true;\n }\n e.preventDefault();\n e.stopPropagation();\n this.capturedPointerId = e.pointerId;\n try {\n scrubberEl.setPointerCapture(e.pointerId);\n } catch (err) {\n // setPointerCapture may fail in some cases, continue anyway\n console.warn(\"Failed to set pointer capture:\", err);\n }\n this.updateProgress(e);\n }\n\n private boundHandlePointerMove = (e: PointerEvent) => {\n if (this.isMoving && e.pointerId === this.capturedPointerId) {\n e.preventDefault();\n e.stopPropagation();\n this.updateProgress(e);\n }\n };\n\n private boundHandlePointerUp = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n e.preventDefault();\n e.stopPropagation();\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandlePointerCancel = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandleContextMenu = (e: Event) => {\n if (this.isMoving) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n render() {\n const duration = this.effectiveDurationMs;\n const currentTime = this.effectiveCurrentTimeMs;\n\n if (duration <= 0) {\n return html``;\n }\n\n if (this.isTimelineMode) {\n // Vertical timeline mode: render playhead line\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrubberEl?.parentElement?.getBoundingClientRect().width || 0;\n\n const positionPixels =\n effectiveWidth > 0\n ? timeToPixels(currentTime, duration, effectiveWidth, this.zoomScale)\n : 0;\n\n const rawScrubPositionPixels =\n this.rawScrubTimeMs !== null &&\n this.rawScrubTimeMs !== undefined &&\n effectiveWidth > 0\n ? timeToPixels(\n this.rawScrubTimeMs,\n duration,\n effectiveWidth,\n this.zoomScale,\n )\n : null;\n\n return html`\n ${\n rawScrubPositionPixels !== null &&\n rawScrubPositionPixels !== positionPixels\n ? html`<div\n class=\"raw-preview\"\n style=\"left: ${rawScrubPositionPixels}px\"\n ></div>`\n : html``\n }\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div\n part=\"playhead\"\n class=\"playhead\"\n style=\"left: ${positionPixels}px\"\n @pointerdown=${this.handlePointerDown}\n >\n <div class=\"playhead-handle\"></div>\n </div>\n </div>\n `;\n } else {\n // Horizontal mode: render progress bar\n const currentProgress = duration > 0 ? currentTime / duration : 0;\n const displayProgress = this.isMoving\n ? this.scrubProgress\n : currentProgress;\n\n return html`\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div class=\"progress\" style=\"width: ${displayProgress * 100}%\"></div>\n <div class=\"handle\" style=\"left: ${displayProgress * 100}%\"></div>\n </div>\n `;\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n window.addEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n { passive: false },\n );\n window.addEventListener(\"pointermove\", this.boundHandlePointerMove, {\n passive: false,\n });\n window.addEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n { passive: false },\n );\n this.addEventListener(\"contextmenu\", this.boundHandleContextMenu, {\n passive: false,\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n window.removeEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n );\n window.removeEventListener(\"pointermove\", this.boundHandlePointerMove);\n window.removeEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n );\n this.removeEventListener(\"contextmenu\", this.boundHandleContextMenu);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-scrubber\": EFScrubber;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EFScrubber.js","names":["EFScrubber"],"sources":["../../src/gui/EFScrubber.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport {\n customElement,\n eventOptions,\n property,\n state,\n} from \"lit/decorators.js\";\n\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport type { ControllableInterface } from \"./Controllable.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { playingContext } from \"./playingContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\nimport { quantizeToFrameTimeMs } from \"./EFTimelineRuler.js\";\n\nconst BASE_PIXELS_PER_SECOND = 100;\n\nfunction timeToPixels(\n timeMs: number,\n durationMs: number,\n _containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (timeMs / 1000) * pixelsPerSecond;\n}\n\nfunction pixelsToTime(\n pixels: number,\n durationMs: number,\n _containerWidth: number,\n zoomScale: number,\n): number {\n if (durationMs <= 0) return 0;\n const pixelsPerSecond = BASE_PIXELS_PER_SECOND * zoomScale;\n return (pixels / pixelsPerSecond) * 1000;\n}\n\n@customElement(\"ef-scrubber\")\nexport class EFScrubber extends TargetOrContextMixin(LitElement, efContext) {\n static styles = [\n css`\n :host {\n --ef-scrubber-height: 4px;\n --ef-scrubber-background: var(--ef-color-border, rgba(255, 255, 255, 0.2));\n --ef-scrubber-progress-color: var(--ef-color-primary, #fff);\n --ef-scrubber-handle-size: 12px;\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n :host([orientation=\"vertical\"]) {\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n pointer-events: auto;\n }\n\n .scrubber {\n width: 100%;\n height: var(--ef-scrubber-height);\n background: var(--ef-scrubber-background);\n position: relative;\n cursor: pointer;\n border-radius: 2px;\n touch-action: none;\n user-select: none;\n }\n\n :host([orientation=\"vertical\"]) .scrubber {\n width: 100%;\n height: 100%;\n background: transparent;\n cursor: ew-resize;\n }\n\n .progress {\n position: absolute;\n height: 100%;\n background: var(--ef-scrubber-progress-color);\n border-radius: 2px;\n }\n\n :host([orientation=\"vertical\"]) .progress {\n display: none;\n }\n\n .handle {\n position: absolute;\n width: var(--ef-scrubber-handle-size);\n height: var(--ef-scrubber-handle-size);\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n cursor: grab;\n }\n\n :host([orientation=\"vertical\"]) .handle {\n display: none;\n }\n\n .playhead {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: var(--ef-scrubber-progress-color);\n pointer-events: auto;\n cursor: ew-resize;\n z-index: 30;\n }\n\n ::part(playhead) {\n z-index: 30;\n }\n\n .playhead-handle {\n position: absolute;\n top: 0;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 12px;\n height: 12px;\n background: var(--ef-scrubber-progress-color);\n border-radius: 50%;\n }\n\n .raw-preview {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: color-mix(in srgb, var(--ef-color-primary) 20%, transparent);\n pointer-events: none;\n z-index: 20;\n }\n\n /* Add CSS Shadow Parts */\n ::part(scrubber) { }\n ::part(progress) { }\n ::part(handle) { }\n `,\n ];\n\n @consume({ context: playingContext, subscribe: true })\n playing = false;\n\n @consume({ context: currentTimeContext, subscribe: true })\n contextCurrentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n @property({ type: String, attribute: \"orientation\" })\n orientation: \"horizontal\" | \"vertical\" = \"horizontal\";\n\n @property({ type: Number, attribute: \"current-time-ms\" })\n currentTimeMs = Number.NaN;\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @property({ type: Number, attribute: \"zoom-scale\" })\n zoomScale = 1.0;\n\n @property({ type: Number, attribute: \"container-width\" })\n containerWidth = 0;\n\n @property({ type: Number, attribute: \"fps\" })\n fps?: number;\n\n @property({ type: Number, attribute: \"raw-scrub-time-ms\" })\n rawScrubTimeMs?: number | null;\n\n @property({ attribute: false })\n scrollContainerRef?: { current: HTMLElement | null };\n\n /**\n * Reference to the element that represents the actual track content area.\n * Used to calculate the offset between the scroll container and where tracks begin.\n */\n @property({ attribute: false })\n trackContentRef?: { current: HTMLElement | null };\n\n @property({ attribute: false })\n onSeek?: (time: number) => void;\n\n @property({ attribute: false })\n isScrubbingRef?: { current: boolean };\n\n get context(): ControllableInterface | null {\n return this.effectiveContext;\n }\n\n get effectiveCurrentTimeMs(): number {\n if (!Number.isNaN(this.currentTimeMs)) {\n return this.currentTimeMs;\n }\n if (!Number.isNaN(this.contextCurrentTimeMs)) {\n return this.contextCurrentTimeMs;\n }\n return 0;\n }\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n get isTimelineMode(): boolean {\n return this.orientation === \"vertical\" && this.zoomScale > 0;\n }\n\n @state()\n private scrubProgress = 0;\n\n @state()\n private isMoving = false;\n\n private scrubberRef = createRef<HTMLElement>();\n private _scrubberElement?: HTMLElement;\n private capturedPointerId: number | null = null;\n\n private updateProgress(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n const duration = this.effectiveDurationMs;\n if (duration <= 0) return;\n\n if (this.isTimelineMode) {\n // Timeline mode: use pixel-based positioning with zoom\n const scrollContainer =\n this.scrollContainerRef?.current || scrubberEl.parentElement;\n if (!scrollContainer) return;\n\n const scrollContainerRect = scrollContainer.getBoundingClientRect();\n const scrollLeft = scrollContainer.scrollLeft || 0;\n\n // Calculate pixel offset dynamically from the track content element\n // This accounts for any hierarchy panel or other elements before the tracks\n let pixelOffset = 0;\n if (this.trackContentRef?.current) {\n const trackRect = this.trackContentRef.current.getBoundingClientRect();\n pixelOffset =\n trackRect.left -\n scrollContainerRect.left +\n scrollContainer.scrollLeft;\n }\n\n const x = e.clientX - scrollContainerRect.left - pixelOffset;\n const pixelPosition = scrollLeft + x;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrollContainerRect.width;\n if (effectiveWidth <= 0) return;\n\n let rawTime = pixelsToTime(\n pixelPosition,\n duration,\n effectiveWidth,\n this.zoomScale,\n );\n rawTime = Math.max(0, Math.min(rawTime, duration));\n\n // Quantize to frame boundaries if FPS is provided, then clamp to duration\n let quantizedTime =\n this.fps && this.fps > 0\n ? quantizeToFrameTimeMs(rawTime, this.fps)\n : rawTime;\n quantizedTime = Math.max(0, Math.min(quantizedTime, duration));\n\n this.scrubProgress = quantizedTime / duration;\n\n if (this.onSeek) {\n this.onSeek(quantizedTime);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: quantizedTime,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = quantizedTime;\n }\n }\n } else {\n // Horizontal mode: simple progress calculation\n const rect = scrubberEl.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const progress = Math.max(0, Math.min(1, x / rect.width));\n\n this.scrubProgress = progress;\n const timeMs = progress * duration;\n\n if (this.onSeek) {\n this.onSeek(timeMs);\n } else {\n // Emit seek event for event listeners\n this.dispatchEvent(\n new CustomEvent(\"seek\", {\n detail: timeMs,\n bubbles: true,\n composed: true,\n }),\n );\n if (this.context) {\n this.context.currentTimeMs = timeMs;\n }\n }\n }\n }\n\n @eventOptions({ passive: false, capture: false })\n private handlePointerDown(e: PointerEvent) {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (!scrubberEl) return;\n\n this.isMoving = true;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = true;\n }\n e.preventDefault();\n e.stopPropagation();\n this.capturedPointerId = e.pointerId;\n try {\n scrubberEl.setPointerCapture(e.pointerId);\n } catch (err) {\n // setPointerCapture may fail in some cases, continue anyway\n console.warn(\"Failed to set pointer capture:\", err);\n }\n this.updateProgress(e);\n }\n\n private boundHandlePointerMove = (e: PointerEvent) => {\n if (this.isMoving && e.pointerId === this.capturedPointerId) {\n e.preventDefault();\n e.stopPropagation();\n this.updateProgress(e);\n }\n };\n\n private boundHandlePointerUp = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n e.preventDefault();\n e.stopPropagation();\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandlePointerCancel = (e: PointerEvent) => {\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n if (e.pointerId === this.capturedPointerId && scrubberEl) {\n try {\n scrubberEl.releasePointerCapture(e.pointerId);\n } catch (_err) {\n // releasePointerCapture may fail if capture was already lost\n }\n this.capturedPointerId = null;\n this.isMoving = false;\n if (this.isScrubbingRef) {\n this.isScrubbingRef.current = false;\n }\n }\n };\n\n private boundHandleContextMenu = (e: Event) => {\n if (this.isMoving) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n\n render() {\n const duration = this.effectiveDurationMs;\n const currentTime = this.effectiveCurrentTimeMs;\n\n if (duration <= 0) {\n return html``;\n }\n\n if (this.isTimelineMode) {\n // Vertical timeline mode: render playhead line\n const scrubberEl = this.scrubberRef.value || this._scrubberElement;\n const effectiveWidth =\n this.containerWidth > 0\n ? this.containerWidth\n : scrubberEl?.parentElement?.getBoundingClientRect().width || 0;\n\n const positionPixels =\n effectiveWidth > 0\n ? timeToPixels(currentTime, duration, effectiveWidth, this.zoomScale)\n : 0;\n\n const rawScrubPositionPixels =\n this.rawScrubTimeMs !== null &&\n this.rawScrubTimeMs !== undefined &&\n effectiveWidth > 0\n ? timeToPixels(\n this.rawScrubTimeMs,\n duration,\n effectiveWidth,\n this.zoomScale,\n )\n : null;\n\n return html`\n ${\n rawScrubPositionPixels !== null &&\n rawScrubPositionPixels !== positionPixels\n ? html`<div\n class=\"raw-preview\"\n style=\"left: ${rawScrubPositionPixels}px\"\n ></div>`\n : html``\n }\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div\n part=\"playhead\"\n class=\"playhead\"\n style=\"left: ${positionPixels}px\"\n @pointerdown=${this.handlePointerDown}\n >\n <div class=\"playhead-handle\"></div>\n </div>\n </div>\n `;\n } else {\n // Horizontal mode: render progress bar\n const currentProgress = duration > 0 ? currentTime / duration : 0;\n const displayProgress = this.isMoving\n ? this.scrubProgress\n : currentProgress;\n\n return html`\n <div\n ${ref(this.scrubberRef)}\n part=\"scrubber\"\n class=\"scrubber\"\n @pointerdown=${this.handlePointerDown}\n @contextmenu=${this.boundHandleContextMenu}\n >\n <div part=\"progress\" class=\"progress\" style=\"width: ${displayProgress * 100}%\"></div>\n <div part=\"handle\" class=\"handle\" style=\"left: ${displayProgress * 100}%\"></div>\n </div>\n `;\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n window.addEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n { passive: false },\n );\n window.addEventListener(\"pointermove\", this.boundHandlePointerMove, {\n passive: false,\n });\n window.addEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n { passive: false },\n );\n this.addEventListener(\"contextmenu\", this.boundHandleContextMenu, {\n passive: false,\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n window.removeEventListener(\n \"pointerup\",\n this.boundHandlePointerUp as EventListener,\n );\n window.removeEventListener(\"pointermove\", this.boundHandlePointerMove);\n window.removeEventListener(\n \"pointercancel\",\n this.boundHandlePointerCancel as EventListener,\n );\n this.removeEventListener(\"contextmenu\", this.boundHandleContextMenu);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-scrubber\": EFScrubber;\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit19 from "lit";
2
+ import * as lit21 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html19 from "lit-html";
4
+ import * as lit_html20 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTimeDisplay.d.ts
7
7
  declare const EFTimeDisplay_base: (new (...args: any[]) => {
@@ -10,11 +10,15 @@ declare const EFTimeDisplay_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFTimeDisplay extends EFTimeDisplay_base {
13
- static styles: lit19.CSSResult;
13
+ static styles: lit21.CSSResult;
14
14
  currentTimeMs: number;
15
15
  durationMs: number;
16
+ contextCurrentTimeMs: number;
17
+ contextDurationMs: number;
18
+ get effectiveCurrentTimeMs(): number;
19
+ get effectiveDurationMs(): number;
16
20
  private formatTime;
17
- render(): lit_html19.TemplateResult<1>;
21
+ render(): lit_html20.TemplateResult<1>;
18
22
  }
19
23
  declare global {
20
24
  interface HTMLElementTagNameMap {
@@ -1,11 +1,11 @@
1
+ import { efContext } from "./efContext.js";
1
2
  import { currentTimeContext } from "./currentTimeContext.js";
2
3
  import { durationContext } from "./durationContext.js";
3
4
  import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
4
- import { efContext } from "./efContext.js";
5
5
  import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
6
6
  import { consume } from "@lit/context";
7
7
  import { LitElement, css, html } from "lit";
8
- import { customElement } from "lit/decorators.js";
8
+ import { customElement, property } from "lit/decorators.js";
9
9
 
10
10
  //#region src/gui/EFTimeDisplay.ts
11
11
  let EFTimeDisplay = class EFTimeDisplay$1 extends TargetOrContextMixin(LitElement, efContext) {
@@ -13,6 +13,8 @@ let EFTimeDisplay = class EFTimeDisplay$1 extends TargetOrContextMixin(LitElemen
13
13
  super(..._args);
14
14
  this.currentTimeMs = NaN;
15
15
  this.durationMs = 0;
16
+ this.contextCurrentTimeMs = NaN;
17
+ this.contextDurationMs = 0;
16
18
  }
17
19
  static {
18
20
  this.styles = css`
@@ -21,21 +23,29 @@ let EFTimeDisplay = class EFTimeDisplay$1 extends TargetOrContextMixin(LitElemen
21
23
  align-items: center;
22
24
  font-family: var(--ef-font-family, system-ui);
23
25
  font-size: var(--ef-font-size-xs, 0.75rem);
24
- color: var(--ef-text-color, rgb(75 85 99));
26
+ color: var(--ef-text-color, var(--ef-color-text));
25
27
  white-space: nowrap;
26
28
  }
27
29
 
28
30
  ::part(time) {}
29
31
  `;
30
32
  }
33
+ get effectiveCurrentTimeMs() {
34
+ if (!Number.isNaN(this.currentTimeMs)) return this.currentTimeMs;
35
+ if (!Number.isNaN(this.contextCurrentTimeMs)) return this.contextCurrentTimeMs;
36
+ return 0;
37
+ }
38
+ get effectiveDurationMs() {
39
+ return this.durationMs || this.contextDurationMs || 0;
40
+ }
31
41
  formatTime(ms) {
32
42
  if (!Number.isFinite(ms) || ms < 0) return "0:00";
33
43
  const totalSeconds = Math.floor(ms / 1e3);
34
44
  return `${Math.floor(totalSeconds / 60)}:${(totalSeconds % 60).toString().padStart(2, "0")}`;
35
45
  }
36
46
  render() {
37
- const currentTime = this.currentTimeMs;
38
- const totalTime = this.durationMs;
47
+ const currentTime = this.effectiveCurrentTimeMs;
48
+ const totalTime = this.effectiveDurationMs;
39
49
  return html`
40
50
  <span part="time">
41
51
  ${this.formatTime(currentTime)} / ${this.formatTime(totalTime)}
@@ -43,14 +53,22 @@ let EFTimeDisplay = class EFTimeDisplay$1 extends TargetOrContextMixin(LitElemen
43
53
  `;
44
54
  }
45
55
  };
56
+ __decorate([property({
57
+ type: Number,
58
+ attribute: "current-time-ms"
59
+ })], EFTimeDisplay.prototype, "currentTimeMs", void 0);
60
+ __decorate([property({
61
+ type: Number,
62
+ attribute: "duration-ms"
63
+ })], EFTimeDisplay.prototype, "durationMs", void 0);
46
64
  __decorate([consume({
47
65
  context: currentTimeContext,
48
66
  subscribe: true
49
- })], EFTimeDisplay.prototype, "currentTimeMs", void 0);
67
+ })], EFTimeDisplay.prototype, "contextCurrentTimeMs", void 0);
50
68
  __decorate([consume({
51
69
  context: durationContext,
52
70
  subscribe: true
53
- })], EFTimeDisplay.prototype, "durationMs", void 0);
71
+ })], EFTimeDisplay.prototype, "contextDurationMs", void 0);
54
72
  EFTimeDisplay = __decorate([customElement("ef-time-display")], EFTimeDisplay);
55
73
 
56
74
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"EFTimeDisplay.js","names":["EFTimeDisplay"],"sources":["../../src/gui/EFTimeDisplay.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement } from \"lit/decorators.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\n\n@customElement(\"ef-time-display\")\nexport class EFTimeDisplay extends TargetOrContextMixin(LitElement, efContext) {\n static styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n font-family: var(--ef-font-family, system-ui);\n font-size: var(--ef-font-size-xs, 0.75rem);\n color: var(--ef-text-color, rgb(75 85 99));\n white-space: nowrap;\n }\n\n ::part(time) {}\n `;\n\n @consume({ context: currentTimeContext, subscribe: true })\n currentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n durationMs = 0;\n\n private formatTime(ms: number): string {\n // Handle NaN, undefined, null, or negative values\n if (!Number.isFinite(ms) || ms < 0) {\n return \"0:00\";\n }\n\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n render() {\n const currentTime = this.currentTimeMs;\n const totalTime = this.durationMs;\n\n return html`\n <span part=\"time\">\n ${this.formatTime(currentTime)} / ${this.formatTime(totalTime)}\n </span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-time-display\": EFTimeDisplay;\n }\n}\n"],"mappings":";;;;;;;;;;AASO,0BAAMA,wBAAsB,qBAAqB,YAAY,UAAU,CAAC;;;uBAe7D;oBAGH;;;gBAjBG,GAAG;;;;;;;;;;;;;CAmBnB,AAAQ,WAAW,IAAoB;AAErC,MAAI,CAAC,OAAO,SAAS,GAAG,IAAI,KAAK,EAC/B,QAAO;EAGT,MAAM,eAAe,KAAK,MAAM,KAAK,IAAK;AAG1C,SAAO,GAFS,KAAK,MAAM,eAAe,GAAG,CAE3B,IADF,eAAe,IACF,UAAU,CAAC,SAAS,GAAG,IAAI;;CAG1D,SAAS;EACP,MAAM,cAAc,KAAK;EACzB,MAAM,YAAY,KAAK;AAEvB,SAAO,IAAI;;UAEL,KAAK,WAAW,YAAY,CAAC,KAAK,KAAK,WAAW,UAAU,CAAC;;;;;YAxBpE,QAAQ;CAAE,SAAS;CAAoB,WAAW;CAAM,CAAC;YAGzD,QAAQ;CAAE,SAAS;CAAiB,WAAW;CAAM,CAAC;4BAlBxD,cAAc,kBAAkB"}
1
+ {"version":3,"file":"EFTimeDisplay.js","names":["EFTimeDisplay"],"sources":["../../src/gui/EFTimeDisplay.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { currentTimeContext } from \"./currentTimeContext.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport { efContext } from \"./efContext.js\";\nimport { TargetOrContextMixin } from \"./TargetOrContextMixin.js\";\n\n@customElement(\"ef-time-display\")\nexport class EFTimeDisplay extends TargetOrContextMixin(LitElement, efContext) {\n static styles = css`\n :host {\n display: inline-flex;\n align-items: center;\n font-family: var(--ef-font-family, system-ui);\n font-size: var(--ef-font-size-xs, 0.75rem);\n color: var(--ef-text-color, var(--ef-color-text));\n white-space: nowrap;\n }\n\n ::part(time) {}\n `;\n\n @property({ type: Number, attribute: \"current-time-ms\" })\n currentTimeMs = Number.NaN;\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @consume({ context: currentTimeContext, subscribe: true })\n contextCurrentTimeMs = Number.NaN;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n get effectiveCurrentTimeMs(): number {\n if (!Number.isNaN(this.currentTimeMs)) return this.currentTimeMs;\n if (!Number.isNaN(this.contextCurrentTimeMs))\n return this.contextCurrentTimeMs;\n return 0;\n }\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n private formatTime(ms: number): string {\n // Handle NaN, undefined, null, or negative values\n if (!Number.isFinite(ms) || ms < 0) {\n return \"0:00\";\n }\n\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n }\n\n render() {\n const currentTime = this.effectiveCurrentTimeMs;\n const totalTime = this.effectiveDurationMs;\n\n return html`\n <span part=\"time\">\n ${this.formatTime(currentTime)} / ${this.formatTime(totalTime)}\n </span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-time-display\": EFTimeDisplay;\n }\n}\n"],"mappings":";;;;;;;;;;AASO,0BAAMA,wBAAsB,qBAAqB,YAAY,UAAU,CAAC;;;uBAe7D;oBAGH;8BAGU;2BAGH;;;gBAvBJ,GAAG;;;;;;;;;;;;;CAyBnB,IAAI,yBAAiC;AACnC,MAAI,CAAC,OAAO,MAAM,KAAK,cAAc,CAAE,QAAO,KAAK;AACnD,MAAI,CAAC,OAAO,MAAM,KAAK,qBAAqB,CAC1C,QAAO,KAAK;AACd,SAAO;;CAGT,IAAI,sBAA8B;AAChC,SAAO,KAAK,cAAc,KAAK,qBAAqB;;CAGtD,AAAQ,WAAW,IAAoB;AAErC,MAAI,CAAC,OAAO,SAAS,GAAG,IAAI,KAAK,EAC/B,QAAO;EAGT,MAAM,eAAe,KAAK,MAAM,KAAK,IAAK;AAG1C,SAAO,GAFS,KAAK,MAAM,eAAe,GAAG,CAE3B,IADF,eAAe,IACF,UAAU,CAAC,SAAS,GAAG,IAAI;;CAG1D,SAAS;EACP,MAAM,cAAc,KAAK;EACzB,MAAM,YAAY,KAAK;AAEvB,SAAO,IAAI;;UAEL,KAAK,WAAW,YAAY,CAAC,KAAK,KAAK,WAAW,UAAU,CAAC;;;;;YAzCpE,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAmB,CAAC;YAGxD,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAe,CAAC;YAGpD,QAAQ;CAAE,SAAS;CAAoB,WAAW;CAAM,CAAC;YAGzD,QAAQ;CAAE,SAAS;CAAiB,WAAW;CAAM,CAAC;4BAxBxD,cAAc,kBAAkB"}
@@ -1,7 +1,7 @@
1
1
  import { TimelineState } from "./timeline/timelineStateContext.js";
2
- import * as lit33 from "lit";
2
+ import * as lit32 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html32 from "lit-html";
4
+ import * as lit_html30 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTimelineRuler.d.ts
7
7
  /**
@@ -25,7 +25,7 @@ declare function calculatePixelsPerFrame(frameIntervalMs: number, pixelsPerMs: n
25
25
  */
26
26
  declare function shouldShowFrameMarkers(pixelsPerFrame: number, minSpacing?: number): boolean;
27
27
  declare class EFTimelineRuler extends LitElement {
28
- static styles: lit33.CSSResult[];
28
+ static styles: lit32.CSSResult[];
29
29
  durationMs: number;
30
30
  contextDurationMs: number;
31
31
  timelineState?: TimelineState;
@@ -59,7 +59,7 @@ declare class EFTimelineRuler extends LitElement {
59
59
  private calculateLabelInterval;
60
60
  private getVisibleLabels;
61
61
  private renderCanvas;
62
- render(): lit_html32.TemplateResult<1>;
62
+ render(): lit_html30.TemplateResult<1>;
63
63
  }
64
64
  declare global {
65
65
  interface HTMLElementTagNameMap {
@@ -96,7 +96,7 @@ let EFTimelineRuler = class EFTimelineRuler$1 extends LitElement {
96
96
  position: absolute;
97
97
  top: 50%;
98
98
  font-size: 10px;
99
- color: rgb(156, 163, 175);
99
+ color: var(--ef-color-text-muted);
100
100
  font-family: ui-monospace, monospace;
101
101
  white-space: nowrap;
102
102
  pointer-events: none;
@@ -231,7 +231,7 @@ let EFTimelineRuler = class EFTimelineRuler$1 extends LitElement {
231
231
  ctx.clearRect(0, 0, width, height);
232
232
  const pixelsPerMs = this.pixelsPerMs;
233
233
  const canvasLeft = viewport.left;
234
- ctx.strokeStyle = "rgb(156, 163, 175)";
234
+ ctx.strokeStyle = getComputedStyle(this).getPropertyValue("--ef-color-text-muted").trim() || "rgb(156, 163, 175)";
235
235
  ctx.lineWidth = 1;
236
236
  const labelIntervalMs = this.calculateLabelInterval();
237
237
  const visibleStartTimeMs = Math.max(0, canvasLeft / pixelsPerMs - labelIntervalMs);
@@ -251,7 +251,7 @@ let EFTimelineRuler = class EFTimelineRuler$1 extends LitElement {
251
251
  }
252
252
  const frameIntervalMs = 1e3 / this.fps;
253
253
  if (frameIntervalMs * pixelsPerMs >= MIN_FRAME_SPACING_PX) {
254
- ctx.strokeStyle = "rgb(107, 114, 128)";
254
+ ctx.strokeStyle = getComputedStyle(this).getPropertyValue("--ef-color-border-subtle").trim() || "rgb(107, 114, 128)";
255
255
  ctx.lineWidth = 1;
256
256
  const firstFrameIndex = Math.floor(visibleStartTimeMs / frameIntervalMs);
257
257
  const lastFrameIndex = Math.ceil(visibleEndTimeMs / frameIntervalMs);
@@ -1 +1 @@
1
- {"version":3,"file":"EFTimelineRuler.js","names":["EFTimelineRuler","labels: VisibleLabel[]"],"sources":["../../src/gui/EFTimelineRuler.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport {\n timelineStateContext,\n type TimelineState,\n DEFAULT_PIXELS_PER_MS,\n} from \"./timeline/timelineStateContext.js\";\n\nconst MIN_LABEL_SPACING_PX = 80;\nconst MIN_FRAME_SPACING_PX = 5;\n\n/** Maximum canvas width for ruler virtualization */\nconst MAX_RULER_CANVAS_WIDTH = 2000;\n\n/** Buffer pixels on each side of viewport for smooth scrolling */\nconst RULER_CANVAS_BUFFER = 200;\n\n/**\n * Quantize a time value to the nearest frame boundary.\n * This ensures frame markers align perfectly with playhead position.\n */\nexport function quantizeToFrameTimeMs(timeMs: number, fps: number): number {\n if (!fps || fps <= 0) return timeMs;\n const frameDurationS = 1 / fps;\n const timeSeconds = timeMs / 1000;\n const quantizedSeconds =\n Math.round(timeSeconds / frameDurationS) * frameDurationS;\n return quantizedSeconds * 1000;\n}\n\n/**\n * Calculate the duration of a single frame in milliseconds.\n */\nexport function calculateFrameIntervalMs(fps: number): number {\n if (fps <= 0) return 1000 / 30; // fallback to 30fps\n return 1000 / fps;\n}\n\n/**\n * Calculate pixels per frame given frame interval and zoom scale.\n * @param frameIntervalMs Duration of one frame in ms\n * @param pixelsPerMs Current zoom level (pixels per millisecond)\n */\nexport function calculatePixelsPerFrame(\n frameIntervalMs: number,\n pixelsPerMs: number,\n): number {\n return frameIntervalMs * pixelsPerMs;\n}\n\n/**\n * Determine if frame markers should be visible at the current zoom level.\n * Frame markers appear when each frame is at least MIN_FRAME_SPACING_PX wide.\n */\nexport function shouldShowFrameMarkers(\n pixelsPerFrame: number,\n minSpacing: number = MIN_FRAME_SPACING_PX,\n): boolean {\n return pixelsPerFrame >= minSpacing;\n}\n\ninterface VisibleLabel {\n timeMs: number;\n viewportX: number;\n text: string;\n}\n\n@customElement(\"ef-timeline-ruler\")\nexport class EFTimelineRuler extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n height: 100%;\n pointer-events: none;\n }\n \n .ruler-container {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n \n .canvas-viewport {\n position: absolute;\n top: 0;\n height: 100%;\n /* left and width set via inline styles for virtualization */\n }\n \n canvas {\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n }\n \n .label {\n position: absolute;\n top: 50%;\n font-size: 10px;\n color: rgb(156, 163, 175);\n font-family: ui-monospace, monospace;\n white-space: nowrap;\n pointer-events: none;\n user-select: none;\n }\n `,\n ];\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n @consume({ context: timelineStateContext, subscribe: true })\n timelineState?: TimelineState;\n\n @property({ type: Number, attribute: \"fps\" })\n fps = 30;\n\n /** Full content width in pixels (for virtualization) */\n @property({ type: Number, attribute: \"content-width\" })\n contentWidth = 0;\n\n private containerRef = createRef<HTMLDivElement>();\n private canvasRef = createRef<HTMLCanvasElement>();\n private resizeObserver?: ResizeObserver;\n\n @state()\n private viewportWidth = 0;\n\n /** Canvas viewport left position for virtualization */\n @state()\n private _canvasViewportLeft = 0;\n\n /** Canvas viewport width for virtualization */\n @state()\n private _canvasViewportWidth = 0;\n\n /** Last rendered scroll position - for detecting scroll changes */\n private _lastRenderedScrollLeft = -1;\n\n /** Last rendered viewport width - for detecting viewport changes */\n private _lastRenderedViewportWidth = 0;\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n get pixelsPerMs(): number {\n return this.timelineState?.pixelsPerMs ?? DEFAULT_PIXELS_PER_MS;\n }\n\n get scrollLeft(): number {\n return this.timelineState?.viewportScrollLeft ?? 0;\n }\n\n /**\n * Calculate canvas viewport bounds for virtualization.\n * Returns the left position and width of the canvas viewport.\n */\n private calculateCanvasViewport(): { left: number; width: number } {\n const totalWidth = this.contentWidth || this.viewportWidth;\n \n // If content is small enough, no virtualization needed\n if (totalWidth <= MAX_RULER_CANVAS_WIDTH) {\n return { left: 0, width: totalWidth };\n }\n\n // Get visible region from scroll position\n const viewportScrollLeft = this.scrollLeft;\n const viewportWidth = this.timelineState?.viewportWidth ?? this.viewportWidth;\n\n // Calculate canvas viewport with buffer for smooth scrolling\n const canvasLeft = Math.max(0, viewportScrollLeft - RULER_CANVAS_BUFFER);\n const canvasRight = Math.min(\n totalWidth,\n viewportScrollLeft + viewportWidth + RULER_CANVAS_BUFFER\n );\n\n // Cap canvas width at maximum\n let canvasWidth = canvasRight - canvasLeft;\n if (canvasWidth > MAX_RULER_CANVAS_WIDTH) {\n canvasWidth = MAX_RULER_CANVAS_WIDTH;\n }\n\n return { left: canvasLeft, width: canvasWidth };\n }\n\n connectedCallback() {\n super.connectedCallback();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n }\n\n protected firstUpdated(): void {\n const container = this.containerRef.value;\n if (container) {\n this.resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n const width = entry.contentRect.width;\n if (width !== this.viewportWidth) {\n this.viewportWidth = width;\n }\n }\n });\n this.resizeObserver.observe(container);\n this.viewportWidth = container.clientWidth;\n }\n }\n\n protected updated(changedProperties: Map<string | number | symbol, unknown>): void {\n // Check if scroll position or viewport changed from context\n const currentScrollLeft = this.scrollLeft;\n const currentViewportWidth = this.timelineState?.viewportWidth ?? this.viewportWidth;\n \n // Check if scroll changed, viewport changed, or other relevant properties changed\n const scrollChanged = currentScrollLeft !== this._lastRenderedScrollLeft;\n const viewportChanged = currentViewportWidth !== this._lastRenderedViewportWidth;\n const pixelsPerMsChanged = changedProperties.has(\"timelineState\") || \n changedProperties.has(\"pixelsPerMs\");\n const contentWidthChanged = changedProperties.has(\"contentWidth\");\n const durationChanged = changedProperties.has(\"durationMs\") || \n changedProperties.has(\"contextDurationMs\");\n \n // Only render if something actually changed\n if (scrollChanged || viewportChanged || pixelsPerMsChanged || \n contentWidthChanged || durationChanged || \n this._lastRenderedScrollLeft < 0) {\n this.renderCanvas();\n this._lastRenderedScrollLeft = currentScrollLeft;\n this._lastRenderedViewportWidth = currentViewportWidth;\n }\n }\n\n private calculateLabelInterval(): number {\n const pixelsPerMs = this.pixelsPerMs;\n const pixelsPerSecond = pixelsPerMs * 1000;\n\n const intervals = [0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60];\n\n for (const intervalS of intervals) {\n const pixelsPerInterval = intervalS * pixelsPerSecond;\n if (pixelsPerInterval >= MIN_LABEL_SPACING_PX) {\n return intervalS * 1000;\n }\n }\n\n return 60000;\n }\n\n private getVisibleLabels(): VisibleLabel[] {\n const canvasWidth = this._canvasViewportWidth;\n if (canvasWidth <= 0) return [];\n\n const pixelsPerMs = this.pixelsPerMs;\n const canvasLeft = this._canvasViewportLeft;\n\n const intervalMs = this.calculateLabelInterval();\n\n // Generate labels for the canvas viewport range\n const visibleStartTimeMs = Math.max(\n 0,\n canvasLeft / pixelsPerMs - intervalMs,\n );\n const visibleEndTimeMs =\n (canvasLeft + canvasWidth) / pixelsPerMs + intervalMs;\n\n const firstLabelIndex = Math.floor(visibleStartTimeMs / intervalMs);\n const lastLabelIndex = Math.ceil(visibleEndTimeMs / intervalMs);\n\n const labels: VisibleLabel[] = [];\n\n for (let i = firstLabelIndex; i <= lastLabelIndex; i++) {\n const timeMs = i * intervalMs;\n if (timeMs < 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport (canvas is positioned at canvasLeft)\n const viewportX = absoluteX - canvasLeft;\n\n if (viewportX >= -50 && viewportX <= canvasWidth + 50) {\n const timeSeconds = timeMs / 1000;\n const text =\n timeSeconds % 1 === 0\n ? `${timeSeconds}s`\n : `${timeSeconds.toFixed(1)}s`;\n\n labels.push({ timeMs, viewportX, text });\n }\n }\n\n return labels;\n }\n\n private renderCanvas(): void {\n const canvas = this.canvasRef.value;\n const container = this.containerRef.value;\n if (!canvas || !container) return;\n\n // Calculate virtualized canvas viewport\n const viewport = this.calculateCanvasViewport();\n this._canvasViewportLeft = viewport.left;\n this._canvasViewportWidth = viewport.width;\n\n const width = viewport.width;\n const height = container.getBoundingClientRect().height;\n\n if (width <= 0 || height <= 0) return;\n\n const dpr = window.devicePixelRatio || 1;\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, width, height);\n\n const pixelsPerMs = this.pixelsPerMs;\n const canvasLeft = viewport.left;\n\n // Time label ticks - more prominent (gray-400)\n ctx.strokeStyle = \"rgb(156, 163, 175)\";\n ctx.lineWidth = 1;\n\n const labelIntervalMs = this.calculateLabelInterval();\n // Fill the canvas viewport with ticks\n const visibleStartTimeMs = Math.max(\n 0,\n canvasLeft / pixelsPerMs - labelIntervalMs,\n );\n const visibleEndTimeMs =\n (canvasLeft + width) / pixelsPerMs + labelIntervalMs;\n\n const firstTickIndex = Math.floor(visibleStartTimeMs / labelIntervalMs);\n const lastTickIndex = Math.ceil(visibleEndTimeMs / labelIntervalMs);\n\n for (let i = firstTickIndex; i <= lastTickIndex; i++) {\n const timeMs = i * labelIntervalMs;\n if (timeMs < 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport\n const canvasX = absoluteX - canvasLeft;\n\n if (canvasX >= -1 && canvasX <= width + 1) {\n ctx.beginPath();\n ctx.moveTo(canvasX, 0);\n ctx.lineTo(canvasX, height * 0.4);\n ctx.stroke();\n }\n }\n\n const frameIntervalMs = 1000 / this.fps;\n const pixelsPerFrame = frameIntervalMs * pixelsPerMs;\n\n if (pixelsPerFrame >= MIN_FRAME_SPACING_PX) {\n // Frame markers should be lighter than background (gray-500) to be visible\n ctx.strokeStyle = \"rgb(107, 114, 128)\";\n ctx.lineWidth = 1;\n\n const firstFrameIndex = Math.floor(visibleStartTimeMs / frameIntervalMs);\n const lastFrameIndex = Math.ceil(visibleEndTimeMs / frameIntervalMs);\n\n for (let i = firstFrameIndex; i <= lastFrameIndex; i++) {\n const timeMs = i * frameIntervalMs;\n if (timeMs < 0) continue;\n\n if (timeMs % labelIntervalMs === 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport\n const canvasX = absoluteX - canvasLeft;\n\n if (canvasX >= -1 && canvasX <= width + 1) {\n ctx.beginPath();\n ctx.moveTo(canvasX, 0);\n ctx.lineTo(canvasX, height * 0.25);\n ctx.stroke();\n }\n }\n }\n }\n\n render() {\n const visibleLabels = this.getVisibleLabels();\n \n const canvasViewportStyles = styleMap({\n left: `${this._canvasViewportLeft}px`,\n width: `${this._canvasViewportWidth}px`,\n });\n\n return html`\n <div ${ref(this.containerRef)} class=\"ruler-container\">\n <div class=\"canvas-viewport\" style=${canvasViewportStyles}>\n <canvas ${ref(this.canvasRef)}></canvas>\n ${visibleLabels.map(\n ({ viewportX, text }) => html`\n <span \n class=\"label\" \n style=\"transform: translateX(${viewportX}px)\"\n >${text}</span>\n `,\n )}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timeline-ruler\": EFTimelineRuler;\n }\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;;AAG7B,MAAM,yBAAyB;;AAG/B,MAAM,sBAAsB;;;;;AAM5B,SAAgB,sBAAsB,QAAgB,KAAqB;AACzE,KAAI,CAAC,OAAO,OAAO,EAAG,QAAO;CAC7B,MAAM,iBAAiB,IAAI;CAC3B,MAAM,cAAc,SAAS;AAG7B,QADE,KAAK,MAAM,cAAc,eAAe,GAAG,iBACnB;;;;;AAM5B,SAAgB,yBAAyB,KAAqB;AAC5D,KAAI,OAAO,EAAG,QAAO,MAAO;AAC5B,QAAO,MAAO;;;;;;;AAQhB,SAAgB,wBACd,iBACA,aACQ;AACR,QAAO,kBAAkB;;;;;;AAO3B,SAAgB,uBACd,gBACA,aAAqB,sBACZ;AACT,QAAO,kBAAkB;;AAUpB,4BAAMA,0BAAwB,WAAW;;;oBA8CjC;2BAGO;aAMd;sBAIS;sBAEQ,WAA2B;mBAC9B,WAA8B;uBAI1B;6BAIM;8BAIC;iCAGG;oCAGG;;;gBA/ErB,CACd,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAyCJ;;CAuCD,IAAI,sBAA8B;AAChC,SAAO,KAAK,cAAc,KAAK,qBAAqB;;CAGtD,IAAI,cAAsB;AACxB,SAAO,KAAK,eAAe,eAAe;;CAG5C,IAAI,aAAqB;AACvB,SAAO,KAAK,eAAe,sBAAsB;;;;;;CAOnD,AAAQ,0BAA2D;EACjE,MAAM,aAAa,KAAK,gBAAgB,KAAK;AAG7C,MAAI,cAAc,uBAChB,QAAO;GAAE,MAAM;GAAG,OAAO;GAAY;EAIvC,MAAM,qBAAqB,KAAK;EAChC,MAAM,gBAAgB,KAAK,eAAe,iBAAiB,KAAK;EAGhE,MAAM,aAAa,KAAK,IAAI,GAAG,qBAAqB,oBAAoB;EAOxE,IAAI,cANgB,KAAK,IACvB,YACA,qBAAqB,gBAAgB,oBACtC,GAG+B;AAChC,MAAI,cAAc,uBAChB,eAAc;AAGhB,SAAO;GAAE,MAAM;GAAY,OAAO;GAAa;;CAGjD,oBAAoB;AAClB,QAAM,mBAAmB;;CAG3B,uBAAuB;AACrB,QAAM,sBAAsB;AAC5B,MAAI,KAAK,eACP,MAAK,eAAe,YAAY;;CAIpC,AAAU,eAAqB;EAC7B,MAAM,YAAY,KAAK,aAAa;AACpC,MAAI,WAAW;AACb,QAAK,iBAAiB,IAAI,gBAAgB,YAAY;IACpD,MAAM,QAAQ,QAAQ;AACtB,QAAI,OAAO;KACT,MAAM,QAAQ,MAAM,YAAY;AAChC,SAAI,UAAU,KAAK,cACjB,MAAK,gBAAgB;;KAGzB;AACF,QAAK,eAAe,QAAQ,UAAU;AACtC,QAAK,gBAAgB,UAAU;;;CAInC,AAAU,QAAQ,mBAAiE;EAEjF,MAAM,oBAAoB,KAAK;EAC/B,MAAM,uBAAuB,KAAK,eAAe,iBAAiB,KAAK;EAGvE,MAAM,gBAAgB,sBAAsB,KAAK;EACjD,MAAM,kBAAkB,yBAAyB,KAAK;EACtD,MAAM,qBAAqB,kBAAkB,IAAI,gBAAgB,IACtC,kBAAkB,IAAI,cAAc;EAC/D,MAAM,sBAAsB,kBAAkB,IAAI,eAAe;EACjE,MAAM,kBAAkB,kBAAkB,IAAI,aAAa,IACrC,kBAAkB,IAAI,oBAAoB;AAGhE,MAAI,iBAAiB,mBAAmB,sBACpC,uBAAuB,mBACvB,KAAK,0BAA0B,GAAG;AACpC,QAAK,cAAc;AACnB,QAAK,0BAA0B;AAC/B,QAAK,6BAA6B;;;CAItC,AAAQ,yBAAiC;EAEvC,MAAM,kBADc,KAAK,cACa;AAItC,OAAK,MAAM,aAFO;GAAC;GAAK;GAAM;GAAK;GAAG;GAAG;GAAG;GAAI;GAAI;GAAG,CAIrD,KAD0B,YAAY,mBACb,qBACvB,QAAO,YAAY;AAIvB,SAAO;;CAGT,AAAQ,mBAAmC;EACzC,MAAM,cAAc,KAAK;AACzB,MAAI,eAAe,EAAG,QAAO,EAAE;EAE/B,MAAM,cAAc,KAAK;EACzB,MAAM,aAAa,KAAK;EAExB,MAAM,aAAa,KAAK,wBAAwB;EAGhD,MAAM,qBAAqB,KAAK,IAC9B,GACA,aAAa,cAAc,WAC5B;EACD,MAAM,oBACH,aAAa,eAAe,cAAc;EAE7C,MAAM,kBAAkB,KAAK,MAAM,qBAAqB,WAAW;EACnE,MAAM,iBAAiB,KAAK,KAAK,mBAAmB,WAAW;EAE/D,MAAMC,SAAyB,EAAE;AAEjC,OAAK,IAAI,IAAI,iBAAiB,KAAK,gBAAgB,KAAK;GACtD,MAAM,SAAS,IAAI;AACnB,OAAI,SAAS,EAAG;GAIhB,MAAM,YAFY,SAAS,cAEG;AAE9B,OAAI,aAAa,OAAO,aAAa,cAAc,IAAI;IACrD,MAAM,cAAc,SAAS;IAC7B,MAAM,OACJ,cAAc,MAAM,IAChB,GAAG,YAAY,KACf,GAAG,YAAY,QAAQ,EAAE,CAAC;AAEhC,WAAO,KAAK;KAAE;KAAQ;KAAW;KAAM,CAAC;;;AAI5C,SAAO;;CAGT,AAAQ,eAAqB;EAC3B,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,YAAY,KAAK,aAAa;AACpC,MAAI,CAAC,UAAU,CAAC,UAAW;EAG3B,MAAM,WAAW,KAAK,yBAAyB;AAC/C,OAAK,sBAAsB,SAAS;AACpC,OAAK,uBAAuB,SAAS;EAErC,MAAM,QAAQ,SAAS;EACvB,MAAM,SAAS,UAAU,uBAAuB,CAAC;AAEjD,MAAI,SAAS,KAAK,UAAU,EAAG;EAE/B,MAAM,MAAM,OAAO,oBAAoB;AACvC,SAAO,QAAQ,QAAQ;AACvB,SAAO,SAAS,SAAS;AACzB,SAAO,MAAM,QAAQ,GAAG,MAAM;AAC9B,SAAO,MAAM,SAAS,GAAG,OAAO;EAEhC,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,MAAI,CAAC,IAAK;AAEV,MAAI,MAAM,KAAK,IAAI;AACnB,MAAI,UAAU,GAAG,GAAG,OAAO,OAAO;EAElC,MAAM,cAAc,KAAK;EACzB,MAAM,aAAa,SAAS;AAG5B,MAAI,cAAc;AAClB,MAAI,YAAY;EAEhB,MAAM,kBAAkB,KAAK,wBAAwB;EAErD,MAAM,qBAAqB,KAAK,IAC9B,GACA,aAAa,cAAc,gBAC5B;EACD,MAAM,oBACH,aAAa,SAAS,cAAc;EAEvC,MAAM,iBAAiB,KAAK,MAAM,qBAAqB,gBAAgB;EACvE,MAAM,gBAAgB,KAAK,KAAK,mBAAmB,gBAAgB;AAEnE,OAAK,IAAI,IAAI,gBAAgB,KAAK,eAAe,KAAK;GACpD,MAAM,SAAS,IAAI;AACnB,OAAI,SAAS,EAAG;GAIhB,MAAM,UAFY,SAAS,cAEC;AAE5B,OAAI,WAAW,MAAM,WAAW,QAAQ,GAAG;AACzC,QAAI,WAAW;AACf,QAAI,OAAO,SAAS,EAAE;AACtB,QAAI,OAAO,SAAS,SAAS,GAAI;AACjC,QAAI,QAAQ;;;EAIhB,MAAM,kBAAkB,MAAO,KAAK;AAGpC,MAFuB,kBAAkB,eAEnB,sBAAsB;AAE1C,OAAI,cAAc;AAClB,OAAI,YAAY;GAEhB,MAAM,kBAAkB,KAAK,MAAM,qBAAqB,gBAAgB;GACxE,MAAM,iBAAiB,KAAK,KAAK,mBAAmB,gBAAgB;AAEpE,QAAK,IAAI,IAAI,iBAAiB,KAAK,gBAAgB,KAAK;IACtD,MAAM,SAAS,IAAI;AACnB,QAAI,SAAS,EAAG;AAEhB,QAAI,SAAS,oBAAoB,EAAG;IAIpC,MAAM,UAFY,SAAS,cAEC;AAE5B,QAAI,WAAW,MAAM,WAAW,QAAQ,GAAG;AACzC,SAAI,WAAW;AACf,SAAI,OAAO,SAAS,EAAE;AACtB,SAAI,OAAO,SAAS,SAAS,IAAK;AAClC,SAAI,QAAQ;;;;;CAMpB,SAAS;EACP,MAAM,gBAAgB,KAAK,kBAAkB;EAE7C,MAAM,uBAAuB,SAAS;GACpC,MAAM,GAAG,KAAK,oBAAoB;GAClC,OAAO,GAAG,KAAK,qBAAqB;GACrC,CAAC;AAEF,SAAO,IAAI;aACF,IAAI,KAAK,aAAa,CAAC;6CACS,qBAAqB;oBAC9C,IAAI,KAAK,UAAU,CAAC;YAC5B,cAAc,KACb,EAAE,WAAW,WAAW,IAAI;;;6CAGI,UAAU;eACxC,KAAK;YAET,CAAC;;;;;;YAjTT,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAe,CAAC;YAGpD,QAAQ;CAAE,SAAS;CAAiB,WAAW;CAAM,CAAC;YAGtD,QAAQ;CAAE,SAAS;CAAsB,WAAW;CAAM,CAAC;YAG3D,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAO,CAAC;YAI5C,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAiB,CAAC;YAOtD,OAAO;YAIP,OAAO;YAIP,OAAO;8BA1ET,cAAc,oBAAoB"}
1
+ {"version":3,"file":"EFTimelineRuler.js","names":["EFTimelineRuler","labels: VisibleLabel[]"],"sources":["../../src/gui/EFTimelineRuler.ts"],"sourcesContent":["import { consume } from \"@lit/context\";\nimport { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { durationContext } from \"./durationContext.js\";\nimport {\n timelineStateContext,\n type TimelineState,\n DEFAULT_PIXELS_PER_MS,\n} from \"./timeline/timelineStateContext.js\";\n\nconst MIN_LABEL_SPACING_PX = 80;\nconst MIN_FRAME_SPACING_PX = 5;\n\n/** Maximum canvas width for ruler virtualization */\nconst MAX_RULER_CANVAS_WIDTH = 2000;\n\n/** Buffer pixels on each side of viewport for smooth scrolling */\nconst RULER_CANVAS_BUFFER = 200;\n\n/**\n * Quantize a time value to the nearest frame boundary.\n * This ensures frame markers align perfectly with playhead position.\n */\nexport function quantizeToFrameTimeMs(timeMs: number, fps: number): number {\n if (!fps || fps <= 0) return timeMs;\n const frameDurationS = 1 / fps;\n const timeSeconds = timeMs / 1000;\n const quantizedSeconds =\n Math.round(timeSeconds / frameDurationS) * frameDurationS;\n return quantizedSeconds * 1000;\n}\n\n/**\n * Calculate the duration of a single frame in milliseconds.\n */\nexport function calculateFrameIntervalMs(fps: number): number {\n if (fps <= 0) return 1000 / 30; // fallback to 30fps\n return 1000 / fps;\n}\n\n/**\n * Calculate pixels per frame given frame interval and zoom scale.\n * @param frameIntervalMs Duration of one frame in ms\n * @param pixelsPerMs Current zoom level (pixels per millisecond)\n */\nexport function calculatePixelsPerFrame(\n frameIntervalMs: number,\n pixelsPerMs: number,\n): number {\n return frameIntervalMs * pixelsPerMs;\n}\n\n/**\n * Determine if frame markers should be visible at the current zoom level.\n * Frame markers appear when each frame is at least MIN_FRAME_SPACING_PX wide.\n */\nexport function shouldShowFrameMarkers(\n pixelsPerFrame: number,\n minSpacing: number = MIN_FRAME_SPACING_PX,\n): boolean {\n return pixelsPerFrame >= minSpacing;\n}\n\ninterface VisibleLabel {\n timeMs: number;\n viewportX: number;\n text: string;\n}\n\n@customElement(\"ef-timeline-ruler\")\nexport class EFTimelineRuler extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n position: relative;\n height: 100%;\n pointer-events: none;\n }\n \n .ruler-container {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n \n .canvas-viewport {\n position: absolute;\n top: 0;\n height: 100%;\n /* left and width set via inline styles for virtualization */\n }\n \n canvas {\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n }\n \n .label {\n position: absolute;\n top: 50%;\n font-size: 10px;\n color: var(--ef-color-text-muted);\n font-family: ui-monospace, monospace;\n white-space: nowrap;\n pointer-events: none;\n user-select: none;\n }\n `,\n ];\n\n @property({ type: Number, attribute: \"duration-ms\" })\n durationMs = 0;\n\n @consume({ context: durationContext, subscribe: true })\n contextDurationMs = 0;\n\n @consume({ context: timelineStateContext, subscribe: true })\n timelineState?: TimelineState;\n\n @property({ type: Number, attribute: \"fps\" })\n fps = 30;\n\n /** Full content width in pixels (for virtualization) */\n @property({ type: Number, attribute: \"content-width\" })\n contentWidth = 0;\n\n private containerRef = createRef<HTMLDivElement>();\n private canvasRef = createRef<HTMLCanvasElement>();\n private resizeObserver?: ResizeObserver;\n\n @state()\n private viewportWidth = 0;\n\n /** Canvas viewport left position for virtualization */\n @state()\n private _canvasViewportLeft = 0;\n\n /** Canvas viewport width for virtualization */\n @state()\n private _canvasViewportWidth = 0;\n\n /** Last rendered scroll position - for detecting scroll changes */\n private _lastRenderedScrollLeft = -1;\n\n /** Last rendered viewport width - for detecting viewport changes */\n private _lastRenderedViewportWidth = 0;\n\n get effectiveDurationMs(): number {\n return this.durationMs || this.contextDurationMs || 0;\n }\n\n get pixelsPerMs(): number {\n return this.timelineState?.pixelsPerMs ?? DEFAULT_PIXELS_PER_MS;\n }\n\n get scrollLeft(): number {\n return this.timelineState?.viewportScrollLeft ?? 0;\n }\n\n /**\n * Calculate canvas viewport bounds for virtualization.\n * Returns the left position and width of the canvas viewport.\n */\n private calculateCanvasViewport(): { left: number; width: number } {\n const totalWidth = this.contentWidth || this.viewportWidth;\n\n // If content is small enough, no virtualization needed\n if (totalWidth <= MAX_RULER_CANVAS_WIDTH) {\n return { left: 0, width: totalWidth };\n }\n\n // Get visible region from scroll position\n const viewportScrollLeft = this.scrollLeft;\n const viewportWidth =\n this.timelineState?.viewportWidth ?? this.viewportWidth;\n\n // Calculate canvas viewport with buffer for smooth scrolling\n const canvasLeft = Math.max(0, viewportScrollLeft - RULER_CANVAS_BUFFER);\n const canvasRight = Math.min(\n totalWidth,\n viewportScrollLeft + viewportWidth + RULER_CANVAS_BUFFER,\n );\n\n // Cap canvas width at maximum\n let canvasWidth = canvasRight - canvasLeft;\n if (canvasWidth > MAX_RULER_CANVAS_WIDTH) {\n canvasWidth = MAX_RULER_CANVAS_WIDTH;\n }\n\n return { left: canvasLeft, width: canvasWidth };\n }\n\n connectedCallback() {\n super.connectedCallback();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n }\n\n protected firstUpdated(): void {\n const container = this.containerRef.value;\n if (container) {\n this.resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n const width = entry.contentRect.width;\n if (width !== this.viewportWidth) {\n this.viewportWidth = width;\n }\n }\n });\n this.resizeObserver.observe(container);\n this.viewportWidth = container.clientWidth;\n }\n }\n\n protected updated(\n changedProperties: Map<string | number | symbol, unknown>,\n ): void {\n // Check if scroll position or viewport changed from context\n const currentScrollLeft = this.scrollLeft;\n const currentViewportWidth =\n this.timelineState?.viewportWidth ?? this.viewportWidth;\n\n // Check if scroll changed, viewport changed, or other relevant properties changed\n const scrollChanged = currentScrollLeft !== this._lastRenderedScrollLeft;\n const viewportChanged =\n currentViewportWidth !== this._lastRenderedViewportWidth;\n const pixelsPerMsChanged =\n changedProperties.has(\"timelineState\") ||\n changedProperties.has(\"pixelsPerMs\");\n const contentWidthChanged = changedProperties.has(\"contentWidth\");\n const durationChanged =\n changedProperties.has(\"durationMs\") ||\n changedProperties.has(\"contextDurationMs\");\n\n // Only render if something actually changed\n if (\n scrollChanged ||\n viewportChanged ||\n pixelsPerMsChanged ||\n contentWidthChanged ||\n durationChanged ||\n this._lastRenderedScrollLeft < 0\n ) {\n this.renderCanvas();\n this._lastRenderedScrollLeft = currentScrollLeft;\n this._lastRenderedViewportWidth = currentViewportWidth;\n }\n }\n\n private calculateLabelInterval(): number {\n const pixelsPerMs = this.pixelsPerMs;\n const pixelsPerSecond = pixelsPerMs * 1000;\n\n const intervals = [0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60];\n\n for (const intervalS of intervals) {\n const pixelsPerInterval = intervalS * pixelsPerSecond;\n if (pixelsPerInterval >= MIN_LABEL_SPACING_PX) {\n return intervalS * 1000;\n }\n }\n\n return 60000;\n }\n\n private getVisibleLabels(): VisibleLabel[] {\n const canvasWidth = this._canvasViewportWidth;\n if (canvasWidth <= 0) return [];\n\n const pixelsPerMs = this.pixelsPerMs;\n const canvasLeft = this._canvasViewportLeft;\n\n const intervalMs = this.calculateLabelInterval();\n\n // Generate labels for the canvas viewport range\n const visibleStartTimeMs = Math.max(\n 0,\n canvasLeft / pixelsPerMs - intervalMs,\n );\n const visibleEndTimeMs =\n (canvasLeft + canvasWidth) / pixelsPerMs + intervalMs;\n\n const firstLabelIndex = Math.floor(visibleStartTimeMs / intervalMs);\n const lastLabelIndex = Math.ceil(visibleEndTimeMs / intervalMs);\n\n const labels: VisibleLabel[] = [];\n\n for (let i = firstLabelIndex; i <= lastLabelIndex; i++) {\n const timeMs = i * intervalMs;\n if (timeMs < 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport (canvas is positioned at canvasLeft)\n const viewportX = absoluteX - canvasLeft;\n\n if (viewportX >= -50 && viewportX <= canvasWidth + 50) {\n const timeSeconds = timeMs / 1000;\n const text =\n timeSeconds % 1 === 0\n ? `${timeSeconds}s`\n : `${timeSeconds.toFixed(1)}s`;\n\n labels.push({ timeMs, viewportX, text });\n }\n }\n\n return labels;\n }\n\n private renderCanvas(): void {\n const canvas = this.canvasRef.value;\n const container = this.containerRef.value;\n if (!canvas || !container) return;\n\n // Calculate virtualized canvas viewport\n const viewport = this.calculateCanvasViewport();\n this._canvasViewportLeft = viewport.left;\n this._canvasViewportWidth = viewport.width;\n\n const width = viewport.width;\n const height = container.getBoundingClientRect().height;\n\n if (width <= 0 || height <= 0) return;\n\n const dpr = window.devicePixelRatio || 1;\n canvas.width = width * dpr;\n canvas.height = height * dpr;\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, width, height);\n\n const pixelsPerMs = this.pixelsPerMs;\n const canvasLeft = viewport.left;\n\n // Time label ticks - more prominent\n ctx.strokeStyle =\n getComputedStyle(this).getPropertyValue(\"--ef-color-text-muted\").trim() ||\n \"rgb(156, 163, 175)\";\n ctx.lineWidth = 1;\n\n const labelIntervalMs = this.calculateLabelInterval();\n // Fill the canvas viewport with ticks\n const visibleStartTimeMs = Math.max(\n 0,\n canvasLeft / pixelsPerMs - labelIntervalMs,\n );\n const visibleEndTimeMs =\n (canvasLeft + width) / pixelsPerMs + labelIntervalMs;\n\n const firstTickIndex = Math.floor(visibleStartTimeMs / labelIntervalMs);\n const lastTickIndex = Math.ceil(visibleEndTimeMs / labelIntervalMs);\n\n for (let i = firstTickIndex; i <= lastTickIndex; i++) {\n const timeMs = i * labelIntervalMs;\n if (timeMs < 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport\n const canvasX = absoluteX - canvasLeft;\n\n if (canvasX >= -1 && canvasX <= width + 1) {\n ctx.beginPath();\n ctx.moveTo(canvasX, 0);\n ctx.lineTo(canvasX, height * 0.4);\n ctx.stroke();\n }\n }\n\n const frameIntervalMs = 1000 / this.fps;\n const pixelsPerFrame = frameIntervalMs * pixelsPerMs;\n\n if (pixelsPerFrame >= MIN_FRAME_SPACING_PX) {\n // Frame markers should be lighter than background to be visible\n ctx.strokeStyle =\n getComputedStyle(this)\n .getPropertyValue(\"--ef-color-border-subtle\")\n .trim() || \"rgb(107, 114, 128)\";\n ctx.lineWidth = 1;\n\n const firstFrameIndex = Math.floor(visibleStartTimeMs / frameIntervalMs);\n const lastFrameIndex = Math.ceil(visibleEndTimeMs / frameIntervalMs);\n\n for (let i = firstFrameIndex; i <= lastFrameIndex; i++) {\n const timeMs = i * frameIntervalMs;\n if (timeMs < 0) continue;\n\n if (timeMs % labelIntervalMs === 0) continue;\n\n const absoluteX = timeMs * pixelsPerMs;\n // Position relative to canvas viewport\n const canvasX = absoluteX - canvasLeft;\n\n if (canvasX >= -1 && canvasX <= width + 1) {\n ctx.beginPath();\n ctx.moveTo(canvasX, 0);\n ctx.lineTo(canvasX, height * 0.25);\n ctx.stroke();\n }\n }\n }\n }\n\n render() {\n const visibleLabels = this.getVisibleLabels();\n\n const canvasViewportStyles = styleMap({\n left: `${this._canvasViewportLeft}px`,\n width: `${this._canvasViewportWidth}px`,\n });\n\n return html`\n <div ${ref(this.containerRef)} class=\"ruler-container\">\n <div class=\"canvas-viewport\" style=${canvasViewportStyles}>\n <canvas ${ref(this.canvasRef)}></canvas>\n ${visibleLabels.map(\n ({ viewportX, text }) => html`\n <span \n class=\"label\" \n style=\"transform: translateX(${viewportX}px)\"\n >${text}</span>\n `,\n )}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-timeline-ruler\": EFTimelineRuler;\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit17 from "lit";
2
+ import * as lit19 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html17 from "lit-html";
4
+ import * as lit_html18 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFToggleLoop.d.ts
7
7
  declare const EFToggleLoop_base: (new (...args: any[]) => {
@@ -10,9 +10,9 @@ declare const EFToggleLoop_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFToggleLoop extends EFToggleLoop_base {
13
- static styles: lit17.CSSResult[];
13
+ static styles: lit19.CSSResult[];
14
14
  get context(): ControllableInterface | null;
15
- render(): lit_html17.TemplateResult<1>;
15
+ render(): lit_html18.TemplateResult<1>;
16
16
  }
17
17
  declare global {
18
18
  interface HTMLElementTagNameMap {
@@ -1,5 +1,5 @@
1
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
2
1
  import { efContext } from "./efContext.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
3
3
  import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
4
4
  import { LitElement, css, html } from "lit";
5
5
  import { customElement } from "lit/decorators.js";
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit14 from "lit";
2
+ import * as lit16 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html14 from "lit-html";
4
+ import * as lit_html15 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTogglePlay.d.ts
7
7
  declare const EFTogglePlay_base: (new (...args: any[]) => {
@@ -10,12 +10,12 @@ declare const EFTogglePlay_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFTogglePlay extends EFTogglePlay_base {
13
- static styles: lit14.CSSResult[];
13
+ static styles: lit16.CSSResult[];
14
14
  playing: boolean;
15
15
  get efContext(): ControllableInterface | null;
16
16
  connectedCallback(): void;
17
17
  disconnectedCallback(): void;
18
- render(): lit_html14.TemplateResult<1>;
18
+ render(): lit_html15.TemplateResult<1>;
19
19
  togglePlay: () => void;
20
20
  private getPlaybackController;
21
21
  }
@@ -1,7 +1,7 @@
1
+ import { efContext } from "./efContext.js";
1
2
  import { playingContext } from "./playingContext.js";
2
3
  import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
3
4
  import { isEFTemporal } from "../elements/EFTemporal.js";
4
- import { efContext } from "./efContext.js";
5
5
  import { attachContextRoot } from "../attachContextRoot.js";
6
6
  import { TargetOrContextMixin } from "./TargetOrContextMixin.js";
7
7
  import { consume } from "@lit/context";
@@ -1,7 +1,7 @@
1
1
  import { PanZoomTransform } from "../elements/EFPanZoom.js";
2
- import * as lit24 from "lit";
2
+ import * as lit13 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html23 from "lit-html";
4
+ import * as lit_html12 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTransformHandles.d.ts
7
7
  interface TransformBounds {
@@ -49,7 +49,7 @@ declare class EFTransformHandles extends LitElement {
49
49
  * Note: Not a @state() property to avoid re-renders during interaction.
50
50
  */
51
51
  private initialBounds;
52
- static styles: lit24.CSSResult;
52
+ static styles: lit13.CSSResult;
53
53
  private resizeObserver?;
54
54
  /**
55
55
  * Single source of truth for zoom scale.
@@ -79,7 +79,7 @@ declare class EFTransformHandles extends LitElement {
79
79
  private handleMouseMove;
80
80
  private handleMouseUp;
81
81
  private cleanup;
82
- render(): lit_html23.TemplateResult<1>;
82
+ render(): lit_html12.TemplateResult<1>;
83
83
  }
84
84
  declare global {
85
85
  interface HTMLElementTagNameMap {
@@ -145,11 +145,11 @@ let EFTransformHandles = class EFTransformHandles$1 extends LitElement {
145
145
  }
146
146
  .overlay {
147
147
  position: absolute;
148
- border: 2px solid var(--ef-transform-handles-border-color, #3b82f6);
148
+ border: 2px solid var(--ef-transform-handles-border-color, var(--ef-color-primary));
149
149
  pointer-events: none;
150
150
  }
151
151
  .overlay.dragging {
152
- border-color: var(--ef-transform-handles-dragging-border-color, #2563eb);
152
+ border-color: var(--ef-transform-handles-dragging-border-color, var(--ef-color-primary));
153
153
  }
154
154
  .drag-area {
155
155
  position: absolute;
@@ -165,8 +165,8 @@ let EFTransformHandles = class EFTransformHandles$1 extends LitElement {
165
165
  position: absolute;
166
166
  width: 8px;
167
167
  height: 8px;
168
- background: var(--ef-transform-handles-handle-color, white);
169
- border: 1px solid var(--ef-transform-handles-handle-border-color, #3b82f6);
168
+ background: var(--ef-transform-handles-handle-color, var(--ef-color-bg-elevated));
169
+ border: 1px solid var(--ef-transform-handles-handle-border-color, var(--ef-color-primary));
170
170
  pointer-events: auto;
171
171
  /* Only capture pointer events, allow wheel events to pass through */
172
172
  touch-action: none;
@@ -192,8 +192,8 @@ let EFTransformHandles = class EFTransformHandles$1 extends LitElement {
192
192
  .rotate-handle-circle {
193
193
  width: 24px;
194
194
  height: 24px;
195
- background: var(--ef-transform-handles-rotate-handle-color, #10b981);
196
- border: 2px solid white;
195
+ background: var(--ef-transform-handles-rotate-handle-color, var(--ef-color-success));
196
+ border: 2px solid var(--ef-color-bg-elevated);
197
197
  border-radius: 50%;
198
198
  display: flex;
199
199
  align-items: center;