You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.8 KiB
139 lines
3.8 KiB
'use strict'; |
|
|
|
const ArrayPrompt = require('../types/array'); |
|
const utils = require('../utils'); |
|
|
|
class SelectPrompt extends ArrayPrompt { |
|
constructor(options) { |
|
super(options); |
|
this.emptyError = this.options.emptyError || 'No items were selected'; |
|
} |
|
|
|
async dispatch(s, key) { |
|
if (this.multiple) { |
|
return this[key.name] ? await this[key.name](s, key) : await super.dispatch(s, key); |
|
} |
|
this.alert(); |
|
} |
|
|
|
separator() { |
|
if (this.options.separator) return super.separator(); |
|
let sep = this.styles.muted(this.symbols.ellipsis); |
|
return this.state.submitted ? super.separator() : sep; |
|
} |
|
|
|
pointer(choice, i) { |
|
return (!this.multiple || this.options.pointer) ? super.pointer(choice, i) : ''; |
|
} |
|
|
|
indicator(choice, i) { |
|
return this.multiple ? super.indicator(choice, i) : ''; |
|
} |
|
|
|
choiceMessage(choice, i) { |
|
let message = this.resolve(choice.message, this.state, choice, i); |
|
if (choice.role === 'heading' && !utils.hasColor(message)) { |
|
message = this.styles.strong(message); |
|
} |
|
return this.resolve(message, this.state, choice, i); |
|
} |
|
|
|
choiceSeparator() { |
|
return ':'; |
|
} |
|
|
|
async renderChoice(choice, i) { |
|
await this.onChoice(choice, i); |
|
|
|
let focused = this.index === i; |
|
let pointer = await this.pointer(choice, i); |
|
let check = await this.indicator(choice, i) + (choice.pad || ''); |
|
let hint = await this.resolve(choice.hint, this.state, choice, i); |
|
|
|
if (hint && !utils.hasColor(hint)) { |
|
hint = this.styles.muted(hint); |
|
} |
|
|
|
let ind = this.indent(choice); |
|
let msg = await this.choiceMessage(choice, i); |
|
let line = () => [this.margin[3], ind + pointer + check, msg, this.margin[1], hint].filter(Boolean).join(' '); |
|
|
|
if (choice.role === 'heading') { |
|
return line(); |
|
} |
|
|
|
if (choice.disabled) { |
|
if (!utils.hasColor(msg)) { |
|
msg = this.styles.disabled(msg); |
|
} |
|
return line(); |
|
} |
|
|
|
if (focused) { |
|
msg = this.styles.em(msg); |
|
} |
|
|
|
return line(); |
|
} |
|
|
|
async renderChoices() { |
|
if (this.state.loading === 'choices') { |
|
return this.styles.warning('Loading choices'); |
|
} |
|
|
|
if (this.state.submitted) return ''; |
|
let choices = this.visible.map(async(ch, i) => await this.renderChoice(ch, i)); |
|
let visible = await Promise.all(choices); |
|
if (!visible.length) visible.push(this.styles.danger('No matching choices')); |
|
let result = this.margin[0] + visible.join('\n'); |
|
let header; |
|
|
|
if (this.options.choicesHeader) { |
|
header = await this.resolve(this.options.choicesHeader, this.state); |
|
} |
|
|
|
return [header, result].filter(Boolean).join('\n'); |
|
} |
|
|
|
format() { |
|
if (!this.state.submitted || this.state.cancelled) return ''; |
|
if (Array.isArray(this.selected)) { |
|
return this.selected.map(choice => this.styles.primary(choice.name)).join(', '); |
|
} |
|
return this.styles.primary(this.selected.name); |
|
} |
|
|
|
async render() { |
|
let { submitted, size } = this.state; |
|
|
|
let prompt = ''; |
|
let header = await this.header(); |
|
let prefix = await this.prefix(); |
|
let separator = await this.separator(); |
|
let message = await this.message(); |
|
|
|
if (this.options.promptLine !== false) { |
|
prompt = [prefix, message, separator, ''].join(' '); |
|
this.state.prompt = prompt; |
|
} |
|
|
|
let output = await this.format(); |
|
let help = (await this.error()) || (await this.hint()); |
|
let body = await this.renderChoices(); |
|
let footer = await this.footer(); |
|
|
|
if (output) prompt += output; |
|
if (help && !prompt.includes(help)) prompt += ' ' + help; |
|
|
|
if (submitted && !output && !body.trim() && this.multiple && this.emptyError != null) { |
|
prompt += this.styles.danger(this.emptyError); |
|
} |
|
|
|
this.clear(size); |
|
this.write([header, prompt, body, footer].filter(Boolean).join('\n')); |
|
this.write(this.margin[2]); |
|
this.restore(); |
|
} |
|
} |
|
|
|
module.exports = SelectPrompt;
|
|
|