@topcli/prompts 0.0.1 → 0.0.2

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
@@ -45,17 +45,30 @@ const isAdult = await confirm('Are you over 18 ?', { initial: true })
45
45
 
46
46
  ## API
47
47
 
48
- ### `prompt(message: string): Promise<string>`
48
+ ### `prompt()`
49
+
50
+ ```ts
51
+ prompt(message: string): Promise<string>
52
+ ```
49
53
 
50
54
  Simple prompt, similar to `rl.question()` with an improved UI.
51
55
 
52
- ### `select(message: string, options: { choices: (Choice | string)[], maxVisible?: number }): Promise<string>`
56
+ ### `select()`
57
+
58
+ ```ts
59
+ select(message: string, options: { choices: (Choice | string)[], maxVisible?: number, ignoreValues?: (string | number | boolean)[] }): Promise<string>
60
+ ```
53
61
 
54
62
  Scrollable select depending `maxVisible` (default `8`).
63
+ Use `ignoreValues` to skip result render & clear lines after a selected one.
64
+
65
+ ### `confirm()`
55
66
 
56
- ### `confirm(message: string, options?: { initial: boolean }): Promise<string>`
67
+ ```ts
68
+ confirm(message: string, options?: { initial: boolean }): Promise<string>
69
+ ```
57
70
 
58
- Boolean prompt.
71
+ Boolean prompt, return `options.initial` if user input is different from "y"/"yes"/"n"/"no", (default `false`).
59
72
 
60
73
  ## Interfaces
61
74
 
package/index.d.ts CHANGED
@@ -4,5 +4,5 @@ export interface Choice {
4
4
  description?: string,
5
5
  }
6
6
  export function prompt(message: string): Promise<string>;
7
- export function select(message: string, options: { choices: (Choice | string)[], maxVisble?: number }): Promise<string>;
7
+ export function select(message: string, options: { choices: (Choice | string)[], maxVisble?: number, ignoreValues: (string | number | boolean)[] }): Promise<string>;
8
8
  export function confirm(message: string, options?: { initial: boolean }): Promise<string>;
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { createInterface } from 'node:readline/promises'
2
-
1
+ import { createInterface } from 'node:readline'
2
+ import { promisify } from 'node:util'
3
+ import { EOL } from 'node:os'
3
4
  import ansi from 'ansi-styles'
4
5
 
5
6
  const kQuestionMark = `${ansi.blue.open}?${ansi.blue.close}`
@@ -13,9 +14,9 @@ const kNext = '⭣'
13
14
  const kShowCursor = '\x1B[?25h'
14
15
  const kHideCursor = '\x1B[?25l'
15
16
 
