Spaces:
Runtime error
Runtime error
; | |
const colors = require('ansi-colors'); | |
const SelectPrompt = require('./select'); | |
const placeholder = require('../placeholder'); | |
class FormPrompt extends SelectPrompt { | |
constructor(options) { | |
super({ ...options, multiple: true }); | |
this.type = 'form'; | |
this.initial = this.options.initial; | |
this.align = [this.options.align, 'right'].find(v => v != null); | |
this.emptyError = ''; | |
this.values = {}; | |
} | |
async reset(first) { | |
await super.reset(); | |
if (first === true) this._index = this.index; | |
this.index = this._index; | |
this.values = {}; | |
this.choices.forEach(choice => choice.reset && choice.reset()); | |
return this.render(); | |
} | |
dispatch(char) { | |
return !!char && this.append(char); | |
} | |
append(char) { | |
let choice = this.focused; | |
if (!choice) return this.alert(); | |
let { cursor, input } = choice; | |
choice.value = choice.input = input.slice(0, cursor) + char + input.slice(cursor); | |
choice.cursor++; | |
return this.render(); | |
} | |
delete() { | |
let choice = this.focused; | |
if (!choice || choice.cursor <= 0) return this.alert(); | |
let { cursor, input } = choice; | |
choice.value = choice.input = input.slice(0, cursor - 1) + input.slice(cursor); | |
choice.cursor--; | |
return this.render(); | |
} | |
deleteForward() { | |
let choice = this.focused; | |
if (!choice) return this.alert(); | |
let { cursor, input } = choice; | |
if (input[cursor] === void 0) return this.alert(); | |
let str = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1); | |
choice.value = choice.input = str; | |
return this.render(); | |
} | |
right() { | |
let choice = this.focused; | |
if (!choice) return this.alert(); | |
if (choice.cursor >= choice.input.length) return this.alert(); | |
choice.cursor++; | |
return this.render(); | |
} | |
left() { | |
let choice = this.focused; | |
if (!choice) return this.alert(); | |
if (choice.cursor <= 0) return this.alert(); | |
choice.cursor--; | |
return this.render(); | |
} | |
space(ch, key) { | |
return this.dispatch(ch, key); | |
} | |
number(ch, key) { | |
return this.dispatch(ch, key); | |
} | |
next() { | |
let ch = this.focused; | |
if (!ch) return this.alert(); | |
let { initial, input } = ch; | |
if (initial && initial.startsWith(input) && input !== initial) { | |
ch.value = ch.input = initial; | |
ch.cursor = ch.value.length; | |
return this.render(); | |
} | |
return super.next(); | |
} | |
prev() { | |
let ch = this.focused; | |
if (!ch) return this.alert(); | |
if (ch.cursor === 0) return super.prev(); | |
ch.value = ch.input = ''; | |
ch.cursor = 0; | |
return this.render(); | |
} | |
separator() { | |
return ''; | |
} | |
format(value) { | |
return !this.state.submitted ? super.format(value) : ''; | |
} | |
pointer() { | |
return ''; | |
} | |
indicator(choice) { | |
return choice.input ? '⦿' : '⊙'; | |
} | |
async choiceSeparator(choice, i) { | |
let sep = await this.resolve(choice.separator, this.state, choice, i) || ':'; | |
return sep ? ' ' + this.styles.disabled(sep) : ''; | |
} | |
async renderChoice(choice, i) { | |
await this.onChoice(choice, i); | |
let { state, styles } = this; | |
let { cursor, initial = '', name, hint, input = '' } = choice; | |
let { muted, submitted, primary, danger } = styles; | |
let help = hint; | |
let focused = this.index === i; | |
let validate = choice.validate || (() => true); | |
let sep = await this.choiceSeparator(choice, i); | |
let msg = choice.message; | |
if (this.align === 'right') msg = msg.padStart(this.longest + 1, ' '); | |
if (this.align === 'left') msg = msg.padEnd(this.longest + 1, ' '); | |
// re-populate the form values (answers) object | |
let value = this.values[name] = (input || initial); | |
let color = input ? 'success' : 'dark'; | |
if ((await validate.call(choice, value, this.state)) !== true) { | |
color = 'danger'; | |
} | |
let style = styles[color]; | |
let indicator = style(await this.indicator(choice, i)) + (choice.pad || ''); | |
let indent = this.indent(choice); | |
let line = () => [indent, indicator, msg + sep, input, help].filter(Boolean).join(' '); | |
if (state.submitted) { | |
msg = colors.unstyle(msg); | |
input = submitted(input); | |
help = ''; | |
return line(); | |
} | |
if (choice.format) { | |
input = await choice.format.call(this, input, choice, i); | |
} else { | |
let color = this.styles.muted; | |
let options = { input, initial, pos: cursor, showCursor: focused, color }; | |
input = placeholder(this, options); | |
} | |
if (!this.isValue(input)) { | |
input = this.styles.muted(this.symbols.ellipsis); | |
} | |
if (choice.result) { | |
this.values[name] = await choice.result.call(this, value, choice, i); | |
} | |
if (focused) { | |
msg = primary(msg); | |
} | |
if (choice.error) { | |
input += (input ? ' ' : '') + danger(choice.error.trim()); | |
} else if (choice.hint) { | |
input += (input ? ' ' : '') + muted(choice.hint.trim()); | |
} | |
return line(); | |
} | |
async submit() { | |
this.value = this.values; | |
return super.base.submit.call(this); | |
} | |
} | |
module.exports = FormPrompt; | |