|
|
'use strict';
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;
|