admin管理员组文章数量:1290263
I have a custom block that has block variations. If I make the scope of the variations "inserter", they work as expected. But if I make the scope "block" and use BlockVariationPicker so the user chooses a variation upon adding a block (like they do when adding the core columns block), nothing happens when I click on a variation icon.
I assume it's because I need onSelect added, but I'm not sure what to do.
Register block:
import { __ } from "@wordpress/i18n";
import { registerBlockType } from "@wordpress/blocks";
import "./style.scss";
import Edit from "./edit";
import save from "./save";
registerBlockType("create-block/variation", {
edit: Edit,
save,
});
My variations:
const variations = [
{
name: "one-column",
title: __("One Column"),
description: __("One column"),
icon: "palmtree",
innerBlocks: [["core/paragraph"]],
scope: ["inserter"],
},
{
name: "two-columns",
title: __("Two Column"),
description: __("Two columns"),
icon: "palmtree",
// isDefault: true,
innerBlocks: [["core/paragraph"], ["core/paragraph"]],
scope: ["inserter"],
},
];
export default variations;
My edit.js
import { __ } from "@wordpress/i18n";
import {
useBlockProps,
__experimentalBlockVariationPicker as BlockVariationPicker,
} from "@wordpress/block-editor";
import variations from "./variations";
import "./editor.scss";
export default function Edit() {
return (
<div {...useBlockProps()}>
<BlockVariationPicker
variations={variations}
label={__("Menu Columns")}
instructions={__("Choose how many menu columns")}
/>
</div>
);
}
What do I need to add to make it so when the user clicks on the variation it's entered in the editor? This is what it looks like when I add my block, but nothing happens when I click.
I have a custom block that has block variations. If I make the scope of the variations "inserter", they work as expected. But if I make the scope "block" and use BlockVariationPicker so the user chooses a variation upon adding a block (like they do when adding the core columns block), nothing happens when I click on a variation icon.
I assume it's because I need onSelect added, but I'm not sure what to do.
Register block:
import { __ } from "@wordpress/i18n";
import { registerBlockType } from "@wordpress/blocks";
import "./style.scss";
import Edit from "./edit";
import save from "./save";
registerBlockType("create-block/variation", {
edit: Edit,
save,
});
My variations:
const variations = [
{
name: "one-column",
title: __("One Column"),
description: __("One column"),
icon: "palmtree",
innerBlocks: [["core/paragraph"]],
scope: ["inserter"],
},
{
name: "two-columns",
title: __("Two Column"),
description: __("Two columns"),
icon: "palmtree",
// isDefault: true,
innerBlocks: [["core/paragraph"], ["core/paragraph"]],
scope: ["inserter"],
},
];
export default variations;
My edit.js
import { __ } from "@wordpress/i18n";
import {
useBlockProps,
__experimentalBlockVariationPicker as BlockVariationPicker,
} from "@wordpress/block-editor";
import variations from "./variations";
import "./editor.scss";
export default function Edit() {
return (
<div {...useBlockProps()}>
<BlockVariationPicker
variations={variations}
label={__("Menu Columns")}
instructions={__("Choose how many menu columns")}
/>
</div>
);
}
What do I need to add to make it so when the user clicks on the variation it's entered in the editor? This is what it looks like when I add my block, but nothing happens when I click.
Share Improve this question edited Jun 17, 2021 at 15:05 Elizabeth asked Jun 16, 2021 at 22:27 ElizabethElizabeth 3772 silver badges13 bronze badges2 Answers
Reset to default 2I assume it's because I need onSelect added, but I'm not sure what to do.
What do I need to add to make it so when the user clicks on the variation it's entered in the editor?
One way, is add a variation
attribute to your block type, then change the attribute value in the onSelect
callback of the variation picker. That in turn will instruct React to re-render the block (because the block state has changed), hence on that render, we no longer display the variation picker. So basically, the picker is "closed". :)
See example below where the block type renders a simple button with two variations — with an icon, and without it.
// File: index.js
import { registerBlockType } from '@wordpress/blocks';
import {
useBlockProps,
__experimentalBlockVariationPicker as BlockVariationPicker,
} from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
const variations = [{
name: 'button-with-icon',
title: 'Button + Text + Icon',
icon: 'button',
scope: [ 'block' ],
attributes: { icon: 'heart' },
}, {
name: 'button-without-icon',
title: 'Button + Text only',
icon: 'button',
scope: [ 'block' ],
}];
registerBlockType( 'my-blocks/foo-button', {
apiVersion: 2,
title: 'Foo Button',
category: 'formatting',
attributes: {
icon: {
type: 'string',
default: '',
},
variation: {
type: 'string',
default: '',
},
},
edit( { attributes, setAttributes } ) {
if ( ! attributes.variation ) {
return (
<div { ...useBlockProps() }>
<BlockVariationPicker
variations={ variations }
label="Button Variant"
onSelect={ ( variation = variations[0] ) => {
setAttributes( {
...variation.attributes,
variation: variation.name,
});
}}
/>
</div>
);
}
return (
<div { ...useBlockProps() }>
<Button
text="Foo Button"
icon={ attributes.icon }
/>
</div>
);
},
save: ( { attributes } ) => (
<div { ...useBlockProps.save() }>
<Button
text="Foo Button"
icon={ attributes.icon }
/>
</div>
),
} );
However, in the case of inner blocks, you would want to use the same approach as used by the core Columns block (see source on GitHub), where it checks if the current block contains any inner blocks and if yes, the inner blocks are displayed; otherwise, the variation picker is then displayed.
Here's a full working example you can try where I used the same variations in your variations.js
file:
// File: index.js
import {
registerBlockType,
createBlocksFromInnerBlocksTemplate,
} from '@wordpress/blocks';
import {
useBlockProps,
__experimentalUseInnerBlocksProps as useInnerBlocksProps,
store as blockEditorStore,
__experimentalBlockVariationPicker as BlockVariationPicker,
InnerBlocks,
} from '@wordpress/block-editor';
import { useDispatch, useSelect } from '@wordpress/data';
import variations from './variations';
// Note that you can do EditContainer( props ) or EditContainer( { attributes, etc } ).
function EditContainer() {
const blockProps = useBlockProps();
const innerBlocksProps = useInnerBlocksProps( blockProps, {
//allowedBlocks: ALLOWED_BLOCKS,
orientation: 'horizontal',
renderAppender: false,
} );
return <div { ...innerBlocksProps } />;
}
function Placeholder( { clientId, setAttributes } ) {
// Always set a default variation, particularly if allowing skipping the variation picker.
const defaultVariation = variations[0];
// Or do something like this, which selects the variation having "isDefault: true":
// const defaultVariation = variations.filter( item => item.isDefault )[0] || variations[0];
const { replaceInnerBlocks } = useDispatch( blockEditorStore );
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<BlockVariationPicker
label="Section Variant"
variations={ variations }
onSelect={ ( variation = defaultVariation ) => {
if ( variation.attributes ) {
setAttributes( variation.attributes );
}
if ( variation.innerBlocks ) {
replaceInnerBlocks(
clientId,
createBlocksFromInnerBlocksTemplate(
variation.innerBlocks
),
true
);
}
} }
allowSkip
/>
</div>
);
}
const Edit = ( props ) => {
const { clientId } = props;
const hasInnerBlocks = useSelect(
( select ) =>
select( blockEditorStore ).getBlocks( clientId ).length > 0,
[ clientId ]
);
const Component = hasInnerBlocks
? EditContainer // display the inner blocks
: Placeholder; // or the variation picker
return <Component { ...props } />;
};
registerBlockType( 'my-blocks/foo-section', {
apiVersion: 2,
title: 'Foo Section',
category: 'layout',
edit: Edit,
save: () => (
<div { ...useBlockProps.save( { className: 'foo-section' } ) }>
<InnerBlocks.Content />
</div>
),
} );
So try that and just let me know if you have questions regarding the code. :)
*This is a supplemental answer to the accepted answer, so to OP, take this as a supplemental vitamin to the main one as prescribed by the doctor... :p
So in reply to your comment:
Is it possible to have additional elements in there? I have RichText and InspectorControls. From what I can tell, the
return <div { ...innerBlocksProps } />;
can't have anything added to it.
Yes, it is possible:
Firstly, define our imports:
import { useBlockProps, __experimentalUseInnerBlocksProps as useInnerBlocksProps, store as blockEditorStore, __experimentalBlockVariationPicker as BlockVariationPicker, InnerBlocks, // add these lines: InspectorControls, RichText, } from '@wordpress/block-editor'; // and also this: import { PanelBody, TextControl } from '@wordpress/components';
Change the
EditContainer()
function so that it includes theInspectorControls
andRichText
elements — the inspector control (which in my code below, has just a plain simple text box) will be displayed in the sidebar, whereas the rich text will be placed above the inner blocks (as defined via the specific variation):function EditContainer() { const blockProps = useBlockProps(); const innerBlocksProps = useInnerBlocksProps( {}, { //allowedBlocks: ALLOWED_BLOCKS, orientation: 'horizontal', renderAppender: false, } ); // *This line is just for demonstration, and so does the onChange callback below. // In actual implementation, you'd want to set the data via the block attributes. const [ foo, setFoo ] = wp.element.useState( 'bar baz' ); return ( <div { ...blockProps }> <InspectorControls> <PanelBody> <TextControl label="Foo Input" value={ foo } onChange={ ( value ) => setFoo( value ) } /> </PanelBody> </InspectorControls> <RichText value={ foo } onChange={ ( value ) => setFoo( value ) } /> <div { ...innerBlocksProps } /> </div> ); }
So the main thing you need to know is, I use a div to wrap the inspector controls, rich text and also inner blocks. Therefore, I used the
blockProps
with that div and notuseInnerBlocksProps
.In the
save
function, though, it will be up to you on how you want to output the rich text and the input value (i.e. the value of "Foo Input" above).
And if everything went well, you'd see something like so:
本文标签: How to select block variation from BlockVariationPicker
版权声明:本文标题:How to select block variation from BlockVariationPicker 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741495023a2381799.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论