UNPKG

@novely/typewriter

Version:
116 lines (115 loc) 2.43 kB
// src/utils.ts var defaultSpeed = () => { return Math.min(90 * Math.random() + 100, 90); }; var collectTextNodes = (el) => { const items = []; el.childNodes.forEach((child) => { if (child.nodeName === "#text") items.push(child); else items.push(...collectTextNodes(child)); }); return items; }; // src/index.ts var map = (it, cb) => { const result = []; for (const value of it) { const val = cb(value, result.at(-1)); if (val) { result.push(val); } } return result; }; var typewriter = ({ node, text, ended, speed = defaultSpeed }) => { node.innerHTML = text; const nodes = collectTextNodes(node).map((child) => { const letters = map(child.textContent, (char, prev) => { if (char === " " && prev) { prev.textContent += " "; return void 0; } else { const text2 = document.createElement("span"); text2.textContent = char; text2.style.opacity = "0"; return text2; } }); child.replaceWith(...letters); return letters; }); let current = 0; let pos = 0; let end = false; let frame; const enqueue = () => { frame = requestAnimationFrame(queue); }; const dequeue = () => { cancelAnimationFrame(frame); }; let timeout = 0; let start = 0; let container; const queue = (time) => { if (time >= start + timeout) { start = time; timeout = speed(); process(); } else if (end) { dequeue(); } else { enqueue(); } }; const process = () => { const block = nodes[current]; if (block?.length > pos) { const span = block[pos]; const text2 = span.textContent; if (pos++ === 0) { span.replaceWith(container = document.createTextNode(text2)); } else { container.textContent += text2; span.remove(); } enqueue(); } else if (current++ < nodes.length) { pos = 0; enqueue(); } else { end = true; dequeue(); ended && ended(); } }; process(); return { /** * End */ end() { dequeue(); if (end) { node.innerHTML = ""; return end; } node.innerHTML = text; end = true; return false; }, /** * Destroy */ destroy() { dequeue(); node.innerHTML = ""; } }; }; export { typewriter }; //# sourceMappingURL=index.js.map