multiselect.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. 'use strict';
  2. const color = require('kleur');
  3. const Prompt = require('./prompt');
  4. var _require = require('sisteransi');
  5. const cursor = _require.cursor;
  6. var _require2 = require('../util');
  7. const clear = _require2.clear,
  8. figures = _require2.figures,
  9. style = _require2.style;
  10. /**
  11. * MultiselectPrompt Base Element
  12. * @param {Object} opts Options
  13. * @param {String} opts.message Message
  14. * @param {Array} opts.choices Array of choice objects
  15. * @param {String} [opts.hint] Hint to display
  16. * @param {Number} [opts.cursor=0] Cursor start position
  17. * @param {Number} [opts.max] Max choices
  18. */
  19. class MultiselectPrompt extends Prompt {
  20. constructor(opts = {}) {
  21. super(opts);
  22. this.msg = opts.message;
  23. this.cursor = opts.cursor || 0;
  24. this.hint = opts.hint || '- Space to select. Return to submit';
  25. this.maxChoices = opts.max;
  26. this.value = opts.choices.map(v => Object.assign({ title: v.value, selected: false }, v));
  27. this.clear = clear('');
  28. this.render(true);
  29. }
  30. reset() {
  31. this.value.map(v => !v.selected);
  32. this.cursor = 0;
  33. this.fire();
  34. this.render();
  35. }
  36. selected() {
  37. return this.value.filter(v => v.selected);
  38. }
  39. abort() {
  40. this.done = this.aborted = true;
  41. this.fire();
  42. this.render();
  43. this.out.write('\n');
  44. this.close();
  45. }
  46. submit() {
  47. this.done = true;
  48. this.aborted = false;
  49. this.fire();
  50. this.render();
  51. this.out.write('\n');
  52. this.close();
  53. }
  54. first() {
  55. this.cursor = 0;
  56. this.render();
  57. }
  58. last() {
  59. this.cursor = this.value.length - 1;
  60. this.render();
  61. }
  62. next() {
  63. this.cursor = (this.cursor + 1) % this.value.length;
  64. this.render();
  65. }
  66. up() {
  67. if (this.cursor === 0) return this.bell();
  68. this.cursor--;
  69. this.render();
  70. }
  71. down() {
  72. if (this.cursor === this.value.length - 1) return this.bell();
  73. this.cursor++;
  74. this.render();
  75. }
  76. left() {
  77. this.value[this.cursor].selected = false;
  78. this.render();
  79. }
  80. right() {
  81. if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
  82. this.value[this.cursor].selected = true;
  83. this.render();
  84. }
  85. _(c, key) {
  86. if (c !== ' ') return this.bell();
  87. const v = this.value[this.cursor];
  88. if (v.selected) {
  89. v.selected = false;
  90. this.render();
  91. } else if (this.value.filter(e => e.selected).length >= this.maxChoices) {
  92. return this.bell();
  93. } else {
  94. v.selected = true;
  95. this.render();
  96. }
  97. }
  98. render(first) {
  99. if (first) this.out.write(cursor.hide);
  100. // print prompt
  101. const selected = this.value.filter(e => e.selected).map(v => v.title).join(', ');
  102. let prompt = [style.symbol(this.done, this.aborted), color.bold(this.msg), style.delimiter(false), this.done ? selected : color.gray(this.hint)].join(' ');
  103. // print choices
  104. if (!this.done) {
  105. const c = this.cursor;
  106. prompt += '\n' + this.value.map((v, i) => (v.selected ? color.green(figures.tick) : ' ') + ' ' + (c === i ? color.cyan.underline(v.title) : v.title)).join('\n');
  107. }
  108. this.out.write(this.clear + prompt);
  109. this.clear = clear(prompt);
  110. }
  111. }
  112. module.exports = MultiselectPrompt;