Skip to content

Commit

Permalink
Feat (input): add option to allow skipping the transformer
Browse files Browse the repository at this point in the history
When the user presses the CTRL+Space combination, transformer is toggled
  • Loading branch information
matteosacchetto authored and SBoudrias committed Jan 27, 2024
1 parent 11bbb4b commit ae62463
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 2 deletions.
76 changes: 76 additions & 0 deletions packages/password/password.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,80 @@ describe('password prompt', () => {
events.keypress('enter');
await expect(answer).resolves.toEqual('12345678');
});

it('handle show password: false', async () => {
const { answer, events, getScreen } = await render(password, {
message: 'Enter your password',
mask: true,
allowShowPassword: false,
});

expect(getScreen()).toMatchInlineSnapshot('"? Enter your password"');

events.type('J');
expect(getScreen()).toMatchInlineSnapshot('"? Enter your password *"');

events.type('ohn');
expect(getScreen()).toMatchInlineSnapshot('"? Enter your password ****"');

events.keypress({
name: '`',
ctrl: true,
});
expect(getScreen()).toMatchInlineSnapshot('"? Enter your password ****"');

events.keypress('enter');
await expect(answer).resolves.toEqual('John');
expect(getScreen()).toMatchInlineSnapshot('"? Enter your password ****"');
});

it('handle show password: true', async () => {
const { answer, events, getScreen } = await render(password, {
message: 'Enter your password',
mask: true,
allowShowPassword: true,
});

expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password)"',
);

events.type('J');
expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password) *"',
);

events.type('ohn');
expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password) ****"',
);

events.keypress({
name: '`',
ctrl: true,
});
expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password) John"',
);

events.keypress({
name: '`',
ctrl: true,
});
expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password) ****"',
);

events.keypress({
name: '`',
ctrl: true,
});
expect(getScreen()).toMatchInlineSnapshot(
'"? Enter your password (CTRL+Space to show/hide the password) John"',
);

events.keypress('enter');
await expect(answer).resolves.toEqual('John');
expect(getScreen()).toMatchInlineSnapshot('"? Enter your password ****"');
});
});
23 changes: 21 additions & 2 deletions packages/password/src/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import ansiEscapes from 'ansi-escapes';
type PasswordConfig = PromptConfig<{
mask?: boolean | string;
validate?: (value: string) => boolean | string | Promise<string | boolean>;
allowShowPassword?: boolean;
}>;

export default createPrompt<string, PasswordConfig>((config, done) => {
const { validate = () => true } = config;
const { validate = () => true, allowShowPassword } = config;
const [status, setStatus] = useState<string>('pending');
const [errorMsg, setError] = useState<string | undefined>(undefined);
const [value, setValue] = useState<string>('');
const [isMasked, setIsMasked] = useState<boolean>(true);

const isLoading = status === 'loading';
const prefix = usePrefix(isLoading);
Expand All @@ -44,6 +46,12 @@ export default createPrompt<string, PasswordConfig>((config, done) => {
setError(isValid || 'You must provide a valid value');
setStatus('pending');
}
} else if (allowShowPassword && key.ctrl === true && key.name === '`') {
// CTRL + Space
// I only tried on Linux, but the combination on Linux was reported like that
// key.crtl = true
// key.name = '`'
setIsMasked(!isMasked);
} else {
setValue(rl.line);
setError(undefined);
Expand All @@ -60,6 +68,10 @@ export default createPrompt<string, PasswordConfig>((config, done) => {
formattedValue = `${chalk.dim('[input is masked]')}${ansiEscapes.cursorHide}`;
}

if (!isMasked && status !== 'done') {
formattedValue = value;
}

if (status === 'done') {
formattedValue = chalk.cyan(formattedValue);
}
Expand All @@ -69,5 +81,12 @@ export default createPrompt<string, PasswordConfig>((config, done) => {
error = chalk.red(`> ${errorMsg}`);
}

return [`${prefix} ${message} ${formattedValue}`, error];
return [
`${prefix} ${message}${
allowShowPassword && status !== 'done'
? chalk.dim(' (CTRL+Space to show/hide the password)')
: ''
} ${formattedValue}`,
error,
];
});

0 comments on commit ae62463

Please sign in to comment.