@editframe/elements 0.7.0-beta.8 → 0.8.0-beta.1

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 (121) hide show
  1. package/dist/EF_INTERACTIVE.d.ts +1 -0
  2. package/dist/{lib/av → assets/dist}/EncodedAsset.js +1 -1
  3. package/dist/{packages/elements/src/elements → elements}/EFAudio.d.ts +2 -2
  4. package/dist/{packages/elements/src/elements → elements}/EFCaptions.d.ts +5 -5
  5. package/dist/{packages/elements/src/elements → elements}/EFImage.d.ts +3 -3
  6. package/dist/{packages/elements/src/elements → elements}/EFMedia.d.ts +4 -4
  7. package/dist/{packages/elements/src/elements → elements}/EFTemporal.d.ts +1 -1
  8. package/dist/{packages/elements/src/elements → elements}/EFTimegroup.browsertest.d.ts +1 -1
  9. package/dist/{packages/elements/src/elements → elements}/EFTimegroup.d.ts +3 -3
  10. package/dist/{packages/elements/src/elements → elements}/EFVideo.d.ts +3 -3
  11. package/dist/{packages/elements/src/elements → elements}/EFWaveform.d.ts +3 -3
  12. package/dist/{packages/elements/src/elements → elements}/TimegroupController.d.ts +1 -1
  13. package/dist/{packages/elements → elements}/src/EF_FRAMEGEN.js +4 -3
  14. package/dist/elements/src/EF_INTERACTIVE.js +7 -0
  15. package/dist/{packages/elements → elements}/src/elements/EFCaptions.js +5 -5
  16. package/dist/{packages/elements → elements}/src/elements/EFMedia.js +6 -3
  17. package/dist/{packages/elements → elements}/src/elements/EFSourceMixin.js +1 -1
  18. package/dist/{packages/elements → elements}/src/elements/EFTemporal.js +37 -2
  19. package/dist/{packages/elements → elements}/src/elements/EFTimegroup.js +4 -2
  20. package/dist/{packages/elements → elements}/src/elements/FetchMixin.js +1 -1
  21. package/dist/elements/src/gui/ContextMixin.js +234 -0
  22. package/dist/{packages/elements → elements}/src/gui/EFFilmstrip.js +30 -134
  23. package/dist/elements/src/gui/EFPreview.js +45 -0
  24. package/dist/{packages/elements → elements}/src/gui/EFWorkbench.js +6 -93
  25. package/dist/{packages/elements → elements}/src/gui/TWMixin.js +10 -2
  26. package/dist/elements/src/gui/apiHostContext.js +5 -0
  27. package/dist/elements/src/gui/fetchContext.js +5 -0
  28. package/dist/elements/src/gui/focusContext.js +5 -0
  29. package/dist/elements/src/gui/focusedElementContext.js +7 -0
  30. package/dist/elements/src/gui/playingContext.js +5 -0
  31. package/dist/{packages/elements → elements}/src/index.js +5 -1
  32. package/dist/{packages/elements/src/elements → elements}/util.d.ts +1 -1
  33. package/dist/gui/ContextMixin.d.ts +23 -0
  34. package/dist/{packages/elements/src/gui → gui}/EFFilmstrip.d.ts +12 -15
  35. package/dist/gui/EFPreview.d.ts +27 -0
  36. package/dist/gui/EFWorkbench.d.ts +34 -0
  37. package/dist/gui/apiHostContext.d.ts +3 -0
  38. package/dist/gui/fetchContext.d.ts +3 -0
  39. package/dist/gui/focusContext.d.ts +6 -0
  40. package/dist/gui/focusedElementContext.d.ts +3 -0
  41. package/dist/gui/playingContext.d.ts +3 -0
  42. package/dist/index.d.ts +11 -0
  43. package/dist/msToTimeCode.d.ts +1 -0
  44. package/dist/style.css +9 -0
  45. package/package.json +6 -9
  46. package/src/elements/EFAudio.ts +1 -1
  47. package/src/elements/EFCaptions.ts +9 -9
  48. package/src/elements/EFImage.ts +3 -3
  49. package/src/elements/EFMedia.ts +11 -8
  50. package/src/elements/EFSourceMixin.ts +1 -1
  51. package/src/elements/EFTemporal.ts +42 -5
  52. package/src/elements/EFTimegroup.browsertest.ts +3 -3
  53. package/src/elements/EFTimegroup.ts +9 -6
  54. package/src/elements/EFVideo.ts +2 -2
  55. package/src/elements/EFWaveform.ts +6 -6
  56. package/src/elements/FetchMixin.ts +5 -3
  57. package/src/elements/TimegroupController.ts +1 -1
  58. package/src/elements/durationConverter.ts +1 -1
  59. package/src/elements/util.ts +1 -1
  60. package/src/gui/ContextMixin.ts +254 -0
  61. package/src/gui/EFFilmstrip.ts +41 -150
  62. package/src/gui/EFPreview.ts +39 -0
  63. package/src/gui/EFWorkbench.ts +7 -105
  64. package/src/gui/TWMixin.ts +10 -3
  65. package/src/gui/apiHostContext.ts +3 -0
  66. package/src/gui/fetchContext.ts +5 -0
  67. package/src/gui/focusContext.ts +7 -0
  68. package/src/gui/focusedElementContext.ts +5 -0
  69. package/src/gui/playingContext.ts +3 -0
  70. package/dist/lib/av/EncodedAsset.cjs +0 -577
  71. package/dist/lib/av/MP4File.cjs +0 -187
  72. package/dist/lib/av/msToTimeCode.cjs +0 -15
  73. package/dist/lib/util/awaitMicrotask.cjs +0 -4
  74. package/dist/lib/util/awaitMicrotask.js +0 -4
  75. package/dist/lib/util/memoize.cjs +0 -14
  76. package/dist/packages/elements/src/EF_FRAMEGEN.cjs +0 -197
  77. package/dist/packages/elements/src/EF_INTERACTIVE.cjs +0 -4
  78. package/dist/packages/elements/src/EF_INTERACTIVE.d.ts +0 -1
  79. package/dist/packages/elements/src/EF_INTERACTIVE.js +0 -4
  80. package/dist/packages/elements/src/elements/CrossUpdateController.cjs +0 -16
  81. package/dist/packages/elements/src/elements/EFAudio.cjs +0 -53
  82. package/dist/packages/elements/src/elements/EFCaptions.cjs +0 -164
  83. package/dist/packages/elements/src/elements/EFImage.cjs +0 -79
  84. package/dist/packages/elements/src/elements/EFMedia.cjs +0 -336
  85. package/dist/packages/elements/src/elements/EFSourceMixin.cjs +0 -55
  86. package/dist/packages/elements/src/elements/EFTemporal.cjs +0 -199
  87. package/dist/packages/elements/src/elements/EFTimegroup.cjs +0 -352
  88. package/dist/packages/elements/src/elements/EFVideo.cjs +0 -109
  89. package/dist/packages/elements/src/elements/EFWaveform.cjs +0 -242
  90. package/dist/packages/elements/src/elements/FetchMixin.cjs +0 -28
  91. package/dist/packages/elements/src/elements/TimegroupController.cjs +0 -20
  92. package/dist/packages/elements/src/elements/durationConverter.cjs +0 -8
  93. package/dist/packages/elements/src/elements/parseTimeToMs.cjs +0 -12
  94. package/dist/packages/elements/src/elements/util.cjs +0 -11
  95. package/dist/packages/elements/src/gui/EFFilmstrip.cjs +0 -825
  96. package/dist/packages/elements/src/gui/EFWorkbench.cjs +0 -214
  97. package/dist/packages/elements/src/gui/EFWorkbench.d.ts +0 -45
  98. package/dist/packages/elements/src/gui/TWMixin.cjs +0 -28
  99. package/dist/packages/elements/src/gui/TWMixin.css.cjs +0 -3
  100. package/dist/packages/elements/src/index.cjs +0 -50
  101. package/dist/packages/elements/src/index.d.ts +0 -10
  102. /package/dist/{packages/elements/src/EF_FRAMEGEN.d.ts → EF_FRAMEGEN.d.ts} +0 -0
  103. /package/dist/{lib/av → assets/dist}/MP4File.js +0 -0
  104. /package/dist/{lib/util → assets/dist}/memoize.js +0 -0
  105. /package/dist/{packages/elements/src/elements → elements}/CrossUpdateController.d.ts +0 -0
  106. /package/dist/{packages/elements/src/elements → elements}/EFSourceMixin.d.ts +0 -0
  107. /package/dist/{packages/elements/src/elements → elements}/FetchMixin.d.ts +0 -0
  108. /package/dist/{packages/elements/src/elements → elements}/durationConverter.d.ts +0 -0
  109. /package/dist/{packages/elements/src/elements → elements}/parseTimeToMs.d.ts +0 -0
  110. /package/dist/{packages/elements → elements}/src/elements/CrossUpdateController.js +0 -0
  111. /package/dist/{packages/elements → elements}/src/elements/EFAudio.js +0 -0
  112. /package/dist/{packages/elements → elements}/src/elements/EFImage.js +0 -0
  113. /package/dist/{packages/elements → elements}/src/elements/EFVideo.js +0 -0
  114. /package/dist/{packages/elements → elements}/src/elements/EFWaveform.js +0 -0
  115. /package/dist/{packages/elements → elements}/src/elements/TimegroupController.js +0 -0
  116. /package/dist/{packages/elements → elements}/src/elements/durationConverter.js +0 -0
  117. /package/dist/{packages/elements → elements}/src/elements/parseTimeToMs.js +0 -0
  118. /package/dist/{packages/elements → elements}/src/elements/util.js +0 -0
  119. /package/dist/{packages/elements → elements}/src/gui/TWMixin.css.js +0 -0
  120. /package/dist/{lib/av → elements/src}/msToTimeCode.js +0 -0
  121. /package/dist/{packages/elements/src/gui → gui}/TWMixin.d.ts +0 -0
