Skip to content

Node.js module to create and manage multiple spinners in command-line interface programs

License

Notifications You must be signed in to change notification settings

SweetMNM/dreidels

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

spin Dreidels spin

Node.js module to create and manage multiple spinners in command-line interface programs

CircleCI npm standard-readme compliant License: MIT


Note:

This project was forked from the original spinnies package.

Without the amazing work of jcarpanelli, this would not have been possible.

I have opened a PR but the project seems to be unmaintained. Which is why I decided to publish this package.

You can see all the changes made from the original spinnies in the PR. I kept the original package philosophy of non-error-throwing while also creating tests and demos for all the new features.

Although the name of the package changed, the programmatic name stayed as spinnies. Which is why in the examples we still refer to it as spinnies

Meaning of the name

Features

🎎 Create and manage multiple spinners at the same time

πŸ”‘ Control each spinner from it's own instance

🎬 Support for rendering in CI environments

🌈 Colorful spinners thanks to chalk

➿ (Optional) Use spinners from the cli-spinners library

🎼 Long texts will be wrapped across multiple lines based on the terminal size thanks to wordwrapjs

πŸ“œ Indent spinners

🐍 Temporarily hide spinners and show them later

πŸ™ Bind a spinner to a Promise. The spinner will fail if the promise rejects and succeed if it's resolved

🚦 Bind a spinner to an Observable. Use next() to update the spinner text, complete() to succeed the spinner and error() to fail the spinner with an optional error message or Error

πŸ‘Ύ Change the spinner animation while spinning

🍁 Completely remove a spinner

🎾 Easily update existing spinners

✨ 'Non-spinnable' lines

πŸ’Ž Change the status of a spinner. Each status has it's unique colors and symbols

βœ… Preset 'success' status

❌ Preset 'fail' status

⚠️ Preset 'warn' status

ℹ️ Preset 'info' status

⚾ Preset 'stopped' status

🈹 Create your own custom statuses

🐾 Custom statuses are highly customizable to suit your needs

Table of Contents

Installation

With npm

npm i dreidels

With yarn

yarn add dreidels

Usage & Example

const Spinnies = require('dreidels')
const spinnies = new Spinnies();

spinnies.add('spinner-1', { text: 'I am a spinner' });
spinnies.add('spinner-2', { text: 'I am another spinner' });
const theCoolSpinner = spinnies.add('spinner-3', { text: 'I am a cooler spinner' });

setTimeout(() => {
  spinnies.succeed('spinner-1', { text: 'Success!' });

  spinnies.get('spinner-2').fail({ text: 'Fail :(' });

  theCoolSpinner.warn({ text: 'I think i\'m fine :-' });
}, 2000);

API

This library follows a non-error-throwing philosophy. If you provide an invalid option or an invalid value for a valid option it will be ignored.

Abouts

About spinner types

The spinner option, passed to the spinnies constructor and to setFrames() Follow this protocol:

  • If spinner is a string: It will try to use the spinner as the name for a spinner from the cli-spinners package

    Note: cli-spinners is an optional dependency. Install it:

    • With yarn yarn add cli-spinners
    • With npm npm i cli-spinners

    If you are intrested in using this feature.

    If cli-spinners was not installed and a string was passed as the spinner option the spinner will default to the default spinner

  • If spinner is an object It should have keys: frames and interval Where frames is an array of characters and interval is a number of milliseconds.

About statuses

To fully understand how spinner statuses like success, fail, stopped, spinning or any other custom status works you should check out the statues section

About spinner instance

Every spinner you create using add() will have it's own instance.

You can access that instance by storing the return value of the add() method or using the get() method.

Methods of the spinnies constructor that apply to individual spinners like update(), hidden(), hide(), show(), status(), text(), indent(), and remove() Can be called on the main spinnies instance: spinnies.update('spinner-name', options)

Or directly on the spinner instance: spinner.update(options)

For every methods, examples using both ways will be provided.

Initialization:

new Spinnies([options])

