UNPKG

asciitorium

Version:

an ASCII ui framework for web + cli

62 lines (61 loc) 2.62 kB
import { Component } from '../core/Component'; import { requestRender } from '../core/RenderScheduler'; export class ProgressBar extends Component { constructor(options) { options.height = 3; options.border = false; super(options); // Store percent as 0–100 internally this.value = 0; this.showPercentage = options.showPercentage ?? false; this.durationMs = options.durationMs ?? 1000; // Bind to a 0–100 State<number> this.bind(options.percent, (newValue) => { this.animateTo(newValue, this.durationMs); }); } animateTo(value, durationMs = 1000) { // Clamp to 0–100 const target = Math.max(0, Math.min(100, value)); if (this.animationInterval) clearInterval(this.animationInterval); const steps = 10; const delay = durationMs / steps; const start = this.value; // also 0–100 let currentStep = 0; this.animationInterval = setInterval(() => { currentStep++; const t = currentStep / steps; // 0..1 this.value = start + (target - start) * t; if (currentStep >= steps) { clearInterval(this.animationInterval); this.animationInterval = undefined; this.value = target; } requestRender(); }, delay); } draw() { const width = this.width ?? 10; const innerWidth = width - 2; // Convert 0–100 to cells filled const filledLength = Math.round((this.value / 100) * innerWidth); const emptyLength = Math.max(0, innerWidth - filledLength); let barContent = '█'.repeat(Math.max(0, filledLength)) + ' '.repeat(Math.max(0, emptyLength)); if (this.showPercentage && innerWidth > 0) { const percentStr = `${Math.round(this.value)}%`; // Center the text; if it overflows, truncate const startIdx = Math.max(0, Math.floor((innerWidth - percentStr.length) / 2)); const before = barContent.slice(0, startIdx); const after = barContent.slice(startIdx + percentStr.length); barContent = (before + percentStr + after).slice(0, innerWidth); } // Frame lines (kept as in your original) const top = ' ⎽' + '⎽'.repeat(Math.max(0, width - 3)); const mid = `⎹${barContent}⎸`; const bot = ' ' + '⎺'.repeat(Math.max(0, width - 2)); this.buffer = [top, mid, bot].map((line) => Array.from(line)); return this.buffer; } }