@editframe/elements 0.20.4-beta.0 → 0.23.6-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/DelayedLoadingState.js +0 -27
  2. package/dist/EF_FRAMEGEN.d.ts +5 -3
  3. package/dist/EF_FRAMEGEN.js +49 -11
  4. package/dist/_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js +7 -0
  5. package/dist/attachContextRoot.d.ts +1 -0
  6. package/dist/attachContextRoot.js +9 -0
  7. package/dist/elements/ContextProxiesController.d.ts +1 -2
  8. package/dist/elements/EFAudio.js +5 -9
  9. package/dist/elements/EFCaptions.d.ts +1 -3
  10. package/dist/elements/EFCaptions.js +112 -129
  11. package/dist/elements/EFImage.js +6 -7
  12. package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -5
  13. package/dist/elements/EFMedia/AssetMediaEngine.js +36 -33
  14. package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
  15. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
  16. package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -78
  17. package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
  18. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +7 -13
  19. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -3
  20. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
  21. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
  22. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
  23. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
  24. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
  25. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
  26. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +9 -25
  27. package/dist/elements/EFMedia/shared/BufferUtils.js +2 -17
  28. package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
  29. package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
  30. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
  31. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
  32. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
  33. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
  34. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
  35. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
  36. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
  37. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
  38. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
  39. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
  40. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -18
  41. package/dist/elements/EFMedia.d.ts +19 -0
  42. package/dist/elements/EFMedia.js +44 -25
  43. package/dist/elements/EFSourceMixin.js +5 -7
  44. package/dist/elements/EFSurface.js +6 -9
  45. package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
  46. package/dist/elements/EFTemporal.d.ts +10 -0
  47. package/dist/elements/EFTemporal.js +100 -41
  48. package/dist/elements/EFThumbnailStrip.js +23 -73
  49. package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
  50. package/dist/elements/EFTimegroup.d.ts +35 -14
  51. package/dist/elements/EFTimegroup.js +138 -181
  52. package/dist/elements/EFVideo.d.ts +16 -2
  53. package/dist/elements/EFVideo.js +156 -108
  54. package/dist/elements/EFWaveform.js +23 -40
  55. package/dist/elements/SampleBuffer.js +3 -7
  56. package/dist/elements/TargetController.js +5 -5
  57. package/dist/elements/durationConverter.js +4 -4
  58. package/dist/elements/renderTemporalAudio.d.ts +10 -0
  59. package/dist/elements/renderTemporalAudio.js +35 -0
  60. package/dist/elements/updateAnimations.js +19 -43
  61. package/dist/gui/ContextMixin.d.ts +5 -5
  62. package/dist/gui/ContextMixin.js +167 -162
  63. package/dist/gui/Controllable.browsertest.d.ts +0 -0
  64. package/dist/gui/Controllable.d.ts +15 -0
  65. package/dist/gui/Controllable.js +9 -0
  66. package/dist/gui/EFConfiguration.js +7 -7
  67. package/dist/gui/EFControls.browsertest.d.ts +11 -0
  68. package/dist/gui/EFControls.d.ts +18 -4
  69. package/dist/gui/EFControls.js +70 -28
  70. package/dist/gui/EFDial.browsertest.d.ts +0 -0
  71. package/dist/gui/EFDial.d.ts +18 -0
  72. package/dist/gui/EFDial.js +141 -0
  73. package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
  74. package/dist/gui/EFFilmstrip.d.ts +12 -2
  75. package/dist/gui/EFFilmstrip.js +214 -129
  76. package/dist/gui/EFFitScale.js +5 -8
  77. package/dist/gui/EFFocusOverlay.js +4 -4
  78. package/dist/gui/EFPause.browsertest.d.ts +0 -0
  79. package/dist/gui/EFPause.d.ts +23 -0
  80. package/dist/gui/EFPause.js +59 -0
  81. package/dist/gui/EFPlay.browsertest.d.ts +0 -0
  82. package/dist/gui/EFPlay.d.ts +23 -0
  83. package/dist/gui/EFPlay.js +59 -0
  84. package/dist/gui/EFPreview.d.ts +4 -0
  85. package/dist/gui/EFPreview.js +18 -9
  86. package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
  87. package/dist/gui/EFResizableBox.d.ts +34 -0
  88. package/dist/gui/EFResizableBox.js +547 -0
  89. package/dist/gui/EFScrubber.d.ts +9 -3
  90. package/dist/gui/EFScrubber.js +13 -13
  91. package/dist/gui/EFTimeDisplay.d.ts +7 -1
  92. package/dist/gui/EFTimeDisplay.js +8 -8
  93. package/dist/gui/EFToggleLoop.d.ts +9 -3
  94. package/dist/gui/EFToggleLoop.js +7 -5
  95. package/dist/gui/EFTogglePlay.d.ts +12 -4
  96. package/dist/gui/EFTogglePlay.js +26 -21
  97. package/dist/gui/EFWorkbench.js +5 -5
  98. package/dist/gui/PlaybackController.d.ts +67 -0
  99. package/dist/gui/PlaybackController.js +310 -0
  100. package/dist/gui/TWMixin.js +1 -1
  101. package/dist/gui/TWMixin2.js +1 -1
  102. package/dist/gui/TargetOrContextMixin.d.ts +10 -0
  103. package/dist/gui/TargetOrContextMixin.js +98 -0
  104. package/dist/gui/efContext.d.ts +2 -2
  105. package/dist/index.d.ts +5 -0
  106. package/dist/index.js +5 -1
  107. package/dist/otel/BridgeSpanExporter.d.ts +13 -0
  108. package/dist/otel/BridgeSpanExporter.js +87 -0
  109. package/dist/otel/setupBrowserTracing.d.ts +12 -0
  110. package/dist/otel/setupBrowserTracing.js +32 -0
  111. package/dist/otel/tracingHelpers.d.ts +34 -0
  112. package/dist/otel/tracingHelpers.js +112 -0
  113. package/dist/style.css +1 -1
  114. package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
  115. package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
  116. package/dist/transcoding/utils/UrlGenerator.js +2 -19
  117. package/dist/utils/LRUCache.js +6 -53
  118. package/package.json +13 -5
  119. package/src/elements/ContextProxiesController.ts +10 -10
  120. package/src/elements/EFAudio.ts +1 -0
  121. package/src/elements/EFCaptions.browsertest.ts +128 -56
  122. package/src/elements/EFCaptions.ts +60 -34
  123. package/src/elements/EFImage.browsertest.ts +1 -2
  124. package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
  125. package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
  126. package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
  127. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
  128. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
  129. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
  130. package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
  131. package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
  132. package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
  133. package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
  134. package/src/elements/EFMedia.browsertest.ts +8 -15
  135. package/src/elements/EFMedia.ts +54 -8
  136. package/src/elements/EFSurface.browsertest.ts +2 -6
  137. package/src/elements/EFSurface.ts +1 -0
  138. package/src/elements/EFTemporal.browsertest.ts +58 -1
  139. package/src/elements/EFTemporal.ts +140 -4
  140. package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
  141. package/src/elements/EFThumbnailStrip.ts +1 -0
  142. package/src/elements/EFTimegroup.browsertest.ts +16 -15
  143. package/src/elements/EFTimegroup.ts +281 -275
  144. package/src/elements/EFVideo.browsertest.ts +162 -74
  145. package/src/elements/EFVideo.ts +229 -101
  146. package/src/elements/FetchContext.browsertest.ts +7 -2
  147. package/src/elements/TargetController.browsertest.ts +1 -0
  148. package/src/elements/TargetController.ts +1 -0
  149. package/src/elements/renderTemporalAudio.ts +108 -0
  150. package/src/elements/updateAnimations.browsertest.ts +181 -6
  151. package/src/elements/updateAnimations.ts +6 -6
  152. package/src/gui/ContextMixin.browsertest.ts +274 -27
  153. package/src/gui/ContextMixin.ts +230 -175
  154. package/src/gui/Controllable.browsertest.ts +258 -0
  155. package/src/gui/Controllable.ts +41 -0
  156. package/src/gui/EFControls.browsertest.ts +294 -80
  157. package/src/gui/EFControls.ts +139 -28
  158. package/src/gui/EFDial.browsertest.ts +84 -0
  159. package/src/gui/EFDial.ts +172 -0
  160. package/src/gui/EFFilmstrip.browsertest.ts +712 -0
  161. package/src/gui/EFFilmstrip.ts +213 -23
  162. package/src/gui/EFPause.browsertest.ts +202 -0
  163. package/src/gui/EFPause.ts +73 -0
  164. package/src/gui/EFPlay.browsertest.ts +202 -0
  165. package/src/gui/EFPlay.ts +73 -0
  166. package/src/gui/EFPreview.ts +20 -5
  167. package/src/gui/EFResizableBox.browsertest.ts +79 -0
  168. package/src/gui/EFResizableBox.ts +898 -0
  169. package/src/gui/EFScrubber.ts +7 -5
  170. package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
  171. package/src/gui/EFTimeDisplay.ts +3 -1
  172. package/src/gui/EFToggleLoop.ts +6 -5
  173. package/src/gui/EFTogglePlay.ts +30 -23
  174. package/src/gui/PlaybackController.ts +522 -0
  175. package/src/gui/TWMixin.css +3 -0
  176. package/src/gui/TargetOrContextMixin.ts +185 -0
  177. package/src/gui/efContext.ts +2 -2
  178. package/src/otel/BridgeSpanExporter.ts +150 -0
  179. package/src/otel/setupBrowserTracing.ts +73 -0
  180. package/src/otel/tracingHelpers.ts +251 -0
  181. package/test/cache-integration-verification.browsertest.ts +1 -1
  182. package/types.json +1 -1
  183. package/dist/elements/ContextProxiesController.js +0 -69
