@editframe/elements 0.8.0-beta.1 → 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 (57) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +0 -1
  2. package/dist/elements/CrossUpdateController.d.ts +0 -1
  3. package/dist/elements/EFAudio.d.ts +0 -1
  4. package/dist/elements/EFCaptions.d.ts +3 -3
  5. package/dist/elements/EFImage.d.ts +0 -1
  6. package/dist/elements/EFMedia.d.ts +5 -3
  7. package/dist/elements/EFSourceMixin.d.ts +0 -1
  8. package/dist/elements/EFTemporal.d.ts +3 -1
  9. package/dist/elements/EFTimegroup.browsertest.d.ts +0 -1
  10. package/dist/elements/EFTimegroup.d.ts +2 -5
  11. package/dist/elements/EFVideo.d.ts +0 -1
  12. package/dist/elements/EFWaveform.d.ts +0 -1
  13. package/dist/elements/FetchMixin.d.ts +0 -1
  14. package/dist/elements/TimegroupController.d.ts +0 -1
  15. package/dist/elements/durationConverter.d.ts +8 -0
  16. package/dist/elements/src/elements/EFCaptions.js +10 -7
  17. package/dist/elements/src/elements/EFMedia.js +25 -8
  18. package/dist/elements/src/elements/EFTemporal.js +51 -2
  19. package/dist/elements/src/elements/EFTimegroup.js +22 -39
  20. package/dist/elements/src/elements/EFWaveform.js +3 -3
  21. package/dist/elements/src/elements/parseTimeToMs.js +1 -0
  22. package/dist/elements/src/gui/ContextMixin.js +37 -25
  23. package/dist/elements/src/gui/EFFilmstrip.js +27 -25
  24. package/dist/elements/src/gui/EFToggleLoop.js +39 -0
  25. package/dist/elements/src/gui/EFTogglePlay.js +43 -0
  26. package/dist/elements/src/gui/EFWorkbench.js +4 -4
  27. package/dist/elements/src/gui/TWMixin.css.js +1 -1
  28. package/dist/elements/src/gui/efContext.js +7 -0
  29. package/dist/elements/src/gui/playingContext.js +2 -0
  30. package/dist/elements/src/index.js +4 -0
  31. package/dist/elements/util.d.ts +0 -1
  32. package/dist/gui/ContextMixin.d.ts +8 -12
  33. package/dist/gui/EFFilmstrip.d.ts +7 -3
  34. package/dist/gui/EFPreview.d.ts +1 -16
  35. package/dist/gui/EFToggleLoop.d.ts +12 -0
  36. package/dist/gui/EFTogglePlay.d.ts +12 -0
  37. package/dist/gui/EFWorkbench.d.ts +1 -17
  38. package/dist/gui/TWMixin.d.ts +0 -1
  39. package/dist/gui/efContext.d.ts +4 -0
  40. package/dist/gui/playingContext.d.ts +3 -0
  41. package/dist/index.d.ts +2 -1
  42. package/dist/style.css +7 -5
  43. package/package.json +3 -3
  44. package/src/elements/EFCaptions.ts +14 -8
  45. package/src/elements/EFMedia.ts +37 -9
  46. package/src/elements/EFTemporal.ts +60 -2
  47. package/src/elements/EFTimegroup.ts +21 -41
  48. package/src/elements/EFWaveform.ts +3 -3
  49. package/src/elements/durationConverter.ts +20 -0
  50. package/src/elements/parseTimeToMs.ts +1 -0
  51. package/src/gui/ContextMixin.ts +50 -36
  52. package/src/gui/EFFilmstrip.ts +27 -28
  53. package/src/gui/EFToggleLoop.ts +34 -0
  54. package/src/gui/EFTogglePlay.ts +38 -0
  55. package/src/gui/EFWorkbench.ts +4 -4
  56. package/src/gui/efContext.ts +6 -0
  57. package/src/gui/playingContext.ts +2 -0
@@ -1,5 +1,4 @@
1
1
  import { VideoRenderOptions } from '../../assets/src';
2
-
3
2
  declare global {
4
3
  interface Window {
5
4
  EF_FRAMEGEN?: EfFramegen;
@@ -1,5 +1,4 @@
1
1
  import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit';
2
-
3
2
  export declare class CrossUpdateController implements ReactiveController {
4
3
  private host;
5
4
  private target;
@@ -1,6 +1,5 @@
1
1
  import { EFMedia } from './EFMedia.ts';
2
2
  import { Task } from '@lit/task';
3
-
4
3
  export declare class EFAudio extends EFMedia {
5
4
  audioElementRef: import('lit-html/directives/ref.js').Ref<HTMLAudioElement>;
6
5
  src: string;
@@ -2,7 +2,6 @@ import { LitElement, PropertyValueMap } from 'lit';
2
2
  import { Task } from '@lit/task';
3
3
  import { EFVideo } from './EFVideo.ts';
4
4
  import { EFAudio } from './EFAudio.ts';
5
-
6
5
  declare const EFCaptionsActiveWord_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
7
6
  export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
8
7
  static styles: import('lit').CSSResult[];
@@ -16,11 +15,12 @@ export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
16
15
  declare const EFCaptions_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
17
16
  export declare class EFCaptions extends EFCaptions_base {
18
17
  static styles: import('lit').CSSResult[];
19
- target: null;
18
+ targetSelector: string;
19
+ set target(value: string);
20
20
  wordStyle: string;
21
21
  activeWordContainers: HTMLCollectionOf<EFCaptionsActiveWord>;
22
22
  captionsPath(): string;
23
- protected md5SumLoader: Task<readonly [null, typeof fetch], string | undefined>;
23
+ protected md5SumLoader: Task<readonly [string, typeof fetch], string | undefined>;
24
24
  private captionsDataTask;
25
25
  frameTask: Task<import('@lit/task').TaskStatus[], void>;
26
26
  connectedCallback(): void;
@@ -1,6 +1,5 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement } from 'lit';
3
-
4
3
  declare const EFImage_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
5
4
  export declare class EFImage extends EFImage_base {
6
5
  static styles: import('lit').CSSResult[];
@@ -1,9 +1,8 @@
1
1
  import { LitElement, PropertyValueMap } from 'lit';
2
2
  import { Task } from '@lit/task';
3
3
  import { TrackFragmentIndex, TrackSegment } from '../../../assets/src';
4
- import { MP4File } from '../../../assets/MP4File.js/src';
5
- import { VideoAsset } from '../../../assets/EncodedAsset.js/src';
6
-
4
+ import { MP4File } from '@editframe/assets/MP4File.js';
5
+ import { VideoAsset } from '@editframe/assets/EncodedAsset.js';
7
6
  import type * as MP4Box from "mp4box";
8
7
  export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
9
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;
@@ -29,6 +28,7 @@ export declare class EFMedia extends EFMedia_base {
29
28
  }[] | undefined], Record<string, {
30
29
  segment: TrackSegment;
31
30
  track: MP4Box.TrackInfo;
31
+ nextSegment?: TrackSegment;
32
32
  }> | undefined>;
33
33
  fetchSeekTask: Task<readonly [{
34
34
  trackId: string;
@@ -37,6 +37,7 @@ export declare class EFMedia extends EFMedia_base {
37
37
  }[] | undefined, Record<string, {
38
38
  segment: TrackSegment;
39
39
  track: MP4Box.TrackInfo;
40
+ nextSegment?: TrackSegment;
40
41
  }> | undefined, typeof fetch], Record<string, File> | undefined>;
41
42
  videoAssetTask: Task<readonly [Record<string, File> | undefined], VideoAsset | undefined>;
42
43
  desiredSeekTimeMs: number;
@@ -48,6 +49,7 @@ export declare class EFMedia extends EFMedia_base {
48
49
  audioBufferTask: Task<readonly [Record<string, File> | undefined, Record<string, {
49
50
  segment: TrackSegment;
50
51
  track: MP4Box.TrackInfo;
52
+ nextSegment?: TrackSegment;
51
53
  }> | undefined], {
52
54
  buffer: AudioBuffer;
53
55
  startOffsetMs: number;
@@ -1,5 +1,4 @@
1
1
  import { LitElement } from 'lit';
2
-
3
2
  export declare class EFSourceMixinInterface {
4
3
  productionSrc(): string;
5
4
  src: string;
@@ -1,17 +1,19 @@
1
1
  import { LitElement, ReactiveController } from 'lit';
2
2
  import { EFTimegroup } from './EFTimegroup.ts';
3
3
  import { Task } from '@lit/task';
4
-
5
4
  export declare const timegroupContext: {
6
5
  __context__: EFTimegroup;
7
6
  };
8
7
  export declare class TemporalMixinInterface {
9
8
  get hasOwnDuration(): boolean;
9
+ get trimStartMs(): number;
10
+ get trimEndMs(): number;
10
11
  get durationMs(): number;
11
12
  get startTimeMs(): number;
12
13
  get startTimeWithinParentMs(): number;
13
14
  get endTimeMs(): number;
14
15
  get ownCurrentTimeMs(): number;
16
+ get trimAdjustedOwnCurrentTimeMs(): number;
15
17
  set duration(value: string);
16
18
  get duration(): string;
17
19
  parentTimegroup?: EFTimegroup;
@@ -1,5 +1,4 @@
1
1
  import { LitElement } from 'lit';
2
-
3
2
  declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
4
3
  declare class TestTemporal extends TestTemporal_base {
5
4
  get hasOwnDuration(): boolean;
@@ -1,6 +1,5 @@
1
1
  import { LitElement, PropertyValueMap } from 'lit';
2
2
  import { Task } from '@lit/task';
3
-
4
3
  export declare const shallowGetTimegroups: (element: Element, groups?: EFTimegroup[]) => EFTimegroup[];
5
4
  declare const EFTimegroup_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
6
5
  export declare class EFTimegroup extends EFTimegroup_base {
@@ -8,19 +7,17 @@ export declare class EFTimegroup extends EFTimegroup_base {
8
7
  static styles: import('lit').CSSResult;
9
8
  _timeGroupContext: this;
10
9
  mode: "fixed" | "sequence" | "contain";
10
+ overlapMs: number;
11
11
  set currentTime(time: number);
12
12
  get currentTime(): number;
13
13
  get currentTimeMs(): number;
14
14
  set currentTimeMs(ms: number);
15
- crossoverMs: number;
16
15
  render(): import('lit-html').TemplateResult<1>;
17
16
  maybeLoadTimeFromLocalStorage(): number;
18
17
  connectedCallback(): void;
19
18
  get storageKey(): string;
20
- get crossoverStartMs(): number;
21
- get crossoverEndMs(): number;
22
19
  get durationMs(): number;
23
- waitForMediaDurations(): Promise<(Record<number, import('packages/assets/dist/Probe.js').TrackFragmentIndex> | undefined)[]>;
20
+ waitForMediaDurations(): Promise<(Record<number, import('packages/assets/src/Probe.ts').TrackFragmentIndex> | undefined)[]>;
24
21
  get childTemporals(): import('./EFTemporal.ts').TemporalMixinInterface[];
25
22
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
26
23
  shouldWrapWithWorkbench(): boolean;
@@ -1,6 +1,5 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { EFMedia } from './EFMedia.ts';
3
-
4
3
  declare const EFVideo_base: typeof EFMedia;
5
4
  export declare class EFVideo extends EFVideo_base {
6
5
  #private;
@@ -3,7 +3,6 @@ import { LitElement } from 'lit';
3
3
  import { EFVideo } from './EFVideo.ts';
4
4
  import { Task } from '@lit/task';
5
5
  import { Ref } from 'lit/directives/ref.js';
6
-
7
6
  declare const EFWaveform_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
8
7
  export declare class EFWaveform extends EFWaveform_base {
9
8
  static styles: never[];
@@ -1,5 +1,4 @@
1
1
  import { LitElement } from 'lit';
2
-
3
2
  export declare class FetchMixinInterface {
4
3
  fetch: typeof fetch;
5
4
  }
@@ -1,6 +1,5 @@
1
1
  import { ReactiveController, LitElement } from 'lit';
2
2
  import { EFTimegroup } from './EFTimegroup.ts';
3
-
4
3
  export declare class TimegroupController implements ReactiveController {
5
4
  private host;
6
5
  private child;
@@ -2,3 +2,11 @@ export declare const durationConverter: {
2
2
  fromAttribute: (value: string) => number;
3
3
  toAttribute: (value: number) => string;
4
4
  };
5
+ export declare const trimDurationConverter: {
6
+ fromAttribute: (value: string) => number;
7
+ toAttribute: (value: number) => string;
8
+ };
9
+ export declare const imageDurationConverter: {
10
+ fromAttribute: (value: string) => number;
11
+ toAttribute: (value: number) => string;
12
+ };
@@ -60,7 +60,7 @@ let EFCaptions = class extends EFSourceMixin(
60
60
  ) {
61
61
  constructor() {
62
62
  super(...arguments);
63
- this.target = null;
63
+ this.targetSelector = "";
64
64
  this.wordStyle = "";
65
65
  this.activeWordContainers = this.getElementsByTagName("ef-captions-active-word");
66
66
  this.md5SumLoader = new Task(this, {
@@ -88,6 +88,9 @@ let EFCaptions = class extends EFSourceMixin(
88
88
  }
89
89
  });
90
90
  }
91
+ set target(value) {
92
+ this.targetSelector = value;
93
+ }
91
94
  captionsPath() {
92
95
  const targetSrc = this.targetElement.src;
93
96
  if (targetSrc.startsWith("editframe://") || targetSrc.startsWith("http")) {
@@ -120,9 +123,9 @@ let EFCaptions = class extends EFSourceMixin(
120
123
  let startMs = 0;
121
124
  let endMs = 0;
122
125
  for (const segment of caption.segments) {
123
- if (this.targetElement.ownCurrentTimeMs >= segment.start * 1e3 && this.targetElement.ownCurrentTimeMs <= segment.end * 1e3) {
126
+ if (this.targetElement.trimAdjustedOwnCurrentTimeMs >= segment.start * 1e3 && this.targetElement.trimAdjustedOwnCurrentTimeMs <= segment.end * 1e3) {
124
127
  for (const word of segment.words) {
125
- if (this.targetElement.ownCurrentTimeMs >= word.start * 1e3 && this.targetElement.ownCurrentTimeMs <= word.end * 1e3) {
128
+ if (this.targetElement.trimAdjustedOwnCurrentTimeMs >= word.start * 1e3 && this.targetElement.trimAdjustedOwnCurrentTimeMs <= word.end * 1e3) {
126
129
  words.push(word.text);
127
130
  startMs = word.start * 1e3;
128
131
  endMs = word.end * 1e3;
@@ -137,11 +140,11 @@ let EFCaptions = class extends EFSourceMixin(
137
140
  }
138
141
  }
139
142
  get targetElement() {
140
- const target = document.getElementById(this.getAttribute("target") ?? "");
143
+ const target = document.getElementById(this.targetSelector ?? "");
141
144
  if (target instanceof EFAudio || target instanceof EFVideo) {
142
145
  return target;
143
146
  }
144
- throw new Error("Invalid target, must be an EFAudio or EFVideo element");
147
+ throw new Error("Invalid target, must be an EFAudio or EFVideo element");
145
148
  }
146
149
  };
147
150
  EFCaptions.styles = [
@@ -152,8 +155,8 @@ EFCaptions.styles = [
152
155
  `
153
156
  ];
154
157
  __decorateClass([
155
- property({ type: String, attribute: "target" })
156
- ], EFCaptions.prototype, "target", 2);
158
+ property({ type: String, attribute: "target", reflect: true })
159
+ ], EFCaptions.prototype, "targetSelector", 2);
157
160
  __decorateClass([
158
161
  property({ attribute: "word-style" })
159
162
  ], EFCaptions.prototype, "wordStyle", 2);
@@ -101,10 +101,13 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
101
101
  const segment = index.segments.toReversed().find((segment2) => {
102
102
  return segment2.dts / track.timescale * 1e3 <= seekToMs;
103
103
  });
104
+ const nextSegment = index.segments.find((segment2) => {
105
+ return segment2.dts / track.timescale * 1e3 > seekToMs;
106
+ });
104
107
  if (!segment) {
105
108
  return;
106
109
  }
107
- result[index.track] = { segment, track };
110
+ result[index.track] = { segment, track, nextSegment };
108
111
  }
109
112
  return result;
110
113
  }
@@ -121,13 +124,27 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
121
124
  return;
122
125
  }
123
126
  const files = {};
124
- for (const [trackId, { segment, track }] of Object.entries(seekResult)) {
127
+ for (const [trackId, { segment, track, nextSegment }] of Object.entries(
128
+ seekResult
129
+ )) {
125
130
  const start = segment.offset;
126
131
  const end = segment.offset + segment.size;
127
132
  const response = await fetch(this.fragmentTrackPath(trackId), {
128
133
  signal,
129
134
  headers: { Range: `bytes=${start}-${end}` }
130
135
  });
136
+ if (nextSegment) {
137
+ const nextStart = nextSegment.offset;
138
+ const nextEnd = nextSegment.offset + nextSegment.size;
139
+ fetch(this.fragmentTrackPath(trackId), {
140
+ signal,
141
+ headers: { Range: `bytes=${nextStart}-${nextEnd}` }
142
+ }).then(() => {
143
+ log("Prefetched next segment");
144
+ }).catch((error) => {
145
+ log("Failed to prefetch next segment", error);
146
+ });
147
+ }
131
148
  const initSegment = Object.values(initSegments).find(
132
149
  (initSegment2) => initSegment2.trackId === String(track.id)
133
150
  );
@@ -238,7 +255,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
238
255
  }
239
256
  updated(changedProperties) {
240
257
  if (changedProperties.has("ownCurrentTimeMs")) {
241
- this.executeSeek(this.ownCurrentTimeMs);
258
+ this.executeSeek(this.trimAdjustedOwnCurrentTimeMs);
242
259
  }
243
260
  }
244
261
  get hasOwnDuration() {
@@ -256,15 +273,15 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
256
273
  if (durations.length === 0) {
257
274
  return 0;
258
275
  }
259
- return Math.max(...durations);
276
+ return Math.max(...durations) - this.trimStartMs - this.trimEndMs;
260
277
  }
261
278
  get startTimeMs() {
262
279
  return getStartTimeMs(this);
263
280
  }
264
281
  #audioContext;
265
282
  async fetchAudioSpanningTime(fromMs, toMs) {
266
- fromMs -= this.startTimeMs;
267
- toMs -= this.startTimeMs;
283
+ fromMs -= this.startTimeMs - this.trimStartMs;
284
+ toMs -= this.startTimeMs - this.trimStartMs;
268
285
  await this.trackFragmentIndexLoader.taskComplete;
269
286
  const audioTrackId = this.defaultAudioTrackId;
270
287
  if (!audioTrackId) {
@@ -318,8 +335,8 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
318
335
  });
319
336
  return {
320
337
  blob: audioBlob,
321
- startMs: firstFragment.dts / audioTrackIndex.timescale * 1e3,
322
- endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3
338
+ startMs: firstFragment.dts / audioTrackIndex.timescale * 1e3 - this.trimStartMs,
339
+ endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3 - this.trimEndMs
323
340
  };
324
341
  }
325
342
  }
@@ -85,6 +85,9 @@ const EFTemporal = (superClass) => {
85
85
  constructor() {
86
86
  super(...arguments);
87
87
  this._offsetMs = 0;
88
+ this._trimStartMs = 0;
89
+ this._trimEndMs = 0;
90
+ this._startOffsetMs = 0;
88
91
  this.rootTimegroup = this.getRootTimegroup();
89
92
  this.frameTask = new Task(this, {
90
93
  autoRun: EF_INTERACTIVE,
@@ -112,6 +115,15 @@ const EFTemporal = (superClass) => {
112
115
  get parentTimegroup() {
113
116
  return this.#parentTimegroup;
114
117
  }
118
+ get trimStartMs() {
119
+ return this._trimStartMs;
120
+ }
121
+ get trimEndMs() {
122
+ return this._trimEndMs;
123
+ }
124
+ get startOffsetMs() {
125
+ return this._startOffsetMs;
126
+ }
115
127
  getRootTimegroup() {
116
128
  let parent = this.tagName === "EF-TIMEGROUP" ? this : this.parentTimegroup;
117
129
  while (parent?.parentTimegroup) {
@@ -169,9 +181,9 @@ const EFTemporal = (superClass) => {
169
181
  }
170
182
  startTimeMsCache.set(
171
183
  this,
172
- previous.startTimeMs + previous.durationMs
184
+ previous.startTimeMs + previous.durationMs - parentTimegroup.overlapMs
173
185
  );
174
- return previous.startTimeMs + previous.durationMs;
186
+ return previous.startTimeMs + previous.durationMs - parentTimegroup.overlapMs;
175
187
  }
176
188
  case "contain":
177
189
  case "fixed":
@@ -196,6 +208,22 @@ const EFTemporal = (superClass) => {
196
208
  }
197
209
  return 0;
198
210
  }
211
+ /**
212
+ * Used to calculate the internal currentTimeMs of the element. This is useful
213
+ * for mapping to internal media time codes for audio/video elements.
214
+ */
215
+ get trimAdjustedOwnCurrentTimeMs() {
216
+ if (this.rootTimegroup) {
217
+ return Math.min(
218
+ Math.max(
219
+ 0,
220
+ this.rootTimegroup.currentTimeMs - this.startTimeMs + this.trimStartMs
221
+ ),
222
+ this.durationMs + Math.abs(this.startOffsetMs) + this.trimStartMs
223
+ );
224
+ }
225
+ return 0;
226
+ }
199
227
  }
200
228
  __decorateClass([
201
229
  consume({ context: timegroupContext, subscribe: true }),
@@ -215,6 +243,27 @@ const EFTemporal = (superClass) => {
215
243
  converter: durationConverter
216
244
  })
217
245
  ], TemporalMixinClass.prototype, "_durationMs", 2);
246
+ __decorateClass([
247
+ property({
248
+ type: Number,
249
+ attribute: "trimstart",
250
+ converter: durationConverter
251
+ })
252
+ ], TemporalMixinClass.prototype, "_trimStartMs", 2);
253
+ __decorateClass([
254
+ property({
255
+ type: Number,
256
+ attribute: "trimend",
257
+ converter: durationConverter
258
+ })
259
+ ], TemporalMixinClass.prototype, "_trimEndMs", 2);
260
+ __decorateClass([
261
+ property({
262
+ type: Number,
263
+ attribute: "startoffset",
264
+ converter: durationConverter
265
+ })
266
+ ], TemporalMixinClass.prototype, "_startOffsetMs", 2);
218
267
  __decorateClass([
219
268
  state()
220
269
  ], TemporalMixinClass.prototype, "rootTimegroup", 2);
@@ -7,6 +7,7 @@ import { EFTemporal, shallowGetTemporalElements, isEFTemporal, timegroupContext
7
7
  import { TimegroupController } from "./TimegroupController.js";
8
8
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
9
9
  import { deepGetMediaElements } from "./EFMedia.js";
10
+ import { durationConverter } from "./durationConverter.js";
10
11
  var __defProp = Object.defineProperty;
11
12
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
13
  var __typeError = (msg) => {
@@ -44,7 +45,7 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
44
45
  this._timeGroupContext = this;
45
46
  __privateAdd(this, _currentTime, 0);
46
47
  this.mode = "sequence";
47
- this.crossoverMs = 0;
48
+ this.overlapMs = 0;
48
49
  this.frameTask = new Task(this, {
49
50
  autoRun: EF_INTERACTIVE,
50
51
  args: () => [this.ownCurrentTimeMs, this.currentTimeMs],
@@ -110,29 +111,18 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
110
111
  }
111
112
  return `ef-timegroup-${this.id}`;
112
113
  }
113
- get crossoverStartMs() {
114
- const parentTimeGroup = this.parentTimegroup;
115
- if (!parentTimeGroup || !this.previousElementSibling) {
116
- return 0;
117
- }
118
- return parentTimeGroup.crossoverMs;
119
- }
120
- get crossoverEndMs() {
121
- const parentTimeGroup = this.parentTimegroup;
122
- if (!parentTimeGroup || !this.nextElementSibling) {
123
- return 0;
124
- }
125
- return parentTimeGroup.crossoverMs;
126
- }
127
114
  get durationMs() {
128
115
  switch (this.mode) {
129
116
  case "fixed":
130
117
  return super.durationMs;
131
118
  case "sequence": {
132
119
  let duration = 0;
133
- for (const node of this.childTemporals) {
120
+ this.childTemporals.forEach((node, index) => {
121
+ if (index > 0) {
122
+ duration -= this.overlapMs;
123
+ }
134
124
  duration += node.durationMs;
135
- }
125
+ });
136
126
  return duration;
137
127
  }
138
128
  case "contain": {
@@ -168,9 +158,14 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
168
158
  }
169
159
  this.style.display = "";
170
160
  const animations = this.getAnimations({ subtree: true });
161
+ this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
162
+ this.style.setProperty(
163
+ "--ef-transition--duration",
164
+ `${this.parentTimegroup?.overlapMs ?? 0}ms`
165
+ );
171
166
  this.style.setProperty(
172
- "--ef-duration",
173
- `${this.durationMs + this.crossoverEndMs + this.crossoverStartMs}ms`
167
+ "--ef-transition-out-start",
168
+ `${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`
174
169
  );
175
170
  for (const animation of animations) {
176
171
  if (animation.playState === "running") {
@@ -311,7 +306,7 @@ EFTimegroup.styles = css`
311
306
  display: block;
312
307
  width: 100%;
313
308
  height: 100%;
314
- position: relative;
309
+ position: absolute;
315
310
  top: 0;
316
311
  }
317
312
  `;
@@ -324,28 +319,16 @@ __decorateClass([
324
319
  attribute: "mode"
325
320
  })
326
321
  ], EFTimegroup.prototype, "mode", 2);
327
- __decorateClass([
328
- property({ type: Number })
329
- ], EFTimegroup.prototype, "currentTime", 1);
330
322
  __decorateClass([
331
323
  property({
332
- attribute: "crossover",
333
- converter: {
334
- fromAttribute: (value) => {
335
- if (value.endsWith("ms")) {
336
- return Number.parseFloat(value);
337
- }
338
- if (value.endsWith("s")) {
339
- return Number.parseFloat(value) * 1e3;
340
- }
341
- throw new Error(
342
- "`crossover` MUST be in milliseconds or seconds (10s, 10000ms)"
343
- );
344
- },
345
- toAttribute: (value) => `${value}ms`
346
- }
324
+ type: Number,
325
+ converter: durationConverter,
326
+ attribute: "overlap"
347
327
  })
348
- ], EFTimegroup.prototype, "crossoverMs", 2);
328
+ ], EFTimegroup.prototype, "overlapMs", 2);
329
+ __decorateClass([
330
+ property({ type: Number })
331
+ ], EFTimegroup.prototype, "currentTime", 1);
349
332
  EFTimegroup = __decorateClass([
350
333
  customElement("ef-timegroup")
351
334
  ], EFTimegroup);
@@ -148,7 +148,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
148
148
  if (!this.targetElement.audioBufferTask.value) {
149
149
  return;
150
150
  }
151
- if (this.targetElement.ownCurrentTimeMs > 0) {
151
+ if (this.targetElement.trimAdjustedOwnCurrentTimeMs > 0) {
152
152
  const audioContext = new OfflineAudioContext(2, 48e3 / 25, 48e3);
153
153
  const audioBufferSource = audioContext.createBufferSource();
154
154
  audioBufferSource.buffer = this.targetElement.audioBufferTask.value.buffer;
@@ -159,7 +159,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
159
159
  0,
160
160
  Math.max(
161
161
  0,
162
- (this.targetElement.ownCurrentTimeMs - this.targetElement.audioBufferTask.value.startOffsetMs) / 1e3
162
+ (this.targetElement.trimAdjustedOwnCurrentTimeMs - this.targetElement.audioBufferTask.value.startOffsetMs) / 1e3
163
163
  ),
164
164
  48e3 / 1e3
165
165
  );
@@ -202,7 +202,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
202
202
  if (target instanceof EFAudio || target instanceof EFVideo) {
203
203
  return target;
204
204
  }
205
- throw new Error("Invalid target, must be an EFAudio element");
205
+ throw new Error("Invalid target, must be an EFAudio or EFVideo element");
206
206
  }
207
207
  };
208
208
  EFWaveform.styles = [];
@@ -1,4 +1,5 @@
1
1
  const parseTimeToMs = (time) => {
2
+ console.log("parseTimeToMs", time);
2
3
  if (time.endsWith("ms")) {
3
4
  return Number.parseFloat(time);
4
5
  }