co-mono/packages/tui/src/components/loader.ts
2025-11-21 03:12:42 +01:00

55 lines
1.3 KiB
TypeScript

import type { TUI } from "../tui.js";
import { Text } from "./text.js";
/**
* Loader component that updates every 80ms with spinning animation
*/
export class Loader extends Text {
private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
private currentFrame = 0;
private intervalId: NodeJS.Timeout | null = null;
private ui: TUI | null = null;
constructor(
ui: TUI,
private spinnerColorFn: (str: string) => string,
private messageColorFn: (str: string) => string,
private message: string = "Loading...",
) {
super("", 1, 0);
this.ui = ui;
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 = null;
}
}
setMessage(message: string) {
this.message = message;
this.updateDisplay();
}
private updateDisplay() {
const frame = this.frames[this.currentFrame];
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(this.message)}`);
if (this.ui) {
this.ui.requestRender();
}
}
}