@editframe/elements 0.11.0-beta.1 → 0.11.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 (38) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +8 -15
  2. package/dist/elements/EFMedia.d.ts +2 -2
  3. package/dist/elements/EFTemporal.browsertest.d.ts +10 -0
  4. package/dist/elements/EFTemporal.d.ts +10 -2
  5. package/dist/elements/EFTimegroup.browsertest.d.ts +4 -0
  6. package/dist/elements/EFTimegroup.d.ts +12 -1
  7. package/dist/elements/EFWaveform.d.ts +3 -3
  8. package/dist/elements/durationConverter.d.ts +4 -0
  9. package/dist/elements/src/EF_FRAMEGEN.js +24 -26
  10. package/dist/elements/src/elements/EFImage.js +3 -7
  11. package/dist/elements/src/elements/EFMedia.js +27 -9
  12. package/dist/elements/src/elements/EFTemporal.js +100 -3
  13. package/dist/elements/src/elements/EFTimegroup.js +26 -5
  14. package/dist/elements/src/elements/EFVideo.js +7 -7
  15. package/dist/elements/src/elements/EFWaveform.js +14 -8
  16. package/dist/elements/src/gui/ContextMixin.js +20 -6
  17. package/dist/elements/src/gui/EFFilmstrip.js +28 -8
  18. package/dist/elements/src/gui/EFTogglePlay.js +38 -6
  19. package/dist/elements/src/gui/TWMixin.css.js +1 -1
  20. package/dist/gui/ContextMixin.d.ts +1 -0
  21. package/dist/gui/EFFilmstrip.d.ts +4 -4
  22. package/dist/gui/EFTogglePlay.d.ts +4 -0
  23. package/dist/style.css +15 -4
  24. package/package.json +2 -2
  25. package/src/elements/EFImage.ts +4 -8
  26. package/src/elements/EFMedia.browsertest.ts +231 -2
  27. package/src/elements/EFMedia.ts +48 -9
  28. package/src/elements/EFTemporal.browsertest.ts +79 -0
  29. package/src/elements/EFTemporal.ts +133 -6
  30. package/src/elements/EFTimegroup.browsertest.ts +38 -1
  31. package/src/elements/EFTimegroup.ts +27 -6
  32. package/src/elements/EFVideo.ts +7 -8
  33. package/src/elements/EFWaveform.ts +14 -9
  34. package/src/elements/durationConverter.ts +4 -0
  35. package/src/gui/ContextMixin.browsertest.ts +28 -2
  36. package/src/gui/ContextMixin.ts +23 -7
  37. package/src/gui/EFFilmstrip.ts +37 -17
  38. package/src/gui/EFTogglePlay.ts +38 -7
@@ -3,12 +3,12 @@ declare global {
3
3
  interface Window {
4
4
  EF_FRAMEGEN?: EfFramegen;
5
5
  FRAMEGEN_BRIDGE?: {
6
- onInitialize: (callback: (renderId: string, renderOptions: VideoRenderOptions) => void) => void;
7
- initialized(renderId: string): void;
8
- onBeginFrame(callback: (renderId: string, frameNumber: number, isLast: boolean) => void): void;
6
+ onInitialize: (callback: (renderOptions: VideoRenderOptions) => void) => void;
7
+ initialized(): void;
8
+ onBeginFrame(callback: (frameNumber: number, isLast: boolean) => void): void;
9
9
  onTriggerCanvas(callback: () => void): void;
10
- frameReady(renderId: string, frameNumber: number, audioSamples: ArrayBuffer): void;
11
- error(renderId: string, error: Error): void;
10
+ frameReady(frameNumber: number, audioSamples: ArrayBuffer): void;
11
+ error(error: Error): void;
12
12
  };
13
13
  }
14
14
  }
