-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
1,805 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#!/usr/bin/env node | ||
|
||
require('../dist/cli'); | ||
import('../dist/cli.js'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# @clack/core and @clack/prompt | ||
|
||
Forked from https://github.com/sveltejs/cli . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export { default as ConfirmPrompt } from './src/prompts/confirm.js'; | ||
export { default as GroupMultiSelectPrompt } from './src/prompts/group-multiselect.js'; | ||
export { default as MultiSelectPrompt } from './src/prompts/multi-select.js'; | ||
export { default as PasswordPrompt } from './src/prompts/password.js'; | ||
export { default as Prompt, isCancel } from './src/prompts/prompt.js'; | ||
export type { State } from './src/prompts/prompt.js'; | ||
export { default as SelectPrompt } from './src/prompts/select.js'; | ||
export { default as SelectKeyPrompt } from './src/prompts/select-key.js'; | ||
export { default as TextPrompt } from './src/prompts/text.js'; | ||
export { block } from './src/utils.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { cursor } from 'sisteransi'; | ||
import Prompt, { type PromptOptions } from './prompt.js'; | ||
|
||
interface ConfirmOptions extends PromptOptions<ConfirmPrompt> { | ||
active: string; | ||
inactive: string; | ||
initialValue?: boolean; | ||
} | ||
export default class ConfirmPrompt extends Prompt { | ||
get cursor(): 0 | 1 { | ||
return this.value ? 0 : 1; | ||
} | ||
|
||
private get _value() { | ||
return this.cursor === 0; | ||
} | ||
|
||
constructor(opts: ConfirmOptions) { | ||
super(opts, false); | ||
this.value = opts.initialValue ? true : false; | ||
|
||
this.on('value', () => { | ||
this.value = this._value; | ||
}); | ||
|
||
this.on('confirm', (confirm) => { | ||
this.output.write(cursor.move(0, -1)); | ||
this.value = confirm; | ||
this.state = 'submit'; | ||
this.close(); | ||
}); | ||
|
||
this.on('cursor', () => { | ||
this.value = !this.value; | ||
}); | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
create-tnf/src/clack/core/src/prompts/group-multiselect.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import Prompt, { type PromptOptions } from './prompt.js'; | ||
|
||
interface GroupMultiSelectOptions<T extends { value: any }> | ||
extends PromptOptions<GroupMultiSelectPrompt<T>> { | ||
options: Record<string, T[]>; | ||
initialValues?: Array<T['value']>; | ||
required?: boolean; | ||
cursorAt?: T['value']; | ||
selectableGroups?: boolean; | ||
} | ||
export default class GroupMultiSelectPrompt< | ||
T extends { value: any }, | ||
> extends Prompt { | ||
options: Array<T & { group: string | boolean }>; | ||
cursor: number = 0; | ||
#selectableGroups: boolean; | ||
|
||
getGroupItems(group: string): T[] { | ||
return this.options.filter((o) => o.group === group); | ||
} | ||
|
||
isGroupSelected(group: string): boolean { | ||
const items = this.getGroupItems(group); | ||
return ( | ||
this.#selectableGroups && items.every((i) => this.value.includes(i.value)) | ||
); | ||
} | ||
|
||
private toggleValue() { | ||
const item = this.options[this.cursor]!; | ||
if (item.group === true) { | ||
const group = item.value; | ||
const groupedItems = this.getGroupItems(group); | ||
if (this.isGroupSelected(group)) { | ||
this.value = this.value.filter( | ||
(v: string) => groupedItems.findIndex((i) => i.value === v) === -1, | ||
); | ||
} else { | ||
this.value = [...this.value, ...groupedItems.map((i) => i.value)]; | ||
} | ||
this.value = Array.from(new Set(this.value)); | ||
} else { | ||
const selected = this.value.includes(item.value); | ||
this.value = selected | ||
? this.value.filter((v: T['value']) => v !== item.value) | ||
: [...this.value, item.value]; | ||
} | ||
} | ||
|
||
constructor(opts: GroupMultiSelectOptions<T>) { | ||
super(opts, false); | ||
const { options } = opts; | ||
this.#selectableGroups = opts.selectableGroups ?? true; | ||
this.options = Object.entries(options).flatMap(([key, option]) => [ | ||
{ value: key, group: true, label: key }, | ||
...option.map((opt) => ({ ...opt, group: key })), | ||
]) as any; | ||
this.value = [...(opts.initialValues ?? [])]; | ||
this.cursor = Math.max( | ||
this.options.findIndex(({ value }) => value === opts.cursorAt), | ||
this.#selectableGroups ? 0 : 1, | ||
); | ||
|
||
this.on('cursor', (key) => { | ||
switch (key) { | ||
case 'left': | ||
case 'up': | ||
this.cursor = | ||
this.cursor === 0 ? this.options.length - 1 : this.cursor - 1; | ||
if ( | ||
!this.#selectableGroups && | ||
this.options[this.cursor]!.group === true | ||
) { | ||
this.cursor = | ||
this.cursor === 0 ? this.options.length - 1 : this.cursor - 1; | ||
} | ||
break; | ||
case 'down': | ||
case 'right': | ||
this.cursor = | ||
this.cursor === this.options.length - 1 ? 0 : this.cursor + 1; | ||
if ( | ||
!this.#selectableGroups && | ||
this.options[this.cursor]!.group === true | ||
) { | ||
this.cursor = | ||
this.cursor === this.options.length - 1 ? 0 : this.cursor + 1; | ||
} | ||
break; | ||
case 'space': | ||
this.toggleValue(); | ||
break; | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import Prompt, { type PromptOptions } from './prompt.js'; | ||
|
||
interface MultiSelectOptions<T extends { value: any }> | ||
extends PromptOptions<MultiSelectPrompt<T>> { | ||
options: T[]; | ||
initialValues?: Array<T['value']>; | ||
required?: boolean; | ||
cursorAt?: T['value']; | ||
} | ||
export default class MultiSelectPrompt< | ||
T extends { value: any }, | ||
> extends Prompt { | ||
options: T[]; | ||
cursor: number = 0; | ||
|
||
private get _value() { | ||
return this.options[this.cursor]!.value; | ||
} | ||
|
||
private toggleAll() { | ||
const allSelected = this.value.length === this.options.length; | ||
this.value = allSelected ? [] : this.options.map((v) => v.value); | ||
} | ||
|
||
private toggleValue() { | ||
const selected = this.value.includes(this._value); | ||
this.value = selected | ||
? this.value.filter((value: T['value']) => value !== this._value) | ||
: [...this.value, this._value]; | ||
} | ||
|
||
constructor(opts: MultiSelectOptions<T>) { | ||
super(opts, false); | ||
|
||
this.options = opts.options; | ||
this.value = [...(opts.initialValues ?? [])]; | ||
this.cursor = Math.max( | ||
this.options.findIndex(({ value }) => value === opts.cursorAt), | ||
0, | ||
); | ||
this.on('key', (char) => { | ||
if (char === 'a') { | ||
this.toggleAll(); | ||
} | ||
}); | ||
|
||
this.on('cursor', (key) => { | ||
switch (key) { | ||
case 'left': | ||
case 'up': | ||
this.cursor = | ||
this.cursor === 0 ? this.options.length - 1 : this.cursor - 1; | ||
break; | ||
case 'down': | ||
case 'right': | ||
this.cursor = | ||
this.cursor === this.options.length - 1 ? 0 : this.cursor + 1; | ||
break; | ||
case 'space': | ||
this.toggleValue(); | ||
break; | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import color from 'picocolors'; | ||
import Prompt, { type PromptOptions } from './prompt.js'; | ||
|
||
interface PasswordOptions extends PromptOptions<PasswordPrompt> { | ||
mask?: string; | ||
} | ||
export default class PasswordPrompt extends Prompt { | ||
valueWithCursor = ''; | ||
private _mask = '•'; | ||
get cursor(): number { | ||
return this._cursor; | ||
} | ||
get masked(): string { | ||
return this.value.replaceAll(/./g, this._mask); | ||
} | ||
constructor({ mask, ...opts }: PasswordOptions) { | ||
super(opts); | ||
this._mask = mask ?? '•'; | ||
|
||
this.on('finalize', () => { | ||
this.valueWithCursor = this.masked; | ||
}); | ||
this.on('value', () => { | ||
if (this.cursor >= this.value.length) { | ||
this.valueWithCursor = `${this.masked}${color.inverse(color.hidden('_'))}`; | ||
} else { | ||
const s1 = this.masked.slice(0, this.cursor); | ||
const s2 = this.masked.slice(this.cursor); | ||
this.valueWithCursor = `${s1}${color.inverse(s2[0])}${s2.slice(1)}`; | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.