···22export { default as GroupMultiSelectPrompt } from './prompts/group-multiselect';
33export { default as MultiSelectPrompt } from './prompts/multi-select';
44export { default as PasswordPrompt } from './prompts/password';
55-export { default as Prompt, isCancel, type State } from './prompts/prompt';
55+export { default as Prompt } from './prompts/prompt';
66export { default as SelectPrompt } from './prompts/select';
77export { default as SelectKeyPrompt } from './prompts/select-key';
88export { default as TextPrompt } from './prompts/text';
99-export { block, setGlobalAliases } from './utils';
99+export type { ClackState as State } from './types';
1010+export { block, isCancel, setGlobalAliases } from './utils';
1111+
+18-64
packages/core/src/prompts/prompt.ts
···11-import type { Key, ReadLine } from 'node:readline';
22-31import { stdin, stdout } from 'node:process';
44-import readline from 'node:readline';
22+import readline, { type Key, type ReadLine } from 'node:readline';
53import { Readable, Writable } from 'node:stream';
64import { WriteStream } from 'node:tty';
75import { cursor, erase } from 'sisteransi';
86import wrap from 'wrap-ansi';
971010-import { type InferSetType, aliases, keys, hasAliasKey } from '../utils';
88+import { ALIASES, CANCEL_SYMBOL, diffLines, hasAliasKey, KEYS, setRawMode } from '../utils';
1191212-function diffLines(a: string, b: string) {
1313- if (a === b) return;
1414-1515- const aLines = a.split('\n');
1616- const bLines = b.split('\n');
1717- const diff: number[] = [];
1818-1919- for (let i = 0; i < Math.max(aLines.length, bLines.length); i++) {
2020- if (aLines[i] !== bLines[i]) diff.push(i);
2121- }
2222-2323- return diff;
2424-}
2525-2626-const cancel = Symbol('clack:cancel');
2727-export function isCancel(value: unknown): value is symbol {
2828- return value === cancel;
2929-}
3030-3131-function setRawMode(input: Readable, value: boolean) {
3232- if ((input as typeof stdin).isTTY) (input as typeof stdin).setRawMode(value);
3333-}
1010+import type { ClackEvents, ClackState, InferSetType } from '../types';
34113512export interface PromptOptions<Self extends Prompt> {
3613 render(this: Omit<Self, 'prompt'>): string | void;
···4219 debug?: boolean;
4320}
44214545-export type State = 'initial' | 'active' | 'cancel' | 'submit' | 'error';
4646-4747-/**
4848- * Typed event emitter for clack
4949- */
5050-interface ClackHooks {
5151- 'initial': (value?: any) => void;
5252- 'active': (value?: any) => void;
5353- 'cancel': (value?: any) => void;
5454- 'submit': (value?: any) => void;
5555- 'error': (value?: any) => void;
5656- 'cursor': (key?: InferSetType<typeof keys>) => void;
5757- 'key': (key?: string) => void;
5858- 'value': (value?: string) => void;
5959- 'confirm': (value?: boolean) => void;
6060- 'finalize': () => void;
6161-}
6262-6322export default class Prompt {
6423 protected input: Readable;
6524 protected output: Writable;
···7231 private _subscribers = new Map<string, { cb: (...args: any) => any; once?: boolean }[]>();
7332 protected _cursor = 0;
74337575- public state: State = 'initial';
3434+ public state: ClackState = 'initial';
7635 public error = '';
7736 public value: any;
78377979- constructor(
8080- options: PromptOptions<Prompt>,
8181- trackValue: boolean = true
8282- ) {
8383- const {
8484- input = stdin,
8585- output = stdout,
8686- render,
8787- ...opts
8888- } = options;
3838+ constructor(options: PromptOptions<Prompt>, trackValue: boolean = true) {
3939+ const { input = stdin, output = stdout, render, ...opts } = options;
89409041 this.opts = opts;
9142 this.onKeypress = this.onKeypress.bind(this);
···10960 * Set a subscriber with opts
11061 * @param event - The event name
11162 */
112112- private setSubscriber<T extends keyof ClackHooks>(event: T, opts: { cb: ClackHooks[T]; once?: boolean }) {
6363+ private setSubscriber<T extends keyof ClackEvents>(
6464+ event: T,
6565+ opts: { cb: ClackEvents[T]; once?: boolean }
6666+ ) {
11367 const params = this._subscribers.get(event) ?? [];
11468 params.push(opts);
11569 this._subscribers.set(event, params);
···12074 * @param event - The event name
12175 * @param cb - The callback
12276 */
123123- public on<T extends keyof ClackHooks>(event: T, cb: ClackHooks[T]) {
7777+ public on<T extends keyof ClackEvents>(event: T, cb: ClackEvents[T]) {
12478 this.setSubscriber(event, { cb });
12579 }
12680···12983 * @param event - The event name
13084 * @param cb - The callback
13185 */
132132- public once<T extends keyof ClackHooks>(event: T, cb: ClackHooks[T]) {
8686+ public once<T extends keyof ClackEvents>(event: T, cb: ClackEvents[T]) {
13387 this.setSubscriber(event, { cb, once: true });
13488 }
13589···13892 * @param event - The event name
13993 * @param data - The data to pass to the callback
14094 */
141141- public emit<T extends keyof ClackHooks>(event: T, ...data: Parameters<ClackHooks[T]>) {
9595+ public emit<T extends keyof ClackEvents>(event: T, ...data: Parameters<ClackEvents[T]>) {
14296 const cbs = this._subscribers.get(event) ?? [];
14397 const cleanup: (() => void)[] = [];
14498···197151 this.output.write(cursor.show);
198152 this.output.off('resize', this.render);
199153 setRawMode(this.input, false);
200200- resolve(cancel);
154154+ resolve(CANCEL_SYMBOL);
201155 });
202156 });
203157 }
···206160 if (this.state === 'error') {
207161 this.state = 'active';
208162 }
209209- if (key?.name && !this._track && aliases.has(key.name)) {
210210- this.emit('cursor', aliases.get(key.name));
163163+ if (key?.name && !this._track && ALIASES.has(key.name)) {
164164+ this.emit('cursor', ALIASES.get(key.name));
211165 }
212212- if (key?.name && keys.has(key.name as InferSetType<typeof keys>)) {
213213- this.emit('cursor', key.name as InferSetType<typeof keys>);
166166+ if (key?.name && KEYS.has(key.name as InferSetType<typeof KEYS>)) {
167167+ this.emit('cursor', key.name as InferSetType<typeof KEYS>);
214168 }
215169 if (char && (char.toLowerCase() === 'y' || char.toLowerCase() === 'n')) {
216170 this.emit('confirm', char.toLowerCase() === 'y');
···11-22-export type InferSetType<T> = T extends Set<infer U> ? U : never;
11+import type { InferSetType } from '../types';
3243const DEFAULT_KEYS = ['up', 'down', 'left', 'right', 'space', 'enter', 'cancel'] as const;
55-export const keys = new Set(DEFAULT_KEYS);
44+export const KEYS = new Set(DEFAULT_KEYS);
6577-export const aliases = new Map<string, InferSetType<typeof keys>>([
66+export const ALIASES = new Map<string, InferSetType<typeof KEYS>>([
87 ['k', 'up'],
98 ['j', 'down'],
109 ['h', 'left'],
···1918 * @default
2019 * new Map([['k', 'up'], ['j', 'down'], ['h', 'left'], ['l', 'right'], ['\x03', 'cancel'],])
2120 */
2222-export function setGlobalAliases(alias: Array<[string, InferSetType<typeof keys>]>) {
2121+export function setGlobalAliases(alias: Array<[string, InferSetType<typeof KEYS>]>) {
2322 for (const [newAlias, key] of alias) {
2424- if (!aliases.has(newAlias)) {
2525- aliases.set(newAlias, key);
2323+ if (!ALIASES.has(newAlias)) {
2424+ ALIASES.set(newAlias, key);
2625 }
2726 }
2827}
···3332 * @param type - The type of key to check for
3433 * @returns boolean
3534 */
3636-export function hasAliasKey(key: string | Array<string | undefined>, type: InferSetType<typeof keys>) {
3535+export function hasAliasKey(
3636+ key: string | Array<string | undefined>,
3737+ type: InferSetType<typeof KEYS>
3838+) {
3739 if (typeof key === 'string') {
3838- return aliases.has(key) && aliases.get(key) === type;
4040+ return ALIASES.has(key) && ALIASES.get(key) === type;
3941 }
40424141- return key.map((n) => {
4242- if (n !== undefined && aliases.has(n) && aliases.get(n) === type) return true;
4343- return false;
4444- }).includes(true);
4343+ return key
4444+ .map((n) => {
4545+ if (n !== undefined && ALIASES.has(n) && ALIASES.get(n) === type) return true;
4646+ return false;
4747+ })
4848+ .includes(true);
4549}
+17-4
packages/core/src/utils/index.ts
···11+import { stdin, stdout } from 'node:process';
12import type { Key } from 'node:readline';
22-33-import { stdin, stdout } from 'node:process';
43import * as readline from 'node:readline';
44+import type { Readable } from 'node:stream';
55import { cursor } from 'sisteransi';
66import { hasAliasKey } from './aliases';
7788const isWindows = globalThis.process.platform.startsWith('win');
99+1010+export * from './aliases';
1111+export * from './string';
1212+1313+export const CANCEL_SYMBOL = Symbol('clack:cancel');
1414+1515+export function isCancel(value: unknown): value is symbol {
1616+ return value === CANCEL_SYMBOL;
1717+}
1818+1919+export function setRawMode(input: Readable, value: boolean) {
2020+ const i = input as typeof stdin;
2121+2222+ if (i.isTTY) i.setRawMode(value);
2323+}
9241025export function block({
1126 input = stdin,
···5469 rl.close();
5570 };
5671}
5757-5858-export * from './aliases';
+13
packages/core/src/utils/string.ts
···11+export function diffLines(a: string, b: string) {
22+ if (a === b) return;
33+44+ const aLines = a.split('\n');
55+ const bLines = b.split('\n');
66+ const diff: number[] = [];
77+88+ for (let i = 0; i < Math.max(aLines.length, bLines.length); i++) {
99+ if (aLines[i] !== bLines[i]) diff.push(i);
1010+ }
1111+1212+ return diff;
1313+}