diff --git a/.changeset/empty-bananas-melt.md b/.changeset/empty-bananas-melt.md new file mode 100644 index 00000000..c1543962 --- /dev/null +++ b/.changeset/empty-bananas-melt.md @@ -0,0 +1,6 @@ +--- +"@clack/prompts": patch +"@clack/core": patch +--- + +Rework the spinner prompt to use the `Prompt` base class for rendering. diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 7299d075..66752310 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -14,6 +14,8 @@ export type { SelectOptions } from './prompts/select.js'; export { default as SelectPrompt } from './prompts/select.js'; export type { SelectKeyOptions } from './prompts/select-key.js'; export { default as SelectKeyPrompt } from './prompts/select-key.js'; +export type { SpinnerOptions } from './prompts/spinner.js'; +export { default as SpinnerPrompt } from './prompts/spinner.js'; export type { TextOptions } from './prompts/text.js'; export { default as TextPrompt } from './prompts/text.js'; export type { ClackState as State } from './types.js'; diff --git a/packages/core/src/prompts/prompt.ts b/packages/core/src/prompts/prompt.ts index b30deb02..7c54c4b4 100644 --- a/packages/core/src/prompts/prompt.ts +++ b/packages/core/src/prompts/prompt.ts @@ -270,7 +270,7 @@ export default class Prompt { this.output.write(cursor.move(-999, lines * -1)); } - private render() { + protected render() { const frame = wrapAnsi(this._render(this) ?? '', process.stdout.columns, { hard: true, trim: false, diff --git a/packages/core/src/prompts/spinner.ts b/packages/core/src/prompts/spinner.ts new file mode 100644 index 00000000..38880dd3 --- /dev/null +++ b/packages/core/src/prompts/spinner.ts @@ -0,0 +1,183 @@ +import { settings } from '../utils/index.js'; +import Prompt, { type PromptOptions } from './prompt.js'; + +const removeTrailingDots = (msg: string): string => { + return msg.replace(/\.+$/, ''); +}; + +export interface SpinnerOptions extends PromptOptions { + indicator?: 'dots' | 'timer'; + onCancel?: () => void; + cancelMessage?: string; + errorMessage?: string; + frames: string[]; + delay: number; + styleFrame?: (frame: string) => string; +} + +export default class SpinnerPrompt extends Prompt { + #isCancelled = false; + #isActive = false; + #startTime: number = 0; + #frameIndex: number = 0; + #indicatorTimer: number = 0; + #intervalId: ReturnType | undefined; + #delay: number; + #frames: string[]; + #cancelMessage: string; + #errorMessage: string; + #onCancel?: () => void; + #message: string = ''; + #silentExit: boolean = false; + #exitCode: number = 0; + + constructor(opts: SpinnerOptions) { + super(opts); + this.#delay = opts.delay; + this.#frames = opts.frames; + this.#cancelMessage = opts.cancelMessage ?? settings.messages.cancel; + this.#errorMessage = opts.errorMessage ?? settings.messages.error; + this.#onCancel = opts.onCancel; + + this.on('cancel', () => this.#onExit(1)); + } + + start(msg?: string): void { + if (this.#isActive) { + this.#reset(); + } + this.#isActive = true; + this.#message = removeTrailingDots(msg ?? ''); + this.#startTime = performance.now(); + this.#frameIndex = 0; + this.#indicatorTimer = 0; + + if (Number.isFinite(this.#delay)) { + this.#intervalId = setInterval(() => this.#onInterval(), this.#delay); + } else { + this.render(); + } + + this.#addGlobalListeners(); + } + + stop(msg?: string, exitCode?: number, silent?: boolean): void { + if (!this.#isActive) { + return; + } + + this.#reset(); + this.#silentExit = silent === true; + this.#exitCode = exitCode ?? 0; + + if (msg !== undefined) { + this.#message = msg; + } + + this.state = 'cancel'; + this.render(); + this.close(); + } + + get isCancelled(): boolean { + return this.#isCancelled; + } + + get message(): string { + return this.#message; + } + + set message(msg: string) { + this.#message = removeTrailingDots(msg); + } + + get exitCode(): number | undefined { + return this.#exitCode; + } + + get frameIndex(): number { + return this.#frameIndex; + } + + get indicatorTimer(): number { + return this.#indicatorTimer; + } + + get isActive(): boolean { + return this.#isActive; + } + + get silentExit(): boolean { + return this.#silentExit; + } + + getFormattedTimer(): string { + const duration = (performance.now() - this.#startTime) / 1000; + const min = Math.floor(duration / 60); + const secs = Math.floor(duration % 60); + return min > 0 ? `[${min}m ${secs}s]` : `[${secs}s]`; + } + + #reset(): void { + this.#isActive = false; + this.#exitCode = 0; + + if (this.#intervalId) { + clearInterval(this.#intervalId); + this.#intervalId = undefined; + } + + this.#removeGlobalListeners(); + } + + #onInterval(): void { + this.render(); + + this.#frameIndex = this.#frameIndex + 1 < this.#frames.length ? this.#frameIndex + 1 : 0; + // indicator increase by 1 every 8 frames + this.#indicatorTimer = this.#indicatorTimer < 4 ? this.#indicatorTimer + 0.125 : 0; + } + + #onProcessError: () => void = () => { + this.#onExit(2); + }; + + #onProcessSignal: () => void = () => { + this.#onExit(1); + }; + + #onExit: (exitCode: number) => void = (exitCode) => { + this.#exitCode = exitCode; + if (exitCode > 1) { + this.#message = this.#errorMessage; + } else { + this.#message = this.#cancelMessage; + } + this.#isCancelled = exitCode === 1; + if (this.#isActive) { + this.stop(this.#message, exitCode); + if (this.#isCancelled && this.#onCancel) { + this.#onCancel(); + } + } + }; + + #addGlobalListeners(): void { + // Reference: https://nodejs.org/api/process.html#event-uncaughtexception + process.on('uncaughtExceptionMonitor', this.#onProcessError); + // Reference: https://nodejs.org/api/process.html#event-unhandledrejection + process.on('unhandledRejection', this.#onProcessError); + // Reference Signal Events: https://nodejs.org/api/process.html#signal-events + process.on('SIGINT', this.#onProcessSignal); + process.on('SIGTERM', this.#onProcessSignal); + process.on('exit', this.#onExit); + } + + #removeGlobalListeners(): void { + process.removeListener('uncaughtExceptionMonitor', this.#onProcessError); + process.removeListener('unhandledRejection', this.#onProcessError); + process.removeListener('SIGINT', this.#onProcessSignal); + process.removeListener('SIGTERM', this.#onProcessSignal); + process.removeListener('exit', this.#onExit); + } +} diff --git a/packages/core/test/prompts/spinner.test.ts b/packages/core/test/prompts/spinner.test.ts new file mode 100644 index 00000000..b49ed929 --- /dev/null +++ b/packages/core/test/prompts/spinner.test.ts @@ -0,0 +1,151 @@ +import { cursor } from 'sisteransi'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import { default as SpinnerPrompt } from '../../src/prompts/spinner.js'; +import { MockReadable } from '../mock-readable.js'; +import { MockWritable } from '../mock-writable.js'; + +describe('SpinnerPrompt', () => { + let input: MockReadable; + let output: MockWritable; + let instance: SpinnerPrompt; + + beforeEach(() => { + input = new MockReadable(); + output = new MockWritable(); + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + vi.restoreAllMocks(); + instance.stop(); + }); + + test('renders render() result', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.prompt(); + expect(output.buffer).to.deep.equal([cursor.hide, 'foo']); + }); + + describe('start', () => { + test('starts the spinner and updates frames', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.start('Loading'); + expect(instance.message).to.equal('Loading'); + expect(instance.frameIndex).to.equal(0); + expect(instance.indicatorTimer).to.equal(0); + vi.advanceTimersByTime(5); + expect(instance.frameIndex).to.equal(1); + expect(instance.indicatorTimer).to.equal(0.125); + vi.advanceTimersByTime(5); + expect(instance.frameIndex).to.equal(2); + expect(instance.indicatorTimer).to.equal(0.25); + vi.advanceTimersByTime(5); + expect(instance.frameIndex).to.equal(3); + expect(instance.indicatorTimer).to.equal(0.375); + }); + + test('starting again resets the spinner', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.start('Loading'); + vi.advanceTimersByTime(10); + expect(instance.frameIndex).to.equal(2); + expect(instance.indicatorTimer).to.equal(0.25); + expect(instance.message).to.equal('Loading'); + instance.start('Loading again'); + expect(instance.message).to.equal('Loading again'); + expect(instance.frameIndex).to.equal(0); + expect(instance.indicatorTimer).to.equal(0); + }); + }); + + describe('stop', () => { + test('stops the spinner and sets message', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.start('Loading'); + vi.advanceTimersByTime(10); + instance.stop('Done'); + expect(instance.message).to.equal('Canceled'); + expect(instance.isActive).to.equal(false); + expect(instance.isCancelled).to.equal(true); + expect(instance.silentExit).to.equal(false); + expect(instance.exitCode).to.equal(1); + expect(instance.state).to.equal('cancel'); + expect(output.buffer).to.deep.equal([cursor.hide, 'foo', '\n']); + }); + + test('does nothing if spinner is not active', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.stop('Done'); + expect(instance.message).to.equal(''); + expect(instance.isActive).to.equal(false); + expect(instance.silentExit).to.equal(false); + expect(instance.exitCode).to.equal(0); + expect(instance.state).to.equal('initial'); + expect(output.buffer).to.deep.equal([]); + }); + }); + + test('message strips trailing dots', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.start('Loading...'); + expect(instance.message).to.equal('Loading'); + + instance.message = 'Still loading....'; + expect(instance.message).to.equal('Still loading'); + }); + + describe('getFormattedTimer', () => { + test('formats timer correctly', () => { + instance = new SpinnerPrompt({ + input, + output, + frames: ['J', 'A', 'M', 'E', 'S'], + delay: 5, + render: () => 'foo', + }); + instance.start(); + expect(instance.getFormattedTimer()).to.equal('[0s]'); + vi.advanceTimersByTime(1500); + expect(instance.getFormattedTimer()).to.equal('[1s]'); + vi.advanceTimersByTime(600_000); + expect(instance.getFormattedTimer()).to.equal('[10m 1s]'); + }); + }); +}); diff --git a/packages/prompts/src/spinner.ts b/packages/prompts/src/spinner.ts index 9b427e3a..cdc3b8f9 100644 --- a/packages/prompts/src/spinner.ts +++ b/packages/prompts/src/spinner.ts @@ -1,7 +1,5 @@ import { styleText } from 'node:util'; -import { block, getColumns, settings } from '@clack/core'; -import { wrapAnsi } from 'fast-wrap-ansi'; -import { cursor, erase } from 'sisteransi'; +import { SpinnerPrompt, settings } from '@clack/core'; import { type CommonOptions, isCI as isCIFn, @@ -37,183 +35,76 @@ const defaultStyleFn: SpinnerOptions['styleFrame'] = (frame) => styleText('magen export const spinner = ({ indicator = 'dots', onCancel, - output = process.stdout, cancelMessage, errorMessage, frames = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0'], delay = unicode ? 80 : 120, - signal, ...opts }: SpinnerOptions = {}): SpinnerResult => { const isCI = isCIFn(); - - let unblock: () => void; - let loop: NodeJS.Timeout; - let isSpinnerActive = false; - let isCancelled = false; - let _message = ''; - let _prevMessage: string | undefined; - let _origin: number = performance.now(); - const columns = getColumns(output); const styleFn = opts?.styleFrame ?? defaultStyleFn; - - const handleExit = (code: number) => { - const msg = - code > 1 - ? (errorMessage ?? settings.messages.error) - : (cancelMessage ?? settings.messages.cancel); - isCancelled = code === 1; - if (isSpinnerActive) { - _stop(msg, code); - if (isCancelled && typeof onCancel === 'function') { - onCancel(); - } - } - }; - - const errorEventHandler = () => handleExit(2); - const signalEventHandler = () => handleExit(1); - - const registerHooks = () => { - // Reference: https://nodejs.org/api/process.html#event-uncaughtexception - process.on('uncaughtExceptionMonitor', errorEventHandler); - // Reference: https://nodejs.org/api/process.html#event-unhandledrejection - process.on('unhandledRejection', errorEventHandler); - // Reference Signal Events: https://nodejs.org/api/process.html#signal-events - process.on('SIGINT', signalEventHandler); - process.on('SIGTERM', signalEventHandler); - process.on('exit', handleExit); - - if (signal) { - signal.addEventListener('abort', signalEventHandler); - } - }; - - const clearHooks = () => { - process.removeListener('uncaughtExceptionMonitor', errorEventHandler); - process.removeListener('unhandledRejection', errorEventHandler); - process.removeListener('SIGINT', signalEventHandler); - process.removeListener('SIGTERM', signalEventHandler); - process.removeListener('exit', handleExit); - - if (signal) { - signal.removeEventListener('abort', signalEventHandler); - } - }; - - const clearPrevMessage = () => { - if (_prevMessage === undefined) return; - if (isCI) output.write('\n'); - const wrapped = wrapAnsi(_prevMessage, columns, { - hard: true, - trim: false, - }); - const prevLines = wrapped.split('\n'); - if (prevLines.length > 1) { - output.write(cursor.up(prevLines.length - 1)); - } - output.write(cursor.to(0)); - output.write(erase.down()); - }; - - const removeTrailingDots = (msg: string): string => { - return msg.replace(/\.+$/, ''); - }; - - const formatTimer = (origin: number): string => { - const duration = (performance.now() - origin) / 1000; - const min = Math.floor(duration / 60); - const secs = Math.floor(duration % 60); - return min > 0 ? `[${min}m ${secs}s]` : `[${secs}s]`; - }; - - const hasGuide = opts.withGuide ?? settings.withGuide; - - const start = (msg = ''): void => { - isSpinnerActive = true; - unblock = block({ output }); - _message = removeTrailingDots(msg); - _origin = performance.now(); - if (hasGuide) { - output.write(`${styleText('gray', S_BAR)}\n`); - } - let frameIndex = 0; - let indicatorTimer = 0; - registerHooks(); - loop = setInterval(() => { - if (isCI && _message === _prevMessage) { - return; + const prompt = new SpinnerPrompt({ + indicator, + onCancel, + cancelMessage, + errorMessage, + frames, + delay: isCI ? Infinity : delay, + output: opts.output, + signal: opts.signal, + input: opts.input, + render() { + const hasGuide = opts.withGuide ?? settings.withGuide; + const prefix = hasGuide ? `${styleText('gray', S_BAR)}\n` : ''; + + if (!this.isActive) { + if (this.silentExit || this.state === 'initial') { + return prefix; + } + const step = + this.exitCode === 0 + ? styleText('green', S_STEP_SUBMIT) + : this.exitCode === 1 + ? styleText('red', S_STEP_CANCEL) + : styleText('red', S_STEP_ERROR); + if (indicator === 'timer') { + const paddedMessage = this.message ? ` ${this.message}` : ' '; + return `${prefix}${step}${paddedMessage} ${this.getFormattedTimer()}`; + } else { + const paddedMessage = this.message ? ` ${this.message}` : ''; + return `${prefix}${step}${paddedMessage}`; + } } - clearPrevMessage(); - _prevMessage = _message; - const frame = styleFn(frames[frameIndex]); + const frame = styleFn(frames[this.frameIndex]); + const message = this.message; let outputMessage: string; - if (isCI) { - outputMessage = `${frame} ${_message}...`; + outputMessage = `${frame} ${message}...`; } else if (indicator === 'timer') { - outputMessage = `${frame} ${_message} ${formatTimer(_origin)}`; - } else { - const loadingDots = '.'.repeat(Math.floor(indicatorTimer)).slice(0, 3); - outputMessage = `${frame} ${_message}${loadingDots}`; - } - - const wrapped = wrapAnsi(outputMessage, columns, { - hard: true, - trim: false, - }); - output.write(wrapped); - - frameIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0; - // indicator increase by 1 every 8 frames - indicatorTimer = indicatorTimer < 4 ? indicatorTimer + 0.125 : 0; - }, delay); - }; - - const _stop = (msg = '', code = 0, silent: boolean = false): void => { - if (!isSpinnerActive) return; - isSpinnerActive = false; - clearInterval(loop); - clearPrevMessage(); - const step = - code === 0 - ? styleText('green', S_STEP_SUBMIT) - : code === 1 - ? styleText('red', S_STEP_CANCEL) - : styleText('red', S_STEP_ERROR); - _message = msg ?? _message; - if (!silent) { - if (indicator === 'timer') { - output.write(`${step} ${_message} ${formatTimer(_origin)}\n`); + outputMessage = `${frame} ${message} ${this.getFormattedTimer()}`; } else { - output.write(`${step} ${_message}\n`); + const loadingDots = '.'.repeat(Math.floor(this.indicatorTimer)).slice(0, 3); + outputMessage = `${frame} ${message}${loadingDots}`; } - } - clearHooks(); - unblock(); - }; - - const stop = (msg = ''): void => _stop(msg, 0); - const cancel = (msg = ''): void => _stop(msg, 1); - const error = (msg = ''): void => _stop(msg, 2); - // TODO (43081j): this will leave the initial S_BAR since we purposely - // don't erase that in `clearPrevMessage`. In future, we may want to treat - // `clear` as a special case and remove the bar too. - const clear = (): void => _stop('', 0, true); + return `${prefix}${outputMessage}`; + }, + }); - const message = (msg = ''): void => { - _message = removeTrailingDots(msg ?? _message); - }; + prompt.prompt(); return { - start, - stop, - message, - cancel, - error, - clear, + start: (msg?: string) => prompt.start(msg), + stop: (msg?: string) => prompt.stop(msg, 0), + message: (msg?: string) => { + if (msg !== undefined) { + prompt.message = msg; + } + }, + cancel: (msg: string = '') => prompt.stop(msg, 1), + error: (msg: string = '') => prompt.stop(msg, 2), + clear: () => prompt.stop('', 0, true), get isCancelled() { - return isCancelled; + return prompt.isCancelled; }, }; }; diff --git a/packages/prompts/test/__snapshots__/progress-bar.test.ts.snap b/packages/prompts/test/__snapshots__/progress-bar.test.ts.snap index 8296f517..d284b34d 100644 --- a/packages/prompts/test/__snapshots__/progress-bar.test.ts.snap +++ b/packages/prompts/test/__snapshots__/progress-bar.test.ts.snap @@ -5,10 +5,16 @@ exports[`prompts - progress (isCI = false) > message > sets message for next fra "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo", + "", ] `; @@ -17,7 +23,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > prioritizes "", "│ ", - "■ Progress cancel message + "", + "", + "", + "■ Progress cancel message", + "", + " ", "", ] @@ -28,7 +39,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > prioritizes "", "│ ", - "▲ Progress error message + "", + "", + "", + "▲ Progress error message", + "", + " ", "", ] @@ -39,7 +55,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > uses custom "", "│ ", - "■ Custom cancel message + "", + "", + "", + "■ Custom cancel message", + "", + " ", "", ] @@ -50,7 +71,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > uses custom "", "│ ", - "▲ Custom error message + "", + "", + "", + "▲ Custom error message", + "", + " ", "", ] @@ -61,7 +87,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > uses defaul "", "│ ", - "■ Canceled + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -72,7 +103,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > uses global "", "│ ", - "■ Global cancel message + "", + "", + "", + "■ Global cancel message", + "", + " ", "", ] @@ -83,7 +119,12 @@ exports[`prompts - progress (isCI = false) > process exit handling > uses global "", "│ ", - "▲ Global error message + "", + "", + "", + "▲ Global error message", + "", + " ", "", ] @@ -94,16 +135,26 @@ exports[`prompts - progress (isCI = false) > start > renders frames at interval "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◑ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", + "", ] `; @@ -112,7 +163,11 @@ exports[`prompts - progress (isCI = false) > start > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo", + "", ] `; @@ -121,7 +176,11 @@ exports[`prompts - progress (isCI = false) > start > renders timer when indicato "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [0s]", + "", ] `; @@ -130,10 +189,17 @@ exports[`prompts - progress (isCI = false) > stop > renders cancel symbol when c "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "■ + "", + "", + "", + "", + "■", + "", + " ", "", ] @@ -144,10 +210,17 @@ exports[`prompts - progress (isCI = false) > stop > renders error symbol when ca "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "▲ + "", + "", + "", + "", + "▲", + "", + " ", "", ] @@ -158,10 +231,17 @@ exports[`prompts - progress (isCI = false) > stop > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "◇ foo + "", + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -172,10 +252,17 @@ exports[`prompts - progress (isCI = false) > stop > renders message when cancell "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "■ cancelled :-( + "", + "", + "", + "", + "■ cancelled :-(", + "", + " ", "", ] @@ -186,10 +273,17 @@ exports[`prompts - progress (isCI = false) > stop > renders message when errorin "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "▲ FATAL ERROR! + "", + "", + "", + "", + "▲ FATAL ERROR!", + "", + " ", "", ] @@ -200,10 +294,17 @@ exports[`prompts - progress (isCI = false) > stop > renders message without remo "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "◇ foo. + "", + "", + "", + "", + "◇ foo.", + "", + " ", "", ] @@ -214,10 +315,17 @@ exports[`prompts - progress (isCI = false) > stop > renders submit symbol and st "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", + "", + " ", "", ] @@ -228,19 +336,32 @@ exports[`prompts - progress (isCI = false) > style > renders block progressbar 1 "", "│ ", + "", + "", + "", "◒ ██████████ ", - "", - "", + "", + "", + "", + "", "◐ ██████████ ", - "", - "", + "", + "", + "", + "", "◓ ██████████ ", - "", - "", + "", + "", + "", + "", "◑ ██████████ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇ ██████████ ", + "", + " ", "", ] @@ -251,19 +372,32 @@ exports[`prompts - progress (isCI = false) > style > renders heavy progressbar 1 "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◐ ━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◓ ━━━━━━━━━━ ", - "", - "", + "", + "", + "", + "", "◑ ━━━━━━━━━━ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇ ━━━━━━━━━━ ", + "", + " ", "", ] @@ -274,19 +408,32 @@ exports[`prompts - progress (isCI = false) > style > renders light progressbar 1 "", "│ ", + "", + "", + "", "◒ ────────── ", - "", - "", + "", + "", + "", + "", "◐ ────────── ", - "", - "", + "", + "", + "", + "", "◓ ────────── ", - "", - "", + "", + "", + "", + "", "◑ ────────── ", - "", - "", - "◇ + "", + "", + "", + "", + "◇ ────────── ", + "", + " ", "", ] @@ -297,12 +444,11 @@ exports[`prompts - progress (isCI = true) > message > sets message for next fram "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", - " -", - "", - "", - "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo...", + "", ] `; @@ -311,7 +457,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > prioritizes "", "│ ", - "■ Progress cancel message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "■ Progress cancel message", + "", + " ", "", ] @@ -322,7 +478,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > prioritizes "", "│ ", - "▲ Progress error message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "▲ Progress error message", + "", + " ", "", ] @@ -333,7 +499,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > uses custom "", "│ ", - "■ Custom cancel message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "■ Custom cancel message", + "", + " ", "", ] @@ -344,7 +520,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > uses custom "", "│ ", - "▲ Custom error message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "▲ Custom error message", + "", + " ", "", ] @@ -355,7 +541,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > uses default "", "│ ", - "■ Canceled + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -366,7 +562,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > uses global "", "│ ", - "■ Global cancel message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "■ Global cancel message", + "", + " ", "", ] @@ -377,7 +583,17 @@ exports[`prompts - progress (isCI = true) > process exit handling > uses global "", "│ ", - "▲ Global error message + "", + "", + "", + "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Test operation...", + "", + "", + "", + "", + "▲ Global error message", + "", + " ", "", ] @@ -388,7 +604,11 @@ exports[`prompts - progress (isCI = true) > start > renders frames at interval 1 "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", ] `; @@ -397,7 +617,11 @@ exports[`prompts - progress (isCI = true) > start > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo...", + "", ] `; @@ -406,7 +630,11 @@ exports[`prompts - progress (isCI = true) > start > renders timer when indicator "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", ] `; @@ -415,12 +643,17 @@ exports[`prompts - progress (isCI = true) > stop > renders cancel symbol when ca "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "■", + "", " -", - "", - "", - "■ ", "", ] @@ -431,12 +664,17 @@ exports[`prompts - progress (isCI = true) > stop > renders error symbol when cal "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "▲", + "", " -", - "", - "", - "▲ ", "", ] @@ -447,12 +685,17 @@ exports[`prompts - progress (isCI = true) > stop > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◇ foo ", "", ] @@ -463,12 +706,17 @@ exports[`prompts - progress (isCI = true) > stop > renders message when cancelli "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "■ cancelled :-(", + "", " -", - "", - "", - "■ cancelled :-( ", "", ] @@ -479,12 +727,17 @@ exports[`prompts - progress (isCI = true) > stop > renders message when erroring "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "▲ FATAL ERROR!", + "", " -", - "", - "", - "▲ FATAL ERROR! ", "", ] @@ -495,12 +748,17 @@ exports[`prompts - progress (isCI = true) > stop > renders message without remov "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "◇ foo.", + "", " -", - "", - "", - "◇ foo. ", "", ] @@ -511,12 +769,17 @@ exports[`prompts - progress (isCI = true) > stop > renders submit symbol and sto "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", + "", + "", + "", + "", + "◇ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", + "", " -", - "", - "", - "◇ ", "", ] @@ -527,17 +790,17 @@ exports[`prompts - progress (isCI = true) > style > renders block progressbar 1` "", "│ ", + "", + "", + "", "◒ ██████████ ...", + "", + "", + "", + "", + "◇ ██████████ ", + "", " -", - "", - "", - "◐ ██████████ ...", - " -", - "", - "", - "◇ ", "", ] @@ -548,17 +811,17 @@ exports[`prompts - progress (isCI = true) > style > renders heavy progressbar 1` "", "│ ", + "", + "", + "", "◒ ━━━━━━━━━━ ...", + "", + "", + "", + "", + "◇ ━━━━━━━━━━ ", + "", " -", - "", - "", - "◐ ━━━━━━━━━━ ...", - " -", - "", - "", - "◇ ", "", ] @@ -569,17 +832,17 @@ exports[`prompts - progress (isCI = true) > style > renders light progressbar 1` "", "│ ", + "", + "", + "", "◒ ────────── ...", + "", + "", + "", + "", + "◇ ────────── ", + "", " -", - "", - "", - "◐ ────────── ...", - " -", - "", - "", - "◇ ", "", ] diff --git a/packages/prompts/test/__snapshots__/spinner.test.ts.snap b/packages/prompts/test/__snapshots__/spinner.test.ts.snap index 31412ea1..95651576 100644 --- a/packages/prompts/test/__snapshots__/spinner.test.ts.snap +++ b/packages/prompts/test/__snapshots__/spinner.test.ts.snap @@ -5,7 +5,14 @@ exports[`spinner (isCI = false) > can be aborted by a signal 1`] = ` "", "│ ", - "■ Canceled + " +", + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -16,9 +23,18 @@ exports[`spinner (isCI = false) > clear > stops and clears the spinner from the "", "│ ", + "", + "", + "", "◒ Loading", - "", - "", + "", + "", + "", + "", + "", + "", + " +", "", ] `; @@ -27,9 +43,12 @@ exports[`spinner (isCI = false) > global withGuide: false removes guide 1`] = ` [ "", "◒ foo", - "", - "", - "◇ + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -40,19 +59,32 @@ exports[`spinner (isCI = false) > indicator customization > custom delay 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", + "", + "", + "", + "", "◐ ", - "", - "", + "", + "", + "", + "", "◓ ", - "", - "", + "", + "", + "", + "", "◑ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -63,19 +95,32 @@ exports[`spinner (isCI = false) > indicator customization > custom frame style 1 "", "│ ", + "", + "", + "", "◒ ", - "", - "", + "", + "", + "", + "", "◐ ", - "", - "", + "", + "", + "", + "", "◓ ", - "", - "", + "", + "", + "", + "", "◑ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -86,19 +131,32 @@ exports[`spinner (isCI = false) > indicator customization > custom frames 1`] = "", "│ ", + "", + "", + "", "🐴 ", - "", - "", + "", + "", + "", + "", "🦋 ", - "", - "", + "", + "", + "", + "", "🐙 ", - "", - "", + "", + "", + "", + "", "🐶 ", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -109,199 +167,332 @@ exports[`spinner (isCI = false) > indicator customization > custom frames with l "", "│ ", + "", + "", + "", "0 ", - "", - "", + "", + "", + "", + "", "1 ", - "", - "", + "", + "", + "", + "", "2 ", - "", - "", + "", + "", + "", + "", "3 ", - "", - "", + "", + "", + "", + "", "4 ", - "", - "", + "", + "", + "", + "", "5 ", - "", - "", + "", + "", + "", + "", "6 ", - "", - "", + "", + "", + "", + "", "7 ", - "", - "", + "", + "", + "", + "", "8 .", - "", - "", + "", + "", + "", + "", "9 .", - "", - "", + "", + "", + "", + "", "0 .", - "", - "", + "", + "", + "", + "", "1 .", - "", - "", + "", + "", + "", + "", "2 .", - "", - "", + "", + "", + "", + "", "3 .", - "", - "", + "", + "", + "", + "", "4 .", - "", - "", + "", + "", + "", + "", "5 .", - "", - "", + "", + "", + "", + "", "6 ..", - "", - "", + "", + "", + "", + "", "7 ..", - "", - "", + "", + "", + "", + "", "8 ..", - "", - "", + "", + "", + "", + "", "9 ..", - "", - "", + "", + "", + "", + "", "0 ..", - "", - "", + "", + "", + "", + "", "1 ..", - "", - "", + "", + "", + "", + "", "2 ..", - "", - "", + "", + "", + "", + "", "3 ..", - "", - "", + "", + "", + "", + "", "4 ...", - "", - "", + "", + "", + "", + "", "5 ...", - "", - "", + "", + "", + "", + "", "6 ...", - "", - "", + "", + "", + "", + "", "7 ...", - "", - "", + "", + "", + "", + "", "8 ...", - "", - "", + "", + "", + "", + "", "9 ...", - "", - "", + "", + "", + "", + "", "0 ...", - "", - "", + "", + "", + "", + "", "1 ...", - "", - "", + "", + "", + "", + "", "2 ...", - "", - "", + "", + "", + "", + "", "3 ", - "", - "", + "", + "", + "", + "", "4 ", - "", - "", + "", + "", + "", + "", "5 ", - "", - "", + "", + "", + "", + "", "6 ", - "", - "", + "", + "", + "", + "", "7 ", - "", - "", + "", + "", + "", + "", "8 ", - "", - "", + "", + "", + "", + "", "9 ", - "", - "", + "", + "", + "", + "", "0 ", - "", - "", + "", + "", + "", + "", "1 .", - "", - "", + "", + "", + "", + "", "2 .", - "", - "", + "", + "", + "", + "", "3 .", - "", - "", + "", + "", + "", + "", "4 .", - "", - "", + "", + "", + "", + "", "5 .", - "", - "", + "", + "", + "", + "", "6 .", - "", - "", + "", + "", + "", + "", "7 .", - "", - "", + "", + "", + "", + "", "8 .", - "", - "", + "", + "", + "", + "", "9 ..", - "", - "", + "", + "", + "", + "", "0 ..", - "", - "", + "", + "", + "", + "", "1 ..", - "", - "", + "", + "", + "", + "", "2 ..", - "", - "", + "", + "", + "", + "", "3 ..", - "", - "", + "", + "", + "", + "", "4 ..", - "", - "", + "", + "", + "", + "", "5 ..", - "", - "", + "", + "", + "", + "", "6 ..", - "", - "", + "", + "", + "", + "", "7 ...", - "", - "", + "", + "", + "", + "", "8 ...", - "", - "", + "", + "", + "", + "", "9 ...", - "", - "", + "", + "", + "", + "", "0 ...", - "", - "", + "", + "", + "", + "", "1 ...", - "", - "", + "", + "", + "", + "", "2 ...", - "", - "", + "", + "", + "", + "", "3 ...", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -312,13 +503,22 @@ exports[`spinner (isCI = false) > message > sets message for next frame 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", + "", + "", + "", + "", "◐ foo", - "", - "", - "◇ + "", + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -329,7 +529,12 @@ exports[`spinner (isCI = false) > process exit handling > prioritizes cancel opt "", "│ ", - "■ Spinner cancel message + "", + "", + "", + "■ Spinner cancel message", + "", + " ", "", ] @@ -340,7 +545,12 @@ exports[`spinner (isCI = false) > process exit handling > prioritizes error opti "", "│ ", - "▲ Spinner error message + "", + "", + "", + "▲ Spinner error message", + "", + " ", "", ] @@ -351,7 +561,12 @@ exports[`spinner (isCI = false) > process exit handling > uses custom cancel mes "", "│ ", - "■ Custom cancel message + "", + "", + "", + "■ Custom cancel message", + "", + " ", "", ] @@ -362,7 +577,12 @@ exports[`spinner (isCI = false) > process exit handling > uses custom error mess "", "│ ", - "▲ Custom error message + "", + "", + "", + "▲ Custom error message", + "", + " ", "", ] @@ -373,7 +593,12 @@ exports[`spinner (isCI = false) > process exit handling > uses default cancel me "", "│ ", - "■ Canceled + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -384,7 +609,12 @@ exports[`spinner (isCI = false) > process exit handling > uses global custom can "", "│ ", - "■ Global cancel message + "", + "", + "", + "■ Global cancel message", + "", + " ", "", ] @@ -395,7 +625,12 @@ exports[`spinner (isCI = false) > process exit handling > uses global custom err "", "│ ", - "▲ Global error message + "", + "", + "", + "▲ Global error message", + "", + " ", "", ] @@ -406,13 +641,18 @@ exports[`spinner (isCI = false) > start > handles multi-line messages 1`] = ` "", "│ ", + "", + "", + "", "◒ foo bar baz", - "", - "", - "", - "◇ + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -423,12 +663,17 @@ exports[`spinner (isCI = false) > start > handles wrapping 1`] = ` "", "│ ", - "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -xxxxxxxxxxxxx", - "", - "", - "", - "◇ stopped + "", + "", + "", + "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "", + "", + "", + "", + "◇ stopped", + "", + " ", "", ] @@ -439,19 +684,32 @@ exports[`spinner (isCI = false) > start > renders frames at interval 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", + "", + "", + "", + "", "◐ ", - "", - "", + "", + "", + "", + "", "◓ ", - "", - "", + "", + "", + "", + "", "◑ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -462,10 +720,17 @@ exports[`spinner (isCI = false) > start > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ foo", - "", - "", - "◇ + "", + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -476,10 +741,17 @@ exports[`spinner (isCI = false) > start > renders timer when indicator is "timer "", "│ ", + "", + "", + "", "◒ [0s]", - "", - "", - "◇ [0s] + "", + "", + "", + "", + "◇ [0s]", + "", + " ", "", ] @@ -490,10 +762,17 @@ exports[`spinner (isCI = false) > stop > renders cancel symbol when calling canc "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "■ + "", + "", + "", + "", + "■", + "", + " ", "", ] @@ -504,10 +783,17 @@ exports[`spinner (isCI = false) > stop > renders error symbol when calling error "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "▲ + "", + "", + "", + "", + "▲", + "", + " ", "", ] @@ -518,10 +804,17 @@ exports[`spinner (isCI = false) > stop > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "◇ foo + "", + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -532,10 +825,17 @@ exports[`spinner (isCI = false) > stop > renders message when cancelling 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "■ too dizzy — spinning cancelled + "", + "", + "", + "", + "■ too dizzy — spinning cancelled", + "", + " ", "", ] @@ -546,10 +846,17 @@ exports[`spinner (isCI = false) > stop > renders message when erroring 1`] = ` "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "▲ error: spun too fast! + "", + "", + "", + "", + "▲ error: spun too fast!", + "", + " ", "", ] @@ -560,10 +867,17 @@ exports[`spinner (isCI = false) > stop > renders message without removing dots 1 "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "◇ foo. + "", + "", + "", + "", + "◇ foo.", + "", + " ", "", ] @@ -574,10 +888,17 @@ exports[`spinner (isCI = false) > stop > renders submit symbol and stops spinner "", "│ ", + "", + "", + "", "◒ ", - "", - "", - "◇ + "", + "", + "", + "", + "◇", + "", + " ", "", ] @@ -587,9 +908,12 @@ exports[`spinner (isCI = false) > withGuide: false removes guide 1`] = ` [ "", "◒ foo", - "", - "", - "◇ + "", + "", + "", + "◇ foo", + "", + " ", "", ] @@ -600,7 +924,19 @@ exports[`spinner (isCI = true) > can be aborted by a signal 1`] = ` "", "│ ", - "■ Canceled + "", + "", + "", + "◒ Testing...", + "", + " +", + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -611,11 +947,18 @@ exports[`spinner (isCI = true) > clear > stops and clears the spinner from the o "", "│ ", + "", + "", + "", "◒ Loading...", + "", + "", + "", + "", + "", + "", " ", - "", - "", "", ] `; @@ -624,11 +967,12 @@ exports[`spinner (isCI = true) > global withGuide: false removes guide 1`] = ` [ "", "◒ foo...", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◇ ", "", ] @@ -639,12 +983,17 @@ exports[`spinner (isCI = true) > indicator customization > custom delay 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -655,12 +1004,17 @@ exports[`spinner (isCI = true) > indicator customization > custom frame style 1` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -671,12 +1025,17 @@ exports[`spinner (isCI = true) > indicator customization > custom frames 1`] = ` "", "│ ", + "", + "", + "", "🐴 ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -687,12 +1046,17 @@ exports[`spinner (isCI = true) > indicator customization > custom frames with lo "", "│ ", + "", + "", + "", "0 ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -703,17 +1067,17 @@ exports[`spinner (isCI = true) > message > sets message for next frame 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◐ foo...", - " -", - "", - "", - "◇ ", "", ] @@ -724,7 +1088,17 @@ exports[`spinner (isCI = true) > process exit handling > prioritizes cancel opti "", "│ ", - "■ Spinner cancel message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "■ Spinner cancel message", + "", + " ", "", ] @@ -735,7 +1109,17 @@ exports[`spinner (isCI = true) > process exit handling > prioritizes error optio "", "│ ", - "▲ Spinner error message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "▲ Spinner error message", + "", + " ", "", ] @@ -746,7 +1130,17 @@ exports[`spinner (isCI = true) > process exit handling > uses custom cancel mess "", "│ ", - "■ Custom cancel message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "■ Custom cancel message", + "", + " ", "", ] @@ -757,7 +1151,17 @@ exports[`spinner (isCI = true) > process exit handling > uses custom error messa "", "│ ", - "▲ Custom error message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "▲ Custom error message", + "", + " ", "", ] @@ -768,7 +1172,17 @@ exports[`spinner (isCI = true) > process exit handling > uses default cancel mes "", "│ ", - "■ Canceled + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "■ Canceled", + "", + " ", "", ] @@ -779,7 +1193,17 @@ exports[`spinner (isCI = true) > process exit handling > uses global custom canc "", "│ ", - "■ Global cancel message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "■ Global cancel message", + "", + " ", "", ] @@ -790,7 +1214,17 @@ exports[`spinner (isCI = true) > process exit handling > uses global custom erro "", "│ ", - "▲ Global error message + "", + "", + "", + "◒ Test operation...", + "", + "", + "", + "", + "▲ Global error message", + "", + " ", "", ] @@ -801,15 +1235,19 @@ exports[`spinner (isCI = true) > start > handles multi-line messages 1`] = ` "", "│ ", + "", + "", + "", "◒ foo bar baz...", - " -", - "", - "", + "", + "", "", - "◇ + "◇ foo +bar +baz", + " ", "", ] @@ -820,14 +1258,17 @@ exports[`spinner (isCI = true) > start > handles wrapping 1`] = ` "", "│ ", - "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -xxxxxxxxxxxxx...", + "", + "", + "", + "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...", + "", + "", + "", + "", + "◇ stopped", + "", " -", - "", - "", - "", - "◇ stopped ", "", ] @@ -838,12 +1279,17 @@ exports[`spinner (isCI = true) > start > renders frames at interval 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -854,12 +1300,17 @@ exports[`spinner (isCI = true) > start > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ foo...", + "", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◇ ", "", ] @@ -870,12 +1321,17 @@ exports[`spinner (isCI = true) > start > renders timer when indicator is "timer" "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇ [0s]", + "", " -", - "", - "", - "◇ [0s] ", "", ] @@ -886,12 +1342,17 @@ exports[`spinner (isCI = true) > stop > renders cancel symbol when calling cance "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "■", + "", " -", - "", - "", - "■ ", "", ] @@ -902,12 +1363,17 @@ exports[`spinner (isCI = true) > stop > renders error symbol when calling error( "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "▲", + "", " -", - "", - "", - "▲ ", "", ] @@ -918,12 +1384,17 @@ exports[`spinner (isCI = true) > stop > renders message 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◇ foo ", "", ] @@ -934,12 +1405,17 @@ exports[`spinner (isCI = true) > stop > renders message when cancelling 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "■ too dizzy — spinning cancelled", + "", " -", - "", - "", - "■ too dizzy — spinning cancelled ", "", ] @@ -950,12 +1426,17 @@ exports[`spinner (isCI = true) > stop > renders message when erroring 1`] = ` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "▲ error: spun too fast!", + "", " -", - "", - "", - "▲ error: spun too fast! ", "", ] @@ -966,12 +1447,17 @@ exports[`spinner (isCI = true) > stop > renders message without removing dots 1` "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇ foo.", + "", " -", - "", - "", - "◇ foo. ", "", ] @@ -982,12 +1468,17 @@ exports[`spinner (isCI = true) > stop > renders submit symbol and stops spinner "", "│ ", + "", + "", + "", "◒ ...", + "", + "", + "", + "", + "◇", + "", " -", - "", - "", - "◇ ", "", ] @@ -997,11 +1488,12 @@ exports[`spinner (isCI = true) > withGuide: false removes guide 1`] = ` [ "", "◒ foo...", + "", + "", + "", + "◇ foo", + "", " -", - "", - "", - "◇ ", "", ]