@@ -25,19 +25,12 @@ export declare class EfFramegen {
25
25
  audioBufferPromise?: Promise<AudioBuffer>;
26
26
  renderOptions?: VideoRenderOptions;
27
27
  frameBox: HTMLDivElement;
28
- BRIDGE: {
29
- onInitialize: (callback: (renderId: string, renderOptions: VideoRenderOptions) => void) => void;
30
- initialized(renderId: string): void;
31
- onBeginFrame(callback: (renderId: string, frameNumber: number, isLast: boolean) => void): void;
32
- onTriggerCanvas(callback: () => void): void;
33
- frameReady(renderId: string, frameNumber: number, audioSamples: ArrayBuffer): void;
34
- error(renderId: string, error: Error): void;
35
- } | undefined;
28
+ BRIDGE: typeof window.FRAMEGEN_BRIDGE;
36
29
  triggerCanvas: TriggerCanvas;
37
30
  trace(...args: any[]): void;
38
31
  constructor();
39
32
  connectToBridge(): void;
40
- initialize(renderId: string, renderOptions: VideoRenderOptions): Promise<void>;
41
- beginFrame(renderId: string, frameNumber: number, isLast: boolean): Promise<string | ArrayBuffer | null | undefined>;
33
+ initialize(renderOptions: VideoRenderOptions): Promise<void>;
34
+ beginFrame(frameNumber: number, isLast: boolean): Promise<string | ArrayBuffer | null | undefined>;
42
35
  }
43
36
  export {};
@@ -1,8 +1,8 @@
1
- import { LitElement, PropertyValueMap } from 'lit';
2
1
  import { Task } from '@lit/task';
2
+ import { LitElement, PropertyValueMap } from 'lit';
3
3
  import { TrackFragmentIndex, TrackSegment } from '../../../assets/src/index.ts';
4
- import { MP4File } from '../../../assets/src/MP4File.ts';
5
4
  import { VideoAsset } from '../../../assets/src/EncodedAsset.ts';
5
+ import { MP4File } from '../../../assets/src/MP4File.ts';
6
6
  import type * as MP4Box from "mp4box";
7
7
  export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
8
8
  declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
