mirror of
https://github.com/litruv/lit.ruv.wtf.git
synced 2026-07-24 02:36:02 +10:00
72 lines
2.1 KiB
JavaScript
72 lines
2.1 KiB
JavaScript
/**
|
|
* Manages a Twitch-chat-style stacked speech bubble above a print node element.
|
|
*
|
|
* Messages enter at the bottom of the stack, push older messages upward, and
|
|
* individually fade out after 5 seconds — matching the Twitch chat feel.
|
|
*/
|
|
export class PrintBubble {
|
|
/** @type {HTMLElement} */
|
|
#stack;
|
|
|
|
/** Each active message and its cleanup timer. @type {Array<{ el: HTMLElement, timer: number }>} */
|
|
#entries = [];
|
|
|
|
static #FADE_START_MS = 4500;
|
|
static #FADE_DURATION_MS = 500;
|
|
|
|
/**
|
|
* @param {HTMLElement} nodeEl - The node element to attach bubbles to.
|
|
*/
|
|
constructor(nodeEl) {
|
|
this.#stack = document.createElement("div");
|
|
this.#stack.className = "print-bubble-stack";
|
|
this.#stack.setAttribute("role", "log");
|
|
this.#stack.setAttribute("aria-live", "polite");
|
|
nodeEl.appendChild(this.#stack);
|
|
}
|
|
|
|
/**
|
|
* Pushes a new message onto the bubble stack.
|
|
*
|
|
* @param {string} text - The message to display.
|
|
*/
|
|
push(text) {
|
|
const msg = document.createElement("div");
|
|
msg.className = "print-bubble-msg";
|
|
msg.textContent = String(text);
|
|
this.#stack.appendChild(msg);
|
|
|
|
const entry = { el: msg, timer: 0 };
|
|
this.#entries.push(entry);
|
|
|
|
entry.timer = window.setTimeout(() => {
|
|
this.#fadeOut(entry);
|
|
}, PrintBubble.#FADE_START_MS);
|
|
}
|
|
|
|
/**
|
|
* Triggers the fade-out animation and removes the message element.
|
|
*
|
|
* @param {{ el: HTMLElement, timer: number }} entry
|
|
*/
|
|
#fadeOut(entry) {
|
|
entry.el.classList.add("is-fading");
|
|
window.setTimeout(() => {
|
|
entry.el.remove();
|
|
const idx = this.#entries.indexOf(entry);
|
|
if (idx !== -1) this.#entries.splice(idx, 1);
|
|
}, PrintBubble.#FADE_DURATION_MS);
|
|
}
|
|
|
|
/**
|
|
* Immediately clears all active messages and their timers.
|
|
*/
|
|
clear() {
|
|
for (const entry of this.#entries) {
|
|
window.clearTimeout(entry.timer);
|
|
entry.el.remove();
|
|
}
|
|
this.#entries = [];
|
|
}
|
|
}
|