16
- function clearLastLine () {
17
- process.stdout.moveCursor(0, -1)
18
- process.stdout.clearLine()
17
+ function clearLastLine (stdout = process.stdout) {
18
+ stdout.moveCursor(0, -1)
19
+ stdout.clearLine()
19
20
  }
20
21
 
21
22
  export async function prompt (message) {
@@ -26,7 +27,7 @@ export async function prompt (message) {
26
27
  const { stdin: input, stdout: output } = process
27
28
  const rl = createInterface({ input, output })
28
29
 
29
- const answer = await rl.question(`${ansi.bold.open} ${kPointer} ${message} ${ansi.bold.close}`)
30
+ const answer = await promisify(rl.question)(`${ansi.bold.open}${kQuestionMark} ${message}${ansi.bold.close} `)
30
31
 
31
32
  clearLastLine()
32
33
  console.log(`${ansi.bold.open}${answer ? kTick : kCross} ${message} ${kPointer} ${ansi.yellow.open}${answer}${ansi.yellow.close}${ansi.bold.close}`)
@@ -44,8 +45,7 @@ export async function select (message, options) {
44
45
  if (!options) {
45
46
  throw new TypeError('Missing required options')
46
47
  }
47
-
48
- const { choices } = options
48
+ const { choices, ignoreValues, stdout = process.stdout, stdin = process.stdin } = options
49
49
 
50
50
  if (!choices?.length) {
51
51
  throw new TypeError('Missing required param: choices')
@@ -67,13 +67,12 @@ export async function select (message, options) {
67
67
  return choice.label.length
68
68
  }))
69
69
 
70
- process.stdout.write(kHideCursor)
71
- const { stdin: input, stdout: output } = process
72
- const rl = createInterface({ input, output })
70
+ stdout.write(kHideCursor)
71
+ const rl = options.stdin && options.stdout ? null : createInterface({ input: stdin, output: stdout })
73
72
 
74
73
  let activeIndex = 0
75
74
 
76
- console.log(`${ansi.bold.open}${kQuestionMark} ${message}${ansi.bold.close}`)
75
+ stdout.write(`${ansi.bold.open}${kQuestionMark} ${message}${ansi.bold.close}${EOL}`)
77
76
 
78
77
  let lastRender = null
79
78
  const render = (initialRender = false, { reset } = {}) => {
@@ -94,14 +93,14 @@ export async function select (message, options) {
94
93
 
95
94
  if (!initialRender) {
96
95
  const linesToClear = lastRender.endIndex - lastRender.startIndex
97
- process.stdout.clearLine(1)
98
- process.stdout.moveCursor(0, -linesToClear)
99
- process.stdout.clearLine(1)
96
+ stdout.moveCursor(0, -linesToClear)
97
+ stdout.clearScreenDown()
100
98
  }
101
99
 
102
100
  if (reset) {
103
- clearLastLine()
104
- clearLastLine()
101
+ clearLastLine(stdout)
102
+ clearLastLine(stdout)
103
+
105
104
  return
106
105
  }
107
106
 
@@ -110,8 +109,8 @@ export async function select (message, options) {
110
109
  for (let i = startIndex; i < endIndex; i++) {
111
110
  const choice = typeof choices[i] === 'string' ? { value: choices[i], label: choices[i] } : choices[i]
112
111
  const prefix = `${startIndex > 0 && i === startIndex ? kPrevious : endIndex < choices.length && i === endIndex - 1 ? kNext : ' '}${i === activeIndex ? kActive : kInactive}`
113
- const str = `${prefix}${choice.label.padEnd(longestChoice < 10 ? longestChoice : 0)}${choice.description ? ` - ${choice.description}` : ''}${ansi.reset.open}`
114
- console.log(str)
112
+ const str = `${prefix}${choice.label.padEnd(longestChoice < 10 ? longestChoice : 0)}${choice.description ? ` - ${choice.description}` : ''}${ansi.reset.open}${EOL}`
113
+ stdout.write(str)
115
114
  }
116
115
  }
117
116
 
@@ -126,19 +125,23 @@ export async function select (message, options) {
126
125
  activeIndex = activeIndex === choices.length - 1 ? 0 : activeIndex + 1
127
126
  render()
128
127
  } else if (key.name === 'return') {
129
- process.stdin.off('keypress', onKeypress)
128
+ stdin.off('keypress', onKeypress)
129
+
130
130
  render(false, { reset: true })
131
131
 
132
- console.log(`${ansi.bold.open}${kTick} ${message} ${kPointer} ${ansi.yellow.open}${choices[activeIndex].value}${ansi.reset.open}`)
132
+ const value = choices[activeIndex].value ?? choices[activeIndex]
133
+ if (!ignoreValues?.includes(value)) {
134
+ stdout.write(`${ansi.bold.open}${kTick} ${message} ${kPointer} ${ansi.yellow.open}${choices[activeIndex].label ?? choices[activeIndex]}${ansi.reset.open}${EOL}`)
135
+ }
133
136
 
134
- process.stderr.write(kShowCursor)
135
- rl.close()
137
+ stdout.write(kShowCursor)
138
+ rl?.close()
136
139
 
137
- resolve(choices[activeIndex].value)
140
+ resolve(value)
138
141
  }
139
142
  }
140
143
 
141
- process.stdin.on('keypress', onKeypress)
144
+ stdin.on('keypress', onKeypress)
142
145
  })
143
146
  }
144
147
 
@@ -156,7 +159,7 @@ export async function confirm (message, options = kDefaultConfirmOptions) {
156
159
 
157
160
  const tip = initial ? `${ansi.bold.open}Yes${ansi.bold.close}/no` : `yes/${ansi.bold.open}No${ansi.bold.close}`
158
161
  const answer = await rl.question(`${kQuestionMark} ${message} ${ansi.grey.open}(${tip})${ansi.grey.close} ${kPointer} `)
159
- const result = (!answer && initial) || ['y', 'yes'].includes(answer.toLocaleLowerCase())
162
+ const result = answer ? ['y', 'yes'].includes(answer.toLocaleLowerCase()) : initial
160
163
 
161
164
  clearLastLine()
162
165
  console.log(`${result ? kTick : kCross} ${message}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topcli/prompts",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Node.js user input library for command-line interfaces.",
5
5
  "scripts": {
6
6
  "test": "node --test ./test/**.test.js",
@@ -21,7 +21,8 @@
21
21
  "type": "module",
22
22
  "devDependencies": {
23
23
  "snazzy": "^9.0.0",
24
- "standard": "^17.0.0"
24
+ "standard": "^17.0.0",
25
+ "strip-ansi": "^7.0.1"
25
26
  },
26
27
  "dependencies": {
27
28
  "ansi-styles": "^6.2.1"
@@ -32,8 +33,5 @@
32
33
  "bugs": {
33
34
  "url": "https://github.com/TopCli/prompts/issues"
34
35
  },
35
- "homepage": "https://github.com/TopCli/prompts#readme",
36
- "publishConfig": {
37
- "access": "public"
38
- }
36
+ "homepage": "https://github.com/TopCli/prompts#readme"
39
37
  }