JavaScript
Latest commit 59739f0 Oct 10, 2017 @nitin42 nitin42 Merge pull request #41 from fmedinac/chore/license
Add MIT License file

README.md

Terminal in React

Downloads Downloads NPM Version Dependencies Dev Dependencies License size size

A component that renders a terminal

Table of contents

Install

npm install terminal-in-react --save

or if you use yarn

yarn add terminal-in-react

Usage

import React, { Component } from 'react';
import Terminal from 'terminal-in-react';

class App extends Component {
  showMsg = () => 'Hello World'

  render() {
    return (
      <div
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          height: "100vh"
        }}
      >
        <Terminal
          color='green'
          backgroundColor='black'
          barColor='black'
          style={{ fontWeight: "bold", fontSize: "1em" }}
          commands={{
            'open-google': () => window.open('https://www.google.com/', '_blank'),
            showmsg: this.showMsg,
            popup: () => alert('Terminal in React')
          }}
          descriptions={{
            'open-google': 'opens google.com',
            showmsg: 'shows a message',
            alert: 'alert', popup: 'alert'
          }}
          msg='You can write anything here. Example - Hello! My name is Foo and I like Bar.'
        />
      </div>
    );
  }
}

Be careful when copying this example because it uses window object ('open-google': () => window.open("https://www.google.com/", "_blank"),) which is only available on the client-side and it will give you an error if you're doing server side rendering.

Working

Adding commands ✍️

To add your own command, use prop commands which accepts an object. This objects then maps command name -> command function.

Let's take an example. You want to open a website with a command open-google

<Terminal commands={{ 'open-google': () => window.open("https://www.google.com/", "_blank")}} />

Adding description of your command πŸ’πŸΌβ€β™‚οΈ

Add a description of your command using prop description.

<Terminal descriptions={{ 'open-google': 'opens google' }} />

Console logging

You can have the terminal watch console.log/info function and print out. It does so by default.

<Terminal watchConsoleLogging />

Command passthrough

You can have the terminal pass out the cmd that was input

<Terminal commandPassThrough={cmd => `-PassedThrough:${cmd}: command not found`} />

Async handling of commands 😎

you can also handle the result with a callback

<Terminal
  commandPassThrough={(cmd, print) => {
    // do something async
    print(`-PassedThrough:${cmd}: command not found`);
  }}
/>

Minimise, maximise and close the window

Hide the default options

<Terminal descriptions={{ color: false, show: false, clear: false }} />

This will hide the option color, show and clear.

Advanced commands πŸ‘¨β€πŸ’»

You can give your commands options and get them back parsed to the method. Using this method will also give your command a build in help output. With the option -h or --help.

<Terminal
  commands={{
    color: {
      method: (args, print, runCommand) => {
        print(`The color is ${args._[0] || args.color}`);
      },
      options: [
        {
          name: 'color',
          description: 'The color the output should be',
          defaultValue: 'white',
        },
      ],
    },
  }}
/>

The command API has three parameters arguments, print, and runCommand.

  • arguments will be an array of the input split on spaces or and object with parameters meeting the options given as well as a _ option with any strings given after the options.
  • print is a method to write a new line to the terminals output. Any string returned as a result of a command will also be printed.
  • runCommand is a method to call other commands it takes a string and will attempt to run the command given

Let's take an another example -

<Terminal
  commands={{
    'type-text': (args, print, runCommand) => {
      const text = args.slice(1).join(' ');
      print('');
      for (let i = 0; i < text.length; i += 1) {
        setTimeout(() => {
          runCommand(`edit-line ${text.slice(0, i + 1)}`);
        }, 100 * i);
      }
    }
  }}
/>

Using plugins πŸ”₯ [WIP]

We have also developed a plugin system for the <Terminal /> component which helps you develop custom plugins. Here is one example of plugin which creates a fake file system called terminal-in-react-pseudo-file-system-plugin.

Instantiating the plugin

