(message = '', title = '', opts?: BoxOptions)
| 121 | * ``` |
| 122 | */ |
| 123 | export const box = (message = '', title = '', opts?: BoxOptions) => { |
| 124 | const output: Writable = opts?.output ?? process.stdout; |
| 125 | const columns = getColumns(output); |
| 126 | const borderWidth = 1; |
| 127 | const borderTotalWidth = borderWidth * 2; |
| 128 | const titlePadding = opts?.titlePadding ?? 1; |
| 129 | const contentPadding = opts?.contentPadding ?? 2; |
| 130 | const width = opts?.width === undefined || opts.width === 'auto' ? 1 : Math.min(1, opts.width); |
| 131 | const hasGuide = opts?.withGuide ?? settings.withGuide; |
| 132 | const linePrefix = !hasGuide ? '' : `${S_BAR} `; |
| 133 | const formatBorder = opts?.formatBorder ?? defaultFormatBorder; |
| 134 | const symbols = (opts?.rounded ? roundedSymbols : squareSymbols).map(formatBorder); |
| 135 | const hSymbol = formatBorder(S_BAR_H); |
| 136 | const vSymbol = formatBorder(S_BAR); |
| 137 | const linePrefixWidth = stringWidth(linePrefix); |
| 138 | const titleWidth = stringWidth(title); |
| 139 | const maxBoxWidth = columns - linePrefixWidth; |
| 140 | let boxWidth = Math.floor(columns * width) - linePrefixWidth; |
| 141 | if (opts?.width === 'auto') { |
| 142 | const lines = message.split('\n'); |
| 143 | let longestLine = titleWidth + titlePadding * 2; |
| 144 | for (const line of lines) { |
| 145 | const lineWithPadding = stringWidth(line) + contentPadding * 2; |
| 146 | if (lineWithPadding > longestLine) { |
| 147 | longestLine = lineWithPadding; |
| 148 | } |
| 149 | } |
| 150 | const longestLineWidth = longestLine + borderTotalWidth; |
| 151 | if (longestLineWidth < boxWidth) { |
| 152 | boxWidth = longestLineWidth; |
| 153 | } |
| 154 | } |
| 155 | if (boxWidth % 2 !== 0) { |
| 156 | if (boxWidth < maxBoxWidth) { |
| 157 | boxWidth++; |
| 158 | } else { |
| 159 | boxWidth--; |
| 160 | } |
| 161 | } |
| 162 | const innerWidth = boxWidth - borderTotalWidth; |
| 163 | const maxTitleLength = innerWidth - titlePadding * 2; |
| 164 | const truncatedTitle = |
| 165 | titleWidth > maxTitleLength ? `${title.slice(0, maxTitleLength - 3)}...` : title; |
| 166 | const [titlePaddingLeft, titlePaddingRight] = getPaddingForLine( |
| 167 | stringWidth(truncatedTitle), |
| 168 | innerWidth, |
| 169 | titlePadding, |
| 170 | opts?.titleAlign |
| 171 | ); |
| 172 | const wrappedMessage = wrapAnsi(message, innerWidth - contentPadding * 2, { |
| 173 | hard: true, |
| 174 | trim: false, |
| 175 | }); |
| 176 | output.write( |
| 177 | `${linePrefix}${symbols[0]}${hSymbol.repeat(titlePaddingLeft)}${truncatedTitle}${hSymbol.repeat(titlePaddingRight)}${symbols[1]}\n` |
| 178 | ); |
| 179 | const wrappedLines = wrappedMessage.split('\n'); |
| 180 | for (const line of wrappedLines) { |
nothing calls this directly
no test coverage detected