概要
react-blessedは、Reactのblessed.js向けのrendererです。
blessed.jsのウィジェットを、Reactのコンポーネントを使用して描画することができます。
ターミナル上で動作するアプリを作成する際に便利そうだったため、使ってみました。
動作環境
- Ubuntu 18.04
- Node.js 8.11.4
- blessed 0.18.1
- react-blessed 0.3.0
- Babel 7
インストール
$ yarn add blessed react react-blessed
$ yarn add @babel/cli @babel/core @babel/plugin-transform-react-jsx @babel/plugin-transform-modules-commonjs @babel/plugin-proposal-class-properties --dev
Hello world
ビルド設定
.babelrcに必要な設定を記述します
{
"plugins": [
["@babel/plugin-transform-react-jsx"],
["@babel/plugin-transform-modules-commonjs"],
["@babel/plugin-proposal-class-properties"]
]
}
ソースコード
import React, { Component } from 'react';
import blessed from 'blessed';
import { render } from 'react-blessed';
class App extends Component {
render() {
// blessed.jsのBoxを描画する
return (
<box
width='100%'
height='10%'
border={{ type: 'line' }}
style={{ border: { fg: '#888' } }}>
Hello, world
</box>
);
}
}
const screen = blessed.screen({
autopadding: true,
smartCSR: true,
title: 'Test',
fullUnicode: true,
});
// Escapeキーで終了
screen.key(['escape'], (ch, key) => {
process.exit(0);
});
render(<App></App>, screen);
ビルド
ビルドする際は、package.jsonにスクリプトを記述しておくとよいと思います。
ウォッチしたい場合は、--watch
をつけます。
"scripts": {
"build": "babel src --out-dir lib"
}
$ yarn run build
実行
$ node ./lib/index.js
Hello, worldが画面に出力されると思います。
Escapeキーを押すと、終了します。
tags
blessed.jsのタグを利用する際は、要素に対してtags属性を指定します。
その際に、タグを含むテキストを子として指定するのではなく、
content属性に指定する必要があります。
class App extends Component {
render() {
// <text tags>{'{green-fg}{bold}Hello, world{/bold}{/green-fg}'</text>
// ↑だと、タグが解釈されない
return (
<text
tags
content={'{green-fg}{bold}Hello, world{/bold}{/green-fg}'}>
</text>
);
}
}
refs
react-dom同様、ref属性が使えます。
class App extends Component {
constructor(props) {
super(props);
this.state = {
selectedUser: ''
};
}
componentDidMount() {
// コンポーネントに対する参照
this.refs.userList.focus();
}
onUserSelected(item) {
this.setState({ selectedUser: item.content });
}
render() {
return (
<box height='40%' border={{ type: 'line' }}>
<box height='10%'>{'selected: ' + this.state.selectedUser}</box>
<box top='10%' height='20%'>
<UserList
ref='userList'
onUserSelected={this.onUserSelected.bind(this)}
users={['hoge', 'fuga', 'piyo']}>
</UserList>
</box>
</box>
);
}
}
class UserList extends Component {
focus() {
// blessed.jsのNodeに対する参照
this.refs.list.focus();
}
render() {
const { users, onUserSelected } = this.props;
return (
<list
ref='list'
onSelect={onUserSelected}
items={['hoge', 'fuga', 'piyo']}
style={{
selected: {
bg: '#373b41',
fg: '#c5c8c6'
}
}}
vi
keys>
</list>
);
}
}
ref
属性を指定した要素は、コンポーネントのrefs
プロパティから参照することができます。
prop-types
import PropTypes from 'prop-types';
class UserList extends Component {
static propTypes = {
users: PropTypes.func.isRequired,
onUserSelected: PropTypes.func.isRequired
};
...
}
neo-blessed
blessed.js自体は、現在、あまりメンテナンスされていないようです。
そのため、neo-blessedというfork版が存在します。
react-blessedからneo-blessedを利用する際は、以下の設定を記述します。
import blessed from 'neo-blessed';
import {createBlessedRenderer} from 'react-blessed';
const render = createBlessedRenderer(blessed);
...
render(<App></App>, screen);
ユニットテスト
Enzymeやreact-testing-library等のライブラリは、現在のところ対応していません。
react-test-rendererを使うとよいのだろうか?
import test from 'tape';
import ShallowRenderer from 'react-test-renderer/shallow';
import ChatMessage from './ChatMessage';
test('/components/ChatMessage', assert => {
const renderer = new ShallowRenderer();
const output = renderer.render(
<ChatMessage
top={0}
height={20}
width='100%'
content='{bold}hoge{/bold}'>
</ChatMessage>
);
assert.equal(
output.props.content,
'{bold}hoge{/bold}',
'should have content'
);
assert.end();
});