import pseudoFileSystem from 'terminal-in-react-pseudo-file-system-plugin';
const FileSystemPlugin = pseudoFileSystem();

<Terminal
  plugins={[
    FileSystemPlugin,
  ]}
/>

or if the plugin requires config

import NodeEvalPlugin from 'terminal-in-react-node-eval-plugin';
import pseudoFileSystemPlugin from 'terminal-in-react-pseudo-file-system-plugin';
const FileSystemPlugin = pseudoFileSystemPlugin();

...
<Terminal
  plugins={[
    FileSystemPlugin,
    {
      class: NodeEvalPlugin,
      config: {
        filesystem: FileSystemPlugin.displayName
      }
    }
  ]}
/>
...

Awesome! Right? Let us know if you make something interesting πŸ˜ƒ

Plugin List

More features

Tab autocomplete

Multiline input πŸ€ΉπŸΌβ€β™€οΈ

via shift + enter

Check history of your commands πŸ–±οΈ

using arrow down and up keys

Keyboard shortcuts ⌨

You can define keyboard shortcuts. They have to be grouped by os. The three available are win, darwin, and linux. You can group multiple os by a , for example if the shortcut was for all platforms win,darwin,linux would be fine as a key

<Terminal
  shortcuts={{
    'darwin,win,linux': {
      'ctrl + a': 'echo whoo',
    },
  }}
/>

But you might want to specific

<Terminal
  shortcuts={{
    'win': {
      'ctrl + a': 'echo hi windows',
    },
    'darwin': {
      'cmd + a': 'echo hi mac'
    },
    'linux': {
      'ctrl + a': 'echo hi linux'
    }
  }}
/>

You can mix and match

<Terminal
  shortcuts={{
    'win,linux': {
      'ctrl + b': 'echo we are special',
    },
    'win': {
      'ctrl + a': 'echo hi windows',
    },
    'darwin': {
      'cmd + a': 'echo hi mac'
    },
    'linux': {
      'ctrl + a': 'echo hi linux'
    }
  }}
/>

The value of the shortcut should be a command to run.

Override the top bar buttons actionHandlers

Use the prop actionHandlers.

The object allows for 3 methods handleClose, handleMaximise, handleMinimise;

Each one is a function and will pass in the default method as the first param. Any method not passed in will use the default.

<Terminal
  actionHandlers={{
    handleClose: (toggleClose) => {
      // do something on close
      toggleClose();
    },
    handleMaximise: (toggleMaximise) => {
      // do something on maximise
      toggleMaximise();
    }
  }}
/>

Customization

Use

  • prop color to change the color of the text.
  • prop backgroundColor to change the background.
  • prop barColor to change the color of bar.
  • prop prompt to change the prompt (>) color.
  • prop showActions to change if the three circles are shown.
  • prop hideTopBar to hide the top bar altogether.
  • prop allowTabs to allow multiple tabs.

API

component props

Props Type Default
color string 'green'
backgroundColor string 'black'
prompt string 'green'
barColor string 'black'
description object {}
commands object { clear, help, show, }
msg string -
watchConsoleLogging bool false
commandPassThrough function null
promptSymbol string >
plugins array [ { name: '', load: new Plugin(), commands: {} descriptions: {} } ]
startState string ['open', 'maximised', 'minimised', 'closed'] 'open'
showActions bool true
hideTopBar bool false
allowTabs bool true
actionHandlers object -

Built-in commands

  • clear - Clears the screen
  • help - List all the commands
  • show - Shows a msg if any
  • echo - Display the input message
  • edit-line - Edits the last line or a given line using the -l argument

Where to use ?

  • Embed it as a toy on your website
  • For showcasing
  • Explain any of your project using this terminal component
  • or just play with it

You want a X feature

Sure! Check our todolist or create an issue.

Contributing

Contributing Guide

Troubleshooting

Build errors when using with create-react-app

Eject from create-react-app and use a custom webpack configuration with babili-webpack-plugin. Read more about this here.

Style issues when maximizing

Set the style to height: 100vh on parent element.

Sponsor