@@ -0,0 +1,34 @@
1
+ import { LitElement, PropertyValueMap } from 'lit';
2
+ import { createRef } from 'lit/directives/ref.js';
3
+
4
+ declare const EFWorkbench_base: (new (...args: any[]) => {
5
+ focusContext: import('./focusContext.ts').FocusContext;
6
+ focusedElement?: HTMLElement;
7
+ fetch: typeof fetch;
8
+ signingURL?: string;
9
+ apiToken?: string;
10
+ apiHost: string;
11
+ stageScale: number;
12
+ rendering: boolean;
13
+ stageRef: ReturnType<typeof createRef>;
14
+ canvasRef: ReturnType<typeof createRef>;
15
+ playing: boolean;
16
+ targetTimegroup?: import('../elements/EFTimegroup.ts').EFTimegroup;
17
+ currentTimeMs: number;
18
+ }) & typeof LitElement;
19
+ export declare class EFWorkbench extends EFWorkbench_base {
20
+ static styles: import('lit').CSSResult[];
21
+ disconnectedCallback(): void;
22
+ handleStageWheel(event: WheelEvent): void;
23
+ focusOverlay: import('lit-html/directives/ref.js').Ref<HTMLDivElement>;
24
+ update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
25
+ drawOverlays: () => void;
26
+ render(): import('lit-html').TemplateResult<1>;
27
+ stepThrough(): Promise<void>;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ "ef-workbench": EFWorkbench;
32
+ }
33
+ }
34
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare const apiHostContext: {
2
+ __context__: string;
3
+ };
@@ -0,0 +1,3 @@
1
+ export declare const fetchContext: {
2
+ __context__: (url: string, init?: RequestInit) => Promise<Response>;
3
+ };
@@ -0,0 +1,6 @@
1
+ export interface FocusContext {
2
+ focusedElement: HTMLElement | null;
3
+ }
4
+ export declare const focusContext: {
5
+ __context__: FocusContext;
6
+ };
@@ -0,0 +1,3 @@
1
+ export declare const focusedElementContext: {
2
+ __context__: HTMLElement | undefined;
3
+ };
@@ -0,0 +1,3 @@
1
+ export declare const playingContext: {
2
+ __context__: boolean;
3
+ };
@@ -0,0 +1,11 @@
1
+
2
+ export { EFTimegroup } from './elements/EFTimegroup.ts';
3
+ export { EFImage } from './elements/EFImage.ts';
4
+ export type { EFMedia } from './elements/EFMedia.ts';
5
+ export { EFAudio } from './elements/EFAudio.ts';
6
+ export { EFVideo } from './elements/EFVideo.ts';
7
+ export { EFCaptions, EFCaptionsActiveWord } from './elements/EFCaptions.ts';
8
+ export { EFWaveform } from './elements/EFWaveform.ts';
9
+ export { EFWorkbench } from './gui/EFWorkbench.ts';
10
+ export { EFPreview } from './gui/EFPreview.ts';
11
+ export { EFFilmstrip } from './gui/EFFilmstrip.ts';
@@ -0,0 +1 @@
1
+ export declare const msToTimeCode: (ms: number, subSecond?: boolean) => string;
package/dist/style.css CHANGED
@@ -740,6 +740,7 @@ video {
740
740
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
741
741
  transition-duration: 150ms;
742
742
  }
