diff --git a/packages/js/product-editor/changelog/add-37264 b/packages/js/product-editor/changelog/add-37264 new file mode 100644 index 00000000000..cd3fe0ca148 --- /dev/null +++ b/packages/js/product-editor/changelog/add-37264 @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +The BlockIcon component diff --git a/packages/js/product-editor/src/components/block-icon/README.md b/packages/js/product-editor/src/components/block-icon/README.md new file mode 100644 index 00000000000..c224a38b0ba --- /dev/null +++ b/packages/js/product-editor/src/components/block-icon/README.md @@ -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' => '', + + // 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 ( +
+

+ + + { title } +

+ + +
+ ); +} +``` diff --git a/packages/js/product-editor/src/components/block-icon/block-icon.tsx b/packages/js/product-editor/src/components/block-icon/block-icon.tsx new file mode 100644 index 00000000000..fda5b44a7b9 --- /dev/null +++ b/packages/js/product-editor/src/components/block-icon/block-icon.tsx @@ -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 = ( + + ); + return ; + } + + if ( /^https?:\/\/(.)+/.test( src ) ) { + const iconImage = ( + + ); + return ; + } + } + + return ; +} diff --git a/packages/js/product-editor/src/components/block-icon/index.ts b/packages/js/product-editor/src/components/block-icon/index.ts new file mode 100644 index 00000000000..9e20e38d3cf --- /dev/null +++ b/packages/js/product-editor/src/components/block-icon/index.ts @@ -0,0 +1,2 @@ +export * from './block-icon'; +export * from './types'; diff --git a/packages/js/product-editor/src/components/block-icon/types.ts b/packages/js/product-editor/src/components/block-icon/types.ts new file mode 100644 index 00000000000..b1e47017faf --- /dev/null +++ b/packages/js/product-editor/src/components/block-icon/types.ts @@ -0,0 +1,3 @@ +export type BlockIconProps = { + clientId: string; +}; diff --git a/packages/js/product-editor/src/components/index.ts b/packages/js/product-editor/src/components/index.ts index 8a1005c6a43..23075d35584 100644 --- a/packages/js/product-editor/src/components/index.ts +++ b/packages/js/product-editor/src/components/index.ts @@ -15,3 +15,7 @@ export { Editor as __experimentalEditor, ProductEditorSettings, } from './editor'; +export { + BlockIcon as __experimentalBlockIcon, + BlockIconProps, +} from './block-icon'; diff --git a/packages/js/product-editor/src/components/section/block.json b/packages/js/product-editor/src/components/section/block.json index e1d8a35c111..89f8811fb0c 100644 --- a/packages/js/product-editor/src/components/section/block.json +++ b/packages/js/product-editor/src/components/section/block.json @@ -13,6 +13,9 @@ }, "description": { "type": "string" + }, + "icon": { + "type": "object" } }, "supports": { diff --git a/packages/js/product-editor/src/components/section/edit.tsx b/packages/js/product-editor/src/components/section/edit.tsx index 7a46d9ae566..369055d4a0d 100644 --- a/packages/js/product-editor/src/components/section/edit.tsx +++ b/packages/js/product-editor/src/components/section/edit.tsx @@ -3,16 +3,26 @@ */ import { createElement } from '@wordpress/element'; 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 { description, title } = attributes; return (

- { title } + + { title }

{ description } diff --git a/packages/js/product-editor/src/components/section/index.ts b/packages/js/product-editor/src/components/section/index.ts index 15144b2b28d..70224538e05 100644 --- a/packages/js/product-editor/src/components/section/index.ts +++ b/packages/js/product-editor/src/components/section/index.ts @@ -1,17 +1,28 @@ +/** + * External dependencies + */ +import { createElement } from '@wordpress/element'; +import { BlockConfiguration } from '@wordpress/blocks'; + /** * Internal dependencies */ -import initBlock from '../../utils/init-block'; -import metadata from './block.json'; +import { initBlock } from '../../utils/init-blocks'; +import blockConfiguration from './block.json'; import { Edit } from './edit'; +import { SectionBlockAttributes } from './types'; -const { name } = metadata; +const { name, ...metadata } = + blockConfiguration as BlockConfiguration< SectionBlockAttributes >; export { metadata, name }; -export const settings = { - example: {}, - edit: Edit, -}; +export const settings: Partial< BlockConfiguration< SectionBlockAttributes > > = + { + example: {}, + edit: Edit, + }; -export const init = () => initBlock( { name, metadata, settings } ); +export function init() { + return initBlock( { name, metadata, settings } ); +} diff --git a/packages/js/product-editor/src/components/section/style.scss b/packages/js/product-editor/src/components/section/style.scss index d3341c04f49..137bead30c2 100644 --- a/packages/js/product-editor/src/components/section/style.scss +++ b/packages/js/product-editor/src/components/section/style.scss @@ -7,6 +7,18 @@ font-size: 24px; font-weight: 500; 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 { diff --git a/packages/js/product-editor/src/components/section/types.ts b/packages/js/product-editor/src/components/section/types.ts new file mode 100644 index 00000000000..017ae754a7d --- /dev/null +++ b/packages/js/product-editor/src/components/section/types.ts @@ -0,0 +1,9 @@ +/** + * External dependencies + */ +import { BlockAttributes } from '@wordpress/blocks'; + +export interface SectionBlockAttributes extends BlockAttributes { + title: string; + description: string; +} diff --git a/plugins/woocommerce/changelog/add-37264 b/plugins/woocommerce/changelog/add-37264 new file mode 100644 index 00000000000..e340926e2e7 --- /dev/null +++ b/plugins/woocommerce/changelog/add-37264 @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add image configuration to the product block template diff --git a/plugins/woocommerce/includes/class-wc-post-types.php b/plugins/woocommerce/includes/class-wc-post-types.php index 5fcb68552a5..3d630729817 100644 --- a/plugins/woocommerce/includes/class-wc-post-types.php +++ b/plugins/woocommerce/includes/class-wc-post-types.php @@ -379,6 +379,9 @@ class WC_Post_Types { array( 'title' => __( 'Basic details', 'woocommerce' ), 'description' => __( 'This info will be displayed on the product page, category pages, social media, and search results.', 'woocommerce' ), + 'icon' => array( + 'src' => '', + ), ), array( array( @@ -456,6 +459,9 @@ class WC_Post_Types { 'woocommerce/product-section', array( 'title' => __( 'Shipping section', 'woocommerce' ), + 'icon' => array( + 'src' => '', + ), ), array( array(