WordPressのブロック開発メモ その4 コンポーネント

前回はReactだけの知識で完結するようWordPress(Gutenberg)コアで用意されているコンポーネントの使用をさけてました。

WordPressのブロック開発メモ その3 編集

今回はGutenbergに用意されたコンポーネントを使っていきます。
かなりの量があるのでごく一部を紹介します。

StoryBookが便利です。

https://wordpress.github.io/gutenberg/?path=/story/docs-introduction–page

最低限のコンポーネントを使っていきます。

npm install --save-dev @types/wordpress__components

一旦ひな形を綺麗さっぱり余計なものを削除します。

props.ts

export default interface KurageExampleBlockProps
{

}

index.tsの一部

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {},
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};

style.cscc

.wp-block-create-block-kurage-worker {
    padding: .4em;
}

background-colorとcolorをバッサリ削除。

editor.scss

.wp-block-create-block-kurage-worker {
    border: 1px dotted #f00;
}

Button

save.tsxを編集します。

import { useBlockProps } from '@wordpress/block-editor';

import './editor.scss';
import React from 'react';
import { BlockEditProps } from '@wordpress/blocks';

import KurageExampleBlockProps from './props';
import { Button } from '@wordpress/components';

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    return (
        <div {...useBlockProps()}>

            <Button>Kurage</Button>
            <Button variant="primary">Primary</Button>
            <Button variant="link">Link</Button>
            <Button variant="secondary">Secondary</Button>
            <Button variant="tertiary">Tertiary</Button>
            <Button variant="primary" disabled>Disabled</Button>
        </div>
    );
}

ボタンの見た目を変えるにはvariantを使います。
それぞれprimary, secondary, tertiary, linkを指定します。

disabledを指定するとクリック出来ないボタンが出来ます。

TextControl, TextAreaControl

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [name, setName] = useState('');

    return (
        <div {...useBlockProps()}>
            <TextControl value={name} label="Your name" help="3文字以上で入力してください。"  onChange={value => setName(value)} />
        </div>
    );
}

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [name, setName] = useState('');

    return (
        <div {...useBlockProps()}>
            <TextareaControl
                value={name}
                label="苦情内容"
                help="100字程度で入力してください。" 
                rows={3}
                onChange={value => setName(value)} />
        </div>
    );
}

CheckboxControl, ToggleControl, RadioControl

CheckBoxControl

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [agree, setAgree] = useState(false);

    return (
        <div {...useBlockProps()}>
            <CheckboxControl
                label="同意しますか?"
                checked={agree}
                onChange={value => setAgree(value)}
                />
        </div>
    );
}

indeterminatetrueにすると不確定になるらしいですが、現段階では型定義にこのプロパティが含まれていないようです。
なので定義を生やしてます(あるいは@ts-ignoreで無視する)。

// 無理やり生やす
declare module '@wordpress/components'
{
    namespace CheckboxControl
    {
        interface Props
        {
            indeterminate: boolean;
        }
    }
}

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [agree, setAgree] = useState(false);

    return (
        <div {...useBlockProps()}>
            <CheckboxControl
                label="同意しますか?"
                indeterminate={true}
                checked={agree}
                onChange={value => setAgree(value)}
                />
        </div>
    );
}

ToggleControl

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [agree, setAgree] = useState(false);

    return (
        <div {...useBlockProps()}>
            <ToggleControl
                label="同意しますか?"
                checked={agree}
                onChange={value => setAgree(value)}
                />
        </div>
    );
}

RadioControl

const radioOptions: RadioControl.Option<string>[] = [
    { label: '勇者', value: 'yusha' },
    { label: '魔法使い', value: 'wizard' },
    { label: '戦士', value: 'warrior' },
    { label: '遊び人', value: 'neet' }
];
export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [job, setJob] = useState<string|undefined>();

    return (
        <div {...useBlockProps()}>
            <RadioControl
                label="職業は何ですか?"
                selected={job}
                options={radioOptions}
                onChange={value => setJob(value as string)}
                />
        </div>
    );
}

SelectControl, ComboBoxControl

SelectControl

リストの中から一つ選びます。

