@editframe/elements 0.15.0-beta.9 → 0.16.0-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.
Files changed (52) hide show
  1. package/dist/EF_FRAMEGEN.d.ts +14 -10
  2. package/dist/EF_FRAMEGEN.js +17 -28
  3. package/dist/elements/EFCaptions.js +0 -7
  4. package/dist/elements/EFImage.js +0 -4
  5. package/dist/elements/EFMedia.d.ts +13 -8
  6. package/dist/elements/EFMedia.js +164 -146
  7. package/dist/elements/EFSourceMixin.js +2 -1
  8. package/dist/elements/EFTemporal.browsertest.d.ts +4 -3
  9. package/dist/elements/EFTemporal.d.ts +14 -11
  10. package/dist/elements/EFTemporal.js +63 -87
  11. package/dist/elements/EFTimegroup.d.ts +2 -4
  12. package/dist/elements/EFTimegroup.js +15 -103
  13. package/dist/elements/EFVideo.js +3 -1
  14. package/dist/elements/EFWaveform.d.ts +1 -1
  15. package/dist/elements/EFWaveform.js +11 -28
  16. package/dist/elements/durationConverter.d.ts +8 -8
  17. package/dist/elements/durationConverter.js +2 -2
  18. package/dist/elements/updateAnimations.d.ts +9 -0
  19. package/dist/elements/updateAnimations.js +62 -0
  20. package/dist/getRenderInfo.d.ts +51 -0
  21. package/dist/getRenderInfo.js +72 -0
  22. package/dist/gui/EFFilmstrip.js +7 -16
  23. package/dist/gui/EFFitScale.d.ts +27 -0
  24. package/dist/gui/EFFitScale.js +138 -0
  25. package/dist/gui/EFWorkbench.d.ts +2 -5
  26. package/dist/gui/EFWorkbench.js +13 -56
  27. package/dist/gui/TWMixin.css.js +1 -1
  28. package/dist/gui/TWMixin.js +14 -2
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +6 -1
  31. package/dist/style.css +3 -3
  32. package/package.json +4 -3
  33. package/src/elements/EFCaptions.browsertest.ts +2 -2
  34. package/src/elements/EFCaptions.ts +0 -7
  35. package/src/elements/EFImage.browsertest.ts +2 -2
  36. package/src/elements/EFImage.ts +0 -4
  37. package/src/elements/EFMedia.browsertest.ts +14 -14
  38. package/src/elements/EFMedia.ts +220 -182
  39. package/src/elements/EFSourceMixin.ts +4 -4
  40. package/src/elements/EFTemporal.browsertest.ts +64 -31
  41. package/src/elements/EFTemporal.ts +99 -119
  42. package/src/elements/EFTimegroup.ts +15 -133
  43. package/src/elements/EFVideo.ts +3 -1
  44. package/src/elements/EFWaveform.ts +10 -44
  45. package/src/elements/durationConverter.ts +9 -4
  46. package/src/elements/updateAnimations.ts +88 -0
  47. package/src/gui/ContextMixin.ts +0 -3
  48. package/src/gui/EFFilmstrip.ts +7 -16
  49. package/src/gui/EFFitScale.ts +152 -0
  50. package/src/gui/EFWorkbench.ts +18 -65
  51. package/src/gui/TWMixin.ts +19 -2
  52. package/types.json +1 -1
@@ -61,6 +61,9 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
61
61
  @property({ type: String, reflect: true })
62
62
  target = "";
63
63
 
64
+ @property({ type: Number, attribute: "bar-spacing" })
65
+ barSpacing = 0.5;
66
+
64
67
  @state()
65
68
  targetElement: EFAudio | EFVideo | null = null;
66
69
 
@@ -154,7 +157,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
154
157
  const waveHeight = canvas.height;
155
158
 
156
159
  const totalBars = frequencyData.length;
157
- const paddingInner = 0.5;
160
+ const paddingInner = this.barSpacing;
158
161
  const paddingOuter = 0.01;
159
162
  const availableWidth = waveWidth;
160
163
  const barWidth =
@@ -164,7 +167,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
164
167
  const path = new Path2D();
165
168
 
