ブロックに色の設定を追加するときは withColors が便利!

ColorGradientSettingsDropdown

ブロックに色の設定を追加したいときってありますよね。色の設定を追加するときは ColorGradientSettingsDropdown コンポーネントを使うのが簡単です。

こんな感じで使用できます。

block.json

{
	...省略...
	attributes: {
		"iconColor": {
			"type": "string"
		}
	},
	...省略...
}

Edit コンポーネント

import {
	InspectorControls,
	useBlockProps,
	useInnerBlocksProps,
	__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
	__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
} from '@wordpress/block-editor';

import { __ } from '@wordpress/i18n';

function Edit( { attributes, setAttributes, clientId } ) {
	const { iconColor } = attributes;

	const blockProps = useBlockProps();
	const innerBlocksProps = useInnerBlocksProps( blockProps );

	return (
		<>
			<InspectorControls group="color">
				<ColorGradientSettingsDropdown
					__experimentalIsRenderedInSidebar
					settings={ [
						{
							label: __( 'Icon Color' ),
							colorValue: iconColor,
							onColorChange: ( newValue ) => {
								setAttributes( {
									iconColor: newValue,
								} );
							},
						},
					] }
					panelId={ clientId }
					{ ...useMultipleOriginColorsAndGradients() }
					gradients={ [] }
					disableCustomGradients
				/>
			</InspectorControls>

			<div { ...innerBlocksProps } />
		</>
	);
}

export default Edit;

ColorGradientSettingsDropdown は、クリックするとカラーパレットが表示され、色を選ぶと attributes.iconColor にその色が保存されます。

この初期バージョンの問題点

ここで、例えば theme.json で下記のようなカラーパレットが定義されていたとします。

{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"settings": {
		"color": {
			"palette": [
				{
					"slug": "my-accent",
					"color": "#f00",
					"name": "My アクセントカラー"
				}
			]
		}
	}
}

そして、ColorGradientSettingsDropdown で「My アクセントカラー」を選択したとします。すると、attributes.iconColor には #f00 が保存されます。まーこれでも良いっちゃ良いのですが、例えば後で「My アクセントカラー」の色を #000 から変更したいと思い、theme.json を変更し、#00f にしたとします。そしたら、既にブロックに設定済みの「My アクセントカラー」も自動的に #00f になって欲しいですよね?

でも、残念ながらそうはなりません…(TT)
なぜならば、attributes.iconColor にはそのまま #f00 というカラーコードが保存されてしまっているからです。

例えば保存されるのがカラーコードではなく、my-accent のような色のスラッグであれば、カラーコードが直接保存されているわけではないので、裏で WordPress がよしなにやってくれます。実際、コアの文字色や背景色の設定ではそのようなスラッグが保存されるようになっています。

じゃあカラーコードではなくてスラッグで保存してみようとなるわけですが、そのためには onColorChange のときに渡ってきた値(カラーコード)を、カラーパレットの各色と比較して、カラーパレットに定義されている色なのか、それとも独自に入力されたカラーコードなのかを判別し、もしカラーパレットに定義されている色なのであればスラッグを取得する、という処理が必要になります。……めんどい……。

withColors を使ってみる

そういう色々な面倒をよしなに処理してくれるのが withColors という高階コンポーネントです。

block.json の変更

withColors を使う場合、attributes の調整が必要になります。色の attribute の名前が iconColor だとしたら、前に custom を付けた customIconColor を追加します。

{
	...省略...
	attributes: {
		"iconColor": {
			"type": "string"
		},
		"customIconColor": {
			"type": "string"
		}
	},
	...省略...
}

Edit コンポーネントの変更

withColors は高階コンポーネントなので Edit コンポーネントをラップする形で使用します。ラップすると、Editpropsattributes.iconColor の代わりに使用する props.iconColor と、setAttributes の変わりに使用する props.setIconColor が追加されます。

props.iconColor はオブジェクトで、下記のようなデータが格納されます。

// カラーパレットの色を選択した場合
{
	class: "has-my-accent-color",
	color: "#00f",
	name: "My アクセントカラー",
	slug: "unitone-dark-red"
}

// カラーコードを入力した場合
{
	class: undefined,
	color: "#881616"
}

では、先程のコードを withColors を使った形に変更してみます。

import {
	InspectorControls,
	useBlockProps,
	useInnerBlocksProps,
	withColors,
	__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
	__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
} from '@wordpress/block-editor';

import { __ } from '@wordpress/i18n';

function Edit( { clientId, iconColor, setIconColor } ) {
	const blockProps = useBlockProps();
	const innerBlocksProps = useInnerBlocksProps( blockProps );

	return (
		<>
			<InspectorControls group="color">
				<ColorGradientSettingsDropdown
					__experimentalIsRenderedInSidebar
					settings={ [
						{
							label: __( 'Icon Color' ),
							colorValue: iconColor.color,
							onColorChange: setIconColor,
						},
					] }
					panelId={ clientId }
					{ ...useMultipleOriginColorsAndGradients() }
					gradients={ [] }
					disableCustomGradients
				/>
			</InspectorControls>

			<div { ...innerBlocksProps } />
		</>
	);
}

// キーに attribute の名前、値にコンテキストなオブジェクトを引数として渡す。
// コンテキストは文字色として使うなら color、背景色として使うなら background-color を指定する。
export default withColors( {
	iconColor: 'color',
} )( Edit ); // Edit コンポーネントをラップ

これでカラーピッカーで規定の色を選択した場合は attributes.iconColor に色のスラッグ(ここでは my-accent)が、規定の色から選択せずにカラーコードを入力した場合は attributes.customIconColor にカラーコードが保存されるようになります。

後は props.iconColor.class があるときはそれを className に追加すれば自動的に文字色として反映されるようになりますし、あるいは props.iconColor.slug を使って var(--wp--preset--color--${ props.iconColor.slug } )style に追加しても良いですし、好きな形で反映させれば OK です。

inc2734のアバター

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です