const items: SelectControl.Option[] = [
    { label: 'A', value: 'a' },
    { label: 'B', value: 'b', disabled: true },
    { label: 'C', value: 'c' },
    { label: 'D', value: 'd' },
];

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [alfabet, setAlfabet] = useState<string|undefined>('a');

    return (
        <div {...useBlockProps()}>
            <p>{alfabet}</p>
            <SelectControl
                label="アルファベットを選んでください"
                options={items}
                onChange={value => setAlfabet(value as string)}
                />
        </div>
    );
}

optionsSelectControl.Option型の配列を渡します。
disabledtrueにすると選択出来ません。

複数行の選択をするにはmultipletrueにします。
onChangeから受け取る項目が複数になる点に注意してください。

const items: SelectControl.Option[] = [
    { label: 'A', value: 'a' },
    { label: 'B', value: 'b', disabled: true },
    { label: 'C', value: 'c' },
    { label: 'D', value: 'd' },
];

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [alfabets, setAlfabets] = useState<string[]|undefined>(['a', 'c']);

    return (
        <div {...useBlockProps()}>
            <p>{alfabets?.join(',')}</p>
            <SelectControl
                label="アルファベットを選んでください"
                value={alfabets}
                multiple={true}
                options={items}
                onChange={value => setAlfabets(value as string[])}
                />
        </div>
    );
}

あれれ?

現在(2023/02/21)、表示がおかしくなる。
調べてみたらselectのサイズが30pxに設定してある。

応急処置のコードを追加してみる

.wp-block-create-block-kurage-worker {
    padding: .4em;
}

select[multiple]
{
    height: auto !important;
}

まだ不安定そう。

ComboboxControl

シングル選択のSelectControlをさらに検索できるようにした感じ。

const items: any = [
    { label: 'Apple', value: 'apple' },
    { label: 'Armond', value: 'armond' },
    { label: 'BlueBerry', value: 'blueberry' },
    { label: 'Banana', value: 'banana' },
    { label: 'Melon', value: 'melon'}
];

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [alfabet, setAlfabet] = useState<string>('apple');

    return (
        <div {...useBlockProps()}>
            <p>{alfabet}</p>
            <ComboboxControl
                label="アルファベットを選んでください"
                value={alfabet}
                options={items}
                onChange={value => setAlfabet(value as string)}
                />
        </div>
    );
}

bを入力するとBlueBerryBananaが候補に上がる。

RangeControl

範囲を指定。
例えば0から100までの範囲の入力を求めるなら、

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [power, setPower] = useState(0);

    return (
        <div {...useBlockProps()}>
            <RangeControl
                min={0}
                max={100}
                label="今のやる気は何パーセントですか?"
                value={power}
                onChange={value => setPower(value || 0)} />
        </div>
    );
}

minは最小値、maxは最大値。

そのほかにも、

step3にすると3ずつカウントする(3,6,9,…)こともできる。
withInputFieldfalseに指定すると右側のテキストを削除出来る、
はずなんだが、型定義に定義されてないようで・・・。

ColorPicker, ColorPallet

ColorPallet

カラーパレットはカラーのリストの中から選べるコンポーネントです。

const colors: ColorPalette.Color[] = [
    { name: 'Blue', color: '#0fe' },
    { name: 'Yellow', color: 'yellow' },
    { name: 'Red', color: '#f00' },
]
export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [color, setColor] = useState('green');

    return (
        <div {...useBlockProps()}>
            <ColorPalette
                colors={colors}
                value={color}
                onChange={value => setColor(value as string)}
                />
        </div>
    );
}

ColorPicker

お絵描きツールなどでよくあるグラデーションなどから色を選ぶやつです。

いろいろおかしいところがあり、ちょっと現段階で使うにはりすくありかなー?

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [color, setColor] = useState<any>();
    console.log(color)

    return (
        <div {...useBlockProps()}>
            <p>{color?.hex}</p>

            <Placeholder label='3パターンのColorPicker'>

                <ColorPicker
                    color={color}
                    onChangeComplete={value => setColor(value)}
                    />

                <ColorPicker
                    color={color}
                    onChangeComplete={value => setColor(value)}
                    />

                <ColorPicker
                    color={color}
                    onChangeComplete={value => setColor(value)}
                    />

            </Placeholder>
        </div>
    );
}

PlaceHolderの説明はいったん飛ばします。

セレクトボックスからHex, HSL, RGBをそれぞれ選択しています。

VStack/HStack

コンポーネント等を一列に整列させて表示する。
VStackは垂直に、HStackは水平にならぶ。