166
169
  frequencyData.forEach((value, i) => {
167
- const normalizedValue = Math.min((value / 255) * 2, 1);
170
+ const normalizedValue = value / 255;
168
171
  const barHeight = normalizedValue * waveHeight;
169
172
  const y = (waveHeight - barHeight) / 2;
170
173
  const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
@@ -190,7 +193,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
190
193
  const maxBricks = Math.floor(waveHeight / (boxSize + verticalGap)); // Account for gaps in height calculation
191
194
 
192
195
  frequencyData.forEach((value, i) => {
193
- const normalizedValue = Math.min((value / 255) * 2, 1);
196
+ const normalizedValue = value / 255;
194
197
  const brickCount = Math.floor(normalizedValue * maxBricks);
195
198
 
196
199
  for (let j = 0; j < brickCount; j++) {
@@ -213,7 +216,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
213
216
 
214
217
  // Similar padding calculation as drawBars
215
218
  const totalBars = frequencyData.length;
216
- const paddingInner = 0.5;
219
+ const paddingInner = this.barSpacing;
217
220
  const paddingOuter = 0.01;
218
221
  const availableWidth = waveWidth;
219
222
  const barWidth =
@@ -225,7 +228,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
225
228
  const path = new Path2D();
226
229
 
227
230
  frequencyData.forEach((value, i) => {
228
- const normalizedValue = Math.min((value / 255) * 2, 1);
231
+ const normalizedValue = value / 255;
229
232
  const height = normalizedValue * waveHeight; // Use full wave height like in drawBars
230
233
  const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
231
234
  const y = (waveHeight - height) / 2; // Center vertically
@@ -238,42 +241,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
238
241
  ctx.fill(path);
239
242
  }
240
243
 
241
- protected drawEqualizer(
242
- ctx: CanvasRenderingContext2D,
243
- frequencyData: Uint8Array,
244
- ) {
245
- const canvas = ctx.canvas;
246
- const waveWidth = canvas.width;
247
- const waveHeight = canvas.height;
248
- const baseline = waveHeight / 2;
249
- const barWidth = (waveWidth / frequencyData.length) * 0.8;
250
-
251
- ctx.clearRect(0, 0, waveWidth, waveHeight);
252
-
253
- // Create paths for baseline and bars
254
- const baselinePath = new Path2D();
255
- const barsPath = new Path2D();
256
-
257
- // Draw baseline
258
- baselinePath.moveTo(0, baseline);
259
- baselinePath.lineTo(waveWidth, baseline);
260
-
261
- // Draw bars
262
- frequencyData.forEach((value, i) => {
263
- const height = (value / 255) * (waveHeight / 2);
264
- const x = i * (waveWidth / frequencyData.length);
265
- const y = baseline - height;
266
- barsPath.rect(x, y, barWidth, Math.max(height * 2, 1));
267
- });
268
-
269
- // Render baseline
270
- ctx.lineWidth = 2;
271
- ctx.stroke(baselinePath);
272
-
273
- // Render bars
274
- ctx.fill(barsPath);
275
- }
276
-
277
244
  protected drawLine(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array) {
278
245
  const canvas = ctx.canvas;
279
246
  const waveWidth = canvas.width;
@@ -283,7 +250,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
283
250
  const path = new Path2D();
284
251
 
285
252
  // Sample fewer points to make sharp angles more visible
286
- const sampleRate = 4; // Only use every 4th point
253
+ const sampleRate = 1; // Only use every 4th point
287
254
 
288
255
  for (let i = 0; i < frequencyData.length; i += sampleRate) {
289
256
  const x = (i / frequencyData.length) * waveWidth;
@@ -295,7 +262,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
295
262
  path.lineTo(x, y);
296
263
  }
297
264
  }
298
-
299
265
  // Ensure we draw to the end
300
266
  const lastX = waveWidth;
301
267
  const lastY =
@@ -351,7 +317,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
351
317
  const path = new Path2D();
352
318
 
353
319
  frequencyData.forEach((value, i) => {
354
- const normalizedValue = Math.min((value / 255) * 2, 1); // Updated normalization
320
+ const normalizedValue = value / 255;
355
321
  const x = i * (waveWidth / frequencyData.length);
356
322
  const barHeight = normalizedValue * (waveHeight / 2); // Half height since we extend both ways
357
323
  const y = baseline - barHeight;
@@ -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
+ };
@@ -129,9 +129,6 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
129
129
  @property({ type: Boolean, reflect: true })
130
130
  loop = false;
131
131
 
132
- // @state()
133
- // private stageScale = 1;
134
-
135
132
  @property({ type: Boolean })
136
133
  rendering = false;
137
134
 
@@ -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
 
@@ -0,0 +1,152 @@
1
+ import { LitElement } from "lit";
2
+ import { customElement, state } from "lit/decorators.js";
3
+ import { createRef } from "lit/directives/ref.js";
4
+
5
+ @customElement("ef-fit-scale")
6
+ export class EFFitScale extends LitElement {
7
+ containerRef = createRef<HTMLDivElement>();
8
+ contentRef = createRef<HTMLSlotElement>();
9
+
10
+ createRenderRoot() {
11
+ Object.assign(this.style, {
12
+ display: "grid",
13
+ width: "100%",
14
+ height: "100%",
15
+ gridTemplateColumns: "100%",
16
+ gridTemplateRows: "100%",
17
+ overflow: "hidden",
18
+ boxSizing: "border-box",
19
+ contain: "strict",
20
+ position: "relative",
21
+ });
22
+ this.id = `${this.uniqueId}`;
23
+ return this;
24
+ }
25
+
26
+ uniqueId = Math.random().toString(36).substring(2, 15);
27
+
28
+ @state()
29
+ private scale = 1;
30
+
31
+ private animationFrameId?: number;
32
+
33
+ get contentChild() {
34
+ const firstElement = this.children[0];
35
+ if (!firstElement) return null;
36
+
37
+ let current: Element = firstElement;
38
+ while (current) {
39
+ if (current instanceof HTMLSlotElement) {
40
+ const assigned = current.assignedElements()[0];
41
+ if (!assigned) break;
42
+ current = assigned;
43
+ continue;
44
+ }
45
+
46
+ const display = window.getComputedStyle(current).display;
47
+ if (display !== "contents" && display !== "none") {
48
+ return current as HTMLElement;
49
+ }
50
+ const firstChild = current.children[0];
51
+ if (!firstChild) break;
52
+ current = firstChild;
53
+ }
54
+ return firstElement as HTMLElement; // Fallback to first element if no non-contents found
55
+ }
56
+
57
+ get scaleInfo() {
58
+ if (!this.contentChild) {
59
+ return {
60
+ scale: 1,
61
+ containerWidth: 0,
62
+ containerHeight: 0,
63
+ contentWidth: 0,
64
+ contentHeight: 0,
65
+ };
66
+ }
67
+
68
+ const containerWidth = this.clientWidth;
69
+ const containerHeight = this.clientHeight;
70
+ const contentWidth = this.contentChild.clientWidth;
71
+ const contentHeight = this.contentChild.clientHeight;
72
+
73
+ const containerRatio = containerWidth / containerHeight;
74
+ const contentRatio = contentWidth / contentHeight;
75
+
76
+ const scale =
77
+ containerRatio > contentRatio
78
+ ? containerHeight / contentHeight
79
+ : containerWidth / contentWidth;
80
+
81
+ return {
82
+ scale,
83
+ containerWidth,
84
+ containerHeight,
85
+ contentWidth,
86
+ contentHeight,
87
+ };
88
+ }
89
+
90
+ scaleLastSetOn: HTMLElement | null = null;
91
+
92
+ setScale = () => {
93
+ if (this.isConnected) {
94
+ const { scale } = this.scaleInfo;
95
+ if (this.contentChild) {
96
+ const containerRect = this.getBoundingClientRect();
97
+ const contentRect = this.contentChild.getBoundingClientRect();
98
+
99
+ const unscaledWidth = contentRect.width / this.scale;
100
+ const unscaledHeight = contentRect.height / this.scale;
101
+ const scaledWidth = unscaledWidth * scale;
102
+ const scaledHeight = unscaledHeight * scale;
103
+ const translateX = (containerRect.width - scaledWidth) / 2;
104
+ const translateY = (containerRect.height - scaledHeight) / 2;
105
+
106
+ // In the rare event that the content child is changed, we need to remove the scale
107
+ // because we don't want to have a scale on the old content child that is somewhere else in the DOM
108
+ if (this.scaleLastSetOn !== this.contentChild) {
109
+ this.removeScale();
110
+ }
111
+ // Use toFixed to avoid floating point precision issues
112
+ // this will update every frame with sub-pixel changes if we don't pin it down
113
+ Object.assign(this.contentChild.style, {
114
+ transform: `translate(${translateX.toFixed(4)}px, ${translateY.toFixed(4)}px) scale(${scale.toFixed(4)})`,
115
+ transformOrigin: "top left",
116
+ });
117
+ this.scale = scale;
118
+ this.scaleLastSetOn = this.contentChild;
119
+ }
120
+ this.animationFrameId = requestAnimationFrame(this.setScale);
121
+ }
122
+ };
123
+
124
+ removeScale = () => {
125
+ if (this.scaleLastSetOn) {
126
+ Object.assign(this.scaleLastSetOn.style, {
127
+ transform: "",
128
+ transformOrigin: "",
129
+ });
130
+ this.scaleLastSetOn = null;
131
+ }
132
+ };
133
+
134
+ connectedCallback(): void {
135
+ super.connectedCallback();
136
+ this.animationFrameId = requestAnimationFrame(this.setScale);
137
+ }
138
+
139
+ disconnectedCallback(): void {
140
+ super.disconnectedCallback();
141
+ this.removeScale();
142
+ if (this.animationFrameId) {
143
+ cancelAnimationFrame(this.animationFrameId);
144
+ }
145
+ }
146
+ }
147
+
148
+ declare global {
149
+ interface HTMLElementTagNameMap {
150
+ "ef-fit-scale": EFFitScale;
151
+ }
152
+ }
@@ -1,5 +1,5 @@
1
1
  import { LitElement, type PropertyValueMap, css, html } from "lit";
2
- import { customElement, eventOptions, state } from "lit/decorators.js";
2
+ import { customElement, eventOptions, property } from "lit/decorators.js";
3
3
  import { createRef, ref } from "lit/directives/ref.js";
4
4
 
5
5
  import { ContextMixin } from "./ContextMixin.js";
@@ -17,69 +17,22 @@ export class EFWorkbench extends ContextMixin(TWMixin(LitElement)) {
17
17
  `,
18
18
  ];
19
19
 
20
- stageRef = createRef<HTMLDivElement>();
21
- canvasRef = createRef<HTMLSlotElement>();
20
+ @property({ type: Boolean })
21
+ rendering = false;
22
+
23
+ focusOverlay = createRef<HTMLDivElement>();
22
24
 
23
25
  @eventOptions({ passive: false, capture: true })
24
26
  handleStageWheel(event: WheelEvent) {
25
27
  event.preventDefault();
26
28
  }
27
29
 
28
- focusOverlay = createRef<HTMLDivElement>();
29
-
30
- @state()
31
- private stageScale = 1;
32
-
33
- setStageScale = () => {
34
- if (this.isConnected && !this.rendering) {
35
- const canvasElement = this.canvasRef.value;
36
- const stageElement = this.stageRef.value;
37
- const canvasChild = canvasElement?.assignedElements()[0];
38
- if (stageElement && canvasElement && canvasChild) {
39
- // Determine the appropriate scale factor to make the canvas fit into
40
- canvasElement.style.width = `${canvasChild.clientWidth}px`;
41
- canvasElement.style.height = `${canvasChild.clientHeight}px`;
42
- const stageWidth = stageElement.clientWidth;
43
- const stageHeight = stageElement.clientHeight;
44
- const canvasWidth = canvasElement.clientWidth;
45
- const canvasHeight = canvasElement.clientHeight;
46
- const stageRatio = stageWidth / stageHeight;
47
- const canvasRatio = canvasWidth / canvasHeight;
48
-
49
- if (stageRatio > canvasRatio) {
50
- const scale = stageHeight / canvasHeight;
51
- if (this.stageScale !== scale) {
52
- canvasElement.style.transform = `scale(${scale})`;
53
- canvasElement.style.transformOrigin = "top center";
54
- }
55
- this.stageScale = scale;
56
- } else {
57
- const scale = stageWidth / canvasWidth;
58
- if (this.stageScale !== scale) {
59
- canvasElement.style.transform = `scale(${scale})`;
60
- canvasElement.style.transformOrigin = "center";
61
- }
62
- this.stageScale = scale;
63
- }
64
- }
65
- }
66
- if (this.isConnected) {
67
- requestAnimationFrame(this.setStageScale);
68
- }
69
- };
70
-
71
30
  connectedCallback(): void {
72
- // Set the body and html to 100% width and height to avoid scaling issues
73
- // this is a hack to avoid scaling issues when the stage is scaled and during output rendering
74
- // What I've discovered recently is that having the workbench be so smart as to determine
75
- // how it should be displayed at render time causes problems. Much of that has been extracted
76
- // but this is a quick fix to avoid scaling issues.
77
31
  document.body.style.width = "100%";
78
32
  document.body.style.height = "100%";
79
33
  document.documentElement.style.width = "100%";
80
34
  document.documentElement.style.height = "100%";
81
35
  super.connectedCallback();
82
- requestAnimationFrame(this.setStageScale);
83
36
  }
84
37
 
85
38
  disconnectedCallback(): void {
@@ -121,30 +74,30 @@ export class EFWorkbench extends ContextMixin(TWMixin(LitElement)) {
121
74
  };
122
75
 
123
76
  render() {
124
- if (this.rendering) {
77
+ // TODO: this.rendering is not correctly set when using the framegen bridge
78
+ // so to hack we're checking for the existence of EF_RENDERING on the window
79
+ if (
80
+ this.rendering ||
81
+ (typeof window !== "undefined" && window.EF_RENDERING?.() === true)
82
+ ) {
83
+ console.log("WORKBENCH RENDERING“");
125
84
  return html`
126
- <slot
127
- ${ref(this.canvasRef)}
128
- class="fixed inset-0 h-full w-full"
129
- name="canvas"
130
- ></slot>
85
+ <slot class="fixed inset-0 h-full w-full" name="canvas"></slot>
131
86
  `;
132
87
  }
88
+ console.log("WORKBENCH NOT RENDERING");
133
89
  return html`
134
90
  <div
135
91
  class="grid h-full w-full bg-slate-800"
136
92
  style="grid-template-rows: 1fr 300px; grid-template-columns: 100%;"
137
93
  >
138
94
  <div
139
- ${ref(this.stageRef)}
140
- class="relative grid h-full w-full justify-center overflow-hidden"
95
+ class="relative h-full w-full overflow-hidden"
141
96
  @wheel=${this.handleStageWheel}
142
97
  >
143
- <slot
144
- ${ref(this.canvasRef)}
145
- name="canvas"
146
- class="inline-block"
147
- ></slot>
98
+ <ef-fit-scale class="h-full grid place-content-center">
99
+ <slot name="canvas" class="contents"></slot>
100
+ </ef-fit-scale>
148
101
  <div
149
102
  class="border border-blue-500 bg-blue-200 bg-opacity-20 absolute"
150
103
  ${ref(this.focusOverlay)}
@@ -1,4 +1,4 @@
1
- import type { LitElement } from "lit";
1
+ import type { CSSResult, LitElement } from "lit";
2
2
  // @ts-expect-error cannot figure out how to declare this module as a string
3
3
  import twStyle from "./TWMixin.css?inline";
4
4
 
@@ -21,13 +21,30 @@ export function TWMixin<T extends new (...args: any[]) => LitElement>(Base: T) {
21
21
  "twSheet not found. Probable cause: CSSStyleSheet not supported in this environment",
22
22
  );
23
23
  }
24
+
25
+ const constructorStylesheets: CSSStyleSheet[] = [];
26
+ const constructorStyles = (("styles" in this.constructor &&
27
+ this.constructor.styles) ||
28
+ []) as CSSResult | CSSResult[];
29
+
30
+ if (Array.isArray(constructorStyles)) {
31
+ for (const item of constructorStyles) {
32
+ if (item.styleSheet) {
33
+ constructorStylesheets.push(item.styleSheet);
34
+ }
35
+ }
36
+ } else if (constructorStyles.styleSheet) {
37
+ constructorStylesheets.push(constructorStyles.styleSheet);
38
+ }
39
+
24
40
  if (renderRoot?.adoptedStyleSheets) {
25
41
  renderRoot.adoptedStyleSheets = [
26
42
  twSheet,
27
43
  ...renderRoot.adoptedStyleSheets,
44
+ ...constructorStylesheets,
28
45
  ];
29
46
  } else {
30
- renderRoot.adoptedStyleSheets = [twSheet];
47
+ renderRoot.adoptedStyleSheets = [twSheet, ...constructorStylesheets];
31
48
  }
32
49
  return renderRoot;
33
50
  }