@editframe/elements 0.15.0-beta.18 → 0.15.0-beta.19

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.
@@ -18,6 +18,8 @@ export declare class TemporalMixinInterface {
18
18
  */
19
19
  get hasExplicitDuration(): boolean;
20
20
 
21
+ get sourceStartMs(): number;
22
+
21
23
  /**
22
24
  * Used to trim the start of the media.
23
25
  *
@@ -27,7 +29,7 @@ export declare class TemporalMixinInterface {
27
29
  *
28
30
  * @domAttribute "trimstart"
29
31
  */
30
- get trimStartMs(): number;
32
+ get trimStartMs(): number | undefined;
31
33
 
32
34
  /**
33
35
  * Used to trim the end of the media.
@@ -40,10 +42,10 @@ export declare class TemporalMixinInterface {
40
42
  */
41
43
  get trimEndMs(): number;
42
44
 
43
- set trimStartMs(value: number);
44
- set trimEndMs(value: number);
45
- set trimstart(value: string);
46
- set trimend(value: string);
45
+ set trimStartMs(value: number | undefined);
46
+ set trimEndMs(value: number | undefined);
47
+ set trimstart(value: string | undefined);
48
+ set trimend(value: string | undefined);
47
49
 
48
50
  /**
49
51
  * The source in time of the element.
@@ -64,7 +66,7 @@ export declare class TemporalMixinInterface {
64
66
  *
65
67
  * @domAttribute "sourcein"
66
68
  */
67
- get sourceInMs(): number;
69
+ get sourceInMs(): number | undefined;
68
70
 
69
71
  /**
70
72
  * The source out time of the element.
@@ -87,18 +89,22 @@ export declare class TemporalMixinInterface {
87
89
  *
88
90
  * @domAttribute "sourceout"
89
91
  */
90
- get sourceOutMs(): number;
92
+ get sourceOutMs(): number | undefined;
91
93
 
92
- set sourceInMs(value: number);
93
- set sourceOutMs(value: number);
94
- set sourcein(value: string);
95
- set sourceout(value: string);
94
+ set sourceInMs(value: number | undefined);
95
+ set sourceOutMs(value: number | undefined);
96
+ set sourcein(value: string | undefined);
97
+ set sourceout(value: string | undefined);
96
98
 
97
99
  /**
98
100
  * @domAttribute "duration"
99
101
  */
100
102
  get durationMs(): number;
101
103
 
104
+ get explicitDurationMs(): number | undefined;
105
+
106
+ get intrinsicDurationMs(): number | undefined;
107
+
102
108
  /**
103
109
  * The start time of the element within its root timegroup in milliseconds.
104
110
  *
@@ -338,109 +344,85 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
338
344
  }
339
345
  }
340
346
 
341
- private _trimStartMs = 0;
342
347
  @property({
343
348
  type: Number,
344
349
  attribute: "trimstart",
345
350
  converter: durationConverter,
346
351
  })
347
- public get trimStartMs(): number {
348
- return this._trimStartMs;
349
- }
350
- public set trimStartMs(value: number) {
351
- if (this._trimStartMs === value) {
352
- return;
352
+ _trimStartMs: number | undefined = undefined;
353
+
354
+ get trimStartMs() {
355
+ if (this._trimStartMs === undefined) {
356
+ return undefined;
353
357
  }
354
- this._trimStartMs = value;
355
- this.setAttribute(
356
- "trimstart",
357
- durationConverter.toAttribute(value / 1000),
358
+ return Math.min(
359
+ Math.max(this._trimStartMs, 0),
360
+ this.intrinsicDurationMs ?? 0,
358
361
  );
359
362
  }
360
- set trimstart(value: string | undefined) {
361
- if (value !== undefined) {
362
- this.setAttribute("trimstart", value);
363
- } else {
364
- this.removeAttribute("trimstart");
365
- }
363
+
364
+ set trimStartMs(value: number | undefined) {
365
+ this._trimStartMs = value;
366
366
  }
367
367
 
368
- private _trimEndMs = 0;
369
368
  @property({
370
369
  type: Number,
371
370
  attribute: "trimend",
372
371
  converter: durationConverter,
373
372
  })
374
- public get trimEndMs(): number {
375
- return this._trimEndMs;
376
- }
377
- public set trimEndMs(value: number) {
378
- if (this._trimEndMs === value) {
379
- return;
373
+ _trimEndMs: number | undefined = undefined;
374
+
375
+ get trimEndMs() {
376
+ if (this._trimEndMs === undefined) {
377
+ return undefined;
380
378
  }
381
- this._trimEndMs = value;
382
- this.setAttribute("trimend", durationConverter.toAttribute(value / 1000));
379
+ return Math.min(this._trimEndMs, this.intrinsicDurationMs ?? 0);
383
380
  }
384
- set trimend(value: string | undefined) {
385
- if (value !== undefined) {
386
- this.setAttribute("trimend", value);
387
- } else {
388
- this.removeAttribute("trimend");
389
- }
381
+
382
+ set trimEndMs(value: number | undefined) {
383
+ this._trimEndMs = value;
390
384
  }
391
385
 
392
- private _sourceInMs: number | undefined;
393
386
  @property({
394
387
  type: Number,
395
388
  attribute: "sourcein",
396
389
  converter: durationConverter,
397
- reflect: true,
398
390
  })
399
- get sourceInMs(): number | undefined {
400
- return this._sourceInMs;
391
+ _sourceInMs: number | undefined = undefined;
392
+
393
+ get sourceInMs() {
394
+ if (this._sourceInMs === undefined) {
395
+ return undefined;
396
+ }
397
+ return Math.max(this._sourceInMs, 0);
401
398
  }
399
+
402
400
  set sourceInMs(value: number | undefined) {
403
401
  this._sourceInMs = value;
404
- value !== undefined
405
- ? this.setAttribute(
406
- "sourcein",
407
- durationConverter.toAttribute(value / 1000),
408
- )
409
- : this.removeAttribute("sourcein");
410
- }
411
- set sourcein(value: string | undefined) {
412
- if (value !== undefined) {
413
- this.setAttribute("sourcein", value);
414
- } else {
415
- this.removeAttribute("sourcein");
416
- }
417
402
  }
418
403
 
419
- private _sourceOutMs: number | undefined;
420
404
  @property({
421
405
  type: Number,
422
406
  attribute: "sourceout",
423
407
  converter: durationConverter,
424
- reflect: true,
425
408
  })
426
- get sourceOutMs(): number | undefined {
427
- return this._sourceOutMs;
409
+ _sourceOutMs: number | undefined = undefined;
410
+
411
+ get sourceOutMs() {
412
+ if (this._sourceOutMs === undefined) {
413
+ return undefined;
414
+ }
415
+ if (
416
+ this.intrinsicDurationMs &&
417
+ this._sourceOutMs > this.intrinsicDurationMs
418
+ ) {
419
+ return this.intrinsicDurationMs;
420
+ }
421
+ return Math.max(this._sourceOutMs, 0);
428
422
  }
423
+
429
424
  set sourceOutMs(value: number | undefined) {
430
425
  this._sourceOutMs = value;
431
- value !== undefined
432
- ? this.setAttribute(
433
- "sourceout",
434
- durationConverter.toAttribute(value / 1000),
435
- )
436
- : this.removeAttribute("sourceout");
437
- }
438
- set sourceout(value: string | undefined) {
439
- if (value !== undefined) {
440
- this.setAttribute("sourceout", value);
441
- } else {
442
- this.removeAttribute("sourceout");
443
- }
444
426
  }
445
427
 
446
428
  @property({
@@ -469,28 +451,51 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
469
451
  return this._durationMs !== undefined;
470
452
  }
471
453
 
454
+ get explicitDurationMs() {
455
+ if (this.hasExplicitDuration) {
456
+ return this._durationMs;
457
+ }
458
+ return undefined;
459
+ }
460
+
472
461
  get hasOwnDuration() {
473
462
  return false;
474
463
  }
475
464
 
476
- // Defining this as a getter to a private property allows us to
477
- // override it classes that include this mixin.
465
+ get intrinsicDurationMs() {
466
+ return undefined;
467
+ }
468
+
478
469
  get durationMs() {
479
- if (this.sourceInMs) {
480
- return (
481
- this._durationMs ||
482
- this.parentTimegroup?.durationMs ||
483
- 0 - this.sourceInMs
484
- );
470
+ if (this.intrinsicDurationMs === undefined) {
471
+ return this._durationMs || this.parentTimegroup?.durationMs || 0;
485
472
  }
486
- if (this.sourceOutMs) {
487
- return (
488
- this._durationMs ||
489
- this.parentTimegroup?.durationMs ||
490
- 0 - this.sourceOutMs
491
- );
473
+
474
+ if (this.trimStartMs || this.trimEndMs) {
475
+ const trimmedDurationMs =
476
+ this.intrinsicDurationMs -
477
+ (this.trimStartMs ?? 0) -
478
+ (this.trimEndMs ?? 0);
479
+ if (trimmedDurationMs < 0) {
480
+ return 0;
481
+ }
482
+ return trimmedDurationMs;
483
+ }
484
+
485
+ if (this.sourceInMs || this.sourceOutMs) {
486
+ const sourceInMs = this.sourceInMs ?? 0;
487
+ const sourceOutMs = this.sourceOutMs ?? this.intrinsicDurationMs;
488
+ if (sourceInMs >= sourceOutMs) {
489
+ return 0;
490
+ }
491
+ return sourceOutMs - sourceInMs;
492
492
  }
493
- return this._durationMs || this.parentTimegroup?.durationMs || 0;
493
+
494
+ return this.intrinsicDurationMs;
495
+ }
496
+
497
+ get sourceStartMs() {
498
+ return this.trimStartMs ?? this.sourceInMs ?? 0;
494
499
  }
495
500
 
496
501
  get offsetMs() {
@@ -586,33 +591,8 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
586
591
  * for mapping to internal media time codes for audio/video elements.
587
592
  */
588
593
  get currentSourceTimeMs() {
589
- if (this.rootTimegroup) {
590
- if (this.sourceInMs && this.sourceOutMs) {
591
- return Math.min(
592
- Math.max(
593
- 0,
594
- this.rootTimegroup.currentTimeMs -
595
- this.startTimeMs +
596
- this.trimStartMs +
597
- this.sourceInMs,
598
- ),
599
- this.durationMs +
600
- Math.abs(this.startOffsetMs) +
601
- this.trimStartMs +
602
- this.sourceInMs,
603
- );
604
- }
605
- return Math.min(
606
- Math.max(
607
- 0,
608
- this.rootTimegroup.currentTimeMs -
609
- this.startTimeMs +
610
- this.trimStartMs,
611
- ),
612
- this.durationMs + Math.abs(this.startOffsetMs) + this.trimStartMs,
613
- );
614
- }
615
- return 0;
594
+ const leadingTrimMs = this.sourceInMs || this.trimStartMs || 0;
595
+ return this.ownCurrentTimeMs + leadingTrimMs;
616
596
  }
617
597
 
618
598
  frameTask = new Task(this, {
@@ -9,12 +9,12 @@ import { isContextMixin } from "../gui/ContextMixin.js";
9
9
  import { deepGetMediaElements } from "./EFMedia.js";
10
10
  import {
11
11
  EFTemporal,
12
- isEFTemporal,
13
12
  shallowGetTemporalElements,
14
13
  timegroupContext,
15
14
  } from "./EFTemporal.js";
16
15
  import { TimegroupController } from "./TimegroupController.js";
17
16
  import { durationConverter } from "./durationConverter.js";
17
+ import { updateAnimations } from "./updateAnimations.ts";
18
18
 
19
19
  const log = debug("ef:elements:EFTimegroup");
20
20
 
@@ -40,7 +40,8 @@ export class EFTimegroup extends EFTemporal(LitElement) {
40
40
  width: 100%;
41
41
  height: 100%;
42
42
  position: absolute;
43
- transform-origin: center center;
43
+ top: 0;
44
+ left: 0;
44
45
  }
45
46
  `;
46
47
 
@@ -121,14 +122,6 @@ export class EFTimegroup extends EFTemporal(LitElement) {
121
122
  this.wrapWithWorkbench();
122
123
  }
123
124
 
124
- // // Create resize observer to handle scaling
125
- // this.#resizeObserver = new ResizeObserver(() => this.updateScale());
126
- // if (this.parentElement) {
127
- // this.#resizeObserver.observe(this.parentElement);
128
- // }
129
-
130
- // Initialize animations when component is first connected
131
- // Regrettably, this doesn't work without the requestAnimationFrame
132
125
  requestAnimationFrame(() => {
133
126
  this.updateAnimations();
134
127
  });
@@ -139,53 +132,6 @@ export class EFTimegroup extends EFTemporal(LitElement) {
139
132
  this.#resizeObserver?.disconnect();
140
133
  }
141
134
 
142
- // private get displayedParent(): Element | null {
143
- // let displayedParent = this.parentElement;
144
- // while (
145
- // displayedParent &&
146
- // getComputedStyle(displayedParent).display === "contents"
147
- // ) {
148
- // displayedParent = displayedParent.parentElement;
149
- // }
150
- // return displayedParent;
151
- // }
152
-
153
- // private updateScale() {
154
- // if (this.fit === "none") return;
155
-
156
- // const displayedParent = this.displayedParent;
157
- // if (!displayedParent) return;
158
-
159
- // // Get the natural size of the content
160
- // const contentWidth = this.clientWidth;
161
- // const contentHeight = this.clientHeight;
162
-
163
- // // Get the available space from displayed parent
164
- // const containerWidth = displayedParent.clientWidth;
165
- // const containerHeight = displayedParent.clientHeight;
166
-
167
- // // Calculate scale ratios
168
- // const widthRatio = containerWidth / contentWidth;
169
- // const heightRatio = containerHeight / contentHeight;
170
-
171
- // let scale: number;
172
- // if (this.fit === "contain") {
173
- // // Use height ratio for contain mode to ensure it fits vertically
174
- // scale = heightRatio;
175
-
176
- // // If width would overflow after scaling, use width ratio instead
177
- // if (contentWidth * scale > containerWidth) {
178
- // scale = widthRatio;
179
- // }
180
- // } else {
181
- // // cover
182
- // scale = Math.max(widthRatio, heightRatio);
183
- // }
184
-
185
- // // Apply transform with fixed center origin
186
- // this.style.transform = `scale(${scale})`;
187
- // }
188
-
189
135
  get storageKey() {
190
136
  if (!this.id) {
191
137
  throw new Error("Timegroup must have an id to use localStorage.");
@@ -193,6 +139,13 @@ export class EFTimegroup extends EFTemporal(LitElement) {
193
139
  return `ef-timegroup-${this.id}`;
194
140
  }
195
141
 
142
+ get intrinsicDurationMs() {
143
+ if (this.hasExplicitDuration) {
144
+ return this.explicitDurationMs;
145
+ }
146
+ return undefined;
147
+ }
148
+
196
149
  get durationMs() {
197
150
  switch (this.mode) {
198
151
  case "fixed":
@@ -210,7 +163,7 @@ export class EFTimegroup extends EFTemporal(LitElement) {
210
163
  case "contain": {
211
164
  let maxDuration = 0;
212
165
  for (const node of this.childTemporals) {
213
- if (node.hasOwnDuration) {
166
+ if (node.intrinsicDurationMs !== undefined) {
214
167
  maxDuration = Math.max(maxDuration, node.durationMs);
215
168
  }
216
169
  }
@@ -251,75 +204,7 @@ export class EFTimegroup extends EFTemporal(LitElement) {
251
204
  }
252
205
 
253
206
  private updateAnimations() {
254
- this.style.setProperty(
255
- "--ef-progress",
256
- `${Math.max(0, Math.min(1, this.currentTimeMs / this.durationMs)) * 100}%`,
257
- );
258
- const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
259
- if (this.startTimeMs > timelineTimeMs || this.endTimeMs < timelineTimeMs) {
260
- this.style.display = "none";
261
- return;
262
- }
263
- this.style.display = "";
264
- const animations = this.getAnimations({ subtree: true });
265
- this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
266
- this.style.setProperty(
267
- "--ef-transition-duration",
268
- `${this.parentTimegroup?.overlapMs ?? 0}ms`,
269
- );
270
- this.style.setProperty(
271
- "--ef-transition-out-start",
272
- `${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`,
273
- );
274
-
275
- for (const animation of animations) {
276
- if (animation.playState === "running") {
277
- animation.pause();
278
- }
279
- const effect = animation.effect;
280
- if (!(effect && effect instanceof KeyframeEffect)) {
281
- return;
282
- }
283
- const target = effect.target;
284
- // TODO: better generalize work avoidance for temporal elements
285
- if (!target) {
286
- return;
287
- }
288
- if (target.closest("ef-timegroup") !== this) {
289
- return;
290
- }
291
-
292
- // Important to avoid going to the end of the animation
293
- // or it will reset awkwardly.
294
- if (isEFTemporal(target)) {
295
- const timing = effect.getTiming();
296
- const duration = Number(timing.duration) ?? 0;
297
- const delay = Number(timing.delay);
298
- const newTime = Math.floor(
299
- Math.min(target.ownCurrentTimeMs, duration - 1 + delay),
300
- );
301
- if (Number.isNaN(newTime)) {
302
- return;
303
- }
304
- animation.currentTime = newTime;
305
- } else if (target) {
306
- const nearestTimegroup = target.closest("ef-timegroup");
307
- if (!nearestTimegroup) {
308
- return;
309
- }
310
- const timing = effect.getTiming();
311
- const duration = Number(timing.duration) ?? 0;
312
- const delay = Number(timing.delay);
313
- const newTime = Math.floor(
314
- Math.min(nearestTimegroup.ownCurrentTimeMs, duration - 1 + delay),
315
- );
316
-
317
- if (Number.isNaN(newTime)) {
318
- return;
319
- }
320
- animation.currentTime = newTime;
321
- }
322
- }
207
+ updateAnimations(this);
323
208
  }
324
209
 
325
210
  get contextProvider() {
@@ -367,10 +252,6 @@ export class EFTimegroup extends EFTemporal(LitElement) {
367
252
  workbench.append(filmstrip);
368
253
  }
369
254
 
370
- get hasOwnDuration() {
371
- return true;
372
- }
373
-
374
255
  get efElements() {
375
256
  return Array.from(
376
257
  this.querySelectorAll(
@@ -20,7 +20,9 @@ export class EFVideo extends TWMixin(EFMedia) {
20
20
  ];
21
21
  canvasRef = createRef<HTMLCanvasElement>();
22
22
  render() {
23
- return html` <canvas ${ref(this.canvasRef)}></canvas>`;
23
+ return html`
24
+ <canvas ${ref(this.canvasRef)}></canvas>
25
+ `;
24
26
  }
25
27
 
26
28
  get canvasElement() {
@@ -1,19 +1,24 @@
1
1
  import { parseTimeToMs } from "./parseTimeToMs.js";
2
2
 
3
3
  export const durationConverter = {
4
- fromAttribute: (value: string): number => parseTimeToMs(value),
5
- toAttribute: (value: number) => `${value}s`,
4
+ fromAttribute: (value: string | null) =>
5
+ value === null ? null : parseTimeToMs(value),
6
+ toAttribute: (value: number | null) => (value === null ? null : `${value}s`),
6
7
  };
7
8
 
8
9
  const positiveDurationConverter = (error: string) => {
9
10
  return {
10
- fromAttribute: (value: string): number => {
11
+ fromAttribute: (value: string | null): number | null => {
12
+ if (value === null) {
13
+ return null;
14
+ }
11
15
  if (value.startsWith("-")) {
12
16
  throw new Error(error);
13
17
  }
14
18
  return parseTimeToMs(value);
15
19
  },
16
- toAttribute: (value: number) => `${value}s`,
20
+ toAttribute: (value: number | null) =>
21
+ value === null ? null : `${value}s`,
17
22
  };
18
23
  };
19
24
 
@@ -0,0 +1,88 @@
1
+ import { isEFTemporal } from "./EFTemporal.ts";
2
+ import type { EFTimegroup } from "./EFTimegroup.ts";
3
+
4
+ export const updateAnimations = (
5
+ element: HTMLElement & {
6
+ currentTimeMs: number;
7
+ durationMs: number;
8
+ rootTimegroup?: EFTimegroup;
9
+ parentTimegroup?: EFTimegroup;
10
+ startTimeMs: number;
11
+ endTimeMs: number;
12
+ },
13
+ ) => {
14
+ element.style.setProperty(
15
+ "--ef-progress",
16
+ `${Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs)) * 100}%`,
17
+ );
18
+ const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
19
+ if (
20
+ element.startTimeMs > timelineTimeMs ||
21
+ element.endTimeMs < timelineTimeMs
22
+ ) {
23
+ element.style.display = "none";
24
+ return;
25
+ }
26
+ element.style.display = "";
27
+ const animations = element.getAnimations({ subtree: true });
28
+ element.style.setProperty("--ef-duration", `${element.durationMs}ms`);
29
+ element.style.setProperty(
30
+ "--ef-transition-duration",
31
+ `${element.parentTimegroup?.overlapMs ?? 0}ms`,
32
+ );
33
+ element.style.setProperty(
34
+ "--ef-transition-out-start",
35
+ `${element.durationMs - (element.parentTimegroup?.overlapMs ?? 0)}ms`,
36
+ );
37
+
38
+ for (const animation of animations) {
39
+ if (animation.playState === "running") {
40
+ animation.pause();
41
+ }
42
+ const effect = animation.effect;
43
+ if (!(effect && effect instanceof KeyframeEffect)) {
44
+ continue;
45
+ }
46
+ const target = effect.target;
47
+ // TODO: better generalize work avoidance for temporal elements
48
+ if (!target) {
49
+ continue;
50
+ }
51
+ if (target.closest("ef-timegroup") !== element) {
52
+ continue;
53
+ }
54
+
55
+ const timing = effect.getTiming();
56
+ const duration = Number(timing.duration) ?? 0;
57
+ const delay = Number(timing.delay) ?? 0;
58
+ const iterations = Number(timing.iterations) ?? 1;
59
+
60
+ const timeTarget = isEFTemporal(target)
61
+ ? target
62
+ : target.closest("ef-timegroup");
63
+ if (!timeTarget) {
64
+ continue;
65
+ }
66
+
67
+ const currentTime = timeTarget.ownCurrentTimeMs;
68
+
69
+ // Handle delay - don't start animation until delay is complete
70
+ if (currentTime < delay) {
71
+ animation.currentTime = 0;
72
+ continue;
73
+ }
74
+
75
+ const currentIteration = Math.floor((currentTime - delay) / duration);
76
+ const currentIterationTime = (currentTime - delay) % duration;
77
+
78
+ if (currentIteration >= iterations) {
79
+ // Stop just before the end to prevent DOM removal
80
+ animation.currentTime = duration - 0.01;
81
+ continue;
82
+ }
83
+
84
+ // Ensure we never reach exactly duration
85
+ animation.currentTime =
86
+ Math.min(currentIterationTime, duration - 0.01) + delay;
87
+ }
88
+ };
@@ -87,31 +87,22 @@ class FilmstripItem extends TWMixin(LitElement) {
87
87
  @property({ type: Number })
88
88
  pixelsPerMs = 0.04;
89
89
 
90
+ // Gutter styles represent the entire source media.
91
+ // If there is no trim, then the gutter and trim portion are the same.
90
92
  get gutterStyles() {
91
- if (this.element.sourceInMs || this.element.sourceOutMs) {
92
- return {
93
- position: "relative",
94
- left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs - this.element.sourceInMs)}px`,
95
- width: `${this.pixelsPerMs * (this.element.durationMs + this.element.trimStartMs + this.element.trimEndMs + this.element.sourceOutMs + this.element.sourceInMs)}px`,
96
- };
97
- }
98
93
  return {
99
94
  position: "relative",
100
- left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs)}px`,
101
- width: `${this.pixelsPerMs * (this.element.durationMs + this.element.trimStartMs + this.element.trimEndMs)}px`,
95
+ left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.sourceStartMs)}px`,
96
+ width: `${this.pixelsPerMs * (this.element.intrinsicDurationMs ?? this.element.durationMs)}px`,
102
97
  };
103
98
  }
104
99
 
100
+ // Trim portion is the section of source that will be placed in the timeline
101
+ // If there is no trim, then the gutter and trim portion are the same.
105
102
  get trimPortionStyles() {
106
- if (this.element.sourceInMs || this.element.sourceOutMs) {
107
- return {
108
- width: `${this.pixelsPerMs * this.element.durationMs}px`,
109
- left: `${this.pixelsPerMs * (this.element.trimStartMs + this.element.sourceInMs)}px`,
110
- };
111
- }
112
103
  return {
113
104
  width: `${this.pixelsPerMs * this.element.durationMs}px`,
114
- left: `${this.pixelsPerMs * this.element.trimStartMs}px`,
105
+ left: `${this.pixelsPerMs * this.element.sourceStartMs}px`,
115
106
  };
116
107
  }
117
108