diff --git a/.changeset/young-mice-vanish.md b/.changeset/young-mice-vanish.md new file mode 100644 index 00000000..00c2706b --- /dev/null +++ b/.changeset/young-mice-vanish.md @@ -0,0 +1,5 @@ +--- +'@clack/prompts': patch +--- + +feat(@clack/prompts): Add validate option for select and multiselect diff --git a/packages/prompts/src/index.ts b/packages/prompts/src/index.ts index 02e29d77..f4f420d4 100644 --- a/packages/prompts/src/index.ts +++ b/packages/prompts/src/index.ts @@ -214,6 +214,7 @@ export interface SelectOptions { options: Option[]; initialValue?: Value; maxItems?: number; + validate?: (value: string) => string | void; } export const select = (opts: SelectOptions) => { @@ -234,6 +235,7 @@ export const select = (opts: SelectOptions) => { }; return new SelectPrompt({ + validate: opts.validate, options: opts.options, initialValue: opts.initialValue, render() { @@ -247,6 +249,20 @@ export const select = (opts: SelectOptions) => { this.options[this.cursor], 'cancelled' )}\n${color.gray(S_BAR)}`; + case 'error': { + const footer = this.error + .split('\n') + .map((ln, i) => + i === 0 ? `${color.yellow(S_BAR_END)} ${color.yellow(ln)}` : ` ${ln}` + ) + .join('\n'); + return `${title}${color.yellow(S_BAR)} ${limitOptions({ + cursor: this.cursor, + options: this.options, + maxItems: opts.maxItems, + style: (item, active) => opt(item, active ? 'active' : 'inactive'), + }).join(`\n${color.yellow(S_BAR)} `)}\n${footer}`; + } default: { return `${title}${color.cyan(S_BAR)} ${limitOptions({ cursor: this.cursor, @@ -313,6 +329,7 @@ export interface MultiSelectOptions { maxItems?: number; required?: boolean; cursorAt?: Value; + validate?: (value: Value[]) => string | void; } export const multiselect = (opts: MultiSelectOptions) => { const opt = ( @@ -344,6 +361,10 @@ export const multiselect = (opts: MultiSelectOptions) => { required: opts.required ?? true, cursorAt: opts.cursorAt, validate(selected: Value[]) { + if (opts.validate) { + const error = opts.validate(selected); + if (error) return error; + } if (this.required && selected.length === 0) return `Please select at least one option.\n${color.reset( color.dim(