@editframe/elements 0.26.2-beta.0 → 0.26.4-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 (135) hide show
  1. package/dist/elements/EFTimegroup.js +7 -2
  2. package/dist/elements/EFTimegroup.js.map +1 -1
  3. package/package.json +2 -2
  4. package/scripts/build-css.js +3 -3
  5. package/tsdown.config.ts +1 -1
  6. package/types.json +1 -1
  7. package/src/elements/ContextProxiesController.ts +0 -124
  8. package/src/elements/CrossUpdateController.ts +0 -22
  9. package/src/elements/EFAudio.browsertest.ts +0 -706
  10. package/src/elements/EFAudio.ts +0 -56
  11. package/src/elements/EFCaptions.browsertest.ts +0 -1960
  12. package/src/elements/EFCaptions.ts +0 -823
  13. package/src/elements/EFImage.browsertest.ts +0 -120
  14. package/src/elements/EFImage.ts +0 -113
  15. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +0 -224
  16. package/src/elements/EFMedia/AssetIdMediaEngine.ts +0 -110
  17. package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +0 -140
  18. package/src/elements/EFMedia/AssetMediaEngine.ts +0 -385
  19. package/src/elements/EFMedia/BaseMediaEngine.browsertest.ts +0 -400
  20. package/src/elements/EFMedia/BaseMediaEngine.ts +0 -505
  21. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +0 -386
  22. package/src/elements/EFMedia/BufferedSeekingInput.ts +0 -430
  23. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +0 -226
  24. package/src/elements/EFMedia/JitMediaEngine.ts +0 -256
  25. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +0 -679
  26. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +0 -117
  27. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +0 -246
  28. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +0 -59
  29. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +0 -27
  30. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +0 -55
  31. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +0 -53
  32. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +0 -207
  33. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +0 -72
  34. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +0 -32
  35. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +0 -29
  36. package/src/elements/EFMedia/audioTasks/makeAudioTasksVideoOnly.browsertest.ts +0 -95
  37. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +0 -184
  38. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +0 -129
  39. package/src/elements/EFMedia/shared/BufferUtils.ts +0 -342
  40. package/src/elements/EFMedia/shared/GlobalInputCache.ts +0 -77
  41. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +0 -44
  42. package/src/elements/EFMedia/shared/PrecisionUtils.ts +0 -46
  43. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +0 -246
  44. package/src/elements/EFMedia/shared/RenditionHelpers.ts +0 -56
  45. package/src/elements/EFMedia/shared/ThumbnailExtractor.ts +0 -227
  46. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +0 -167
  47. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +0 -88
  48. package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +0 -76
  49. package/src/elements/EFMedia/videoTasks/ScrubInputCache.ts +0 -61
  50. package/src/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.ts +0 -114
  51. package/src/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.ts +0 -35
  52. package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +0 -52
  53. package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +0 -124
  54. package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.ts +0 -44
  55. package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.ts +0 -32
  56. package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +0 -370
  57. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +0 -109
  58. package/src/elements/EFMedia.browsertest.ts +0 -872
  59. package/src/elements/EFMedia.ts +0 -341
  60. package/src/elements/EFSourceMixin.ts +0 -60
  61. package/src/elements/EFSurface.browsertest.ts +0 -151
  62. package/src/elements/EFSurface.ts +0 -142
  63. package/src/elements/EFTemporal.browsertest.ts +0 -215
  64. package/src/elements/EFTemporal.ts +0 -800
  65. package/src/elements/EFThumbnailStrip.browsertest.ts +0 -585
  66. package/src/elements/EFThumbnailStrip.media-engine.browsertest.ts +0 -714
  67. package/src/elements/EFThumbnailStrip.ts +0 -906
  68. package/src/elements/EFTimegroup.browsertest.ts +0 -870
  69. package/src/elements/EFTimegroup.ts +0 -878
  70. package/src/elements/EFVideo.browsertest.ts +0 -1482
  71. package/src/elements/EFVideo.ts +0 -564
  72. package/src/elements/EFWaveform.ts +0 -547
  73. package/src/elements/FetchContext.browsertest.ts +0 -401
  74. package/src/elements/FetchMixin.ts +0 -38
  75. package/src/elements/SampleBuffer.ts +0 -94
  76. package/src/elements/TargetController.browsertest.ts +0 -230
  77. package/src/elements/TargetController.ts +0 -224
  78. package/src/elements/TimegroupController.ts +0 -26
  79. package/src/elements/durationConverter.ts +0 -35
  80. package/src/elements/parseTimeToMs.ts +0 -9
  81. package/src/elements/printTaskStatus.ts +0 -16
  82. package/src/elements/renderTemporalAudio.ts +0 -108
  83. package/src/elements/updateAnimations.browsertest.ts +0 -1884
  84. package/src/elements/updateAnimations.ts +0 -217
  85. package/src/elements/util.ts +0 -24
  86. package/src/gui/ContextMixin.browsertest.ts +0 -860
  87. package/src/gui/ContextMixin.ts +0 -562
  88. package/src/gui/Controllable.browsertest.ts +0 -258
  89. package/src/gui/Controllable.ts +0 -41
  90. package/src/gui/EFConfiguration.ts +0 -40
  91. package/src/gui/EFControls.browsertest.ts +0 -389
  92. package/src/gui/EFControls.ts +0 -195
  93. package/src/gui/EFDial.browsertest.ts +0 -84
  94. package/src/gui/EFDial.ts +0 -172
  95. package/src/gui/EFFilmstrip.browsertest.ts +0 -712
  96. package/src/gui/EFFilmstrip.ts +0 -1349
  97. package/src/gui/EFFitScale.ts +0 -152
  98. package/src/gui/EFFocusOverlay.ts +0 -79
  99. package/src/gui/EFPause.browsertest.ts +0 -202
  100. package/src/gui/EFPause.ts +0 -73
  101. package/src/gui/EFPlay.browsertest.ts +0 -202
  102. package/src/gui/EFPlay.ts +0 -73
  103. package/src/gui/EFPreview.ts +0 -74
  104. package/src/gui/EFResizableBox.browsertest.ts +0 -79
  105. package/src/gui/EFResizableBox.ts +0 -898
  106. package/src/gui/EFScrubber.ts +0 -151
  107. package/src/gui/EFTimeDisplay.browsertest.ts +0 -237
  108. package/src/gui/EFTimeDisplay.ts +0 -55
  109. package/src/gui/EFToggleLoop.ts +0 -35
  110. package/src/gui/EFTogglePlay.ts +0 -70
  111. package/src/gui/EFWorkbench.ts +0 -115
  112. package/src/gui/PlaybackController.ts +0 -527
  113. package/src/gui/TWMixin.css +0 -6
  114. package/src/gui/TWMixin.ts +0 -61
  115. package/src/gui/TargetOrContextMixin.ts +0 -185
  116. package/src/gui/currentTimeContext.ts +0 -5
  117. package/src/gui/durationContext.ts +0 -3
  118. package/src/gui/efContext.ts +0 -6
  119. package/src/gui/fetchContext.ts +0 -5
  120. package/src/gui/focusContext.ts +0 -7
  121. package/src/gui/focusedElementContext.ts +0 -5
  122. package/src/gui/playingContext.ts +0 -5
  123. package/src/otel/BridgeSpanExporter.ts +0 -150
  124. package/src/otel/setupBrowserTracing.ts +0 -73
  125. package/src/otel/tracingHelpers.ts +0 -251
  126. package/src/transcoding/cache/RequestDeduplicator.test.ts +0 -170
  127. package/src/transcoding/cache/RequestDeduplicator.ts +0 -65
  128. package/src/transcoding/cache/URLTokenDeduplicator.test.ts +0 -182
  129. package/src/transcoding/cache/URLTokenDeduplicator.ts +0 -101
  130. package/src/transcoding/types/index.ts +0 -312
  131. package/src/transcoding/utils/MediaUtils.ts +0 -63
  132. package/src/transcoding/utils/UrlGenerator.ts +0 -68
  133. package/src/transcoding/utils/constants.ts +0 -36
  134. package/src/utils/LRUCache.test.ts +0 -274
  135. package/src/utils/LRUCache.ts +0 -696
