Files
oh-my-pi/packages/tui/src/components/loader.ts
T
2026-02-10 07:39:39 +01:00

60 lines
1.3 KiB
TypeScript

import type { TUI } from "../tui";
import { Text } from "./text";
/**
* Loader component that updates every 80ms with spinning animation
*/
export class Loader extends Text {
#frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
#currentFrame = 0;
#intervalId?: NodeJS.Timeout;
#ui: TUI | null = null;
constructor(
ui: TUI,
private spinnerColorFn: (str: string) => string,
private messageColorFn: (str: string) => string,
private message: string = "Loading...",
spinnerFrames?: string[],
) {
super("", 1, 0);
this.#ui = ui;
if (spinnerFrames && spinnerFrames.length > 0) {
this.#frames = spinnerFrames;
}
this.start();
}
render(width: number): string[] {
return ["", ...super.render(width)];
}
start() {
this.#updateDisplay();
this.#intervalId = setInterval(() => {
this.#currentFrame = (this.#currentFrame + 1) % this.#frames.length;
this.#updateDisplay();
}, 80);
}
stop() {
if (this.#intervalId) {
clearInterval(this.#intervalId);
this.#intervalId = undefined;
}
}
setMessage(message: string) {
this.message = message;
this.#updateDisplay();
}
#updateDisplay() {
const frame = this.#frames[this.#currentFrame];
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(this.message)}`);
if (this.#ui) {
this.#ui.requestRender();
}
}
}