diff --git a/.changeset/multiselect-overflow-fix.md b/.changeset/multiselect-overflow-fix.md new file mode 100644 index 00000000..141e46da --- /dev/null +++ b/.changeset/multiselect-overflow-fix.md @@ -0,0 +1,5 @@ +--- +'@clack/prompts': patch +--- + +fix: correctly calculate multiselect layout row padding on narrow terminals to prevent option text overflow and visual overwriting diff --git a/packages/prompts/src/multi-select.ts b/packages/prompts/src/multi-select.ts index e5db7069..3f16a04c 100644 --- a/packages/prompts/src/multi-select.ts +++ b/packages/prompts/src/multi-select.ts @@ -170,8 +170,9 @@ export const multiselect = (opts: MultiSelectOptions) => { ) .join('\n'); // Calculate rowPadding: title lines + footer lines (error message + trailing newline) - const titleLineCount = title.split('\n').length; - const footerLineCount = footer.split('\n').length + 1; // footer + trailing newline + const titleLineCount = title.split('\n').length - 1; + const wrappedFooter = wrapTextWithPrefix(opts.output, footer, ''); + const footerLineCount = wrappedFooter.split('\n').length + 1; // footer + trailing newline return `${title}${prefix}${limitOptions({ output: opts.output, options: this.options, @@ -184,14 +185,15 @@ export const multiselect = (opts: MultiSelectOptions) => { } default: { const prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : ''; - const titleLineCount = title.split('\n').length; + const titleLineCount = title.split('\n').length - 1; const footerLines = showInstructions ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, hasGuide) : hasGuide ? [styleText('cyan', S_BAR_END)] : []; const footerText = footerLines.join('\n'); - const footerLineCount = footerLines.length + 1; + const wrappedFooter = wrapTextWithPrefix(opts.output, footerText, ''); + const footerLineCount = wrappedFooter.split('\n').length + 1; return `${title}${prefix}${limitOptions({ output: opts.output, options: this.options, diff --git a/packages/prompts/test/__snapshots__/multi-select.test.ts.snap b/packages/prompts/test/__snapshots__/multi-select.test.ts.snap index ae07ee85..01955fde 100644 --- a/packages/prompts/test/__snapshots__/multi-select.test.ts.snap +++ b/packages/prompts/test/__snapshots__/multi-select.test.ts.snap @@ -1,14 +1,47 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`multiselect (isCI = false) > calculates rowPadding properly on narrow terminals with wrapped footers 1`] = ` +[ + "", + "| +* Select an option +| [•] Option 0 +| [ ] Option 1 +| [ ] Option 2 +| [ ] Option 3 +| [ ] Option 4 +| [ ] Option 5 +| [ ] Option 6 +| [ ] Option 7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— +", + "", + "", + "", + "| [+] Option 0", + "", + "", + "", + "", + "o Select an option +| Option 0", + " +", + "", +] +`; + exports[`multiselect (isCI = false) > can be aborted by a signal 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", " ", @@ -19,18 +52,18 @@ exports[`multiselect (isCI = false) > can be aborted by a signal 1`] = ` exports[`multiselect (isCI = false) > can cancel 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "■ foo -│", + "x foo +|", " ", "", @@ -40,23 +73,23 @@ exports[`multiselect (isCI = false) > can cancel 1`] = ` exports[`multiselect (isCI = false) > can render option hints 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 (Hint 0) -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 (Hint 0) +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0 (Hint 0)", + "| [+] opt0 (Hint 0)", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -66,23 +99,23 @@ exports[`multiselect (isCI = false) > can render option hints 1`] = ` exports[`multiselect (isCI = false) > can set cursorAt to preselect an option 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [ ] opt0 +| [•] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -92,23 +125,23 @@ exports[`multiselect (isCI = false) > can set cursorAt to preselect an option 1` exports[`multiselect (isCI = false) > can set custom labels 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 -│ ◻ Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 +| [ ] Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0", + "| [+] Option 0", "", "", "", "", - "◇ foo -│ Option 0", + "o foo +| Option 0", " ", "", @@ -118,18 +151,18 @@ exports[`multiselect (isCI = false) > can set custom labels 1`] = ` exports[`multiselect (isCI = false) > can set initial values 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◼ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [+] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -139,18 +172,18 @@ exports[`multiselect (isCI = false) > can set initial values 1`] = ` exports[`multiselect (isCI = false) > can submit without selection when required = false 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ none", + "o foo +| none", " ", "", @@ -160,19 +193,19 @@ exports[`multiselect (isCI = false) > can submit without selection when required exports[`multiselect (isCI = false) > global withGuide: false removes guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", "", - "◼ opt0", + "[+] opt0", "", "", "", - "◇ foo + "o foo opt0", " ", @@ -183,94 +216,94 @@ exports[`multiselect (isCI = false) > global withGuide: false removes guide 1`] exports[`multiselect (isCI = false) > maxItems accounts for instruction footer 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt6", + "| [+] opt6", "", "", "", "", - "◇ foo -│ opt6", + "o foo +| opt6", " ", "", @@ -280,94 +313,94 @@ exports[`multiselect (isCI = false) > maxItems accounts for instruction footer 1 exports[`multiselect (isCI = false) > maxItems renders a sliding window 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt6", + "| [+] opt6", "", "", "", "", - "◇ foo -│ opt6", + "o foo +| opt6", " ", "", @@ -377,24 +410,24 @@ exports[`multiselect (isCI = false) > maxItems renders a sliding window 1`] = ` exports[`multiselect (isCI = false) > renders disabled options 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 (Hint 2) -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [ ] opt0 +| [•] opt1 +| [ ] opt2 (Hint 2) +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -404,14 +437,14 @@ exports[`multiselect (isCI = false) > renders disabled options 1`] = ` exports[`multiselect (isCI = false) > renders instructions without guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", - "◇ foo + "o foo none", " ", @@ -422,23 +455,23 @@ exports[`multiselect (isCI = false) > renders instructions without guide 1`] = ` exports[`multiselect (isCI = false) > renders message 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -448,39 +481,39 @@ exports[`multiselect (isCI = false) > renders message 1`] = ` exports[`multiselect (isCI = false) > renders multiple cancelled values 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "│ ◼ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 +| [•] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "■ foo -│ opt0, opt1 -│", + "x foo +| opt0, opt1 +|", " ", "", @@ -490,46 +523,46 @@ exports[`multiselect (isCI = false) > renders multiple cancelled values 1`] = ` exports[`multiselect (isCI = false) > renders multiple selected options 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "│ ◼ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 +| [•] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "│ ◼ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt1 +| [•] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0, opt1", + "o foo +| opt0, opt1", " ", "", @@ -539,36 +572,36 @@ exports[`multiselect (isCI = false) > renders multiple selected options 1`] = ` exports[`multiselect (isCI = false) > renders validation errors 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "▲ foo -│ ◻ opt0 -│ ◻ opt1 -└ Please select at least one option. + "x foo +| [•] opt0 +| [ ] opt1 +— Please select at least one option. Press  space  to select,  enter  to submit ", "", "", "", - "◆ foo -│ ◼ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "* foo +| [+] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -578,17 +611,17 @@ exports[`multiselect (isCI = false) > renders validation errors 1`] = ` exports[`multiselect (isCI = false) > showInstructions: false hides instruction footer 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +— ", "", "", "", - "◇ foo -│ none", + "o foo +| none", " ", "", @@ -598,36 +631,36 @@ exports[`multiselect (isCI = false) > showInstructions: false hides instruction exports[`multiselect (isCI = false) > shows hints for all selected options 1`] = ` [ "", - "│ -◆ foo -│ ◼ opt0 (Hint 0) -│ ◼ opt1 (Hint 1) -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [+] opt0 (Hint 0) +| [+] opt1 (Hint 1) +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0 (Hint 0) -│ ◼ opt1 (Hint 1) -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 (Hint 0) +| [+] opt1 (Hint 1) +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1 (Hint 1) -│ ◻ opt2 (Hint 2) -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt1 (Hint 1) +| [•] opt2 (Hint 2) +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0, opt1", + "o foo +| opt0, opt1", " ", "", @@ -637,156 +670,156 @@ exports[`multiselect (isCI = false) > shows hints for all selected options 1`] = exports[`multiselect (isCI = false) > sliding window loops downwards 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ◻ opt8 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt5 +| [ ] opt6 +| [•] opt7 +| [ ] opt8 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt6 -│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt6 +| [ ] opt7 +| [•] opt8 +| [ ] opt9 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt7 +| [ ] opt8 +| [•] opt9 +| [ ] opt10 +| [ ] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt9 +| [•] opt10 +| [ ] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt10 +| [•] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -796,39 +829,39 @@ exports[`multiselect (isCI = false) > sliding window loops downwards 1`] = ` exports[`multiselect (isCI = false) > sliding window loops upwards 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt7 +| [ ] opt8 +| [ ] opt9 +| [ ] opt10 +| [•] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt11", + "| [+] opt11", "", "", "", "", - "◇ foo -│ opt11", + "o foo +| opt11", " ", "", @@ -838,19 +871,19 @@ exports[`multiselect (isCI = false) > sliding window loops upwards 1`] = ` exports[`multiselect (isCI = false) > withGuide: false removes guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", "", - "◼ opt0", + "[+] opt0", "", "", "", - "◇ foo + "o foo opt0", " ", @@ -861,33 +894,33 @@ exports[`multiselect (isCI = false) > withGuide: false removes guide 1`] = ` exports[`multiselect (isCI = false) > wraps cancelled state with long options 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 -│ ◻ Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 +| [ ] Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0 Option 0 Option ", + "| [+] Option 0 Option 0 ", "", "", "", "", - "■ foo -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 -│", + "x foo +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 +|", " ", "", @@ -897,27 +930,27 @@ exports[`multiselect (isCI = false) > wraps cancelled state with long options 1` exports[`multiselect (isCI = false) > wraps long messages 1`] = ` [ "", - "│ -◆ foo foo foo foo foo foo foo -│ foo foo foo foo foo foo -│ foo foo foo foo foo foo foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo foo foo foo foo foo foo +| foo foo foo foo foo foo +| foo foo foo foo foo foo foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo foo foo foo foo foo foo -│ foo foo foo foo foo foo -│ foo foo foo foo foo foo foo -│ opt0", + "o foo foo foo foo foo foo foo +| foo foo foo foo foo foo +| foo foo foo foo foo foo foo +| opt0", " ", "", @@ -927,32 +960,65 @@ exports[`multiselect (isCI = false) > wraps long messages 1`] = ` exports[`multiselect (isCI = false) > wraps success state with long options 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 -│ ◻ Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 +| [ ] Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0 Option 0 Option ", + "| [+] Option 0 Option 0 ", "", "", "", "", - "◇ foo -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0", + "o foo +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0", + " +", + "", +] +`; + +exports[`multiselect (isCI = true) > calculates rowPadding properly on narrow terminals with wrapped footers 1`] = ` +[ + "", + "| +* Select an option +| [•] Option 0 +| [ ] Option 1 +| [ ] Option 2 +| [ ] Option 3 +| [ ] Option 4 +| [ ] Option 5 +| [ ] Option 6 +| [ ] Option 7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— +", + "", + "", + "", + "| [+] Option 0", + "", + "", + "", + "", + "o Select an option +| Option 0", " ", "", @@ -962,12 +1028,12 @@ exports[`multiselect (isCI = false) > wraps success state with long options 1`] exports[`multiselect (isCI = true) > can be aborted by a signal 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", " ", @@ -978,18 +1044,18 @@ exports[`multiselect (isCI = true) > can be aborted by a signal 1`] = ` exports[`multiselect (isCI = true) > can cancel 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "■ foo -│", + "x foo +|", " ", "", @@ -999,23 +1065,23 @@ exports[`multiselect (isCI = true) > can cancel 1`] = ` exports[`multiselect (isCI = true) > can render option hints 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 (Hint 0) -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 (Hint 0) +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0 (Hint 0)", + "| [+] opt0 (Hint 0)", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -1025,23 +1091,23 @@ exports[`multiselect (isCI = true) > can render option hints 1`] = ` exports[`multiselect (isCI = true) > can set cursorAt to preselect an option 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [ ] opt0 +| [•] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -1051,23 +1117,23 @@ exports[`multiselect (isCI = true) > can set cursorAt to preselect an option 1`] exports[`multiselect (isCI = true) > can set custom labels 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 -│ ◻ Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 +| [ ] Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0", + "| [+] Option 0", "", "", "", "", - "◇ foo -│ Option 0", + "o foo +| Option 0", " ", "", @@ -1077,18 +1143,18 @@ exports[`multiselect (isCI = true) > can set custom labels 1`] = ` exports[`multiselect (isCI = true) > can set initial values 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◼ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [+] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -1098,18 +1164,18 @@ exports[`multiselect (isCI = true) > can set initial values 1`] = ` exports[`multiselect (isCI = true) > can submit without selection when required = false 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ none", + "o foo +| none", " ", "", @@ -1119,19 +1185,19 @@ exports[`multiselect (isCI = true) > can submit without selection when required exports[`multiselect (isCI = true) > global withGuide: false removes guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", "", - "◼ opt0", + "[+] opt0", "", "", "", - "◇ foo + "o foo opt0", " ", @@ -1142,94 +1208,94 @@ exports[`multiselect (isCI = true) > global withGuide: false removes guide 1`] = exports[`multiselect (isCI = true) > maxItems accounts for instruction footer 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt6", + "| [+] opt6", "", "", "", "", - "◇ foo -│ opt6", + "o foo +| opt6", " ", "", @@ -1239,94 +1305,94 @@ exports[`multiselect (isCI = true) > maxItems accounts for instruction footer 1` exports[`multiselect (isCI = true) > maxItems renders a sliding window 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt6", + "| [+] opt6", "", "", "", "", - "◇ foo -│ opt6", + "o foo +| opt6", " ", "", @@ -1336,24 +1402,24 @@ exports[`multiselect (isCI = true) > maxItems renders a sliding window 1`] = ` exports[`multiselect (isCI = true) > renders disabled options 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 (Hint 2) -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [ ] opt0 +| [•] opt1 +| [ ] opt2 (Hint 2) +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "◇ foo -│ opt1", + "o foo +| opt1", " ", "", @@ -1363,14 +1429,14 @@ exports[`multiselect (isCI = true) > renders disabled options 1`] = ` exports[`multiselect (isCI = true) > renders instructions without guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", - "◇ foo + "o foo none", " ", @@ -1381,23 +1447,23 @@ exports[`multiselect (isCI = true) > renders instructions without guide 1`] = ` exports[`multiselect (isCI = true) > renders message 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -1407,39 +1473,39 @@ exports[`multiselect (isCI = true) > renders message 1`] = ` exports[`multiselect (isCI = true) > renders multiple cancelled values 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "│ ◼ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 +| [•] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "■ foo -│ opt0, opt1 -│", + "x foo +| opt0, opt1 +|", " ", "", @@ -1449,46 +1515,46 @@ exports[`multiselect (isCI = true) > renders multiple cancelled values 1`] = ` exports[`multiselect (isCI = true) > renders multiple selected options 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "│ ◼ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 +| [•] opt1 +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1", + "| [+] opt1", "", "", "", "", - "│ ◼ opt1 -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt1 +| [•] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0, opt1", + "o foo +| opt0, opt1", " ", "", @@ -1498,36 +1564,36 @@ exports[`multiselect (isCI = true) > renders multiple selected options 1`] = ` exports[`multiselect (isCI = true) > renders validation errors 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "▲ foo -│ ◻ opt0 -│ ◻ opt1 -└ Please select at least one option. + "x foo +| [•] opt0 +| [ ] opt1 +— Please select at least one option. Press  space  to select,  enter  to submit ", "", "", "", - "◆ foo -│ ◼ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "* foo +| [+] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -1537,17 +1603,17 @@ exports[`multiselect (isCI = true) > renders validation errors 1`] = ` exports[`multiselect (isCI = true) > showInstructions: false hides instruction footer 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +— ", "", "", "", - "◇ foo -│ none", + "o foo +| none", " ", "", @@ -1557,36 +1623,36 @@ exports[`multiselect (isCI = true) > showInstructions: false hides instruction f exports[`multiselect (isCI = true) > shows hints for all selected options 1`] = ` [ "", - "│ -◆ foo -│ ◼ opt0 (Hint 0) -│ ◼ opt1 (Hint 1) -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [+] opt0 (Hint 0) +| [+] opt1 (Hint 1) +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0 (Hint 0) -│ ◼ opt1 (Hint 1) -│ ◻ opt2 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt0 (Hint 0) +| [+] opt1 (Hint 1) +| [ ] opt2 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt1 (Hint 1) -│ ◻ opt2 (Hint 2) -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [+] opt1 (Hint 1) +| [•] opt2 (Hint 2) +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "◇ foo -│ opt0, opt1", + "o foo +| opt0, opt1", " ", "", @@ -1596,156 +1662,156 @@ exports[`multiselect (isCI = true) > shows hints for all selected options 1`] = exports[`multiselect (isCI = true) > sliding window loops downwards 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt0 +| [•] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt1 +| [•] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt2 +| [•] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt2 +| [ ] opt3 +| [•] opt4 +| [ ] opt5 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt3 -│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt3 +| [ ] opt4 +| [•] opt5 +| [ ] opt6 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt4 -│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt4 +| [ ] opt5 +| [•] opt6 +| [ ] opt7 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt5 -│ ◻ opt6 -│ ◻ opt7 -│ ◻ opt8 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt5 +| [ ] opt6 +| [•] opt7 +| [ ] opt8 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt6 -│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt6 +| [ ] opt7 +| [•] opt8 +| [ ] opt9 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt7 +| [ ] opt8 +| [•] opt9 +| [ ] opt10 +| [ ] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt9 +| [•] opt10 +| [ ] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [ ] opt10 +| [•] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo -│ opt0", + "o foo +| opt0", " ", "", @@ -1755,39 +1821,39 @@ exports[`multiselect (isCI = true) > sliding window loops downwards 1`] = ` exports[`multiselect (isCI = true) > sliding window loops upwards 1`] = ` [ "", - "│ -◆ foo -│ ◻ opt0 -│ ◻ opt1 -│ ◻ opt2 -│ ◻ opt3 -│ ◻ opt4 -│ ... -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] opt0 +| [ ] opt1 +| [ ] opt2 +| [ ] opt3 +| [ ] opt4 +| ... +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ... -│ ◻ opt7 -│ ◻ opt8 -│ ◻ opt9 -│ ◻ opt10 -│ ◻ opt11 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| ... +| [ ] opt7 +| [ ] opt8 +| [ ] opt9 +| [ ] opt10 +| [•] opt11 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt11", + "| [+] opt11", "", "", "", "", - "◇ foo -│ opt11", + "o foo +| opt11", " ", "", @@ -1797,19 +1863,19 @@ exports[`multiselect (isCI = true) > sliding window loops upwards 1`] = ` exports[`multiselect (isCI = true) > withGuide: false removes guide 1`] = ` [ "", - "◆ foo -◻ opt0 -◻ opt1 + "* foo +[•] opt0 +[ ] opt1 ↑/↓ to navigate • Space: select • Enter: confirm ", "", "", "", - "◼ opt0", + "[+] opt0", "", "", "", - "◇ foo + "o foo opt0", " ", @@ -1820,33 +1886,33 @@ exports[`multiselect (isCI = true) > withGuide: false removes guide 1`] = ` exports[`multiselect (isCI = true) > wraps cancelled state with long options 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 -│ ◻ Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 +| [ ] Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0 Option 0 Option ", + "| [+] Option 0 Option 0 ", "", "", "", "", - "■ foo -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 -│", + "x foo +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 +|", " ", "", @@ -1856,27 +1922,27 @@ exports[`multiselect (isCI = true) > wraps cancelled state with long options 1`] exports[`multiselect (isCI = true) > wraps long messages 1`] = ` [ "", - "│ -◆ foo foo foo foo foo foo foo -│ foo foo foo foo foo foo -│ foo foo foo foo foo foo foo -│ ◻ opt0 -│ ◻ opt1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo foo foo foo foo foo foo +| foo foo foo foo foo foo +| foo foo foo foo foo foo foo +| [•] opt0 +| [ ] opt1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ opt0", + "| [+] opt0", "", "", "", "", - "◇ foo foo foo foo foo foo foo -│ foo foo foo foo foo foo -│ foo foo foo foo foo foo foo -│ opt0", + "o foo foo foo foo foo foo foo +| foo foo foo foo foo foo +| foo foo foo foo foo foo foo +| opt0", " ", "", @@ -1886,32 +1952,32 @@ exports[`multiselect (isCI = true) > wraps long messages 1`] = ` exports[`multiselect (isCI = true) > wraps success state with long options 1`] = ` [ "", - "│ -◆ foo -│ ◻ Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 Option 0 Option -│ 0 Option 0 -│ ◻ Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 Option 1 Option  -│ 1 Option 1 -│ ↑/↓ to navigate • Space: select • Enter: confirm -└ + "| +* foo +| [•] Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 Option 0 +| Option 0 Option 0 +| [ ] Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 Option 1  +| Option 1 Option 1 +| ↑/↓ to navigate • Space: select • Enter: confirm +— ", "", "", "", - "│ ◼ Option 0 Option 0 Option ", + "| [+] Option 0 Option 0 ", "", "", "", "", - "◇ foo -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0 Option 0 Option 0  -│ Option 0", + "o foo +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0 Option 0 Option 0  +| Option 0", " ", "", diff --git a/packages/prompts/test/multi-select.test.ts b/packages/prompts/test/multi-select.test.ts index e11125e1..551a5011 100644 --- a/packages/prompts/test/multi-select.test.ts +++ b/packages/prompts/test/multi-select.test.ts @@ -492,4 +492,28 @@ describe.each(['true', 'false'])('multiselect (isCI = %s)', (isCI) => { await result; expect(output.buffer).toMatchSnapshot(); }); + + test('calculates rowPadding properly on narrow terminals with wrapped footers', async () => { + output.columns = 30; // Very narrow terminal + output.rows = 15; // Small height + + const result = prompts.multiselect({ + message: 'Select an option', + options: Array.from({ length: 20 }).map((_, i) => ({ + value: `opt${i}`, + label: `Option ${i}`, + })), + input, + output, + }); + + // Just confirm selection + input.emit('keypress', '', { name: 'space' }); + input.emit('keypress', '', { name: 'return' }); + + await result; + + // The output should be snapshotted correctly without overflowing the rows limit. + expect(output.buffer).toMatchSnapshot(); + }); });