pax_global_header00006660000000000000000000000064135724031160014514gustar00rootroot0000000000000052 comment=c5776208a5aebd4883e9b06683710a3a19fb979f boxen-4.2.0/000077500000000000000000000000001357240311600126325ustar00rootroot00000000000000boxen-4.2.0/.editorconfig000066400000000000000000000002571357240311600153130ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 boxen-4.2.0/.gitattributes000066400000000000000000000000231357240311600155200ustar00rootroot00000000000000* text=auto eol=lf boxen-4.2.0/.github/000077500000000000000000000000001357240311600141725ustar00rootroot00000000000000boxen-4.2.0/.github/funding.yml000066400000000000000000000001571357240311600163520ustar00rootroot00000000000000github: sindresorhus open_collective: sindresorhus tidelift: npm/boxen custom: https://sindresorhus.com/donate boxen-4.2.0/.github/security.md000066400000000000000000000002631357240311600163640ustar00rootroot00000000000000# Security Policy To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. boxen-4.2.0/.gitignore000066400000000000000000000000431357240311600146170ustar00rootroot00000000000000node_modules yarn.lock .nyc_output boxen-4.2.0/.npmrc000066400000000000000000000000231357240311600137450ustar00rootroot00000000000000package-lock=false boxen-4.2.0/.travis.yml000066400000000000000000000000651357240311600147440ustar00rootroot00000000000000language: node_js node_js: - '12' - '10' - '8' boxen-4.2.0/example.js000066400000000000000000000016331357240311600146260ustar00rootroot00000000000000'use strict'; const chalk = require('chalk'); const boxen = require('.'); console.log('\n\n' + boxen(chalk.blue.bold('unicorn'), { padding: 1, margin: 1, borderColor: 'yellow' }) + '\n'); console.log('\n\n' + boxen(chalk.blue.bold('unicorn'), { padding: 1, margin: 1, borderColor: 'yellow', borderStyle: 'double' }) + '\n'); console.log('\n\n' + boxen(chalk.blue.bold('unicorn'), { padding: 1, margin: 1, borderColor: '#eebbaa', borderStyle: 'double' }) + '\n'); console.log('\n\n' + boxen(chalk.blue.bold('unicorn'), { padding: 1, margin: 1, borderColor: '#ffc0cb', backgroundColor: '#00ffff', borderStyle: 'double' }) + '\n'); console.log('\n\n' + boxen(chalk.blue.bold('unicorn'), { padding: 1, margin: 1, borderColor: 'yellow', backgroundColor: 'magenta', borderStyle: { topLeft: '+', topRight: '+', bottomLeft: '+', bottomRight: '+', horizontal: '-', vertical: '|' } }) + '\n'); boxen-4.2.0/index.d.ts000066400000000000000000000057751357240311600145510ustar00rootroot00000000000000import {LiteralUnion} from 'type-fest'; import cliBoxes, {BoxStyle} from 'cli-boxes'; declare namespace boxen { /** Characters used for custom border. @example ``` // affffb // e e // dffffc const border: CustomBorderStyle = { topLeft: 'a', topRight: 'b', bottomRight: 'c', bottomLeft: 'd', vertical: 'e', horizontal: 'f' }; ``` */ interface CustomBorderStyle extends BoxStyle {} /** Spacing used for `padding` and `margin`. */ interface Spacing { readonly top: number; readonly right: number; readonly bottom: number; readonly left: number; } interface Options { /** Color of the box border. */ readonly borderColor?: LiteralUnion< | 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | 'grey' | 'blackBright' | 'redBright' | 'greenBright' | 'yellowBright' | 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright', string >; /** Style of the box border. @default BorderStyle.Single */ readonly borderStyle?: BorderStyle | CustomBorderStyle; /** Reduce opacity of the border. @default false */ readonly dimBorder?: boolean; /** Space between the text and box border. @default 0 */ readonly padding?: number | Spacing; /** Space around the box. @default 0 */ readonly margin?: number | Spacing; /** Float the box on the available terminal screen space. @default 'left' */ readonly float?: 'left' | 'right' | 'center'; /** Color of the background. */ readonly backgroundColor?: LiteralUnion< | 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'blackBright' | 'redBright' | 'greenBright' | 'yellowBright' | 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright', string >; /** Align the text in the box based on the widest line. @default 'left' */ readonly align?: 'left' | 'right' | 'center'; } } declare const enum BorderStyle { Single = 'single', Double = 'double', Round = 'round', Bold = 'bold', SingleDouble = 'singleDouble', DoubleSingle = 'doubleSingle', Classic = 'classic' } declare const boxen: { /** Creates a box in the terminal. @param text - The text inside the box. @returns The box. @example ``` import boxen = require('boxen'); console.log(boxen('unicorn', {padding: 1})); // ┌─────────────┐ // │ │ // │ unicorn │ // │ │ // └─────────────┘ console.log(boxen('unicorn', {padding: 1, margin: 1, borderStyle: 'double'})); // // ╔═════════════╗ // ║ ║ // ║ unicorn ║ // ║ ║ // ╚═════════════╝ // ``` */ (text: string, options?: boxen.Options): string; /** Border styles from [`cli-boxes`](https://github.com/sindresorhus/cli-boxes). */ BorderStyle: typeof BorderStyle; }; export = boxen; boxen-4.2.0/index.js000066400000000000000000000074041357240311600143040ustar00rootroot00000000000000'use strict'; const stringWidth = require('string-width'); const chalk = require('chalk'); const widestLine = require('widest-line'); const cliBoxes = require('cli-boxes'); const camelCase = require('camelcase'); const ansiAlign = require('ansi-align'); const termSize = require('term-size'); const getObject = detail => { let object; if (typeof detail === 'number') { object = { top: detail, right: detail * 3, bottom: detail, left: detail * 3 }; } else { object = { top: 0, right: 0, bottom: 0, left: 0, ...detail }; } return object; }; const getBorderChars = borderStyle => { const sides = [ 'topLeft', 'topRight', 'bottomRight', 'bottomLeft', 'vertical', 'horizontal' ]; let chararacters; if (typeof borderStyle === 'string') { chararacters = cliBoxes[borderStyle]; if (!chararacters) { throw new TypeError(`Invalid border style: ${borderStyle}`); } } else { for (const side of sides) { if (!borderStyle[side] || typeof borderStyle[side] !== 'string') { throw new TypeError(`Invalid border style: ${side}`); } } chararacters = borderStyle; } return chararacters; }; const isHex = color => color.match(/^#[0-f]{3}(?:[0-f]{3})?$/i); const isColorValid = color => typeof color === 'string' && ((chalk[color]) || isHex(color)); const getColorFn = color => isHex(color) ? chalk.hex(color) : chalk[color]; const getBGColorFn = color => isHex(color) ? chalk.bgHex(color) : chalk[camelCase(['bg', color])]; module.exports = (text, options) => { options = { padding: 0, borderStyle: 'single', dimBorder: false, align: 'left', float: 'left', ...options }; if (options.borderColor && !isColorValid(options.borderColor)) { throw new Error(`${options.borderColor} is not a valid borderColor`); } if (options.backgroundColor && !isColorValid(options.backgroundColor)) { throw new Error(`${options.backgroundColor} is not a valid backgroundColor`); } const chars = getBorderChars(options.borderStyle); const padding = getObject(options.padding); const margin = getObject(options.margin); const colorizeBorder = border => { const newBorder = options.borderColor ? getColorFn(options.borderColor)(border) : border; return options.dimBorder ? chalk.dim(newBorder) : newBorder; }; const colorizeContent = content => options.backgroundColor ? getBGColorFn(options.backgroundColor)(content) : content; text = ansiAlign(text, {align: options.align}); const NL = '\n'; const PAD = ' '; let lines = text.split(NL); if (padding.top > 0) { lines = new Array(padding.top).fill('').concat(lines); } if (padding.bottom > 0) { lines = lines.concat(new Array(padding.bottom).fill('')); } const contentWidth = widestLine(text) + padding.left + padding.right; const paddingLeft = PAD.repeat(padding.left); const {columns} = termSize(); let marginLeft = PAD.repeat(margin.left); if (options.float === 'center') { const padWidth = Math.max((columns - contentWidth) / 2, 0); marginLeft = PAD.repeat(padWidth); } else if (options.float === 'right') { const padWidth = Math.max(columns - contentWidth - margin.right - 2, 0); marginLeft = PAD.repeat(padWidth); } const horizontal = chars.horizontal.repeat(contentWidth); const top = colorizeBorder(NL.repeat(margin.top) + marginLeft + chars.topLeft + horizontal + chars.topRight); const bottom = colorizeBorder(marginLeft + chars.bottomLeft + horizontal + chars.bottomRight + NL.repeat(margin.bottom)); const side = colorizeBorder(chars.vertical); const middle = lines.map(line => { const paddingRight = PAD.repeat(contentWidth - stringWidth(line) - padding.left); return marginLeft + side + colorizeContent(paddingLeft + line + paddingRight) + side; }).join(NL); return top + NL + middle + NL + bottom; }; module.exports._borderStyles = cliBoxes; boxen-4.2.0/index.test-d.ts000066400000000000000000000022201357240311600155040ustar00rootroot00000000000000import {expectType} from 'tsd'; import boxen = require('.'); import {Spacing, BorderStyle, CustomBorderStyle} from '.'; const border: CustomBorderStyle = { topLeft: ' ', topRight: ' ', bottomLeft: ' ', bottomRight: ' ', horizontal: ' ', vertical: ' ' }; const spacing: Spacing = { top: 1, right: 0, bottom: 1, left: 0 }; expectType(boxen('unicorns')); expectType(boxen('unicorns', {borderColor: 'green'})); expectType(boxen('unicorns', {borderColor: '#ff0000'})); expectType(boxen('unicorns', {borderStyle: BorderStyle.Double})); expectType(boxen('unicorns', {borderStyle: border})); expectType(boxen('unicorns', {dimBorder: true})); expectType(boxen('unicorns', {padding: 3})); expectType(boxen('unicorns', {padding: spacing})); expectType(boxen('unicorns', {margin: 3})); expectType(boxen('unicorns', {margin: spacing})); expectType(boxen('unicorns', {float: 'center'})); expectType(boxen('unicorns', {backgroundColor: 'green'})); expectType(boxen('unicorns', {backgroundColor: '#ff0000'})); expectType(boxen('unicorns', {align: 'right'})); boxen-4.2.0/license000066400000000000000000000021251357240311600141770ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. boxen-4.2.0/package.json000066400000000000000000000016021357240311600151170ustar00rootroot00000000000000{ "name": "boxen", "version": "4.2.0", "description": "Create boxes in the terminal", "license": "MIT", "repository": "sindresorhus/boxen", "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "engines": { "node": ">=8" }, "scripts": { "test": "xo && nyc ava && tsd" }, "files": [ "index.js", "index.d.ts" ], "keywords": [ "cli", "box", "boxes", "terminal", "term", "console", "ascii", "unicode", "border", "text" ], "dependencies": { "ansi-align": "^3.0.0", "camelcase": "^5.3.1", "chalk": "^3.0.0", "cli-boxes": "^2.2.0", "string-width": "^4.1.0", "term-size": "^2.1.0", "type-fest": "^0.8.1", "widest-line": "^3.1.0" }, "devDependencies": { "ava": "^2.1.0", "nyc": "^14.1.1", "tsd": "^0.11.0", "xo": "^0.25.3" } } boxen-4.2.0/readme.md000066400000000000000000000072351357240311600144200ustar00rootroot00000000000000# boxen [![Build Status](https://travis-ci.org/sindresorhus/boxen.svg?branch=master)](https://travis-ci.org/sindresorhus/boxen) > Create boxes in the terminal ![](screenshot.png) ## Install ``` $ npm install boxen ``` ## Usage ```js const boxen = require('boxen'); console.log(boxen('unicorn', {padding: 1})); /* ┌─────────────┐ │ │ │ unicorn │ │ │ └─────────────┘ */ console.log(boxen('unicorn', {padding: 1, margin: 1, borderStyle: 'double'})); /* ╔═════════════╗ ║ ║ ║ unicorn ║ ║ ║ ╚═════════════╝ */ ``` ## API ### boxen(text, options?) #### text Type: `string` Text inside the box. #### options Type: `object` ##### borderColor Type: `string`\ Values: `'black'` `'red'` `'green'` `'yellow'` `'blue'` `'magenta'` `'cyan'` `'white'` `'gray'` or a hex value like `'#ff0000'` Color of the box border. ##### borderStyle Type: `string | object`\ Default: `'single'`\ Values: - `'single'` ``` ┌───┐ │foo│ └───┘ ``` - `'double'` ``` ╔═══╗ ║foo║ ╚═══╝ ``` - `'round'` (`'single'` sides with round corners) ``` ╭───╮ │foo│ ╰───╯ ``` - `'bold'` ``` ┏━━━┓ ┃foo┃ ┗━━━┛ ``` - `'singleDouble'` (`'single'` on top and bottom, `'double'` on right and left) ``` ╓───╖ ║foo║ ╙───╜ ``` - `'doubleSingle'` (`'double'` on top and bottom, `'single'` on right and left) ``` ╒═══╕ │foo│ ╘═══╛ ``` - `'classic'` ``` +---+ |foo| +---+ ``` Style of the box border. Can be any of the above predefined styles or an object with the following keys: ```js { topLeft: '+', topRight: '+', bottomLeft: '+', bottomRight: '+', horizontal: '-', vertical: '|' } ``` ##### dimBorder Type: `boolean`\ Default: `false` Reduce opacity of the border. ##### padding Type: `number | object`\ Default: `0` Space between the text and box border. Accepts a number or an object with any of the `top`, `right`, `bottom`, `left` properties. When a number is specified, the left/right padding is 3 times the top/bottom to make it look nice. ##### margin Type: `number | object`\ Default: `0` Space around the box. Accepts a number or an object with any of the `top`, `right`, `bottom`, `left` properties. When a number is specified, the left/right margin is 3 times the top/bottom to make it look nice. ##### float Type: `string`\ Default: `'left'`\ Values: `'right'` `'center'` `'left'` Float the box on the available terminal screen space. ##### backgroundColor Type: `string`\ Values: `'black'` `'red'` `'green'` `'yellow'` `'blue'` `'magenta'` `'cyan'` `'white'` `'gray'` or a hex value like `'#ff0000'` Color of the background. ##### align Type: `string`\ Default: `'left'`\ Values: `'left'` `'center'` `'right'` Align the text in the box based on the widest line. ## Related - [boxen-cli](https://github.com/sindresorhus/boxen-cli) - CLI for this module - [cli-boxes](https://github.com/sindresorhus/cli-boxes) - Boxes for use in the terminal - [ink-box](https://github.com/sindresorhus/ink-box) - Box component for Ink that uses this package ---
Get professional support for this package with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.
boxen-4.2.0/screenshot.png000066400000000000000000000507341357240311600155260ustar00rootroot00000000000000PNG  IHDR w-QIDATxA0qM -²gY)8vX`4vG8 (8 (8 (8 (8 (8 (8 ((8 ((8 ((8 8 (8 8 ((8 ((8 ((8 8 (8 8 (8 8 (8 (8 (8 (8 (8 (8 ((8 (qgޱ߷F5⤶vQmAmwL2N;|r? 4 F@h4 F(hF(Q4 @Q4 F@h4 F(hF(Q4 @Q4 F@h4 F(hQ(A~/͝WQ6s̙o̙y^~^AaNNNߖ Txfb231hH}Ww-kwժl6Lw9[og ۿqާx$0:0M޻!4 yy;{>6sAM=+W75:0068864LNNe7_!'/Y f*5+3._Yaɦkhf/Yr-/!75}s-߷zuH[^^;}Bgk˓W^64 [Bouo ٶ9=o(8rF v=x?~_~BqaehxΜ=,;9H8l㼍#7NQHm?2wVqƑn($PnK/Ho_zi($N;g3_| yq@,nh,3闉)mGsSq@m]+گ;i#036c*Gف#cRP[~jjx|x ^@"w׏@~|ȍ QHxGy(\y~v<<=5(a1uhXos1uhN)\f/F S7f/F n7CBb(ݹP; QHbݎphPHLM($q^˟ԽlF j|2 n44 Fa=ﯧVNٛFjQx;b(@େn)ha jU(QٛF`^.1{Fὕ1uc&Qٛ FC(@C6F`^.Q Ihfo=TlBPF!f'0*i~>2 n$4 whsOZ4lfhw `ƵXu~ ; ڧYDQCIb:"FOqoWh4 65 13 k+1à 3K1 jb~hF(;twpqYa , 1뮻6u}VSh+Db$θn_뾙g0dē;;H$ nwtvkuuwUVTTS@XXȸqcBB}@Vko}u?vf#0yP,H-UvZmJu 9e&G'IUHe5jm.J\79ID$ k6wXW_k&GC*B!C%8l5ƶZc{auڱ (UW_")-MEb/i(Z<=%uFR4YYyG-ڠA+W^D57pLGp8_ !DQ)3RSg rhuGCRR%Թ0#H$rUIÕaf[uҐ|zD>3$`[Kq!#SBFTEq.rlz ~EkM>'tܰQZ(%"1 o>ovhrt Gv8l|oGL84Pn+5fe:9$'pDcΤ~9Ddm[|Bk/Kvl>(HMlܴ> ^we9NBh}ƍ[,sm뷁ttu^%!Wk#W 'kbxAa9?FJI,0s߉ ?sщCҜWۓsYךּ)#HyK򤟘n;^BJC3$/4:fx&D}<ڜ-$@Nqw\5ɜXB>c]ˤ"ɱ/+[ 8㹙':l!vʌuur]) ZpI*NN^4ZOyRJ߼^X|UWY@ǧ zoo@^l{$WJE꬙ Czz&y&_ޚ'Y@PWqӏ?sT/`zP3[1:zR>F2b*4=e CS MoڜD$"!It)0tV ! iw')t>wS|;'FTq2L"#@F7+cƌ$A-YpG=rXacc3y#1q* j钅/F*<5RXB^į&)xDkFWq^j82rڛo$tAM ];89N 2 G̛Rܹ\Iz=(%&w _!S=NEߝx dVO&͟c)8N1 @F ܝ ^o(**ۿ?gmnI[ Wl63))3{X<#,EtV@[qEKp"duLj١I8/uy4k+8l0.~ۛuGB Q# fMUfљV5~,vOPKgEʂnOlV=ܬ2'9ADÒCFH8 |955?,(8A nZ]Ãܑ[hC#qS&!-+Hܳ#TgJlgnݖkȕ\}ةz`_?j+gJ~룫c/4~SB͸0u_>'1/l,[;̝8Yɯw*~/IîLl 'Oݼ#|u_WD||Jď֌ZQ]6/](֭ϟ M  nh*/IŒ~n]`}TKUOI2}#6)%WDLM !0pb11ƻ]\o>p;yt:ɕEisIR)7o^ Җ& #e9hZY$(Y3ɕꚒ #<<[J ς+cƌLLJGXK6mz bAD7 oC'm>G@5& 1Qo+ZD KO9:q|OʓwL+.,S Y~QCF | k>J`yHa 8 /̞(箻RbGwv+Ǻ_w9A.B=tF"hH 0DB V446S:=CU~»ON8|"G;en=e@*/G ?`$/ [)XF`-ݠyK [`6b2}3‰E[f+SL }#SV`02|.1k뿨GT$Y1={Po7u{[#Σʷי: WLvv@FO;v:09H^ssɓ2z\I[4z*0?)i*RXX\_Hҥ'!WvLٺu'¿ |^O=euZɕPHLC@ қN܌$K8kl6OD"rEɢ/GCmmCv\#GƑ}J||L\pyR8#W3s3O";pN.5LJRt4yBDEbDFxD#r &C (bxt@cuGEO # Qp!F=yF'ءV+a=l]d26/HO'\0)q*'wMHFaZP,1lk٩!?ՕVPp\;c\} cȐȄEEe䉅 gb=L4=D^;˟?&WZZA9( WyJSG>@&TPo&T/l[`uh:N?2 ;L"Bg֑@Μ9K 11b1r=gSzQHct_0M&NK W]_tQeZAN]ԏ)AÉتīKDbrt1@*-sq PS]MƳƶPrE!{}7 s]nz v#>B &F#ra"-2rcȕLf\Tda>L/DINbQ7X LVa'pre4g˺Lrkzc<0&zY|؅>_E ͭ$Vg2AyFAa'/BB|f&Zz814H8^(YtV=vYpw\"Ĩ&=5NݱisBDŽ WJb0M$(ԃ{{aQ\궴ȕH$b}QX,&ar@-UiOAɈAM}2؜N|<1+t]qiM˾OY3vX@Fǩe2 Qk8u\Y0?U"S7C}nwUH jMFD!@"gWЭ$o=m& # -%mɏ؀hd֬A> *z*=}/1}2z#S/xFh> 2r߼u[Uy6E+BޟxښoW9(F '!A9n;|49i:cWFEdd²g55u=es D>j~>ʾ%8/BݺU~;tMti|΀ ô؇ 7uYA!r|܃JLNgCF>)FKlR#/6gtY )Hx7PJHP ]mU;g|s|#SZo>&y*.8d@B A) bsLiis?cplr^(pR)y|i'(9Hgke[:ng8{{ZN5Cj72 GA!x;*a /rɕԙnɓƅ cf$/LfJ R)G¬$u 2 Qvҏw{_X%2[NnX.,d@($HT*E%Ie9!m\rpڵh1;N$&Hbb0;>j$0 Z)D$RIdĠc9Xٛ?Xgs\;4E)х0tH '2r0IQ =yС. c\rE",?\)(8NàA 0 a~_}+H8`N,A2&ꩢ+Mx).F2 J AA$aâA&n߽8501cd:ٕkg!.>@rN$FO(7øh M.bPKR $F54Vn8yvXĖ:. d͜Ç@b؇*- !g+͛JX`6[23kǎC\0hl1A$A>hg`=;>LU67іXU8 $NCg7azp,7$7:3 pY ]@(@II91$%M#$%NswIKL:!44 9eJtߏYZ\ Yv{YYcB@Fܷ19s6zT|xxF`db}6kV"1:HUUM)#8m.7R2\ܛmH yİl"ԚډAjR)rߑQnq؈ከDZbPHG%f6Ufb0-t |D.d ye=N'18a1se2?l߱KCDGGm*z괦b%rڸ!b\XVï putRr]hՆbm=1\Dޑ$n[7pE -]X(;aı +V,L [Ν6JSS˱c$ټ~VbxѻJATrE,J^[9Nhj|ښ̓L"}>JBX;!p(yᲨQ`K7&CYK2 7Zp7ROIob8s"TKKѣ'ɕEsH1c s>a:֯b2Y~N528m1*_*^1K2m-")A17 EKxL{.scCX \.S+-fi hCb+\I=J [^reȸCO8  S}nbXd5W_BB ˭nepk%:+CjNb[_xe>b{d2 A&^w]C]6CfibH uTg\ΪL65!1b==aPԽq@[2 u-)qykĠmE sob%Wa z./^g߶3=0(,{in!(HMڑ"mZ#ID oN>JL 4w >)j[Qbs!hywY1z,b{|ԊY!C *r1l($oK~7BBuˢfBd|㧶l D k.xuD"V>ˎN:>;;\YɓǓ+{wttt=̫v.d8zT735O}o^T*h`by؜9TB638~SCI!#t~{ {xcD"ѓW6HYy.Dzl-I$DQOtVm#H] nmO zXB 1 g/tYİ|٢%.`?資mʋ/K^ʫo߾?OIB(g~85uƻ|FlF=} #G"6mN9X'Ng}k=q''֮}C_S&Npl>R)ixش!” 3pG"ɬKO^2xH$"擕ff:Iİ4bAPEC _1JymC'I KxlKYClcK||P%~;DieJv4Z=sBu<U;N;]X(D"G#/ Jɥjuo/qEEfGp2}~xwMbk"POuXwRo7@2#8>NNBIs|.7S<cb?9ɉ%$ FOjs~ KD}>_=|}(H~]HMk3jm\"n3ۭop;b? uI_0s8Ͽ[2gdRlݻP3?ƍCǹ (@f*vPo8lNw|~f'1-(0dӷgRqbO>o>Q` &kOj zoYGB<((8JpPFnwo g=Zf^PmhfWK5^*LaiF@9e(?ZtzHCCӣ>k~:_N箝 ~{Simm.- ۛ]j#WS#Nik{wcaAj5k4. /l0aSgl;סrd| [o7^8㯮C$dг{ZNݘѵGl=M1.}s]].g!Yͅŧ:{찑p:7^oMu6y9~Z?O>hƪ7gb]ͅ|ƛB叟aM4fL=CDN&_%H&O239y!Ǒ+&*+pVV ǎ=sƔ3 WB566WUTV8SPp\(yAqӃc+(}uX0EXJH~MRSEb8b]}dW"D K:f"T*έTװ?1$:E3.pHrPrP\-DgJt 5u?{w6P4 pb19A: q38(5:IvI۶^UuoBxﶻxwҵ]^y^yx hO)My|< * ܎tNVt5cSԔ.n&v^og0ff<_ݟi8.KV|+p Qp@hF(Q(@Q4 @h4 F(hF(Q(@Q4 @h4 F(hF(Q(Q4 @ٻ(( çWx&03e&l@M*]F(Q(@Q4 @h4 F(hF(Q(@Q4 @h4 F(hF(Q(@Q4 [>-@h4 F(hF(Q(@Q4 @h4 F(hF(Q(@Q4 F@9c Q4 _8(X< Qcl[3(~(#QX QdZw1褦Z4 [C@/c[9-FMݚ(ǚhe|5h|m6j]Ft<&..mԭٻY@Ff24 FQopR4 wF^wVhNn=(O(\ڨ[wsw`r2]__\^]ڨ[w=ppH:HMݚQ|w4 omn=FuO[5{Q8 ݼcG$5jҊU9.>Bطqc^3Q("Lfq' { t.is(actual.trim(), expected.trim()); }; test('creates a box', t => { compare(t, boxen('foo'), ` ┌───┐ │foo│ └───┘ `); }); test('padding option', t => { compare(t, boxen('foo', {padding: 2}), ` ┌───────────────┐ │ │ │ │ │ foo │ │ │ │ │ └───────────────┘ `); }); test('padding option - advanced', t => { compare(t, boxen('foo', { padding: { top: 0, bottom: 2, left: 5, right: 10 } }), ` ┌──────────────────┐ │ foo │ │ │ │ │ └──────────────────┘ `); }); test('margin option', t => { compare(t, boxen('foo', { padding: 2, margin: 2 }), ` ┌───────────────┐ │ │ │ │ │ foo │ │ │ │ │ └───────────────┘ `); }); test('float option (left)', t => { compare(t, boxen('foo', { float: 'left' }), ` ┌───┐ │foo│ └───┘ `); }); test('float option (center)', t => { const padSize = Math.ceil((process.stdout.columns - 2) / 2) - 1; const padding = ' '.repeat(padSize); compare(t, boxen('foo', { float: 'center' }), ` ${padding}┌───┐ ${padding}│foo│ ${padding}└───┘ ${padding} `); }); test('float option (center) does not throw when content > columns', t => { const longContent = 'ab'.repeat(process.stdout.columns); t.notThrows(() => { boxen(longContent, { float: 'center' }); }); }); test('float option (center) ignored when content > columns', t => { const longContent = 'ab'.repeat(process.stdout.columns); const gotWithCenter = boxen(longContent, { float: 'center' }); const gotWithLeft = boxen(longContent, { float: 'left' }); const gotWithRight = boxen(longContent, { float: 'right' }); compare(t, gotWithCenter, gotWithLeft); compare(t, gotWithCenter, gotWithRight); }); test('float option (right)', t => { const padSize = Math.max(process.stdout.columns - 4, 0) - 1; const padding = ' '.repeat(padSize); compare(t, boxen('foo', { float: 'right' }), ` ${padding}┌───┐ ${padding}│foo│ ${padding}└───┘ ${padding} `); }); test('float option (right) with margin', t => { const marginWidth = 6; const padSize = Math.max(process.stdout.columns - 4 - marginWidth, 0) - 1; const padding = ' '.repeat(padSize); compare(t, boxen('foo', { float: 'right', margin: 2 }), ` ${padding}┌───┐ ${padding}│foo│ ${padding}└───┘ `); }); test('float option (right) with margin right', t => { const marginWidth = 2; const padSize = Math.max(process.stdout.columns - 4 - marginWidth, 0) - 1; const padding = ' '.repeat(padSize); compare(t, boxen('foo', { float: 'right', margin: { right: 2 } }), ` ${padding}┌───┐ ${padding}│foo│ ${padding}└───┘ `); }); test('borderStyle option `double`', t => { compare(t, boxen('foo', {borderStyle: 'double'}), ` ╔═══╗ ║foo║ ╚═══╝ `); }); test('borderStyle option `round`', t => { compare(t, boxen('foo', {borderStyle: 'round'}), ` ╭───╮ │foo│ ╰───╯ `); }); test('borderStyle option `singleDouble`', t => { compare(t, boxen('foo', {borderStyle: 'singleDouble'}), ` ╓───╖ ║foo║ ╙───╜ `); }); test('borderStyle option `doubleSingle`', t => { compare(t, boxen('foo', {borderStyle: 'doubleSingle'}), ` ╒═══╕ │foo│ ╘═══╛ `); }); test('borderStyle option with object', t => { const asciiStyle = { topLeft: '1', topRight: '2', bottomLeft: '3', bottomRight: '4', horizontal: '-', vertical: '|' }; compare(t, boxen('foo', {borderStyle: asciiStyle}), ` 1---2 |foo| 3---4 `); }); test('throws on unexpected borderStyle as string', t => { t.throws(() => { boxen('foo', {borderStyle: 'shakenSnake'}); }, /border style/); }); test('throws on unexpected borderStyle as object', t => { t.throws(() => { boxen('foo', {borderStyle: {shake: 'snake'}}); }, /border style/); // Missing bottomRight const invalid = { topLeft: '1', topRight: '2', bottomLeft: '3', horizontal: '-', vertical: '|' }; t.throws(() => { boxen('foo', {borderStyle: invalid}); }, /bottomRight/); }); test('borderColor option', t => { const box = boxen('foo', {borderColor: 'yellow'}); const yellowAnsiOpen = '\u001B[33m'; const colorAnsiClose = '\u001B[39m'; t.true(box.includes(yellowAnsiOpen)); t.true(box.includes(colorAnsiClose)); }); test('borderColor hex', t => { const box = boxen('foo', {borderColor: '#FF0000'}); const rgbAnsiOpen = '\u001B[38;2;255;0;0m'; const colorAnsiClose = '\u001B[39m'; t.true(box.includes(rgbAnsiOpen)); t.true(box.includes(colorAnsiClose)); }); test('throws on unexpected borderColor', t => { t.throws(() => { boxen('foo', {borderColor: 'greasy-white'}); }, /borderColor/); }); test('backgroundColor option', t => { const box = boxen('foo', {backgroundColor: 'red'}); const redAnsiOpen = '\u001B[41m'; const redAnsiClose = '\u001B[49m'; t.true(box.includes(redAnsiOpen)); t.true(box.includes(redAnsiClose)); }); test('backgroundColor hex', t => { const box = boxen('foo', {backgroundColor: '#FF0000'}); const rgbAnsiOpen = '\u001B[48;2;255;0;0m'; const colorAnsiClose = '\u001B[49m'; t.true(box.includes(rgbAnsiOpen)); t.true(box.includes(colorAnsiClose)); }); test('throws on unexpected backgroundColor', t => { t.throws(() => { boxen('foo', {backgroundColor: 'dark-yellow'}); }, /backgroundColor/); }); test('align option `center`', t => { const beautifulColor = chalk.magenta('B E A U T I F U L'); compare(t, boxen(`Boxes are\n${beautifulColor}\nand beneficial too!`, { align: 'center', padding: 1 }), ` ┌─────────────────────────┐ │ │ │ Boxes are │ │ ${beautifulColor} │ │ and beneficial too! │ │ │ └─────────────────────────┘ `); }); test('align option `right`', t => { const beautifulColor = chalk.magenta('B E A U T I F U L'); compare(t, boxen(`Boxes are\n${beautifulColor}\nand beneficial too!`, {align: 'right'}), ` ┌───────────────────┐ │ Boxes are│ │ ${beautifulColor}│ │and beneficial too!│ └───────────────────┘ `); }); test('align option `left`', t => { const beautifulColor = chalk.magenta('B E A U T I F U L'); compare(t, boxen(`Boxes are\n${beautifulColor}\nand beneficial too!`, {align: 'left'}), ` ┌───────────────────┐ │Boxes are │ │${beautifulColor} │ │and beneficial too!│ └───────────────────┘ `); }); test('dimBorder option', t => { const dimTopBorder = chalk.dim('┌───┐'); const dimSide = chalk.dim('│'); const dimBottomBorder = chalk.dim('└───┘'); compare(t, boxen('foo', {dimBorder: true}), ` ${dimTopBorder} ${dimSide}foo${dimSide} ${dimBottomBorder} `); });