Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

boxen

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

boxen - npm Package Compare versions

Comparing version 5.0.1 to 5.1.0

42

index.d.ts

@@ -124,4 +124,46 @@ import {LiteralUnion} from 'type-fest';

@default 'left'
@deprecated Use `textAlignment` instead.
*/
readonly align?: 'left' | 'right' | 'center';
/**
Align the text in the box based on the widest line.
@default 'left'
*/
readonly textAlignment?: 'left' | 'right' | 'center';
/**
Display a title at the top of the box.
If needed, the box will horizontally expand to fit the title.
@example
```
console.log(boxen('foo bar', {title: 'example'}));
// ┌ example ┐
// │foo bar │
// └─────────┘
```
*/
readonly title?: string;
/**
Align the title in the top bar.
@default 'left'
@example
```
console.log(boxen('foo bar foo bar', {title: 'example', textAlignmentTitle: 'center'}));
// ┌─── example ───┐
// │foo bar foo bar│
// └───────────────┘
console.log(boxen('foo bar foo bar', {title: 'example', textAlignmentTitle: 'right'}));
// ┌────── example ┐
// │foo bar foo bar│
// └───────────────┘
```
*/
readonly titleAlignment?: 'left' | 'right' | 'center';
}

@@ -128,0 +170,0 @@ }

190

index.js

@@ -10,2 +10,5 @@ 'use strict';

