@editframe/elements 0.11.0-beta.1 → 0.11.0-beta.14
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/EF_FRAMEGEN.d.ts +8 -15
- package/dist/elements/EFMedia.d.ts +2 -2
- package/dist/elements/EFTemporal.browsertest.d.ts +10 -0
- package/dist/elements/EFTemporal.d.ts +10 -2
- package/dist/elements/EFTimegroup.browsertest.d.ts +4 -0
- package/dist/elements/EFTimegroup.d.ts +12 -1
- package/dist/elements/EFWaveform.d.ts +3 -3
- package/dist/elements/durationConverter.d.ts +4 -0
- package/dist/elements/src/EF_FRAMEGEN.js +24 -26
- package/dist/elements/src/elements/EFImage.js +3 -7
- package/dist/elements/src/elements/EFMedia.js +27 -9
- package/dist/elements/src/elements/EFTemporal.js +106 -13
- package/dist/elements/src/elements/EFTimegroup.js +26 -5
- package/dist/elements/src/elements/EFVideo.js +7 -7
- package/dist/elements/src/elements/EFWaveform.js +14 -8
- package/dist/elements/src/gui/ContextMixin.js +22 -6
- package/dist/elements/src/gui/EFFilmstrip.js +28 -8
- package/dist/elements/src/gui/EFTogglePlay.js +38 -6
- package/dist/elements/src/gui/EFWorkbench.js +1 -24
- package/dist/elements/src/gui/TWMixin.css.js +1 -1
- package/dist/gui/ContextMixin.d.ts +1 -0
- package/dist/gui/EFFilmstrip.d.ts +4 -4
- package/dist/gui/EFTogglePlay.d.ts +4 -0
- package/dist/gui/EFWorkbench.d.ts +0 -1
- package/dist/style.css +15 -4
- package/package.json +2 -2
- package/src/elements/EFImage.ts +4 -8
- package/src/elements/EFMedia.browsertest.ts +231 -2
- package/src/elements/EFMedia.ts +48 -9
- package/src/elements/EFTemporal.browsertest.ts +79 -0
- package/src/elements/EFTemporal.ts +139 -6
- package/src/elements/EFTimegroup.browsertest.ts +38 -1
- package/src/elements/EFTimegroup.ts +28 -5
- package/src/elements/EFVideo.ts +7 -8
- package/src/elements/EFWaveform.ts +14 -9
- package/src/elements/durationConverter.ts +4 -0
- package/src/gui/ContextMixin.browsertest.ts +28 -2
- package/src/gui/ContextMixin.ts +25 -7
- package/src/gui/EFFilmstrip.ts +37 -17
- package/src/gui/EFTogglePlay.ts +38 -7
- package/src/gui/EFWorkbench.ts +3 -36
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { LitElement, html, css, type PropertyValueMap } from "lit";
|
|
2
1
|
import { provide } from "@lit/context";
|
|
3
2
|
import { Task } from "@lit/task";
|
|
4
|
-
import { customElement, property } from "lit/decorators.js";
|
|
5
3
|
import debug from "debug";
|
|
4
|
+
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
5
|
+
import { customElement, property } from "lit/decorators.js";
|
|
6
6
|
|
|
7
|
+
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
8
|
+
import { isContextMixin } from "../gui/ContextMixin.ts";
|
|
9
|
+
import { deepGetMediaElements } from "./EFMedia.ts";
|
|
7
10
|
import {
|
|
8
11
|
EFTemporal,
|
|
9
12
|
isEFTemporal,
|
|
@@ -11,8 +14,6 @@ import {
|
|
|
11
14
|
timegroupContext,
|
|
12
15
|
} from "./EFTemporal.ts";
|
|
13
16
|
import { TimegroupController } from "./TimegroupController.ts";
|
|
14
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
15
|
-
import { deepGetMediaElements } from "./EFMedia.ts";
|
|
16
17
|
import { durationConverter } from "./durationConverter.ts";
|
|
17
18
|
|
|
18
19
|
const log = debug("ef:elements:EFTimegroup");
|
|
@@ -243,12 +244,34 @@ export class EFTimegroup extends EFTemporal(LitElement) {
|
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
246
|
|
|
247
|
+
get contextProvider() {
|
|
248
|
+
let parent = this.parentNode;
|
|
249
|
+
while (parent) {
|
|
250
|
+
if (isContextMixin(parent)) {
|
|
251
|
+
return parent;
|
|
252
|
+
}
|
|
253
|
+
parent = parent.parentNode;
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Returns true if the timegroup should be wrapped with a workbench.
|
|
260
|
+
*
|
|
261
|
+
* A timegroup should be wrapped with a workbench if it is the root-most timegroup
|
|
262
|
+
* and EF_INTERACTIVE is true.
|
|
263
|
+
*
|
|
264
|
+
* If the timegroup is already wrappedin a context provider like ef-preview,
|
|
265
|
+
* it should NOT be wrapped in a workbench.
|
|
266
|
+
*
|
|
267
|
+
*/
|
|
246
268
|
shouldWrapWithWorkbench() {
|
|
247
269
|
return (
|
|
248
270
|
EF_INTERACTIVE &&
|
|
249
271
|
this.closest("ef-timegroup") === this &&
|
|
272
|
+
this.closest("ef-preview") === null &&
|
|
250
273
|
this.closest("ef-workbench") === null &&
|
|
251
|
-
this.closest("
|
|
274
|
+
this.closest("test-context") === null
|
|
252
275
|
);
|
|
253
276
|
}
|
|
254
277
|
|
package/src/elements/EFVideo.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { html, css } from "lit";
|
|
2
1
|
import { Task } from "@lit/task";
|
|
3
|
-
import {
|
|
2
|
+
import { css, html } from "lit";
|
|
4
3
|
import { customElement } from "lit/decorators.js";
|
|
4
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
5
|
|
|
6
|
-
import { EFMedia } from "./EFMedia.ts";
|
|
7
6
|
import { TWMixin } from "../gui/TWMixin.ts";
|
|
7
|
+
import { EFMedia } from "./EFMedia.ts";
|
|
8
8
|
|
|
9
9
|
@customElement("ef-video")
|
|
10
10
|
export class EFVideo extends TWMixin(EFMedia) {
|
|
@@ -13,15 +13,14 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
13
13
|
:host {
|
|
14
14
|
display: block;
|
|
15
15
|
}
|
|
16
|
+
canvas {
|
|
17
|
+
all: inherit;
|
|
18
|
+
}
|
|
16
19
|
`,
|
|
17
20
|
];
|
|
18
21
|
canvasRef = createRef<HTMLCanvasElement>();
|
|
19
|
-
|
|
20
22
|
render() {
|
|
21
|
-
return html` <canvas
|
|
22
|
-
class="h-full w-full object-fill"
|
|
23
|
-
${ref(this.canvasRef)}
|
|
24
|
-
></canvas>`;
|
|
23
|
+
return html` <canvas ${ref(this.canvasRef)}></canvas>`;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
get canvasElement() {
|
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
import { EFAudio } from "./EFAudio.ts";
|
|
2
2
|
|
|
3
|
-
import { LitElement, html } from "lit";
|
|
4
|
-
import { customElement, property } from "lit/decorators.js";
|
|
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
3
|
import { Task } from "@lit/task";
|
|
10
4
|
import * as d3 from "d3";
|
|
5
|
+
import { LitElement, css, html } from "lit";
|
|
6
|
+
import { customElement, property } from "lit/decorators.js";
|
|
11
7
|
import { type Ref, createRef, ref } from "lit/directives/ref.js";
|
|
12
8
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.ts";
|
|
9
|
+
import { TWMixin } from "../gui/TWMixin.ts";
|
|
10
|
+
import { CrossUpdateController } from "./CrossUpdateController.ts";
|
|
11
|
+
import { EFTemporal } from "./EFTemporal.ts";
|
|
12
|
+
import { EFVideo } from "./EFVideo.ts";
|
|
13
13
|
|
|
14
14
|
@customElement("ef-waveform")
|
|
15
15
|
export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
16
|
-
static styles = [
|
|
16
|
+
static styles = [
|
|
17
|
+
css`
|
|
18
|
+
svg {
|
|
19
|
+
all: inherit;
|
|
20
|
+
}
|
|
21
|
+
`,
|
|
22
|
+
];
|
|
17
23
|
svgRef: Ref<SVGElement> = createRef();
|
|
18
24
|
createRenderRoot() {
|
|
19
25
|
return this;
|
|
20
26
|
}
|
|
21
27
|
render() {
|
|
22
|
-
return html` <svg ${ref(this.svgRef)}
|
|
28
|
+
return html` <svg ${ref(this.svgRef)} store></svg> `;
|
|
23
29
|
}
|
|
24
|
-
|
|
25
30
|
@property({
|
|
26
31
|
type: String,
|
|
27
32
|
attribute: "mode",
|
|
@@ -24,3 +24,7 @@ export const trimDurationConverter = positiveDurationConverter(
|
|
|
24
24
|
export const imageDurationConverter = positiveDurationConverter(
|
|
25
25
|
"Image duration must be a positive value in milliseconds or seconds (1s, 1000ms)",
|
|
26
26
|
);
|
|
27
|
+
|
|
28
|
+
export const sourceDurationConverter = positiveDurationConverter(
|
|
29
|
+
"Sourcein & sourceout must be a positive value in milliseconds or seconds (1s, 1000ms)",
|
|
30
|
+
);
|
|
@@ -2,10 +2,13 @@ import { LitElement } from "lit";
|
|
|
2
2
|
import { customElement } from "lit/decorators/custom-element.js";
|
|
3
3
|
import { describe, expect, test, vi } from "vitest";
|
|
4
4
|
|
|
5
|
-
import { ContextMixin } from "./ContextMixin.ts";
|
|
6
5
|
import { consume } from "@lit/context";
|
|
6
|
+
import { ContextMixin } from "./ContextMixin.ts";
|
|
7
7
|
import { apiHostContext } from "./apiHostContext.ts";
|
|
8
8
|
|
|
9
|
+
// Required to test timeupdate event, we need a duration, and timegroups are a quick way to do that
|
|
10
|
+
import "../elements/EFTimegroup.ts";
|
|
11
|
+
|
|
9
12
|
@customElement("test-context")
|
|
10
13
|
class TestContext extends ContextMixin(LitElement) {}
|
|
11
14
|
|
|
@@ -49,7 +52,6 @@ describe("ContextMixin", () => {
|
|
|
49
52
|
expect(element.apiHost).toBe("test2");
|
|
50
53
|
});
|
|
51
54
|
});
|
|
52
|
-
|
|
53
55
|
describe("Playback", () => {
|
|
54
56
|
test("should start playback", () => {
|
|
55
57
|
const element = document.createElement("test-context");
|
|
@@ -78,4 +80,28 @@ describe("ContextMixin", () => {
|
|
|
78
80
|
expect(playbackSpy).toHaveBeenCalled();
|
|
79
81
|
});
|
|
80
82
|
});
|
|
83
|
+
|
|
84
|
+
test("Time update event when the currentTimeMs changed", async () => {
|
|
85
|
+
const timegroup = document.createElement("ef-timegroup");
|
|
86
|
+
timegroup.mode = "fixed";
|
|
87
|
+
timegroup.duration = "10s";
|
|
88
|
+
|
|
89
|
+
const preview = document.createElement("test-context");
|
|
90
|
+
preview.append(timegroup);
|
|
91
|
+
document.body.append(preview);
|
|
92
|
+
|
|
93
|
+
type CurrentTimeEvent = CustomEvent<{ currentTimeMs: number }>;
|
|
94
|
+
|
|
95
|
+
// Expect the timeupdate event to be dispatched
|
|
96
|
+
const timeupdatePromise = new Promise<CurrentTimeEvent>((resolve) => {
|
|
97
|
+
preview.addEventListener(
|
|
98
|
+
"timeupdate",
|
|
99
|
+
(event: Event) => resolve(event as CurrentTimeEvent),
|
|
100
|
+
{ once: true },
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
preview.currentTimeMs = 1000;
|
|
104
|
+
const event = await timeupdatePromise;
|
|
105
|
+
expect(event.detail.currentTimeMs).toBe(1000);
|
|
106
|
+
});
|
|
81
107
|
});
|
package/src/gui/ContextMixin.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { LitElement } from "lit";
|
|
2
1
|
import { provide } from "@lit/context";
|
|
2
|
+
import type { LitElement } from "lit";
|
|
3
3
|
import { property, state } from "lit/decorators.js";
|
|
4
4
|
|
|
5
|
-
import { focusContext, type FocusContext } from "./focusContext.ts";
|
|
6
|
-
import { focusedElementContext } from "./focusedElementContext.ts";
|
|
7
|
-
import { fetchContext } from "./fetchContext.ts";
|
|
8
5
|
import { createRef } from "lit/directives/ref.js";
|
|
9
|
-
import { loopContext, playingContext } from "./playingContext.ts";
|
|
10
6
|
import type { EFTimegroup } from "../elements/EFTimegroup.ts";
|
|
11
|
-
import { efContext } from "./efContext.ts";
|
|
12
7
|
import { apiHostContext } from "./apiHostContext.ts";
|
|
8
|
+
import { efContext } from "./efContext.ts";
|
|
9
|
+
import { fetchContext } from "./fetchContext.ts";
|
|
10
|
+
import { type FocusContext, focusContext } from "./focusContext.ts";
|
|
11
|
+
import { focusedElementContext } from "./focusedElementContext.ts";
|
|
12
|
+
import { loopContext, playingContext } from "./playingContext.ts";
|
|
13
13
|
|
|
14
14
|
export declare class ContextMixinInterface {
|
|
15
15
|
signingURL?: string;
|
|
@@ -26,9 +26,21 @@ export declare class ContextMixinInterface {
|
|
|
26
26
|
pause(): void;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
const contextMixinSymbol = Symbol("contextMixin");
|
|
30
|
+
|
|
31
|
+
export function isContextMixin(value: any): value is ContextMixinInterface {
|
|
32
|
+
return (
|
|
33
|
+
typeof value === "object" &&
|
|
34
|
+
value !== null &&
|
|
35
|
+
contextMixinSymbol in value.constructor
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
type Constructor<T = {}> = new (...args: any[]) => T;
|
|
30
40
|
export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
|
|
31
41
|
class ContextElement extends superClass {
|
|
42
|
+
static [contextMixinSymbol] = true;
|
|
43
|
+
|
|
32
44
|
@provide({ context: focusContext })
|
|
33
45
|
focusContext = this as FocusContext;
|
|
34
46
|
|
|
@@ -164,10 +176,16 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
|
|
|
164
176
|
this.stopPlayback();
|
|
165
177
|
}
|
|
166
178
|
}
|
|
167
|
-
|
|
168
179
|
if (changedProperties.has("currentTimeMs") && this.targetTimegroup) {
|
|
169
180
|
if (this.targetTimegroup.currentTimeMs !== this.currentTimeMs) {
|
|
170
181
|
this.targetTimegroup.currentTimeMs = this.currentTimeMs;
|
|
182
|
+
if (this.isConnected) {
|
|
183
|
+
this.dispatchEvent(
|
|
184
|
+
new CustomEvent("timeupdate", {
|
|
185
|
+
detail: { currentTimeMs: this.currentTimeMs },
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
171
189
|
}
|
|
172
190
|
}
|
|
173
191
|
super.update(changedProperties);
|
package/src/gui/EFFilmstrip.ts
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
+
import { consume } from "@lit/context";
|
|
1
2
|
import {
|
|
2
3
|
LitElement,
|
|
3
|
-
|
|
4
|
+
type PropertyValueMap,
|
|
5
|
+
type ReactiveController,
|
|
6
|
+
type TemplateResult,
|
|
4
7
|
css,
|
|
8
|
+
html,
|
|
5
9
|
nothing,
|
|
6
|
-
type TemplateResult,
|
|
7
|
-
type ReactiveController,
|
|
8
|
-
type PropertyValueMap,
|
|
9
10
|
} from "lit";
|
|
10
11
|
import {
|
|
11
12
|
customElement,
|
|
12
|
-
property,
|
|
13
13
|
eventOptions,
|
|
14
|
+
property,
|
|
14
15
|
state,
|
|
15
16
|
} from "lit/decorators.js";
|
|
16
|
-
import {
|
|
17
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
17
18
|
import { styleMap } from "lit/directives/style-map.js";
|
|
18
|
-
import { ref, createRef } from "lit/directives/ref.js";
|
|
19
19
|
|
|
20
|
-
import { EFImage } from "../elements/EFImage.ts";
|
|
21
20
|
import { EFAudio } from "../elements/EFAudio.ts";
|
|
22
|
-
import { EFVideo } from "../elements/EFVideo.ts";
|
|
23
21
|
import { EFCaptions, EFCaptionsActiveWord } from "../elements/EFCaptions.ts";
|
|
24
|
-
import {
|
|
25
|
-
import { EFTimegroup } from "../elements/EFTimegroup.ts";
|
|
22
|
+
import { EFImage } from "../elements/EFImage.ts";
|
|
26
23
|
import type { TemporalMixinInterface } from "../elements/EFTemporal.ts";
|
|
24
|
+
import { EFTimegroup } from "../elements/EFTimegroup.ts";
|
|
25
|
+
import { EFVideo } from "../elements/EFVideo.ts";
|
|
26
|
+
import { EFWaveform } from "../elements/EFWaveform.ts";
|
|
27
27
|
import { TimegroupController } from "../elements/TimegroupController.ts";
|
|
28
|
-
import { TWMixin } from "./TWMixin.ts";
|
|
29
28
|
import { msToTimeCode } from "../msToTimeCode.ts";
|
|
30
|
-
import { focusedElementContext } from "./focusedElementContext.ts";
|
|
31
|
-
import { type FocusContext, focusContext } from "./focusContext.ts";
|
|
32
|
-
import { playingContext, loopContext } from "./playingContext.ts";
|
|
33
|
-
import type { EFWorkbench } from "./EFWorkbench.ts";
|
|
34
29
|
import type { EFPreview } from "./EFPreview.ts";
|
|
30
|
+
import type { EFWorkbench } from "./EFWorkbench.ts";
|
|
31
|
+
import { TWMixin } from "./TWMixin.ts";
|
|
32
|
+
import { type FocusContext, focusContext } from "./focusContext.ts";
|
|
33
|
+
import { focusedElementContext } from "./focusedElementContext.ts";
|
|
34
|
+
import { loopContext, playingContext } from "./playingContext.ts";
|
|
35
35
|
|
|
36
36
|
class ElementFilmstripController implements ReactiveController {
|
|
37
37
|
constructor(
|
|
@@ -87,6 +87,13 @@ class FilmstripItem extends TWMixin(LitElement) {
|
|
|
87
87
|
pixelsPerMs = 0.04;
|
|
88
88
|
|
|
89
89
|
get gutterStyles() {
|
|
90
|
+
if (this.element.sourceInMs || this.element.sourceOutMs) {
|
|
91
|
+
return {
|
|
92
|
+
position: "relative",
|
|
93
|
+
left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs - this.element.sourceInMs)}px`,
|
|
94
|
+
width: `${this.pixelsPerMs * (this.element.durationMs + this.element.trimStartMs + this.element.trimEndMs + this.element.sourceOutMs + this.element.sourceInMs)}px`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
90
97
|
return {
|
|
91
98
|
position: "relative",
|
|
92
99
|
left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs)}px`,
|
|
@@ -95,6 +102,12 @@ class FilmstripItem extends TWMixin(LitElement) {
|
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
get trimPortionStyles() {
|
|
105
|
+
if (this.element.sourceInMs || this.element.sourceOutMs) {
|
|
106
|
+
return {
|
|
107
|
+
width: `${this.pixelsPerMs * this.element.durationMs}px`,
|
|
108
|
+
left: `${this.pixelsPerMs * (this.element.trimStartMs + this.element.sourceInMs)}px`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
98
111
|
return {
|
|
99
112
|
width: `${this.pixelsPerMs * this.element.durationMs}px`,
|
|
100
113
|
left: `${this.pixelsPerMs * this.element.trimStartMs}px`,
|
|
@@ -694,7 +707,14 @@ export class EFFilmstrip extends TWMixin(LitElement) {
|
|
|
694
707
|
/>
|
|
695
708
|
<code>${msToTimeCode(this.currentTimeMs, true)} </code> /
|
|
696
709
|
<code>${msToTimeCode(target?.durationMs ?? 0, true)}</code>
|
|
697
|
-
<ef-toggle-play
|
|
710
|
+
<ef-toggle-play class="inline-block mx-2">
|
|
711
|
+
<div slot="pause">
|
|
712
|
+
<button class="bg-white">▶</button>
|
|
713
|
+
</div>
|
|
714
|
+
<div slot="play">
|
|
715
|
+
<button>⏸️</button>
|
|
716
|
+
</div>
|
|
717
|
+
</ef-toggle-play>
|
|
698
718
|
<ef-toggle-loop><button>${this.loop ? "🔁" : html`<span class="opacity-50">🔁</span>`}</button></ef-toggle-loop>
|
|
699
719
|
</div>
|
|
700
720
|
<div
|
package/src/gui/EFTogglePlay.ts
CHANGED
|
@@ -1,33 +1,64 @@
|
|
|
1
|
-
import { css, html, LitElement } from "lit";
|
|
2
|
-
import { customElement } from "lit/decorators.js";
|
|
3
1
|
import { consume } from "@lit/context";
|
|
2
|
+
import { LitElement, css, html } from "lit";
|
|
3
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
4
4
|
|
|
5
|
-
import { efContext } from "./efContext.ts";
|
|
6
5
|
import type { ContextMixinInterface } from "./ContextMixin.ts";
|
|
6
|
+
import { efContext } from "./efContext.ts";
|
|
7
7
|
|
|
8
8
|
@customElement("ef-toggle-play")
|
|
9
9
|
export class EFTogglePlay extends LitElement {
|
|
10
10
|
static styles = [
|
|
11
11
|
css`
|
|
12
12
|
:host {}
|
|
13
|
+
div {
|
|
14
|
+
all: inherit;
|
|
15
|
+
}
|
|
13
16
|
`,
|
|
14
17
|
];
|
|
15
18
|
|
|
16
|
-
@consume({ context: efContext })
|
|
19
|
+
@consume({ context: efContext, subscribe: true })
|
|
17
20
|
context?: ContextMixinInterface | null;
|
|
18
21
|
|
|
22
|
+
@property({ type: String })
|
|
23
|
+
play = '<button class="text-2xl cursor-pointer">▶️</button>';
|
|
24
|
+
|
|
25
|
+
@property({ type: String })
|
|
26
|
+
pause = '<button class="text-2xl cursor-pointer">⏸️</button>';
|
|
27
|
+
|
|
28
|
+
@state()
|
|
29
|
+
playing = false;
|
|
30
|
+
|
|
19
31
|
render() {
|
|
20
32
|
return html`
|
|
21
|
-
<
|
|
33
|
+
<div
|
|
34
|
+
@click=${() => {
|
|
22
35
|
if (this.context) {
|
|
23
36
|
if (this.context.playing) {
|
|
24
37
|
this.context.pause();
|
|
38
|
+
this.playing = false;
|
|
25
39
|
} else {
|
|
26
40
|
this.context.play();
|
|
41
|
+
this.playing = true;
|
|
27
42
|
}
|
|
28
43
|
}
|
|
29
|
-
}}
|
|
30
|
-
|
|
44
|
+
}}>
|
|
45
|
+
${
|
|
46
|
+
this.playing
|
|
47
|
+
? html`<slot name="play"></slot>`
|
|
48
|
+
: html`<slot name="pause"></slot>`
|
|
49
|
+
}
|
|
50
|
+
</div>`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
togglePlay() {
|
|
54
|
+
this.requestUpdate();
|
|
55
|
+
if (this.context) {
|
|
56
|
+
if (this.context.playing) {
|
|
57
|
+
this.context.pause();
|
|
58
|
+
} else {
|
|
59
|
+
this.context.play();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
31
62
|
}
|
|
32
63
|
}
|
|
33
64
|
|
package/src/gui/EFWorkbench.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { LitElement,
|
|
2
|
-
import { TaskStatus } from "@lit/task";
|
|
1
|
+
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
3
2
|
import { customElement, eventOptions } from "lit/decorators.js";
|
|
4
|
-
import {
|
|
3
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
4
|
|
|
6
|
-
import { deepGetTemporalElements } from "../elements/EFTemporal.ts";
|
|
7
|
-
import { TWMixin } from "./TWMixin.ts";
|
|
8
|
-
import { shallowGetTimegroups } from "../elements/EFTimegroup.ts";
|
|
9
5
|
import { ContextMixin } from "./ContextMixin.ts";
|
|
6
|
+
import { TWMixin } from "./TWMixin.ts";
|
|
10
7
|
|
|
11
8
|
@customElement("ef-workbench")
|
|
12
9
|
export class EFWorkbench extends ContextMixin(TWMixin(LitElement)) {
|
|
@@ -96,36 +93,6 @@ export class EFWorkbench extends ContextMixin(TWMixin(LitElement)) {
|
|
|
96
93
|
</div>
|
|
97
94
|
`;
|
|
98
95
|
}
|
|
99
|
-
|
|
100
|
-
async stepThrough() {
|
|
101
|
-
const stepDurationMs = 1000 / 30;
|
|
102
|
-
const timegroups = shallowGetTimegroups(this);
|
|
103
|
-
const firstGroup = timegroups[0];
|
|
104
|
-
if (!firstGroup) {
|
|
105
|
-
throw new Error("No temporal elements found");
|
|
106
|
-
}
|
|
107
|
-
firstGroup.currentTimeMs = 0;
|
|
108
|
-
|
|
109
|
-
const temporals = deepGetTemporalElements(this);
|
|
110
|
-
const frameCount = Math.ceil(firstGroup.durationMs / stepDurationMs);
|
|
111
|
-
|
|
112
|
-
const busyTasks = temporals
|
|
113
|
-
.filter((temporal) => temporal.frameTask.status < TaskStatus.COMPLETE)
|
|
114
|
-
.map((temporal) => temporal.frameTask);
|
|
115
|
-
|
|
116
|
-
await Promise.all(busyTasks.map((task) => task.taskComplete));
|
|
117
|
-
|
|
118
|
-
for (let i = 0; i < frameCount; i++) {
|
|
119
|
-
firstGroup.currentTimeMs = i * stepDurationMs;
|
|
120
|
-
await new Promise<void>(queueMicrotask);
|
|
121
|
-
const busyTasks = temporals
|
|
122
|
-
.filter((temporal) => temporal.frameTask.status < TaskStatus.COMPLETE)
|
|
123
|
-
.map((temporal) => temporal.frameTask);
|
|
124
|
-
|
|
125
|
-
await Promise.all(busyTasks.map((task) => task.taskComplete));
|
|
126
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
96
|
}
|
|
130
97
|
|
|
131
98
|
declare global {
|