Parameters

  • options - object:
    • color - string: Any valid chalk color. The default value is white. Will set the color option for the spinning (default) status.

    • succeedColor - string: Any valid chalk color. The default value is green. Will set the color option for the success status.

    • failColor - string: Any valid chalk color. The default value is red. Will set the color option for the fail status.

    • spinnerColor - string: Any valid chalk color. The default value is greenBright. Will set the spinnerColor option for the spinning (default) status.

    • succeedPrefix - string: The default value is βœ“. Will set the prefix for the success status.

    • failPrefix - string: The default value is βœ–. Will set the prefix for the fail status.

    • spinner - spinnerNameFromCliSpinners = string or object:

      • interval - number
      • frames - string[]

      You can see the already provided spinner here.

    • stream - stream.Writable: Spinnies will write output to this stream. Defaults to process.stderr.

    • disableSpins - boolean: Disable spins (will still print raw messages).

Note: If you are working in any win32 platform, the default spin animation will be overriden. You can get rid of this defining a different spinner animation manually, or by using the integrated VSCode terminal or Windows Terminal.

Example:

const spinner = { interval: 80, frames: ['πŸ‡', '🍈', 'πŸ‰', 'πŸ‹'] }
const spinnies = new Spinnies({ color: 'blue', succeedColor: 'green', spinner });

Instance methods:

add(name, [options])

Adds a new spinner with the given name.

Parameters:

  • name - string: spinner reference name.
  • options - object:
    • text: - string: Optional text to show in the spinner. If none is provided, the name field will be shown.
    • status - string: Initial status of the spinner. For valid statuses see statuses.
    • indent: - number: Optional number of spaces to add before the spinner.
    • hidden: - boolean: If true the spinner will be hidden and not print to the console. See hidden(), hide() and show().
    • color - string: Any valid chalk color. The default value is white. Will set the color option for the spinning (default) status. This will only modify the status options for this spinner.
    • succeedColor - string: Any valid chalk color. The default value is green. Will set the color option for the success status. This will only modify the status options for this spinner.
    • failColor - string: Any valid chalk color. The default value is red. Will set the color option for the fail status. This will only modify the status options for this spinner.

Return value: Returns the created spinner instance.

Example:

const spinnies = new Spinnies();
spinnies.add('spinner-1');
const anotherSpinner = spinnies.add('another-spinner', { text: 'Hello, I am a spinner!', color: 'greenBright' });

get(name)

Return the spinner instance of the spinner with the given name.

Parameters:

  • name - string: spinner reference name.

Return value: Return the spinner instance of the spinner with the given name.

Example:

const spinnies = new Spinnies();
spinnies.add('apple-spinner');
// do stuff
const apple = spinnies.get('apple-spinner');
// we can now do stuff with `apple`
apple.update(options);
apple.succeed();
apple.fail();
apple.remove();
// same as doing
spinnies.update('apple-spinner', options);
spinnies.succeed('apple-spinner');
spinnies.fail('apple-spinner');
spinnies.remove('apple-spinner');

pick(name)

Picks a spinner.

Parameters:

  • name - string: spinner reference name.

Return value: Returns the spinner's options.

Example:

const spinnies = new Spinnies();
spinnies.add('generic-spinner-name');
// some code
const genericSpinnerNameColor = spinnies.pick('generic-spinner-name').color;

setFrames(spinner)

Updates the spinners frames.

Parameters:

  • spinner - spinnerNameFromCliSpinners = string or object:
    • interval - number
    • frames - string[]

Return value: Returns the spinners instance (this).

Example:

const fruits = {
  interval: 150,
  frames: ['πŸ‡', '🍈', 'πŸ‰', 'πŸ‹']
};
const veggies = {
  interval: 100,
  frames: ['πŸ…', 'πŸ₯’', 'πŸ₯¦', 'πŸ₯•']
};
const spinnies = new Spinnies({ spinner: fruits });
// some code
spinnies.setFrames(vegis);

update(name, [options])

Updates the spinner with name name with the provided options.

Parameters:

  • name - string: spinner reference name.
  • options - object:
    • text: - string: Optional text to show in the spinner. If none is provided, the name field will be shown.
    • status - string: New status of the spinner. For valid statuses see statuses.
    • indent: - number: Optional number of spaces to add before the spinner.
    • hidden: - boolean: If true the spinner will be hidden and not print to the console. See hidden(), hide() and show().
    • color - string: Any valid chalk color. The default value is white. Will set the color option for the spinning (default) status. This will only modify the status options for this spinner.
    • succeedColor - string: Any valid chalk color. The default value is green. Will set the color option for the success status. This will only modify the status options for this spinner.
    • failColor - string: Any valid chalk color. The default value is red. Will set the color option for the fail status. This will only modify the status options for this spinner.

Return value: Returns the updated spinner instance.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
// some code
spinnies.update('spinner-1', { text: 'Hello, I am an updated text!', color: 'blue' });
// same as
spinnies.get('spinner-1').update({ text: 'Hello, I am an updated text!', color: 'blue' });
// same as
spinner1.update({ text: 'Hello, I am an updated text!', color: 'blue' });

status(name, status)

Sets the status of a spinner. See Setting status for more ways to set the status of a spinner.

Parameters:

  • name - string: spinner reference name.
  • status - string: New status of the spinner. For valid statuses see statuses.

Return value: Returns the updated spinner instance.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am a spinner with the initial "spinning" status', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });

// some code
spinnies.status('spinner-1', 'success');
// same as
spinnies.get('spinner-1').status('success');
// same as
spinner1.status('success');

spinnies.status('spinner-2', 'failed');

text(name, text)

Sets the text of a spinner.

Parameters:

  • name - string: spinner reference name.
  • text - string: New text of the spinner.

Return value: Returns the updated spinner instance.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text' });

// some code
spinnies.text('spinner-1', 'Hello, I am an updated text!');
// same as
spinnies.get('spinner-1').text('Hello, I am an updated text!');
// same as
spinner1.text('Hello, I am an updated text!');

indent(name, indent)

Sets the indent of a spinner.

Parameters:

  • name - string: spinner reference name.
  • indent: - number: number of spaces to add before the spinner.

Return value: Returns the updated spinner instance.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am indented with 2 spaces, but soon will upgrade to 4 spaces :D', indent: 2 });

// some code
spinnies.indent('spinner-1', 4);
// same as
spinnies.get('spinner-1').indent(4);
// same as
spinner1.indent(4);

hidden(name, [bool])

Pass true to hide a spinner, pass false to show a spinner. Hidden spinners will not print to the console. Unlike remove() hidden spinner can be shown again after hiding them. Use hide() and show() for convenient.

Parameters:

  • name - string: spinner reference name.
  • bool - boolean: Optional. Pass true to hide and false to show. Pass nothing to return the current hidden state of the spinner.

Return value: return true if the spinner is hidden and return false if the spinner is not hidden.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });
// some code
spinnies.hidden('spinner-1', true); // Hide the spinner
// some code
spinnies.hidden('spinner-1', false); // Show the spinner
// some code
spinnies.hidden('spinner-1'); // return `false`

// OR

spinner1.hidden(true); // Call on the spinner directly
// same as
spinnies.get('spinner-1').hidden(true);

hide(name)

Hide a spinner. Use show() to show a spinner after hiding it.

Parameters:

  • name - string: spinner reference name.

Return value: true.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });
// some code
spinnies.hide('spinner-1');
// same as
spinnies.get('spinner-1').hide();
// same as
spinner1.hide();

show(name)

Show a spinner after it was hidden. Use hide() to hide a spinner.

Parameters:

  • name - string: spinner reference name.

Return value: false.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });

// WE HID THE SPINNER USING hide()

// some code
spinnies.show('spinner-1');
// same as
spinnies.get('spinner-1').show();
// same as
spinner1.show();

bind(name, task)

Bind a spinner to a Promise or an Observable.

When task is a Promise:

If that promise resolves, the spinner will succeed. Passing a string to the resolve call will update the spinner text when succeeding it.

If that promise rejects, the spinner will fail. Passing a string to the reject call will update the spinner text when failing it. Passing an Error to the reject call will format that error and update the spinner text with the error message and stack.

When task is an Observable:

Calling next() with a string will update the spinner text. you can call next() multiple times.

Calling complete() will succeed the spinner. Note: Observables do not allow passing arguments to complete(), meaning you can't change the text using complete().

Calling error() with a string will update the spinner text when failing it.

Calling error() with an Error will format that error and update the spinner text with the error message and stack.