const NL = '\n';
const PAD = ' ';
const terminalColumns = () => {

@@ -75,2 +78,104 @@ const {env, stdout, stderr} = process;

const makeTitle = (text, horizontal, alignement) => {
let title = '';
const textWidth = stringWidth(text);
switch (alignement) {
case 'left':
title = text + horizontal.slice(textWidth);
break;
case 'right':
title = horizontal.slice(textWidth) + text;
break;
default:
horizontal = horizontal.slice(textWidth);
if (horizontal.length % 2 === 1) { // This is needed in case the length is odd
horizontal = horizontal.slice(Math.floor(horizontal.length / 2));
title = horizontal.slice(1) + text + horizontal; // We reduce the left part of one character to avoid the bar to go beyond its limit
} else {
horizontal = horizontal.slice(horizontal.length / 2);
title = horizontal + text + horizontal;
}
break;
}
return title;
};
const makeContentText = (text, padding, columns, align) => {
text = ansiAlign(text, {align});
let lines = text.split(NL);
const textWidth = widestLine(text);
const max = columns - padding.left - padding.right;
if (textWidth > max) {
const newLines = [];
for (const line of lines) {
const createdLines = wrapAnsi(line, max, {hard: true});
const alignedLines = ansiAlign(createdLines, {align});
const alignedLinesArray = alignedLines.split('\n');
const longestLength = Math.max(...alignedLinesArray.map(s => stringWidth(s)));
for (const alignedLine of alignedLinesArray) {
let paddedLine;
switch (align) {
case 'center':
paddedLine = PAD.repeat((max - longestLength) / 2) + alignedLine;
break;
case 'right':
paddedLine = PAD.repeat(max - longestLength) + alignedLine;
break;
default:
paddedLine = alignedLine;
break;
}
newLines.push(paddedLine);
}
}
lines = newLines;
}
if (align === 'center' && textWidth < max) {
lines = lines.map(line => PAD.repeat((max - textWidth) / 2) + line);
} else if (align === 'right' && textWidth < max) {
lines = lines.map(line => PAD.repeat(max - textWidth) + line);
}
const paddingLeft = PAD.repeat(padding.left);
const paddingRight = PAD.repeat(padding.right);
lines = lines.map(line => paddingLeft + line + paddingRight);
lines = lines.map(line => {
if (columns - stringWidth(line) > 0) {
switch (align) {
case 'center':
return line + PAD.repeat(columns - stringWidth(line));
case 'right':
return line + PAD.repeat(columns - stringWidth(line));
default:
return line + PAD.repeat(columns - stringWidth(line));
}
}
return line;
});
if (padding.top > 0) {
lines = new Array(padding.top).fill(PAD.repeat(columns)).concat(lines);
}
if (padding.bottom > 0) {
lines = lines.concat(new Array(padding.bottom).fill(PAD.repeat(columns)));
}
return lines.join(NL);
};
const isHex = color => color.match(/^#(?:[0-f]{3}){1,2}$/i);

@@ -86,7 +191,15 @@ const isColorValid = color => typeof color === 'string' && ((chalk[color]) || isHex(color));

dimBorder: false,
align: 'left',
textAlignment: 'left',
float: 'left',
titleAlignment: 'left',
...options
};
// This option is deprecated
if (options.align) {
options.textAlignment = options.align;
}
const BORDERS_WIDTH = 2;
if (options.borderColor && !isColorValid(options.borderColor)) {

@@ -111,45 +224,19 @@ throw new Error(`${options.borderColor} is not a valid borderColor`);

const NL = '\n';
const PAD = ' ';
const columns = terminalColumns();
text = ansiAlign(text, {align: options.align});
let contentWidth = widestLine(wrapAnsi(text, columns - BORDERS_WIDTH, {hard: true})) + padding.left + padding.right;
let lines = text.split(NL);
// This prevents the title bar to exceed the console's width
let title = options.title && options.title.slice(0, columns - 4 - margin.left - margin.right);
let contentWidth = widestLine(text) + padding.left + padding.right;
if (title) {
title = ` ${title} `;
}
const BORDERS_WIDTH = 2;
if (contentWidth + BORDERS_WIDTH > columns) {
contentWidth = columns - BORDERS_WIDTH;
const max = contentWidth - padding.left - padding.right;
const newLines = [];
for (const line of lines) {
const createdLines = wrapAnsi(line, max, {hard: true});
const alignedLines = ansiAlign(createdLines, {align: options.align});
const alignedLinesArray = alignedLines.split('\n');
const longestLength = Math.max(...alignedLinesArray.map(s => stringWidth(s)));
for (const alignedLine of alignedLinesArray) {
let paddedLine;
switch (options.align) {
case 'center':
paddedLine = PAD.repeat((max - longestLength) / 2) + alignedLine;
break;
case 'right':
paddedLine = PAD.repeat(max - longestLength) + alignedLine;
break;
default:
paddedLine = alignedLine;
break;
}
newLines.push(paddedLine);
}
}
lines = newLines;
// Make the box larger to fit a larger title
if (stringWidth(title) > contentWidth) {
contentWidth = stringWidth(title);
}
if (contentWidth + BORDERS_WIDTH + margin.left + margin.right > columns) {
if ((margin.left && margin.right) && contentWidth + BORDERS_WIDTH + margin.left + margin.right > columns) {
// Let's assume we have margins: left = 3, right = 5, in total = 8

@@ -160,4 +247,4 @@ const spaceForMargins = columns - contentWidth - BORDERS_WIDTH;

// Here: multiplier = 4/8 = 0.5
margin.left = Math.floor(margin.left * multiplier);
margin.right = Math.floor(margin.right * multiplier);
margin.left = Math.max(0, Math.floor(margin.left * multiplier));
margin.right = Math.max(0, Math.floor(margin.right * multiplier));
// Left: 3 * 0.5 = 1.5 -> 1

@@ -167,23 +254,19 @@ // Right: 6 * 0.5 = 3

if (padding.top > 0) {
lines = new Array(padding.top).fill('').concat(lines);
}
// Prevent content from exceeding the console's width
contentWidth = Math.min(contentWidth, columns - BORDERS_WIDTH - margin.left - margin.right);
if (padding.bottom > 0) {
lines = lines.concat(new Array(padding.bottom).fill(''));
}
text = makeContentText(text, padding, contentWidth, options.textAlignment);
const paddingLeft = PAD.repeat(padding.left);
let marginLeft = PAD.repeat(margin.left);
if (options.float === 'center') {
const padWidth = Math.max((columns - contentWidth - BORDERS_WIDTH) / 2, 0);
marginLeft = PAD.repeat(padWidth);
const marginWidth = Math.max((columns - contentWidth - BORDERS_WIDTH) / 2, 0);
marginLeft = PAD.repeat(marginWidth);
} else if (options.float === 'right') {
const padWidth = Math.max(columns - contentWidth - margin.right - BORDERS_WIDTH, 0);
marginLeft = PAD.repeat(padWidth);
const marginWidth = Math.max(columns - contentWidth - margin.right - BORDERS_WIDTH, 0);
marginLeft = PAD.repeat(marginWidth);
}
const horizontal = chars.horizontal.repeat(contentWidth);
const top = colorizeBorder(NL.repeat(margin.top) + marginLeft + chars.topLeft + horizontal + chars.topRight);
const top = colorizeBorder(NL.repeat(margin.top) + marginLeft + chars.topLeft + (title ? makeTitle(title, horizontal, options.titleAlignment) : horizontal) + chars.topRight);
const bottom = colorizeBorder(marginLeft + chars.bottomLeft + horizontal + chars.bottomRight + NL.repeat(margin.bottom));

@@ -194,5 +277,6 @@ const side = colorizeBorder(chars.vertical);

const lines = text.split(NL);
const middle = lines.map(line => {
const paddingRight = PAD.repeat(contentWidth - stringWidth(line) - padding.left);
return marginLeft + side + colorizeContent(paddingLeft + line + paddingRight) + side;
return marginLeft + side + colorizeContent(line) + side;
}).join(LINE_SEPARATOR);

@@ -199,0 +283,0 @@

{
"name": "boxen",
"version": "5.0.1",
"version": "5.1.0",
"description": "Create boxes in the terminal",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -37,2 +37,9 @@ # boxen

*/
console.log(boxen('unicorns love rainbows', {title: 'magical', titleAlignment: 'center'}));
/*
┌────── magical ───────┐
│unicorns love rainbows│
└──────────────────────┘
*/
```

@@ -131,2 +138,52 @@

##### title
Type: `string`
Display a title at the top of the box.
If needed, the box will horizontally expand to fit the title.
Example:
```js
console.log(boxen('foo bar', {title: 'example'}));
/*
┌ example ┐
│foo bar │
└─────────┘
*/
```
##### titleAlignment
Type: `string`\
Default: `'left'`
Align the title in the top bar.
Values:
- `'left'`
```js
/*
┌ example ──────┐
│foo bar foo bar│
└───────────────┘
*/
```
- `'center'`
```js
/*
┌─── example ───┐
│foo bar foo bar│
└───────────────┘
*/
```
- `'right'`
```js
/*
┌────── example ┐
│foo bar foo bar│
└───────────────┘
*/
```
##### padding

@@ -165,3 +222,3 @@

##### align
##### textAlignment

@@ -168,0 +225,0 @@ Type: `string`\

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc