@editframe/elements 0.7.0-beta.9 → 0.8.0-beta.10

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 (107) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +43 -0
  2. package/dist/EF_INTERACTIVE.d.ts +1 -0
  3. package/dist/assets/dist/EncodedAsset.js +560 -0
  4. package/dist/assets/dist/MP4File.js +170 -0
  5. package/dist/assets/dist/memoize.js +14 -0
  6. package/dist/elements/CrossUpdateController.d.ts +8 -0
  7. package/dist/elements/EFAudio.d.ts +9 -0
  8. package/dist/elements/EFCaptions.d.ts +38 -0
  9. package/dist/elements/EFImage.d.ts +13 -0
  10. package/dist/elements/EFMedia.d.ts +63 -0
  11. package/dist/elements/EFSourceMixin.d.ts +11 -0
  12. package/dist/elements/EFTemporal.d.ts +40 -0
  13. package/dist/elements/EFTimegroup.browsertest.d.ts +11 -0
  14. package/dist/elements/EFTimegroup.d.ts +36 -0
  15. package/dist/elements/EFVideo.d.ts +13 -0
  16. package/dist/elements/EFWaveform.d.ts +29 -0
  17. package/dist/elements/FetchMixin.d.ts +7 -0
  18. package/dist/elements/TimegroupController.d.ts +13 -0
  19. package/dist/elements/durationConverter.d.ts +12 -0
  20. package/dist/elements/parseTimeToMs.d.ts +1 -0
  21. package/{src/EF_FRAMEGEN.ts → dist/elements/src/EF_FRAMEGEN.js} +35 -115
  22. package/dist/elements/src/EF_INTERACTIVE.js +7 -0
  23. package/dist/elements/src/elements/CrossUpdateController.js +16 -0
  24. package/dist/elements/src/elements/EFAudio.js +54 -0
  25. package/dist/elements/src/elements/EFCaptions.js +169 -0
  26. package/dist/elements/src/elements/EFImage.js +80 -0
  27. package/dist/elements/src/elements/EFMedia.js +356 -0
  28. package/dist/elements/src/elements/EFSourceMixin.js +55 -0
  29. package/dist/elements/src/elements/EFTemporal.js +283 -0
  30. package/dist/elements/src/elements/EFTimegroup.js +338 -0
  31. package/dist/elements/src/elements/EFVideo.js +110 -0
  32. package/dist/elements/src/elements/EFWaveform.js +226 -0
  33. package/dist/elements/src/elements/FetchMixin.js +28 -0
  34. package/dist/elements/src/elements/TimegroupController.js +20 -0
  35. package/dist/elements/src/elements/durationConverter.js +8 -0
  36. package/dist/elements/src/elements/parseTimeToMs.js +13 -0
  37. package/dist/elements/src/elements/util.js +11 -0
  38. package/dist/elements/src/gui/ContextMixin.js +246 -0
  39. package/dist/elements/src/gui/EFFilmstrip.js +731 -0
  40. package/dist/elements/src/gui/EFPreview.js +45 -0
  41. package/dist/elements/src/gui/EFToggleLoop.js +39 -0
  42. package/dist/elements/src/gui/EFTogglePlay.js +43 -0
  43. package/dist/elements/src/gui/EFWorkbench.js +128 -0
  44. package/dist/elements/src/gui/TWMixin.css.js +4 -0
  45. package/dist/elements/src/gui/TWMixin.js +36 -0
  46. package/dist/elements/src/gui/apiHostContext.js +5 -0
  47. package/dist/elements/src/gui/efContext.js +7 -0
  48. package/dist/elements/src/gui/fetchContext.js +5 -0
  49. package/dist/elements/src/gui/focusContext.js +5 -0
  50. package/dist/elements/src/gui/focusedElementContext.js +7 -0
  51. package/dist/elements/src/gui/playingContext.js +7 -0
  52. package/dist/elements/src/index.js +31 -0
  53. package/dist/elements/src/msToTimeCode.js +15 -0
  54. package/dist/elements/util.d.ts +3 -0
  55. package/dist/gui/ContextMixin.d.ts +19 -0
  56. package/dist/gui/EFFilmstrip.d.ts +148 -0
  57. package/dist/gui/EFPreview.d.ts +12 -0
  58. package/dist/gui/EFToggleLoop.d.ts +12 -0
  59. package/dist/gui/EFTogglePlay.d.ts +12 -0
  60. package/dist/gui/EFWorkbench.d.ts +18 -0
  61. package/dist/gui/TWMixin.d.ts +2 -0
  62. package/dist/gui/apiHostContext.d.ts +3 -0
  63. package/dist/gui/efContext.d.ts +4 -0
  64. package/dist/gui/fetchContext.d.ts +3 -0
  65. package/dist/gui/focusContext.d.ts +6 -0
  66. package/dist/gui/focusedElementContext.d.ts +3 -0
  67. package/dist/gui/playingContext.d.ts +6 -0
  68. package/dist/index.d.ts +12 -0
  69. package/dist/msToTimeCode.d.ts +1 -0
  70. package/dist/style.css +802 -0
  71. package/package.json +7 -10
  72. package/src/elements/EFAudio.ts +1 -1
  73. package/src/elements/EFCaptions.ts +23 -17
  74. package/src/elements/EFImage.ts +3 -3
  75. package/src/elements/EFMedia.ts +48 -17
  76. package/src/elements/EFSourceMixin.ts +1 -1
  77. package/src/elements/EFTemporal.ts +101 -6
  78. package/src/elements/EFTimegroup.browsertest.ts +3 -3
  79. package/src/elements/EFTimegroup.ts +30 -47
  80. package/src/elements/EFVideo.ts +2 -2
  81. package/src/elements/EFWaveform.ts +9 -9
  82. package/src/elements/FetchMixin.ts +5 -3
  83. package/src/elements/TimegroupController.ts +1 -1
  84. package/src/elements/durationConverter.ts +21 -1
  85. package/src/elements/parseTimeToMs.ts +1 -0
  86. package/src/elements/util.ts +1 -1
  87. package/src/gui/ContextMixin.ts +268 -0
  88. package/src/gui/EFFilmstrip.ts +61 -171
  89. package/src/gui/EFPreview.ts +39 -0
  90. package/src/gui/EFToggleLoop.ts +34 -0
  91. package/src/gui/EFTogglePlay.ts +38 -0
  92. package/src/gui/EFWorkbench.ts +11 -109
  93. package/src/gui/TWMixin.ts +10 -3
  94. package/src/gui/apiHostContext.ts +3 -0
  95. package/src/gui/efContext.ts +6 -0
  96. package/src/gui/fetchContext.ts +5 -0
  97. package/src/gui/focusContext.ts +7 -0
  98. package/src/gui/focusedElementContext.ts +5 -0
  99. package/src/gui/playingContext.ts +5 -0
  100. package/CHANGELOG.md +0 -7
  101. package/postcss.config.cjs +0 -12
  102. package/src/EF_INTERACTIVE.ts +0 -2
  103. package/src/elements.css +0 -22
  104. package/src/index.ts +0 -33
  105. package/tailwind.config.ts +0 -10
  106. package/tsconfig.json +0 -4
  107. package/vite.config.ts +0 -8