Parameters:

  • task - Promise || Observable: a Promise or an Observable to bind to that spinner.

Return value: Returns the spinner instance.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

// How to bind?
spinnies.bind('spinner-1', task);
// same as
spinnies.get('spinner-1').bind(task);
// same as
spinner1.bind(task);

Example with a resolved Promise:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

spinner1.bind(Promise.resolve('Success :D'));

Example with a rejected Promise:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

spinner1.bind(Promise.reject('I failed :('));

Example with a rejected Promise, passing an Error:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

spinner1.bind(Promise.reject(new Error('Something went wrong :/')));

Example with an Observable:

const { Observable } = require('rxjs');
const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

spinner1.bind(new Observable(subscriber => {
  setTimeout(() => {
    subscriber.next('I was updated!');
  }, 1500);

  setTimeout(() => {
    subscriber.next('I was updated again!');
  }, 3000);

  setTimeout(() => {
    subscriber.next('and again...');
  }, 4500);

  setTimeout(() => {
    subscriber.complete();
  }, 5000);
}));

Example with an Observable that fails:

const { Observable } = require('rxjs');
const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });

spinner1.bind(new Observable(subscriber => {
  setTimeout(() => {
    subscriber.next('Doing some stuff...');
  }, 1000);

  setTimeout(() => {
    subscriber.next('More important stuff...');
  }, 3000);

  setTimeout(() => {
    subscriber.error('Something is not right');
  }, 4500);

remove(name)

Remove a spinner, which will make the spinner disappear and not rerender.

Parameters:

  • name - string: spinner reference name.

Return value: undefined.

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });
// some code
spinnies.remove('spinner-1');
// same as
spinnies.get('spinner-1').remove();
// same as
spinner1.remove();

stopAll([status])

Stops the spinners and sets all of the active spinners statuses to the provided status, which can any valid status. You can see an example here.

Parameters:

  • status - string: Optional. Status to set for all of the active spinner. Defaults to 'stopped'

Example:

const spinnies = new Spinnies();
spinnies.add('spinner-1', { text: 'Hello! I am the initial text', color: 'green' });
spinnies.add('spinner-2', { text: 'Hello! I am a cool spinner', color: 'blue' });

// some code
spinnies.stopAll();
// or
spinnies.stopAll('failed'); // Fail all active spinners

hasActiveSpinners()

Return value: returns true if there are still active spinners.

Statuses

Valid statuses

The default statuses are:

  • spinning, aliases: default, active, spin, static: false
  • fail, aliases: failed, error, static: true, default color: green
  • success, aliases: succeed, done, static: true, default color: red
  • warn, alias warning, static: true, default color: yellow
  • info, alias information, static: true, default color: blue
  • non-spinnable, aliases: static, inactive, static: true, prefix false
  • stopped, aliases: stop, cancel, static: true, prefix false, default color: gray

Also any status you manually set using configureStatus is valid.

Compatibility

For backwards compatibility reasons and convenient: passing succeedColor, failColor, warnColor, infoColor, failPrefix, succeedPrefix, warnPrefix, infoPrefix, color and spinnerColor To the spinnies constructor, spinnies.add() and spinnies.update() will set the status options.

Passing those options to spinnies.add() and spinnies.update() will set those options for the status specific to these spinners. That way every spinner can have a different succeedColor for example.

Setting status

There are 3 ways to set the status of a spinner.

  1. Using the update() method and passing status.
spinner.update({ status: 'statusName' })
// or
spinnies.update('spinnerName', { status: 'statusName' });
// e.g
spinner.update({ status: 'success' });
  1. Using the status() method.
spinner.status('statusName')
// e.g
spinner.status('fail');
  1. Use the status name as the method name. If you create a custom status and a property with that status name exists on the spinnies constructor (add, update, get, pick etc...) it would not override that property and you wouldn't be able to set that status using this method.
spinner.statusName()
// or
spinners.statusName('spinnerName')

// e.g
spinner.success();
// using alias
spinner.succeed();

// failing a spinner
spinner.fail();

// warning a spinner
spinner.warn();
// or
spinner.warning();

// stopping a spinner
spinner.stop();

StatusRegistry

Status registry is used to create and configure spinner statuses. A single instance of StatusRegistry is shared between the main spinners instance and the rest of the spinners.

Note: StatusRegistry is not used to set the status of a spinner just to store information about statuses, like prefixes,colors, ect... To set the status of a spinner see setting statuses

configureStatus(name, options)

Configure a status with the name. Will create a status with that name if it doesn't exist or modify the status options if it does exist. Will try to set the spinnies instance[name] as a function to set that status.

Parameters:

  • name - string: The name of the status.
  • options - object:
    • aliases: - string || string[]: Optional string or array of string, an alias will be created to this status name for every string. Modifying the original status will also apply for the aliases.
    • textColor - string: Any valid chalk color. This color will be applied to the spinner's text whenever this status is the spinner's active status.
    • spinnerColor - string: Any valid chalk color. This color will be applied to the spinner's spinner whenever this status is the spinner's active status. The default value is greenBright.
    • prefixColor - string: Any valid chalk color. This color will be applied to the spinner's prefix whenever this status is the spinner's active status. The default value is greenBright.
    • prefix - string || false: The prefix for the spinner. Can be set to false to not render a prefix.
    • noSpaceAfterPrefix - boolean: By default the spinner/prefix will have a space rendered. Set this to false to disable this behavior.
    • isStatic - boolean: A static status will not spin and show the prefix at the start of the spinner. If this is set to true the prefix will be rendered with the prefixColor and an optional space after it as long as noSpaceAfterPrefix is set to false. If this option is false, The spinner will spin (use the current frame...) and the prefix will not render. Meaning when this is false, prefix, prefixColor and noSpaceAfterPrefix are completely meaningless. Defaults to false.
    • isDone - booolean: By default statuses are treated as 'done' if the isStatic option is true. For example statuses like success, fail and stopped are treated as done, while the spinning status is not treated as 'done'. Whenever a status of a spinner is treated as 'done' spinnies will know to complete that spinner and to stop spinning when ever all spinners are done. By default any static status with isStatic set to true will also be treated as 'done'. The isDone option is rarely ever used since the default behavior suits most statuses. This is good for example if we want to create a pending status. The pending status can be good for tasks that will be executed in the future but are not running yet. We don't want spinnies to think a spinner with the pending status is 'done' but we also don't want a spinner with a pending status to spin.

Return value: Returns the StatusRegistry instance (this).

Example:

const spinnies = new Spinnies();
const spinner1 = spinnies.add('spinner-1', { text: 'Hello! I use the default status which is "spinning" my "color" option is set to yellow which just means my default status color is yellow', color: 'yellow' });
spinnies.statusRegistry.configureStatus('pinkify', {
  aliases: ['pinky', 'pinkful'],
  textColor: 'magenta',
  spinnerColor: 'magenta'
});

spinnies.statusRegistry.configureStatus('santa', {
  textColor: 'red',
  isStatic: true,
  prefix: 'πŸŽ…'
});

/* When modifying an existing status
   it is important to use the original name of the status
   and not an alias name.
   Any changes to the original status will also apply to that status aliases */
spinnies.statusRegistry.configureStatus('fail' /* GOOD */, {
  prefixColor: 'cyan' // same as `new Spinnies({ failColor: 'cyan' })`
});
// spinnies.statusRegistry.configureStatus('failed' /* BAD: don't use alias names */);

// some code
spinner1.update({
  status: 'pinkful',
  text: 'Hi there! I am now completely pink (magenta but you know), my text and my spinner. I still spin since this status is not "static"',
});
spinner1.update({
  status: 'spinning',
  text: 'I\'m yellow again! Back to my default status'
});
spinner1.pinkify();

// some code
spinner1.status('santa');
// or
spinner1.santa();

spinner1.fail();
// or
spinner1.failed();

getStatus(nameOrAlias)

Return the status options for the specified status.

Contribute

Star it, fork it, improve it, PR it! πŸ™Œ.

Acknowledgements

Thanks to chalk (<=v0.5.1) and colorette (>=v0.5.2) for helping to make this lib colorful 🌈 and to ora which was a great inspiration πŸ¦„.

License

MIT

About

Node.js module to create and manage multiple spinners in command-line interface programs

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%