@topcli/prompts 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,6 +100,7 @@ Boolean prompt, return `options.initial` if user input is different from "y"/"ye
100
100
 
101
101
  ```ts
102
102
  export interface PromptOptions {
103
+ defaultValue?: string;
103
104
  validators?: {
104
105
  validate: (input: string) => boolean;
105
106
  error: (input: string) => string;
package/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export interface PromptOptions {
2
+ defaultValue?: string;
2
3
  validators?: Validator[];
3
4
  }
4
5
 
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@topcli/prompts",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Node.js user input library for command-line interfaces.",
5
5
  "scripts": {
6
- "test": "node --loader=esmock --test ./test/**.test.js",
6
+ "test": "node --loader=esmock --test test/",
7
7
  "coverage": "c8 -r html npm run test",
8
8
  "lint": "eslint .",
9
9
  "lint:fix": "eslint . --fix"
@@ -29,7 +29,8 @@
29
29
  "esmock": "^2.1.0"
30
30
  },
31
31
  "dependencies": {
32
- "ansi-styles": "^6.2.1",
32
+ "is-unicode-supported": "^1.3.0",
33
+ "kleur": "^4.1.5",
33
34
  "strip-ansi": "^7.0.1"
34
35
  },
35
36
  "engines": {
@@ -2,7 +2,7 @@
2
2
  import { EOL } from "node:os";
3
3
 
4
4
  // Import Third-party Dependencies
5
- import ansi from "ansi-styles";
5
+ import kleur from "kleur";
6
6
 
7
7
  // Import Internal Dependencies
8
8
  import { AbstractPrompt } from "./abstract-prompt.js";
@@ -17,9 +17,9 @@ export class ConfirmPrompt extends AbstractPrompt {
17
17
  } = options;
18
18
  super(message, stdin, stdout);
19
19
 
20
- const Yes = `${ansi.bold.open}Yes${ansi.bold.close}`;
21
- const No = `${ansi.bold.open}No${ansi.bold.close}`;
22
- const tip = initial ? `${Yes}/no` : `yes/${No}`;
20
+ const Yes = kleur.bold("Yes");
21
+ const No = kleur.bold("No");
22
+ this.tip = kleur.gray(initial ? `(${Yes}/no)` : `(yes/${No})`);
23
23
 
24
24
  this.initial = initial;
25
25
  }
@@ -39,14 +39,14 @@ export class ConfirmPrompt extends AbstractPrompt {
39
39
  }
40
40
 
41
41
  #getQuestionQuery() {
42
- const query = `${ansi.bold.open}${SYMBOLS.QuestionMark} ${this.message}${ansi.bold.close}`;
42
+ const query = kleur.bold(`${SYMBOLS.QuestionMark} ${this.message}`);
43
43
 
44
- return `${query} ${ansi.grey.open}(${this.initial ? "Yes/no" : "yes/No"})${ansi.grey.close} `;
44
+ return `${query} ${this.tip} `;
45
45
  }
46
46
 
47
47
  #onQuestionAnswer() {
48
48
  this.clearLastLine();
49
- this.write(`${this.answer ? SYMBOLS.Tick : SYMBOLS.Cross} ${this.message}${EOL}`);
49
+ this.write(`${this.answer ? SYMBOLS.Tick : SYMBOLS.Cross} ${kleur.bold(this.message)}${EOL}`);
50
50
  }
51
51
 
52
52
  #validateResult(result) {
package/src/constants.js CHANGED
@@ -1,17 +1,31 @@
1
1
  // Import Third-party Dependencies
2
- import ansi from "ansi-styles";
2
+ import kleur from "kleur";
3
+ import isUnicodeSupported from "is-unicode-supported";
3
4
 
4
- const kPointer = `${ansi.gray.open}›${ansi.gray.close}`;
5
+ const kMainSymbols = {
6
+ tick: "✔",
7
+ cross: "✖",
8
+ pointer: "›",
9
+ previous: "⭡",
10
+ next: "⭣"
11
+ };
12
+ const kFallbackSymbols = {
13
+ tick: "√",
14
+ cross: "×",
15
+ pointer: ">",
16
+ previous: "↑",
17
+ next: "↓"
18
+ };
19
+ const kSymbols = isUnicodeSupported() ? kMainSymbols : kFallbackSymbols;
20
+ const kPointer = kleur.gray(kSymbols.pointer);
5
21
 
6
22
  export const SYMBOLS = {
7
- QuestionMark: `${ansi.blue.open}?${ansi.blue.close}`,
8
- Tick: `${ansi.green.open}✔${ansi.green.close}`,
9
- Cross: `${ansi.red.open}✖${ansi.red.close}`,
23
+ QuestionMark: kleur.blue().bold("?"),
24
+ Tick: kleur.green().bold(kSymbols.tick),
25
+ Cross: kleur.red().bold(kSymbols.cross),
10
26
  Pointer: kPointer,
11
- Active: `${ansi.reset.open}${kPointer}`,
12
- Inactive: `${ansi.gray.open}`,
13
- Previous: "⭡",
14
- Next: "⭣",
27
+ Previous: kSymbols.previous,
28
+ Next: kSymbols.next,
15
29
  ShowCursor: "\x1B[?25h",
16
30
  HideCursor: "\x1B[?25l"
17
31
  };
@@ -2,8 +2,7 @@
2
2
  import { EOL } from "node:os";
3
3
 
4
4
  // Import Third-party Dependencies
5
- import ansi from "ansi-styles";
6
- import stripAnsi from "strip-ansi";
5
+ import kleur from "kleur";
7
6
 
8
7
  // Import Internal Dependencies
9
8
  import { AbstractPrompt } from "./abstract-prompt.js";
@@ -13,12 +12,22 @@ export class QuestionPrompt extends AbstractPrompt {
13
12
  #validators;
14
13
 
15
14
  constructor(message, options = {}) {
16
- const { stdin = process.stdin, stdout = process.stdout, validators = [] } = options;
15
+ const {
16
+ stdin = process.stdin,
17
+ stdout = process.stdout,
18
+ defaultValue,
19
+ validators = []
20
+ } = options;
21
+
17
22
  super(message, stdin, stdout);
18
23
 
24
+ if (defaultValue && typeof defaultValue !== "string") {
25
+ throw new TypeError("defaultValue must be a string");
26
+ }
27
+
28
+ this.defaultValue = defaultValue;
29
+ this.tip = this.defaultValue ? ` (${this.defaultValue})` : "";
19
30
  this.#validators = validators;
20
- this.questionPrefix = `${ansi.bold.open}${SYMBOLS.QuestionMark} `;
21
- this.questionSuffix = `${ansi.bold.close} `;
22
31
  this.questionSuffixError = "";
23
32
  }
24
33
 
@@ -35,19 +44,19 @@ export class QuestionPrompt extends AbstractPrompt {
35
44
  }
36
45
 
37
46
  #getQuestionQuery() {
38
- return `${this.questionPrefix}${this.message}${this.questionSuffix}${this.questionSuffixError}`;
47
+ return `${kleur.bold(`${SYMBOLS.QuestionMark} ${this.message}${this.tip}`)} ${this.questionSuffixError}`;
39
48
  }
40
49
 
41
50
  #setQuestionSuffixError(error) {
42
- const suffix = `${ansi.red.open}[${error}]${ansi.red.close} `;
51
+ const suffix = kleur.red(`[${error}] `);
43
52
  this.questionSuffixError = suffix;
44
53
  }
45
54
 
46
55
  #writeAnswer() {
47
- const prefix = `${ansi.bold.open}${this.answer ? SYMBOLS.Tick : SYMBOLS.Cross}`;
48
- const suffix = `${ansi.yellow.close}${ansi.bold.close}${EOL}`;
56
+ const prefix = this.answer ? SYMBOLS.Tick : SYMBOLS.Cross;
57
+ const answer = kleur.yellow(this.answer ?? "");
49
58
 
50
- this.write(`${prefix} ${this.message} ${SYMBOLS.Pointer} ${ansi.yellow.open}${this.answer ?? ""}${suffix}`);
59
+ this.write(`${prefix} ${kleur.bold(this.message)} ${SYMBOLS.Pointer} ${answer}${EOL}`);
51
60
  }
52
61
 
53
62
  #onQuestionAnswer() {
@@ -69,6 +78,10 @@ export class QuestionPrompt extends AbstractPrompt {
69
78
  async question() {
70
79
  this.answer = await this.#question();
71
80
 
81
+ if (this.answer === "" && this.defaultValue) {
82
+ this.answer = this.defaultValue;
83
+ }
84
+
72
85
  this.#onQuestionAnswer();
73
86
 
74
87
  while (this.answer?.constructor.name === "Promise") {
@@ -2,7 +2,7 @@
2
2
  import { EOL } from "node:os";
3
3
 
4
4
  // Import Third-party Dependencies
5
- import ansi from "ansi-styles";
5
+ import kleur from "kleur";
6
6
 
7
7
  // Import Internal Dependencies
8
8
  import { AbstractPrompt } from "./abstract-prompt.js";
@@ -82,6 +82,7 @@ export class SelectPrompt extends AbstractPrompt {
82
82
 
83
83
  for (let choiceIndex = startIndex; choiceIndex < endIndex; choiceIndex++) {
84
84
  const choice = this.#getFormattedChoice(choiceIndex);
85
+ const isChoiceSelected = choiceIndex === this.activeIndex;
85
86
  const showPreviousChoicesArrow = startIndex > 0 && choiceIndex === startIndex;
86
87
  const showNextChoicesArrow = endIndex < this.choices.length && choiceIndex === endIndex - 1;
87
88
 
@@ -93,20 +94,21 @@ export class SelectPrompt extends AbstractPrompt {
93
94
  prefixArrow = SYMBOLS.Next;
94
95
  }
95
96
 
96
- const prefix = `${prefixArrow}${choiceIndex === this.activeIndex ? `${SYMBOLS.Active} ` : `${SYMBOLS.Inactive} `}`;
97
+ const prefix = `${prefixArrow}${isChoiceSelected ? `${SYMBOLS.Pointer} ` : " "}`;
97
98
  const formattedLabel = choice.label.padEnd(
98
99
  this.longestChoice < 10 ? this.longestChoice : 0
99
100
  );
100
101
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
101
- const str = `${prefix}${formattedLabel}${formattedDescription}${ansi.reset.open}${EOL}`;
102
+ const color = isChoiceSelected ? kleur.white().bold : kleur.gray;
103
+ const str = color(`${prefix}${formattedLabel}${formattedDescription}${EOL}`);
102
104
 
103
105
  this.write(str);
104
106
  }
105
107
  }
106
108
 
107
109
  #showAnsweredQuestion(choice) {
108
- const prefix = `${ansi.bold.open}${SYMBOLS.Tick} ${this.message} ${SYMBOLS.Pointer}`;
109
- const formattedChoice = `${ansi.yellow.open}${choice.label ?? choice}${ansi.reset.open}`;
110
+ const prefix = `${SYMBOLS.Tick} ${kleur.bold(this.message)} ${SYMBOLS.Pointer}`;
111
+ const formattedChoice = kleur.yellow(choice.label ?? choice);
110
112
 
111
113
  this.write(`${prefix} ${formattedChoice}${EOL}`);
112
114
  }
@@ -175,6 +177,6 @@ export class SelectPrompt extends AbstractPrompt {
175
177
  }
176
178
 
177
179
  #showQuestion() {
178
- this.write(`${ansi.bold.open}${SYMBOLS.QuestionMark} ${this.message}${ansi.bold.close}${EOL}`);
180
+ this.write(`${SYMBOLS.QuestionMark} ${kleur.bold(this.message)}${EOL}`);
179
181
  }
180
182
  }