@editframe/elements 0.19.4-beta.0 → 0.20.1-beta.0
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.
- package/dist/elements/ContextProxiesController.d.ts +40 -0
- package/dist/elements/ContextProxiesController.js +69 -0
- package/dist/elements/EFCaptions.d.ts +45 -6
- package/dist/elements/EFCaptions.js +220 -26
- package/dist/elements/EFImage.js +4 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +2 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +9 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +1 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +11 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +13 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +9 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +7 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +15 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +2 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +3 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +6 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +3 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +2 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +2 -2
- package/dist/elements/EFMedia/shared/GlobalInputCache.d.ts +39 -0
- package/dist/elements/EFMedia/shared/GlobalInputCache.js +57 -0
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.d.ts +27 -0
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +106 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -1
- package/dist/elements/EFMedia.d.ts +2 -2
- package/dist/elements/EFMedia.js +25 -1
- package/dist/elements/EFSurface.browsertest.d.ts +0 -0
- package/dist/elements/EFSurface.d.ts +30 -0
- package/dist/elements/EFSurface.js +96 -0
- package/dist/elements/EFTemporal.js +7 -6
- package/dist/elements/EFThumbnailStrip.browsertest.d.ts +0 -0
- package/dist/elements/EFThumbnailStrip.d.ts +86 -0
- package/dist/elements/EFThumbnailStrip.js +490 -0
- package/dist/elements/EFThumbnailStrip.media-engine.browsertest.d.ts +0 -0
- package/dist/elements/EFTimegroup.d.ts +6 -1
- package/dist/elements/EFTimegroup.js +53 -11
- package/dist/elements/updateAnimations.browsertest.d.ts +13 -0
- package/dist/elements/updateAnimations.d.ts +5 -0
- package/dist/elements/updateAnimations.js +37 -13
- package/dist/getRenderInfo.js +1 -1
- package/dist/gui/ContextMixin.js +27 -14
- package/dist/gui/EFControls.browsertest.d.ts +0 -0
- package/dist/gui/EFControls.d.ts +38 -0
- package/dist/gui/EFControls.js +51 -0
- package/dist/gui/EFFilmstrip.d.ts +40 -1
- package/dist/gui/EFFilmstrip.js +240 -3
- package/dist/gui/EFPreview.js +2 -1
- package/dist/gui/EFScrubber.d.ts +6 -5
- package/dist/gui/EFScrubber.js +31 -21
- package/dist/gui/EFTimeDisplay.browsertest.d.ts +0 -0
- package/dist/gui/EFTimeDisplay.d.ts +2 -6
- package/dist/gui/EFTimeDisplay.js +13 -23
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/currentTimeContext.d.ts +3 -0
- package/dist/gui/currentTimeContext.js +3 -0
- package/dist/gui/durationContext.d.ts +3 -0
- package/dist/gui/durationContext.js +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/dist/style.css +1 -1
- package/dist/transcoding/types/index.d.ts +11 -0
- package/dist/utils/LRUCache.d.ts +46 -0
- package/dist/utils/LRUCache.js +382 -1
- package/dist/utils/LRUCache.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/elements/ContextProxiesController.ts +124 -0
- package/src/elements/EFCaptions.browsertest.ts +1820 -0
- package/src/elements/EFCaptions.ts +373 -36
- package/src/elements/EFImage.ts +4 -1
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +30 -1
- package/src/elements/EFMedia/AssetMediaEngine.ts +33 -0
- package/src/elements/EFMedia/BaseMediaEngine.browsertest.ts +3 -8
- package/src/elements/EFMedia/BaseMediaEngine.ts +35 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +34 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +6 -5
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +5 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +8 -5
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +5 -5
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +11 -12
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +7 -4
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +5 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +2 -2
- package/src/elements/EFMedia/shared/GlobalInputCache.ts +77 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +2 -2
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +2 -2
- package/src/elements/EFMedia/shared/ThumbnailExtractor.ts +227 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +1 -1
- package/src/elements/EFMedia.ts +38 -1
- package/src/elements/EFSurface.browsertest.ts +155 -0
- package/src/elements/EFSurface.ts +141 -0
- package/src/elements/EFTemporal.ts +14 -8
- package/src/elements/EFThumbnailStrip.browsertest.ts +591 -0
- package/src/elements/EFThumbnailStrip.media-engine.browsertest.ts +713 -0
- package/src/elements/EFThumbnailStrip.ts +905 -0
- package/src/elements/EFTimegroup.browsertest.ts +56 -7
- package/src/elements/EFTimegroup.ts +88 -16
- package/src/elements/updateAnimations.browsertest.ts +333 -11
- package/src/elements/updateAnimations.ts +68 -19
- package/src/gui/ContextMixin.browsertest.ts +0 -25
- package/src/gui/ContextMixin.ts +44 -20
- package/src/gui/EFControls.browsertest.ts +175 -0
- package/src/gui/EFControls.ts +84 -0
- package/src/gui/EFFilmstrip.ts +323 -4
- package/src/gui/EFPreview.ts +2 -1
- package/src/gui/EFScrubber.ts +29 -25
- package/src/gui/EFTimeDisplay.browsertest.ts +237 -0
- package/src/gui/EFTimeDisplay.ts +12 -40
- package/src/gui/currentTimeContext.ts +5 -0
- package/src/gui/durationContext.ts +3 -0
- package/src/transcoding/types/index.ts +13 -0
- package/src/utils/LRUCache.test.ts +272 -0
- package/src/utils/LRUCache.ts +543 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/metadata.json +1 -1
- package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -1
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +1 -1
- package/types.json +1 -1
- package/dist/transcoding/cache/CacheManager.d.ts +0 -73
- package/src/transcoding/cache/CacheManager.ts +0 -208
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { deepGetTemporalElements
|
|
2
|
-
const ANIMATION_PRECISION_OFFSET = .
|
|
1
|
+
import { deepGetTemporalElements } from "./EFTemporal.js";
|
|
2
|
+
const ANIMATION_PRECISION_OFFSET = .1;
|
|
3
3
|
const DEFAULT_ANIMATION_ITERATIONS = 1;
|
|
4
4
|
const PROGRESS_PROPERTY = "--ef-progress";
|
|
5
5
|
const DURATION_PROPERTY = "--ef-duration";
|
|
@@ -12,7 +12,23 @@ const TIMEGROUP_TAGNAME = "ef-timegroup";
|
|
|
12
12
|
const evaluateTemporalState = (element) => {
|
|
13
13
|
const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
|
|
14
14
|
const progress = element.durationMs <= 0 ? 1 : Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs));
|
|
15
|
-
const
|
|
15
|
+
const isRootTimegroup = element.tagName.toLowerCase() === TIMEGROUP_TAGNAME && !element.parentTimegroup;
|
|
16
|
+
const useInclusiveEnd = isRootTimegroup;
|
|
17
|
+
const isVisible = element.startTimeMs <= timelineTimeMs && (useInclusiveEnd ? element.endTimeMs >= timelineTimeMs : element.endTimeMs > timelineTimeMs);
|
|
18
|
+
return {
|
|
19
|
+
progress,
|
|
20
|
+
isVisible,
|
|
21
|
+
timelineTimeMs
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Evaluates element visibility specifically for animation coordination
|
|
26
|
+
* Uses inclusive end boundaries to prevent animation jumps at exact boundaries
|
|
27
|
+
*/
|
|
28
|
+
const evaluateTemporalStateForAnimation = (element) => {
|
|
29
|
+
const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
|
|
30
|
+
const progress = element.durationMs <= 0 ? 1 : Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs));
|
|
31
|
+
const isVisible = element.startTimeMs <= timelineTimeMs && element.endTimeMs >= timelineTimeMs;
|
|
16
32
|
return {
|
|
17
33
|
progress,
|
|
18
34
|
isVisible,
|
|
@@ -34,18 +50,16 @@ const updateVisualState = (element, state) => {
|
|
|
34
50
|
element.style.setProperty(TRANSITION_OUT_START_PROPERTY, `${element.durationMs - (element.parentTimegroup?.overlapMs ?? 0)}ms`);
|
|
35
51
|
};
|
|
36
52
|
/**
|
|
37
|
-
* Coordinates animations
|
|
53
|
+
* Coordinates animations for a single element and its subtree, using the element as the time source
|
|
38
54
|
*/
|
|
39
|
-
const
|
|
55
|
+
const coordinateAnimationsForSingleElement = (element) => {
|
|
40
56
|
const animations = element.getAnimations({ subtree: true });
|
|
41
57
|
for (const animation of animations) {
|
|
42
58
|
if (animation.playState === "running") animation.pause();
|
|
43
59
|
const effect = animation.effect;
|
|
44
60
|
if (!(effect && effect instanceof KeyframeEffect)) continue;
|
|
45
61
|
const target = effect.target;
|
|
46
|
-
if (!target
|
|
47
|
-
const timeTarget = isEFTemporal(target) ? target : target.closest(TIMEGROUP_TAGNAME);
|
|
48
|
-
if (!timeTarget) continue;
|
|
62
|
+
if (!target) continue;
|
|
49
63
|
const timing = effect.getTiming();
|
|
50
64
|
const duration = Number(timing.duration) || 0;
|
|
51
65
|
const delay = Number(timing.delay) || 0;
|
|
@@ -54,7 +68,7 @@ const coordinateAnimations = (element) => {
|
|
|
54
68
|
animation.currentTime = 0;
|
|
55
69
|
continue;
|
|
56
70
|
}
|
|
57
|
-
const currentTime =
|
|
71
|
+
const currentTime = element.ownCurrentTimeMs ?? 0;
|
|
58
72
|
if (currentTime < delay) {
|
|
59
73
|
animation.currentTime = 0;
|
|
60
74
|
continue;
|
|
@@ -62,8 +76,13 @@ const coordinateAnimations = (element) => {
|
|
|
62
76
|
const adjustedTime = currentTime - delay;
|
|
63
77
|
const currentIteration = Math.floor(adjustedTime / duration);
|
|
64
78
|
const currentIterationTime = adjustedTime % duration;
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
const totalAnimationLength = delay + duration * iterations;
|
|
80
|
+
const maxSafeCurrentTime = totalAnimationLength - ANIMATION_PRECISION_OFFSET;
|
|
81
|
+
if (currentIteration >= iterations) animation.currentTime = maxSafeCurrentTime;
|
|
82
|
+
else {
|
|
83
|
+
const proposedCurrentTime = Math.min(currentIterationTime, duration - ANIMATION_PRECISION_OFFSET) + delay;
|
|
84
|
+
animation.currentTime = Math.min(proposedCurrentTime, maxSafeCurrentTime);
|
|
85
|
+
}
|
|
67
86
|
}
|
|
68
87
|
};
|
|
69
88
|
/**
|
|
@@ -76,6 +95,11 @@ const updateAnimations = (element) => {
|
|
|
76
95
|
updateVisualState(temporalElement, temporalState$1);
|
|
77
96
|
});
|
|
78
97
|
updateVisualState(element, temporalState);
|
|
79
|
-
|
|
98
|
+
const animationState = evaluateTemporalStateForAnimation(element);
|
|
99
|
+
if (animationState.isVisible) coordinateAnimationsForSingleElement(element);
|
|
100
|
+
deepGetTemporalElements(element).forEach((temporalElement) => {
|
|
101
|
+
const childAnimationState = evaluateTemporalStateForAnimation(temporalElement);
|
|
102
|
+
if (childAnimationState.isVisible) coordinateAnimationsForSingleElement(temporalElement);
|
|
103
|
+
});
|
|
80
104
|
};
|
|
81
|
-
export {
|
|
105
|
+
export { evaluateTemporalStateForAnimation, updateAnimations };
|
package/dist/getRenderInfo.js
CHANGED
|
@@ -43,7 +43,7 @@ const getRenderInfo = async () => {
|
|
|
43
43
|
case "EF-CAPTIONS": {
|
|
44
44
|
const src = element.targetElement?.src;
|
|
45
45
|
console.error("Processing element", element.tagName, src);
|
|
46
|
-
assets.efCaptions.add(src);
|
|
46
|
+
assets.efCaptions.add(src ?? "undefined");
|
|
47
47
|
break;
|
|
48
48
|
}
|
|
49
49
|
}
|
package/dist/gui/ContextMixin.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
2
2
|
import { globalURLTokenDeduplicator } from "../transcoding/cache/URLTokenDeduplicator.js";
|
|
3
|
+
import { currentTimeContext } from "./currentTimeContext.js";
|
|
4
|
+
import { durationContext } from "./durationContext.js";
|
|
3
5
|
import { efConfigurationContext } from "./EFConfiguration.js";
|
|
4
6
|
import { efContext } from "./efContext.js";
|
|
5
7
|
import { fetchContext } from "./fetchContext.js";
|
|
@@ -22,6 +24,8 @@ function ContextMixin(superClass) {
|
|
|
22
24
|
this.focusContext = this;
|
|
23
25
|
this.efContext = this;
|
|
24
26
|
this.targetTimegroup = null;
|
|
27
|
+
this.durationMs = 0;
|
|
28
|
+
this.endTimeMs = 0;
|
|
25
29
|
this.fetch = async (url, init = {}) => {
|
|
26
30
|
init.headers ||= {};
|
|
27
31
|
Object.assign(init.headers, { "Content-Type": "application/json" });
|
|
@@ -67,12 +71,6 @@ function ContextMixin(superClass) {
|
|
|
67
71
|
set apiHost(value) {
|
|
68
72
|
this.#apiHost = value;
|
|
69
73
|
}
|
|
70
|
-
get durationMs() {
|
|
71
|
-
return this.targetTimegroup?.durationMs ?? 0;
|
|
72
|
-
}
|
|
73
|
-
get endTimeMs() {
|
|
74
|
-
return this.targetTimegroup?.endTimeMs ?? 0;
|
|
75
|
-
}
|
|
76
74
|
/**
|
|
77
75
|
* Generate a cache key for URL token based on signing strategy
|
|
78
76
|
*
|
|
@@ -157,16 +155,35 @@ function ContextMixin(superClass) {
|
|
|
157
155
|
shouldUpdate = true;
|
|
158
156
|
} else if (mutation.target instanceof Element && (mutation.target.tagName === "EF-TIMEGROUP" || mutation.target.closest("ef-timegroup"))) shouldUpdate = true;
|
|
159
157
|
} else if (mutation.type === "attributes") {
|
|
160
|
-
|
|
158
|
+
const durationAffectingAttributes = [
|
|
159
|
+
"duration",
|
|
160
|
+
"mode",
|
|
161
|
+
"trimstart",
|
|
162
|
+
"trimend",
|
|
163
|
+
"sourcein",
|
|
164
|
+
"sourceout"
|
|
165
|
+
];
|
|
166
|
+
if (durationAffectingAttributes.includes(mutation.attributeName || "") || mutation.target instanceof Element && (mutation.target.tagName === "EF-TIMEGROUP" || mutation.target.tagName === "EF-VIDEO" || mutation.target.tagName === "EF-AUDIO" || mutation.target.tagName === "EF-CAPTIONS" || mutation.target.closest("ef-timegroup"))) shouldUpdate = true;
|
|
161
167
|
}
|
|
162
168
|
if (shouldUpdate) queueMicrotask(() => {
|
|
169
|
+
this.updateDurationProperties();
|
|
163
170
|
this.requestUpdate();
|
|
164
171
|
if (this.targetTimegroup) this.targetTimegroup.requestUpdate();
|
|
165
172
|
});
|
|
166
173
|
});
|
|
174
|
+
/**
|
|
175
|
+
* Update duration properties when timegroup changes
|
|
176
|
+
*/
|
|
177
|
+
updateDurationProperties() {
|
|
178
|
+
const newDuration = this.targetTimegroup?.durationMs ?? 0;
|
|
179
|
+
const newEndTime = this.targetTimegroup?.endTimeMs ?? 0;
|
|
180
|
+
if (this.durationMs !== newDuration) this.durationMs = newDuration;
|
|
181
|
+
if (this.endTimeMs !== newEndTime) this.endTimeMs = newEndTime;
|
|
182
|
+
}
|
|
167
183
|
connectedCallback() {
|
|
168
184
|
super.connectedCallback();
|
|
169
185
|
this.targetTimegroup = this.querySelector("ef-timegroup");
|
|
186
|
+
this.updateDurationProperties();
|
|
170
187
|
this.#timegroupObserver.observe(this, {
|
|
171
188
|
childList: true,
|
|
172
189
|
subtree: true,
|
|
@@ -187,10 +204,6 @@ function ContextMixin(superClass) {
|
|
|
187
204
|
if (this.isConnected) {
|
|
188
205
|
if (this.targetTimegroup.currentTimeMs === this.currentTimeMs) return;
|
|
189
206
|
this.targetTimegroup.currentTimeMs = this.currentTimeMs;
|
|
190
|
-
this.dispatchEvent(new CustomEvent("timeupdate", { detail: {
|
|
191
|
-
currentTimeMs: this.currentTimeMs,
|
|
192
|
-
progress: this.currentTimeMs / this.targetTimegroup.durationMs
|
|
193
|
-
} }));
|
|
194
207
|
}
|
|
195
208
|
}
|
|
196
209
|
}
|
|
@@ -290,8 +303,8 @@ function ContextMixin(superClass) {
|
|
|
290
303
|
})], ContextElement.prototype, "apiHost", null);
|
|
291
304
|
_decorate([provide({ context: efContext })], ContextElement.prototype, "efContext", void 0);
|
|
292
305
|
_decorate([provide({ context: targetTimegroupContext }), state()], ContextElement.prototype, "targetTimegroup", void 0);
|
|
293
|
-
_decorate([
|
|
294
|
-
_decorate([
|
|
306
|
+
_decorate([provide({ context: durationContext }), property({ type: Number })], ContextElement.prototype, "durationMs", void 0);
|
|
307
|
+
_decorate([property({ type: Number })], ContextElement.prototype, "endTimeMs", void 0);
|
|
295
308
|
_decorate([provide({ context: fetchContext })], ContextElement.prototype, "fetch", void 0);
|
|
296
309
|
_decorate([property({
|
|
297
310
|
type: String,
|
|
@@ -306,7 +319,7 @@ function ContextMixin(superClass) {
|
|
|
306
319
|
reflect: true
|
|
307
320
|
})], ContextElement.prototype, "loop", void 0);
|
|
308
321
|
_decorate([property({ type: Boolean })], ContextElement.prototype, "rendering", void 0);
|
|
309
|
-
_decorate([
|
|
322
|
+
_decorate([provide({ context: currentTimeContext }), property({ type: Number })], ContextElement.prototype, "currentTimeMs", void 0);
|
|
310
323
|
return ContextElement;
|
|
311
324
|
}
|
|
312
325
|
export { ContextMixin, isContextMixin, targetTimegroupContext };
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { ContextMixinInterface } from './ContextMixin.js';
|
|
3
|
+
/**
|
|
4
|
+
* EFControls provides a way to control an ef-preview element that is not a direct ancestor.
|
|
5
|
+
* It bridges the contexts from a target preview element to its children controls.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```html
|
|
9
|
+
* <ef-preview id="my-preview">...</ef-preview>
|
|
10
|
+
*
|
|
11
|
+
* <ef-controls target="my-preview">
|
|
12
|
+
* <ef-toggle-play>
|
|
13
|
+
* <button slot="play">Play</button>
|
|
14
|
+
* <button slot="pause">Pause</button>
|
|
15
|
+
* </ef-toggle-play>
|
|
16
|
+
* <ef-scrubber></ef-scrubber>
|
|
17
|
+
* <ef-time-display></ef-time-display>
|
|
18
|
+
* </ef-controls>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class EFControls extends LitElement {
|
|
22
|
+
#private;
|
|
23
|
+
static styles: import('lit').CSSResult;
|
|
24
|
+
/**
|
|
25
|
+
* The ID of the ef-preview element to control
|
|
26
|
+
*/
|
|
27
|
+
target: string;
|
|
28
|
+
/**
|
|
29
|
+
* The target element (set by TargetController)
|
|
30
|
+
*/
|
|
31
|
+
targetElement: ContextMixinInterface | null;
|
|
32
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
33
|
+
}
|
|
34
|
+
declare global {
|
|
35
|
+
interface HTMLElementTagNameMap {
|
|
36
|
+
"ef-controls": EFControls;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { currentTimeContext } from "./currentTimeContext.js";
|
|
2
|
+
import { durationContext } from "./durationContext.js";
|
|
3
|
+
import { efConfigurationContext } from "./EFConfiguration.js";
|
|
4
|
+
import { efContext } from "./efContext.js";
|
|
5
|
+
import { fetchContext } from "./fetchContext.js";
|
|
6
|
+
import { focusContext } from "./focusContext.js";
|
|
7
|
+
import { focusedElementContext } from "./focusedElementContext.js";
|
|
8
|
+
import { loopContext, playingContext } from "./playingContext.js";
|
|
9
|
+
import { targetTimegroupContext } from "./ContextMixin.js";
|
|
10
|
+
import { TargetController } from "../elements/TargetController.js";
|
|
11
|
+
import { ContextProxyController } from "../elements/ContextProxiesController.js";
|
|
12
|
+
import { LitElement, css, html } from "lit";
|
|
13
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
14
|
+
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
15
|
+
let EFControls = class EFControls$1 extends LitElement {
|
|
16
|
+
constructor(..._args) {
|
|
17
|
+
super(..._args);
|
|
18
|
+
this.target = "";
|
|
19
|
+
this.targetElement = null;
|
|
20
|
+
}
|
|
21
|
+
static {
|
|
22
|
+
this.styles = css`
|
|
23
|
+
:host {
|
|
24
|
+
display: block;
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
#targetController = new TargetController(this);
|
|
29
|
+
#contextProxyController = new ContextProxyController(this, {
|
|
30
|
+
target: () => this.targetElement,
|
|
31
|
+
contexts: [
|
|
32
|
+
playingContext,
|
|
33
|
+
loopContext,
|
|
34
|
+
currentTimeContext,
|
|
35
|
+
durationContext,
|
|
36
|
+
targetTimegroupContext,
|
|
37
|
+
focusedElementContext,
|
|
38
|
+
efContext,
|
|
39
|
+
fetchContext,
|
|
40
|
+
focusContext,
|
|
41
|
+
efConfigurationContext
|
|
42
|
+
]
|
|
43
|
+
});
|
|
44
|
+
render() {
|
|
45
|
+
return html`<slot></slot>`;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
_decorate([property({ type: String })], EFControls.prototype, "target", void 0);
|
|
49
|
+
_decorate([state()], EFControls.prototype, "targetElement", void 0);
|
|
50
|
+
EFControls = _decorate([customElement("ef-controls")], EFControls);
|
|
51
|
+
export { EFControls };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LitElement, nothing, PropertyValueMap, ReactiveController, TemplateResult } from 'lit';
|
|
2
2
|
import { EFAudio } from '../elements/EFAudio.js';
|
|
3
|
+
import { Caption } from '../elements/EFCaptions.js';
|
|
3
4
|
import { EFImage } from '../elements/EFImage.js';
|
|
4
5
|
import { TemporalMixinInterface } from '../elements/EFTemporal.js';
|
|
5
6
|
import { EFTimegroup } from '../elements/EFTimegroup.js';
|
|
@@ -45,7 +46,41 @@ export declare class EFVideoFilmstrip extends FilmstripItem {
|
|
|
45
46
|
contents(): TemplateResult<1>;
|
|
46
47
|
}
|
|
47
48
|
export declare class EFCaptionsFilmstrip extends FilmstripItem {
|
|
48
|
-
|
|
49
|
+
render(): TemplateResult<1>;
|
|
50
|
+
renderCaptionsData(captionsData: Caption | null | undefined): TemplateResult<1>;
|
|
51
|
+
renderChildren(): Array<TemplateResult<1> | typeof nothing> | typeof nothing;
|
|
52
|
+
}
|
|
53
|
+
export declare class EFCaptionsActiveWordFilmstrip extends FilmstripItem {
|
|
54
|
+
get captionsTrackStyles(): {
|
|
55
|
+
position: string;
|
|
56
|
+
left: string;
|
|
57
|
+
width: string;
|
|
58
|
+
};
|
|
59
|
+
render(): TemplateResult<1>;
|
|
60
|
+
}
|
|
61
|
+
export declare class EFCaptionsSegmentFilmstrip extends FilmstripItem {
|
|
62
|
+
get captionsTrackStyles(): {
|
|
63
|
+
position: string;
|
|
64
|
+
left: string;
|
|
65
|
+
width: string;
|
|
66
|
+
};
|
|
67
|
+
render(): TemplateResult<1>;
|
|
68
|
+
}
|
|
69
|
+
export declare class EFCaptionsBeforeWordFilmstrip extends FilmstripItem {
|
|
70
|
+
get captionsTrackStyles(): {
|
|
71
|
+
position: string;
|
|
72
|
+
left: string;
|
|
73
|
+
width: string;
|
|
74
|
+
};
|
|
75
|
+
render(): TemplateResult<1>;
|
|
76
|
+
}
|
|
77
|
+
export declare class EFCaptionsAfterWordFilmstrip extends FilmstripItem {
|
|
78
|
+
get captionsTrackStyles(): {
|
|
79
|
+
position: string;
|
|
80
|
+
left: string;
|
|
81
|
+
width: string;
|
|
82
|
+
};
|
|
83
|
+
render(): TemplateResult<1>;
|
|
49
84
|
}
|
|
50
85
|
export declare class EFWaveformFilmstrip extends FilmstripItem {
|
|
51
86
|
contents(): TemplateResult<1>;
|
|
@@ -147,6 +182,10 @@ declare global {
|
|
|
147
182
|
"ef-audio-filmstrip": EFAudioFilmstrip;
|
|
148
183
|
"ef-video-filmstrip": EFVideoFilmstrip;
|
|
149
184
|
"ef-captions-filmstrip": EFCaptionsFilmstrip;
|
|
185
|
+
"ef-captions-active-word-filmstrip": EFCaptionsActiveWordFilmstrip;
|
|
186
|
+
"ef-captions-segment-filmstrip": EFCaptionsSegmentFilmstrip;
|
|
187
|
+
"ef-captions-before-word-filmstrip": EFCaptionsBeforeWordFilmstrip;
|
|
188
|
+
"ef-captions-after-word-filmstrip": EFCaptionsAfterWordFilmstrip;
|
|
150
189
|
"ef-waveform-filmstrip": EFWaveformFilmstrip;
|
|
151
190
|
"ef-image-filmstrip": EFImageFilmstrip;
|
|
152
191
|
"ef-html-filmstrip": EFHTMLFilmstrip;
|
package/dist/gui/EFFilmstrip.js
CHANGED
|
@@ -162,11 +162,232 @@ let EFVideoFilmstrip = class EFVideoFilmstrip$1 extends FilmstripItem {
|
|
|
162
162
|
};
|
|
163
163
|
EFVideoFilmstrip = _decorate([customElement("ef-video-filmstrip")], EFVideoFilmstrip);
|
|
164
164
|
let EFCaptionsFilmstrip = class EFCaptionsFilmstrip$1 extends FilmstripItem {
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
render() {
|
|
166
|
+
const captions = this.element;
|
|
167
|
+
const captionsData = captions.unifiedCaptionsDataTask.value;
|
|
168
|
+
return html`<div style=${styleMap(this.gutterStyles)}>
|
|
169
|
+
<div
|
|
170
|
+
class="bg-slate-300 relative"
|
|
171
|
+
?data-focused=${this.isFocused}
|
|
172
|
+
@mouseenter=${() => {
|
|
173
|
+
if (this.focusContext) this.focusContext.focusedElement = this.element;
|
|
174
|
+
}}
|
|
175
|
+
@mouseleave=${() => {
|
|
176
|
+
if (this.focusContext) this.focusContext.focusedElement = null;
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
<div
|
|
180
|
+
?data-focused=${this.isFocused}
|
|
181
|
+
class="border-outset relative mb-[1px] block h-[1.1rem] text-nowrap border border-slate-500 bg-blue-200 text-sm data-[focused]:bg-slate-400 overflow-hidden"
|
|
182
|
+
style=${styleMap(this.trimPortionStyles)}
|
|
183
|
+
>
|
|
184
|
+
📝 ${this.renderCaptionsData(captionsData)}
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
${this.renderChildren()}
|
|
188
|
+
</div>`;
|
|
189
|
+
}
|
|
190
|
+
renderCaptionsData(captionsData) {
|
|
191
|
+
if (!captionsData) return html``;
|
|
192
|
+
const captions = this.element;
|
|
193
|
+
const rootTimegroup = captions.rootTimegroup;
|
|
194
|
+
const currentTimeMs = rootTimegroup?.currentTimeMs || 0;
|
|
195
|
+
const captionsLocalTimeMs = currentTimeMs - captions.startTimeMs;
|
|
196
|
+
const captionsLocalTimeSec = captionsLocalTimeMs / 1e3;
|
|
197
|
+
const segmentElements = captionsData.segments.map((segment) => {
|
|
198
|
+
const isActive = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
|
|
199
|
+
return html`<div
|
|
200
|
+
class="absolute border border-slate-600 text-xs overflow-hidden flex items-center ${isActive ? "bg-green-200 border-green-500 font-bold z-[5]" : "bg-slate-100"}"
|
|
201
|
+
style=${styleMap({
|
|
202
|
+
left: `${this.pixelsPerMs * segment.start * 1e3}px`,
|
|
203
|
+
width: `${this.pixelsPerMs * (segment.end - segment.start) * 1e3}px`,
|
|
204
|
+
height: "100%",
|
|
205
|
+
top: "0px"
|
|
206
|
+
})}
|
|
207
|
+
title="Segment: '${segment.text}' (${segment.start}s - ${segment.end}s)"
|
|
208
|
+
>
|
|
209
|
+
<span class="px-0.5 text-[8px] ${isActive ? "font-bold" : ""}">${segment.text}</span>
|
|
210
|
+
</div>`;
|
|
211
|
+
});
|
|
212
|
+
return html`${segmentElements}`;
|
|
213
|
+
}
|
|
214
|
+
renderChildren() {
|
|
215
|
+
return super.renderChildren();
|
|
167
216
|
}
|
|
168
217
|
};
|
|
169
218
|
EFCaptionsFilmstrip = _decorate([customElement("ef-captions-filmstrip")], EFCaptionsFilmstrip);
|
|
219
|
+
let EFCaptionsActiveWordFilmstrip = class EFCaptionsActiveWordFilmstrip$1 extends FilmstripItem {
|
|
220
|
+
get captionsTrackStyles() {
|
|
221
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
222
|
+
return {
|
|
223
|
+
position: "relative",
|
|
224
|
+
left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
|
|
225
|
+
width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
render() {
|
|
229
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
230
|
+
const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
|
|
231
|
+
if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
232
|
+
<div class="bg-slate-300 border border-slate-500 h-[1.1rem] mb-[1px] text-xs">
|
|
233
|
+
🗣️ Active Word
|
|
234
|
+
</div>
|
|
235
|
+
</div>`;
|
|
236
|
+
const rootTimegroup = parentCaptions.rootTimegroup;
|
|
237
|
+
const currentTimeMs = rootTimegroup?.currentTimeMs || 0;
|
|
238
|
+
const captionsLocalTimeMs = currentTimeMs - parentCaptions.startTimeMs;
|
|
239
|
+
const captionsLocalTimeSec = captionsLocalTimeMs / 1e3;
|
|
240
|
+
return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
241
|
+
<div class="bg-slate-300 relative border border-slate-500 h-[1.1rem] mb-[1px] w-full">
|
|
242
|
+
${captionsData.word_segments.map((word) => {
|
|
243
|
+
const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
|
|
244
|
+
return html`<div
|
|
245
|
+
class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "bg-yellow-200 border-yellow-500 font-bold z-[5]" : "bg-blue-50 border-blue-200"}"
|
|
246
|
+
style=${styleMap({
|
|
247
|
+
left: `${this.pixelsPerMs * word.start * 1e3}px`,
|
|
248
|
+
width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
|
|
249
|
+
height: "100%",
|
|
250
|
+
top: "0px"
|
|
251
|
+
})}
|
|
252
|
+
title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
|
|
253
|
+
>
|
|
254
|
+
${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap bg-yellow-200">${word.text.trim()}</span>` : ""}
|
|
255
|
+
</div>`;
|
|
256
|
+
})}
|
|
257
|
+
</div>
|
|
258
|
+
</div>`;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
EFCaptionsActiveWordFilmstrip = _decorate([customElement("ef-captions-active-word-filmstrip")], EFCaptionsActiveWordFilmstrip);
|
|
262
|
+
let EFCaptionsSegmentFilmstrip = class EFCaptionsSegmentFilmstrip$1 extends FilmstripItem {
|
|
263
|
+
get captionsTrackStyles() {
|
|
264
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
265
|
+
return {
|
|
266
|
+
position: "relative",
|
|
267
|
+
left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
|
|
268
|
+
width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
render() {
|
|
272
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
273
|
+
const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
|
|
274
|
+
if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
275
|
+
<div class="bg-slate-300 border border-slate-500 h-[1.1rem] mb-[1px] text-xs">
|
|
276
|
+
📄 Segment
|
|
277
|
+
</div>
|
|
278
|
+
</div>`;
|
|
279
|
+
const rootTimegroup = parentCaptions.rootTimegroup;
|
|
280
|
+
const currentTimeMs = rootTimegroup?.currentTimeMs || 0;
|
|
281
|
+
const captionsLocalTimeMs = currentTimeMs - parentCaptions.startTimeMs;
|
|
282
|
+
const captionsLocalTimeSec = captionsLocalTimeMs / 1e3;
|
|
283
|
+
return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
284
|
+
<div class="bg-slate-300 relative border border-slate-500 h-[1.1rem] mb-[1px] w-full">
|
|
285
|
+
${captionsData.segments.map((segment) => {
|
|
286
|
+
const isCurrentlyActive = captionsLocalTimeSec >= segment.start && captionsLocalTimeSec < segment.end;
|
|
287
|
+
return html`<div
|
|
288
|
+
class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "bg-green-200 border-green-500 font-bold z-[5]" : "bg-green-50 border-green-200"}"
|
|
289
|
+
style=${styleMap({
|
|
290
|
+
left: `${this.pixelsPerMs * segment.start * 1e3}px`,
|
|
291
|
+
width: `${this.pixelsPerMs * (segment.end - segment.start) * 1e3}px`,
|
|
292
|
+
height: "100%",
|
|
293
|
+
top: "0px"
|
|
294
|
+
})}
|
|
295
|
+
title="Segment: '${segment.text}' (${segment.start}s - ${segment.end}s)"
|
|
296
|
+
>
|
|
297
|
+
${isCurrentlyActive ? html`<span class="px-0.5 text-[8px] font-bold whitespace-nowrap bg-green-200">${segment.text}</span>` : ""}
|
|
298
|
+
</div>`;
|
|
299
|
+
})}
|
|
300
|
+
</div>
|
|
301
|
+
</div>`;
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
EFCaptionsSegmentFilmstrip = _decorate([customElement("ef-captions-segment-filmstrip")], EFCaptionsSegmentFilmstrip);
|
|
305
|
+
let EFCaptionsBeforeWordFilmstrip = class EFCaptionsBeforeWordFilmstrip$1 extends FilmstripItem {
|
|
306
|
+
get captionsTrackStyles() {
|
|
307
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
308
|
+
return {
|
|
309
|
+
position: "relative",
|
|
310
|
+
left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
|
|
311
|
+
width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
render() {
|
|
315
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
316
|
+
const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
|
|
317
|
+
if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
318
|
+
<div class="bg-slate-300 border border-slate-500 h-[1.1rem] mb-[1px] text-xs">
|
|
319
|
+
⬅️ Before
|
|
320
|
+
</div>
|
|
321
|
+
</div>`;
|
|
322
|
+
const rootTimegroup = parentCaptions.rootTimegroup;
|
|
323
|
+
const currentTimeMs = rootTimegroup?.currentTimeMs || 0;
|
|
324
|
+
const captionsLocalTimeMs = currentTimeMs - parentCaptions.startTimeMs;
|
|
325
|
+
const captionsLocalTimeSec = captionsLocalTimeMs / 1e3;
|
|
326
|
+
return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
327
|
+
<div class="bg-slate-300 relative border border-slate-500 h-[1.1rem] mb-[1px] w-full">
|
|
328
|
+
${captionsData.word_segments.map((word) => {
|
|
329
|
+
const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
|
|
330
|
+
return html`<div
|
|
331
|
+
class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "bg-yellow-200 border-yellow-500 font-bold z-[5]" : "bg-purple-50 border-purple-200"}"
|
|
332
|
+
style=${styleMap({
|
|
333
|
+
left: `${this.pixelsPerMs * word.start * 1e3}px`,
|
|
334
|
+
width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
|
|
335
|
+
height: "100%",
|
|
336
|
+
top: "0px"
|
|
337
|
+
})}
|
|
338
|
+
title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
|
|
339
|
+
>
|
|
340
|
+
<!-- No text for before tracks - they're redundant -->
|
|
341
|
+
</div>`;
|
|
342
|
+
})}
|
|
343
|
+
</div>
|
|
344
|
+
</div>`;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
EFCaptionsBeforeWordFilmstrip = _decorate([customElement("ef-captions-before-word-filmstrip")], EFCaptionsBeforeWordFilmstrip);
|
|
348
|
+
let EFCaptionsAfterWordFilmstrip = class EFCaptionsAfterWordFilmstrip$1 extends FilmstripItem {
|
|
349
|
+
get captionsTrackStyles() {
|
|
350
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
351
|
+
return {
|
|
352
|
+
position: "relative",
|
|
353
|
+
left: `${this.pixelsPerMs * (parentCaptions?.startTimeWithinParentMs || 0)}px`,
|
|
354
|
+
width: `${this.pixelsPerMs * (parentCaptions?.durationMs || 0)}px`
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
render() {
|
|
358
|
+
const parentCaptions = this.element.closest("ef-captions");
|
|
359
|
+
const captionsData = parentCaptions?.unifiedCaptionsDataTask.value;
|
|
360
|
+
if (!captionsData) return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
361
|
+
<div class="bg-slate-300 border border-slate-500 h-[1.1rem] mb-[1px] text-xs">
|
|
362
|
+
➡️ After
|
|
363
|
+
</div>
|
|
364
|
+
</div>`;
|
|
365
|
+
const rootTimegroup = parentCaptions.rootTimegroup;
|
|
366
|
+
const currentTimeMs = rootTimegroup?.currentTimeMs || 0;
|
|
367
|
+
const captionsLocalTimeMs = currentTimeMs - parentCaptions.startTimeMs;
|
|
368
|
+
const captionsLocalTimeSec = captionsLocalTimeMs / 1e3;
|
|
369
|
+
return html`<div style=${styleMap(this.captionsTrackStyles)}>
|
|
370
|
+
<div class="bg-slate-300 relative border border-slate-500 h-[1.1rem] mb-[1px] w-full">
|
|
371
|
+
${captionsData.word_segments.map((word) => {
|
|
372
|
+
const isCurrentlyActive = captionsLocalTimeSec >= word.start && captionsLocalTimeSec < word.end;
|
|
373
|
+
return html`<div
|
|
374
|
+
class="absolute border text-xs overflow-visible flex items-center ${isCurrentlyActive ? "bg-yellow-200 border-yellow-500 font-bold z-[5]" : "bg-purple-50 border-purple-200"}"
|
|
375
|
+
style=${styleMap({
|
|
376
|
+
left: `${this.pixelsPerMs * word.start * 1e3}px`,
|
|
377
|
+
width: `${this.pixelsPerMs * (word.end - word.start) * 1e3}px`,
|
|
378
|
+
height: "100%",
|
|
379
|
+
top: "0px"
|
|
380
|
+
})}
|
|
381
|
+
title="Word: '${word.text}' (${word.start}s - ${word.end}s)"
|
|
382
|
+
>
|
|
383
|
+
<!-- No text for after tracks - they're redundant -->
|
|
384
|
+
</div>`;
|
|
385
|
+
})}
|
|
386
|
+
</div>
|
|
387
|
+
</div>`;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
EFCaptionsAfterWordFilmstrip = _decorate([customElement("ef-captions-after-word-filmstrip")], EFCaptionsAfterWordFilmstrip);
|
|
170
391
|
let EFWaveformFilmstrip = class EFWaveformFilmstrip$1 extends FilmstripItem {
|
|
171
392
|
contents() {
|
|
172
393
|
return html` 🌊 `;
|
|
@@ -369,6 +590,22 @@ const renderFilmstripChildren = (children, pixelsPerMs) => {
|
|
|
369
590
|
.element=${child}
|
|
370
591
|
.pixelsPerMs=${pixelsPerMs}
|
|
371
592
|
></ef-captions-filmstrip>`;
|
|
593
|
+
if (child instanceof EFCaptionsActiveWord) return html`<ef-captions-active-word-filmstrip
|
|
594
|
+
.element=${child}
|
|
595
|
+
.pixelsPerMs=${pixelsPerMs}
|
|
596
|
+
></ef-captions-active-word-filmstrip>`;
|
|
597
|
+
if (child.tagName === "EF-CAPTIONS-SEGMENT") return html`<ef-captions-segment-filmstrip
|
|
598
|
+
.element=${child}
|
|
599
|
+
.pixelsPerMs=${pixelsPerMs}
|
|
600
|
+
></ef-captions-segment-filmstrip>`;
|
|
601
|
+
if (child.tagName === "EF-CAPTIONS-BEFORE-ACTIVE-WORD") return html`<ef-captions-before-word-filmstrip
|
|
602
|
+
.element=${child}
|
|
603
|
+
.pixelsPerMs=${pixelsPerMs}
|
|
604
|
+
></ef-captions-before-word-filmstrip>`;
|
|
605
|
+
if (child.tagName === "EF-CAPTIONS-AFTER-ACTIVE-WORD") return html`<ef-captions-after-word-filmstrip
|
|
606
|
+
.element=${child}
|
|
607
|
+
.pixelsPerMs=${pixelsPerMs}
|
|
608
|
+
></ef-captions-after-word-filmstrip>`;
|
|
372
609
|
if (child instanceof EFWaveform) return html`<ef-waveform-filmstrip
|
|
373
610
|
.element=${child}
|
|
374
611
|
.pixelsPerMs=${pixelsPerMs}
|
|
@@ -551,7 +788,7 @@ let EFFilmstrip = class EFFilmstrip$1 extends TWMixin(LitElement) {
|
|
|
551
788
|
@mousedown=${this.startScrub}
|
|
552
789
|
>
|
|
553
790
|
<div
|
|
554
|
-
class="border-red pointer-events-none absolute z-
|
|
791
|
+
class="border-red pointer-events-none absolute z-[20] h-full w-[2px] border-r-2 border-red-700"
|
|
555
792
|
style=${styleMap({
|
|
556
793
|
left: `${this.pixelsPerMs * this.currentTimeMs}px`,
|
|
557
794
|
top: `${this.timelineScrolltop}px`
|
package/dist/gui/EFPreview.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { focusedElementContext } from "./focusedElementContext.js";
|
|
2
2
|
import { ContextMixin } from "./ContextMixin.js";
|
|
3
|
+
import { EFTargetable } from "../elements/TargetController.js";
|
|
3
4
|
import { TWMixin } from "./TWMixin2.js";
|
|
4
5
|
import { provide } from "@lit/context";
|
|
5
6
|
import { LitElement, css, html } from "lit";
|
|
6
7
|
import { customElement } from "lit/decorators.js";
|
|
7
8
|
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
8
|
-
let EFPreview = class EFPreview$1 extends ContextMixin(TWMixin(LitElement)) {
|
|
9
|
+
let EFPreview = class EFPreview$1 extends EFTargetable(ContextMixin(TWMixin(LitElement))) {
|
|
9
10
|
static {
|
|
10
11
|
this.styles = [css`
|
|
11
12
|
:host {
|
package/dist/gui/EFScrubber.d.ts
CHANGED
|
@@ -4,14 +4,15 @@ export declare class EFScrubber extends LitElement {
|
|
|
4
4
|
static styles: import('lit').CSSResult[];
|
|
5
5
|
context?: ContextMixinInterface | null;
|
|
6
6
|
playing: boolean;
|
|
7
|
-
|
|
7
|
+
currentTimeMs: number;
|
|
8
|
+
durationMs: number;
|
|
8
9
|
private scrubProgress;
|
|
9
|
-
private
|
|
10
|
+
private isMoving;
|
|
10
11
|
private scrubberRef?;
|
|
11
12
|
private updateProgress;
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
private
|
|
13
|
+
private boundHandlePointerDown;
|
|
14
|
+
private boundHandlePointerMove;
|
|
15
|
+
private boundHandlePointerUp;
|
|
15
16
|
render(): import('lit-html').TemplateResult<1>;
|
|
16
17
|
connectedCallback(): void;
|
|
17
18
|
disconnectedCallback(): void;
|