ただ現在(2023/02/21)実装されてない模様。

一応つかってみる。

import { useBlockProps } from '@wordpress/block-editor';
import React from 'react';
import { BlockEditProps } from '@wordpress/blocks';
import {  Button } from '@wordpress/components';

import KurageExampleBlockProps from './props';
import './editor.scss';

import {
    __experimentalVStack as VStack,
    __experimentalHStack as HStack
} from '@wordpress/components';

declare module '@wordpress/components'
{
    const __experimentalVStack: any;
    const __experimentalHStack: any;
}

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    return (
        <div {...useBlockProps()}>

            <p>垂直</p>
            <VStack>
                <Button variant="primary">AAAAAAA</Button>
                <Button variant="primary">BBBBBBB</Button>
                <Button variant="primary">CCCCCCC</Button>
                <Button variant="primary">DDDDDDD</Button>
            </VStack>

            <p>水平</p>
            <HStack>
                <Button variant="primary">AAAAAAA</Button>
                <Button variant="primary">BBBBBBB</Button>
                <Button variant="primary">CCCCCCC</Button>
                <Button variant="primary">DDDDDDD</Button>
            </HStack>

        </div>
    );
}

Placeholder

複数のコンポーネントをひとまとめに纏めときたい時とかに使う。
VStackの代わりに使ってます。

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    return (
        <div {...useBlockProps()}>
            <Placeholder label='Hello Kurage' icon="wordpress" instructions="ここに入力してね!">
                <TextControl value="えーーーーーーー" label="message" onChange={e => {}}/>
                <TextControl value="えーーーーーーー" label="message" onChange={e => {}}/>
                <TextControl value="えーーーーーーー" label="message" onChange={e => {}}/>
                <TextControl value="えーーーーーーー" label="message" onChange={e => {}}/>
                <Button variant="primary">Click me</Button>
            </Placeholder>
        </div>
    );
}

<Placeholder label='Hello Kurage' icon="wordpress" instructions="ここに入力してね!" isColumnLayout={true}>

isColumnLayouttrueにすると横に全快! 一列に並んでくれる。

Spinner

読み込み中とか、Loading… で表示するやつ。

<Spinner />

Modal

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const [isOpen, setIsOpen] = useState(false);

    const cancel = () => {
        setIsOpen(false);
    }

    const ok = () => {

        // ここで何らかの処理

        setIsOpen(false);
    }

    return (
        <div {...useBlockProps()}>
            <Button variant="primary" onClick={() => setIsOpen(true)}>Open Modal!</Button>

            { isOpen && (
                <Modal title="Hello Modal" onRequestClose={() => setIsOpen(false)}>
                    <p>ここにいろいろ表示する</p>
                    <ButtonGroup>
                        <Button variant="primary" onClick={cancel}>Cancel</Button>
                        <Button variant="primary" onClick={ok}>OK</Button>
                    </ButtonGroup>
                </Modal>
            )}
        </div>
    );
}

モーダルのバツボタンを押すとonRequestCloseイベントが発生します。
このイベントを拾ってモーダルを非表示にするようにしますが、内部のボタンからでも出来ます。

他にこれと同じようなことをするConfirmDialogがあるようですが今のところ(2023/02/21)非推奨。

Notice

お知らせ。
例えばワードプレス本体にてプラグインをインストールした時とかに「プラグインをインストールしました。」などとメッセージを表示してくれるやつのコンポーネント版的なやつ。

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    return (
        <div {...useBlockProps()}>
            <Notice>頭上に注意してください!</Notice>
        </div>
    );
}

Snackbar, SnackbarList

動作がおかしいのでパスします。

Icon

import { wordpress, alignLeft, arrowRight, backup } from '@wordpress/icons';

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    return (
        <div {...useBlockProps()}>
            <Icon icon={wordpress} />
            <Icon icon={alignLeft} />
            <Icon icon={arrowRight} />
            <Icon icon={backup} />
        </div>
    );
}

アイコン一覧はこちら。

WordPressのブロック開発メモ その4ー1 アイコン一覧

次回はツールバーとサイドバーについてです。

WordPressのブロック開発メモ その5 ツールバーとサイドバー

BlockEditor certificate css DataGrid Docker Gutenberg Hyper-V iframe MUI openssl PHP React ReduxToolkit REST ubuntu WordPress オレオレ認証局 フレームワーク