@novely/typewriter
Version:
Эффект пишущей машинки
116 lines (115 loc) • 2.43 kB
JavaScript
// 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