@@ -1,10 +1,16 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement, ReactiveController } from 'lit';
3
+ import { PlaybackController } from '../gui/PlaybackController.js';
3
4
  import { EFTimegroup } from './EFTimegroup.js';
4
5
  export declare const timegroupContext: {
5
6
  __context__: EFTimegroup;
6
7
  };
7
8
  export declare class TemporalMixinInterface {
9
+ playbackController?: PlaybackController;
10
+ playing: boolean;
11
+ loop: boolean;
12
+ play(): void;
13
+ pause(): void;
8
14
  get hasOwnDuration(): boolean;
9
15
  /**
10
16
  * Whether the element has a duration set as an attribute.
@@ -137,6 +143,7 @@ export declare class TemporalMixinInterface {
137
143
  * For other temporal elements: their ownCurrentTimeMs
138
144
  */
139
145
  get currentTimeMs(): number;
146
+ set currentTimeMs(value: number);
140
147
  /**
141
148
  * The current time of the element in milliseconds, adjusted for trimming.
142
149
  *
@@ -185,6 +192,9 @@ export declare class TemporalMixinInterface {
185
192
  */
186
193
  rootTimegroup?: EFTimegroup;
187
194
  frameTask: Task<readonly unknown[], unknown>;
195
+ didBecomeRoot(): void;
196
+ didBecomeChild(): void;
197
+ updateComplete: Promise<boolean>;
188
198
  }