@@ -0,0 +1,10 @@
1
+ import { LitElement } from 'lit';
2
+ declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
3
+ declare class TestTemporal extends TestTemporal_base {
4
+ }
5
+ declare global {
6
+ interface HTMLElementTagNameMap {
7
+ "test-temporal": TestTemporal;
8
+ }
9
+ }
10
+ export {};
@@ -8,6 +8,16 @@ export declare class TemporalMixinInterface {
8
8
  get hasOwnDuration(): boolean;
9
9
  get trimStartMs(): number;
10
10
  get trimEndMs(): number;
11
+ set trimStartMs(value: number);
12
+ set trimEndMs(value: number);
13
+ set trimstart(value: string);
14
+ set trimend(value: string);
15
+ get sourceInMs(): number;
16
+ get sourceOutMs(): number;
17
+ set sourceInMs(value: number);
18
+ set sourceOutMs(value: number);
19
+ set sourcein(value: string);
20
+ set sourceout(value: string);
11
21
  get durationMs(): number;
12
22
  get startTimeMs(): number;
13
23
  get startTimeWithinParentMs(): number;
@@ -16,8 +26,6 @@ export declare class TemporalMixinInterface {
16
26
  get trimAdjustedOwnCurrentTimeMs(): number;
17
27
  set duration(value: string);
18
28
  get duration(): string;
19
- set trimstart(value: string);
20
- set trimend(value: string);
21
29
  parentTimegroup?: EFTimegroup;
22
30
  rootTimegroup?: EFTimegroup;
23
31
  frameTask: Task<readonly unknown[], unknown>;
@@ -1,4 +1,7 @@
1
1
  import { LitElement } from 'lit';
2
+ declare const TestContext_base: (new (...args: any[]) => import('../gui/ContextMixin.ts').ContextMixinInterface) & typeof LitElement;
3
+ declare class TestContext extends TestContext_base {
4
+ }
2
5
  declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
3
6
  declare class TestTemporal extends TestTemporal_base {
4
7
  get hasOwnDuration(): boolean;
@@ -6,6 +9,7 @@ declare class TestTemporal extends TestTemporal_base {
6
9
  declare global {
7
10
  interface HTMLElementTagNameMap {
8
11
  "test-temporal": TestTemporal;
12
+ "test-context": TestContext;
9
13
  }
10
14
  }
11
15
  export {};
@@ -1,5 +1,5 @@
1
- import { LitElement, PropertyValueMap } from 'lit';
2
1
  import { Task } from '@lit/task';
2
+ import { LitElement, PropertyValueMap } from 'lit';
3
3
  export declare const shallowGetTimegroups: (element: Element, groups?: EFTimegroup[]) => EFTimegroup[];
4
4
  declare const EFTimegroup_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
5
5
  export declare class EFTimegroup extends EFTimegroup_base {
@@ -20,6 +20,17 @@ export declare class EFTimegroup extends EFTimegroup_base {
20
20
  waitForMediaDurations(): Promise<Record<number, import('../../../assets/src/index.ts').TrackFragmentIndex>[]>;
21
21
  get childTemporals(): import('./EFTemporal.ts').TemporalMixinInterface[];
22
22
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
23
+ get contextProvider(): (ParentNode & import('../gui/ContextMixin.ts').ContextMixinInterface) | null;
24
+ /**
25
+ * Returns true if the timegroup should be wrapped with a workbench.
26
+ *
27
+ * A timegroup should be wrapped with a workbench if it is the root-most timegroup
28
+ * and EF_INTERACTIVE is true.
29
+ *
30
+ * If the timegroup is already wrappedin a context provider like ef-preview,
31
+ * it should NOT be wrapped in a workbench.
32
+ *
33
+ */
23
34
  shouldWrapWithWorkbench(): boolean;
24
35
  wrapWithWorkbench(): void;
25
36
  get hasOwnDuration(): boolean;
@@ -1,11 +1,11 @@
1
1
  import { EFAudio } from './EFAudio.ts';
2
- import { LitElement } from 'lit';
3
- import { EFVideo } from './EFVideo.ts';
4
2
  import { Task } from '@lit/task';
3
+ import { LitElement } from 'lit';
5
4
  import { Ref } from 'lit/directives/ref.js';
5
+ import { EFVideo } from './EFVideo.ts';
6
6
  declare const EFWaveform_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
7
7
  export declare class EFWaveform extends EFWaveform_base {
8
- static styles: never[];
8
+ static styles: import('lit').CSSResult[];
9
9
  svgRef: Ref<SVGElement>;
10
10
  createRenderRoot(): this;
11
11
  render(): import('lit-html').TemplateResult<1>;
@@ -10,3 +10,7 @@ export declare const imageDurationConverter: {
10
10
  fromAttribute: (value: string) => number;
11
11
  toAttribute: (value: number) => string;
12
12
  };
13
+ export declare const sourceDurationConverter: {
14
+ fromAttribute: (value: string) => number;
15
+ toAttribute: (value: number) => string;
16
+ };
@@ -1,8 +1,6 @@
1
- import debug from "debug";
2
1
  import { TaskStatus } from "@lit/task";
3
2
  import { deepGetElementsWithFrameTasks } from "./elements/EFTemporal.js";
4
3
  import { shallowGetTimegroups } from "./elements/EFTimegroup.js";
5
- const log = debug("ef:elements:EF_FRAMEGEN");
6
4
  class TriggerCanvas {
7
5
  constructor() {
8
6
  this.canvas = document.createElement("canvas");
@@ -23,7 +21,7 @@ class TriggerCanvas {
23
21
  this.ctx.fillStyle = "black";
24
22
  }
25
23
  trigger() {
26
- log("TRIGGERING CANVAS");
24
+ console.log("TRIGGERING CANVAS");
27
25
  this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
28
26
  }
29
27
  }
@@ -33,9 +31,10 @@ class EfFramegen {
33
31
  this.frameDurationMs = 0;
34
32
  this.initialBusyTasks = Promise.resolve([]);
35
33
  this.frameBox = document.createElement("div");
36
- this.BRIDGE = window.FRAMEGEN_BRIDGE;
37
34
  this.triggerCanvas = new TriggerCanvas();
35
+ this.BRIDGE = window.FRAMEGEN_BRIDGE;
38
36
  if (this.BRIDGE) {
37
+ console.log("BRIDGE.constructor (connecting to bridge)");
39
38
  this.connectToBridge();
40
39
  }
41
40
  }
@@ -47,27 +46,28 @@ class EfFramegen {
47
46
  if (!BRIDGE) {
48
47
  throw new Error("No BRIDGE when attempting to connect to bridge");
49
48
  }
50
- BRIDGE.onInitialize(async (renderId, renderOptions) => {
51
- log("BRIDGE.onInitialize", renderId, renderOptions);
52
- await this.initialize(renderId, renderOptions);
53
- BRIDGE.initialized(renderId);
49
+ console.log("BRIDGE.connectToBridge");
50
+ BRIDGE.onInitialize(async (renderOptions) => {
51
+ console.log("BRIDGE.onInitialize", renderOptions);
52
+ await this.initialize(renderOptions);
53
+ BRIDGE.initialized();
54
54
  });
55
- BRIDGE.onBeginFrame((renderId, frameNumber, isLast) => {
56
- log("BRIDGE.onBeginFrame", renderId, frameNumber, isLast);
57
- this.beginFrame(renderId, frameNumber, isLast);
55
+ BRIDGE.onBeginFrame((frameNumber, isLast) => {
56
+ console.log("BRIDGE.onBeginFrame", frameNumber, isLast);
57
+ this.beginFrame(frameNumber, isLast);
58
58
  });
59
59
  }
60
- async initialize(renderId, renderOptions) {
60
+ async initialize(renderOptions) {
61
61
  addEventListener("unhandledrejection", (event) => {
62
62
  this.trace("Unhandled rejection:", event.reason);
63
63
  if (this.BRIDGE) {
64
- this.BRIDGE.error(renderId, event.reason);
64
+ this.BRIDGE.error(event.reason);
65
65
  }
66
66
  });
67
67
  addEventListener("error", (event) => {
68
68
  this.trace("Uncaught error", event.error);
69
69
  if (this.BRIDGE) {
70
- this.BRIDGE.error(renderId, event.error);
70
+ this.BRIDGE.error(event.error);
71
71
  }
72
72
  });
73
73
  this.renderOptions = renderOptions;
@@ -107,9 +107,9 @@ class EfFramegen {
107
107
  // renderOptions.encoderOptions.fromMs,
108
108
  // renderOptions.encoderOptions.toMs,
109
109
  );
110
- log("Initialized");
110
+ console.log("Initialized");
111
111
  }
112
- async beginFrame(renderId, frameNumber, isLast) {
112
+ async beginFrame(frameNumber, isLast) {
113
113
  if (this.renderOptions === void 0) {
114
114
  throw new Error("No renderOptions");
115
115
  }
@@ -132,18 +132,20 @@ class EfFramegen {
132
132
  }
133
133
  this.time = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
134
134
  firstGroup.currentTimeMs = this.time;
135
- log("Awaiting initialBusyTasks");
135
+ console.log("Awaiting initialBusyTasks");
136
136
  await this.initialBusyTasks;
137
- log("Awaiting microtask");
137
+ console.log("Awaiting microtask");
138
138
  await new Promise(queueMicrotask);
139
- log("Awaiting frame tasks");
139
+ console.log("Awaiting frame tasks");
140
140
  const now = performance.now();
141
141
  await Promise.all(
142
142
  temporals.filter((temporal) => temporal.frameTask.status < TaskStatus.COMPLETE).map((temporal) => {
143
143
  return temporal.frameTask;
144
144
  }).map((task) => task.taskComplete)
145
145
  );
146
- log(`frame:${frameNumber} All tasks complete ${performance.now() - now}ms`);
146
+ console.log(
147
+ `frame:${frameNumber} All tasks complete ${performance.now() - now}ms`
148
+ );
147
149
  if (isLast && this.audioBufferPromise) {
148
150
  const renderedAudio = await this.audioBufferPromise;
149
151
  const channelCount = renderedAudio.numberOfChannels;
@@ -160,11 +162,7 @@ class EfFramegen {
160
162
  }
161
163
  if (this.BRIDGE) {
162
164
  this.triggerCanvas.trigger();
163
- this.BRIDGE.frameReady(
164
- renderId,
165
- frameNumber,
166
- interleavedSamples.buffer
167
- );
165
+ this.BRIDGE.frameReady(frameNumber, interleavedSamples.buffer);
168
166
  } else {
169
167
  const fileReader = new FileReader();
170
168
  fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));
@@ -177,7 +175,7 @@ class EfFramegen {
177
175
  } else {
178
176
  if (this.BRIDGE) {
179
177
  this.triggerCanvas.trigger();
180
- this.BRIDGE.frameReady(renderId, frameNumber, new ArrayBuffer(0));
178
+ this.BRIDGE.frameReady(frameNumber, new ArrayBuffer(0));
181
179
  } else {
182
180
  const fileReader = new FileReader();
183
181
  fileReader.readAsDataURL(new Blob([]));
@@ -2,10 +2,10 @@ import { Task } from "@lit/task";
2
2
  import { html, css, LitElement } from "lit";
3
3
  import { property, customElement } from "lit/decorators.js";
4
4
  import { createRef, ref } from "lit/directives/ref.js";
5
- import { FetchMixin } from "./FetchMixin.js";
6
- import { EFSourceMixin } from "./EFSourceMixin.js";
7
5
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
8
6
  import { EF_RENDERING } from "../EF_RENDERING.js";
7
+ import { EFSourceMixin } from "./EFSourceMixin.js";
8
+ import { FetchMixin } from "./FetchMixin.js";
9
9
  var __defProp = Object.defineProperty;
10
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
11
  var __typeError = (msg) => {
@@ -90,11 +90,7 @@ EFImage.styles = [
90
90
  display: block;
91
91
  }
92
92
  canvas {
93
- display: block;
94
- width: 100%;
95
- height: 100%;
96
- object-fit: fill;
97
- object-position: center;
93
+ all: inherit
98
94
  }
99
95
  `
100
96
  ];
@@ -1,18 +1,18 @@
1
- import { css, LitElement } from "lit";
2
- import { property, state } from "lit/decorators.js";
3
- import { deepArrayEquals } from "@lit/task/deep-equals.js";
4
- import { Task } from "@lit/task";
5
1
  import { consume } from "@lit/context";
2
+ import { Task } from "@lit/task";
3
+ import { deepArrayEquals } from "@lit/task/deep-equals.js";
6
4
  import debug from "debug";
7
- import { MP4File } from "../../../assets/src/MP4File.js";
5
+ import { css, LitElement } from "lit";
6
+ import { property, state } from "lit/decorators.js";
8
7
  import { VideoAsset } from "../../../assets/src/EncodedAsset.js";
8
+ import { MP4File } from "../../../assets/src/MP4File.js";
9
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
10
+ import { EF_RENDERING } from "../EF_RENDERING.js";
11
+ import { apiHostContext } from "../gui/apiHostContext.js";
12
+ import { EFSourceMixin } from "./EFSourceMixin.js";
9
13
  import { EFTemporal } from "./EFTemporal.js";
10
14
  import { FetchMixin } from "./FetchMixin.js";
11
- import { EFSourceMixin } from "./EFSourceMixin.js";
12
15
  import { getStartTimeMs } from "./util.js";
13
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
14
- import { apiHostContext } from "../gui/apiHostContext.js";
15
- import { EF_RENDERING } from "../EF_RENDERING.js";
16
16
  var __defProp = Object.defineProperty;
17
17
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
18
18
  var __decorateClass = (decorators, target, key, kind) => {
@@ -291,6 +291,18 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
291
291
  if (durations.length === 0) {
292
292
  return 0;
293
293
  }
294
+ if (this.sourceInMs && this.sourceOutMs && this.sourceOutMs > this.sourceInMs) {
295
+ return Math.max(this.sourceOutMs - this.sourceInMs);
296
+ }
297
+ if (this.sourceInMs) {
298
+ return Math.max(...durations) - this.trimStartMs - this.trimEndMs - this.sourceInMs;
299
+ }
300
+ if (this.sourceOutMs) {
301
+ return Math.max(...durations) - this.trimStartMs - this.trimEndMs - this.sourceOutMs;
302
+ }
303
+ if (this.sourceInMs && this.sourceOutMs) {
304
+ return Math.max(...durations) - this.trimStartMs - this.trimEndMs - this.sourceOutMs - this.sourceInMs;
305
+ }
294
306
  return Math.max(...durations) - this.trimStartMs - this.trimEndMs;
295
307
  }
296
308
  get startTimeMs() {
@@ -298,6 +310,12 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
298
310
  }
299
311
  #audioContext;
300
312
  async fetchAudioSpanningTime(fromMs, toMs) {
313
+ if (this.sourceInMs) {
314
+ fromMs -= this.startTimeMs - this.trimStartMs - this.sourceInMs;
315
+ }
316
+ if (this.sourceOutMs) {
317
+ toMs -= this.startTimeMs - this.trimStartMs - this.sourceOutMs;
318
+ }
301
319
  fromMs -= this.startTimeMs - this.trimStartMs;
302
320
  toMs -= this.startTimeMs - this.trimStartMs;
303
321
  await this.trackFragmentIndexLoader.taskComplete;
@@ -1,8 +1,8 @@
1
1
  import { createContext, consume } from "@lit/context";
2
2
  import { property, state } from "lit/decorators.js";
3
- import { durationConverter } from "./durationConverter.js";
4
3
  import { Task } from "@lit/task";
5
4
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
5
+ import { durationConverter } from "./durationConverter.js";
6
6
  var __defProp = Object.defineProperty;
7
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
8
  var __decorateClass = (decorators, target, key, kind) => {
@@ -115,12 +115,78 @@ const EFTemporal = (superClass) => {
115
115
  get parentTimegroup() {
116
116
  return this.#parentTimegroup;
117
117
  }
118
+ set duration(value) {
119
+ if (value !== void 0) {
120
+ this.setAttribute("duration", value);
121
+ } else {
122
+ this.removeAttribute("duration");
123
+ }
124
+ }
118
125
  get trimStartMs() {
119
126
  return this._trimStartMs;
120
127
  }
128
+ set trimStartMs(value) {
129
+ this._trimStartMs = value;
130
+ this.setAttribute(
131
+ "trimstart",
132
+ durationConverter.toAttribute(value / 1e3)
133
+ );
134
+ }
135
+ set trimstart(value) {
136
+ if (value !== void 0) {
137
+ this.setAttribute("trimstart", value);
138
+ } else {
139
+ this.removeAttribute("trimstart");
140
+ }
141
+ }
121
142
  get trimEndMs() {
122
143
  return this._trimEndMs;
123
144
  }
145
+ set trimEndMs(value) {
146
+ this._trimEndMs = value;
147
+ this.setAttribute("trimend", durationConverter.toAttribute(value / 1e3));
148
+ }
149
+ set trimend(value) {
150
+ if (value !== void 0) {
151
+ this.setAttribute("trimend", value);
152
+ } else {
153
+ this.removeAttribute("trimend");
154
+ }
155
+ }
156
+ get sourceInMs() {
157
+ return this._sourceInMs;
158
+ }
159
+ set sourceInMs(value) {
160
+ this._sourceInMs = value;
161
+ value !== void 0 ? this.setAttribute(
162
+ "sourcein",
163
+ durationConverter.toAttribute(value / 1e3)
164
+ ) : this.removeAttribute("sourcein");
165
+ }
166
+ set sourcein(value) {
167
+ if (value !== void 0) {
168
+ this.setAttribute("sourcein", value);
169
+ } else {
170
+ this.removeAttribute("sourcein");
171
+ }
172
+ }
173
+ get sourceOutMs() {
174
+ return this._sourceOutMs;
175
+ }
176
+ set sourceOutMs(value) {
177
+ this._sourceOutMs = value;
178
+ value !== void 0 ? this.setAttribute(
179
+ "sourceout",
180
+ durationConverter.toAttribute(value / 1e3)
181
+ ) : this.removeAttribute("sourceout");
182
+ }
183
+ set sourceout(value) {
184
+ if (value !== void 0) {
185
+ this.setAttribute("sourceout", value);
186
+ } else {
187
+ this.removeAttribute("sourceout");
188
+ }
189
+ }
124
190
  get startOffsetMs() {
125
191
  return this._startOffsetMs;
126
192
  }
@@ -137,6 +203,12 @@ const EFTemporal = (superClass) => {
137
203
  // Defining this as a getter to a private property allows us to
138
204
  // override it classes that include this mixin.
139
205
  get durationMs() {
206
+ if (this.sourceInMs) {
207
+ return this._durationMs || this.parentTimegroup?.durationMs || 0 - this.sourceInMs;
208
+ }
209
+ if (this.sourceOutMs) {
210
+ return this._durationMs || this.parentTimegroup?.durationMs || 0 - this.sourceOutMs;
211
+ }
140
212
  return this._durationMs || this.parentTimegroup?.durationMs || 0;
141
213
  }
142
214
  get offsetMs() {
@@ -214,6 +286,15 @@ const EFTemporal = (superClass) => {
214
286
  */
215
287
  get trimAdjustedOwnCurrentTimeMs() {
216
288
  if (this.rootTimegroup) {
289
+ if (this.sourceInMs && this.sourceOutMs) {
290
+ return Math.min(
291
+ Math.max(
292
+ 0,
293
+ this.rootTimegroup.currentTimeMs - this.startTimeMs + this.trimStartMs + this.sourceInMs
294
+ ),
295
+ this.durationMs + Math.abs(this.startOffsetMs) + this.trimStartMs + this.sourceInMs
296
+ );
297
+ }
217
298
  return Math.min(
218
299
  Math.max(
219
300
  0,
@@ -249,14 +330,30 @@ const EFTemporal = (superClass) => {
249
330
  attribute: "trimstart",
250
331
  converter: durationConverter
251
332
  })
252
- ], TemporalMixinClass.prototype, "_trimStartMs", 2);
333
+ ], TemporalMixinClass.prototype, "trimStartMs", 1);
253
334
  __decorateClass([
254
335
  property({
255
336
  type: Number,
256
337
  attribute: "trimend",
257
338
  converter: durationConverter
258
339
  })
259
- ], TemporalMixinClass.prototype, "_trimEndMs", 2);
340
+ ], TemporalMixinClass.prototype, "trimEndMs", 1);
341
+ __decorateClass([
342
+ property({
343
+ type: Number,
344
+ attribute: "sourcein",
345
+ converter: durationConverter,
346
+ reflect: true
347
+ })
348
+ ], TemporalMixinClass.prototype, "sourceInMs", 1);
349
+ __decorateClass([
350
+ property({
351
+ type: Number,
352
+ attribute: "sourceout",
353
+ converter: durationConverter,
354
+ reflect: true
355
+ })
356
+ ], TemporalMixinClass.prototype, "sourceOutMs", 1);
260
357
  __decorateClass([
261
358
  property({
262
359
  type: Number,
@@ -1,12 +1,13 @@
1
- import { html, css, LitElement } from "lit";
2
1
  import { provide } from "@lit/context";
3
2
  import { Task } from "@lit/task";
4
- import { property, customElement } from "lit/decorators.js";
5
3
  import debug from "debug";
6
- import { EFTemporal, shallowGetTemporalElements, isEFTemporal, timegroupContext } from "./EFTemporal.js";
7
- import { TimegroupController } from "./TimegroupController.js";
4
+ import { html, css, LitElement } from "lit";
5
+ import { property, customElement } from "lit/decorators.js";
8
6
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
7
+ import { isContextMixin } from "../gui/ContextMixin.js";
9
8
  import { deepGetMediaElements } from "./EFMedia.js";
9
+ import { EFTemporal, shallowGetTemporalElements, isEFTemporal, timegroupContext } from "./EFTemporal.js";
10
+ import { TimegroupController } from "./TimegroupController.js";
10
11
  import { durationConverter } from "./durationConverter.js";
11
12
  var __defProp = Object.defineProperty;
12
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -212,8 +213,28 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
212
213
  }
213
214
  }
214
215
  }
216
+ get contextProvider() {
217
+ let parent = this.parentNode;
218
+ while (parent) {
219
+ if (isContextMixin(parent)) {
220
+ return parent;
221
+ }
222
+ parent = parent.parentNode;
223
+ }
224
+ return null;
225
+ }
226
+ /**
227
+ * Returns true if the timegroup should be wrapped with a workbench.
228
+ *
229
+ * A timegroup should be wrapped with a workbench if it is the root-most timegroup
230
+ * and EF_INTERACTIVE is true.
231
+ *
232
+ * If the timegroup is already wrappedin a context provider like ef-preview,
233
+ * it should NOT be wrapped in a workbench.
234
+ *
235
+ */
215
236
  shouldWrapWithWorkbench() {
216
- return EF_INTERACTIVE && this.closest("ef-timegroup") === this && this.closest("ef-workbench") === null && this.closest("ef-preview") === null;
237
+ return EF_INTERACTIVE && this.closest("ef-timegroup") === this && this.contextProvider === null;
217
238
  }
218
239
  wrapWithWorkbench() {
219
240
  const workbench = document.createElement("ef-workbench");
@@ -1,9 +1,9 @@
1
- import { css, html } from "lit";
2
1
  import { Task } from "@lit/task";
3
- import { createRef, ref } from "lit/directives/ref.js";
2
+ import { css, html } from "lit";
4
3
  import { customElement } from "lit/decorators.js";
5
- import { EFMedia } from "./EFMedia.js";
4
+ import { createRef, ref } from "lit/directives/ref.js";
6
5
  import { TWMixin } from "../gui/TWMixin.js";
6
+ import { EFMedia } from "./EFMedia.js";
7
7
  var __defProp = Object.defineProperty;
8
8
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
9
  var __typeError = (msg) => {
@@ -85,10 +85,7 @@ let EFVideo = class extends TWMixin(EFMedia) {
85
85
  });
86
86
  }
87
87
  render() {
88
- return html` <canvas
89
- class="h-full w-full object-fill"
90
- ${ref(this.canvasRef)}
91
- ></canvas>`;
88
+ return html` <canvas ${ref(this.canvasRef)}></canvas>`;
92
89
  }
93
90
  get canvasElement() {
94
91
  return this.canvasRef.value;
@@ -100,6 +97,9 @@ EFVideo.styles = [
100
97
  :host {
101
98
  display: block;
102
99
  }
100
+ canvas {
101
+ all: inherit;
102
+ }
103
103
  `
104
104
  ];
105
105
  EFVideo = __decorateClass([
@@ -1,14 +1,14 @@
1
1
  import { EFAudio } from "./EFAudio.js";
2
- import { html, LitElement } from "lit";
3
- import { property, customElement } from "lit/decorators.js";
4
- import { EFVideo } from "./EFVideo.js";
5
- import { EFTemporal } from "./EFTemporal.js";
6
- import { CrossUpdateController } from "./CrossUpdateController.js";
7
- import { TWMixin } from "../gui/TWMixin.js";
8
2
  import { Task } from "@lit/task";
9
3
  import * as d3 from "d3";
4
+ import { html, css, LitElement } from "lit";
5
+ import { property, customElement } from "lit/decorators.js";
10
6
  import { createRef, ref } from "lit/directives/ref.js";
11
7
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
8
+ import { TWMixin } from "../gui/TWMixin.js";
9
+ import { CrossUpdateController } from "./CrossUpdateController.js";
10
+ import { EFTemporal } from "./EFTemporal.js";
11
+ import { EFVideo } from "./EFVideo.js";
12
12
  var __defProp = Object.defineProperty;
13
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
14
14
  var __decorateClass = (decorators, target, key, kind) => {
@@ -38,7 +38,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
38
38
  return this;
39
39
  }
40
40
  render() {
41
- return html` <svg ${ref(this.svgRef)} class="h-full w-full" store></svg> `;
41
+ return html` <svg ${ref(this.svgRef)} store></svg> `;
42
42
  }
43
43
  set target(value) {
44
44
  this.targetSelector = value;
@@ -205,7 +205,13 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
205
205
  throw new Error("Invalid target, must be an EFAudio or EFVideo element");
206
206
  }
207
207
  };
208
- EFWaveform.styles = [];
208
+ EFWaveform.styles = [
209
+ css`
210
+ svg {
211
+ all: inherit;
212
+ }
213
+ `
214
+ ];
209
215
  __decorateClass([
210
216
  property({
211
217
  type: String,