@editframe/elements 0.30.0-beta.14 → 0.30.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.
@@ -2,7 +2,7 @@ import { MediaEngine } from "../transcoding/types/index.js";
2
2
  import { EFMedia } from "./EFMedia.js";
3
3
  import * as _lit_task8 from "@lit/task";
4
4
  import { Task } from "@lit/task";
5
- import * as lit_html1 from "lit-html";
5
+ import * as lit_html2 from "lit-html";
6
6
  import * as lit_html_directives_ref_js1 from "lit-html/directives/ref.js";
7
7
 
8
8
  //#region src/elements/EFAudio.d.ts
@@ -10,7 +10,7 @@ declare const EFAudio_base: typeof EFMedia;
10
10
  declare class EFAudio extends EFAudio_base {
11
11
  private _propertyHack;
12
12
  audioElementRef: lit_html_directives_ref_js1.Ref<HTMLAudioElement>;
13
- render(): lit_html1.TemplateResult<1>;
13
+ render(): lit_html2.TemplateResult<1>;
14
14
  frameTask: Task<readonly [_lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus], void>;
15
15
  /**
16
16
  * Legacy getter for fragment index task (maps to audioSegmentIdTask)
@@ -4,9 +4,9 @@ import { FetchMixinInterface } from "./FetchMixin.js";
4
4
  import { EFAudio } from "./EFAudio.js";
5
5
  import { EFVideo } from "./EFVideo.js";
6
6
  import { Task, TaskStatus } from "@lit/task";
7
- import * as lit3 from "lit";
7
+ import * as lit4 from "lit";
8
8
  import { LitElement, PropertyValueMap } from "lit";
9
- import * as lit_html3 from "lit-html";
9
+ import * as lit_html4 from "lit-html";
10
10
 
11
11
  //#region src/elements/EFCaptions.d.ts
12
12
  interface WordSegment {
@@ -25,8 +25,8 @@ interface Caption {
25
25
  }
26
26
  declare const EFCaptionsActiveWord_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
27
27
  declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
28
- static styles: lit3.CSSResult[];
29
- render(): lit_html3.TemplateResult<1> | undefined;
28
+ static styles: lit4.CSSResult[];
29
+ render(): lit_html4.TemplateResult<1> | undefined;
30
30
  wordStartMs: number;
31
31
  wordEndMs: number;
32
32
  wordText: string;
@@ -38,8 +38,8 @@ declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
38
38
  }
39
39
  declare const EFCaptionsSegment_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
40
40
  declare class EFCaptionsSegment extends EFCaptionsSegment_base {
41
- static styles: lit3.CSSResult[];
42
- render(): lit_html3.TemplateResult<1> | undefined;
41
+ static styles: lit4.CSSResult[];
42
+ render(): lit_html4.TemplateResult<1> | undefined;
43
43
  segmentStartMs: number;
44
44
  segmentEndMs: number;
45
45
  segmentText: string;
@@ -49,8 +49,8 @@ declare class EFCaptionsSegment extends EFCaptionsSegment_base {
49
49
  get durationMs(): number;
50
50
  }
51
51
  declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
52
- static styles: lit3.CSSResult[];
53
- render(): lit_html3.TemplateResult<1> | undefined;
52
+ static styles: lit4.CSSResult[];
53
+ render(): lit_html4.TemplateResult<1> | undefined;
54
54
  hidden: boolean;
55
55
  segmentText: string;
56
56
  segmentStartMs: number;
@@ -60,8 +60,8 @@ declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
60
60
  get durationMs(): number;
61
61
  }
62
62
  declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
63
- static styles: lit3.CSSResult[];
64
- render(): lit_html3.TemplateResult<1> | undefined;
63
+ static styles: lit4.CSSResult[];
64
+ render(): lit_html4.TemplateResult<1> | undefined;
65
65
  hidden: boolean;
66
66
  segmentText: string;
67
67
  segmentStartMs: number;
@@ -72,7 +72,7 @@ declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
72
72
  }
73
73
  declare const EFCaptions_base: (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
74
74
  declare class EFCaptions extends EFCaptions_base {
75
- static styles: lit3.CSSResult[];
75
+ static styles: lit4.CSSResult[];
76
76
  targetSelector: string;
77
77
  set target(value: string);
78
78
  wordStyle: string;
@@ -95,7 +95,7 @@ declare class EFCaptions extends EFCaptions_base {
95
95
  segmentContainers: HTMLCollectionOf<EFCaptionsSegment>;
96
96
  beforeActiveWordContainers: HTMLCollectionOf<EFCaptionsBeforeActiveWord>;
97
97
  afterActiveWordContainers: HTMLCollectionOf<EFCaptionsAfterActiveWord>;
98
- render(): lit_html3.TemplateResult<1>;
98
+ render(): lit_html4.TemplateResult<1>;
99
99
  transcriptionsPath(): string | null;
100
100
  captionsPath(): string | null;
101
101
  protected md5SumLoader: Task<readonly [string, typeof fetch], string | null | undefined>;
@@ -3,21 +3,21 @@ import { EFSourceMixinInterface } from "./EFSourceMixin.js";
3
3
  import { FetchMixinInterface } from "./FetchMixin.js";
4
4
  import * as _lit_task0 from "@lit/task";
5
5
  import { Task } from "@lit/task";
6
- import * as lit0 from "lit";
6
+ import * as lit1 from "lit";
7
7
  import { LitElement } from "lit";
8
- import * as lit_html0 from "lit-html";
8
+ import * as lit_html1 from "lit-html";
9
9
  import * as lit_html_directives_ref_js0 from "lit-html/directives/ref.js";
10
10
 
11
11
  //#region src/elements/EFImage.d.ts
12
12
  declare const EFImage_base: (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
13
13
  declare class EFImage extends EFImage_base {
14
14
  #private;
15
- static styles: lit0.CSSResult[];
15
+ static styles: lit1.CSSResult[];
16
16
  imageRef: lit_html_directives_ref_js0.Ref<HTMLImageElement>;
17
17
  canvasRef: lit_html_directives_ref_js0.Ref<HTMLCanvasElement>;
18
18
  set assetId(value: string | null);
19
19
  get assetId(): string | null;
20
- render(): lit_html0.TemplateResult<1>;
20
+ render(): lit_html1.TemplateResult<1>;
21
21
  private isDirectUrl;
22
22
  assetPath(): string;
23
23
  get hasOwnDuration(): boolean;
@@ -9,7 +9,7 @@ import { AudioBufferState } from "./EFMedia/audioTasks/makeAudioBufferTask.js";
9
9
  import { ControllableInterface } from "../gui/Controllable.js";
10
10
  import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
11
11
  import * as _lit_task0 from "@lit/task";
12
- import * as lit1 from "lit";
12
+ import * as lit2 from "lit";
13
13
  import { LitElement, PropertyValueMap } from "lit";
14
14
  import * as mediabunny0 from "mediabunny";
15
15
 
@@ -23,7 +23,7 @@ declare class EFMedia extends EFMedia_base {
23
23
  static readonly VIDEO_SAMPLE_BUFFER_SIZE = 30;
24
24
  static readonly AUDIO_SAMPLE_BUFFER_SIZE = 120;
25
25
  static get observedAttributes(): string[];
26
- static styles: lit1.CSSResult[];
26
+ static styles: lit2.CSSResult[];
27
27
  /**
28
28
  * Duration in milliseconds for audio buffering ahead of current time
29
29
  * @domAttribute "audio-buffer-duration"
@@ -1,14 +1,14 @@
1
1
  import { TemporalMixinInterface } from "./EFTemporal.js";
2
2
  import { EFTextSegment } from "./EFTextSegment.js";
3
- import * as lit8 from "lit";
3
+ import * as lit9 from "lit";
4
4
  import { LitElement, PropertyValueMap } from "lit";
5
- import * as lit_html8 from "lit-html";
5
+ import * as lit_html9 from "lit-html";
6
6
 
7
7
  //#region src/elements/EFText.d.ts
8
8
  type SplitMode = "line" | "word" | "char";
9
9
  declare const EFText_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
10
10
  declare class EFText extends EFText_base {
11
- static styles: lit8.CSSResult[];
11
+ static styles: lit9.CSSResult[];
12
12
  split: SplitMode;
13
13
  private validateSplit;
14
14
  staggerMs?: number;
@@ -19,7 +19,7 @@ declare class EFText extends EFText_base {
19
19
  private _textContent;
20
20
  private _templateElement;
21
21
  private _segmentsReadyResolvers;
22
- render(): lit_html8.TemplateResult<1>;
22
+ render(): lit_html9.TemplateResult<1>;
23
23
  set textContent(value: string | null);
24
24
  get textContent(): string;
25
25
  /**
@@ -258,45 +258,26 @@ let EFText = class EFText$1 extends EFTemporal(LitElement) {
258
258
  });
259
259
  }
260
260
  splitTextIntoSegments(text) {
261
+ const trimmedText = text.trim();
262
+ if (!trimmedText) return [];
261
263
  switch (this.split) {
262
- case "line": return text.split(/\r?\n/).filter((line) => line.length > 0);
264
+ case "line": return trimmedText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
263
265
  case "word": {
264
- const words = [];
265
- const parts = text.split(/(\S+)/);
266
- for (const part of parts) if (part.trim().length > 0) words.push(part);
267
- else if (part.length > 0) {
268
- if (words.length > 0) words[words.length - 1] += part;
269
- }
270
- return words.length > 0 ? words : [text];
266
+ const segmenter = new Intl.Segmenter(void 0, { granularity: "word" });
267
+ return Array.from(segmenter.segment(trimmedText)).filter((seg) => seg.isWordLike).map((seg) => seg.segment);
271
268
  }
272
- case "char": return Array.from(text);
273
- default: return [text];
269
+ case "char": {
270
+ const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
271
+ return Array.from(segmenter.segment(trimmedText)).map((seg) => seg.segment);
272
+ }
273
+ default: return [trimmedText];
274
274
  }
275
275
  }
276
276
  get intrinsicDurationMs() {
277
277
  if (this.hasExplicitDuration) return;
278
278
  const text = this._textContent !== null ? this._textContent : this.getTextContent();
279
279
  if (!text || text.trim().length === 0) return 0;
280
- let segmentCount = 1;
281
- switch (this.split) {
282
- case "line":
283
- segmentCount = text.split(/\r?\n/).filter((line) => line.trim().length > 0).length || 1;
284
- break;
285
- case "word": {
286
- const words = [];
287
- const parts = text.split(/(\S+)/);
288
- for (const part of parts) if (part.trim().length > 0) words.push(part);
289
- else if (part.length > 0) {
290
- if (words.length > 0) words[words.length - 1] += part;
291
- }
292
- segmentCount = words.length > 0 ? words.length : 1;
293
- break;
294
- }
295
- case "char":
296
- segmentCount = text.length || 1;
297
- break;
298
- }
299
- return segmentCount * 1e3;
280
+ return (this.splitTextIntoSegments(text).length || 1) * 1e3;
300
281
  }
301
282
  };
302
283
  __decorate([property({
@@ -1 +1 @@
1
- {"version":3,"file":"EFText.js","names":["EFText","textNodes: ChildNode[]","staggerOffset: number | undefined","words: string[]"],"sources":["../../src/elements/EFText.ts"],"sourcesContent":["import { css, html, LitElement, type PropertyValueMap } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { durationConverter } from \"./durationConverter.js\";\nimport { EFTemporal } from \"./EFTemporal.js\";\nimport { evaluateEasing } from \"./easingUtils.js\";\nimport type { EFTextSegment } from \"./EFTextSegment.js\";\nimport { updateAnimations } from \"./updateAnimations.js\";\n\nexport type SplitMode = \"line\" | \"word\" | \"char\";\n\n@customElement(\"ef-text\")\nexport class EFText extends EFTemporal(LitElement) {\n static styles = [\n css`\n :host {\n display: inline-flex;\n white-space: normal;\n line-height: 1;\n gap: 0;\n }\n :host([split=\"char\"]) {\n white-space: pre;\n }\n :host([split=\"line\"]) {\n display: flex;\n flex-direction: column;\n }\n ::slotted(*) {\n display: inline-block;\n margin: 0;\n padding: 0;\n }\n `,\n ];\n\n @property({ type: String, reflect: true })\n split: SplitMode = \"word\";\n\n private validateSplit(value: string): SplitMode {\n if (value === \"line\" || value === \"word\" || value === \"char\") {\n return value as SplitMode;\n }\n console.warn(\n `Invalid split value \"${value}\". Must be \"line\", \"word\", or \"char\". Defaulting to \"word\".`,\n );\n return \"word\";\n }\n\n @property({\n type: Number,\n attribute: \"stagger\",\n converter: durationConverter,\n })\n staggerMs?: number;\n\n private validateStagger(value: number | undefined): number | undefined {\n if (value === undefined) return undefined;\n if (value < 0) {\n console.warn(`Invalid stagger value ${value}ms. Must be >= 0. Using 0.`);\n return 0;\n }\n return value;\n }\n\n @property({ type: String, reflect: true })\n easing = \"linear\";\n\n private mutationObserver?: MutationObserver;\n private lastTextContent = \"\";\n private _textContent: string | null = null; // null means not initialized, \"\" means explicitly empty\n private _templateElement: HTMLTemplateElement | null = null;\n private _segmentsReadyResolvers: Array<() => void> = [];\n\n render() {\n return html`<slot></slot>`;\n }\n\n // Store text content so we can use it even after DOM is cleared\n set textContent(value: string | null) {\n const newValue = value || \"\";\n // Only update if value actually changed\n if (this._textContent !== newValue) {\n this._textContent = newValue;\n\n // Find template element if not already stored\n if (!this._templateElement && this.isConnected) {\n this._templateElement = this.querySelector(\"template\");\n }\n\n // Clear any existing text nodes\n const textNodes: ChildNode[] = [];\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n textNodes.push(node as ChildNode);\n }\n }\n for (const node of textNodes) {\n node.remove();\n }\n // Add new text node if value is not empty\n if (newValue) {\n const textNode = document.createTextNode(newValue);\n this.appendChild(textNode);\n }\n // Trigger re-split\n if (this.isConnected) {\n this.splitText();\n }\n }\n }\n\n get textContent(): string {\n // If _textContent is null, it hasn't been initialized - read from DOM\n if (this._textContent === null) {\n return this.getTextContent();\n }\n // Otherwise use stored value (even if empty string)\n return this._textContent;\n }\n\n /**\n * Get all ef-text-segment elements directly\n * @public\n */\n get segments(): EFTextSegment[] {\n return Array.from(\n this.querySelectorAll(\"ef-text-segment[data-segment-created]\"),\n ) as EFTextSegment[];\n }\n\n /**\n * Returns a promise that resolves when segments are ready (created and connected)\n * Use this to wait for segments after setting textContent or other properties\n * @public\n */\n async whenSegmentsReady(): Promise<EFTextSegment[]> {\n // Wait for text element to be updated first\n await this.updateComplete;\n\n // If no text content, segments will be empty - return immediately\n // Use same logic as splitText to read text content\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n return [];\n }\n\n // Wait a frame for splitText to run\n await new Promise((resolve) => requestAnimationFrame(resolve));\n\n // If segments already exist and are connected, wait for updates\n let segments = this.segments;\n if (segments.length > 0) {\n // Wait for all segments to be updated\n await Promise.all(segments.map((seg) => seg.updateComplete));\n // Wait one more frame to ensure connectedCallback has run and properties are set\n await new Promise((resolve) => requestAnimationFrame(resolve));\n // Wait one more frame to ensure properties are fully processed\n await new Promise((resolve) => requestAnimationFrame(resolve));\n return this.segments;\n }\n\n // Otherwise, wait for segments to be created (with timeout)\n return new Promise<EFTextSegment[]>((resolve) => {\n let attempts = 0;\n const maxAttempts = 100; // 100 frames = ~1.6 seconds at 60fps\n\n const checkSegments = () => {\n segments = this.segments;\n if (segments.length > 0) {\n // Wait for all segments to be updated\n Promise.all(segments.map((seg) => seg.updateComplete)).then(() => {\n // Wait frames to ensure connectedCallback has run and properties are set\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n resolve(this.segments);\n });\n });\n });\n } else if (attempts < maxAttempts) {\n attempts++;\n requestAnimationFrame(checkSegments);\n } else {\n // Timeout - return empty array (might be empty text)\n resolve([]);\n }\n };\n checkSegments();\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n // Find and store template element before any modifications\n this._templateElement = this.querySelector(\"template\");\n\n // Initialize _textContent from DOM if not already set (for declarative usage)\n if (this._textContent === null) {\n this._textContent = this.getTextContent();\n this.lastTextContent = this._textContent;\n }\n\n // Use requestAnimationFrame to ensure DOM is ready\n requestAnimationFrame(() => {\n this.setupMutationObserver();\n this.splitText();\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.mutationObserver?.disconnect();\n }\n\n protected updated(\n changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,\n ): void {\n if (\n changedProperties.has(\"split\") ||\n changedProperties.has(\"staggerMs\") ||\n changedProperties.has(\"easing\") ||\n changedProperties.has(\"durationMs\")\n ) {\n this.splitText();\n }\n }\n\n private setupMutationObserver() {\n this.mutationObserver = new MutationObserver(() => {\n // Only react to changes that aren't from our own segment creation\n const currentText = this._textContent || this.getTextContent();\n if (currentText !== this.lastTextContent) {\n this._textContent = currentText;\n this.lastTextContent = currentText;\n this.splitText();\n }\n });\n\n this.mutationObserver.observe(this, {\n childList: true,\n characterData: true,\n subtree: true,\n });\n }\n\n private getTextContent(): string {\n // Get text content, handling both text nodes and HTML content\n let text = \"\";\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent || \"\";\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n // Skip ef-text-segment elements (they're created by us)\n if (element.tagName === \"EF-TEXT-SEGMENT\") {\n continue;\n }\n // Skip template elements (they're templates, not content)\n if (element.tagName === \"TEMPLATE\") {\n continue;\n }\n text += element.textContent || \"\";\n }\n }\n return text;\n }\n\n private splitText() {\n // Validate split mode\n const validatedSplit = this.validateSplit(this.split);\n if (validatedSplit !== this.split) {\n this.split = validatedSplit;\n return; // Will trigger updated() which calls splitText() again\n }\n\n // Validate stagger\n const validatedStagger = this.validateStagger(this.staggerMs);\n if (validatedStagger !== this.staggerMs) {\n this.staggerMs = validatedStagger;\n return; // Will trigger updated() which calls splitText() again\n }\n\n // Read text content - use stored _textContent if set, otherwise read from DOM\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n // Clear segments if no text\n const existingSegments = Array.from(\n this.querySelectorAll(\"ef-text-segment\"),\n );\n for (const segment of existingSegments) {\n segment.remove();\n }\n // Clear text nodes\n const textNodes: ChildNode[] = [];\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n textNodes.push(node as ChildNode);\n }\n }\n for (const node of textNodes) {\n node.remove();\n }\n this.lastTextContent = \"\";\n // Resolve any waiting promises\n this._segmentsReadyResolvers.forEach((resolve) => {\n resolve();\n });\n this._segmentsReadyResolvers = [];\n return;\n }\n\n const segments = this.splitTextIntoSegments(text);\n const durationMs = this.durationMs || 1000; // Default 1 second if no duration\n\n // Clear ALL child nodes (text nodes and segments) by replacing innerHTML\n // This ensures we don't have any leftover text nodes\n const fragment = document.createDocumentFragment();\n\n // Find template element if not already stored\n if (!this._templateElement) {\n this._templateElement = this.querySelector(\"template\");\n }\n\n // Get template content structure\n // If template exists, clone it; otherwise create default ef-text-segment\n const templateContent = this._templateElement?.content;\n const templateSegments = templateContent\n ? Array.from(templateContent.querySelectorAll(\"ef-text-segment\"))\n : [];\n\n // If no template segments found, we'll create a default one\n const useTemplate = templateSegments.length > 0;\n const segmentsPerTextSegment = useTemplate ? templateSegments.length : 1;\n\n // Create new segments in a fragment first\n segments.forEach((segmentText, textIndex) => {\n // Calculate stagger offset if stagger is set\n let staggerOffset: number | undefined;\n if (this.staggerMs !== undefined) {\n // Apply easing to the stagger offset\n // Normalize index to 0-1 range (0 for first segment, 1 for last segment)\n const totalSegments = segments.length;\n const normalizedProgress =\n totalSegments > 1 ? textIndex / (totalSegments - 1) : 0;\n\n // Apply easing function to get eased progress\n const easedProgress = evaluateEasing(this.easing, normalizedProgress);\n\n // Calculate total stagger duration (last segment gets full stagger)\n const totalStaggerDuration = (totalSegments - 1) * this.staggerMs;\n\n // Apply eased progress to total stagger duration\n staggerOffset = easedProgress * totalStaggerDuration;\n }\n\n if (useTemplate && templateContent) {\n // Clone template content for each text segment\n // This allows multiple ef-text-segment elements per character/word/line\n const clonedContent = templateContent.cloneNode(\n true,\n ) as DocumentFragment;\n const clonedSegments = Array.from(\n clonedContent.querySelectorAll(\"ef-text-segment\"),\n ) as EFTextSegment[];\n\n clonedSegments.forEach((segment, templateIndex) => {\n // Set properties - Lit will process these when element is connected\n segment.segmentText = segmentText;\n // Calculate segment index accounting for multiple segments per text segment\n segment.segmentIndex =\n textIndex * segmentsPerTextSegment + templateIndex;\n segment.segmentStartMs = 0;\n segment.segmentEndMs = durationMs;\n segment.staggerOffsetMs = staggerOffset ?? 0;\n\n // Set data attribute for line mode to enable block display\n if (this.split === \"line\") {\n segment.setAttribute(\"data-line-segment\", \"true\");\n }\n\n // Mark as created to avoid being picked up as template\n segment.setAttribute(\"data-segment-created\", \"true\");\n\n fragment.appendChild(segment);\n });\n } else {\n // No template - create default ef-text-segment\n const segment = document.createElement(\n \"ef-text-segment\",\n ) as EFTextSegment;\n\n segment.segmentText = segmentText;\n segment.segmentIndex = textIndex;\n segment.segmentStartMs = 0;\n segment.segmentEndMs = durationMs;\n segment.staggerOffsetMs = staggerOffset ?? 0;\n\n // Set data attribute for line mode to enable block display\n if (this.split === \"line\") {\n segment.setAttribute(\"data-line-segment\", \"true\");\n }\n\n // Mark as created to avoid being picked up as template\n segment.setAttribute(\"data-segment-created\", \"true\");\n\n fragment.appendChild(segment);\n }\n });\n\n // Ensure segments are connected to DOM before checking for animations\n // Append fragment first, then trigger updates\n\n // Replace all children with the fragment (this clears text nodes and old segments)\n // But preserve the template element if it exists\n const templateToPreserve = this._templateElement;\n while (this.firstChild) {\n const child = this.firstChild;\n // Don't remove the template element\n if (child === templateToPreserve) {\n // Skip template, but we need to move it after the fragment\n // So we'll remove it temporarily and re-add it after\n this.removeChild(child);\n continue;\n }\n this.removeChild(child);\n }\n this.appendChild(fragment);\n // Re-add template element if it existed\n if (templateToPreserve) {\n this.appendChild(templateToPreserve);\n }\n\n // Segments will pause their own animations in connectedCallback\n // Lit will automatically update them when they're connected to the DOM\n // Ensure segments are updated after being connected\n requestAnimationFrame(() => {\n const segmentElements = this.segments;\n Promise.all(segmentElements.map((seg) => seg.updateComplete)).then(() => {\n // Wait an additional frame to ensure animations are paused in connectedCallback\n // Then trigger updateAnimations to set correct state\n // This ensures animations are positioned correctly on first load\n requestAnimationFrame(() => {\n const rootTimegroup = this.rootTimegroup;\n if (rootTimegroup) {\n updateAnimations(rootTimegroup);\n } else {\n updateAnimations(this);\n }\n });\n });\n });\n\n this.lastTextContent = text;\n this._textContent = text;\n\n // Resolve any waiting promises after segments are connected\n requestAnimationFrame(() => {\n this._segmentsReadyResolvers.forEach((resolve) => {\n resolve();\n });\n this._segmentsReadyResolvers = [];\n });\n }\n\n private splitTextIntoSegments(text: string): string[] {\n switch (this.split) {\n case \"line\": {\n // Split on newlines\n const lines = text.split(/\\r?\\n/);\n // Filter out empty lines but keep the structure\n return lines.filter((line) => line.length > 0);\n }\n case \"word\": {\n // Split on whitespace boundaries, preserving spaces after words\n const words: string[] = [];\n // Split by word boundaries, but keep spaces after words\n const parts = text.split(/(\\S+)/);\n for (const part of parts) {\n if (part.trim().length > 0) {\n // This is a word - check if there's a space after it in the original text\n words.push(part);\n } else if (part.length > 0) {\n // This is whitespace - attach it to the previous word if exists, otherwise skip\n if (words.length > 0) {\n words[words.length - 1] += part;\n }\n }\n }\n // If no words found, return original text\n return words.length > 0 ? words : [text];\n }\n case \"char\": {\n // Split every character, preserving whitespace\n return Array.from(text);\n }\n default:\n return [text];\n }\n }\n\n get intrinsicDurationMs(): number | undefined {\n // If explicit duration is set, use it\n if (this.hasExplicitDuration) {\n return undefined; // Let explicit duration take precedence\n }\n\n // Otherwise, calculate from content\n // Use _textContent if set, otherwise read from DOM\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n return 0;\n }\n\n // Default to 1 second per segment (can be overridden with explicit duration)\n // Use the same splitting logic as splitTextIntoSegments\n let segmentCount = 1;\n switch (this.split) {\n case \"line\": {\n const lines = text\n .split(/\\r?\\n/)\n .filter((line) => line.trim().length > 0);\n segmentCount = lines.length || 1;\n break;\n }\n case \"word\": {\n // Use same logic as splitTextIntoSegments for consistency\n const words: string[] = [];\n const parts = text.split(/(\\S+)/);\n for (const part of parts) {\n if (part.trim().length > 0) {\n words.push(part);\n } else if (part.length > 0) {\n if (words.length > 0) {\n words[words.length - 1] += part;\n }\n }\n }\n segmentCount = words.length > 0 ? words.length : 1;\n break;\n }\n case \"char\": {\n segmentCount = text.length || 1;\n break;\n }\n }\n\n return segmentCount * 1000;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-text\": EFText;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EFText.js","names":["EFText","textNodes: ChildNode[]","staggerOffset: number | undefined"],"sources":["../../src/elements/EFText.ts"],"sourcesContent":["import { css, html, LitElement, type PropertyValueMap } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { durationConverter } from \"./durationConverter.js\";\nimport { EFTemporal } from \"./EFTemporal.js\";\nimport { evaluateEasing } from \"./easingUtils.js\";\nimport type { EFTextSegment } from \"./EFTextSegment.js\";\nimport { updateAnimations } from \"./updateAnimations.js\";\n\nexport type SplitMode = \"line\" | \"word\" | \"char\";\n\n@customElement(\"ef-text\")\nexport class EFText extends EFTemporal(LitElement) {\n static styles = [\n css`\n :host {\n display: inline-flex;\n white-space: normal;\n line-height: 1;\n gap: 0;\n }\n :host([split=\"char\"]) {\n white-space: pre;\n }\n :host([split=\"line\"]) {\n display: flex;\n flex-direction: column;\n }\n ::slotted(*) {\n display: inline-block;\n margin: 0;\n padding: 0;\n }\n `,\n ];\n\n @property({ type: String, reflect: true })\n split: SplitMode = \"word\";\n\n private validateSplit(value: string): SplitMode {\n if (value === \"line\" || value === \"word\" || value === \"char\") {\n return value as SplitMode;\n }\n console.warn(\n `Invalid split value \"${value}\". Must be \"line\", \"word\", or \"char\". Defaulting to \"word\".`,\n );\n return \"word\";\n }\n\n @property({\n type: Number,\n attribute: \"stagger\",\n converter: durationConverter,\n })\n staggerMs?: number;\n\n private validateStagger(value: number | undefined): number | undefined {\n if (value === undefined) return undefined;\n if (value < 0) {\n console.warn(`Invalid stagger value ${value}ms. Must be >= 0. Using 0.`);\n return 0;\n }\n return value;\n }\n\n @property({ type: String, reflect: true })\n easing = \"linear\";\n\n private mutationObserver?: MutationObserver;\n private lastTextContent = \"\";\n private _textContent: string | null = null; // null means not initialized, \"\" means explicitly empty\n private _templateElement: HTMLTemplateElement | null = null;\n private _segmentsReadyResolvers: Array<() => void> = [];\n\n render() {\n return html`<slot></slot>`;\n }\n\n // Store text content so we can use it even after DOM is cleared\n set textContent(value: string | null) {\n const newValue = value || \"\";\n // Only update if value actually changed\n if (this._textContent !== newValue) {\n this._textContent = newValue;\n\n // Find template element if not already stored\n if (!this._templateElement && this.isConnected) {\n this._templateElement = this.querySelector(\"template\");\n }\n\n // Clear any existing text nodes\n const textNodes: ChildNode[] = [];\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n textNodes.push(node as ChildNode);\n }\n }\n for (const node of textNodes) {\n node.remove();\n }\n // Add new text node if value is not empty\n if (newValue) {\n const textNode = document.createTextNode(newValue);\n this.appendChild(textNode);\n }\n // Trigger re-split\n if (this.isConnected) {\n this.splitText();\n }\n }\n }\n\n get textContent(): string {\n // If _textContent is null, it hasn't been initialized - read from DOM\n if (this._textContent === null) {\n return this.getTextContent();\n }\n // Otherwise use stored value (even if empty string)\n return this._textContent;\n }\n\n /**\n * Get all ef-text-segment elements directly\n * @public\n */\n get segments(): EFTextSegment[] {\n return Array.from(\n this.querySelectorAll(\"ef-text-segment[data-segment-created]\"),\n ) as EFTextSegment[];\n }\n\n /**\n * Returns a promise that resolves when segments are ready (created and connected)\n * Use this to wait for segments after setting textContent or other properties\n * @public\n */\n async whenSegmentsReady(): Promise<EFTextSegment[]> {\n // Wait for text element to be updated first\n await this.updateComplete;\n\n // If no text content, segments will be empty - return immediately\n // Use same logic as splitText to read text content\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n return [];\n }\n\n // Wait a frame for splitText to run\n await new Promise((resolve) => requestAnimationFrame(resolve));\n\n // If segments already exist and are connected, wait for updates\n let segments = this.segments;\n if (segments.length > 0) {\n // Wait for all segments to be updated\n await Promise.all(segments.map((seg) => seg.updateComplete));\n // Wait one more frame to ensure connectedCallback has run and properties are set\n await new Promise((resolve) => requestAnimationFrame(resolve));\n // Wait one more frame to ensure properties are fully processed\n await new Promise((resolve) => requestAnimationFrame(resolve));\n return this.segments;\n }\n\n // Otherwise, wait for segments to be created (with timeout)\n return new Promise<EFTextSegment[]>((resolve) => {\n let attempts = 0;\n const maxAttempts = 100; // 100 frames = ~1.6 seconds at 60fps\n\n const checkSegments = () => {\n segments = this.segments;\n if (segments.length > 0) {\n // Wait for all segments to be updated\n Promise.all(segments.map((seg) => seg.updateComplete)).then(() => {\n // Wait frames to ensure connectedCallback has run and properties are set\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n resolve(this.segments);\n });\n });\n });\n } else if (attempts < maxAttempts) {\n attempts++;\n requestAnimationFrame(checkSegments);\n } else {\n // Timeout - return empty array (might be empty text)\n resolve([]);\n }\n };\n checkSegments();\n });\n }\n\n connectedCallback() {\n super.connectedCallback();\n // Find and store template element before any modifications\n this._templateElement = this.querySelector(\"template\");\n\n // Initialize _textContent from DOM if not already set (for declarative usage)\n if (this._textContent === null) {\n this._textContent = this.getTextContent();\n this.lastTextContent = this._textContent;\n }\n\n // Use requestAnimationFrame to ensure DOM is ready\n requestAnimationFrame(() => {\n this.setupMutationObserver();\n this.splitText();\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.mutationObserver?.disconnect();\n }\n\n protected updated(\n changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,\n ): void {\n if (\n changedProperties.has(\"split\") ||\n changedProperties.has(\"staggerMs\") ||\n changedProperties.has(\"easing\") ||\n changedProperties.has(\"durationMs\")\n ) {\n this.splitText();\n }\n }\n\n private setupMutationObserver() {\n this.mutationObserver = new MutationObserver(() => {\n // Only react to changes that aren't from our own segment creation\n const currentText = this._textContent || this.getTextContent();\n if (currentText !== this.lastTextContent) {\n this._textContent = currentText;\n this.lastTextContent = currentText;\n this.splitText();\n }\n });\n\n this.mutationObserver.observe(this, {\n childList: true,\n characterData: true,\n subtree: true,\n });\n }\n\n private getTextContent(): string {\n // Get text content, handling both text nodes and HTML content\n let text = \"\";\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent || \"\";\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n // Skip ef-text-segment elements (they're created by us)\n if (element.tagName === \"EF-TEXT-SEGMENT\") {\n continue;\n }\n // Skip template elements (they're templates, not content)\n if (element.tagName === \"TEMPLATE\") {\n continue;\n }\n text += element.textContent || \"\";\n }\n }\n return text;\n }\n\n private splitText() {\n // Validate split mode\n const validatedSplit = this.validateSplit(this.split);\n if (validatedSplit !== this.split) {\n this.split = validatedSplit;\n return; // Will trigger updated() which calls splitText() again\n }\n\n // Validate stagger\n const validatedStagger = this.validateStagger(this.staggerMs);\n if (validatedStagger !== this.staggerMs) {\n this.staggerMs = validatedStagger;\n return; // Will trigger updated() which calls splitText() again\n }\n\n // Read text content - use stored _textContent if set, otherwise read from DOM\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n // Clear segments if no text\n const existingSegments = Array.from(\n this.querySelectorAll(\"ef-text-segment\"),\n );\n for (const segment of existingSegments) {\n segment.remove();\n }\n // Clear text nodes\n const textNodes: ChildNode[] = [];\n for (const node of Array.from(this.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n textNodes.push(node as ChildNode);\n }\n }\n for (const node of textNodes) {\n node.remove();\n }\n this.lastTextContent = \"\";\n // Resolve any waiting promises\n this._segmentsReadyResolvers.forEach((resolve) => {\n resolve();\n });\n this._segmentsReadyResolvers = [];\n return;\n }\n\n const segments = this.splitTextIntoSegments(text);\n const durationMs = this.durationMs || 1000; // Default 1 second if no duration\n\n // Clear ALL child nodes (text nodes and segments) by replacing innerHTML\n // This ensures we don't have any leftover text nodes\n const fragment = document.createDocumentFragment();\n\n // Find template element if not already stored\n if (!this._templateElement) {\n this._templateElement = this.querySelector(\"template\");\n }\n\n // Get template content structure\n // If template exists, clone it; otherwise create default ef-text-segment\n const templateContent = this._templateElement?.content;\n const templateSegments = templateContent\n ? Array.from(templateContent.querySelectorAll(\"ef-text-segment\"))\n : [];\n\n // If no template segments found, we'll create a default one\n const useTemplate = templateSegments.length > 0;\n const segmentsPerTextSegment = useTemplate ? templateSegments.length : 1;\n\n // Create new segments in a fragment first\n segments.forEach((segmentText, textIndex) => {\n // Calculate stagger offset if stagger is set\n let staggerOffset: number | undefined;\n if (this.staggerMs !== undefined) {\n // Apply easing to the stagger offset\n // Normalize index to 0-1 range (0 for first segment, 1 for last segment)\n const totalSegments = segments.length;\n const normalizedProgress =\n totalSegments > 1 ? textIndex / (totalSegments - 1) : 0;\n\n // Apply easing function to get eased progress\n const easedProgress = evaluateEasing(this.easing, normalizedProgress);\n\n // Calculate total stagger duration (last segment gets full stagger)\n const totalStaggerDuration = (totalSegments - 1) * this.staggerMs;\n\n // Apply eased progress to total stagger duration\n staggerOffset = easedProgress * totalStaggerDuration;\n }\n\n if (useTemplate && templateContent) {\n // Clone template content for each text segment\n // This allows multiple ef-text-segment elements per character/word/line\n const clonedContent = templateContent.cloneNode(\n true,\n ) as DocumentFragment;\n const clonedSegments = Array.from(\n clonedContent.querySelectorAll(\"ef-text-segment\"),\n ) as EFTextSegment[];\n\n clonedSegments.forEach((segment, templateIndex) => {\n // Set properties - Lit will process these when element is connected\n segment.segmentText = segmentText;\n // Calculate segment index accounting for multiple segments per text segment\n segment.segmentIndex =\n textIndex * segmentsPerTextSegment + templateIndex;\n segment.segmentStartMs = 0;\n segment.segmentEndMs = durationMs;\n segment.staggerOffsetMs = staggerOffset ?? 0;\n\n // Set data attribute for line mode to enable block display\n if (this.split === \"line\") {\n segment.setAttribute(\"data-line-segment\", \"true\");\n }\n\n // Mark as created to avoid being picked up as template\n segment.setAttribute(\"data-segment-created\", \"true\");\n\n fragment.appendChild(segment);\n });\n } else {\n // No template - create default ef-text-segment\n const segment = document.createElement(\n \"ef-text-segment\",\n ) as EFTextSegment;\n\n segment.segmentText = segmentText;\n segment.segmentIndex = textIndex;\n segment.segmentStartMs = 0;\n segment.segmentEndMs = durationMs;\n segment.staggerOffsetMs = staggerOffset ?? 0;\n\n // Set data attribute for line mode to enable block display\n if (this.split === \"line\") {\n segment.setAttribute(\"data-line-segment\", \"true\");\n }\n\n // Mark as created to avoid being picked up as template\n segment.setAttribute(\"data-segment-created\", \"true\");\n\n fragment.appendChild(segment);\n }\n });\n\n // Ensure segments are connected to DOM before checking for animations\n // Append fragment first, then trigger updates\n\n // Replace all children with the fragment (this clears text nodes and old segments)\n // But preserve the template element if it exists\n const templateToPreserve = this._templateElement;\n while (this.firstChild) {\n const child = this.firstChild;\n // Don't remove the template element\n if (child === templateToPreserve) {\n // Skip template, but we need to move it after the fragment\n // So we'll remove it temporarily and re-add it after\n this.removeChild(child);\n continue;\n }\n this.removeChild(child);\n }\n this.appendChild(fragment);\n // Re-add template element if it existed\n if (templateToPreserve) {\n this.appendChild(templateToPreserve);\n }\n\n // Segments will pause their own animations in connectedCallback\n // Lit will automatically update them when they're connected to the DOM\n // Ensure segments are updated after being connected\n requestAnimationFrame(() => {\n const segmentElements = this.segments;\n Promise.all(segmentElements.map((seg) => seg.updateComplete)).then(() => {\n // Wait an additional frame to ensure animations are paused in connectedCallback\n // Then trigger updateAnimations to set correct state\n // This ensures animations are positioned correctly on first load\n requestAnimationFrame(() => {\n const rootTimegroup = this.rootTimegroup;\n if (rootTimegroup) {\n updateAnimations(rootTimegroup);\n } else {\n updateAnimations(this);\n }\n });\n });\n });\n\n this.lastTextContent = text;\n this._textContent = text;\n\n // Resolve any waiting promises after segments are connected\n requestAnimationFrame(() => {\n this._segmentsReadyResolvers.forEach((resolve) => {\n resolve();\n });\n this._segmentsReadyResolvers = [];\n });\n }\n\n private splitTextIntoSegments(text: string): string[] {\n // Trim text before segmenting to remove leading/trailing whitespace\n const trimmedText = text.trim();\n if (!trimmedText) {\n return [];\n }\n\n switch (this.split) {\n case \"line\": {\n // Split on newlines and trim each line\n const lines = trimmedText.split(/\\r?\\n/);\n return lines\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n }\n case \"word\": {\n // Use Intl.Segmenter for locale-aware word segmentation\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: \"word\",\n });\n const segments = Array.from(segmenter.segment(trimmedText));\n // Filter to only include word-like segments (excludes whitespace/punctuation)\n return segments\n .filter((seg) => seg.isWordLike)\n .map((seg) => seg.segment);\n }\n case \"char\": {\n // Use Intl.Segmenter for grapheme-aware character segmentation\n const segmenter = new Intl.Segmenter(undefined, {\n granularity: \"grapheme\",\n });\n const segments = Array.from(segmenter.segment(trimmedText));\n return segments.map((seg) => seg.segment);\n }\n default:\n return [trimmedText];\n }\n }\n\n get intrinsicDurationMs(): number | undefined {\n // If explicit duration is set, use it\n if (this.hasExplicitDuration) {\n return undefined; // Let explicit duration take precedence\n }\n\n // Otherwise, calculate from content\n // Use _textContent if set, otherwise read from DOM\n const text =\n this._textContent !== null ? this._textContent : this.getTextContent();\n if (!text || text.trim().length === 0) {\n return 0;\n }\n\n // Use the same splitting logic as splitTextIntoSegments for consistency\n const segments = this.splitTextIntoSegments(text);\n const segmentCount = segments.length || 1;\n\n return segmentCount * 1000;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-text\": EFText;\n }\n}\n"],"mappings":";;;;;;;;;AAWO,mBAAMA,iBAAe,WAAW,WAAW,CAAC;;;eAyB9B;gBA6BV;yBAGiB;sBACY;0BACiB;iCACF,EAAE;;;gBA3DvC,CACd,GAAG;;;;;;;;;;;;;;;;;;;MAoBJ;;CAKD,AAAQ,cAAc,OAA0B;AAC9C,MAAI,UAAU,UAAU,UAAU,UAAU,UAAU,OACpD,QAAO;AAET,UAAQ,KACN,wBAAwB,MAAM,6DAC/B;AACD,SAAO;;CAUT,AAAQ,gBAAgB,OAA+C;AACrE,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,QAAQ,GAAG;AACb,WAAQ,KAAK,yBAAyB,MAAM,4BAA4B;AACxE,UAAO;;AAET,SAAO;;CAYT,SAAS;AACP,SAAO,IAAI;;CAIb,IAAI,YAAY,OAAsB;EACpC,MAAM,WAAW,SAAS;AAE1B,MAAI,KAAK,iBAAiB,UAAU;AAClC,QAAK,eAAe;AAGpB,OAAI,CAAC,KAAK,oBAAoB,KAAK,YACjC,MAAK,mBAAmB,KAAK,cAAc,WAAW;GAIxD,MAAMC,YAAyB,EAAE;AACjC,QAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,CAC5C,KAAI,KAAK,aAAa,KAAK,UACzB,WAAU,KAAK,KAAkB;AAGrC,QAAK,MAAM,QAAQ,UACjB,MAAK,QAAQ;AAGf,OAAI,UAAU;IACZ,MAAM,WAAW,SAAS,eAAe,SAAS;AAClD,SAAK,YAAY,SAAS;;AAG5B,OAAI,KAAK,YACP,MAAK,WAAW;;;CAKtB,IAAI,cAAsB;AAExB,MAAI,KAAK,iBAAiB,KACxB,QAAO,KAAK,gBAAgB;AAG9B,SAAO,KAAK;;;;;;CAOd,IAAI,WAA4B;AAC9B,SAAO,MAAM,KACX,KAAK,iBAAiB,wCAAwC,CAC/D;;;;;;;CAQH,MAAM,oBAA8C;AAElD,QAAM,KAAK;EAIX,MAAM,OACJ,KAAK,iBAAiB,OAAO,KAAK,eAAe,KAAK,gBAAgB;AACxE,MAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,WAAW,EAClC,QAAO,EAAE;AAIX,QAAM,IAAI,SAAS,YAAY,sBAAsB,QAAQ,CAAC;EAG9D,IAAI,WAAW,KAAK;AACpB,MAAI,SAAS,SAAS,GAAG;AAEvB,SAAM,QAAQ,IAAI,SAAS,KAAK,QAAQ,IAAI,eAAe,CAAC;AAE5D,SAAM,IAAI,SAAS,YAAY,sBAAsB,QAAQ,CAAC;AAE9D,SAAM,IAAI,SAAS,YAAY,sBAAsB,QAAQ,CAAC;AAC9D,UAAO,KAAK;;AAId,SAAO,IAAI,SAA0B,YAAY;GAC/C,IAAI,WAAW;GACf,MAAM,cAAc;GAEpB,MAAM,sBAAsB;AAC1B,eAAW,KAAK;AAChB,QAAI,SAAS,SAAS,EAEpB,SAAQ,IAAI,SAAS,KAAK,QAAQ,IAAI,eAAe,CAAC,CAAC,WAAW;AAEhE,iCAA4B;AAC1B,kCAA4B;AAC1B,eAAQ,KAAK,SAAS;QACtB;OACF;MACF;aACO,WAAW,aAAa;AACjC;AACA,2BAAsB,cAAc;UAGpC,SAAQ,EAAE,CAAC;;AAGf,kBAAe;IACf;;CAGJ,oBAAoB;AAClB,QAAM,mBAAmB;AAEzB,OAAK,mBAAmB,KAAK,cAAc,WAAW;AAGtD,MAAI,KAAK,iBAAiB,MAAM;AAC9B,QAAK,eAAe,KAAK,gBAAgB;AACzC,QAAK,kBAAkB,KAAK;;AAI9B,8BAA4B;AAC1B,QAAK,uBAAuB;AAC5B,QAAK,WAAW;IAChB;;CAGJ,uBAAuB;AACrB,QAAM,sBAAsB;AAC5B,OAAK,kBAAkB,YAAY;;CAGrC,AAAU,QACR,mBACM;AACN,MACE,kBAAkB,IAAI,QAAQ,IAC9B,kBAAkB,IAAI,YAAY,IAClC,kBAAkB,IAAI,SAAS,IAC/B,kBAAkB,IAAI,aAAa,CAEnC,MAAK,WAAW;;CAIpB,AAAQ,wBAAwB;AAC9B,OAAK,mBAAmB,IAAI,uBAAuB;GAEjD,MAAM,cAAc,KAAK,gBAAgB,KAAK,gBAAgB;AAC9D,OAAI,gBAAgB,KAAK,iBAAiB;AACxC,SAAK,eAAe;AACpB,SAAK,kBAAkB;AACvB,SAAK,WAAW;;IAElB;AAEF,OAAK,iBAAiB,QAAQ,MAAM;GAClC,WAAW;GACX,eAAe;GACf,SAAS;GACV,CAAC;;CAGJ,AAAQ,iBAAyB;EAE/B,IAAI,OAAO;AACX,OAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,CAC5C,KAAI,KAAK,aAAa,KAAK,UACzB,SAAQ,KAAK,eAAe;WACnB,KAAK,aAAa,KAAK,cAAc;GAC9C,MAAM,UAAU;AAEhB,OAAI,QAAQ,YAAY,kBACtB;AAGF,OAAI,QAAQ,YAAY,WACtB;AAEF,WAAQ,QAAQ,eAAe;;AAGnC,SAAO;;CAGT,AAAQ,YAAY;EAElB,MAAM,iBAAiB,KAAK,cAAc,KAAK,MAAM;AACrD,MAAI,mBAAmB,KAAK,OAAO;AACjC,QAAK,QAAQ;AACb;;EAIF,MAAM,mBAAmB,KAAK,gBAAgB,KAAK,UAAU;AAC7D,MAAI,qBAAqB,KAAK,WAAW;AACvC,QAAK,YAAY;AACjB;;EAIF,MAAM,OACJ,KAAK,iBAAiB,OAAO,KAAK,eAAe,KAAK,gBAAgB;AACxE,MAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,WAAW,GAAG;GAErC,MAAM,mBAAmB,MAAM,KAC7B,KAAK,iBAAiB,kBAAkB,CACzC;AACD,QAAK,MAAM,WAAW,iBACpB,SAAQ,QAAQ;GAGlB,MAAMA,YAAyB,EAAE;AACjC,QAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,CAC5C,KAAI,KAAK,aAAa,KAAK,UACzB,WAAU,KAAK,KAAkB;AAGrC,QAAK,MAAM,QAAQ,UACjB,MAAK,QAAQ;AAEf,QAAK,kBAAkB;AAEvB,QAAK,wBAAwB,SAAS,YAAY;AAChD,aAAS;KACT;AACF,QAAK,0BAA0B,EAAE;AACjC;;EAGF,MAAM,WAAW,KAAK,sBAAsB,KAAK;EACjD,MAAM,aAAa,KAAK,cAAc;EAItC,MAAM,WAAW,SAAS,wBAAwB;AAGlD,MAAI,CAAC,KAAK,iBACR,MAAK,mBAAmB,KAAK,cAAc,WAAW;EAKxD,MAAM,kBAAkB,KAAK,kBAAkB;EAC/C,MAAM,mBAAmB,kBACrB,MAAM,KAAK,gBAAgB,iBAAiB,kBAAkB,CAAC,GAC/D,EAAE;EAGN,MAAM,cAAc,iBAAiB,SAAS;EAC9C,MAAM,yBAAyB,cAAc,iBAAiB,SAAS;AAGvE,WAAS,SAAS,aAAa,cAAc;GAE3C,IAAIC;AACJ,OAAI,KAAK,cAAc,QAAW;IAGhC,MAAM,gBAAgB,SAAS;IAC/B,MAAM,qBACJ,gBAAgB,IAAI,aAAa,gBAAgB,KAAK;AASxD,oBANsB,eAAe,KAAK,QAAQ,mBAAmB,KAGvC,gBAAgB,KAAK,KAAK;;AAM1D,OAAI,eAAe,iBAAiB;IAGlC,MAAM,gBAAgB,gBAAgB,UACpC,KACD;AAKD,IAJuB,MAAM,KAC3B,cAAc,iBAAiB,kBAAkB,CAClD,CAEc,SAAS,SAAS,kBAAkB;AAEjD,aAAQ,cAAc;AAEtB,aAAQ,eACN,YAAY,yBAAyB;AACvC,aAAQ,iBAAiB;AACzB,aAAQ,eAAe;AACvB,aAAQ,kBAAkB,iBAAiB;AAG3C,SAAI,KAAK,UAAU,OACjB,SAAQ,aAAa,qBAAqB,OAAO;AAInD,aAAQ,aAAa,wBAAwB,OAAO;AAEpD,cAAS,YAAY,QAAQ;MAC7B;UACG;IAEL,MAAM,UAAU,SAAS,cACvB,kBACD;AAED,YAAQ,cAAc;AACtB,YAAQ,eAAe;AACvB,YAAQ,iBAAiB;AACzB,YAAQ,eAAe;AACvB,YAAQ,kBAAkB,iBAAiB;AAG3C,QAAI,KAAK,UAAU,OACjB,SAAQ,aAAa,qBAAqB,OAAO;AAInD,YAAQ,aAAa,wBAAwB,OAAO;AAEpD,aAAS,YAAY,QAAQ;;IAE/B;EAOF,MAAM,qBAAqB,KAAK;AAChC,SAAO,KAAK,YAAY;GACtB,MAAM,QAAQ,KAAK;AAEnB,OAAI,UAAU,oBAAoB;AAGhC,SAAK,YAAY,MAAM;AACvB;;AAEF,QAAK,YAAY,MAAM;;AAEzB,OAAK,YAAY,SAAS;AAE1B,MAAI,mBACF,MAAK,YAAY,mBAAmB;AAMtC,8BAA4B;GAC1B,MAAM,kBAAkB,KAAK;AAC7B,WAAQ,IAAI,gBAAgB,KAAK,QAAQ,IAAI,eAAe,CAAC,CAAC,WAAW;AAIvE,gCAA4B;KAC1B,MAAM,gBAAgB,KAAK;AAC3B,SAAI,cACF,kBAAiB,cAAc;SAE/B,kBAAiB,KAAK;MAExB;KACF;IACF;AAEF,OAAK,kBAAkB;AACvB,OAAK,eAAe;AAGpB,8BAA4B;AAC1B,QAAK,wBAAwB,SAAS,YAAY;AAChD,aAAS;KACT;AACF,QAAK,0BAA0B,EAAE;IACjC;;CAGJ,AAAQ,sBAAsB,MAAwB;EAEpD,MAAM,cAAc,KAAK,MAAM;AAC/B,MAAI,CAAC,YACH,QAAO,EAAE;AAGX,UAAQ,KAAK,OAAb;GACE,KAAK,OAGH,QADc,YAAY,MAAM,QAAQ,CAErC,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAS,KAAK,SAAS,EAAE;GAEtC,KAAK,QAAQ;IAEX,MAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAC9C,aAAa,QACd,CAAC;AAGF,WAFiB,MAAM,KAAK,UAAU,QAAQ,YAAY,CAAC,CAGxD,QAAQ,QAAQ,IAAI,WAAW,CAC/B,KAAK,QAAQ,IAAI,QAAQ;;GAE9B,KAAK,QAAQ;IAEX,MAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAC9C,aAAa,YACd,CAAC;AAEF,WADiB,MAAM,KAAK,UAAU,QAAQ,YAAY,CAAC,CAC3C,KAAK,QAAQ,IAAI,QAAQ;;GAE3C,QACE,QAAO,CAAC,YAAY;;;CAI1B,IAAI,sBAA0C;AAE5C,MAAI,KAAK,oBACP;EAKF,MAAM,OACJ,KAAK,iBAAiB,OAAO,KAAK,eAAe,KAAK,gBAAgB;AACxE,MAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,WAAW,EAClC,QAAO;AAOT,UAHiB,KAAK,sBAAsB,KAAK,CACnB,UAAU,KAElB;;;YAvevB,SAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,CAAC;YAazC,SAAS;CACR,MAAM;CACN,WAAW;CACX,WAAW;CACZ,CAAC;YAYD,SAAS;CAAE,MAAM;CAAQ,SAAS;CAAM,CAAC;qBAtD3C,cAAc,UAAU"}
@@ -1,13 +1,13 @@
1
1
  import { TemporalMixinInterface } from "./EFTemporal.js";
2
- import * as lit9 from "lit";
2
+ import * as lit10 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html9 from "lit-html";
4
+ import * as lit_html10 from "lit-html";
5
5
 
6
6
  //#region src/elements/EFTextSegment.d.ts
7
7
  declare const EFTextSegment_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
8
8
  declare class EFTextSegment extends EFTextSegment_base {
9
- static styles: lit9.CSSResult[];
10
- render(): lit_html9.TemplateResult<1>;
9
+ static styles: lit10.CSSResult[];
10
+ render(): lit_html10.TemplateResult<1>;
11
11
  private _animationsPaused;
12
12
  connectedCallback(): void;
13
13
  segmentText: string;
@@ -4,10 +4,10 @@ import { MediaEngine } from "../transcoding/types/index.js";
4
4
  import { EFMedia } from "./EFMedia.js";
5
5
  import { VideoBufferState } from "./EFMedia/videoTasks/makeVideoBufferTask.js";
6
6
  import { Task } from "@lit/task";
7
- import * as lit2 from "lit";
7
+ import * as lit3 from "lit";
8
8
  import { PropertyValueMap } from "lit";
9
9
  import * as mediabunny0 from "mediabunny";
10
- import * as lit_html2 from "lit-html";
10
+ import * as lit_html3 from "lit-html";
11
11
  import * as lit_html_directives_ref0 from "lit-html/directives/ref";
12
12
 
13
13
  //#region src/elements/EFVideo.d.ts
@@ -21,7 +21,7 @@ interface LoadingState {
21
21
  }
22
22
  declare const EFVideo_base: typeof EFMedia;
23
23
  declare class EFVideo extends EFVideo_base {
24
- static styles: lit2.CSSResult[];
24
+ static styles: lit3.CSSResult[];
25
25
  canvasRef: lit_html_directives_ref0.Ref<HTMLCanvasElement>;
26
26
  /**
27
27
  * Duration in milliseconds for video buffering ahead of current time
@@ -60,7 +60,7 @@ declare class EFVideo extends EFVideo_base {
60
60
  };
61
61
  constructor();
62
62
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
63
- render(): lit_html2.TemplateResult<1>;
63
+ render(): lit_html3.TemplateResult<1>;
64
64
  get canvasElement(): HTMLCanvasElement | undefined;
65
65
  frameTask: Task<readonly [number], void>;
66
66
  /**
@@ -3,21 +3,21 @@ import { EFAudio } from "./EFAudio.js";
3
3
  import { EFVideo } from "./EFVideo.js";
4
4
  import { TargetController } from "./TargetController.js";
5
5
  import { Task } from "@lit/task";
6
- import * as lit10 from "lit";
6
+ import * as lit11 from "lit";
7
7
  import { LitElement, PropertyValueMap } from "lit";
8
8
  import { Ref } from "lit/directives/ref.js";
9
- import * as lit_html10 from "lit-html";
9
+ import * as lit_html11 from "lit-html";
10
10
 
11
11
  //#region src/elements/EFWaveform.d.ts
12
12
  declare const EFWaveform_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
13
13
  declare class EFWaveform extends EFWaveform_base {
14
- static styles: lit10.CSSResult;
14
+ static styles: lit11.CSSResult;
15
15
  canvasRef: Ref<HTMLCanvasElement>;
16
16
  private ctx;
17
17
  private styleObserver;
18
18
  private resizeObserver?;
19
19
  private mutationObserver?;
20
- render(): lit_html10.TemplateResult<1>;
20
+ render(): lit_html11.TemplateResult<1>;
21
21
  mode: "roundBars" | "bars" | "bricks" | "line" | "curve" | "pixel" | "wave" | "spikes";
22
22
  color: string;
23
23
  target: string;
@@ -1,15 +1,15 @@
1
- import * as lit11 from "lit";
1
+ import * as lit12 from "lit";
2
2
  import { LitElement } from "lit";
3
- import * as lit_html11 from "lit-html";
3
+ import * as lit_html12 from "lit-html";
4
4
 
5
5
  //#region src/gui/EFConfiguration.d.ts
6
6
  declare class EFConfiguration extends LitElement {
7
- static styles: lit11.CSSResult[];
7
+ static styles: lit12.CSSResult[];
8
8
  efConfiguration: this;
9
9
  apiHost?: string;
10
10
  signingURL: string;
11
11
  mediaEngine?: "cloud" | "local";
12
- render(): lit_html11.TemplateResult<1>;
12
+ render(): lit_html12.TemplateResult<1>;
13
13
  }
14
14
  declare global {
15
15
  interface HTMLElementTagNameMap {
@@ -7,7 +7,7 @@ import { Caption } from "../elements/EFCaptions.js";
7
7
  import { EFTextSegment } from "../elements/EFTextSegment.js";
8
8
  import { TimegroupController } from "../elements/TimegroupController.js";
9
9
  import { FocusContext } from "./focusContext.js";
10
- import * as lit14 from "lit";
10
+ import * as lit15 from "lit";
11
11
  import { LitElement, PropertyValueMap, ReactiveController, TemplateResult, nothing } from "lit";
12
12
  import * as lit_html_directives_ref0 from "lit-html/directives/ref";
13
13
 
@@ -22,7 +22,7 @@ declare class ElementFilmstripController implements ReactiveController {
22
22
  }
23
23
  declare const FilmstripItem_base: typeof LitElement;
24
24
  declare class FilmstripItem extends FilmstripItem_base {
25
- static styles: lit14.CSSResult[];
25
+ static styles: lit15.CSSResult[];
26
26
  focusContext?: FocusContext;
27
27
  focusedElement?: HTMLElement | null;
28
28
  get isFocused(): boolean;
@@ -166,7 +166,7 @@ declare class EFHTMLHierarchyItem extends EFHierarchyItem {
166
166
  declare const EFFilmstrip_base: typeof LitElement;
167
167
  declare class EFFilmstrip extends EFFilmstrip_base {
168
168
  #private;
169
- static styles: lit14.CSSResult[];
169
+ static styles: lit15.CSSResult[];
170
170
  pixelsPerMs: number;
171
171
  hide: string;
172
172
  show: string;
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit18 from "lit";
2
+ import * as lit19 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html16 from "lit-html";
4
+ import * as lit_html17 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFPause.d.ts
7
7
  declare const EFPause_base: (new (...args: any[]) => {
@@ -10,13 +10,13 @@ declare const EFPause_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFPause extends EFPause_base {
13
- static styles: lit18.CSSResult[];
13
+ static styles: lit19.CSSResult[];
14
14
  playing: boolean;
15
15
  get efContext(): ControllableInterface | null;
16
16
  connectedCallback(): void;
17
17
  disconnectedCallback(): void;
18
18
  updated(changedProperties: Map<string | number | symbol, unknown>): void;
19
- render(): lit_html16.TemplateResult<1>;
19
+ render(): lit_html17.TemplateResult<1>;
20
20
  handleClick: () => void;
21
21
  }
22
22
  declare global {
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit17 from "lit";
2
+ import * as lit18 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html15 from "lit-html";
4
+ import * as lit_html16 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFPlay.d.ts
7
7
  declare const EFPlay_base: (new (...args: any[]) => {
@@ -10,13 +10,13 @@ declare const EFPlay_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFPlay extends EFPlay_base {
13
- static styles: lit17.CSSResult[];
13
+ static styles: lit18.CSSResult[];
14
14
  playing: boolean;
15
15
  get efContext(): ControllableInterface | null;
16
16
  connectedCallback(): void;
17
17
  disconnectedCallback(): void;
18
18
  updated(changedProperties: Map<string | number | symbol, unknown>): void;
19
- render(): lit_html15.TemplateResult<1>;
19
+ render(): lit_html16.TemplateResult<1>;
20
20
  handleClick: () => void;
21
21
  }
22
22
  declare global {
@@ -1,19 +1,19 @@
1
1
  import { ContextMixinInterface } from "./ContextMixin.js";
2
- import * as lit13 from "lit";
2
+ import * as lit14 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html13 from "lit-html";
4
+ import * as lit_html14 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFPreview.d.ts
7
7
  declare const EFPreview_base: (new (...args: any[]) => ContextMixinInterface) & typeof LitElement;
8
8
  declare class EFPreview extends EFPreview_base {
9
- static styles: lit13.CSSResult[];
9
+ static styles: lit14.CSSResult[];
10
10
  focusedElement?: HTMLElement;
11
11
  /**
12
12
  * Find the closest temporal element (timegroup, video, audio, etc.)
13
13
  */
14
14
  private findClosestTemporal;
15
15
  constructor();
16
- render(): lit_html13.TemplateResult<1>;
16
+ render(): lit_html14.TemplateResult<1>;
17
17
  }
18
18
  declare global {
19
19
  interface HTMLElementTagNameMap {
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit20 from "lit";
2
+ import * as lit21 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html18 from "lit-html";
4
+ import * as lit_html19 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFScrubber.d.ts
7
7
  declare const EFScrubber_base: (new (...args: any[]) => {
@@ -10,7 +10,7 @@ declare const EFScrubber_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFScrubber extends EFScrubber_base {
13
- static styles: lit20.CSSResult[];
13
+ static styles: lit21.CSSResult[];
14
14
  playing: boolean;
15
15
  currentTimeMs: number;
16
16
  durationMs: number;
@@ -25,7 +25,7 @@ declare class EFScrubber extends EFScrubber_base {
25
25
  private boundHandlePointerUp;
26
26
  private boundHandlePointerCancel;
27
27
  private boundHandleContextMenu;
28
- render(): lit_html18.TemplateResult<1>;
28
+ render(): lit_html19.TemplateResult<1>;
29
29
  connectedCallback(): void;
30
30
  disconnectedCallback(): void;
31
31
  }
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit21 from "lit";
2
+ import * as lit0 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html19 from "lit-html";
4
+ import * as lit_html0 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFTimeDisplay.d.ts
7
7
  declare const EFTimeDisplay_base: (new (...args: any[]) => {
@@ -10,11 +10,11 @@ declare const EFTimeDisplay_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFTimeDisplay extends EFTimeDisplay_base {
13
- static styles: lit21.CSSResult;
13
+ static styles: lit0.CSSResult;
14
14
  currentTimeMs: number;
15
15
  durationMs: number;
16
16
  private formatTime;
17
- render(): lit_html19.TemplateResult<1>;
17
+ render(): lit_html0.TemplateResult<1>;
18
18
  }
19
19
  declare global {
20
20
  interface HTMLElementTagNameMap {
@@ -1,7 +1,7 @@
1
1
  import { ControllableInterface } from "./Controllable.js";
2
- import * as lit19 from "lit";
2
+ import * as lit20 from "lit";
3
3
  import { LitElement } from "lit";
4
- import * as lit_html17 from "lit-html";
4
+ import * as lit_html18 from "lit-html";
5
5
 
6
6
  //#region src/gui/EFToggleLoop.d.ts
7
7
  declare const EFToggleLoop_base: (new (...args: any[]) => {
@@ -10,9 +10,9 @@ declare const EFToggleLoop_base: (new (...args: any[]) => {
10
10
  effectiveContext: ControllableInterface | null;
11
11
  }) & typeof LitElement;
12
12
  declare class EFToggleLoop extends EFToggleLoop_base {
13
- static styles: lit19.CSSResult[];
13
+ static styles: lit20.CSSResult[];
14
14
  get context(): ControllableInterface | null;
15
- render(): lit_html17.TemplateResult<1>;
15
+ render(): lit_html18.TemplateResult<1>;
16
16
  }
17
17
  declare global {
18
18
  interface HTMLElementTagNameMap {