UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

160 lines 5.38 kB
import chalk from 'chalk'; export class ScrollManager { scrollPosition = 0; totalLines = 0; visibleHeight = 0; resetScroll() { this.scrollPosition = 0; } updateDimensions(totalLines, visibleHeight) { this.totalLines = totalLines; this.visibleHeight = visibleHeight; this.validateScrollPosition(); } scrollUp(lines = 1) { this.scrollPosition += lines; this.validateScrollPosition(); } scrollDown(lines = 1) { this.scrollPosition -= lines; this.validateScrollPosition(); } pageUp() { const pageSize = Math.max(1, this.visibleHeight - 2); this.scrollUp(pageSize); } pageDown() { const pageSize = Math.max(1, this.visibleHeight - 2); this.scrollDown(pageSize); } scrollToTop() { this.scrollPosition = this.getMaxScrollPosition(); } scrollToBottom() { this.scrollPosition = 0; } getScrollPosition() { return this.scrollPosition; } getVisibleStartIndex() { const maxStartIdx = Math.max(0, this.totalLines - this.visibleHeight); const startIdx = maxStartIdx - this.scrollPosition; return Math.max(0, Math.min(startIdx, maxStartIdx)); } getVisibleRange() { const start = this.getVisibleStartIndex(); const end = Math.min(start + this.visibleHeight, this.totalLines); return { start, end }; } calculateScrollbar() { const hasScrollbar = this.totalLines > this.visibleHeight; if (!hasScrollbar) { return { height: this.visibleHeight, thumbHeight: 0, thumbPosition: 0, hasScrollbar: false }; } const thumbHeight = Math.max(1, Math.floor((this.visibleHeight / this.totalLines) * this.visibleHeight)); const startIdx = this.getVisibleStartIndex(); const scrollPercentage = startIdx / Math.max(1, this.totalLines - this.visibleHeight); const thumbPosition = Math.floor(scrollPercentage * (this.visibleHeight - thumbHeight)); return { height: this.visibleHeight, thumbHeight, thumbPosition, hasScrollbar: true }; } renderScrollbarCharacter(row) { const config = this.calculateScrollbar(); if (!config.hasScrollbar) { return ''; } const startIdx = this.getVisibleStartIndex(); if (row === 0 && startIdx > 0) { return chalk.yellow('▲'); } else if (row === this.visibleHeight - 1 && startIdx + this.visibleHeight < this.totalLines) { return chalk.yellow('▼'); } if (row >= config.thumbPosition && row < config.thumbPosition + config.thumbHeight) { return chalk.cyan('█'); } return chalk.dim('│'); } canScroll(direction) { if (this.totalLines <= this.visibleHeight) { return false; } if (direction === 'up') { return this.scrollPosition < this.getMaxScrollPosition(); } else { return this.scrollPosition > 0; } } getScrollPercentage() { if (this.totalLines <= this.visibleHeight) { return 100; } const startIdx = this.getVisibleStartIndex(); const maxStartIdx = Math.max(0, this.totalLines - this.visibleHeight); if (maxStartIdx === 0) { return 100; } return Math.round((startIdx / maxStartIdx) * 100); } getScrollStatus() { if (this.totalLines <= this.visibleHeight) { return 'All'; } const percentage = this.getScrollPercentage(); if (percentage === 0) { return 'Top'; } else if (percentage === 100) { return 'Bottom'; } else { return `${percentage}%`; } } validateScrollPosition() { const maxScroll = this.getMaxScrollPosition(); this.scrollPosition = Math.max(0, Math.min(this.scrollPosition, maxScroll)); } getMaxScrollPosition() { return Math.max(0, this.totalLines - this.visibleHeight); } handleResize(newVisibleHeight) { const oldHeight = this.visibleHeight; this.visibleHeight = newVisibleHeight; if (oldHeight > 0 && newVisibleHeight > 0) { const ratio = newVisibleHeight / oldHeight; this.scrollPosition = Math.floor(this.scrollPosition * ratio); } this.validateScrollPosition(); } scrollToLine(lineIndex) { if (lineIndex < 0 || lineIndex >= this.totalLines) { return; } const { start, end } = this.getVisibleRange(); if (lineIndex >= start && lineIndex < end) { return; } const targetStartIdx = Math.max(0, lineIndex - Math.floor(this.visibleHeight / 2)); const maxStartIdx = Math.max(0, this.totalLines - this.visibleHeight); const newStartIdx = Math.min(targetStartIdx, maxStartIdx); this.scrollPosition = maxStartIdx - newStartIdx; } shouldAutoscroll() { return this.scrollPosition === 0; } } export const scrollManager = new ScrollManager(); //# sourceMappingURL=scroll-manager.js.map