/terminal-in-react

๐Ÿ‘จโ€๐Ÿ’ป A component that renders a terminal

Primary LanguageJavaScriptMIT LicenseMIT

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

This package also depends on react so make sure you've already installed it.

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 ๐Ÿ”ฅ

Plugin Documentation.

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 outputColor to change the color of the output text defaults to color prop.
  • 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'
outputColor string props.color
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 projects 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