Gutenberg/日記004
ブロックの入れ子
前回、オリジナルのブロックを作ってみて、また、実際の記事編集に使ってみて、「なんかこれじゃない」感が湧いてきました。ブロック要素をガツガツつなげて、簡単編集を目指していたのに、求めるブロックができてないのです。
<section class="wrap">
<div class="inner">
<h3>見出し</h3>
<p>本文1</p>
<p>本文2</p>
</div>
</section>
↑多分、今自分に必要だったのは、こういうブロックがガツガツつなげられて、中に「見出し」や「本文」を自由に足していける構造になっていることなのです。前回作成したRichTextを使ったブロックは簡単な装飾はできるものの、
タグが一つ中に入れられるだけのものでしかありませんでした。もっと複雑な構造になることも想定されますが、それはどのように解決してばいいのか、しばらく検索エンジンとにらめっこしていました。そこで出た結論は、
- 見出しや本文を入力するh3要素やp要素用にブロックをいちいち作成するのではなく、既存のブロックを使う。
- 大事なのはそのブロックを囲むコンテナ役のブロックではなかろうか。
ということでした。Wordpressにプリセットされている段落ブロックは思っていたよりも優秀で、ヘッディング要素(h1,h2,h3...)をコピペしたらちゃんとブロックが見出し用のものに自動的に変換されてくれました。これを内包できる、入れ子にできるコンテナ役のブロックができるのかな、と調べていたらどうやらできるとのことでした。
const { InnerBlocks } = wp.editor;
その正体はInnerBlocksというコンポーネントでした。これがまさに子ブロックのコンテナ役となります。リッチテキストエディタ同様、wp.editorに属するコンポーネントとのことで、他にも便利なものが多く眠っている予感がしますね。
edit: function( props ) {
const { className } = props;
return (
<div className={className}>
<InnerBlocks />
</div>
);
},
save: function( props ) {
return (
<section className="wrap">
<div class="inner">
<InnerBlocks.Content />
</div>
</section>
);
}
editメソッドとsaveメソッドはこんな感じに定義しました。これだけでsection.wrapタグとdiv.innerタグの皮を被った子ブロックを持つコンテナブロックができあがります。ちなみに一回躓いた点として、section要素にclass属性をつけて使ってみたら「不正な内容が含まれます」的なエラーメッセージが出て、ちゃんと使えませんでした。内容を確認してみると
<section class="wrap" class="amy-block">
<div class="inner">
</div>
</section>
こんな感じで、sectionタグにclass属性が二つついてしまっていました。Gutenbergではsaveメソッドに明示的に指定しなくても、勝手にルート要素にそのブロックを示すclass名が付加されるのだそうです。明示的にルート要素にclass属性をつけていると、class属性が二つになっちゃうみたいでした。解決方法としてはclass属性の代わりにclassName属性を付けてあげるといいようです。よく知らないのですが、これはReactあたりのお作法なのかもしれません。
さて、一応目的が達成されたのでめでたしめでたしなのですが、実際に記事編集画面でこの入れ子ブロックを使ってみると、「親ブロックの上にブロックを追加する」と「子ブロックの上にブロックを追加する」のUIがちょっとわかりにくいかなぁという印象を持ちました。ブロックの上をマウスオーバーすると、+マークがでてきて、それを押すとブロックが追加されるのですが、DOMツリーのどこにブロックが増えるのかちょっとわかりませんでした。(子ブロックの上に増えたかな)自分は内容を詳細に確認できるからいいとして、納品したお客さんがこの操作に手こずるような気がしますね。おいおい改良されていくのでしょうか。