743
+
743
744
  html {
744
745
  height: 100%;
745
746
  width: 100%;
@@ -750,6 +751,7 @@ body {
750
751
  --tw-bg-opacity: 1;
751
752
  background-color: rgb(0 0 0 / var(--tw-bg-opacity));
752
753
  }
754
+
753
755
  :root {
754
756
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
755
757
  line-height: 1.5;
@@ -761,30 +763,37 @@ body {
761
763
  -moz-osx-font-smoothing: grayscale;
762
764
  -webkit-text-size-adjust: 100%;
763
765
  }
766
+
764
767
  .hover\:bg-blue-400:hover {
765
768
  --tw-bg-opacity: 1;
766
769
  background-color: rgb(96 165 250 / var(--tw-bg-opacity));
767
770
  }
771
+
768
772
  .hover\:bg-slate-400:hover {
769
773
  --tw-bg-opacity: 1;
770
774
  background-color: rgb(148 163 184 / var(--tw-bg-opacity));
771
775
  }
776
+
772
777
  .peer:hover ~ .peer-hover\:border-slate-400 {
773
778
  --tw-border-opacity: 1;
774
779
  border-color: rgb(148 163 184 / var(--tw-border-opacity));
775
780
  }
781
+
776
782
  .peer:hover ~ .peer-hover\:bg-slate-300 {
777
783
  --tw-bg-opacity: 1;
778
784
  background-color: rgb(203 213 225 / var(--tw-bg-opacity));
779
785
  }
786
+
780
787
  .data-\[focused\]\:bg-slate-400[data-focused] {
781
788
  --tw-bg-opacity: 1;
782
789
  background-color: rgb(148 163 184 / var(--tw-bg-opacity));
783
790
  }
791
+
784
792
  .peer[data-focused] ~ .peer-data-\[focused\]\:border-slate-400 {
785
793
  --tw-border-opacity: 1;
786
794
  border-color: rgb(148 163 184 / var(--tw-border-opacity));
787
795
  }
796
+
788
797
  .peer[data-focused] ~ .peer-data-\[focused\]\:bg-slate-300 {
789
798
  --tw-bg-opacity: 1;
790
799
  background-color: rgb(203 213 225 / var(--tw-bg-opacity));
package/package.json CHANGED
@@ -1,16 +1,12 @@
1
1
  {
2
2
  "name": "@editframe/elements",
3
- "version": "0.7.0-beta.8",
3
+ "version": "0.8.0-beta.1",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
7
7
  "import": {
8
- "default": "./dist/packages/elements/src/index.js",
9
- "types": "./dist/packages/elements/src/index.d.ts"
10
- },
11
- "require": {
12
- "default": "./dist/packages/elements/src/index.cjs",
13
- "types": "./dist/packages/elements/src/index.d.ts"
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/elements/src/index.js"
14
10
  }
15
11
  },
16
12
  "./styles.css": "./dist/style.css"
@@ -24,7 +20,7 @@
24
20
  "author": "",
25
21
  "license": "UNLICENSED",
26
22
  "dependencies": {
27
- "@editframe/assets": "0.7.0-beta.8",
23
+ "@editframe/assets": "0.8.0-beta.1",
28
24
  "@lit/context": "^1.1.2",
29
25
  "@lit/task": "^1.0.1",
30
26
  "d3": "^7.9.0",
@@ -35,9 +31,10 @@
35
31
  "devDependencies": {
36
32
  "@types/d3": "^7.4.3",
37
33
  "@types/dom-webcodecs": "^0.1.11",
38
- "@types/node": "^20.14.9",
34
+ "@types/node": "^20.14.13",
39
35
  "autoprefixer": "^10.4.19",
40
36
  "rollup-plugin-tsconfig-paths": "^1.5.2",
37
+ "typescript": "^5.5.4",
41
38
  "vite-plugin-dts": "^3.9.1",
42
39
  "vite-tsconfig-paths": "^4.3.2"
43
40
  }
@@ -1,7 +1,7 @@
1
1
  import { html } from "lit";
2
2
  import { createRef, ref } from "lit/directives/ref.js";
3
3
  import { customElement, property } from "lit/decorators.js";
4
- import { EFMedia } from "./EFMedia";
4
+ import { EFMedia } from "./EFMedia.ts";
5
5
  import { Task } from "@lit/task";
6
6
 
7
7
  @customElement("ef-audio")
@@ -1,13 +1,13 @@
1
- import { EFAudio } from "./EFAudio";
2
1
  import { LitElement, type PropertyValueMap, html, css } from "lit";
3
2
  import { Task } from "@lit/task";
4
3
  import { customElement, property } from "lit/decorators.js";
5
- import { EFVideo } from "./EFVideo";
6
- import { EFTemporal } from "./EFTemporal";
7
- import { CrossUpdateController } from "./CrossUpdateController";
8
- import { FetchMixin } from "./FetchMixin";
9
- import { EFSourceMixin } from "./EFSourceMixin";
10
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
4
+ import { EFVideo } from "./EFVideo.ts";
5
+ import { EFAudio } from "./EFAudio.ts";
6
+ import { EFTemporal } from "./EFTemporal.ts";
7
+ import { CrossUpdateController } from "./CrossUpdateController.ts";
8
+ import { FetchMixin } from "./FetchMixin.ts";
9
+ import { EFSourceMixin } from "./EFSourceMixin.ts";
10
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
11
11
 
12
12
  interface Word {
13
13
  text: string;
@@ -93,8 +93,8 @@ export class EFCaptions extends EFSourceMixin(
93
93
 
94
94
  protected md5SumLoader = new Task(this, {
95
95
  autoRun: false,
96
- args: () => [this.target] as const,
97
- task: async ([], { signal }) => {
96
+ args: () => [this.target, this.fetch] as const,
97
+ task: async ([_target, fetch], { signal }) => {
98
98
  const md5Path = `/@ef-asset/${this.targetElement.src ?? ""}`;
99
99
  const response = await fetch(md5Path, { method: "HEAD", signal });
100
100
  return response.headers.get("etag") ?? undefined;
@@ -2,9 +2,9 @@ import { Task } from "@lit/task";
2
2
  import { LitElement, html, css } from "lit";
3
3
  import { customElement } from "lit/decorators.js";
4
4
  import { createRef, ref } from "lit/directives/ref.js";
5
- import { FetchMixin } from "./FetchMixin";
6
- import { EFSourceMixin } from "./EFSourceMixin";
7
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
5
+ import { FetchMixin } from "./FetchMixin.ts";
6
+ import { EFSourceMixin } from "./EFSourceMixin.ts";
7
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
8
8
 
9
9
  @customElement("ef-image")
10
10
  export class EFImage extends EFSourceMixin(FetchMixin(LitElement), {
@@ -8,14 +8,14 @@ import debug from "debug";
8
8
 
9
9
  import type { TrackFragmentIndex, TrackSegment } from "@editframe/assets";
10
10
 
11
- import { MP4File } from "@/av/MP4File";
12
- import { EFTemporal } from "./EFTemporal";
13
- import { VideoAsset } from "@/av/EncodedAsset";
14
- import { FetchMixin } from "./FetchMixin";
15
- import { apiHostContext } from "../gui/EFWorkbench";
16
- import { EFSourceMixin } from "./EFSourceMixin";
17
- import { getStartTimeMs } from "./util";
18
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
11
+ import { MP4File } from "@editframe/assets/MP4File.js";
12
+ import { VideoAsset } from "@editframe/assets/EncodedAsset.js";
13
+ import { EFTemporal } from "./EFTemporal.ts";
14
+ import { FetchMixin } from "./FetchMixin.ts";
15
+ import { EFSourceMixin } from "./EFSourceMixin.ts";
16
+ import { getStartTimeMs } from "./util.ts";
17
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
18
+ import { apiHostContext } from "../gui/apiHostContext.ts";
19
19
 
20
20
  const log = debug("ef:elements:EFMedia");
21
21
 
@@ -70,6 +70,9 @@ export class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
70
70
  public trackFragmentIndexLoader = new Task(this, {
71
71
  args: () => [this.fragmentIndexPath(), this.fetch] as const,
72
72
  task: async ([fragmentIndexPath, fetch], { signal }) => {
73
+ if (this.src === "") {
74
+ return;
75
+ }
73
76
  const response = await fetch(fragmentIndexPath, { signal });
74
77
  return (await response.json()) as Record<number, TrackFragmentIndex>;
75
78
  },
@@ -1,9 +1,9 @@
1
1
  import { consume } from "@lit/context";
2
2
  import type { LitElement } from "lit";
3
- import { apiHostContext } from "../gui/EFWorkbench";
4
3
  import { state } from "lit/decorators/state.js";
5
4
  import { Task } from "@lit/task";
6
5
  import { property } from "lit/decorators/property.js";
6
+ import { apiHostContext } from "../gui/apiHostContext.ts";
7
7
 
8
8
  export declare class EFSourceMixinInterface {
9
9
  productionSrc(): string;
@@ -1,11 +1,11 @@
1
1
  import type { LitElement, ReactiveController } from "lit";
2
2
  import { consume, createContext } from "@lit/context";
3
3
  import { property, state } from "lit/decorators.js";
4
- import type { EFTimegroup } from "./EFTimegroup";
4
+ import type { EFTimegroup } from "./EFTimegroup.ts";
5
5
 
6
- import { durationConverter } from "./durationConverter";
6
+ import { durationConverter } from "./durationConverter.ts";
7
7
  import { Task } from "@lit/task";
8
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
8
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
9
9
 
10
10
  export const timegroupContext = createContext<EFTimegroup>(
11
11
  Symbol("timeGroupContext"),
@@ -59,10 +59,23 @@ export const deepGetElementsWithFrameTasks = (
59
59
  return elements;
60
60
  };
61
61
 
62
+ let temporalCache: Map<Element, TemporalMixinInterface[]>;
63
+ const resetTemporalCache = () => {
64
+ temporalCache = new Map();
65
+ if (typeof requestAnimationFrame !== "undefined") {
66
+ requestAnimationFrame(resetTemporalCache);
67
+ }
68
+ };
69
+ resetTemporalCache();
70
+
62
71
  export const shallowGetTemporalElements = (
63
72
  element: Element,
64
73
  temporals: TemporalMixinInterface[] = [],
65
74
  ) => {
75
+ const cachedResult = temporalCache.get(element);
76
+ if (cachedResult) {
77
+ return cachedResult;
78
+ }
66
79
  for (const child of element.children) {
67
80
  if (isEFTemporal(child)) {
68
81
  temporals.push(child);
@@ -70,6 +83,7 @@ export const shallowGetTemporalElements = (
70
83
  shallowGetTemporalElements(child, temporals);
71
84
  }
72
85
  }
86
+ temporalCache.set(element, temporals);
73
87
  return temporals;
74
88
  };
75
89
 
@@ -92,6 +106,15 @@ export class OwnCurrentTimeController implements ReactiveController {
92
106
 
93
107
  type Constructor<T = {}> = new (...args: any[]) => T;
94
108
 
109
+ let startTimeMsCache = new WeakMap<Element, number>();
110
+ const resetStartTimeMsCache = () => {
111
+ startTimeMsCache = new WeakMap();
112
+ if (typeof requestAnimationFrame !== "undefined") {
113
+ requestAnimationFrame(resetStartTimeMsCache);
114
+ }
115
+ };
116
+ resetStartTimeMsCache();
117
+
95
118
  export const EFTemporal = <T extends Constructor<LitElement>>(
96
119
  superClass: T,
97
120
  ) => {
@@ -172,27 +195,41 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
172
195
  }
173
196
 
174
197
  get startTimeMs(): number {
198
+ const cachedStartTime = startTimeMsCache.get(this);
199
+ if (cachedStartTime !== undefined) {
200
+ return cachedStartTime;
201
+ }
175
202
  const parentTimegroup = this.parentTimegroup;
176
203
  if (!parentTimegroup) {
204
+ startTimeMsCache.set(this, 0);
177
205
  return 0;
178
206
  }
179
207
  switch (parentTimegroup.mode) {
180
208
  case "sequence": {
181
209
  const siblingTemorals = shallowGetTemporalElements(parentTimegroup);
182
- const ownIndex = siblingTemorals.indexOf(
210
+ const ownIndex = siblingTemorals?.indexOf(
183
211
  this as InstanceType<Constructor<TemporalMixinInterface> & T>,
184
212
  );
185
213
  if (ownIndex === 0) {
214
+ startTimeMsCache.set(this, parentTimegroup.startTimeMs);
186
215
  return parentTimegroup.startTimeMs;
187
216
  }
188
- const previous = siblingTemorals[ownIndex - 1];
217
+ const previous = siblingTemorals?.[(ownIndex ?? 0) - 1];
189
218
  if (!previous) {
190
219
  throw new Error("Previous temporal element not found");
191
220
  }
221
+ startTimeMsCache.set(
222
+ this,
223
+ previous.startTimeMs + previous.durationMs,
224
+ );
192
225
  return previous.startTimeMs + previous.durationMs;
193
226
  }
194
227
  case "contain":
195
228
  case "fixed":
229
+ startTimeMsCache.set(
230
+ this,
231
+ parentTimegroup.startTimeMs + this.offsetMs,
232
+ );
196
233
  return parentTimegroup.startTimeMs + this.offsetMs;
197
234
  default:
198
235
  throw new Error(`Invalid time mode: ${parentTimegroup.mode}`);
@@ -5,10 +5,10 @@ import {
5
5
  html,
6
6
  render as litRender,
7
7
  } from "lit";
8
- import { EFTimegroup } from "./EFTimegroup";
9
- import "./EFTimegroup";
8
+ import { EFTimegroup } from "./EFTimegroup.ts";
9
+ import "./EFTimegroup.ts";
10
10
  import { customElement } from "lit/decorators/custom-element.js";
11
- import { EFTemporal } from "./EFTemporal";
11
+ import { EFTemporal } from "./EFTemporal.ts";
12
12
 
13
13
  beforeEach(() => {
14
14
  for (let i = 0; i < localStorage.length; i++) {
@@ -9,10 +9,10 @@ import {
9
9
  isEFTemporal,
10
10
  shallowGetTemporalElements,
11
11
  timegroupContext,
12
- } from "./EFTemporal";
13
- import { TimegroupController } from "./TimegroupController";
14
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
15
- import { deepGetMediaElements } from "./EFMedia";
12
+ } from "./EFTemporal.ts";
13
+ import { TimegroupController } from "./TimegroupController.ts";
14
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
15
+ import { deepGetMediaElements } from "./EFMedia.ts";
16
16
 
17
17
  const log = debug("ef:elements:EFTimegroup");
18
18
 
@@ -113,7 +113,9 @@ export class EFTimegroup extends EFTemporal(LitElement) {
113
113
  connectedCallback() {
114
114
  super.connectedCallback();
115
115
  if (this.id) {
116
- this.#currentTime = this.maybeLoadTimeFromLocalStorage();
116
+ this.waitForMediaDurations().then(() => {
117
+ this.#currentTime = this.maybeLoadTimeFromLocalStorage();
118
+ });
117
119
  }
118
120
 
119
121
  if (this.parentTimegroup) {
@@ -265,7 +267,8 @@ export class EFTimegroup extends EFTemporal(LitElement) {
265
267
  return (
266
268
  EF_INTERACTIVE &&
267
269
  this.closest("ef-timegroup") === this &&
268
- this.closest("ef-workbench") === null
270
+ this.closest("ef-workbench") === null &&
271
+ this.closest("ef-preview") === null
269
272
  );
270
273
  }
271
274
 
@@ -3,8 +3,8 @@ import { Task } from "@lit/task";
3
3
  import { createRef, ref } from "lit/directives/ref.js";
4
4
  import { customElement } from "lit/decorators.js";
5
5
 
6
- import { EFMedia } from "./EFMedia";
7
- import { TWMixin } from "../gui/TWMixin";
6
+ import { EFMedia } from "./EFMedia.ts";
7
+ import { TWMixin } from "../gui/TWMixin.ts";
8
8
 
9
9
  @customElement("ef-video")
10
10
  export class EFVideo extends TWMixin(EFMedia) {
@@ -1,15 +1,15 @@
1
- import { EFAudio } from "./EFAudio";
1
+ import { EFAudio } from "./EFAudio.ts";
2
2
 
3
3
  import { LitElement, html } from "lit";
4
4
  import { customElement, property } from "lit/decorators.js";
5
- import { EFVideo } from "./EFVideo";
6
- import { EFTemporal } from "./EFTemporal";
7
- import { CrossUpdateController } from "./CrossUpdateController";
8
- import { TWMixin } from "../gui/TWMixin";
5
+ import { EFVideo } from "./EFVideo.ts";
6
+ import { EFTemporal } from "./EFTemporal.ts";
7
+ import { CrossUpdateController } from "./CrossUpdateController.ts";
8
+ import { TWMixin } from "../gui/TWMixin.ts";
9
9
  import { Task } from "@lit/task";
10
10
  import * as d3 from "d3";
11
11
  import { type Ref, createRef, ref } from "lit/directives/ref.js";
12
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE";
12
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
13
13
 
14
14
  @customElement("ef-waveform")
15
15
  export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
@@ -1,8 +1,9 @@
1
- import { consume } from "@lit/context";
2
1
  import type { LitElement } from "lit";
3
- import { fetchContext } from "../gui/EFWorkbench";
2
+ import { consume } from "@lit/context";
4
3
  import { state } from "lit/decorators/state.js";
5
4
 
5
+ import { fetchContext } from "../gui/fetchContext.ts";
6
+
6
7
  export declare class FetchMixinInterface {
7
8
  fetch: typeof fetch;
8
9
  }
@@ -12,7 +13,8 @@ export function FetchMixin<T extends Constructor<LitElement>>(superClass: T) {
12
13
  class FetchElement extends superClass {
13
14
  @consume({ context: fetchContext, subscribe: true })
14
15
  @state()
15
- fetch = fetch.bind(window);
16
+ fetch: (url: string, init?: RequestInit) => Promise<Response> =
17
+ fetch.bind(window);
16
18
  }
17
19
 
18
20
  return FetchElement as Constructor<FetchMixinInterface> & T;
@@ -1,5 +1,5 @@
1
1
  import type { ReactiveController, LitElement } from "lit";
2
- import type { EFTimegroup } from "./EFTimegroup";
2
+ import type { EFTimegroup } from "./EFTimegroup.ts";
3
3
 
4
4
  export class TimegroupController implements ReactiveController {
5
5
  constructor(
@@ -1,4 +1,4 @@
1
- import { parseTimeToMs } from "./parseTimeToMs";
1
+ import { parseTimeToMs } from "./parseTimeToMs.ts";
2
2
 
3
3
  export const durationConverter = {
4
4
  fromAttribute: (value: string): number => parseTimeToMs(value),
@@ -1,4 +1,4 @@
1
- import { EFTimegroup } from "./EFTimegroup";
1
+ import { EFTimegroup } from "./EFTimegroup.ts";
2
2
 
3
3
  export const getRootTimeGroup = (element: Element): EFTimegroup | null => {
4
4
  let bestCandidate: EFTimegroup | null = null;