@kya-os/cli
Version:
CLI for KYA-OS MCP-I setup and management
222 lines • 7 kB
JavaScript
/**
* 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