[READ-ONLY] Mirror of https://github.com/bombshell-dev/clack. Effortlessly build beautiful command-line apps bomb.sh/docs/clack/basics/getting-started/
cli command-line command-line-app node prompt prompts
5

Configure Feed

Select the types of activity you want to include in your feed.

feat: add `format` option to `note` prompt (#284)

authored by

James Garbutt and committed by
GitHub
(Apr 12, 2025, 4:05 PM +0100) 99c35302 44df9af1

+162 -6
+5
.changeset/empty-buses-wonder.md
··· 1 + --- 2 + "@clack/prompts": minor 3 + --- 4 + 5 + Adds `format` option to the note prompt to allow formatting of individual lines
+106
packages/prompts/src/__snapshots__/index.test.ts.snap
··· 1265 1265 ] 1266 1266 `; 1267 1267 1268 + exports[`prompts (isCI = false) > note > formatter which adds colors works 1`] = ` 1269 + [ 1270 + "│ 1271 + ◇ title ──╮ 1272 + │ │ 1273 + │ line 0 │ 1274 + │ line 1 │ 1275 + │ line 2 │ 1276 + │ │ 1277 + ├──────────╯ 1278 + ", 1279 + ] 1280 + `; 1281 + 1282 + exports[`prompts (isCI = false) > note > formatter which adds length works 1`] = ` 1283 + [ 1284 + "│ 1285 + ◇ title ──────╮ 1286 + │ │ 1287 + │ * line 0 * │ 1288 + │ * line 1 * │ 1289 + │ * line 2 * │ 1290 + │ │ 1291 + ├──────────────╯ 1292 + ", 1293 + ] 1294 + `; 1295 + 1296 + exports[`prompts (isCI = false) > note > renders as wide as longest line 1`] = ` 1297 + [ 1298 + "│ 1299 + ◇ title ───────────────────────────╮ 1300 + │ │ 1301 + │ short │ 1302 + │ somewhat questionably long line │ 1303 + │ │ 1304 + ├───────────────────────────────────╯ 1305 + ", 1306 + ] 1307 + `; 1308 + 1309 + exports[`prompts (isCI = false) > note > renders message with title 1`] = ` 1310 + [ 1311 + "│ 1312 + ◇ title ───╮ 1313 + │ │ 1314 + │ message │ 1315 + │ │ 1316 + ├───────────╯ 1317 + ", 1318 + ] 1319 + `; 1320 + 1268 1321 exports[`prompts (isCI = false) > password > renders and clears validation errors 1`] = ` 1269 1322 [ 1270 1323 "[?25l", ··· 3124 3177 " 3125 3178 ", 3126 3179 "[?25h", 3180 + ] 3181 + `; 3182 + 3183 + exports[`prompts (isCI = true) > note > formatter which adds colors works 1`] = ` 3184 + [ 3185 + "│ 3186 + ◇ title ──╮ 3187 + │ │ 3188 + │ line 0 │ 3189 + │ line 1 │ 3190 + │ line 2 │ 3191 + │ │ 3192 + ├──────────╯ 3193 + ", 3194 + ] 3195 + `; 3196 + 3197 + exports[`prompts (isCI = true) > note > formatter which adds length works 1`] = ` 3198 + [ 3199 + "│ 3200 + ◇ title ──────╮ 3201 + │ │ 3202 + │ * line 0 * │ 3203 + │ * line 1 * │ 3204 + │ * line 2 * │ 3205 + │ │ 3206 + ├──────────────╯ 3207 + ", 3208 + ] 3209 + `; 3210 + 3211 + exports[`prompts (isCI = true) > note > renders as wide as longest line 1`] = ` 3212 + [ 3213 + "│ 3214 + ◇ title ───────────────────────────╮ 3215 + │ │ 3216 + │ short │ 3217 + │ somewhat questionably long line │ 3218 + │ │ 3219 + ├───────────────────────────────────╯ 3220 + ", 3221 + ] 3222 + `; 3223 + 3224 + exports[`prompts (isCI = true) > note > renders message with title 1`] = ` 3225 + [ 3226 + "│ 3227 + ◇ title ───╮ 3228 + │ │ 3229 + │ message │ 3230 + │ │ 3231 + ├───────────╯ 3232 + ", 3127 3233 ] 3128 3234 `; 3129 3235
+41
packages/prompts/src/index.test.ts
··· 1 1 import { Readable, Writable } from 'node:stream'; 2 + import colors from 'picocolors'; 2 3 import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; 3 4 import * as prompts from './index.js'; 4 5 ··· 1247 1248 1248 1249 expect(output.buffer).toMatchSnapshot(); 1249 1250 }); 1251 + }); 1252 + }); 1253 + 1254 + describe('note', () => { 1255 + test('renders message with title', () => { 1256 + prompts.note('message', 'title', { 1257 + input, 1258 + output, 1259 + }); 1260 + 1261 + expect(output.buffer).toMatchSnapshot(); 1262 + }); 1263 + 1264 + test('renders as wide as longest line', () => { 1265 + prompts.note('short\nsomewhat questionably long line', 'title', { 1266 + input, 1267 + output, 1268 + }); 1269 + 1270 + expect(output.buffer).toMatchSnapshot(); 1271 + }); 1272 + 1273 + test('formatter which adds length works', () => { 1274 + prompts.note('line 0\nline 1\nline 2', 'title', { 1275 + format: (line) => `* ${line} *`, 1276 + input, 1277 + output, 1278 + }); 1279 + 1280 + expect(output.buffer).toMatchSnapshot(); 1281 + }); 1282 + 1283 + test('formatter which adds colors works', () => { 1284 + prompts.note('line 0\nline 1\nline 2', 'title', { 1285 + format: (line) => colors.red(line), 1286 + input, 1287 + output, 1288 + }); 1289 + 1290 + expect(output.buffer).toMatchSnapshot(); 1250 1291 }); 1251 1292 }); 1252 1293 });
+10 -6
packages/prompts/src/index.ts
··· 642 642 }).prompt() as Promise<Value[] | symbol>; 643 643 }; 644 644 645 - export const note = (message = '', title = '', opts?: CommonOptions) => { 646 - const lines = `\n${message}\n`.split('\n'); 645 + export interface NoteOptions extends CommonOptions { 646 + format?: (line: string) => string; 647 + } 648 + 649 + const defaultNoteFormatter = (line: string): string => color.dim(line); 650 + 651 + export const note = (message = '', title = '', opts?: NoteOptions) => { 652 + const format = opts?.format ?? defaultNoteFormatter; 653 + const lines = ['', ...message.split('\n').map(format), '']; 647 654 const titleLen = strip(title).length; 648 655 const output: Writable = opts?.output ?? process.stdout; 649 656 const len = ··· 656 663 ) + 2; 657 664 const msg = lines 658 665 .map( 659 - (ln) => 660 - `${color.gray(S_BAR)} ${color.dim(ln)}${' '.repeat(len - strip(ln).length)}${color.gray( 661 - S_BAR 662 - )}` 666 + (ln) => `${color.gray(S_BAR)} ${ln}${' '.repeat(len - strip(ln).length)}${color.gray(S_BAR)}` 663 667 ) 664 668 .join('\n'); 665 669 output.write(