tl;dr
strategy で 正規表現でヒットさせて、ヒットした部分を component で置き換える。正規表現と色の組み合わせは一般化できるので、そこまでやってみた。
最小コード
@mizchi みたいにユーザー名に色を付ける
decorators/username-decorator.js
import {CompositeDecorator} from "draft-js";
const USERNAME_REGEX = /\@[\w]+/g;
export default new CompositeDecorator([
{
strategy(contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = USERNAME_REGEX.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
},
component(props) {
return <span {...props} style={styles.handle}>{props.children}</span>;
},
},
]);
const styles = {
handle: {
color: "rgba(98, 177, 254, 1.0)",
direction: "ltr",
unicodeBidi: "bidi-override",
}
};
使う
components/my-editor.js
import {Component} from "react";
import {Editor, EditorState} from "draft-js";
import usernameDecorator from "../decorators/tweet-decorator";
export default class MyEditor extends Component {
constructor() {
super();
this.state = {
editorState: EditorState.createEmpty(usernameDecorator),
};
}
onChange(editorState) {
this.setState({editorState});
}
render() {
return (
<Editor
editorState={this.state.editorState}
onChange={this.onChange.bind(this)}
ref="editor"
/>
);
}
}
動きました
一般化する
任意の正規表現でヒットしたものをハイライトするのを一般化するとこうなる。
import {CompositeDecorator} from "draft-js";
const HIGHLIGHT_RULES = [
{
regex: /\@[\w]+/g,
color: "rgb(98, 177, 254)"
},
{
regex: /\#[\w]+/g,
color: "rgb(95, 184, 138)"
}
];
export default new CompositeDecorator(HIGHLIGHT_RULES.map(rule => (
{
strategy(contentBlock, callback) {
const text = contentBlock.getText();
let matchArr, start;
while ((matchArr = rule.regex.exec(text)) !== null) {
start = matchArr.index;
callback(start, start + matchArr[0].length);
}
},
component(props) {
return <span {...props} style={{
color: rule.color,
direction: "ltr",
unicodeBidi: "bidi-override",
}}>{props.children}</span>;
},
}
)));
まだ使い込んでないんで色々と引数を足したくなるだろうが、そのうちライブラリに切り出す。
特定の構文下でルールを変える、といった拡張が考えられる。