UNPKG

@kya-os/cli

Version:

CLI for KYA-OS MCP-I setup and management

222 lines 7 kB
/** * Box Drawing Component * Creates beautiful boxes for CLI output without dependencies */ import chalk from "chalk"; // Predefined box styles const BOX_STYLES = { single: { topLeft: "┌", topRight: "┐", bottomLeft: "└", bottomRight: "┘", horizontal: "─", vertical: "│", topJunction: "┬", bottomJunction: "┴", leftJunction: "├", rightJunction: "┤", cross: "┼", }, double: { topLeft: "╔", topRight: "╗", bottomLeft: "╚", bottomRight: "╝", horizontal: "═", vertical: "║", topJunction: "╦", bottomJunction: "╩", leftJunction: "╠", rightJunction: "╣", cross: "╬", }, round: { topLeft: "╭", topRight: "╮", bottomLeft: "╰", bottomRight: "╯", horizontal: "─", vertical: "│", topJunction: "┬", bottomJunction: "┴", leftJunction: "├", rightJunction: "┤", cross: "┼", }, heavy: { topLeft: "┏", topRight: "┓", bottomLeft: "┗", bottomRight: "┛", horizontal: "━", vertical: "┃", topJunction: "┳", bottomJunction: "┻", leftJunction: "┣", rightJunction: "┫", cross: "╋", }, }; /** * Wrap text to fit within a specific width */ function wrapText(text, width) { const words = text.split(" "); const lines = []; let currentLine = ""; for (const word of words) { if (currentLine.length + word.length + 1 <= width) { currentLine += (currentLine ? " " : "") + word; } else { if (currentLine) lines.push(currentLine); currentLine = word; } } if (currentLine) lines.push(currentLine); return lines.length > 0 ? lines : [""]; } /** * Pad text to center it within a given width */ function stripAnsi(text) { // Simple ANSI code removal - matches most common ANSI escape sequences return text.replace(/\x1b\[[0-9;]*m/g, ''); } /** * Pad text to center it within a given width */ function centerText(text, width) { const textLength = stripAnsi(text).length; if (textLength >= width) return text; const totalPadding = width - textLength; const leftPadding = Math.floor(totalPadding / 2); const rightPadding = totalPadding - leftPadding; return " ".repeat(leftPadding) + text + " ".repeat(rightPadding); } /** * Pad text to align it within a given width */ function alignText(text, width, align = 'left') { const textLength = stripAnsi(text).length; if (textLength >= width) return text.substring(0, width); switch (align) { case 'center': return centerText(text, width); case 'right': return " ".repeat(width - textLength) + text; default: return text + " ".repeat(width - textLength); } } /** * Create a box around content */ export function createBox(content, options = {}) { const { padding = 1, margin = 0, style = "single", width = 72, align = "left", title, titleAlign = "center", borderColor, } = options; // Get box style const boxStyle = typeof style === "string" ? BOX_STYLES[style] : style; if (!boxStyle) throw new Error(`Unknown box style: ${style}`); // Prepare content lines const lines = Array.isArray(content) ? content : content.split("\n"); const contentWidth = width - 2 - (padding * 2); // Account for borders and padding // Wrap and align lines const wrappedLines = []; for (const line of lines) { if (stripAnsi(line).length > contentWidth) { wrappedLines.push(...wrapText(line, contentWidth)); } else { wrappedLines.push(line); } } // Build the box const result = []; // Apply margin for (let i = 0; i < margin; i++) { result.push(""); } // Top border with optional title let topBorder = boxStyle.topLeft + boxStyle.horizontal.repeat(width - 2) + boxStyle.topRight; if (title) { const titleText = ` ${title} `; const titleLength = stripAnsi(titleText).length; const borderLength = width - 2; if (titleLength < borderLength - 4) { let titlePosition; switch (titleAlign) { case 'center': titlePosition = Math.floor((borderLength - titleLength) / 2); break; case 'right': titlePosition = borderLength - titleLength - 2; break; default: titlePosition = 2; } topBorder = boxStyle.topLeft + boxStyle.horizontal.repeat(titlePosition) + titleText + boxStyle.horizontal.repeat(borderLength - titlePosition - titleLength) + boxStyle.topRight; } } if (borderColor) { result.push(chalk.hex(borderColor)(topBorder)); } else { result.push(topBorder); } // Add top padding for (let i = 0; i < padding; i++) { const paddingLine = boxStyle.vertical + " ".repeat(width - 2) + boxStyle.vertical; result.push(borderColor ? chalk.hex(borderColor)(paddingLine) : paddingLine); } // Add content lines for (const line of wrappedLines) { const alignedContent = alignText(line, contentWidth, align); const paddedContent = " ".repeat(padding) + alignedContent + " ".repeat(padding); const contentLine = boxStyle.vertical + paddedContent + boxStyle.vertical; if (borderColor) { // Color only the borders, not the content result.push(chalk.hex(borderColor)(boxStyle.vertical) + paddedContent + chalk.hex(borderColor)(boxStyle.vertical)); } else { result.push(contentLine); } } // Add bottom padding for (let i = 0; i < padding; i++) { const paddingLine = boxStyle.vertical + " ".repeat(width - 2) + boxStyle.vertical; result.push(borderColor ? chalk.hex(borderColor)(paddingLine) : paddingLine); } // Bottom border const bottomBorder = boxStyle.bottomLeft + boxStyle.horizontal.repeat(width - 2) + boxStyle.bottomRight; result.push(borderColor ? chalk.hex(borderColor)(bottomBorder) : bottomBorder); // Apply margin for (let i = 0; i < margin; i++) { result.push(""); } return result.join("\n"); } /** * Create a divider line */ export function createDivider(width = 72, style = 'single') { const chars = { single: "─", double: "═", heavy: "━", }; return chars[style].repeat(width); } //# sourceMappingURL=box.js.map