Skip to content

Commit 37198d5

Browse files
committed
feat: add help on prompt
1 parent 5529c89 commit 37198d5

1 file changed

Lines changed: 23 additions & 11 deletions

File tree

packages/prompts/src/index.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const S_STEP_SUBMIT = s('◇', 'o');
2727

2828
const S_BAR_START = s('┌', 'T');
2929
const S_BAR = s('│', '|');
30+
const S_BAR_DETAIL = s('│ⓘ', `|${color.italic('i')}`);
3031
const S_BAR_END = s('└', '—');
3132

3233
const S_RADIO_ACTIVE = s('●', '>');
@@ -60,6 +61,11 @@ const symbol = (state: State) => {
6061
}
6162
};
6263

64+
const help = (text: string | undefined, style: (input: string) => string) => {
65+
if (text === undefined) return '';
66+
return `${style(S_BAR_DETAIL)} ${color.dim(color.italic(text))}\n`;
67+
};
68+
6369
interface LimitOptionsParams<TOption> {
6470
options: TOption[];
6571
maxItems: number | undefined;
@@ -99,6 +105,7 @@ const limitOptions = <TOption>(params: LimitOptionsParams<TOption>): string[] =>
99105

100106
export interface TextOptions {
101107
message: string;
108+
help?: string;
102109
placeholder?: string;
103110
defaultValue?: string;
104111
initialValue?: string;
@@ -119,7 +126,7 @@ export const text = (opts: TextOptions) => {
119126

120127
switch (this.state) {
121128
case 'error':
122-
return `${title.trim()}\n${color.yellow(S_BAR)} ${value}\n${color.yellow(
129+
return `${title.trim()}\n${help(opts.help, color.yellow)}${color.yellow(S_BAR)} ${value}\n${color.yellow(
123130
S_BAR_END
124131
)} ${color.yellow(this.error)}\n`;
125132
case 'submit':
@@ -129,14 +136,15 @@ export const text = (opts: TextOptions) => {
129136
color.dim(this.value ?? '')
130137
)}${this.value?.trim() ? `\n${color.gray(S_BAR)}` : ''}`;
131138
default:
132-
return `${title}${color.cyan(S_BAR)} ${value}\n${color.cyan(S_BAR_END)}\n`;
139+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${value}\n${color.cyan(S_BAR_END)}\n`;
133140
}
134141
},
135142
}).prompt() as Promise<string | symbol>;
136143
};
137144

138145
export interface PasswordOptions {
139146
message: string;
147+
help?: string;
140148
mask?: string;
141149
validate?: (value: string) => string | Error | undefined;
142150
}
@@ -151,7 +159,7 @@ export const password = (opts: PasswordOptions) => {
151159

152160
switch (this.state) {
153161
case 'error':
154-
return `${title.trim()}\n${color.yellow(S_BAR)} ${masked}\n${color.yellow(
162+
return `${title.trim()}\n${help(opts.help, color.yellow)}${color.yellow(S_BAR)} ${masked}\n${color.yellow(
155163
S_BAR_END
156164
)} ${color.yellow(this.error)}\n`;
157165
case 'submit':
@@ -161,14 +169,15 @@ export const password = (opts: PasswordOptions) => {
161169
masked ? `\n${color.gray(S_BAR)}` : ''
162170
}`;
163171
default:
164-
return `${title}${color.cyan(S_BAR)} ${value}\n${color.cyan(S_BAR_END)}\n`;
172+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${value}\n${color.cyan(S_BAR_END)}\n`;
165173
}
166174
},
167175
}).prompt() as Promise<string | symbol>;
168176
};
169177

170178
export interface ConfirmOptions {
171179
message: string;
180+
help?: string;
172181
active?: string;
173182
inactive?: string;
174183
initialValue?: boolean;
@@ -192,7 +201,7 @@ export const confirm = (opts: ConfirmOptions) => {
192201
color.dim(value)
193202
)}\n${color.gray(S_BAR)}`;
194203
default: {
195-
return `${title}${color.cyan(S_BAR)} ${
204+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${
196205
this.value
197206
? `${color.green(S_RADIO_ACTIVE)} ${active}`
198207
: `${color.dim(S_RADIO_INACTIVE)} ${color.dim(active)}`
@@ -249,6 +258,7 @@ export type Option<Value> = Value extends Primitive
249258

250259
export interface SelectOptions<Value> {
251260
message: string;
261+
help?: string;
252262
options: Option<Value>[];
253263
initialValue?: Value;
254264
maxItems?: number;
@@ -286,7 +296,7 @@ export const select = <Value>(opts: SelectOptions<Value>) => {
286296
'cancelled'
287297
)}\n${color.gray(S_BAR)}`;
288298
default: {
289-
return `${title}${color.cyan(S_BAR)} ${limitOptions({
299+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${limitOptions({
290300
cursor: this.cursor,
291301
options: this.options,
292302
maxItems: opts.maxItems,
@@ -337,7 +347,7 @@ export const selectKey = <Value extends string>(opts: SelectOptions<Value>) => {
337347
S_BAR
338348
)}`;
339349
default: {
340-
return `${title}${color.cyan(S_BAR)} ${this.options
350+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${this.options
341351
.map((option, i) => opt(option, i === this.cursor ? 'active' : 'inactive'))
342352
.join(`\n${color.cyan(S_BAR)} `)}\n${color.cyan(S_BAR_END)}\n`;
343353
}
@@ -348,6 +358,7 @@ export const selectKey = <Value extends string>(opts: SelectOptions<Value>) => {
348358

349359
export interface MultiSelectOptions<Value> {
350360
message: string;
361+
help?: string;
351362
options: Option<Value>[];
352363
initialValues?: Value[];
353364
maxItems?: number;
@@ -436,15 +447,15 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
436447
i === 0 ? `${color.yellow(S_BAR_END)} ${color.yellow(ln)}` : ` ${ln}`
437448
)
438449
.join('\n');
439-
return `${title + color.yellow(S_BAR)} ${limitOptions({
450+
return `${title + help(opts.help, color.yellow) + color.yellow(S_BAR)} ${limitOptions({
440451
options: this.options,
441452
cursor: this.cursor,
442453
maxItems: opts.maxItems,
443454
style: styleOption,
444455
}).join(`\n${color.yellow(S_BAR)} `)}\n${footer}\n`;
445456
}
446457
default: {
447-
return `${title}${color.cyan(S_BAR)} ${limitOptions({
458+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${limitOptions({
448459
options: this.options,
449460
cursor: this.cursor,
450461
maxItems: opts.maxItems,
@@ -458,6 +469,7 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
458469

459470
export interface GroupMultiSelectOptions<Value> {
460471
message: string;
472+
help?: string;
461473
options: Record<string, Option<Value>[]>;
462474
initialValues?: Value[];
463475
required?: boolean;
@@ -552,7 +564,7 @@ export const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) =>
552564
i === 0 ? `${color.yellow(S_BAR_END)} ${color.yellow(ln)}` : ` ${ln}`
553565
)
554566
.join('\n');
555-
return `${title}${color.yellow(S_BAR)} ${this.options
567+
return `${title}${help(opts.help, color.yellow)}${color.yellow(S_BAR)} ${this.options
556568
.map((option, i, options) => {
557569
const selected =
558570
this.value.includes(option.value) ||
@@ -576,7 +588,7 @@ export const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) =>
576588
.join(`\n${color.yellow(S_BAR)} `)}\n${footer}\n`;
577589
}
578590
default: {
579-
return `${title}${color.cyan(S_BAR)} ${this.options
591+
return `${title}${help(opts.help, color.cyan)}${color.cyan(S_BAR)} ${this.options
580592
.map((option, i, options) => {
581593
const selected =
582594
this.value.includes(option.value) ||

0 commit comments

Comments
 (0)