Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ink

Package Overview
Dependencies
Maintainers
2
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ink - npm Package Compare versions

Comparing version 0.1.2 to 0.2.0

65

index.js
'use strict';
const readline = require('readline');
const logUpdate = require('log-update');

@@ -25,5 +26,2 @@ const StringComponent = require('./lib/string-component');

exports.diff = diff;
exports.renderToString = renderToString;
const unmount = tree => callTree(tree, 'unmount');

@@ -33,3 +31,3 @@ const didMount = tree => callTree(tree, 'didMount');

const render = (nextTree, prevTree, onUpdate = noop, context = {}, autoLifecycle = true) => {
const build = (nextTree, prevTree, onUpdate = noop, context = {}, autoLifecycle = true) => {
const reconciledTree = diff(prevTree, nextTree, onUpdate, context);

@@ -45,17 +43,30 @@

exports.render = render;
exports.build = build;
exports.diff = diff;
exports.mount = (tree, stream) => {
const log = logUpdate.create(stream || process.stdout);
exports.renderToString = (...args) => renderToString(build(...args));
exports.render = (tree, options) => {
if (options && typeof options.write === 'function') {
options = {
stdout: options
};
}
const {stdin, stdout} = Object.assign({
stdin: process.stdin,
stdout: process.stdout
}, options);
const log = logUpdate.create(stdout);
const context = {};
let isUnmounted = false;
let currentTree;
const context = {};
const onUpdate = () => {
if (isUnmounted) {
return;
}
readline.emitKeypressEvents(stdin);
stdin.setRawMode(true);
const nextTree = render(tree, currentTree, onUpdate, context, false);
const update = () => {
const nextTree = build(tree, currentTree, onUpdate, context, false); // eslint-disable-line no-use-before-define
log(renderToString(nextTree));

@@ -68,8 +79,21 @@ didMount(nextTree);

currentTree = render(tree, null, onUpdate, context, false);
log(renderToString(currentTree));
didMount(currentTree);
didUpdate(currentTree);
const onUpdate = () => {
if (isUnmounted) {
return;
}
return () => {
update();
};
update();
const onKeyPress = (ch, key) => {
if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {
exit(); // eslint-disable-line no-use-before-define
}
};
stdin.on('keypress', onKeyPress);
const exit = () => {
if (isUnmounted) {

@@ -79,2 +103,5 @@ return;

stdin.setRawMode(false);
stdin.removeListener('keypress', onKeyPress);
isUnmounted = true;

@@ -84,2 +111,4 @@ unmount(currentTree);

};
return exit;
};

@@ -7,2 +7,6 @@ 'use strict';

module.exports = (component, props, ...children) => {
if (typeof component !== 'function' && typeof component !== 'string') {
throw new TypeError(`Expected component to be a function, but received ${typeof component}. You may have forgotten to export a component.`);
}
props = props || {};

@@ -9,0 +13,0 @@

{
"name": "ink",
"version": "0.1.2",
"description": "React for CLI",
"license": "MIT",
"repository": "vadimdemedes/ink",
"author": {
"name": "vdemedes",
"email": "vdemedes@gmail.com",
"url": "github.com/vadimdemedes"
},
"engines": {
"node": ">= 4"
},
"scripts": {
"test": "xo && ava"
},
"files": [
"lib",
"index.js"
],
"keywords": [
"react",
"cli"
],
"dependencies": {
"arrify": "^1.0.1",
"chalk": "^2.0.1",
"indent-string": "^3.1.0",
"lodash.flattendeep": "^4.4.0",
"lodash.isequal": "^4.5.0",
"log-update": "^1.0.2"
},
"devDependencies": {
"ava": "^0.19.1",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-register": "^6.24.1",
"eslint-config-xo-react": "^0.12.0",
"eslint-plugin-react": "^7.1.0",
"sinon": "^2.3.4",
"xo": "^0.18.2"
},
"ava": {
"require": [
"babel-register"
],
"babel": {
"presets": [
"@ava/stage-4"
],
"plugins": [
[
"transform-react-jsx",
{
"pragma": "h"
}
]
]
}
},
"xo": {
"extends": [
"xo-react"
],
"plugins": [
"react"
],
"rules": {
"react/prop-types": 0
},
"settings": {
"react": {
"pragma": "h"
}
}
}
"name": "ink",
"version": "0.2.0",
"description": "React for CLI",
"license": "MIT",
"repository": "vadimdemedes/ink",
"author": {
"name": "vdemedes",
"email": "vdemedes@gmail.com",
"url": "github.com/vadimdemedes"
},
"engines": {
"node": ">=4"
},
"scripts": {
"test": "xo && ava"
},
"files": [
"lib",
"index.js"
],
"keywords": [
"react",
"cli",
"jsx",
"stdout",
"components",
"command-line",
"preact",
"redux",
"print",
"render",
"colors",
"text"
],
"dependencies": {
"arrify": "^1.0.1",
"chalk": "^2.0.1",
"indent-string": "^3.1.0",
"lodash.flattendeep": "^4.4.0",
"lodash.isequal": "^4.5.0",
"log-update": "^1.0.2"
},
"devDependencies": {
"ava": "^0.20.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-register": "^6.24.1",
"eslint-config-xo-react": "^0.13.0",
"eslint-plugin-react": "^7.1.0",
"sinon": "^2.3.4",
"strip-ansi": "^4.0.0",
"xo": "^0.18.2"
},
"ava": {
"require": [
"babel-register"
],
"babel": {
"presets": [
"@ava/stage-4"
],
"plugins": [
[
"transform-react-jsx",
{
"pragma": "h"
}
]
]
}
},
"xo": {
"extends": [
"xo-react"
],
"rules": {
"react/prop-types": 0
},
"settings": {
"react": {
"pragma": "h"
}
}
}
}

@@ -1,6 +0,12 @@

# Ink [![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=master)](https://travis-ci.org/vadimdemedes/ink)
<h1 align="center">
<br>
<img width="192" alt="Ink" src="media/logo.png">
<br>
<br>
<br>
</h1>
> React for CLIs
> React for CLIs. Build and test your CLI output using components.
Build and test your CLI output using components.
[![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=master)](https://travis-ci.org/vadimdemedes/ink)

@@ -11,3 +17,3 @@

```
$ npm install --save ink
$ npm install ink
```

@@ -19,3 +25,3 @@

```jsx
const {h, mount, Component, Text} = require('ink');
const {h, render, Component, Text} = require('ink');

@@ -52,3 +58,3 @@ class Counter extends Component {

mount(<Counter/>, process.stdout);
render(<Counter/>);
```

@@ -59,2 +65,10 @@

## Useful Components
- [ink-redux](https://github.com/vadimdemedes/ink-redux) - Redux bindings.
- [ink-text-input](https://github.com/vadimdemedes/ink-text-input) - Text input.
- [ink-password-input](https://github.com/vadimdemedes/ink-password-input) - Password input.
- [ink-progress-bar](https://github.com/brigand/ink-progress-bar) - Configurable component for rendering progress bars.
## Guide

@@ -73,10 +87,9 @@

Ink's goal is to provide the same component-based UI building experience that React provides, but for CLI. That's why it tries to implement the minimum required functionality of React. If you are already familiar with React (or Preact, since Ink borrows a few ideas from it), you already know Ink.
Ink's goal is to provide the same component-based UI building experience that React provides, but for command-line apps. That's why it tries to implement the minimum required functionality of React. If you are already familiar with React (or Preact, since Ink borrows a few ideas from it), you already know Ink.
They key difference you have to remember is that the rendering result isn't a DOM, but a string, which Ink writes to output.
The key difference you have to remember is that the rendering result isn't a DOM, but a string, which Ink writes to the output.
### Getting Started
To ensure all examples work and you can begin your adventure with Ink, make sure to set up a JSX transpiler and set JSX pragma to `h`.
Don' forget to import `h` into every file that contains JSX.
To ensure all examples work and you can begin your adventure with Ink, make sure to set up a JSX transpiler and set JSX pragma to `h`. Don' forget to import `h` into every file that contains JSX.

@@ -91,3 +104,3 @@ ```jsx

#### mount(tree, stream)
#### render(tree, stream)

@@ -97,2 +110,4 @@ Mount a component, listen for updates and update the output.

It automatically enables `keypress` events on `process.stdin`. Since it requires [raw mode](https://davidwalsh.name/node-raw-mode) to be enabled, Ink handles default behavior for you, like exiting with <kbd>Ctrl</kbd>+<kbd>C</kbd>.
##### tree

@@ -108,3 +123,3 @@

```jsx
const {h, mount, Component} = require('ink');
const {h, render, Component} = require('ink');

@@ -137,6 +152,6 @@ class Counter extends Component {

const unmount = mount(<Counter/>);
const unmount = render(<Counter/>);
setTimeout(() => {
// enough counting
// Enough counting
unmount();

@@ -146,18 +161,13 @@ }, 1000);

#### renderToString(tree)
#### renderToString(tree, [prevTree])
Render a previously generated VDOM to a string, which you can flush to output.
#### render(tree, [prevTree])
Build a VDOM representation of components.
Render a component to a string and return it.
Useful if you don't intend to use state or lifecycle methods and just want to render the UI once and exit.
```jsx
const {h, render, renderToString} = require('ink');
const {h, renderToString} = require('ink');
const Hello = () => 'Hello World';
const tree = render(<Hello/>);
process.stdout.write(renderToString(tree));
process.stdout.write(renderToString(<Hello/>));
```

@@ -167,5 +177,3 @@

Similarly to React, there are 2 kinds of components: Stateful components (next, "component") and stateless function components.
You can create a component by extending `Component` class.
Unlike stateless function components, they have access to state, context, lifecycle methods and they can be accessed via refs.
Similarly to React, there are two kinds of components: Stateful components (next, "component") and stateless function components. You can create a component by extending `Component` class. Unlike stateless function components, they have access to state, context, lifecycle methods and they can be accessed via refs.

@@ -194,3 +202,3 @@ ```js

// other initialization
// Other initialization
}

@@ -254,3 +262,3 @@ ```

Component was rerendered and was written to output.
Component was rerendered and was written to the output.

@@ -260,6 +268,6 @@ #### State

Each component can have its local state accessible via `this.state`.
Whenever a state updates, component is rerendered.
Whenever a state updates, the component is rerendered.
To set the initial state, extend the constructor and assign an object to `this.state`.
Anywhere in the component state is accessible via `this.state`, and it's also passed to `render()` as a second argument.
The state is accessible via `this.state` anywhere in the component, and it's also passed to `render()` as a second argument.

@@ -286,3 +294,3 @@ ```js

Type: `Object`, `Function`
Type: `Object` `Function`
Default: `{}`

@@ -436,3 +444,3 @@

As you may have noticed, stateless function component still get access to props and context.
As you may have noticed, stateless function components still get access to props and context.

@@ -439,0 +447,0 @@ #### Built-in Components

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc