Draft.jsがリッチテキストを表現するために、どのようにメタデータを保持しているか実例を踏まえて解説します。(0.10時点)
Draft.jsを単純に使う分にはあまり意識する必要はありませんが、拡張して独自のstyleを表現したりするにはこの辺りを理解しておく必要があります。
データ構造
メタデータはconvertToRaw()というメソッドを使うことで取得することができます。
blocksというBlockのArrayと
entityMapというEntityのMapからできています。
export type RawDraftContentState = {
blocks: Array<RawDraftContentBlock>;
entityMap: { [key: string]: RawDraftEntity };
};
entityMapのkeyはEntityのidentifierとなります。
Block
Blockはコンテンツの一塊で、これらが集まったものが文章になるといったイメージです。HTMLでいうとパラグラフに近いです。
Blockは以下のような要素で構成されています。
export type RawDraftContentBlock = {
key: ?string;
type: DraftBlockType;
text: string;
depth: ?number;
inlineStyleRanges: ?Array<InlineStyleRange>;
entityRanges: ?Array<EntityRange>;
data?: Object;
};
- key
- blockのidentifier
- type
- Blockの種類
- デフォルトで用意されているtype
- unstyled
- paragraph
- header-one, header-two, header-three, header-four, header-five, header-six
- unordered-list-item
- ordered-list-item
- blockquote
- code-block
- atomic
- 独自のタイプを加えることも可能
- デフォルトで用意されているtype
- Blockの種類
- text
- Block内に記述されたテキスト
- depth
- unordered-list-itemやordred-list-itemでインデントしたときに使われる深さ
- inlineStyleRanges
- boldなどといったinline styleをテキストのどこに反映するかといった情報を持ったArray
- InlineStyleRange
- InlineStyleRangeはstyleとoffsetとlengthを持ち、これらの情報からどの位置にどのstyleを反映するかわかります
- InlineStyleRange
- boldなどといったinline styleをテキストのどこに反映するかといった情報を持ったArray
- entityRanges
- Entityをテキストのどこに反映するかといった情報を持ったArray
- EntityRange
- EntityRangeはkeyとoffsetとlengthを持ち、これらの情報からどの位置にどのEntityを反映するかわかります。keyはEntityのidentifierにあたります。
- EntityRange
- Entityをテキストのどこに反映するかといった情報を持ったArray
- data
- blockにメタデータを持たせたいときに使います。
Entity
Entityはテキストを装飾するのにmeta dataを必要とする場合に用います。(inline styleのようにmeta dataが必要ない、つまりtypeだけわかればよい場合はinline styleを用います)
Entityは以下のような要素で構成されています。
export type RawDraftEntity = {
type: DraftEntityType;
mutability: DraftEntityMutability;
data: ?{ [key: string]: any };
};
- type
- Entityの種類
- mutability
- Entityを適用するテキストが変更可能かどうかを示します
- MUTABLE
- IMMUTABLE
- SEGMENTED
- Entityを適用するテキストが変更可能かどうかを示します
- data
- Entityを適用するのに必要なデータをMapで保持します。
- 例えばLINKというtypeの場合だとLINKにはurlが必要なので
-
{url:
"``http://google.com``"``}
といったデータにします。
-
- 例えばLINKというtypeの場合だとLINKにはurlが必要なので
- Entityを適用するのに必要なデータをMapで保持します。
実例
Block全体のスタイルを変える場合
引用やコードブロックなどのようにBlock全体のスタイルを変更する場合のデータ構造の使われ方です。
「引用です」という文字列でできたBlockを引用にしたときのデータ構造はこのようになります。
{
"entityMap": {},
"blocks": [
{
"key": "1r71t",
"text": "引用です",
"type": "blockquote",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {}
}
]
}
blockは「引用です」というtextを持ち、typeにblockquoteeを適用するというふうに設定されています。
Blockの中の文字列の一部のスタイルを変える場合
太字や斜体などBlockの中の文字列の一部のスタイルを変える場合のデータ構造の使われ方です。
「これが太字です」という文字列の中の太字という文字に太字を設定したときのデータ構造はこのようになります。
{
"entityMap": {},
"blocks": [
{
"key": "4atgo",
"text": "これが太字です",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [
{
"offset": 3,
"length": 2,
"style": "BOLD"
}
],
"entityRanges": [],
"data": {}
}
]
}
blockは「これが太字です」というtextを持ち、inlineStyleRangeで3文字目から2文字の範囲の文字にBOLDのstyleを適用するというふうに設定されています。
また、LINKの場合はstyleだけでなくurlといった別のメタデータも必要となるのでinline styleでは対応できません。
Blockの中の文字列の一部に特殊な装飾を加える場合
LINKなどBlockの中の文字列の一部のに特殊な装飾を加える場合のデータ構造の使われ方です。
「これがLINKです」という文字列の中のLINKという文字にlinkを設定したときのデータ構造はこのようになります。
{
"entityMap": {
"0": {
"type": "LINK",
"mutability": "IMMUTABLE",
"data": {
"url": "https://google.com"
}
}
},
"blocks": [
{
"key": "4atgo",
"text": "これがLINKです",
"type": "unstyled",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [
{
"offset": 3,
"length": 4,
"key": 0
}
],
"data": {}
}
]
}
0というEntityにtypeがLINK、dataにlink先のurlが設定されています。
blockは「これがLINKです」というtextを持ち、enittyRangeで3文字目から4文字の範囲の文字をEntityの0を適用するというふうに設定されています。
Blockでテキスト以外にも情報を使って表現したい場合
文章の中に画像を入れたい場合に、Blockを画像にする場合にBlockに独自のtypeを追加してdataを用いるという方法があります。
{
"entityMap": {},
"blocks": [
{
"key": "7va9s",
"text": "",
"type": "IMAGE",
"depth": 0,
"inlineStyleRanges": [],
"entityRanges": [],
"data": {
"src": "http://example.com/images/example1.jpg"
}
},
]
}
typeにIMAGEという値を設定し、dataに画像ファイルのパスを設定しています。
これらのtypeやdataには任意の値を設定することができるので、どのようなBlockを表現したいかの用途によって決めるとよいです。これらの値を元にBlockの表示を行うCustom Blockを実装します。Custom Blockの実装方法は別の記事で説明したいと思います。