2 const stringWidth = require('string-width');
3 const chalk = require('chalk');
4 const widestLine = require('widest-line');
5 const cliBoxes = require('cli-boxes');
6 const camelCase = require('camelcase');
7 const ansiAlign = require('ansi-align');
8 const termSize = require('term-size');
10 const getObject = detail => {
13 if (typeof detail === 'number') {
32 const getBorderChars = borderStyle => {
44 if (typeof borderStyle === 'string') {
45 chars = cliBoxes[borderStyle];
48 throw new TypeError(`Invalid border style: ${borderStyle}`);
51 sides.forEach(key => {
52 if (!borderStyle[key] || typeof borderStyle[key] !== 'string') {
53 throw new TypeError(`Invalid border style: ${key}`);
63 const getBackgroundColorName = x => camelCase('bg', x);
65 module.exports = (text, opts) => {
66 opts = Object.assign({
68 borderStyle: 'single',
74 if (opts.backgroundColor) {
75 opts.backgroundColor = getBackgroundColorName(opts.backgroundColor);
78 if (opts.borderColor && !chalk[opts.borderColor]) {
79 throw new Error(`${opts.borderColor} is not a valid borderColor`);
82 if (opts.backgroundColor && !chalk[opts.backgroundColor]) {
83 throw new Error(`${opts.backgroundColor} is not a valid backgroundColor`);
86 const chars = getBorderChars(opts.borderStyle);
87 const padding = getObject(opts.padding);
88 const margin = getObject(opts.margin);
90 const colorizeBorder = x => {
91 const ret = opts.borderColor ? chalk[opts.borderColor](x) : x;
92 return opts.dimBorder ? chalk.dim(ret) : ret;
95 const colorizeContent = x => opts.backgroundColor ? chalk[opts.backgroundColor](x) : x;
97 text = ansiAlign(text, {align: opts.align});
102 let lines = text.split(NL);
104 if (padding.top > 0) {
105 lines = Array(padding.top).fill('').concat(lines);
108 if (padding.bottom > 0) {
109 lines = lines.concat(Array(padding.bottom).fill(''));
112 const contentWidth = widestLine(text) + padding.left + padding.right;
113 const paddingLeft = PAD.repeat(padding.left);
114 const columns = termSize().columns;
115 let marginLeft = PAD.repeat(margin.left);
117 if (opts.float === 'center') {
118 const padWidth = Math.max((columns - contentWidth) / 2, 0);
119 marginLeft = PAD.repeat(padWidth);
120 } else if (opts.float === 'right') {
121 const padWidth = Math.max(columns - contentWidth - margin.right - 2, 0);
122 marginLeft = PAD.repeat(padWidth);
125 const horizontal = chars.horizontal.repeat(contentWidth);
126 const top = colorizeBorder(NL.repeat(margin.top) + marginLeft + chars.topLeft + horizontal + chars.topRight);
127 const bottom = colorizeBorder(marginLeft + chars.bottomLeft + horizontal + chars.bottomRight + NL.repeat(margin.bottom));
128 const side = colorizeBorder(chars.vertical);
130 const middle = lines.map(line => {
131 const paddingRight = PAD.repeat(contentWidth - stringWidth(line) - padding.left);
132 return marginLeft + side + colorizeContent(paddingLeft + line + paddingRight) + side;
135 return top + NL + middle + NL + bottom;
138 module.exports._borderStyles = cliBoxes;