123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- 'use strict';
- const color = require('kleur');
- const Prompt = require('./prompt');
- const { cursor } = require('sisteransi');
- const { clear, figures, style } = require('../util');
- /**
- * MultiselectPrompt Base Element
- * @param {Object} opts Options
- * @param {String} opts.message Message
- * @param {Array} opts.choices Array of choice objects
- * @param {String} [opts.hint] Hint to display
- * @param {Number} [opts.cursor=0] Cursor start position
- * @param {Number} [opts.max] Max choices
- */
- class MultiselectPrompt extends Prompt {
- constructor(opts={}) {
- super(opts);
- this.msg = opts.message;
- this.cursor = opts.cursor || 0;
- this.hint = opts.hint || '- Space to select. Return to submit';
- this.maxChoices = opts.max;
- this.value = opts.choices.map(v => Object.assign({ title: v.value, selected: false }, v));
- this.clear = clear('');
- this.render(true);
- }
- reset() {
- this.value.map(v => !v.selected);
- this.cursor = 0;
- this.fire();
- this.render();
- }
- selected() {
- return this.value.filter(v => v.selected);
- }
- abort() {
- this.done = this.aborted = true;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- submit() {
- this.done = true;
- this.aborted = false;
- this.fire();
- this.render();
- this.out.write('\n');
- this.close();
- }
- first() {
- this.cursor = 0;
- this.render();
- }
- last() {
- this.cursor = this.value.length - 1;
- this.render();
- }
- next() {
- this.cursor = (this.cursor + 1) % this.value.length;
- this.render();
- }
- up() {
- if (this.cursor === 0) return this.bell();
- this.cursor--;
- this.render();
- }
- down() {
- if (this.cursor === this.value.length - 1) return this.bell();
- this.cursor++;
- this.render();
- }
- left() {
- this.value[this.cursor].selected = false;
- this.render();
- }
- right() {
- if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
- this.value[this.cursor].selected = true;
- this.render();
- }
- _(c, key) {
- if (c !== ' ') return this.bell();
- const v = this.value[this.cursor];
- if (v.selected) {
- v.selected = false;
- this.render();
- } else if (this.value.filter(e => e.selected).length >= this.maxChoices) {
- return this.bell();
- } else {
- v.selected = true;
- this.render();
- }
- }
- render(first) {
- if (first) this.out.write(cursor.hide);
- // print prompt
- const selected = this.value
- .filter(e => e.selected)
- .map(v => v.title)
- .join(', ');
- let prompt = [
- style.symbol(this.done, this.aborted),
- color.bold(this.msg),
- style.delimiter(false),
- this.done ? selected : color.gray(this.hint)
- ].join(' ');
- // print choices
- if (!this.done) {
- const c = this.cursor;
- prompt +=
- '\n' +
- this.value
- .map(
- (v, i) =>
- (v.selected ? color.green(figures.tick) : ' ') +
- ' ' +
- (c === i ? color.cyan.underline(v.title) : v.title)
- )
- .join('\n');
- }
- this.out.write(this.clear + prompt);
- this.clear = clear(prompt);
- }
- }
- module.exports = MultiselectPrompt;
|