Comparing version 6.1.0 to 6.2.0
@@ -179,2 +179,19 @@ import {LiteralUnion} from 'type-fest'; | ||
readonly titleAlignment?: 'left' | 'right' | 'center'; | ||
/** | ||
Set a fixed width for the box. | ||
**Note*: This disables terminal overflow handling and may cause the box to look broken if the user's terminal is not wide enough. | ||
@example | ||
``` | ||
import boxen from 'boxen'; | ||
console.log(boxen('foo bar', {width: 15})); | ||
// ┌─────────────┐ | ||
// │foo bar │ | ||
// └─────────────┘ | ||
``` | ||
*/ | ||
readonly width?: number; | ||
} | ||
@@ -181,0 +198,0 @@ |
94
index.js
@@ -224,2 +224,62 @@ import process from 'node:process'; | ||
const determineDimensions = (text, options) => { | ||
const widthOverride = options.width !== undefined; | ||
const columns = terminalColumns(); | ||
const maxWidth = columns - options.margin.left - options.margin.right - BORDERS_WIDTH; | ||
// If width is provided, make sure it's not below 1 | ||
if (options.width) { | ||
options.width = Math.max(1, options.width - BORDERS_WIDTH); | ||
} | ||
const widest = widestLine(wrapAnsi(text, columns - BORDERS_WIDTH, {hard: true, trim: false})) + options.padding.left + options.padding.right; | ||
// If title and width are provided, title adheres to fixed width | ||
if (options.title && widthOverride) { | ||
options.title = options.title.slice(0, Math.max(0, options.width - 2)); | ||
if (options.title) { | ||
options.title = ` ${options.title} `; | ||
} | ||
} else if (options.title) { | ||
options.title = options.title.slice(0, Math.max(0, maxWidth - 2)); | ||
// Recheck if title isn't empty now | ||
if (options.title) { | ||
options.title = ` ${options.title} `; | ||
// If the title is larger than content, box adheres to title width | ||
if (stringWidth(options.title) > widest) { | ||
options.width = stringWidth(options.title); | ||
} | ||
} | ||
} | ||
// If fixed width is provided, use it or content width as reference | ||
options.width = options.width ? options.width : widest; | ||
if (!widthOverride) { | ||
if ((options.margin.left && options.margin.right) && options.width > maxWidth) { | ||
// Let's assume we have margins: left = 3, right = 5, in total = 8 | ||
const spaceForMargins = columns - options.width - BORDERS_WIDTH; | ||
// Let's assume we have space = 4 | ||
const multiplier = spaceForMargins / (options.margin.left + options.margin.right); | ||
// Here: multiplier = 4/8 = 0.5 | ||
options.margin.left = Math.max(0, Math.floor(options.margin.left * multiplier)); | ||
options.margin.right = Math.max(0, Math.floor(options.margin.right * multiplier)); | ||
// Left: 3 * 0.5 = 1.5 -> 1 | ||
// Right: 6 * 0.5 = 3 | ||
} | ||
// Re-cap width considering the margins after shrinking | ||
options.width = Math.min(options.width, columns - BORDERS_WIDTH - options.margin.left - options.margin.right); | ||
} | ||
// Prevent padding overflow | ||
if (options.width - (options.padding.left + options.padding.right) <= 0) { | ||
options.padding.left = 0; | ||
options.padding.right = 0; | ||
} | ||
return options; | ||
}; | ||
const isHex = color => color.match(/^#(?:[0-f]{3}){1,2}$/i); | ||
@@ -257,37 +317,9 @@ const isColorValid = color => typeof color === 'string' && ((chalk[color]) || isHex(color)); | ||
const columns = terminalColumns(); | ||
options = determineDimensions(text, options); | ||
let contentWidth = widestLine(wrapAnsi(text, columns - BORDERS_WIDTH, {hard: true, trim: false})) + options.padding.left + options.padding.right; | ||
text = makeContentText(text, options.padding, options.width, options.textAlignment); | ||
// This prevents the title bar to exceed the console's width | ||
options.title = options.title && options.title.slice(0, columns - 4 - options.margin.left - options.margin.right); | ||
if (options.title) { | ||
options.title = ` ${options.title} `; | ||
// Make the box larger to fit a larger title | ||
if (stringWidth(options.title) > contentWidth) { | ||
contentWidth = stringWidth(options.title); | ||
} | ||
} | ||
if ((options.margin.left && options.margin.right) && contentWidth + BORDERS_WIDTH + options.margin.left + options.margin.right > columns) { | ||
// Let's assume we have margins: left = 3, right = 5, in total = 8 | ||
const spaceForMargins = columns - contentWidth - BORDERS_WIDTH; | ||
// Let's assume we have space = 4 | ||
const multiplier = spaceForMargins / (options.margin.left + options.margin.right); | ||
// Here: multiplier = 4/8 = 0.5 | ||
options.margin.left = Math.max(0, Math.floor(options.margin.left * multiplier)); | ||
options.margin.right = Math.max(0, Math.floor(options.margin.right * multiplier)); | ||
// Left: 3 * 0.5 = 1.5 -> 1 | ||
// Right: 6 * 0.5 = 3 | ||
} | ||
// Prevent content from exceeding the console's width | ||
contentWidth = Math.min(contentWidth, columns - BORDERS_WIDTH - options.margin.left - options.margin.right); | ||
text = makeContentText(text, options.padding, contentWidth, options.textAlignment); | ||
return boxContent(text, contentWidth, options); | ||
return boxContent(text, options.width, options); | ||
} | ||
export const _borderStyles = cliBoxes; |
{ | ||
"name": "boxen", | ||
"version": "6.1.0", | ||
"version": "6.2.0", | ||
"description": "Create boxes in the terminal", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -195,2 +195,10 @@ # boxen | ||
##### width | ||
Type: `number` | ||
Set a fixed width for the box. | ||
*Note:* This disables terminal overflow handling and may cause the box to look broken if the user's terminal is not wide enough. | ||
##### padding | ||
@@ -197,0 +205,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21136
448
266