RichTextToolbarButtonは要素のClassを見ないか?

registerFormatTypeで設定しているClassまで見ないようです。
問題の動作と対策をまとめてみました。

注意

記事執筆当時のWordPress5.0.3時点で、発生している仕様です。今後どうなるかは解りません。

問題はどう言うものなのか?

キタジマさん制作のSnow Monkey Blocksでは蛍光ペンと言うのが存在します。
RichTextの要素、つまり入力している文字に対して、このようにマーカーを引くことが出来ると言った便利な機能です。

この蛍光ペンの機能は、RichTextToolbarButtonによって、上記のようなボタンを押す事で選択されている文字に<span class=”smb-highlighter”>と言うspan要素を適用しているようです。

しかし、同時に<span>などで囲ってしまうと、問題が起こります。
蛍光ペンで無いのに蛍光ペンのように表示される、またはコードエディタからビジュアルエディタに切り替えた際に「このブロックでエラーが発生したためプレビューできません。」と表示される…などの問題が生じるようです。

なぜ問題が起こる?

Snow Monkey Blocksだけ入れている場合は、蛍光ペンで無いのに蛍光ペンのように表示されてしまうようです。
Advanced Rich Text Tools for Gutenbergも入れている場合、「このブロックでエラーが発生したためプレビューできません。」と表示されるようになります。
Advanced Rich Text Tools for Gutenbergだけの場合は該当の問題は生じません。

となると、原因として、RichTextToolbarButtonでのActive判定は、registerFormatTypeのclassまで見ていないと言うことになるのではないかと思われます。

どう言うことかと言いますと、
RichTextToolbarButtonは、フォーカスが変更される度に、フォーカスのエリアを毎回判定し、Activeかどうかを取得して、ボタンの表示を変える仕組みが備わっています。その判定にclassまでを判定していない…と言う事です。

問題のケースでは、spanタグを使っている所にフォーカスが当たる事で、RichTextToolbarButtonの蛍光ペンとしてのActive状態を判定しようとしますが、正しい書式(class=”smb-highlighter”)じゃない…ので、判定がtrueとなるが、他のspanのFormatと競合してエラーが出てしまう…と言ったところでしょうか?

Snow Monkey Blocksだけ入れている場合は、蛍光ペンで無いのに蛍光ペンのように表示されてしまうのは競合するFormatが他にないからですね。
Advanced Rich Text Tools for Gutenbergも入れている場合、エラーとなるのはAdvanced Rich Text Tools for Gutenbergにspanでのテキストカラーや背景色を変更する仕組みが備わっている為、そちらと競合してしまう為でしょう。

問題の対策を考える

要は、RichTextToolbarButtonでclass付けをしなければ、Active状態の判定はしなくなるので、競合などのエラー問題は解決するのではないかと思ってます。
なので、Snow Monkey Blocksの蛍光ペンであれば、下記のようにAdvanced Rich Text Tools for Gutenbergと同じような感じで、サイドの設定(インスペクター)にしてあげれば良いと思います。

対策のコード

上記の事を実装する場合のコードを書いてみました。
Snow Monkey Blocksの場合、src/js/_highlighter.js が対象です。(対応される場合は、上書きとなります)

注意

Snow Monkey Blocksのバージョンは執筆当時の 3.0.5 で確認しています。

'use strict';

const { registerFormatType, applyFormat, removeFormat } = wp.richText;
const { InspectorControls, ColorPalette } = wp.editor;
const { PanelBody, Button } = wp.components;
const { __ } = wp.i18n;

const name = 'snow-monkey-blocks/highlighter';

registerFormatType( name, {
	title: __( 'Highlighter', 'snow-monkey-blocks' ),
	tagName: 'span',
	className: 'smb-highlighter',
	attributes: {
		style: 'style',
	},
	edit( { value, onChange } ) {
		let activeColor;
		return (
			<InspectorControls>
				<PanelBody title={ __( 'Highlighter', 'snow-monkey-blocks' ) }>
					<Button
						isDefault={ true }
						isSmall={ true }
						onClick={ () => {
							onChange( applyFormat( value, { type: name } ) );
						} }
					>
						{ __( 'Default color', 'snow-monkey-blocks' ) }
					</Button>
					<ColorPalette
						className="editor-color-palette-control__color-palette"
						value={ activeColor }
						onChange={ ( color ) => {
							if ( color ) {
								const red = parseInt( color.substring( 1, 3 ), 16 );
								const green = parseInt( color.substring( 3, 5 ), 16 );
								const blue = parseInt( color.substring( 5, 7 ), 16 );
								onChange( applyFormat( value, {
									type: name,
									attributes: {
										style: `background:linear-gradient(transparent 60%, rgba(${ red }, ${ green }, ${ blue }, .7) 60%);`,
									},
								} ) );
								return;
							}
							onChange( removeFormat( value, name ) );
						} }
					/>
				</PanelBody>
			</InspectorControls>
		);
	},
} );

こんな感じでしょうか?

対策の問題

RichTextToolbarButtonのように、効果が当たっている場合、ボタンがアクティブになると言うものでもありません。
何の効果が当たっているのか解らないので、その不親切さに対しての対応も考えなければならないと思います。

追加(手順まとめ)

別記事に画像などで手順をまとめてみました。

この記事を書いた人

kmix-39

kmix-39

主に日本の関西に出没する。
小学時代にWindows 95に触れ、BASICを始めて以来、HTML、Perl、Java(JSP, Servlet)、COBOL、C++、C#、PHP、Objective-C、Swift…と、数々の言語を地獄の現場を経験しながら覚えていった元IT社畜。
「好きな時に 好きなことを 好きなだけ」をしたい。