@@ -1,870 +0,0 @@
1
- import {
2
- html,
3
- LitElement,
4
- render as litRender,
5
- type TemplateResult,
6
- } from "lit";
7
- import { assert, beforeEach, describe, test } from "vitest";
8
- import { EFTimegroup } from "./EFTimegroup.js";
9
- import "./EFTimegroup.js";
10
- import { customElement } from "lit/decorators/custom-element.js";
11
- import { ContextMixin } from "../gui/ContextMixin.js";
12
- import { EFTemporal } from "./EFTemporal.js";
13
- // Need workbench to make workbench wrapping occurs
14
- import "../gui/EFWorkbench.js";
15
- // Additional imports for sequence boundary test
16
- import "./EFVideo.js";
17
- import "../gui/EFConfiguration.js";
18
- import { Task } from "@lit/task";
19
- import type { MediaEngine } from "../transcoding/types/index.js";
20
- import { EFMedia } from "./EFMedia.js";
21
-
22
- beforeEach(() => {
23
- for (let i = 0; i < localStorage.length; i++) {
24
- const key = localStorage.key(i);
25
- if (typeof key !== "string") continue;
26
- localStorage.removeItem(key);
27
- }
28
- while (document.body.children.length) {
29
- document.body.children[0]?.remove();
30
- }
31
- });
32
-
33
- @customElement("test-context")
34
- class TestContext extends ContextMixin(LitElement) {}
35
-
36
- @customElement("timegroup-test-media")
37
- class TimegroupTestMedia extends EFMedia {
38
- mediaEngineTaskCount = 0;
39
- mediaEngineTask = new Task(this, {
40
- autoRun: false,
41
- args: () => ["source", null] as const,
42
- task: () => {
43
- this.mediaEngineTaskCount++;
44
- return Promise.resolve({} as unknown as MediaEngine);
45
- },
46
- });
47
- }
48
-
49
- @customElement("test-frame-task-a")
50
- class TestFrameTaskA extends EFTemporal(LitElement) {
51
- frameTaskCount = 0;
52
-
53
- frameTask = new Task(this, {
54
- autoRun: false,
55
- args: () => [],
56
- task: () => {
57
- this.frameTaskCount++;
58
- return Promise.resolve();
59
- },
60
- });
61
- }
62
-
63
- @customElement("test-frame-task-b")
64
- class TestFrameTaskB extends EFTemporal(LitElement) {
65
- frameTaskCount = 0;
66
-
67
- frameTask = new Task(this, {
68
- autoRun: false,
69
- args: () => [],
70
- task: () => {
71
- this.frameTaskCount++;
72
- return Promise.resolve();
73
- },
74
- });
75
- }
76
-
77
- @customElement("test-frame-task-c")
78
- class TestFrameTaskC extends EFTemporal(LitElement) {
79
- frameTaskCount = 0;
80
-
81
- frameTask = new Task(this, {
82
- autoRun: false,
83
- args: () => [],
84
- task: () => {
85
- this.frameTaskCount++;
86
- return Promise.resolve();
87
- },
88
- });
89
- }
90
-
91
- @customElement("test-temporal")
92
- class TestTemporal extends EFTemporal(LitElement) {
93
- get hasOwnDuration(): boolean {
94
- return true;
95
- }
96
- }
97
-
98
- declare global {
99
- interface HTMLElementTagNameMap {
100
- "test-temporal": TestTemporal;
101
- "test-context": TestContext;
102
- "timegroup-test-media": TimegroupTestMedia;
103
- "test-frame-task-a": TestFrameTaskA;
104
- "test-frame-task-b": TestFrameTaskB;
105
- "test-frame-task-c": TestFrameTaskC;
106
- }
107
- }
108
-
109
- const renderTimegroup = (result: TemplateResult) => {
110
- const container = document.createElement("div");
111
- litRender(result, container);
112
- const firstChild = container.querySelector("ef-timegroup");
113
- if (!firstChild) {
114
- throw new Error("No first child found");
115
- }
116
- if (!(firstChild instanceof EFTimegroup)) {
117
- throw new Error("First child is not an EFTimegroup");
118
- }
119
- document.body.appendChild(container);
120
- return firstChild;
121
- };
122
-
123
- describe(`<ef-timegroup mode='fit'>`, () => {
124
- test("duration is zero when there is no parent to fit into", () => {
125
- const timegroup = renderTimegroup(
126
- html`<ef-timegroup mode="fit"></ef-timegroup>`,
127
- );
128
- assert.equal(timegroup.durationMs, 0);
129
- });
130
-
131
- test("duration is zero when there is no parent to fit into, even if there are children with duration", () => {
132
- const timegroup = renderTimegroup(
133
- html`<ef-timegroup mode="fit">
134
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
135
- </ef-timegroup>`,
136
- );
137
- assert.equal(timegroup.durationMs, 0);
138
- });
139
-
140
- test("duration is the duration of the parent timegroup", () => {
141
- const timegroup = renderTimegroup(
142
- html`<ef-timegroup mode="fixed" duration="10s">
143
- <ef-timegroup id="child" mode="fit"></ef-timegroup>
144
- </ef-timegroup>`,
145
- );
146
- const child = timegroup.querySelector("#child") as EFTimegroup;
147
- assert.equal(child.durationMs, 10_000);
148
- });
149
-
150
- test("fit mode items inside a sequence are given zero duration and do not factor into the duration of the sequence", () => {
151
- const timegroup = renderTimegroup(
152
- html`<ef-timegroup mode="sequence">
153
- <ef-timegroup id="child" mode="fit"></ef-timegroup>
154
- </ef-timegroup>`,
155
- );
156
- const child = timegroup.querySelector("#child") as EFTimegroup;
157
- assert.equal(child.durationMs, 0);
158
- assert.equal(timegroup.durationMs, 0);
159
- });
160
-
161
- test("fit mode can be used to constrain a 'background' timegroup into a 'foreground' sequence", async () => {
162
- const timegroup = renderTimegroup(
163
- html`
164
- <ef-timegroup mode="contain">
165
- <ef-timegroup id="foreground" mode="sequence">
166
- <ef-timegroup mode="fixed" duration="10s"></ef-timegroup>
167
- <ef-timegroup mode="fixed" duration="10s"></ef-timegroup>
168
- </ef-timegroup>
169
- <ef-timegroup id="background" mode="fit">
170
- <ef-timegroup mode="fixed" duration="30s"></ef-timegroup>
171
- </ef-timegroup>
172
- </ef-timegroup>
173
- `,
174
- );
175
-
176
- const foreground = timegroup.querySelector("#foreground") as EFTimegroup;
177
- const background = timegroup.querySelector("#background") as EFTimegroup;
178
- assert.equal(foreground.durationMs, 20_000);
179
- assert.equal(background.durationMs, 20_000);
180
- });
181
- });
182
-
183
- describe(`<ef-timegroup mode="fixed">`, () => {
184
- test("can explicitly set a duration in seconds", async () => {
185
- const timegroup = renderTimegroup(
186
- html`<ef-timegroup mode="fixed" duration="10s"></ef-timegroup>`,
187
- );
188
- assert.equal(timegroup.durationMs, 10_000);
189
- });
190
-
191
- test("can explicitly set a duration in milliseconds", async () => {
192
- const timegroup = renderTimegroup(
193
- html`<ef-timegroup mode="fixed" duration="10ms"></ef-timegroup>`,
194
- );
195
- assert.equal(timegroup.durationMs, 10);
196
- });
197
- });
198
-
199
- describe(`<ef-timegroup mode="sequence">`, () => {
200
- test("fixed duration is ignored", () => {
201
- const timegroup = renderTimegroup(
202
- html`<ef-timegroup mode="sequence" duration="10s"></ef-timegroup>`,
203
- );
204
- assert.equal(timegroup.durationMs, 0);
205
- });
206
-
207
- test("duration is the sum of child time groups", async () => {
208
- const timegroup = renderTimegroup(
209
- html`
210
- <ef-timegroup mode="sequence">
211
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
212
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
213
- </ef-timegroup>
214
- `,
215
- );
216
- assert.equal(timegroup.durationMs, 10_000);
217
- });
218
-
219
- test("duration can include any element with a durationMs value", async () => {
220
- const timegroup = renderTimegroup(
221
- html`
222
- <ef-timegroup mode="sequence">
223
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
224
- <test-temporal duration="5s"></test-temporal>
225
- </ef-timegroup>
226
- `,
227
- );
228
-
229
- assert.equal(timegroup.durationMs, 10_000);
230
- });
231
-
232
- test("arbitrary html does not factor into the calculation of a sequence duration", () => {
233
- const timegroup = renderTimegroup(
234
- html`
235
- <ef-timegroup mode="sequence">
236
- <div>
237
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
238
- </div>
239
- </ef-timegroup>
240
- `,
241
- );
242
- assert.equal(timegroup.durationMs, 5_000);
243
- });
244
-
245
- test("nested time groups do not factor into the calculation of a sequence duration", async () => {
246
- const timegroup = renderTimegroup(
247
- html`
248
- <ef-timegroup mode="sequence">
249
- <ef-timegroup mode="fixed" duration="5s">
250
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
251
- </ef-timegroup>
252
- </ef-timegroup>
253
- `,
254
- );
255
- assert.equal(timegroup.durationMs, 5_000);
256
- });
257
- });
258
-
259
- describe(`<ef-timegroup mode="contain">`, () => {
260
- test("fixed duration is ignored", () => {
261
- const timegroup = renderTimegroup(
262
- html`<ef-timegroup mode="contain" duration="10s"></ef-timegroup>`,
263
- );
264
- assert.equal(timegroup.durationMs, 0);
265
- });
266
-
267
- test("duration is the maximum of it's child time groups", async () => {
268
- const timegroup = renderTimegroup(
269
- html`
270
- <ef-timegroup mode="contain">
271
- <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
272
- <ef-timegroup mode="fixed" duration="10s"></ef-timegroup>
273
- </ef-timegroup>
274
- `,
275
- );
276
- assert.equal(timegroup.durationMs, 10_000);
277
- });
278
- });
279
-
280
- describe("startTimeMs", () => {
281
- test("is computed relative to the root time group", async () => {
282
- const timegroup = renderTimegroup(
283
- html`<ef-timegroup id="root" mode="sequence">
284
- <ef-timegroup id="a" mode="fixed" duration="5s"></ef-timegroup>
285
- <ef-timegroup id="b" mode="sequence">
286
- <ef-timegroup id="c" mode="fixed" duration="5s"></ef-timegroup>
287
- <ef-timegroup id="d" mode="contain">
288
- <ef-timegroup id="e" mode="fixed" duration="5s"></ef-timegroup>
289
- <ef-timegroup id="f" mode="fixed" duration="5s"></ef-timegroup>
290
- </ef-timegroup>
291
- </ef-timegroup>
292
- </ef-timegroup>`,
293
- );
294
-
295
- const a = timegroup.querySelector("#a") as EFTimegroup;
296
- const b = timegroup.querySelector("#b") as EFTimegroup;
297
- const c = timegroup.querySelector("#c") as EFTimegroup;
298
- const d = timegroup.querySelector("#d") as EFTimegroup;
299
- const e = timegroup.querySelector("#e") as EFTimegroup;
300
- const f = timegroup.querySelector("#f") as EFTimegroup;
301
-
302
- assert.equal(a.startTimeMs, 0);
303
- assert.equal(b.startTimeMs, 5_000);
304
- assert.equal(c.startTimeMs, 5_000);
305
- assert.equal(d.startTimeMs, 10_000);
306
- assert.equal(e.startTimeMs, 10_000);
307
- assert.equal(f.startTimeMs, 10_000);
308
- });
309
-
310
- // // TODO: Rethink offset math, it shouldn't effect the duration of a temporal item
311
- // // but actually change the start and end time.
312
- // litTest.skip("can be offset with offset attribute", async ({ container }) => {
313
- // render(
314
- // html`<ef-timegroup id="root" mode="contain">
315
- // <test-temporal id="a" duration="5s" offset="5s"></test-temporal>
316
- // </ef-timegroup> `,
317
- // container,
318
- // );
319
-
320
- // const root = container.querySelector("#root") as EFTimegroup;
321
- // const a = container.querySelector("#a") as TestTemporal;
322
-
323
- // assert.equal(a.durationMs, 5_000);
324
- // assert.equal(root.durationMs, 10_000);
325
- // assert.equal(a.startTimeMs, 5_000);
326
- // });
327
-
328
- // litTest.skip(
329
- // "offsets do not affect start time when in a sequence group",
330
- // async ({ container }) => {
331
- // render(
332
- // html`<ef-timegroup id="root" mode="sequence">
333
- // <test-temporal id="a" duration="5s"></test-temporal>
334
- // <test-temporal id="b" duration="5s" offset="5s"></test-temporal>
335
- // </ef-timegroup> `,
336
- // container,
337
- // );
338
-
339
- // const root = container.querySelector("#root") as EFTimegroup;
340
- // const a = container.querySelector("#a") as TestTemporal;
341
- // const b = container.querySelector("#b") as TestTemporal;
342
-
343
- // assert.equal(root.durationMs, 10_000);
344
- // assert.equal(a.startTimeMs, 0);
345
- // assert.equal(b.startTimeMs, 5_000);
346
- // },
347
- // );
348
-
349
- test("temporal elements default to expand to fill a timegroup", async () => {
350
- const timegroup = renderTimegroup(
351
- html`<ef-timegroup id="root" mode="fixed" duration="10s">
352
- <test-temporal id="a"></test-temporal>
353
- </ef-timegroup> `,
354
- );
355
-
356
- const a = timegroup.querySelector("#a") as TestTemporal;
357
-
358
- assert.equal(timegroup.durationMs, 10_000);
359
- assert.equal(a.durationMs, 10_000);
360
- });
361
-
362
- test("element's parentTimegroup updates as they move", async () => {
363
- const container = document.createElement("div");
364
- document.body.appendChild(container);
365
- const timegroup1 = document.createElement("ef-timegroup");
366
- timegroup1.setAttribute("mode", "fixed");
367
- timegroup1.setAttribute("duration", "5s");
368
-
369
- const timegroup2 = document.createElement("ef-timegroup");
370
- timegroup2.setAttribute("mode", "fixed");
371
- timegroup2.setAttribute("duration", "5s");
372
-
373
- container.appendChild(timegroup1);
374
- container.appendChild(timegroup2);
375
-
376
- const temporal = document.createElement("test-temporal");
377
-
378
- timegroup1.appendChild(temporal);
379
-
380
- assert.equal(temporal.parentTimegroup, timegroup1);
381
-
382
- timegroup2.appendChild(temporal);
383
- assert.equal(temporal.parentTimegroup, timegroup2);
384
- });
385
-
386
- test("elements can access their root temporal element", async () => {
387
- const root = renderTimegroup(
388
- html`<ef-timegroup id="root" mode="contain" duration="10s">
389
- <ef-timegroup id="a" mode="contain">
390
- <div>
391
- <ef-timegroup id="b" mode="contain">
392
- <div>
393
- <test-temporal id="c" duration="5s"></test-temporal>
394
- </div>
395
- </ef-timegroup>
396
- </div>
397
- </ef-timegroup>
398
- </ef-timegroup> `,
399
- );
400
-
401
- const a = root.querySelector("#a") as EFTimegroup;
402
- const b = root.querySelector("#b") as EFTimegroup;
403
- const c = root.querySelector("#c") as TestTemporal;
404
-
405
- assert.equal(root.rootTimegroup, root);
406
-
407
- assert.equal(a.rootTimegroup, root);
408
- assert.equal(b.rootTimegroup, root);
409
- assert.equal(c.rootTimegroup, root);
410
- });
411
- });
412
-
413
- describe("setting currentTime", () => {
414
- test("persists in localStorage if the timegroup has an id and is in the dom", async () => {
415
- const timegroup = renderTimegroup(
416
- html`<ef-timegroup id="localStorage-test" mode="fixed" duration="10s"></ef-timegroup>`,
417
- );
418
- localStorage.removeItem(timegroup.storageKey);
419
- document.body.appendChild(timegroup);
420
- await timegroup.updateComplete;
421
- await timegroup.waitForMediaDurations();
422
-
423
- // Use the new seek() method which ensures everything is ready
424
- await timegroup.seek(5_000_000); // 5000 seconds in ms, should clamp to 10s
425
-
426
- const storedValue = localStorage.getItem(timegroup.storageKey);
427
- assert.equal(storedValue, "10"); // Should store 10 (clamped from 5000 to duration)
428
- timegroup.remove();
429
- });
430
-
431
- test("root timegroup remains visible when currentTime equals duration exactly", async () => {
432
- const timegroup = renderTimegroup(
433
- html`<ef-timegroup id="end-time-test" mode="fixed" duration="10s"></ef-timegroup>`,
434
- );
435
- await timegroup.waitForMediaDurations();
436
-
437
- // Set currentTime to exactly the duration
438
- timegroup.currentTime = 10; // 10 seconds
439
- await timegroup.seekTask.taskComplete;
440
- await timegroup.frameTask.taskComplete;
441
-
442
- // The root timegroup should still be visible at the exact end time
443
- assert.notEqual(
444
- timegroup.style.display,
445
- "none",
446
- "Root timegroup should be visible at exact end time",
447
- );
448
- });
449
-
450
- test("root timegroup becomes hidden only after currentTime exceeds duration", async () => {
451
- const timegroup = renderTimegroup(
452
- html`<ef-timegroup id="beyond-end-test" mode="fixed" duration="10s"></ef-timegroup>`,
453
- );
454
- await timegroup.waitForMediaDurations();
455
-
456
- // Set currentTime beyond the duration (should be clamped to duration)
457
- timegroup.currentTime = 15; // 15 seconds, should clamp to 10s
458
- await timegroup.seekTask.taskComplete;
459
- await timegroup.frameTask.taskComplete;
460
-
461
- // Even when clamped, it should still be visible at the end
462
- assert.notEqual(
463
- timegroup.style.display,
464
- "none",
465
- "Root timegroup should be visible even when time is clamped to duration",
466
- );
467
- // Verify that the time was actually clamped
468
- assert.equal(
469
- timegroup.currentTime,
470
- 10,
471
- "Time should be clamped to duration",
472
- );
473
- });
474
-
475
- test("does not persist in localStorage if the timegroup has no id", async () => {
476
- const timegroup = renderTimegroup(
477
- html`<ef-timegroup mode="fixed" duration="10s"></ef-timegroup>`,
478
- );
479
- document.body.appendChild(timegroup);
480
- timegroup.currentTime = 5_000;
481
- timegroup.removeAttribute("id");
482
- assert.throws(() => {
483
- assert.isNull(localStorage.getItem(timegroup.storageKey));
484
- }, "Timegroup must have an id to use localStorage");
485
- timegroup.remove();
486
- });
487
-
488
- test("nested items derive their ownCurrentTimeMs", async () => {
489
- const timegroup = renderTimegroup(
490
- html`
491
- <ef-timegroup id="root" mode="sequence">
492
- <ef-timegroup id="a" mode="fixed" duration="5s"> </ef-timegroup>
493
- <ef-timegroup id="b" mode="fixed" duration="5s"> </ef-timegroup>
494
- </ef-timegroup>
495
- `,
496
- );
497
-
498
- const root = timegroup;
499
- const a = timegroup.querySelector("#a") as EFTimegroup;
500
- const b = timegroup.querySelector("#b") as EFTimegroup;
501
-
502
- assert.equal(a.ownCurrentTimeMs, 0);
503
- assert.equal(b.ownCurrentTimeMs, 0);
504
-
505
- root.currentTimeMs = 2_500;
506
-
507
- assert.equal(a.ownCurrentTimeMs, 2_500);
508
- assert.equal(b.ownCurrentTimeMs, 0);
509
-
510
- // Wait for frame update to complete before next assignment
511
- await new Promise((resolve) => setTimeout(resolve, 10));
512
-
513
- root.currentTimeMs = 7_500;
514
-
515
- assert.equal(a.ownCurrentTimeMs, 5_000);
516
- assert.equal(b.ownCurrentTimeMs, 2_500);
517
- });
518
- });
519
-
520
- describe("shouldWrapWithWorkbench", () => {
521
- test.skip("should not wrap if EF_INTERACTIVE is false", () => {
522
- // TODO: need a way to define EF_INTERACTIVE in a test
523
- });
524
-
525
- test.skip("should wrap if root-most timegroup", () => {
526
- // TODO: This test requires EF_INTERACTIVE to be true, which is a module-level constant
527
- // that cannot be modified in tests. Need a way to test this behavior.
528
- });
529
-
530
- test("should not wrap if contained within a preview context", () => {
531
- const timegorup = document.createElement("ef-timegroup");
532
- const context = document.createElement("test-context");
533
- context.append(timegorup);
534
- assert.isFalse(timegorup.shouldWrapWithWorkbench());
535
- });
536
- });
537
-
538
- describe("DOM nodes", () => {
539
- test("can have mode and duration set as attributes", () => {
540
- const timegroup = document.createElement("ef-timegroup");
541
- timegroup.setAttribute("mode", "fixed");
542
- timegroup.setAttribute("duration", "10s");
543
- assert.equal(timegroup.mode, "fixed");
544
- assert.equal(timegroup.durationMs, 10_000);
545
- });
546
- });
547
-
548
- describe("Dynamic content updates", () => {
549
- test("updates duration when new child temporal elements are added dynamically", async () => {
550
- // Create a sequence timegroup with initial children
551
- const timegroup = renderTimegroup(
552
- html`<ef-timegroup mode="sequence">
553
- <ef-timegroup mode="fixed" duration="3s"></ef-timegroup>
554
- <ef-timegroup mode="fixed" duration="2s"></ef-timegroup>
555
- </ef-timegroup>`,
556
- );
557
-
558
- // Initial duration should be 5 seconds (3s + 2s)
559
- assert.equal(timegroup.durationMs, 5_000);
560
- assert.equal(timegroup.childTemporals.length, 2);
561
-
562
- // Dynamically add a new child element
563
- const newChild = document.createElement("ef-timegroup");
564
- newChild.setAttribute("mode", "fixed");
565
- newChild.setAttribute("duration", "4s");
566
- timegroup.appendChild(newChild);
567
-
568
- // Wait for slot change event to process
569
- await timegroup.updateComplete;
570
-
571
- // Duration should now include the new child (3s + 2s + 4s = 9s)
572
- assert.equal(timegroup.durationMs, 9_000);
573
- assert.equal(timegroup.childTemporals.length, 3);
574
- });
575
-
576
- test("updates duration when child temporal elements are removed dynamically", async () => {
577
- // Create a contain timegroup with initial children
578
- const timegroup = renderTimegroup(
579
- html`<ef-timegroup mode="contain">
580
- <ef-timegroup id="child1" mode="fixed" duration="5s"></ef-timegroup>
581
- <ef-timegroup id="child2" mode="fixed" duration="8s"></ef-timegroup>
582
- <ef-timegroup id="child3" mode="fixed" duration="3s"></ef-timegroup>
583
- </ef-timegroup>`,
584
- );
585
-
586
- // Initial duration should be max of children (8s)
587
- assert.equal(timegroup.durationMs, 8_000);
588
- assert.equal(timegroup.childTemporals.length, 3);
589
-
590
- // Remove the longest duration child
591
- const child2 = timegroup.querySelector("#child2");
592
- child2?.remove();
593
-
594
- // Wait for slot change event to process
595
- await timegroup.updateComplete;
596
-
597
- // Duration should now be max of remaining children (5s)
598
- assert.equal(timegroup.durationMs, 5_000);
599
- assert.equal(timegroup.childTemporals.length, 2);
600
- });
601
-
602
- describe("frameTask", () => {
603
- test("executes all nested frame tasks", async () => {
604
- const timegroup = renderTimegroup(
605
- html`<ef-timegroup mode="sequence">
606
- <test-frame-task-a duration="1s"></test-frame-task-a>
607
- <div>
608
- <test-frame-task-b duration="1s">
609
- <test-frame-task-c duration="1s"></test-frame-task-c>
610
- </test-frame-task-b>
611
- </div>
612
- </ef-timegroup>`,
613
- );
614
- const frameTaskA = timegroup.querySelector("test-frame-task-a")!;
615
- const frameTaskB = timegroup.querySelector("test-frame-task-b")!;
616
- const frameTaskC = timegroup.querySelector("test-frame-task-c")!;
617
-
618
- // Following the initial update, frame tasks may run during initialization
619
- await timegroup.updateComplete;
620
-
621
- // frameTaskB should never run (not visible at time 0ms in sequence)
622
- assert.equal(frameTaskB.frameTaskCount, 0);
623
-
624
- // Then we run them manually.
625
- await timegroup.frameTask.run();
626
-
627
- // At timeline time 0ms:
628
- // - frameTaskA (0-1000ms) should have run (visible)
629
- // - frameTaskB (1000-2000ms) should NOT run (not visible at time 0)
630
- // - frameTaskC (0-1000ms) should have run (inherits root positioning, visible)
631
-
632
- // Verify visible tasks have run at least once
633
- assert.ok(frameTaskA.frameTaskCount > 0, "frameTaskA should have run");
634
- assert.ok(frameTaskC.frameTaskCount > 0, "frameTaskC should have run");
635
- // Verify non-visible task has never run
636
- assert.equal(frameTaskB.frameTaskCount, 0); // Not visible at time 0
637
- });
638
- });
639
-
640
- describe("seekTask", () => {
641
- test("does not execute if not the root timegroup", async () => {
642
- const timegroup = renderTimegroup(
643
- html`<ef-timegroup mode="sequence">
644
- <ef-timegroup mode="fixed" duration="3s">
645
- <test-frame-task-a></test-frame-task-a>
646
- </ef-timegroup>
647
- </ef-timegroup>`,
648
- );
649
- const nonRootTimegroup = timegroup.querySelector("ef-timegroup")!;
650
- const frameTaskA = timegroup.querySelector("test-frame-task-a")!;
651
- await timegroup.updateComplete;
652
- assert.equal(frameTaskA.frameTaskCount, 1);
653
- await nonRootTimegroup.seekTask.run();
654
- assert.equal(frameTaskA.frameTaskCount, 1);
655
- });
656
-
657
- test("waits for media durations", async () => {
658
- const timegroup = renderTimegroup(
659
- html`
660
- <ef-preview>
661
- <ef-timegroup mode="sequence">
662
- <timegroup-test-media></timegroup-test-media>
663
- </ef-timegroup>
664
- </ef-preview>`,
665
- );
666
- const media = timegroup.querySelector("timegroup-test-media")!;
667
- assert.equal(media.mediaEngineTaskCount, 0);
668
- await timegroup.seekTask.run();
669
- assert.equal(media.mediaEngineTaskCount, 1);
670
- });
671
- });
672
-
673
- describe("custom frame tasks", () => {
674
- test("executes registered callback on frame update", async () => {
675
- const timegroup = renderTimegroup(
676
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
677
- );
678
-
679
- let callbackExecuted = false;
680
- const callback = () => {
681
- callbackExecuted = true;
682
- };
683
-
684
- timegroup.addFrameTask(callback);
685
- await timegroup.seek(1000);
686
-
687
- assert.equal(callbackExecuted, true);
688
- }, 1000);
689
-
690
- test("callback receives correct timing information", async () => {
691
- const timegroup = renderTimegroup(
692
- html`<ef-timegroup mode="fixed" duration="5000ms"></ef-timegroup>`,
693
- );
694
-
695
- let receivedInfo: any = null;
696
- const callback = (info: any) => {
697
- receivedInfo = info;
698
- };
699
-
700
- timegroup.addFrameTask(callback);
701
- await timegroup.seek(2000);
702
-
703
- assert.equal(receivedInfo.ownCurrentTimeMs, 2000);
704
- assert.equal(receivedInfo.currentTimeMs, 2000);
705
- assert.equal(receivedInfo.durationMs, 5000);
706
- assert.equal(receivedInfo.percentComplete, 0.4);
707
- assert.equal(receivedInfo.element, timegroup);
708
- }, 1000);
709
-
710
- test("executes multiple callbacks in parallel", async () => {
711
- const timegroup = renderTimegroup(
712
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
713
- );
714
-
715
- let callback1Executed = false;
716
- let callback2Executed = false;
717
- let callback3Executed = false;
718
-
719
- timegroup.addFrameTask(() => {
720
- callback1Executed = true;
721
- });
722
- timegroup.addFrameTask(() => {
723
- callback2Executed = true;
724
- });
725
- timegroup.addFrameTask(() => {
726
- callback3Executed = true;
727
- });
728
-
729
- await timegroup.seek(1000);
730
-
731
- assert.equal(callback1Executed, true);
732
- assert.equal(callback2Executed, true);
733
- assert.equal(callback3Executed, true);
734
- }, 1000);
735
-
736
- test("async callbacks block frame pipeline", async () => {
737
- const timegroup = renderTimegroup(
738
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
739
- );
740
-
741
- let asyncCallbackCompleted = false;
742
- const executionOrder: string[] = [];
743
-
744
- const asyncCallback = async () => {
745
- executionOrder.push("async-start");
746
- await new Promise((resolve) => setTimeout(resolve, 50));
747
- asyncCallbackCompleted = true;
748
- executionOrder.push("async-end");
749
- };
750
-
751
- timegroup.addFrameTask(asyncCallback);
752
-
753
- const seekPromise = timegroup.seek(1000);
754
- executionOrder.push("seek-called");
755
-
756
- await seekPromise;
757
- executionOrder.push("seek-complete");
758
-
759
- assert.equal(asyncCallbackCompleted, true);
760
- assert.deepEqual(executionOrder, [
761
- "seek-called",
762
- "async-start",
763
- "async-end",
764
- "seek-complete",
765
- ]);
766
- }, 1000);
767
-
768
- test("cleanup function removes callback", async () => {
769
- const timegroup = renderTimegroup(
770
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
771
- );
772
-
773
- let callbackExecutionCount = 0;
774
- const cleanup = timegroup.addFrameTask(() => {
775
- callbackExecutionCount++;
776
- });
777
-
778
- await timegroup.seek(1000);
779
- assert.equal(callbackExecutionCount, 1);
780
-
781
- cleanup();
782
- await timegroup.seek(2000);
783
- assert.equal(callbackExecutionCount, 1);
784
- }, 1000);
785
-
786
- test("removeFrameTask removes callback", async () => {
787
- const timegroup = renderTimegroup(
788
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
789
- );
790
-
791
- let callbackExecutionCount = 0;
792
- const callback = () => {
793
- callbackExecutionCount++;
794
- };
795
-
796
- timegroup.addFrameTask(callback);
797
- await timegroup.seek(1000);
798
- assert.equal(callbackExecutionCount, 1);
799
-
800
- timegroup.removeFrameTask(callback);
801
- await timegroup.seek(2000);
802
- assert.equal(callbackExecutionCount, 1);
803
- }, 1000);
804
-
805
- test("addFrameTask throws error for non-function", () => {
806
- const timegroup = renderTimegroup(
807
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
808
- );
809
-
810
- assert.throws(() => {
811
- timegroup.addFrameTask("not a function" as any);
812
- }, "Frame task callback must be a function");
813
- }, 1000);
814
-
815
- test("custom frame tasks persist after disconnect and reconnect", async () => {
816
- const container = document.createElement("div");
817
- document.body.appendChild(container);
818
-
819
- const timegroup = document.createElement("ef-timegroup") as EFTimegroup;
820
- timegroup.setAttribute("mode", "fixed");
821
- timegroup.setAttribute("duration", "5s");
822
- container.appendChild(timegroup);
823
-
824
- let callbackWorkedAfterReconnect = false;
825
- const callback = () => {
826
- callbackWorkedAfterReconnect = true;
827
- };
828
-
829
- timegroup.addFrameTask(callback);
830
-
831
- // Disconnect and reconnect
832
- container.removeChild(timegroup);
833
- callbackWorkedAfterReconnect = false; // Reset after disconnect
834
- container.appendChild(timegroup);
835
-
836
- // Callback should still work after reconnect
837
- await timegroup.seek(2000);
838
- assert.equal(
839
- callbackWorkedAfterReconnect,
840
- true,
841
- "Callback should still work after reconnect",
842
- );
843
-
844
- container.remove();
845
- }, 1000);
846
-
847
- test("sync and async callbacks execute together", async () => {
848
- const timegroup = renderTimegroup(
849
- html`<ef-timegroup mode="fixed" duration="5s"></ef-timegroup>`,
850
- );
851
-
852
- let syncExecuted = false;
853
- let asyncExecuted = false;
854
-
855
- timegroup.addFrameTask(() => {
856
- syncExecuted = true;
857
- });
858
-
859
- timegroup.addFrameTask(async () => {
860
- await new Promise((resolve) => setTimeout(resolve, 10));
861
- asyncExecuted = true;
862
- });
863
-
864
- await timegroup.seek(1000);
865
-
866
- assert.equal(syncExecuted, true);
867
- assert.equal(asyncExecuted, true);
868
- }, 1000);
869
- });
870
- });