@@ -0,0 +1,731 @@
1
+ import { css, html, nothing, LitElement } from "lit";
2
+ import { property, customElement, state, eventOptions } from "lit/decorators.js";
3
+ import { consume } from "@lit/context";
4
+ import { styleMap } from "lit/directives/style-map.js";
5
+ import { createRef, ref } from "lit/directives/ref.js";
6
+ import { EFImage } from "../elements/EFImage.js";
7
+ import { EFAudio } from "../elements/EFAudio.js";
8
+ import { EFVideo } from "../elements/EFVideo.js";
9
+ import { EFCaptions, EFCaptionsActiveWord } from "../elements/EFCaptions.js";
10
+ import { EFWaveform } from "../elements/EFWaveform.js";
11
+ import { EFTimegroup } from "../elements/EFTimegroup.js";
12
+ import { TimegroupController } from "../elements/TimegroupController.js";
13
+ import { TWMixin } from "./TWMixin.js";
14
+ import { msToTimeCode } from "../msToTimeCode.js";
15
+ import { focusedElementContext } from "./focusedElementContext.js";
16
+ import { focusContext } from "./focusContext.js";
17
+ import { playingContext, loopContext } from "./playingContext.js";
18
+ var __defProp = Object.defineProperty;
19
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
20
+ var __typeError = (msg) => {
21
+ throw TypeError(msg);
22
+ };
23
+ var __decorateClass = (decorators, target, key, kind) => {
24
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
25
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
26
+ if (decorator = decorators[i])
27
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
28
+ if (kind && result) __defProp(target, key, result);
29
+ return result;
30
+ };
31
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
32
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
33
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
34
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
35
+ var _EFFilmstrip_instances, bindToTargetTimegroup_fn, _handleKeyPress, contextElement_get;
36
+ class ElementFilmstripController {
37
+ constructor(host, filmstrip) {
38
+ this.host = host;
39
+ this.filmstrip = filmstrip;
40
+ this.host.addController(this);
41
+ }
42
+ remove() {
43
+ this.host.removeController(this);
44
+ }
45
+ hostDisconnected() {
46
+ this.host.removeController(this);
47
+ }
48
+ hostUpdated() {
49
+ this.filmstrip.requestUpdate();
50
+ }
51
+ }
52
+ const CommonEffectKeys = /* @__PURE__ */ new Set([
53
+ "offset",
54
+ "easing",
55
+ "composite",
56
+ "computedOffset"
57
+ ]);
58
+ class FilmstripItem extends TWMixin(LitElement) {
59
+ constructor() {
60
+ super(...arguments);
61
+ this.element = new EFTimegroup();
62
+ this.pixelsPerMs = 0.04;
63
+ }
64
+ static {
65
+ this.styles = [
66
+ css`
67
+ :host {
68
+ display: block;
69
+ }
70
+ `
71
+ ];
72
+ }
73
+ get isFocused() {
74
+ return this.element && this.focusContext?.focusedElement === this.element;
75
+ }
76
+ get gutterStyles() {
77
+ return {
78
+ position: "relative",
79
+ left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs)}px`,
80
+ width: `${this.pixelsPerMs * (this.element.durationMs + this.element.trimStartMs + this.element.trimEndMs)}px`
81
+ };
82
+ }
83
+ get trimPortionStyles() {
84
+ return {
85
+ width: `${this.pixelsPerMs * this.element.durationMs}px`,
86
+ left: `${this.pixelsPerMs * this.element.trimStartMs}px`
87
+ };
88
+ }
89
+ render() {
90
+ return html`<div style=${styleMap(this.gutterStyles)}>
91
+ <div
92
+ class="bg-slate-300"
93
+ ?data-focused=${this.isFocused}
94
+ @mouseenter=${() => {
95
+ if (this.focusContext) {
96
+ this.focusContext.focusedElement = this.element;
97
+ }
98
+ }}
99
+ @mouseleave=${() => {
100
+ if (this.focusContext) {
101
+ this.focusContext.focusedElement = null;
102
+ }
103
+ }}
104
+ >
105
+ <div
106
+ ?data-focused=${this.isFocused}
107
+ class="border-outset relative mb-[1px] block h-[1.1rem] text-nowrap border border-slate-500 bg-blue-200 text-sm data-[focused]:bg-slate-400"
108
+ style=${styleMap(this.trimPortionStyles)}
109
+ >
110
+ ${this.animations()}
111
+ </div>
112
+ </div>
113
+ ${this.renderChildren()}
114
+ </div>`;
115
+ }
116
+ renderChildren() {
117
+ return renderFilmstripChildren(
118
+ Array.from(this.element.children),
119
+ this.pixelsPerMs
120
+ );
121
+ }
122
+ contents() {
123
+ return html``;
124
+ }
125
+ animations() {
126
+ const animations = this.element.getAnimations();
127
+ return animations.map((animation) => {
128
+ const effect = animation.effect;
129
+ if (!(effect instanceof KeyframeEffect)) {
130
+ return nothing;
131
+ }
132
+ const start = effect.getTiming().delay ?? 0;
133
+ const duration = effect.getTiming().duration;
134
+ if (duration === null) {
135
+ return nothing;
136
+ }
137
+ const keyframes = effect.getKeyframes();
138
+ const firstKeyframe = keyframes[0];
139
+ if (!firstKeyframe) {
140
+ return nothing;
141
+ }
142
+ const properties = new Set(Object.keys(firstKeyframe));
143
+ for (const key of CommonEffectKeys) {
144
+ properties.delete(key);
145
+ }
146
+ return html`<div
147
+ class="relative h-[5px] bg-blue-500 opacity-50"
148
+ label="animation"
149
+ style=${styleMap({
150
+ left: `${this.pixelsPerMs * start}px`,
151
+ width: `${this.pixelsPerMs * Number(duration)}px`
152
+ })}
153
+ >
154
+ <!-- <div class="text-nowrap">${Array.from(properties).join(" ")}</div> -->
155
+ ${effect.getKeyframes().map((keyframe) => {
156
+ return html`<div
157
+ class="absolute top-0 h-full w-1 bg-red-500"
158
+ style=${styleMap({
159
+ left: `${this.pixelsPerMs * keyframe.computedOffset * Number(duration)}px`
160
+ })}
161
+ ></div>`;
162
+ })}
163
+ </div>`;
164
+ });
165
+ }
166
+ update(changedProperties) {
167
+ if (changedProperties.has("element") && this.element instanceof LitElement) {
168
+ this.filmstripController?.remove();
169
+ this.filmstripController = new ElementFilmstripController(
170
+ this.element,
171
+ this
172
+ );
173
+ }
174
+ super.update(changedProperties);
175
+ }
176
+ }
177
+ __decorateClass([
178
+ consume({ context: focusContext, subscribe: true })
179
+ ], FilmstripItem.prototype, "focusContext", 2);
180
+ __decorateClass([
181
+ consume({ context: focusedElementContext, subscribe: true })
182
+ ], FilmstripItem.prototype, "focusedElement", 2);
183
+ __decorateClass([
184
+ property({ type: Object, attribute: false })
185
+ ], FilmstripItem.prototype, "element", 2);
186
+ __decorateClass([
187
+ property({ type: Number })
188
+ ], FilmstripItem.prototype, "pixelsPerMs", 2);
189
+ let EFAudioFilmstrip = class extends FilmstripItem {
190
+ contents() {
191
+ return html``;
192
+ }
193
+ };
194
+ EFAudioFilmstrip = __decorateClass([
195
+ customElement("ef-audio-filmstrip")
196
+ ], EFAudioFilmstrip);
197
+ let EFVideoFilmstrip = class extends FilmstripItem {
198
+ contents() {
199
+ return html` 📼 `;
200
+ }
201
+ };
202
+ EFVideoFilmstrip = __decorateClass([
203
+ customElement("ef-video-filmstrip")
204
+ ], EFVideoFilmstrip);
205
+ let EFCaptionsFilmstrip = class extends FilmstripItem {
206
+ contents() {
207
+ return html` 📝 `;
208
+ }
209
+ };
210
+ EFCaptionsFilmstrip = __decorateClass([
211
+ customElement("ef-captions-filmstrip")
212
+ ], EFCaptionsFilmstrip);
213
+ let EFWaveformFilmstrip = class extends FilmstripItem {
214
+ contents() {
215
+ return html` 🌊 `;
216
+ }
217
+ renderChildren() {
218
+ return nothing;
219
+ }
220
+ };
221
+ EFWaveformFilmstrip = __decorateClass([
222
+ customElement("ef-waveform-filmstrip")
223
+ ], EFWaveformFilmstrip);
224
+ let EFImageFilmstrip = class extends FilmstripItem {
225
+ contents() {
226
+ return html` 🖼️ `;
227
+ }
228
+ };
229
+ EFImageFilmstrip = __decorateClass([
230
+ customElement("ef-image-filmstrip")
231
+ ], EFImageFilmstrip);
232
+ let EFTimegroupFilmstrip = class extends FilmstripItem {
233
+ contents() {
234
+ return html`
235
+ <span>TIME GROUP</span>
236
+ ${renderFilmstripChildren(
237
+ Array.from(this.element.children || []),
238
+ this.pixelsPerMs
239
+ )}
240
+ </div>
241
+ `;
242
+ }
243
+ };
244
+ EFTimegroupFilmstrip = __decorateClass([
245
+ customElement("ef-timegroup-filmstrip")
246
+ ], EFTimegroupFilmstrip);
247
+ let EFHTMLFilmstrip = class extends FilmstripItem {
248
+ contents() {
249
+ return html`
250
+ <span>${this.element.tagName}</span>
251
+ ${renderFilmstripChildren(
252
+ Array.from(this.element.children || []),
253
+ this.pixelsPerMs
254
+ )}
255
+ `;
256
+ }
257
+ };
258
+ EFHTMLFilmstrip = __decorateClass([
259
+ customElement("ef-html-filmstrip")
260
+ ], EFHTMLFilmstrip);
261
+ let EFHierarchyItem = class extends TWMixin(LitElement) {
262
+ constructor() {
263
+ super(...arguments);
264
+ this.element = new EFTimegroup();
265
+ }
266
+ get icon() {
267
+ return "📼";
268
+ }
269
+ get isFocused() {
270
+ return this.element && this.focusContext?.focusedElement === this.element;
271
+ }
272
+ displayLabel() {
273
+ return nothing;
274
+ }
275
+ render() {
276
+ return html`
277
+ <div>
278
+ <div
279
+ class="peer
280
+ flex h-[1.1rem] items-center overflow-hidden text-nowrap border border-slate-500
281
+ bg-slate-200 pl-2 text-xs font-mono hover:bg-slate-400 data-[focused]:bg-slate-400"
282
+ ?data-focused=${this.isFocused}
283
+ @mouseenter=${() => {
284
+ if (this.focusContext) {
285
+ this.focusContext.focusedElement = this.element;
286
+ }
287
+ }}
288
+ @mouseleave=${() => {
289
+ if (this.focusContext) {
290
+ this.focusContext.focusedElement = null;
291
+ }
292
+ }}
293
+ >
294
+ ${this.icon} ${this.displayLabel()}
295
+ </div>
296
+ <div
297
+ class="p-[1px] pb-0 pl-2 pr-0 peer-hover:bg-slate-300 peer-data-[focused]:bg-slate-300 peer-hover:border-slate-400 peer-data-[focused]:border-slate-400""
298
+ >
299
+ ${this.renderChildren()}
300
+ </div>
301
+ </div>`;
302
+ }
303
+ renderChildren() {
304
+ return renderHierarchyChildren(Array.from(this.element.children));
305
+ }
306
+ };
307
+ __decorateClass([
308
+ property({ type: Object, attribute: false })
309
+ ], EFHierarchyItem.prototype, "element", 2);
310
+ __decorateClass([
311
+ consume({ context: focusContext })
312
+ ], EFHierarchyItem.prototype, "focusContext", 2);
313
+ __decorateClass([
314
+ consume({ context: focusedElementContext, subscribe: true })
315
+ ], EFHierarchyItem.prototype, "focusedElement", 2);
316
+ EFHierarchyItem = __decorateClass([
317
+ customElement("ef-hierarchy-item")
318
+ ], EFHierarchyItem);
319
+ let EFTimegroupHierarchyItem = class extends EFHierarchyItem {
320
+ get icon() {
321
+ return "🕒";
322
+ }
323
+ displayLabel() {
324
+ return this.element.mode ?? "(no mode)";
325
+ }
326
+ };
327
+ EFTimegroupHierarchyItem = __decorateClass([
328
+ customElement("ef-timegroup-hierarchy-item")
329
+ ], EFTimegroupHierarchyItem);
330
+ let EFAudioHierarchyItem = class extends EFHierarchyItem {
331
+ get icon() {
332
+ return "🔊";
333
+ }
334
+ displayLabel() {
335
+ return this.element.src ?? "(no src)";
336
+ }
337
+ };
338
+ EFAudioHierarchyItem = __decorateClass([
339
+ customElement("ef-audio-hierarchy-item")
340
+ ], EFAudioHierarchyItem);
341
+ let EFVideoHierarchyItem = class extends EFHierarchyItem {
342
+ get icon() {
343
+ return "📼";
344
+ }
345
+ displayLabel() {
346
+ return this.element.src ?? "(no src)";
347
+ }
348
+ };
349
+ EFVideoHierarchyItem = __decorateClass([
350
+ customElement("ef-video-hierarchy-item")
351
+ ], EFVideoHierarchyItem);
352
+ let EFCaptionsHierarchyItem = class extends EFHierarchyItem {
353
+ get icon() {
354
+ return "📝 Captions";
355
+ }
356
+ };
357
+ EFCaptionsHierarchyItem = __decorateClass([
358
+ customElement("ef-captions-hierarchy-item")
359
+ ], EFCaptionsHierarchyItem);
360
+ let EFCaptionsActiveWordHierarchyItem = class extends EFHierarchyItem {
361
+ get icon() {
362
+ return "🗣️ Active Word";
363
+ }
364
+ };
365
+ EFCaptionsActiveWordHierarchyItem = __decorateClass([
366
+ customElement("ef-captions-active-word-hierarchy-item")
367
+ ], EFCaptionsActiveWordHierarchyItem);
368
+ let EFWaveformHierarchyItem = class extends EFHierarchyItem {
369
+ get icon() {
370
+ return "🌊";
371
+ }
372
+ renderChildren() {
373
+ return nothing;
374
+ }
375
+ };
376
+ EFWaveformHierarchyItem = __decorateClass([
377
+ customElement("ef-waveform-hierarchy-item")
378
+ ], EFWaveformHierarchyItem);
379
+ let EFImageHierarchyItem = class extends EFHierarchyItem {
380
+ get icon() {
381
+ return "🖼️";
382
+ }
383
+ displayLabel() {
384
+ return this.element.src ?? "(no src)";
385
+ }
386
+ };
387
+ EFImageHierarchyItem = __decorateClass([
388
+ customElement("ef-image-hierarchy-item")
389
+ ], EFImageHierarchyItem);
390
+ let EFHTMLHierarchyItem = class extends EFHierarchyItem {
391
+ get icon() {
392
+ return html`<code>${`<${this.element.tagName.toLowerCase()}>`}</code>`;
393
+ }
394
+ };
395
+ EFHTMLHierarchyItem = __decorateClass([
396
+ customElement("ef-html-hierarchy-item")
397
+ ], EFHTMLHierarchyItem);
398
+ const renderHierarchyChildren = (children) => {
399
+ return children.map((child) => {
400
+ if (child instanceof EFTimegroup) {
401
+ return html`<ef-timegroup-hierarchy-item
402
+ .element=${child}
403
+ ></ef-timegroup-hierarchy-item>`;
404
+ }
405
+ if (child instanceof EFImage) {
406
+ return html`<ef-image-hierarchy-item
407
+ .element=${child}
408
+ ></ef-image-hierarchy-item>`;
409
+ }
410
+ if (child instanceof EFAudio) {
411
+ return html`<ef-audio-hierarchy-item
412
+ .element=${child}
413
+ ></ef-audio-hierarchy-item>`;
414
+ }
415
+ if (child instanceof EFVideo) {
416
+ return html`<ef-video-hierarchy-item
417
+ .element=${child}
418
+ ></ef-video-hierarchy-item>`;
419
+ }
420
+ if (child instanceof EFCaptions) {
421
+ return html`<ef-captions-hierarchy-item
422
+ .element=${child}
423
+ ></ef-captions-hierarchy-item>`;
424
+ }
425
+ if (child instanceof EFCaptionsActiveWord) {
426
+ return html`<ef-captions-active-word-hierarchy-item
427
+ .element=${child}
428
+ ></ef-captions-active-word-hierarchy-item>`;
429
+ }
430
+ if (child instanceof EFWaveform) {
431
+ return html`<ef-waveform-hierarchy-item
432
+ .element=${child}
433
+ ></ef-waveform-hierarchy-item>`;
434
+ }
435
+ return html`<ef-html-hierarchy-item
436
+ .element=${child}
437
+ ></ef-html-hierarchy-item>`;
438
+ });
439
+ };
440
+ const renderFilmstripChildren = (children, pixelsPerMs) => {
441
+ return children.map((child) => {
442
+ if (child instanceof EFTimegroup) {
443
+ return html`<ef-timegroup-filmstrip
444
+ .element=${child}
445
+ .pixelsPerMs=${pixelsPerMs}
446
+ >
447
+ </ef-timegroup-filmstrip>`;
448
+ }
449
+ if (child instanceof EFImage) {
450
+ return html`<ef-image-filmstrip
451
+ .element=${child}
452
+ .pixelsPerMs=${pixelsPerMs}
453
+ ></ef-image-filmstrip>`;
454
+ }
455
+ if (child instanceof EFAudio) {
456
+ return html`<ef-audio-filmstrip
457
+ .element=${child}
458
+ .pixelsPerMs=${pixelsPerMs}
459
+ ></ef-audio-filmstrip>`;
460
+ }
461
+ if (child instanceof EFVideo) {
462
+ return html`<ef-video-filmstrip
463
+ .element=${child}
464
+ .pixelsPerMs=${pixelsPerMs}
465
+ ></ef-video-filmstrip>`;
466
+ }
467
+ if (child instanceof EFCaptions) {
468
+ return html`<ef-captions-filmstrip
469
+ .element=${child}
470
+ .pixelsPerMs=${pixelsPerMs}
471
+ ></ef-captions-filmstrip>`;
472
+ }
473
+ if (child instanceof EFWaveform) {
474
+ return html`<ef-waveform-filmstrip
475
+ .element=${child}
476
+ .pixelsPerMs=${pixelsPerMs}
477
+ ></ef-waveform-filmstrip>`;
478
+ }
479
+ return html`<ef-html-filmstrip
480
+ .element=${child}
481
+ .pixelsPerMs=${pixelsPerMs}
482
+ ></ef-html-filmstrip>`;
483
+ });
484
+ };
485
+ let EFFilmstrip = class extends TWMixin(LitElement) {
486
+ constructor() {
487
+ super(...arguments);
488
+ __privateAdd(this, _EFFilmstrip_instances);
489
+ this.pixelsPerMs = 0.04;
490
+ this.scrubbing = false;
491
+ this.timelineScrolltop = 0;
492
+ this.currentTimeMs = 0;
493
+ __privateAdd(this, _handleKeyPress, (event) => {
494
+ if (event.key === " ") {
495
+ const [target] = event.composedPath();
496
+ const interactiveSelector = "input, textarea, button, select, a, [contenteditable]";
497
+ const closestInteractive = target?.closest(
498
+ interactiveSelector
499
+ );
500
+ if (closestInteractive) {
501
+ return;
502
+ }
503
+ event.preventDefault();
504
+ if (__privateGet(this, _EFFilmstrip_instances, contextElement_get)) {
505
+ __privateGet(this, _EFFilmstrip_instances, contextElement_get).playing = !__privateGet(this, _EFFilmstrip_instances, contextElement_get).playing;
506
+ }
507
+ }
508
+ });
509
+ this.gutterRef = createRef();
510
+ this.hierarchyRef = createRef();
511
+ this.playheadRef = createRef();
512
+ }
513
+ connectedCallback() {
514
+ super.connectedCallback();
515
+ __privateMethod(this, _EFFilmstrip_instances, bindToTargetTimegroup_fn).call(this);
516
+ window.addEventListener("keypress", __privateGet(this, _handleKeyPress));
517
+ }
518
+ disconnectedCallback() {
519
+ super.disconnectedCallback();
520
+ window.removeEventListener("keypress", __privateGet(this, _handleKeyPress));
521
+ }
522
+ syncGutterScroll() {
523
+ if (this.gutter && this.hierarchyRef.value) {
524
+ this.hierarchyRef.value.scrollTop = this.gutter.scrollTop;
525
+ this.timelineScrolltop = this.gutter.scrollTop;
526
+ }
527
+ }
528
+ syncHierarchyScroll() {
529
+ if (this.gutter && this.hierarchyRef.value) {
530
+ this.gutter.scrollTop = this.hierarchyRef.value.scrollTop;
531
+ this.timelineScrolltop = this.hierarchyRef.value.scrollTop;
532
+ }
533
+ }
534
+ scrub(e) {
535
+ if (this.playing) {
536
+ return;
537
+ }
538
+ if (!this.scrubbing) {
539
+ return;
540
+ }
541
+ const gutter = this.shadowRoot?.querySelector("#gutter");
542
+ if (!gutter) {
543
+ return;
544
+ }
545
+ const rect = gutter.getBoundingClientRect();
546
+ if (this.targetTimegroup) {
547
+ const layerX = e.pageX - rect.left + gutter.scrollLeft;
548
+ this.targetTimegroup.currentTimeMs = layerX / this.pixelsPerMs;
549
+ }
550
+ }
551
+ startScrub(e) {
552
+ e.preventDefault();
553
+ this.scrubbing = true;
554
+ queueMicrotask(() => {
555
+ const gutter = this.shadowRoot?.querySelector("#gutter");
556
+ if (!gutter) {
557
+ return;
558
+ }
559
+ const rect = gutter.getBoundingClientRect();
560
+ if (this.targetTimegroup) {
561
+ const layerX = e.pageX - rect.left + gutter.scrollLeft;
562
+ this.targetTimegroup.currentTimeMs = layerX / this.pixelsPerMs;
563
+ }
564
+ });
565
+ addEventListener(
566
+ "mouseup",
567
+ () => {
568
+ this.scrubbing = false;
569
+ },
570
+ { once: true }
571
+ );
572
+ }
573
+ scrollScrub(e) {
574
+ if (this.targetTimegroup && this.gutter && !this.playing) {
575
+ e.preventDefault();
576
+ if (this.gutterRef.value && this.gutterRef.value.scrollLeft === 0 && e.deltaX < 0) {
577
+ this.gutter.scrollBy(0, e.deltaY);
578
+ return;
579
+ }
580
+ if (this.gutter.scrollWidth - this.gutter.scrollLeft === this.gutter.clientWidth && e.deltaX > 0) {
581
+ this.gutter.scrollBy(0, e.deltaY);
582
+ return;
583
+ }
584
+ if (this) {
585
+ this.gutter.scrollBy(e.deltaX, e.deltaY);
586
+ this.targetTimegroup.currentTimeMs += e.deltaX / this.pixelsPerMs;
587
+ }
588
+ }
589
+ }
590
+ get gutter() {
591
+ return this.gutterRef.value;
592
+ }
593
+ render() {
594
+ const target = this.targetTimegroup;
595
+ return html` <div
596
+ class="grid h-full bg-slate-100"
597
+ style=${styleMap({
598
+ gridTemplateColumns: "200px 1fr",
599
+ gridTemplateRows: "1.5rem 1fr"
600
+ })}
601
+ >
602
+ <div
603
+ class="z-20 col-span-2 border-b-slate-600 bg-slate-100 shadow shadow-slate-300"
604
+ >
605
+ <input
606
+ type="range"
607
+ .value=${this.pixelsPerMs}
608
+ min="0.01"
609
+ max="0.1"
610
+ step="0.001"
611
+ @input=${(e) => {
612
+ const target2 = e.target;
613
+ this.pixelsPerMs = Number.parseFloat(target2.value);
614
+ }}
615
+ />
616
+ <code>${msToTimeCode(this.currentTimeMs, true)} </code> /
617
+ <code>${msToTimeCode(target?.durationMs ?? 0, true)}</code>
618
+ <ef-toggle-play><button>${this.playing ? "⏸️" : "▶️"}</button></ef-toggle-play>
619
+ <ef-toggle-loop><button>${this.loop ? "🔁" : html`<span class="opacity-50">🔁</span>`}</button></ef-toggle-loop>
620
+ </div>
621
+ <div
622
+ class="z-10 pl-1 pr-1 pt-2 shadow shadow-slate-600 overflow-auto"
623
+ ${ref(this.hierarchyRef)}
624
+ @scroll=${this.syncHierarchyScroll}
625
+ >
626
+ ${renderHierarchyChildren(target ? [target] : [])}
627
+ </div>
628
+ <div
629
+ class="h-full w-full cursor-crosshair overflow-auto bg-slate-200 pt-2"
630
+ id="gutter"
631
+ ${ref(this.gutterRef)}
632
+ @scroll=${this.syncGutterScroll}
633
+ @wheel=${this.scrollScrub}
634
+ >
635
+ <div
636
+ class="relative h-full w-full"
637
+ style="width: ${this.pixelsPerMs * (target?.durationMs ?? 0)}px;"
638
+ @mousemove=${this.scrub}
639
+ @mousedown=${this.startScrub}
640
+ >
641
+ <div
642
+ class="border-red pointer-events-none absolute z-10 h-full w-[2px] border-r-2 border-red-700"
643
+ style=${styleMap({
644
+ left: `${this.pixelsPerMs * this.currentTimeMs}px`,
645
+ top: `${this.timelineScrolltop}px`
646
+ })}
647
+ ${ref(this.playheadRef)}
648
+ ></div>
649
+
650
+ ${renderFilmstripChildren(target ? [target] : [], this.pixelsPerMs)}
651
+ </div>
652
+ </div>
653
+ </div>`;
654
+ }
655
+ updated(changes) {
656
+ if (!this.targetTimegroup) {
657
+ return;
658
+ }
659
+ if (changes.has("currentTimeMs")) {
660
+ if (this.targetTimegroup.currentTimeMs !== this.currentTimeMs) {
661
+ this.targetTimegroup.currentTimeMs = this.currentTimeMs;
662
+ }
663
+ }
664
+ }
665
+ get targetTimegroup() {
666
+ return __privateGet(this, _EFFilmstrip_instances, contextElement_get)?.targetTimegroup;
667
+ }
668
+ };
669
+ _EFFilmstrip_instances = /* @__PURE__ */ new WeakSet();
670
+ bindToTargetTimegroup_fn = function() {
671
+ if (this.timegroupController) {
672
+ this.timegroupController.remove();
673
+ }
674
+ const target = this.targetTimegroup;
675
+ if (target) {
676
+ this.timegroupController = new TimegroupController(target, this);
677
+ this.currentTimeMs = target.currentTimeMs;
678
+ }
679
+ };
680
+ _handleKeyPress = /* @__PURE__ */ new WeakMap();
681
+ contextElement_get = function() {
682
+ return this.closest("ef-workbench, ef-preview");
683
+ };
684
+ __decorateClass([
685
+ property({ type: Number })
686
+ ], EFFilmstrip.prototype, "pixelsPerMs", 2);
687
+ __decorateClass([
688
+ state()
689
+ ], EFFilmstrip.prototype, "scrubbing", 2);
690
+ __decorateClass([
691
+ state()
692
+ ], EFFilmstrip.prototype, "timelineScrolltop", 2);
693
+ __decorateClass([
694
+ consume({ context: playingContext, subscribe: true }),
695
+ state()
696
+ ], EFFilmstrip.prototype, "playing", 2);
697
+ __decorateClass([
698
+ consume({ context: loopContext, subscribe: true }),
699
+ state()
700
+ ], EFFilmstrip.prototype, "loop", 2);
701
+ __decorateClass([
702
+ state()
703
+ ], EFFilmstrip.prototype, "currentTimeMs", 2);
704
+ __decorateClass([
705
+ eventOptions({ passive: false })
706
+ ], EFFilmstrip.prototype, "syncGutterScroll", 1);
707
+ __decorateClass([
708
+ eventOptions({ passive: false })
709
+ ], EFFilmstrip.prototype, "syncHierarchyScroll", 1);
710
+ __decorateClass([
711
+ eventOptions({ capture: false })
712
+ ], EFFilmstrip.prototype, "scrub", 1);
713
+ __decorateClass([
714
+ eventOptions({ capture: false })
715
+ ], EFFilmstrip.prototype, "startScrub", 1);
716
+ __decorateClass([
717
+ eventOptions({ passive: false })
718
+ ], EFFilmstrip.prototype, "scrollScrub", 1);
719
+ EFFilmstrip = __decorateClass([
720
+ customElement("ef-filmstrip")
721
+ ], EFFilmstrip);
722
+ export {
723
+ EFAudioFilmstrip,
724
+ EFCaptionsFilmstrip,
725
+ EFFilmstrip,
726
+ EFHTMLFilmstrip,
727
+ EFImageFilmstrip,
728
+ EFTimegroupFilmstrip,
729
+ EFVideoFilmstrip,
730
+ EFWaveformFilmstrip
731
+ };