189
199
  export declare const isEFTemporal: (obj: any) => obj is TemporalMixinInterface;
190
200
  export declare const deepGetTemporalElements: (element: Element, temporals?: Array<TemporalMixinInterface & HTMLElement>) => (TemporalMixinInterface & HTMLElement)[];
@@ -1,12 +1,13 @@
1
1
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
2
+ import { PlaybackController } from "../gui/PlaybackController.js";
2
3
  import { durationConverter } from "./durationConverter.js";
4
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
3
5
  import { consume, createContext } from "@lit/context";
4
6
  import { Task } from "@lit/task";
5
7
  import { property, state } from "lit/decorators.js";
6
- import _decorate from "@oxc-project/runtime/helpers/decorate";
7
8
  const timegroupContext = createContext(Symbol("timeGroupContext"));
8
9
  const isEFTemporal = (obj) => obj[EF_TEMPORAL];
9
- const EF_TEMPORAL = Symbol("EF_TEMPORAL");
10
+ var EF_TEMPORAL = Symbol("EF_TEMPORAL");
10
11
  const deepGetTemporalElements = (element, temporals = []) => {
11
12
  for (const child of element.children) {
12
13
  if (isEFTemporal(child)) temporals.push(child);
@@ -21,7 +22,7 @@ const deepGetElementsWithFrameTasks = (element, elements = []) => {
21
22
  }
22
23
  return elements;
23
24
  };
24
- let temporalCache;
25
+ var temporalCache;
25
26
  const resetTemporalCache = () => {
26
27
  temporalCache = /* @__PURE__ */ new Map();
27
28
  if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(resetTemporalCache);
@@ -48,8 +49,8 @@ var OwnCurrentTimeController = class {
48
49
  this.host.removeController(this);
49
50
  }
50
51
  };
51
- let startTimeMsCache = /* @__PURE__ */ new WeakMap();
52
- const resetStartTimeMsCache = () => {
52
+ var startTimeMsCache = /* @__PURE__ */ new WeakMap();
53
+ var resetStartTimeMsCache = () => {
53
54
  startTimeMsCache = /* @__PURE__ */ new WeakMap();
54
55
  if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(resetStartTimeMsCache);
55
56
  };
@@ -79,45 +80,90 @@ const EFTemporal = (superClass) => {
79
80
  }
80
81
  #parentTimegroup;
81
82
  set parentTimegroup(value) {
83
+ const oldParent = this.#parentTimegroup;
82
84
  this.#parentTimegroup = value;
83
85
  this.ownCurrentTimeController?.remove();
84
86
  this.rootTimegroup = this.getRootTimegroup();
85
87
  if (this.rootTimegroup) this.ownCurrentTimeController = new OwnCurrentTimeController(this.rootTimegroup, this);
88
+ if (oldParent !== value) if (!value) this.didBecomeRoot();
89
+ else this.didBecomeChild();
86
90
  }
87
91
  disconnectedCallback() {
88
92
  super.disconnectedCallback();
89
93
  this.ownCurrentTimeController?.remove();
94
+ if (this.playbackController) {
95
+ this.playbackController.remove();
96
+ this.playbackController = void 0;
97
+ }
98
+ }
99
+ connectedCallback() {
100
+ super.connectedCallback();
101
+ if (!this.parentTimegroup) this.didBecomeRoot();
90
102
  }
91
103
  get parentTimegroup() {
92
104
  return this.#parentTimegroup;
93
105
  }
106
+ get playing() {
107
+ if (!this.playbackController) return false;
108
+ return this.playbackController.playing;
109
+ }
110
+ set playing(value) {
111
+ if (!this.playbackController) {
112
+ console.warn("Cannot set playing on non-root temporal element", this);
113
+ return;
114
+ }
115
+ this.playbackController.setPlaying(value);
116
+ }
117
+ play() {
118
+ if (!this.playbackController) {
119
+ console.warn("play() called on non-root temporal element", this);
120
+ return;
121
+ }
122
+ this.playbackController.play();
123
+ }
124
+ pause() {
125
+ if (!this.playbackController) {
126
+ console.warn("pause() called on non-root temporal element", this);
127
+ return;
128
+ }
129
+ this.playbackController.pause();
130
+ }
131
+ get loop() {
132
+ return this.playbackController?.loop ?? this.#loop;
133
+ }
134
+ set loop(value) {
135
+ const oldValue = this.#loop;
136
+ this.#loop = value;
137
+ if (this.playbackController) this.playbackController.setLoop(value);
138
+ this.requestUpdate("loop", oldValue);
139
+ }
94
140
  set duration(value) {
95
141
  if (value !== void 0) this.setAttribute("duration", value);
96
142
  else this.removeAttribute("duration");
97
143
  }
98
144
  get trimStartMs() {
99
- if (this._trimStartMs === void 0) return void 0;
145
+ if (this._trimStartMs === void 0) return;
100
146
  return Math.min(Math.max(this._trimStartMs, 0), this.intrinsicDurationMs ?? 0);
101
147
  }
102
148
  set trimStartMs(value) {
103
149
  this._trimStartMs = value;
104
150
  }
105
151
  get trimEndMs() {
106
- if (this._trimEndMs === void 0) return void 0;
152
+ if (this._trimEndMs === void 0) return;
107
153
  return Math.min(this._trimEndMs, this.intrinsicDurationMs ?? 0);
108
154
  }
109
155
  set trimEndMs(value) {
110
156
  this._trimEndMs = value;
111
157
  }
112
158
  get sourceInMs() {
113
- if (this._sourceInMs === void 0) return void 0;
159
+ if (this._sourceInMs === void 0) return;
114
160
  return Math.max(this._sourceInMs, 0);
115
161
  }
116
162
  set sourceInMs(value) {
117
163
  this._sourceInMs = value;
118
164
  }
119
165
  get sourceOutMs() {
120
- if (this._sourceOutMs === void 0) return void 0;
166
+ if (this._sourceOutMs === void 0) return;
121
167
  if (this.intrinsicDurationMs && this._sourceOutMs > this.intrinsicDurationMs) return this.intrinsicDurationMs;
122
168
  return Math.max(this._sourceOutMs, 0);
123
169
  }
@@ -137,14 +183,11 @@ const EFTemporal = (superClass) => {
137
183
  }
138
184
  get explicitDurationMs() {
139
185
  if (this.hasExplicitDuration) return this._durationMs;
140
- return void 0;
141
186
  }
142
187
  get hasOwnDuration() {
143
188
  return this.intrinsicDurationMs !== void 0 || this.hasExplicitDuration;
144
189
  }
145
- get intrinsicDurationMs() {
146
- return void 0;
147
- }
190
+ get intrinsicDurationMs() {}
148
191
  get durationMs() {
149
192
  const baseDurationMs = this.intrinsicDurationMs ?? this._durationMs ?? this.parentTimegroup?.durationMs ?? 0;
150
193
  if (baseDurationMs === 0) return 0;
@@ -172,13 +215,11 @@ const EFTemporal = (superClass) => {
172
215
  while (parent && !isEFTemporal(parent)) parent = parent.parentElement;
173
216
  return parent;
174
217
  }
175
- /**
176
- * The start time of the element within its parent timegroup.
177
- */
178
218
  get startTimeWithinParentMs() {
179
219
  if (!this.parentTemporal) return 0;
180
220
  return this.startTimeMs - this.parentTemporal.startTimeMs;
181
221
  }
222
+ #loop = false;
182
223
  get startTimeMs() {
183
224
  const cachedStartTime = startTimeMsCache.get(this);
184
225
  if (cachedStartTime !== void 0) return cachedStartTime;
@@ -218,71 +259,89 @@ const EFTemporal = (superClass) => {
218
259
  get endTimeMs() {
219
260
  return this.startTimeMs + this.durationMs;
220
261
  }
221
- /**
222
- * The current time of the element within itself.
223
- * Compare with `currentTimeMs` to see the current time with respect to the root timegroup
224
- */
262
+ #currentTimeMs = 0;
225
263
  get ownCurrentTimeMs() {
226
- if (this.rootTimegroup) return Math.min(Math.max(0, this.rootTimegroup.currentTimeMs - this.startTimeMs), this.durationMs);
227
- return 0;
264
+ if (this.playbackController) return Math.min(Math.max(0, this.playbackController.currentTimeMs), this.durationMs);
265
+ if (this.rootTimegroup && this.rootTimegroup !== this) return Math.min(Math.max(0, this.rootTimegroup.currentTimeMs - this.startTimeMs), this.durationMs);
266
+ return Math.min(Math.max(0, this.#currentTimeMs), this.durationMs);
228
267
  }
229
- /**
230
- * Element's current time for progress calculation.
231
- * Non-timegroup temporal elements use their local time (ownCurrentTimeMs)
232
- */
233
268
  get currentTimeMs() {
234
269
  return this.ownCurrentTimeMs;
235
270
  }
236
- /**
237
- * Used to calculate the internal currentTimeMs of the element. This is useful
238
- * for mapping to internal media time codes for audio/video elements.
239
- */
271
+ set currentTimeMs(value) {
272
+ if (this.playbackController) {
273
+ this.playbackController.currentTime = value / 1e3;
274
+ return;
275
+ }
276
+ if (this.rootTimegroup && this.rootTimegroup !== this) this.rootTimegroup.currentTimeMs = value;
277
+ else {
278
+ this.#currentTimeMs = value;
279
+ this.requestUpdate("currentTimeMs");
280
+ }
281
+ }
240
282
  get currentSourceTimeMs() {
241
283
  const leadingTrimMs = this.sourceInMs || this.trimStartMs || 0;
242
284
  return this.ownCurrentTimeMs + leadingTrimMs;
243
285
  }
286
+ didBecomeRoot() {
287
+ if (!this.playbackController) {
288
+ this.playbackController = new PlaybackController(this);
289
+ if (this.#loop) this.playbackController.setLoop(this.#loop);
290
+ }
291
+ }
292
+ didBecomeChild() {
293
+ if (this.playbackController) {
294
+ this.playbackController.remove();
295
+ this.playbackController = void 0;
296
+ }
297
+ }
244
298
  }
245
- _decorate([consume({
299
+ __decorate([consume({
246
300
  context: timegroupContext,
247
301
  subscribe: true
248
- }), property({ attribute: false })], TemporalMixinClass.prototype, "parentTimegroup", null);
249
- _decorate([property({
302
+ })], TemporalMixinClass.prototype, "parentTimegroup", null);
303
+ __decorate([property({
304
+ type: Boolean,
305
+ reflect: true,
306
+ attribute: "loop"
307
+ })], TemporalMixinClass.prototype, "loop", null);
308
+ __decorate([property({
250
309
  type: String,
251
310
  attribute: "offset",
252
311
  converter: durationConverter
253
312
  })], TemporalMixinClass.prototype, "_offsetMs", void 0);
254
- _decorate([property({
313
+ __decorate([property({
255
314
  type: Number,
256
315
  attribute: "duration",
257
316
  converter: durationConverter
258
317
  })], TemporalMixinClass.prototype, "_durationMs", void 0);
259
- _decorate([property({
318
+ __decorate([property({
260
319
  type: Number,
261
320
  attribute: "trimstart",
262
321
  converter: durationConverter
263
322
  })], TemporalMixinClass.prototype, "_trimStartMs", void 0);
264
- _decorate([property({
323
+ __decorate([property({
265
324
  type: Number,
266
325
  attribute: "trimend",
267
326
  converter: durationConverter
268
327
  })], TemporalMixinClass.prototype, "_trimEndMs", void 0);
269
- _decorate([property({
328
+ __decorate([property({
270
329
  type: Number,
271
330
  attribute: "sourcein",
272
331
  converter: durationConverter
273
332
  })], TemporalMixinClass.prototype, "_sourceInMs", void 0);
274
- _decorate([property({
333
+ __decorate([property({
275
334
  type: Number,
276
335
  attribute: "sourceout",
277
336
  converter: durationConverter
278
337
  })], TemporalMixinClass.prototype, "_sourceOutMs", void 0);
279
- _decorate([property({
338
+ __decorate([property({
280
339
  type: Number,
281
340
  attribute: "startoffset",
282
341
  converter: durationConverter
283
342
  })], TemporalMixinClass.prototype, "_startOffsetMs", void 0);
284
- _decorate([state()], TemporalMixinClass.prototype, "rootTimegroup", void 0);
343
+ __decorate([state()], TemporalMixinClass.prototype, "rootTimegroup", void 0);
285
344
  Object.defineProperty(TemporalMixinClass.prototype, EF_TEMPORAL, { value: true });
286
345
  return TemporalMixinClass;
287
346
  };
288
- export { EFTemporal, deepGetElementsWithFrameTasks, deepGetTemporalElements, flushStartTimeMsCache, resetTemporalCache, shallowGetTemporalElements, timegroupContext };
347
+ export { EFTemporal, deepGetElementsWithFrameTasks, deepGetTemporalElements, flushStartTimeMsCache, isEFTemporal, resetTemporalCache, shallowGetTemporalElements, timegroupContext };
@@ -1,44 +1,25 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
2
  import { OrderedLRUCache } from "../utils/LRUCache.js";
2
3
  import { TargetController } from "./TargetController.js";
3
4
  import { Task } from "@lit/task";
4
5
  import { LitElement, css, html } from "lit";
5
6
  import { customElement, property, state } from "lit/decorators.js";
6
- import _decorate from "@oxc-project/runtime/helpers/decorate";
7
7
  import { createRef, ref } from "lit/directives/ref.js";
8
- /**
9
- * Global thumbnail image cache for smooth resize performance
10
- * Shared across all thumbnail strip instances
11
- * Uses OrderedLRUCache for efficient timestamp-based searching
12
- */
13
- const thumbnailImageCache = new OrderedLRUCache(200, (a, b) => {
8
+ var thumbnailImageCache = new OrderedLRUCache(200, (a, b) => {
14
9
  const partsA = a.split(":");
15
10
  const partsB = b.split(":");
16
- const timeA = Number.parseFloat(partsA[partsA.length - 1] || "0");
17
- const timeB = Number.parseFloat(partsB[partsB.length - 1] || "0");
18
- return timeA - timeB;
11
+ return Number.parseFloat(partsA[partsA.length - 1] || "0") - Number.parseFloat(partsB[partsB.length - 1] || "0");
19
12
  });
20
13
  globalThis.debugThumbnailCache = thumbnailImageCache;
21
- /**
22
- * Quantize timestamp to 30fps frame boundaries for consistent caching
23
- * This eliminates cache misses from floating point precision differences
24
- */
25
14
  function quantizeTimestamp(timeMs) {
26
15
  const frameIntervalMs = 1e3 / 30;
27
16
  return Math.round(timeMs / frameIntervalMs) * frameIntervalMs;
28
17
  }
29
- /**
30
- * Generate cache key for thumbnail image data (dimension-independent, quantized)
31
- */
32
18
  function getThumbnailCacheKey(videoSrc, timeMs) {
33
- const quantizedTimeMs = quantizeTimestamp(timeMs);
34
- return `${videoSrc}:${quantizedTimeMs}`;
19
+ return `${videoSrc}:${quantizeTimestamp(timeMs)}`;
35
20
  }
36
- const THUMBNAIL_GAP = 1;
37
- const STRIP_BORDER_PADDING = 4;
38
- /**
39
- * Calculate optimal thumbnail count and timestamps for the strip
40
- * Groups thumbnails by scrub segment ID for efficient caching
41
- */
21
+ var THUMBNAIL_GAP = 1;
22
+ var STRIP_BORDER_PADDING = 4;
42
23
  function calculateThumbnailLayout(stripWidth, thumbnailWidth, startTimeMs, endTimeMs, scrubSegmentDurationMs) {
43
24
  if (stripWidth <= 0 || thumbnailWidth <= 0 || endTimeMs <= startTimeMs) return {
44
25
  count: 0,
@@ -59,16 +40,15 @@ function calculateThumbnailLayout(stripWidth, thumbnailWidth, startTimeMs, endTi
59
40
  if (!segmentMap.has(segmentId)) segmentMap.set(segmentId, []);
60
41
  segmentMap.get(segmentId).push({ timeMs });
61
42
  }
62
- const segments = Array.from(segmentMap.entries()).sort(([a], [b]) => a - b).map(([segmentId, thumbnails]) => ({
63
- segmentId,
64
- thumbnails
65
- }));
66
43
  return {
67
44
  count,
68
- segments
45
+ segments: Array.from(segmentMap.entries()).sort(([a], [b]) => a - b).map(([segmentId, thumbnails]) => ({
46
+ segmentId,
47
+ thumbnails
48
+ }))
69
49
  };
70
50
  }
71
- let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
51
+ var EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
72
52
  constructor(..._args) {
73
53
  super(..._args);
74
54
  this.canvasRef = createRef();
@@ -221,9 +201,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
221
201
  get stripWidth() {
222
202
  return this._stripWidth;
223
203
  }
224
- /**
225
- * Run thumbnail render task directly with provided layout (bypasses task args dependency)
226
- */
227
204
  async runThumbnailRenderTask(layout) {
228
205
  if (!layout || !this.targetElement || layout.count === 0) return [];
229
206
  return this.renderThumbnails(layout, this.targetElement, this.thumbnailWidth);
@@ -236,9 +213,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
236
213
  }
237
214
  if (changedProperties.has("thumbnailWidth") || changedProperties.has("startTimeMs") || changedProperties.has("endTimeMs") || changedProperties.has("useIntrinsicDuration")) this.runThumbnailUpdate();
238
215
  }
239
- /**
240
- * Run thumbnail update with responsive debouncing (based on EFTimegroup currentTime pattern)
241
- */
242
216
  runThumbnailUpdate() {
243
217
  if (this._thumbnailUpdateInProgress) {
244
218
  this._pendingThumbnailUpdate = true;
@@ -257,9 +231,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
257
231
  }
258
232
  });
259
233
  }
260
- /**
261
- * Calculate layout with a ready media engine
262
- */
263
234
  calculateLayoutWithMediaEngine(stripWidth, thumbnailWidth, targetElement, startTimeMs, endTimeMs, useIntrinsicDuration, mediaEngine) {
264
235
  if (useIntrinsicDuration) {
265
236
  const effectiveStartMs$1 = startTimeMs ?? 0;
@@ -272,17 +243,9 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
272
243
  const effectiveEndMs = endTimeMs !== void 0 ? sourceStart + endTimeMs : sourceStart + trimmedDuration;
273
244
  return this.generateLayoutFromTimeRange(stripWidth, thumbnailWidth, effectiveStartMs, effectiveEndMs, mediaEngine);
274
245
  }
275
- /**
276
- * Generate layout from calculated time range
277
- */
278
246
  generateLayoutFromTimeRange(stripWidth, thumbnailWidth, effectiveStartMs, effectiveEndMs, mediaEngine) {
279
- const scrubSegmentDurationMs = mediaEngine && typeof mediaEngine.getScrubVideoRendition === "function" ? mediaEngine.getScrubVideoRendition()?.segmentDurationMs : void 0;
280
- const layout = calculateThumbnailLayout(stripWidth, thumbnailWidth, effectiveStartMs, effectiveEndMs, scrubSegmentDurationMs);
281
- return layout;
247
+ return calculateThumbnailLayout(stripWidth, thumbnailWidth, effectiveStartMs, effectiveEndMs, mediaEngine && typeof mediaEngine.getScrubVideoRendition === "function" ? mediaEngine.getScrubVideoRendition()?.segmentDurationMs : void 0);
282
248
  }
283
- /**
284
- * Render thumbnails with provided layout (main rendering logic)
285
- */
286
249
  async renderThumbnails(layout, targetElement, thumbnailWidth) {
287
250
  if (!layout || !targetElement || layout.count === 0) return [];
288
251
  const videoSrc = targetElement.src;
@@ -299,17 +262,14 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
299
262
  const timePlus = thumbnail.timeMs + 5e3;
300
263
  const rangeStartKey = `${videoSrc}:${timeMinus}`;
301
264
  const rangeEndKey = `${videoSrc}:${timePlus}`;
302
- const nearHits = thumbnailImageCache.findRange(rangeStartKey, rangeEndKey);
303
- const sameVideoHits = nearHits.filter((hit) => hit.key.startsWith(`${videoSrc}:`));
265
+ const sameVideoHits = thumbnailImageCache.findRange(rangeStartKey, rangeEndKey).filter((hit) => hit.key.startsWith(`${videoSrc}:`));
304
266
  if (sameVideoHits.length > 0) {
305
267
  const nearestHit = sameVideoHits.reduce((closest, current) => {
306
268
  const currentParts = current.key.split(":");
307
269
  const closestParts = closest.key.split(":");
308
270
  const currentTime = Number.parseFloat(currentParts[currentParts.length - 1] || "0");
309
271
  const closestTime = Number.parseFloat(closestParts[closestParts.length - 1] || "0");
310
- const currentDiff = Math.abs(currentTime - thumbnail.timeMs);
311
- const closestDiff = Math.abs(closestTime - thumbnail.timeMs);
312
- return currentDiff < closestDiff ? current : closest;
272
+ return Math.abs(currentTime - thumbnail.timeMs) < Math.abs(closestTime - thumbnail.timeMs) ? current : closest;
313
273
  });
314
274
  imageData = nearestHit.value;
315
275
  status = "near-hit";
@@ -338,8 +298,7 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
338
298
  this.resizeObserver = new ResizeObserver((entries) => {
339
299
  for (const entry of entries) {
340
300
  const width = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0]?.inlineSize : entry.contentRect.width;
341
- const height = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0]?.blockSize : entry.contentRect.height;
342
- this._stripHeight = height ?? 0;
301
+ this._stripHeight = (entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0]?.blockSize : entry.contentRect.height) ?? 0;
343
302
  this.stripWidth = width ?? 0;
344
303
  }
345
304
  });
@@ -358,9 +317,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
358
317
  this._videoPropertyObserver?.disconnect();
359
318
  this._videoPropertyObserver = void 0;
360
319
  }
361
- /**
362
- * Draw thumbnails to the canvas with cache hits and placeholders
363
- */
364
320
  async drawThumbnails(thumbnails) {
365
321
  const canvas = this.canvasRef.value;
366
322
  if (!canvas) return;
@@ -414,9 +370,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
414
370
  ctx.setLineDash([]);
415
371
  }
416
372
  }
417
- /**
418
- * Load missing thumbnails using MediaEngine batch extraction
419
- */
420
373
  async loadMissingThumbnails(thumbnails, targetElement) {
421
374
  const mediaEngine = targetElement.mediaEngineTask?.value;
422
375
  if (!mediaEngine) return;
@@ -440,9 +393,6 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
440
393
  }
441
394
  await this.drawThumbnails(thumbnails);
442
395
  }
443
- /**
444
- * Convert Canvas to ImageData for caching
445
- */
446
396
  canvasToImageData(canvas) {
447
397
  const ctx = canvas.getContext("2d");
448
398
  if (!ctx) return null;
@@ -459,21 +409,21 @@ let EFThumbnailStrip = class EFThumbnailStrip$1 extends LitElement {
459
409
  `;
460
410
  }
461
411
  };
462
- _decorate([state()], EFThumbnailStrip.prototype, "targetElement", null);
463
- _decorate([property({ type: String })], EFThumbnailStrip.prototype, "target", void 0);
464
- _decorate([property({
412
+ __decorate([state()], EFThumbnailStrip.prototype, "targetElement", null);
413
+ __decorate([property({ type: String })], EFThumbnailStrip.prototype, "target", void 0);
414
+ __decorate([property({
465
415
  type: Number,
466
416
  attribute: "thumbnail-width"
467
417
  })], EFThumbnailStrip.prototype, "thumbnailWidth", void 0);
468
- _decorate([property({
418
+ __decorate([property({
469
419
  type: Number,
470
420
  attribute: "start-time-ms"
471
421
  })], EFThumbnailStrip.prototype, "startTimeMs", void 0);
472
- _decorate([property({
422
+ __decorate([property({
473
423
  type: Number,
474
424
  attribute: "end-time-ms"
475
425
  })], EFThumbnailStrip.prototype, "endTimeMs", void 0);
476
- _decorate([property({
426
+ __decorate([property({
477
427
  type: Boolean,
478
428
  attribute: "use-intrinsic-duration",
479
429
  reflect: true,
@@ -485,6 +435,6 @@ _decorate([property({
485
435
  toAttribute: (value) => value ? "true" : null
486
436
  }
487
437
  })], EFThumbnailStrip.prototype, "useIntrinsicDuration", void 0);
488
- _decorate([state()], EFThumbnailStrip.prototype, "stripWidth", null);
489
- EFThumbnailStrip = _decorate([customElement("ef-thumbnail-strip")], EFThumbnailStrip);
438
+ __decorate([state()], EFThumbnailStrip.prototype, "stripWidth", null);
439
+ EFThumbnailStrip = __decorate([customElement("ef-thumbnail-strip")], EFThumbnailStrip);
490
440
  export { EFThumbnailStrip };
@@ -12,17 +12,17 @@ declare class TimegroupTestMedia extends EFMedia {
12
12
  declare const TestFrameTaskA_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
13
13
  declare class TestFrameTaskA extends TestFrameTaskA_base {
14
14
  frameTaskCount: number;
15
- frameTask: Task<never[], void>;
15
+ frameTask: Task<readonly [], void>;
16
16
  }
17
17
  declare const TestFrameTaskB_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
18
18
  declare class TestFrameTaskB extends TestFrameTaskB_base {
19
19
  frameTaskCount: number;
20
- frameTask: Task<never[], void>;
20
+ frameTask: Task<readonly [], void>;
21
21
  }
22
22
  declare const TestFrameTaskC_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
23
23
  declare class TestFrameTaskC extends TestFrameTaskC_base {
24
24
  frameTaskCount: number;
25
- frameTask: Task<never[], void>;
25
+ frameTask: Task<readonly [], void>;
26
26
  }
27
27
  declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
28
28
  declare class TestTemporal extends TestTemporal_base {
@@ -1,35 +1,44 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement, PropertyValues } from 'lit';
3
+ import { EFMedia } from './EFMedia.js';
4
+ declare global {
5
+ var EF_DEV_WORKBENCH: boolean | undefined;
6
+ }
3
7
  export declare const flushSequenceDurationCache: () => void;
4
8
  export declare const shallowGetTimegroups: (element: Element, groups?: EFTimegroup[]) => EFTimegroup[];
5
9
  declare const EFTimegroup_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
6
10
  export declare class EFTimegroup extends EFTimegroup_base {
7
11
  #private;
12
+ static get observedAttributes(): string[];
8
13
  static styles: import('lit').CSSResult;
9
14
  _timeGroupContext: this;
10
- set mode(value: "fit" | "fixed" | "sequence" | "contain");
11
- get mode(): "fit" | "fixed" | "sequence" | "contain";
12
- private _mode;
13
- set overlapMs(value: number);
14
- get overlapMs(): number;
15
- private _overlapMs;
15
+ efContext: this;
16
+ mode: "fit" | "fixed" | "sequence" | "contain";
17
+ overlapMs: number;
18
+ attributeChangedCallback(name: string, old: string | null, value: string | null): void;
16
19
  fit: "none" | "contain" | "cover";
17
- /**
18
- * Throttles frameTask execution to ensure only one runs at a time while preserving the last request
19
- */
20
20
  private runThrottledFrameTask;
21
21
  set currentTime(time: number);
22
22
  get currentTime(): number;
23
23
  set currentTimeMs(ms: number);
24
24
  get currentTimeMs(): number;
25
+ /**
26
+ * Seek to a specific time and wait for all frames to be ready.
27
+ * This is the recommended way to seek in tests and programmatic control.
28
+ *
29
+ * @param timeMs - Time in milliseconds to seek to
30
+ * @returns Promise that resolves when the seek is complete and all visible children are ready
31
+ */
32
+ seek(timeMs: number): Promise<void>;
25
33
  /**
26
34
  * Determines if this is a root timegroup (no parent timegroups)
27
35
  */
28
36
  get isRootTimegroup(): boolean;
37
+ saveTimeToLocalStorage(time: number): void;
29
38
  render(): import('lit-html').TemplateResult<1>;
30
- maybeLoadTimeFromLocalStorage(): number | undefined;
39
+ loadTimeFromLocalStorage(): number | undefined;
31
40
  connectedCallback(): void;
32
- protected updated(_changedProperties: PropertyValues): void;
41
+ protected updated(changedProperties: PropertyValues): void;
33
42
  disconnectedCallback(): void;
34
43
  get storageKey(): string;
35
44
  get intrinsicDurationMs(): number | undefined;
@@ -45,15 +54,27 @@ export declare class EFTimegroup extends EFTimegroup_base {
45
54
  /**
46
55
  * Returns true if the timegroup should be wrapped with a workbench.
47
56
  *
48
- * A timegroup should be wrapped with a workbench if it is the root-most timegroup
49
- * and EF_INTERACTIVE is true.
57
+ * A timegroup should be wrapped with a workbench if:
58
+ * - It's being rendered (EF_RENDERING), OR
59
+ * - It's in interactive mode (EF_INTERACTIVE) with the dev workbench flag set
50
60
  *
51
- * If the timegroup is already wrappedin a context provider like ef-preview,
61
+ * If the timegroup is already wrapped in a context provider like ef-preview,
52
62
  * it should NOT be wrapped in a workbench.
53
63
  */
54
64
  shouldWrapWithWorkbench(): boolean;
55
65
  wrapWithWorkbench(): void;
56
66
  get efElements(): Element[];
67
+ /**
68
+ * Returns media elements for playback audio rendering
69
+ * For standalone media, returns [this]; for timegroups, returns all descendants
70
+ * Used by PlaybackController for audio-driven playback
71
+ */
72
+ getMediaElements(): EFMedia[];
73
+ /**
74
+ * Render audio buffer for playback
75
+ * Called by PlaybackController during live playback
76
+ * Delegates to shared renderTemporalAudio utility for consistent behavior
77
+ */
57
78
  renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer>;
58
79
  /**
59
80
  * TEMPORARY TEST METHOD: Renders audio and immediately plays it back