import { IEditableAttribute } from "../../core/EditableAttributes.js"; import HtmlControl from "../../core/HtmlControl.js"; import { isInsideHtmlEditor } from "../../core/HtmlEditor.js"; export default class AnimatedText extends HtmlControl { root: ShadowRoot; static observedAttributes = ["text-content"]; get editableAttributes(): IEditableAttribute[] { return [ { name: "text-content", type: "string", value: "Animated Text" }, { name: "delay", type: "time", suggestions: [ { label: "150ms", value: "150ms" }, { label: "250ms", value: "250ms" }, ] } ] } attributeChangedCallback(name, oldValue, newValue) { switch(name) { case "text-content": case "delay": this.updateText(); break; } } updateText() { if (!this.isConnected) { return; } if (!this.root) { if (isInsideHtmlEditor(this)) { this.root = this.attachShadow({ mode: "open", delegatesFocus: true }); } } const root = this.root ?? this; const text = this.getAttribute("text-content"); root.innerHTML = ""; const delayStep = this.parseDelay(this.getAttribute("delay") || "150ms"); let delay = 0; for (const ch of text) { const span = root.ownerDocument.createElement("span"); span.append(ch === ' ' ? '\xa0' : ch); if (delay) { span.style.setProperty("--animation-delay", `${delay}ms`); } delay += delayStep; root.appendChild(span); } } parseDelay(delay: string) { let multiplier = 1; if (delay.endsWith("ms")) { multiplier = 1; } else if(delay.endsWith("s")) { multiplier = 1000; } return Number.parseInt(delay) * multiplier; } async prepare() { this.updateText(); } } customElements.define("animated-text", AnimatedText);