diff --git a/index.js b/index.js index 5ea10e4..a8e0536 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ import wrapAnsi from 'wrap-ansi'; const NEWLINE = '\n'; const PAD = ' '; -const BORDERS_WIDTH = 2; +const NONE = 'none'; const terminalColumns = () => { const {env, stdout, stderr} = process; @@ -42,6 +42,8 @@ const getObject = detail => typeof detail === 'number' ? { ...detail, }; +const getBorderWidth = borderStyle => borderStyle === NONE ? 0 : 2; + const getBorderChars = borderStyle => { const sides = [ 'topLeft', @@ -57,7 +59,7 @@ const getBorderChars = borderStyle => { let characters; // Create empty border style - if (borderStyle === 'none') { + if (borderStyle === NONE) { borderStyle = {}; for (const side of sides) { borderStyle[side] = ''; @@ -95,12 +97,12 @@ const getBorderChars = borderStyle => { return characters; }; -const makeTitle = (text, horizontal, alignement) => { +const makeTitle = (text, horizontal, alignment) => { let title = ''; const textWidth = stringWidth(text); - switch (alignement) { + switch (alignment) { case 'left': { title = text + horizontal.slice(textWidth); break; @@ -231,21 +233,36 @@ const boxContent = (content, contentWidth, options) => { let marginLeft = PAD.repeat(options.margin.left); if (options.float === 'center') { - const marginWidth = Math.max((columns - contentWidth - BORDERS_WIDTH) / 2, 0); + const marginWidth = Math.max((columns - contentWidth - getBorderWidth(options.borderStyle)) / 2, 0); marginLeft = PAD.repeat(marginWidth); } else if (options.float === 'right') { - const marginWidth = Math.max(columns - contentWidth - options.margin.right - BORDERS_WIDTH, 0); + const marginWidth = Math.max(columns - contentWidth - options.margin.right - getBorderWidth(options.borderStyle), 0); marginLeft = PAD.repeat(marginWidth); } - const top = colorizeBorder(NEWLINE.repeat(options.margin.top) + marginLeft + chars.topLeft + (options.title ? makeTitle(options.title, chars.top.repeat(contentWidth), options.titleAlignment) : chars.top.repeat(contentWidth)) + chars.topRight); - const bottom = colorizeBorder(marginLeft + chars.bottomLeft + chars.bottom.repeat(contentWidth) + chars.bottomRight + NEWLINE.repeat(options.margin.bottom)); + let result = ''; + + if (options.margin.top) { + result += NEWLINE.repeat(options.margin.top); + } + + if (options.borderStyle !== NONE || options.title) { + result += colorizeBorder(marginLeft + chars.topLeft + (options.title ? makeTitle(options.title, chars.top.repeat(contentWidth), options.titleAlignment) : chars.top.repeat(contentWidth)) + chars.topRight) + NEWLINE; + } const lines = content.split(NEWLINE); - const middle = lines.map(line => marginLeft + colorizeBorder(chars.left) + colorizeContent(line) + colorizeBorder(chars.right)).join(NEWLINE); + result += lines.map(line => marginLeft + colorizeBorder(chars.left) + colorizeContent(line) + colorizeBorder(chars.right)).join(NEWLINE); - return top + NEWLINE + middle + NEWLINE + bottom; + if (options.borderStyle !== NONE) { + result += NEWLINE + colorizeBorder(marginLeft + chars.bottomLeft + chars.bottom.repeat(contentWidth) + chars.bottomRight); + } + + if (options.margin.bottom) { + result += NEWLINE.repeat(options.margin.bottom); + } + + return result; }; const sanitizeOptions = options => { @@ -268,37 +285,40 @@ const sanitizeOptions = options => { // If width is provided, make sure it's not below 1 if (options.width) { - options.width = Math.max(1, options.width - BORDERS_WIDTH); + options.width = Math.max(1, options.width - getBorderWidth(options.borderStyle)); } // If height is provided, make sure it's not below 1 if (options.height) { - options.height = Math.max(1, options.height - BORDERS_WIDTH); + options.height = Math.max(1, options.height - getBorderWidth(options.borderStyle)); } return options; }; +const formatTitle = (title, borderStyle) => borderStyle === NONE ? title : ` ${title} `; + const determineDimensions = (text, options) => { options = sanitizeOptions(options); const widthOverride = options.width !== undefined; const columns = terminalColumns(); - const maxWidth = columns - options.margin.left - options.margin.right - BORDERS_WIDTH; + const borderWidth = getBorderWidth(options.borderStyle); + const maxWidth = columns - options.margin.left - options.margin.right - borderWidth; - const widest = widestLine(wrapAnsi(text, columns - BORDERS_WIDTH, {hard: true, trim: false})) + options.padding.left + options.padding.right; + const widest = widestLine(wrapAnsi(text, columns - borderWidth, {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} `; + options.title = formatTitle(options.title, options.borderStyle); } } 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} `; + options.title = formatTitle(options.title, options.borderStyle); // If the title is larger than content, box adheres to title width if (stringWidth(options.title) > widest) { options.width = stringWidth(options.title); @@ -312,7 +332,7 @@ const determineDimensions = (text, options) => { 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; + const spaceForMargins = columns - options.width - borderWidth; // Let's assume we have space = 4 const multiplier = spaceForMargins / (options.margin.left + options.margin.right); // Here: multiplier = 4/8 = 0.5 @@ -323,7 +343,7 @@ const determineDimensions = (text, options) => { } // Re-cap width considering the margins after shrinking - options.width = Math.min(options.width, columns - BORDERS_WIDTH - options.margin.left - options.margin.right); + options.width = Math.min(options.width, columns - borderWidth - options.margin.left - options.margin.right); } // Prevent padding overflow diff --git a/readme.md b/readme.md index 20d264f..aee00fe 100644 --- a/readme.md +++ b/readme.md @@ -119,9 +119,7 @@ Values: ``` - `'none'` ``` - foo - ``` Style of the box border. diff --git a/tests/height-option.js b/tests/height-option.js index 0da3a79..822ec64 100644 --- a/tests/height-option.js +++ b/tests/height-option.js @@ -49,3 +49,12 @@ test('height option with width + padding + margin', t => { t.snapshot(box); }); + +test('height option with border style (none)', t => { + const box = boxen('foo', { + height: 3, + borderStyle: 'none', + }); + + t.snapshot(box); +}); diff --git a/tests/margin-option.js b/tests/margin-option.js index e85191a..96e54a6 100644 --- a/tests/margin-option.js +++ b/tests/margin-option.js @@ -54,3 +54,17 @@ test('margin proportionally decreases when content <= columns', t => { t.snapshot(box); }); + +test('margin option with border style (none)', t => { + const box = boxen('foo', { + margin: { + top: 1, + bottom: 1, + left: 1, + right: 1, + }, + borderStyle: 'none', + }); + + t.snapshot(box); +}); diff --git a/tests/padding-option.js b/tests/padding-option.js index 0550c70..dfe8c29 100644 --- a/tests/padding-option.js +++ b/tests/padding-option.js @@ -21,3 +21,17 @@ test('padding option advanced', t => { t.snapshot(box); }); + +test('padding option with border style (none)', t => { + const box = boxen('foo', { + padding: { + top: 1, + bottom: 1, + left: 1, + right: 1, + }, + borderStyle: 'none', + }); + + t.snapshot(box); +}); diff --git a/tests/snapshots/tests/border-option.js.md b/tests/snapshots/tests/border-option.js.md index 33203d8..4c8e306 100644 --- a/tests/snapshots/tests/border-option.js.md +++ b/tests/snapshots/tests/border-option.js.md @@ -104,9 +104,7 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `␊ - foo␊ - ` + 'foo' ## border style (custom ascii style) diff --git a/tests/snapshots/tests/border-option.js.snap b/tests/snapshots/tests/border-option.js.snap index 20c6afe..ef68c02 100644 Binary files a/tests/snapshots/tests/border-option.js.snap and b/tests/snapshots/tests/border-option.js.snap differ diff --git a/tests/snapshots/tests/height-option.js.md b/tests/snapshots/tests/height-option.js.md index 7215674..2b4330c 100644 --- a/tests/snapshots/tests/height-option.js.md +++ b/tests/snapshots/tests/height-option.js.md @@ -72,3 +72,11 @@ Generated by [AVA](https://avajs.dev). └──────────────────┘␊ ␊ ` + +## height option with border style (none) + +> Snapshot 1 + + `foo␊ + ␊ + ` diff --git a/tests/snapshots/tests/height-option.js.snap b/tests/snapshots/tests/height-option.js.snap index 7944916..9d423fb 100644 Binary files a/tests/snapshots/tests/height-option.js.snap and b/tests/snapshots/tests/height-option.js.snap differ diff --git a/tests/snapshots/tests/margin-option.js.md b/tests/snapshots/tests/margin-option.js.md index c6fbf81..b5b32af 100644 --- a/tests/snapshots/tests/margin-option.js.md +++ b/tests/snapshots/tests/margin-option.js.md @@ -73,3 +73,11 @@ Generated by [AVA](https://avajs.dev). └──────────────────────────────────────────────────────────┘␊ ␊ ` + +## margin option with border style (none) + +> Snapshot 1 + + `␊ + foo␊ + ` diff --git a/tests/snapshots/tests/margin-option.js.snap b/tests/snapshots/tests/margin-option.js.snap index c75d107..753af27 100644 Binary files a/tests/snapshots/tests/margin-option.js.snap and b/tests/snapshots/tests/margin-option.js.snap differ diff --git a/tests/snapshots/tests/padding-option.js.md b/tests/snapshots/tests/padding-option.js.md index 45cfdee..588bacb 100644 --- a/tests/snapshots/tests/padding-option.js.md +++ b/tests/snapshots/tests/padding-option.js.md @@ -25,3 +25,11 @@ Generated by [AVA](https://avajs.dev). │ │␊ │ │␊ └──────────────────┘` + +## padding option with border style (none) + +> Snapshot 1 + + ` ␊ + foo ␊ + ` diff --git a/tests/snapshots/tests/padding-option.js.snap b/tests/snapshots/tests/padding-option.js.snap index 44237f6..2a99af7 100644 Binary files a/tests/snapshots/tests/padding-option.js.snap and b/tests/snapshots/tests/padding-option.js.snap differ diff --git a/tests/snapshots/tests/title-option.js.md b/tests/snapshots/tests/title-option.js.md index f7f8f9e..26600fa 100644 --- a/tests/snapshots/tests/title-option.js.md +++ b/tests/snapshots/tests/title-option.js.md @@ -65,3 +65,10 @@ Generated by [AVA](https://avajs.dev). `┌ very long title ─┐␊ │foo │␊ └──────────────────┘` + +## title option with border style (none) + +> Snapshot 1 + + `title␊ + foo ` diff --git a/tests/snapshots/tests/title-option.js.snap b/tests/snapshots/tests/title-option.js.snap index 959c948..9a898c5 100644 Binary files a/tests/snapshots/tests/title-option.js.snap and b/tests/snapshots/tests/title-option.js.snap differ diff --git a/tests/snapshots/tests/width-option.js.md b/tests/snapshots/tests/width-option.js.md index e59df88..423875b 100644 --- a/tests/snapshots/tests/width-option.js.md +++ b/tests/snapshots/tests/width-option.js.md @@ -46,3 +46,9 @@ Generated by [AVA](https://avajs.dev). │ │␊ │ │␊ └────┘` + +## width option with border style (none) + +> Snapshot 1 + + 'foo' diff --git a/tests/snapshots/tests/width-option.js.snap b/tests/snapshots/tests/width-option.js.snap index 74a641f..afe434d 100644 Binary files a/tests/snapshots/tests/width-option.js.snap and b/tests/snapshots/tests/width-option.js.snap differ diff --git a/tests/title-option.js b/tests/title-option.js index 3f868e0..685649c 100644 --- a/tests/title-option.js +++ b/tests/title-option.js @@ -68,3 +68,12 @@ test('title + width option', t => { }), ); }); + +test('title option with border style (none)', t => { + const box = boxen('foo', { + title: 'title', + borderStyle: 'none', + }); + + t.snapshot(box); +}); diff --git a/tests/width-option.js b/tests/width-option.js index fbb5877..42c6e4e 100644 --- a/tests/width-option.js +++ b/tests/width-option.js @@ -37,3 +37,12 @@ test('width option with big padding', t => { t.snapshot(box); }); + +test('width option with border style (none)', t => { + const box = boxen('foo', { + width: 3, + borderStyle: 'none', + }); + + t.snapshot(box); +});