Add icon support to product section block (#37340)
* Add block icon component * Use the block icon component within the section block * Add changelog file * Fix rebase conflicts * Remove icon configuration from the client side * Change the BlockIcon component to get the icon from the attributes first and then from the metadata * Expose the BlockIcon to be used outside of the package * Add the BlockIcon documentation * Configure the block to support the new icon via attributes * Set the icon to the block section in the server template definition * Revert back index.tsx -> index.ts in the section block * Fix php linter errors * Add changelog file * Fix php linter error * Return null instead of a Fragment
This commit is contained in:
parent
de111c1edb
commit
a5b104eaed
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
The BlockIcon component
|
|
@ -0,0 +1,72 @@
|
||||||
|
# BlockIcon
|
||||||
|
|
||||||
|
This component uses the icon defined as a block attribute or metadata and renders it.
|
||||||
|
|
||||||
|
It looks first within the block's `attributes` and if there is no icon defined there, then looks at the block's `metadata`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Icon configuration
|
||||||
|
|
||||||
|
1. As a block attribute
|
||||||
|
|
||||||
|
In the block configuration file `./block.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
"attributes": {
|
||||||
|
"icon": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the server during the template configuration
|
||||||
|
|
||||||
|
```php
|
||||||
|
array(
|
||||||
|
'woocommerce/product-section', // Block name
|
||||||
|
array(
|
||||||
|
// Block attributes
|
||||||
|
'icon' => array(
|
||||||
|
// It's possible to pass a valid html string
|
||||||
|
'src' => '<svg ... />',
|
||||||
|
|
||||||
|
// Or an absolute url
|
||||||
|
'src' => 'https://...',
|
||||||
|
'alt' => 'The alt name for the icon',
|
||||||
|
|
||||||
|
// Or a Dashicon icon-key
|
||||||
|
'src' => 'default-block',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
// Inner blocks
|
||||||
|
),
|
||||||
|
),
|
||||||
|
```
|
||||||
|
|
||||||
|
2. As part of the block's metadata
|
||||||
|
|
||||||
|
See [the official blocks icon documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#icon).
|
||||||
|
|
||||||
|
### Rendering the Icon
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { __experimentalBlockIcon as BlockIcon } from '@woocommerce/product-editor';
|
||||||
|
|
||||||
|
export function BlockEdit( { clientId } ) {
|
||||||
|
const blockProps = useBlockProps();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div { ...blockProps }>
|
||||||
|
<h2>
|
||||||
|
<BlockIcon clientId={ clientId } />
|
||||||
|
|
||||||
|
<span>{ title }</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<InnerBlocks />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { BlockIcon as BaseBlockIcon } from '@wordpress/block-editor';
|
||||||
|
import { Block } from '@wordpress/blocks';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
|
import { createElement, RawHTML } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { BlockIconProps } from './types';
|
||||||
|
|
||||||
|
export function BlockIcon( { clientId }: BlockIconProps ) {
|
||||||
|
const icon = useSelect(
|
||||||
|
( select ) => {
|
||||||
|
// Try to get the icon from the block's attributes
|
||||||
|
const { getBlockAttributes, getBlockName } =
|
||||||
|
select( 'core/block-editor' );
|
||||||
|
const attributes = getBlockAttributes( clientId );
|
||||||
|
if ( attributes?.icon ) {
|
||||||
|
return attributes.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no icon defined in attributes
|
||||||
|
// Then try to get icon from block's metadata
|
||||||
|
const { getBlockType } = select( 'core/blocks' );
|
||||||
|
const blockName = getBlockName( clientId );
|
||||||
|
const block = getBlockType< Block >( blockName );
|
||||||
|
return block?.icon;
|
||||||
|
},
|
||||||
|
[ clientId ]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! icon ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeof icon === 'object' ) {
|
||||||
|
const { src, ...iconProps } = icon;
|
||||||
|
|
||||||
|
if ( /^<(.)+>$/.test( src ) ) {
|
||||||
|
const iconComponent = (
|
||||||
|
<RawHTML aria-hidden="true" { ...iconProps }>
|
||||||
|
{ src }
|
||||||
|
</RawHTML>
|
||||||
|
);
|
||||||
|
return <BaseBlockIcon icon={ iconComponent } showColors />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( /^https?:\/\/(.)+/.test( src ) ) {
|
||||||
|
const iconImage = (
|
||||||
|
<img
|
||||||
|
src={ src }
|
||||||
|
alt=""
|
||||||
|
aria-hidden="true"
|
||||||
|
{ ...iconProps }
|
||||||
|
height={ 24 }
|
||||||
|
width={ 24 }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return <BaseBlockIcon icon={ iconImage } showColors />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return <BaseBlockIcon icon={ icon } showColors />;
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './block-icon';
|
||||||
|
export * from './types';
|
|
@ -0,0 +1,3 @@
|
||||||
|
export type BlockIconProps = {
|
||||||
|
clientId: string;
|
||||||
|
};
|
|
@ -15,3 +15,7 @@ export {
|
||||||
Editor as __experimentalEditor,
|
Editor as __experimentalEditor,
|
||||||
ProductEditorSettings,
|
ProductEditorSettings,
|
||||||
} from './editor';
|
} from './editor';
|
||||||
|
export {
|
||||||
|
BlockIcon as __experimentalBlockIcon,
|
||||||
|
BlockIconProps,
|
||||||
|
} from './block-icon';
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"supports": {
|
"supports": {
|
||||||
|
|
|
@ -3,16 +3,26 @@
|
||||||
*/
|
*/
|
||||||
import { createElement } from '@wordpress/element';
|
import { createElement } from '@wordpress/element';
|
||||||
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
|
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
|
||||||
import type { BlockAttributes } from '@wordpress/blocks';
|
import type { BlockEditProps } from '@wordpress/blocks';
|
||||||
|
|
||||||
export function Edit( { attributes }: { attributes: BlockAttributes } ) {
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { SectionBlockAttributes } from './types';
|
||||||
|
import { BlockIcon } from '../block-icon';
|
||||||
|
|
||||||
|
export function Edit( {
|
||||||
|
attributes,
|
||||||
|
clientId,
|
||||||
|
}: BlockEditProps< SectionBlockAttributes > ) {
|
||||||
const blockProps = useBlockProps();
|
const blockProps = useBlockProps();
|
||||||
const { description, title } = attributes;
|
const { description, title } = attributes;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div { ...blockProps }>
|
<div { ...blockProps }>
|
||||||
<h2 className="wp-block-woocommerce-product-section__title">
|
<h2 className="wp-block-woocommerce-product-section__title">
|
||||||
{ title }
|
<BlockIcon clientId={ clientId } />
|
||||||
|
<span>{ title }</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="wp-block-woocommerce-product-section__description">
|
<p className="wp-block-woocommerce-product-section__description">
|
||||||
{ description }
|
{ description }
|
||||||
|
|
|
@ -1,17 +1,28 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { createElement } from '@wordpress/element';
|
||||||
|
import { BlockConfiguration } from '@wordpress/blocks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import initBlock from '../../utils/init-block';
|
import { initBlock } from '../../utils/init-blocks';
|
||||||
import metadata from './block.json';
|
import blockConfiguration from './block.json';
|
||||||
import { Edit } from './edit';
|
import { Edit } from './edit';
|
||||||
|
import { SectionBlockAttributes } from './types';
|
||||||
|
|
||||||
const { name } = metadata;
|
const { name, ...metadata } =
|
||||||
|
blockConfiguration as BlockConfiguration< SectionBlockAttributes >;
|
||||||
|
|
||||||
export { metadata, name };
|
export { metadata, name };
|
||||||
|
|
||||||
export const settings = {
|
export const settings: Partial< BlockConfiguration< SectionBlockAttributes > > =
|
||||||
example: {},
|
{
|
||||||
edit: Edit,
|
example: {},
|
||||||
};
|
edit: Edit,
|
||||||
|
};
|
||||||
|
|
||||||
export const init = () => initBlock( { name, metadata, settings } );
|
export function init() {
|
||||||
|
return initBlock( { name, metadata, settings } );
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,18 @@
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: $gray-900;
|
color: $gray-900;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.block-editor-block-icon {
|
||||||
|
margin-right: 14px;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__description {
|
&__description {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { BlockAttributes } from '@wordpress/blocks';
|
||||||
|
|
||||||
|
export interface SectionBlockAttributes extends BlockAttributes {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add image configuration to the product block template
|
|
@ -379,6 +379,9 @@ class WC_Post_Types {
|
||||||
array(
|
array(
|
||||||
'title' => __( 'Basic details', 'woocommerce' ),
|
'title' => __( 'Basic details', 'woocommerce' ),
|
||||||
'description' => __( 'This info will be displayed on the product page, category pages, social media, and search results.', 'woocommerce' ),
|
'description' => __( 'This info will be displayed on the product page, category pages, social media, and search results.', 'woocommerce' ),
|
||||||
|
'icon' => array(
|
||||||
|
'src' => '<svg xmlns="http://www.w3.org/2000/svg" view-box="0 0 24 24"><path fill-rule="evenodd" d="M5 5.5h14a.5.5 0 01.5.5v1.5a.5.5 0 01-.5.5H5a.5.5 0 01-.5-.5V6a.5.5 0 01.5-.5zM4 9.232A2 2 0 013 7.5V6a2 2 0 012-2h14a2 2 0 012 2v1.5a2 2 0 01-1 1.732V18a2 2 0 01-2 2H6a2 2 0 01-2-2V9.232zm1.5.268V18a.5.5 0 00.5.5h12a.5.5 0 00.5-.5V9.5h-13z" clip-rule="evenodd" /></svg>',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
|
@ -456,6 +459,9 @@ class WC_Post_Types {
|
||||||
'woocommerce/product-section',
|
'woocommerce/product-section',
|
||||||
array(
|
array(
|
||||||
'title' => __( 'Shipping section', 'woocommerce' ),
|
'title' => __( 'Shipping section', 'woocommerce' ),
|
||||||
|
'icon' => array(
|
||||||
|
'src' => '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 7.75C3.5 6.7835 4.2835 6 5.25 6H14.75H15.5V6.75V9H17.25H17.5607L17.7803 9.21967L20.7803 12.2197L21 12.4393V12.75V14.75C21 15.7165 20.2165 16.5 19.25 16.5H19.2377C19.2458 16.5822 19.25 16.6656 19.25 16.75C19.25 18.1307 18.1307 19.25 16.75 19.25C15.3693 19.25 14.25 18.1307 14.25 16.75C14.25 16.6656 14.2542 16.5822 14.2623 16.5H14H10.2377C10.2458 16.5822 10.25 16.6656 10.25 16.75C10.25 18.1307 9.13071 19.25 7.75 19.25C6.36929 19.25 5.25 18.1307 5.25 16.75C5.25 16.6656 5.25418 16.5822 5.26234 16.5H4.25H3.5V15.75V7.75ZM14 15V9.75V9V7.5H5.25C5.11193 7.5 5 7.61193 5 7.75V15H5.96464C6.41837 14.5372 7.05065 14.25 7.75 14.25C8.44935 14.25 9.08163 14.5372 9.53536 15H14ZM18.5354 15H19.25C19.3881 15 19.5 14.8881 19.5 14.75V13.0607L16.9393 10.5H15.5V14.5845C15.8677 14.3717 16.2946 14.25 16.75 14.25C17.4493 14.25 18.0816 14.5372 18.5354 15ZM6.7815 16.5C6.76094 16.5799 6.75 16.6637 6.75 16.75C6.75 17.3023 7.19772 17.75 7.75 17.75C8.30228 17.75 8.75 17.3023 8.75 16.75C8.75 16.6637 8.73906 16.5799 8.7185 16.5C8.60749 16.0687 8.21596 15.75 7.75 15.75C7.28404 15.75 6.89251 16.0687 6.7815 16.5ZM15.7815 16.5C15.7609 16.5799 15.75 16.6637 15.75 16.75C15.75 17.3023 16.1977 17.75 16.75 17.75C17.3023 17.75 17.75 17.3023 17.75 16.75C17.75 16.6637 17.7391 16.5799 17.7185 16.5C17.7144 16.4841 17.7099 16.4683 17.705 16.4526C17.5784 16.0456 17.1987 15.75 16.75 15.75C16.284 15.75 15.8925 16.0687 15.7815 16.5Z" fill="#1E1E1E"/></svg>',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
|
|
Loading…
Reference in New Issue