Skip to content

Commit 372b526

Browse files
authored
feat: add clear to spinner (#433)
1 parent 4d50be6 commit 372b526

File tree

5 files changed

+59
-5
lines changed

5 files changed

+59
-5
lines changed

.changeset/loose-days-hug.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@clack/prompts": patch
3+
---
4+
5+
Add `clear` method to spinner for stopping and clearing.

packages/prompts/src/progress-bar.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function progress({
6565
stop: spin.stop,
6666
cancel: spin.cancel,
6767
error: spin.error,
68+
clear: spin.clear,
6869
advance,
6970
isCancelled: spin.isCancelled,
7071
message: (msg: string) => advance(0, msg),

packages/prompts/src/spinner.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface SpinnerResult {
2828
cancel(msg?: string): void;
2929
error(msg?: string): void;
3030
message(msg?: string): void;
31+
clear(): void;
3132
readonly isCancelled: boolean;
3233
}
3334

@@ -165,7 +166,7 @@ export const spinner = ({
165166
}, delay);
166167
};
167168

168-
const _stop = (msg = '', code = 0): void => {
169+
const _stop = (msg = '', code = 0, silent: boolean = false): void => {
169170
if (!isSpinnerActive) return;
170171
isSpinnerActive = false;
171172
clearInterval(loop);
@@ -177,10 +178,12 @@ export const spinner = ({
177178
? color.red(S_STEP_CANCEL)
178179
: color.red(S_STEP_ERROR);
179180
_message = msg ?? _message;
180-
if (indicator === 'timer') {
181-
output.write(`${step} ${_message} ${formatTimer(_origin)}\n`);
182-
} else {
183-
output.write(`${step} ${_message}\n`);
181+
if (!silent) {
182+
if (indicator === 'timer') {
183+
output.write(`${step} ${_message} ${formatTimer(_origin)}\n`);
184+
} else {
185+
output.write(`${step} ${_message}\n`);
186+
}
184187
}
185188
clearHooks();
186189
unblock();
@@ -189,6 +192,10 @@ export const spinner = ({
189192
const stop = (msg = ''): void => _stop(msg, 0);
190193
const cancel = (msg = ''): void => _stop(msg, 1);
191194
const error = (msg = ''): void => _stop(msg, 2);
195+
// TODO (43081j): this will leave the initial S_BAR since we purposely
196+
// don't erase that in `clearPrevMessage`. In future, we may want to treat
197+
// `clear` as a special case and remove the bar too.
198+
const clear = (): void => _stop('', 0, true);
192199

193200
const message = (msg = ''): void => {
194201
_message = removeTrailingDots(msg ?? _message);
@@ -200,6 +207,7 @@ export const spinner = ({
200207
message,
201208
cancel,
202209
error,
210+
clear,
203211
get isCancelled() {
204212
return isCancelled;
205213
},

packages/prompts/test/__snapshots__/spinner.test.ts.snap

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ exports[`spinner (isCI = false) > can be aborted by a signal 1`] = `
1111
]
1212
`;
1313
14+
exports[`spinner (isCI = false) > clear > stops and clears the spinner from the output 1`] = `
15+
[
16+
"<cursor.hide>",
17+
"│
18+
",
19+
"◒ Loading",
20+
"<cursor.left count=1>",
21+
"<erase.down>",
22+
"<cursor.show>",
23+
]
24+
`;
25+
1426
exports[`spinner (isCI = false) > indicator customization > custom delay 1`] = `
1527
[
1628
"<cursor.hide>",
@@ -570,6 +582,20 @@ exports[`spinner (isCI = true) > can be aborted by a signal 1`] = `
570582
]
571583
`;
572584
585+
exports[`spinner (isCI = true) > clear > stops and clears the spinner from the output 1`] = `
586+
[
587+
"<cursor.hide>",
588+
"│
589+
",
590+
"◒ Loading...",
591+
"
592+
",
593+
"<cursor.left count=1>",
594+
"<erase.down>",
595+
"<cursor.show>",
596+
]
597+
`;
598+
573599
exports[`spinner (isCI = true) > indicator customization > custom delay 1`] = `
574600
[
575601
"<cursor.hide>",

packages/prompts/test/spinner.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,4 +425,18 @@ describe.each(['true', 'false'])('spinner (isCI = %s)', (isCI) => {
425425

426426
expect(output.buffer).toMatchSnapshot();
427427
});
428+
429+
describe('clear', () => {
430+
test('stops and clears the spinner from the output', () => {
431+
const result = prompts.spinner({ output });
432+
433+
result.start('Loading');
434+
435+
vi.advanceTimersByTime(80);
436+
437+
result.clear();
438+
439+
expect(output.buffer).toMatchSnapshot();
440+
});
441+
});
428442
});

0 commit comments

Comments
 (0)