Comparing version 0.5.1 to 2.0.0-0
217
package.json
{ | ||
"name": "ink", | ||
"version": "0.5.1", | ||
"description": "React for CLI", | ||
"license": "MIT", | ||
"repository": "vadimdemedes/ink", | ||
"author": { | ||
"name": "vdemedes", | ||
"email": "vdemedes@gmail.com", | ||
"url": "github.com/vadimdemedes" | ||
}, | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava", | ||
"cast": "svg-term --command 'node media/demo.js' --out media/demo.svg --from=100 --window --width=50 --height=8 --term=iterm2 --profile=Snazzy" | ||
}, | ||
"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", | ||
"is-equal-shallow": "^0.1.3", | ||
"lodash.flattendeep": "^4.4.0", | ||
"log-update": "^2.1.0", | ||
"prop-types": "^15.5.10" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.0.0-beta.44", | ||
"@babel/plugin-transform-react-jsx": "^7.0.0-beta.44", | ||
"@babel/register": "^7.0.0-beta.44", | ||
"ansi-styles": "^3.1.0", | ||
"ava": "^1.0.0-beta.3", | ||
"babel-eslint": "^8.2.2", | ||
"eslint-config-xo-react": "^0.13.0", | ||
"eslint-plugin-react": "^7.1.0", | ||
"sinon": "^2.3.4", | ||
"strip-ansi": "^4.0.0", | ||
"svg-term-cli": "^2.1.1", | ||
"xo": "^0.18.2" | ||
}, | ||
"ava": { | ||
"require": [ | ||
"@babel/register" | ||
], | ||
"babel": { | ||
"testOptions": { | ||
"presets": [ | ||
"@ava/stage-4" | ||
], | ||
"plugins": [ | ||
[ | ||
"@babel/plugin-transform-react-jsx", | ||
{ | ||
"pragma": "h", | ||
"pragmaFrag": "h.Fragment" | ||
} | ||
] | ||
] | ||
} | ||
} | ||
}, | ||
"xo": { | ||
"extends": [ | ||
"xo-react" | ||
], | ||
"settings": { | ||
"react": { | ||
"pragma": "h", | ||
"pragmaFrag": "h.Fragment" | ||
} | ||
}, | ||
"parser": "babel-eslint", | ||
"rules": { | ||
"react/no-deprecated": 0 | ||
}, | ||
"overrides": [ | ||
{ | ||
"files": "test/*.js", | ||
"rules": { | ||
"react/prop-types": 0, | ||
"quotes": 0 | ||
} | ||
} | ||
] | ||
} | ||
"name": "ink", | ||
"version": "2.0.0-0", | ||
"description": "React for CLI", | ||
"license": "MIT", | ||
"repository": "vadimdemedes/ink", | ||
"author": { | ||
"name": "vdemedes", | ||
"email": "vdemedes@gmail.com", | ||
"url": "github.com/vadimdemedes" | ||
}, | ||
"engines": { | ||
"node": ">=8" | ||
}, | ||
"scripts": { | ||
"build": "babel src --out-dir build", | ||
"prepublish": "npm run build", | ||
"test": "xo && ava", | ||
"pretest": "npm run build", | ||
"cast": "svg-term --command 'node media/demo.js' --out media/demo.svg --from=100 --window --width=50 --height=8 --term=iterm2 --profile=Snazzy" | ||
}, | ||
"main": "build", | ||
"files": [ | ||
"build" | ||
], | ||
"keywords": [ | ||
"react", | ||
"cli", | ||
"jsx", | ||
"stdout", | ||
"components", | ||
"command-line", | ||
"preact", | ||
"redux", | ||
"print", | ||
"render", | ||
"colors", | ||
"text" | ||
], | ||
"dependencies": { | ||
"arrify": "^1.0.1", | ||
"chalk": "^2.4.1", | ||
"cli-cursor": "^2.1.0", | ||
"log-update": "^2.3.0", | ||
"prop-types": "^15.6.2", | ||
"react": "^16.4.2", | ||
"react-reconciler": "^0.12.0", | ||
"slice-ansi": "^1.0.0", | ||
"string-length": "^2.0.0", | ||
"undom": "^0.4.0", | ||
"widest-line": "^2.0.0", | ||
"yoga-layout-prebuilt": "^1.9.3" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.1.2", | ||
"@babel/core": "^7.1.2", | ||
"@babel/plugin-proposal-class-properties": "^7.1.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0", | ||
"@babel/preset-react": "^7.0.0", | ||
"ava": "1.0.0-beta.8", | ||
"babel-eslint": "^10.0.1", | ||
"eslint-config-xo-react": "^0.17.0", | ||
"eslint-plugin-react": "^7.11.1", | ||
"strip-ansi": "^4.0.0", | ||
"svg-term-cli": "^2.1.1", | ||
"xo": "^0.23.0" | ||
}, | ||
"babel": { | ||
"plugins": [ | ||
"@babel/plugin-proposal-class-properties", | ||
"@babel/plugin-proposal-object-rest-spread", | ||
"@babel/plugin-transform-modules-commonjs" | ||
], | ||
"presets": [ | ||
"@babel/preset-react" | ||
] | ||
}, | ||
"ava": { | ||
"babel": { | ||
"testOptions": { | ||
"plugins": [ | ||
"@babel/plugin-proposal-class-properties", | ||
"@babel/plugin-proposal-object-rest-spread", | ||
"@babel/plugin-transform-modules-commonjs" | ||
], | ||
"presets": [ | ||
"@babel/preset-react" | ||
] | ||
} | ||
} | ||
}, | ||
"xo": { | ||
"parser": "babel-eslint", | ||
"extends": [ | ||
"xo-react" | ||
], | ||
"plugins": [ | ||
"react" | ||
], | ||
"overrides": [ | ||
{ | ||
"files": "src/components/*.js", | ||
"rules": { | ||
"unicorn/filename-case": 0, | ||
"react/require-default-props": 1 | ||
} | ||
}, | ||
{ | ||
"files": "test/*.js", | ||
"rules": { | ||
"import/default": 0 | ||
} | ||
} | ||
] | ||
} | ||
} |
651
readme.md
<h1 align="center"> | ||
<br> | ||
<img width="192" alt="Ink" src="media/logo.png"> | ||
<br> | ||
<img width="300" alt="Ink" src="media/logo.png"> | ||
<br> | ||
<br> | ||
<br> | ||
</h1> | ||
@@ -11,3 +12,3 @@ | ||
[![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=master)](https://travis-ci.org/vadimdemedes/ink) | ||
[![Build Status](https://travis-ci.org/vadimdemedes/ink.svg?branch=next)](https://travis-ci.org/vadimdemedes/ink) | ||
@@ -18,3 +19,3 @@ | ||
``` | ||
$ npm install ink | ||
$ npm install ink@next | ||
``` | ||
@@ -26,3 +27,4 @@ | ||
```jsx | ||
const {h, render, Component, Color } = require('ink'); | ||
import React, {Component} from 'react'; | ||
import {render, Color} from 'ink'; | ||
@@ -62,6 +64,5 @@ class Counter extends Component { | ||
<p align="center"> | ||
<img src="media/demo.svg" width="600"> | ||
</p> | ||
<img src="media/demo.svg" width="600"> | ||
## Useful Components | ||
@@ -92,3 +93,5 @@ | ||
- [ink-big-text](https://github.com/sindresorhus/ink-big-text) - Awesome text component. | ||
- [ink-divider](https://github.com/JureSotosek/ink-divider) - A divider component. | ||
## Built with Ink | ||
@@ -99,22 +102,18 @@ | ||
## Guide | ||
- [Getting Started](#getting-started) | ||
- [Core API](#core-api) | ||
- [Components](#components) | ||
- [Props](#props) | ||
- [Lifecycle Methods](#lifecycle-methods) | ||
- [State](#state) | ||
- [Refs](#refs) | ||
- [Context](#context) | ||
- [Stateless Function Components](#stateless-function-components) | ||
- [API](#api) | ||
- [Building Layouts](#building-layouts) | ||
- [Built-in Components](#built-in-components) | ||
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. | ||
Ink's goal is to provide the same component-based UI building experience that React provides, but for command-line apps. It uses [yoga-layout](https://github.com/facebook/yoga) to allow Flexbox layouts in the terminal. If you are already familiar with React, you already know Ink. | ||
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`. You can use [`babel-plugin-transform-react-jsx`](https://babeljs.io/docs/plugins/transform-react-jsx/) to do this. For example, in `package.json`: | ||
To ensure all examples work and you can begin your adventure with Ink, make sure to set up Babel with a React preset. After [installing Babel](https://babeljs.io/docs/en/usage), configure it in `package.json`: | ||
@@ -124,9 +123,4 @@ ```json | ||
"babel": { | ||
"plugins": [ | ||
[ | ||
"transform-react-jsx", | ||
{ | ||
"pragma": "h" | ||
} | ||
] | ||
"presets": [ | ||
"@babel/preset-react" | ||
] | ||
@@ -137,8 +131,9 @@ } | ||
Don't forget to import `h` into every file that contains JSX: | ||
Don't forget to import `React` into every file that contains JSX: | ||
```jsx | ||
const {h} = require('ink'); | ||
import React from 'react'; | ||
import {Box} from 'ink'; | ||
const Demo = () => <div/>; | ||
const Demo = () => <Box/>; | ||
``` | ||
@@ -149,22 +144,42 @@ | ||
### Core API | ||
### API | ||
#### render(tree, stream) | ||
Since Ink is a React renderer, it means that all of React is supported. | ||
Head over to [React](https://reactjs.org/) website for documentation on how to use it. | ||
In this readme only Ink's methods will be documented. | ||
Mount a component, listen for updates and update the output. | ||
This method is used for interactive UIs, where you need state, user input or lifecycle methods. | ||
#### render(tree, options) | ||
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>. | ||
Mount a component and render the output. | ||
##### tree | ||
Type: `VNode` | ||
Type: `ReactElement` | ||
##### stream | ||
##### options | ||
###### stdout | ||
Type: `Stream`<br> | ||
Default: `process.stdout` | ||
Output stream where app will be rendered. | ||
###### stdin | ||
Type: `Stream`<br> | ||
Default: `process.stdin` | ||
Input stream where app will listen for input. | ||
###### debug | ||
Type: `Boolean`<br> | ||
Default: `false` | ||
If `true`, each update will be rendered as a separate output, without replacing the previous one. | ||
```jsx | ||
const {h, render, Component} = require('ink'); | ||
import React, {Component} from 'react'; | ||
import {render, Box} from 'ink'; | ||
@@ -180,4 +195,8 @@ class Counter extends Component { | ||
render(props, state) { | ||
return `Iteration #${state.i}`; | ||
render() { | ||
return ( | ||
<Box> | ||
Iteration #${this.state.i} | ||
</Box> | ||
); | ||
} | ||
@@ -206,411 +225,395 @@ | ||
#### renderToString(tree, [prevTree]) | ||
There's also a shortcut to avoid passing `options` object: | ||
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, renderToString} = require('ink'); | ||
render(<Counter>, process.stdout); | ||
``` | ||
const Hello = () => 'Hello World'; | ||
process.stdout.write(renderToString(<Hello/>)); | ||
``` | ||
### Building Layouts | ||
### Components | ||
Ink uses [Yoga](https://github.com/facebook/yoga) - a Flexbox layout engine to build great user interfaces for your CLIs. | ||
It's important to remember that each element is a Flexbox container. | ||
Think of it as if each `<div>` in the browser had `display: flex`. | ||
See `<Box>` built-in component below for documentation on how to use Flexbox layouts in Ink. | ||
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. | ||
```js | ||
class Demo extends Component { | ||
render(props, state, context) { | ||
// props === this.props | ||
// state === this.state | ||
// context === this.context | ||
### Built-in Components | ||
return 'Hello World'; | ||
} | ||
} | ||
``` | ||
#### <Box> | ||
If you need to extend the constructor to set the initial state or for other purposes, make sure to call `super()` with `props` and `context`: | ||
`<Box>` it's an essential Ink component to build your layout. It's like a `<div>` in a browser. | ||
Import: | ||
```js | ||
constructor(props, context) { | ||
super(props, context); | ||
import {Box} from 'ink'; | ||
``` | ||
this.state = { | ||
i: 0 | ||
}; | ||
##### Padding | ||
// Other initialization | ||
} | ||
``` | ||
###### paddingTop | ||
#### Props | ||
Type: `number`<br> | ||
Default: `0` | ||
Props are basically arguments for components. | ||
Every parent component can pass props to their children. | ||
###### paddingBottom | ||
```jsx | ||
class Child extends Component { | ||
render(props) { | ||
// props === this.props | ||
Type: `number`<br> | ||
Default: `0` | ||
return `Hello, ${props.name}`; | ||
} | ||
} | ||
###### paddingLeft | ||
class Parent extends Component { | ||
render() { | ||
return <Child name="Joe"/>; | ||
} | ||
} | ||
``` | ||
Type: `number`<br> | ||
Default: `0` | ||
To set default props on specific component, use `defaultProps`: | ||
###### paddingRight | ||
```js | ||
const Test = ({first, second}) => `${first} ${second}`; | ||
Type: `number`<br> | ||
Default: `0` | ||
Test.defaultProps = { | ||
first: 'Hello', | ||
second: 'World' | ||
}; | ||
###### paddingX | ||
// <Test/> => "Hello World" | ||
``` | ||
Type: `number`<br> | ||
Default: `0` | ||
##### Prop Types | ||
###### paddingY | ||
Ink supports prop types out-of-the-box. All you have to do is set them in the same way you would in React: | ||
Type: `number`<br> | ||
Default: `0` | ||
```js | ||
const PropTypes = require('prop-types'); | ||
###### padding | ||
Test.propTypes = { | ||
first: PropTypes.string.isRequired, | ||
second: PropTypes.string | ||
}; | ||
Type: `number`<br> | ||
Default: `0` | ||
```jsx | ||
<Box paddingTop={2}>Top</Box> | ||
<Box paddingBottom={2}>Bottom</Box> | ||
<Box paddingLeft={2}>Left</Box> | ||
<Box paddingRight={2}>Right</Box> | ||
<Box paddingX={2}>Left and right</Box> | ||
<Box paddingY={2}>Top and bottom</Box> | ||
<Box padding={2}>Top, bottom, left and right</Box> | ||
``` | ||
**Note**: Prop types are only checked when `NODE_ENV` isn't `'production'`. | ||
##### Margin | ||
#### Lifecycle Methods | ||
###### marginTop | ||
Lifecycle methods are component methods that are called whenever a certain event happens related to that specific component. All lifecycle methods are called from top to down, meaning that components on top receive those events earlier than their children. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentWillMount() | ||
###### marginBottom | ||
Component is initialized and is about to be rendered and written to the output. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentDidMount() | ||
###### marginLeft | ||
Component is rendered and written to the output. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentWillUnmount() | ||
###### marginRight | ||
Component is about to be unmounted and component instance is going to be destroyed. | ||
This is the place to clean up timers, cancel HTTP requests, etc. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentWillReceiveProps(nextProps, nextState) | ||
###### marginX | ||
Component is going to receive new props or state. | ||
At this point `this.props` and `this.state` contain previous props and state. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### shouldComponentUpdate(nextProps, nextState) | ||
###### marginY | ||
Determines whether to rerender component for the next props and state. | ||
Return `false` to skip rerendering of component's children. | ||
By default, returns `true`, so component is always rerendered on update. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentWillUpdate(nextProps, nextState) | ||
###### margin | ||
Component is about to rerender. | ||
Type: `number`<br> | ||
Default: `0` | ||
##### componentDidUpdate() | ||
```jsx | ||
<Box marginTop={2}>Top</Box> | ||
<Box marginBottom={2}>Bottom</Box> | ||
<Box marginLeft={2}>Left</Box> | ||
<Box marginRight={2}>Right</Box> | ||
<Box marginX={2}>Left and right</Box> | ||
<Box marginY={2}>Top and bottom</Box> | ||
<Box margin={2}>Top, bottom, left and right</Box> | ||
``` | ||
Component was rerendered and was written to the output. | ||
##### Flex | ||
#### State | ||
###### flexGrow | ||
Each component can have its local state accessible via `this.state`. | ||
Whenever a state updates, the component is rerendered. | ||
Type: `number` | ||
To set the initial state, extend the constructor and assign an object to `this.state`. | ||
The state is accessible via `this.state` anywhere in the component, and it's also passed to `render()` as a second argument. | ||
See [flex-grow](https://css-tricks.com/almanac/properties/f/flex-grow/). | ||
```js | ||
class Demo extends Component { | ||
constructor(props, context) { | ||
super(props, context); | ||
```jsx | ||
<Box> | ||
Label: | ||
<Box flexGrow={1}> | ||
Fills all remaining space | ||
</Box> | ||
</Box> | ||
``` | ||
this.state = { | ||
i: 0 | ||
} | ||
} | ||
###### flexShrink | ||
render(props, state) { | ||
return `Iteration ${state.i}`; | ||
} | ||
} | ||
``` | ||
Type: `number` | ||
##### setState(nextState) | ||
See [flex-shrink](https://css-tricks.com/almanac/properties/f/flex-shrink/). | ||
###### nextState | ||
```jsx | ||
<Box width={20}> | ||
<Box flexShrink={2} width={10}> | ||
Will be 1/4 | ||
</Box> | ||
<Box width={10}> | ||
Will be 3/4 | ||
</Box> | ||
</Box> | ||
``` | ||
Type: `Object` `Function` | ||
Default: `{}` | ||
###### flexDirection | ||
Set a new state and update the output. | ||
Type: `string`<br> | ||
Allowed values: `row`, `row-reverse`, `column` and `column-reverse` | ||
**Note**: `setState()` works by **extending** the state via `Object.assign()`, not replacing it with a new object. Therefore you can pass only changed values. | ||
See [flex-direction](https://css-tricks.com/almanac/properties/f/flex-direction/). | ||
```js | ||
class Demo extends Component { | ||
constructor(props, context) { | ||
super(props, context); | ||
```jsx | ||
<Box> | ||
<Box marginRight={1}>X</Box> | ||
<Box>Y</Box> | ||
</Box> | ||
// X Y | ||
this.state = { | ||
i: 0 | ||
} | ||
} | ||
<Box flexDirection="row-reverse"> | ||
<Box>X</Box> | ||
<Box marginRight={1}>Y</Box> | ||
</Box> | ||
// Y X | ||
render(props, state) { | ||
return `Iteration ${state.i}`; | ||
} | ||
<Box flexDirection="column"> | ||
<Box>X</Box> | ||
<Box>Y</Box> | ||
</Box> | ||
// X | ||
// Y | ||
componentDidMount() { | ||
this.setState({ | ||
i: this.state.i + 1 | ||
}); | ||
} | ||
} | ||
<Box flexDirection="column-reverse"> | ||
<Box>X</Box> | ||
<Box>Y</Box> | ||
</Box> | ||
// Y | ||
// X | ||
``` | ||
The above example will increment the `i` state property and render `Iteration 1` as a result. | ||
###### alignItems | ||
`setState()` also accepts a function, which receives the current state as an argument. | ||
The same effect of incrementing `i` could be achieved in a following way: | ||
Type: `string`<br> | ||
Allowed values: `flex-start`, `center` and `flex-end` | ||
```js | ||
this.setState(state => { | ||
return { | ||
i: state.i + 1 | ||
} | ||
}); | ||
``` | ||
See [align-items](https://css-tricks.com/almanac/properties/f/align-items/). | ||
This is useful when `setState()` calls are batched to ensure that you update the state in a stable way. | ||
```jsx | ||
<Box alignItems="flex-start"> | ||
<Box marginRight={1}>X</Box> | ||
<Box>{`A\nB\nC`}</Box> | ||
</Box> | ||
// X A | ||
// B | ||
// C | ||
#### Refs | ||
<Box alignItems="center"> | ||
<Box marginRight={1}>X</Box> | ||
<Box>{`A\nB\nC`}</Box> | ||
</Box> | ||
// A | ||
// X B | ||
// C | ||
Refs can be used to get a direct reference to a component instance. | ||
This is useful, if you want to access its methods, for example. | ||
<Box alignItems="flex-end"> | ||
<Box marginRight={1}>X</Box> | ||
<Box>{`A\nB\nC`}</Box> | ||
</Box> | ||
// A | ||
// B | ||
// X C | ||
``` | ||
Refs work by setting a special `ref` prop on a component. | ||
Prop's value must be a function, which receives a reference to a component as an argument or `null` when the wanted component is unmounted. | ||
###### justifyContent | ||
**Note**: You can't get refs to stateless function components. | ||
Type: `string`<br> | ||
Allowed values: `flex-start`, `center`, `flex-end`, `space-between` and `space-around`. | ||
See [justify-content](https://css-tricks.com/almanac/properties/f/justify-content/). | ||
```jsx | ||
class Child extends Component { | ||
render() { | ||
return null; | ||
} | ||
<Box justifyContent="flex-start"> | ||
<Box>X</Box> | ||
</Box> | ||
// [X ] | ||
hello() { | ||
return 'Hello World'; | ||
} | ||
} | ||
<Box justifyContent="center"> | ||
<Box>X</Box> | ||
</Box> | ||
// [ X ] | ||
class Parent extends Component { | ||
constructor(props, context) { | ||
super(props, context); | ||
<Box justifyContent="flex-end"> | ||
<Box>X</Box> | ||
</Box> | ||
// [ X] | ||
this.state = { | ||
message: 'Ink is awesome' | ||
}; | ||
} | ||
<Box justifyContent="space-between"> | ||
<Box>X</Box> | ||
<Box>Y</Box> | ||
</Box> | ||
// [X Y] | ||
render(props, state) { | ||
const setChildRef = ref => { | ||
this.childRef = ref; | ||
}; | ||
<Box justifyContent="space-around"> | ||
<Box>X</Box> | ||
<Box>Y</Box> | ||
</Box> | ||
// [ X Y ] | ||
``` | ||
return ( | ||
<div> | ||
{message} | ||
#### <Color> | ||
<Child ref={setChildRef}/> | ||
</div> | ||
) | ||
} | ||
The `<Color>` compoment is a simple wrapper around [the `chalk` API](https://github.com/chalk/chalk#api). | ||
It supports all of the chalk's methods as `props`. | ||
componentDidMount() { | ||
this.setState({ | ||
message: this.childRef.hello() | ||
}); | ||
} | ||
} | ||
``` | ||
Import: | ||
#### Context | ||
Context is like a global state for all components. | ||
Every component can access context either via `this.context` or inside `render()`: | ||
```js | ||
render(props, state, context) { | ||
// context === this.context | ||
} | ||
import {Color} from 'ink'; | ||
``` | ||
To add new entries to context, add `getChildContext()` method to your component: | ||
Usage: | ||
```js | ||
class Child extends Component { | ||
render() { | ||
return this.context.message; | ||
} | ||
} | ||
```jsx | ||
<Color rgb={[255, 255, 255]} bgKeyword="magenta"> | ||
Hello! | ||
</Color> | ||
class Parent extends Component { | ||
getChildContext() { | ||
return { | ||
message: 'Hello World' | ||
}; | ||
} | ||
<Color hex="#000000" bgHex="#FFFFFF"> | ||
Hey there | ||
</Color> | ||
render() { | ||
return <Child/>; | ||
} | ||
} | ||
<Color blue> | ||
I'm blue | ||
</Color> | ||
``` | ||
#### Stateless Function Components | ||
#### <Text> | ||
If you don't need state, lifecycle methods, context and refs, it's best to use stateless function components for their small amount of code and readability. | ||
This component can change the style of the text, make it bold, underline, italic or strikethrough. | ||
Using stateful components: | ||
Import: | ||
```js | ||
class Demo extends Component { | ||
render(props, state, context) { | ||
return 'Hello World'; | ||
} | ||
} | ||
import {Text} from 'ink'; | ||
``` | ||
Using stateless function components: | ||
##### bold | ||
```js | ||
const Demo = (props, context) => 'Hello World'; | ||
``` | ||
Type: `boolean`<br> | ||
Default: `false` | ||
As you may have noticed, stateless function components still get access to props and context. | ||
##### italic | ||
#### Built-in Components | ||
Type: `boolean`<br> | ||
Default: `false` | ||
Surprise, surprise, our favorite `<div>` and `<span>` can be used in Ink components! | ||
They are useful for grouping elements | ||
The only difference between `<div>` and `<span>` is that `<div>` inserts a newline after children. | ||
##### underline | ||
```jsx | ||
const Demo = ( | ||
<div> | ||
<A/> | ||
<B/> | ||
<C/> | ||
</div> | ||
); | ||
``` | ||
Type: `boolean`<br> | ||
Default: `false` | ||
There's also `<br/>`, which serves the same purpose as on the web - a newline. | ||
##### strikethrough | ||
Type: `boolean`<br> | ||
Default: `false` | ||
Usage: | ||
```jsx | ||
const Demo = ( | ||
<div> | ||
Line 1 | ||
<br/> | ||
Line 2 | ||
</div> | ||
); | ||
<Text bold>I am bold</Text> | ||
<Text italic>I am italic</Text> | ||
<Text underline>I am underline</Text> | ||
<Text strikethrough>I am strikethrough</Text> | ||
``` | ||
Ink also supports Fragments for returning multiple children from a component's render method. | ||
#### <StdinContext> | ||
```jsx | ||
const {h, Fragment} = require('ink'); | ||
`<StdinContext>` is a [React context](https://reactjs.org/docs/context.html#reactcreatecontext), which exposes several props. | ||
render( | ||
<Fragment> | ||
<A/> | ||
<B/> | ||
<C/> | ||
</Fragment> | ||
); | ||
Import: | ||
```js | ||
import {StdinContext} from 'ink'; | ||
``` | ||
Or using the shorthand syntax: | ||
##### stdin | ||
```jsx | ||
const {h} = require('ink'); | ||
Type: `Stream`<br> | ||
Default: `process.stdin` | ||
render( | ||
<> | ||
<A/> | ||
<B/> | ||
<C/> | ||
</> | ||
); | ||
``` | ||
Stdin stream passed to `render()` in `options.stdin` or `process.stdin` by default. | ||
Useful if your app needs to handle user input. | ||
To use the Fragments make sure you have `pragmaFrag` in your configuration: | ||
Usage: | ||
```json | ||
{ | ||
"babel": { | ||
"plugins": [ | ||
[ | ||
"@babel/plugin-transform-react-jsx", | ||
{ | ||
"pragma": "h", | ||
"pragmaFrag": "h.Fragment" | ||
} | ||
] | ||
] | ||
} | ||
} | ||
```jsx | ||
<StdinContext.Consumer> | ||
{({ stdin }) => ( | ||
<MyComponent stdin={stdin}/> | ||
)} | ||
</StdinContext.Consumer> | ||
``` | ||
You will also need [Babel v7.0.0-beta.31](https://github.com/babel/babel/releases/tag/v7.0.0-beta.31) or above, which means you will also need to upgrade any other tools that use Babel to their compatible versions, like [@babel/plugin-transform-react-jsx](https://www.npmjs.com/package/@babel/plugin-transform-react-jsx) and [@babel/core](https://www.npmjs.com/package/@babel/core). | ||
##### setRawMode | ||
The `<Color>` compoment is a simple wrapper around [the `chalk` API](https://github.com/chalk/chalk#api) it supports all of the chalk methods as `props`. | ||
Type: `function`<br> | ||
See [setRawMode](https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode). | ||
Ink exposes this function via own `<StdinContext>` to be able to handle <kbd>Ctrl</kbd>+<kbd>C</kbd>, that's why you should use Ink's `setRawMode` instead of `process.stdin.setRawMode`. | ||
Usage: | ||
```jsx | ||
import {Color} from 'ink'; | ||
<StdinContext.Consumer> | ||
{({ setRawMode }) => ( | ||
<MyComponent setRawMode={setRawMode}/> | ||
)} | ||
</StdinContext.Consumer> | ||
``` | ||
<Color rgb={[255, 255, 255]} bgKeyword="magenta"> | ||
Hello! | ||
</Color> | ||
#### <StdoutContext> | ||
<Color hex="#000000" bgHex="#FFFFFF"> | ||
Hey there | ||
</Color> | ||
`<StdoutContext>` is a [React context](https://reactjs.org/docs/context.html#reactcreatecontext), which exposes stdout stream, where Ink renders your app. | ||
Import: | ||
```js | ||
import {StdoutContext} from 'ink'; | ||
``` | ||
The `<Bold>` and `<Underline>` components render their children bolded and underlined respectively. | ||
##### stdout | ||
```jsx | ||
import {Bold, Underline} from 'ink'; | ||
Type: `Stream`<br> | ||
Default: `process.stdout` | ||
<Bold> | ||
I am bold | ||
</Bold> | ||
Usage: | ||
<Underline> | ||
I am underlined | ||
</Underline> | ||
```jsx | ||
<StdoutContext.Consumer> | ||
{({ stdout }) => ( | ||
<MyComponent stdout={stdout}/> | ||
)} | ||
</StdoutContext.Consumer> | ||
``` | ||
@@ -617,0 +620,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
43393
703
613
1
12
14
1
+ Addedcli-cursor@^2.1.0
+ Addedreact@^16.4.2
+ Addedreact-reconciler@^0.12.0
+ Addedslice-ansi@^1.0.0
+ Addedstring-length@^2.0.0
+ Addedundom@^0.4.0
+ Addedwidest-line@^2.0.0
+ Addedyoga-layout-prebuilt@^1.9.3
+ Added@types/yoga-layout@1.9.2(transitive)
+ Addedasap@2.0.6(transitive)
+ Addedastral-regex@1.0.0(transitive)
+ Addedcore-js@1.2.7(transitive)
+ Addedencoding@0.1.13(transitive)
+ Addedfbjs@0.8.18(transitive)
+ Addediconv-lite@0.6.3(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedisomorphic-fetch@2.2.1(transitive)
+ Addednode-fetch@1.7.3(transitive)
+ Addedpromise@7.3.1(transitive)
+ Addedreact@16.14.0(transitive)
+ Addedreact-reconciler@0.12.0(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsetimmediate@1.0.5(transitive)
+ Addedslice-ansi@1.0.0(transitive)
+ Addedstring-length@2.0.0(transitive)
+ Addedua-parser-js@0.7.39(transitive)
+ Addedundom@0.4.0(transitive)
+ Addedwhatwg-fetch@3.6.20(transitive)
+ Addedwidest-line@2.0.1(transitive)
+ Addedyoga-layout-prebuilt@1.10.0(transitive)
- Removedindent-string@^3.1.0
- Removedis-equal-shallow@^0.1.3
- Removedlodash.flattendeep@^4.4.0
- Removedindent-string@3.2.0(transitive)
- Removedis-equal-shallow@0.1.3(transitive)
- Removedis-primitive@2.0.0(transitive)
- Removedlodash.flattendeep@4.4.0(transitive)
Updatedchalk@^2.4.1
Updatedlog-update@^2.3.0
Updatedprop-types@^15.6.2