diff --git a/.changeset/floppy-laws-tan.md b/.changeset/floppy-laws-tan.md new file mode 100644 index 00000000..36141724 --- /dev/null +++ b/.changeset/floppy-laws-tan.md @@ -0,0 +1,5 @@ +--- +"@clack/prompts": patch +--- + +fix note component overflow bug diff --git a/packages/prompts/src/note.ts b/packages/prompts/src/note.ts index 0d6ff83a..13e8229c 100644 --- a/packages/prompts/src/note.ts +++ b/packages/prompts/src/note.ts @@ -10,6 +10,8 @@ import { S_CORNER_TOP_RIGHT, S_STEP_SUBMIT, } from './common.js'; +import { wrapAnsi } from "fast-wrap-ansi"; +import process from "node:process"; export interface NoteOptions extends CommonOptions { format?: (line: string) => string; @@ -17,11 +19,20 @@ export interface NoteOptions extends CommonOptions { const defaultNoteFormatter = (line: string): string => color.dim(line); +const wrapWithFormat = (message: string, width: number, format: NoteOptions["format"]): string => { + const wrapMsg = wrapAnsi(message, width).split("\n"); + const maxWidthNormal = wrapMsg.reduce((sum, ln) => Math.max(strip(ln).length, sum), 0); + const maxWidthFormat = wrapMsg.map(format).reduce((sum, ln) => Math.max(strip(ln).length, sum), 0); + const wrapWidth = width - (maxWidthFormat - maxWidthNormal); + return wrapAnsi(message, wrapWidth); +} + export const note = (message = '', title = '', opts?: NoteOptions) => { + const output: Writable = opts?.output ?? process.stdout; const format = opts?.format ?? defaultNoteFormatter; - const lines = ['', ...message.split('\n').map(format), '']; + const wrapMsg = wrapWithFormat(message, output.columns - 6, format); + const lines = ['', ...wrapMsg.split('\n').map(format), '']; const titleLen = strip(title).length; - const output: Writable = opts?.output ?? process.stdout; const len = Math.max( lines.reduce((sum, ln) => { diff --git a/packages/prompts/test/__snapshots__/note.test.ts.snap b/packages/prompts/test/__snapshots__/note.test.ts.snap index 93ffe8dd..7135875d 100644 --- a/packages/prompts/test/__snapshots__/note.test.ts.snap +++ b/packages/prompts/test/__snapshots__/note.test.ts.snap @@ -1,5 +1,79 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`note (isCI = false) > don't overflow 1`] = ` +[ + "│ +◇ title ──────────────────────────────────────────────────────────────╮ +│ │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ │ +├──────────────────────────────────────────────────────────────────────╯ +", +] +`; + +exports[`note (isCI = false) > don't overflow with formatter 1`] = ` +[ + "│ +◇ title ────────────────────────────────────────────────────────────────╮ +│ │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ │ +├────────────────────────────────────────────────────────────────────────╯ +", +] +`; + exports[`note (isCI = false) > formatter which adds colors works 1`] = ` [ "│ @@ -53,6 +127,80 @@ exports[`note (isCI = false) > renders message with title 1`] = ` ] `; +exports[`note (isCI = true) > don't overflow 1`] = ` +[ + "│ +◇ title ──────────────────────────────────────────────────────────────╮ +│ │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string test string │ +│ test string test string test string test string test string test │ +│ string test string test string test string test string │ +│ │ +├──────────────────────────────────────────────────────────────────────╯ +", +] +`; + +exports[`note (isCI = true) > don't overflow with formatter 1`] = ` +[ + "│ +◇ title ────────────────────────────────────────────────────────────────╮ +│ │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ * test string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string test string test string test string test * │ +│ * string test string * │ +│ │ +├────────────────────────────────────────────────────────────────────────╯ +", +] +`; + exports[`note (isCI = true) > formatter which adds colors works 1`] = ` [ "│ diff --git a/packages/prompts/test/note.test.ts b/packages/prompts/test/note.test.ts index 91b91ca5..acb5f4bb 100644 --- a/packages/prompts/test/note.test.ts +++ b/packages/prompts/test/note.test.ts @@ -63,4 +63,25 @@ describe.each(['true', 'false'])('note (isCI = %s)', (isCI) => { expect(output.buffer).toMatchSnapshot(); }); + + test('don\'t overflow', () => { + const input = `${'test string '.repeat(32)}\n`.repeat(4).trim(); + prompts.note(input, 'title', { + input, + output: Object.assign(output, { columns: 75 }), + }); + + expect(output.buffer).toMatchSnapshot(); + }); + + test('don\'t overflow with formatter', () => { + const input = `${'test string '.repeat(32)}\n`.repeat(4).trim(); + prompts.note(input, 'title', { + format: (line) => colors.red(`* ${colors.cyan(line)} *`), + input, + output: Object.assign(output, { columns: 75 }), + }); + + expect(output.buffer).toMatchSnapshot(); + }); });