Commit 782059ce41 for woocommerce
commit 782059ce41997a152637524b1a9e8752fdc2d292
Author: Amit Raj <77401999+amitraj2203@users.noreply.github.com>
Date: Thu Jan 15 13:58:53 2026 +0530
Refactor Product Elements Blocks to use ToolsPanel (#62712)
* Refactor WidthPanel to use ToolsPanel in Button block
* Refactor Edit component to use ToolsPanel in Image block
* Refactor TitleEdit component to use ToolsPanel in Title block
* Add changelog file
* Set default linkTarget to '_self' in TitleEdit component
* Fix lint error
diff --git a/plugins/woocommerce/changelog/59464-use-toolspanel-in-product-elements-blocks b/plugins/woocommerce/changelog/59464-use-toolspanel-in-product-elements-blocks
new file mode 100644
index 0000000000..79a38acfca
--- /dev/null
+++ b/plugins/woocommerce/changelog/59464-use-toolspanel-in-product-elements-blocks
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Removes PanelBody and uses ToolsPanel for Button, Image and Title blocks
diff --git a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/button/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/button/edit.tsx
index 2e403d7562..6d1e8ccb30 100644
--- a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/button/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/button/edit.tsx
@@ -2,12 +2,6 @@
* External dependencies
*/
import clsx from 'clsx';
-import {
- Disabled,
- Button,
- ButtonGroup,
- PanelBody,
-} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
AlignmentToolbar,
@@ -19,6 +13,15 @@ import type { BlockEditProps } from '@wordpress/blocks';
import { useEffect } from '@wordpress/element';
import { ProductQueryContext as Context } from '@woocommerce/blocks/product-query/types';
import { useProduct } from '@woocommerce/entities';
+import {
+ Disabled,
+ Button,
+ ButtonGroup,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanel as ToolsPanel,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanelItem as ToolsPanelItem,
+} from '@wordpress/components';
/**
* Internal dependencies
@@ -26,6 +29,10 @@ import { useProduct } from '@woocommerce/entities';
import Block from './block';
import { BlockAttributes } from './types';
+const DEFAULT_ATTRIBUTES = {
+ width: undefined,
+};
+
function WidthPanel( {
selectedWidth,
setAttributes,
@@ -42,26 +49,40 @@ function WidthPanel( {
}
return (
- <PanelBody title={ __( 'Width settings', 'woocommerce' ) }>
- <ButtonGroup aria-label={ __( 'Button width', 'woocommerce' ) }>
- { [ 25, 50, 75, 100 ].map( ( widthValue ) => {
- return (
- <Button
- key={ widthValue }
- isSmall
- variant={
- widthValue === selectedWidth
- ? 'primary'
- : undefined
- }
- onClick={ () => handleChange( widthValue ) }
- >
- { widthValue }%
- </Button>
- );
- } ) }
- </ButtonGroup>
- </PanelBody>
+ <ToolsPanel
+ label={ __( 'Width settings', 'woocommerce' ) }
+ resetAll={ () =>
+ setAttributes( { width: DEFAULT_ATTRIBUTES.width } )
+ }
+ >
+ <ToolsPanelItem
+ label={ __( 'Button width', 'woocommerce' ) }
+ hasValue={ () => selectedWidth !== DEFAULT_ATTRIBUTES.width }
+ onDeselect={ () =>
+ setAttributes( { width: DEFAULT_ATTRIBUTES.width } )
+ }
+ isShownByDefault
+ >
+ <ButtonGroup aria-label={ __( 'Button width', 'woocommerce' ) }>
+ { [ 25, 50, 75, 100 ].map( ( widthValue ) => {
+ return (
+ <Button
+ key={ widthValue }
+ isSmall
+ variant={
+ widthValue === selectedWidth
+ ? 'primary'
+ : undefined
+ }
+ onClick={ () => handleChange( widthValue ) }
+ >
+ { widthValue }%
+ </Button>
+ );
+ } ) }
+ </ButtonGroup>
+ </ToolsPanelItem>
+ </ToolsPanel>
);
}
diff --git a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/edit.tsx
index fc20e50d8b..b042678c9c 100644
--- a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/image/edit.tsx
@@ -20,7 +20,6 @@ import { isBoolean } from '@woocommerce/types';
import type { BlockEditProps } from '@wordpress/blocks';
import { ProductQueryContext as Context } from '@woocommerce/blocks/product-query/types';
import {
- PanelBody,
ToggleControl,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
@@ -30,6 +29,10 @@ import {
// @ts-ignore - Ignoring because `__experimentalToggleGroupControl` is not yet in the type definitions.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanel as ToolsPanel,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
/**
@@ -49,6 +52,11 @@ const TEMPLATE = [
],
];
+const DEFAULT_ATTRIBUTES = {
+ showProductLink: true,
+ imageSizing: ImageSizing.SINGLE,
+};
+
const Edit = ( {
attributes,
setAttributes,
@@ -137,63 +145,103 @@ const Edit = ( {
height={ height }
setAttributes={ setAttributes }
/>
- <PanelBody title={ __( 'Content', 'woocommerce' ) }>
- <ToggleControl
+ <ToolsPanel
+ label={ __( 'Content', 'woocommerce' ) }
+ resetAll={ () =>
+ setAttributes( {
+ showProductLink:
+ DEFAULT_ATTRIBUTES.showProductLink,
+ imageSizing: DEFAULT_ATTRIBUTES.imageSizing,
+ } )
+ }
+ >
+ <ToolsPanelItem
label={ __(
'Link to Product Page',
'woocommerce'
) }
- help={ __(
- 'Links the image to the single product listing.',
- 'woocommerce'
- ) }
- checked={ showProductLink }
- onChange={ () =>
+ hasValue={ () =>
+ showProductLink !==
+ DEFAULT_ATTRIBUTES.showProductLink
+ }
+ onDeselect={ () =>
setAttributes( {
- showProductLink: ! showProductLink,
+ showProductLink:
+ DEFAULT_ATTRIBUTES.showProductLink,
} )
}
- />
- <ToggleGroupControl
+ isShownByDefault
+ >
+ <ToggleControl
+ label={ __(
+ 'Link to Product Page',
+ 'woocommerce'
+ ) }
+ help={ __(
+ 'Links the image to the single product listing.',
+ 'woocommerce'
+ ) }
+ checked={ showProductLink }
+ onChange={ () =>
+ setAttributes( {
+ showProductLink: ! showProductLink,
+ } )
+ }
+ />
+ </ToolsPanelItem>
+ <ToolsPanelItem
label={ __( 'Resolution', 'woocommerce' ) }
- isBlock
- help={
- ! isBlockTheme
- ? createInterpolateElement(
- __(
- 'Product image cropping can be modified in the <a>Customizer</a>.',
- 'woocommerce'
- ),
- {
- a: (
- // eslint-disable-next-line jsx-a11y/anchor-has-content
- <a
- href={ `${ getAdminLink(
- 'customize.php'
- ) }?autofocus[panel]=woocommerce&autofocus[section]=woocommerce_product_images` }
- target="_blank"
- rel="noopener noreferrer"
- />
- ),
- }
- )
- : null
+ hasValue={ () =>
+ imageSizing !== DEFAULT_ATTRIBUTES.imageSizing
}
- value={ imageSizing }
- onChange={ ( value: ImageSizing ) =>
- setAttributes( { imageSizing: value } )
+ onDeselect={ () =>
+ setAttributes( {
+ imageSizing: DEFAULT_ATTRIBUTES.imageSizing,
+ } )
}
+ isShownByDefault
>
- <ToggleGroupControlOption
- value={ ImageSizing.SINGLE }
- label={ __( 'Full Size', 'woocommerce' ) }
- />
- <ToggleGroupControlOption
- value={ ImageSizing.THUMBNAIL }
- label={ __( 'Thumbnail', 'woocommerce' ) }
- />
- </ToggleGroupControl>
- </PanelBody>
+ <ToggleGroupControl
+ label={ __( 'Resolution', 'woocommerce' ) }
+ isBlock
+ help={
+ ! isBlockTheme
+ ? createInterpolateElement(
+ __(
+ 'Product image cropping can be modified in the <a>Customizer</a>.',
+ 'woocommerce'
+ ),
+ {
+ a: (
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
+ <a
+ href={ `${ getAdminLink(
+ 'customize.php'
+ ) }?autofocus[panel]=woocommerce&autofocus[section]=woocommerce_product_images` }
+ target="_blank"
+ rel="noopener noreferrer"
+ />
+ ),
+ }
+ )
+ : null
+ }
+ value={ imageSizing }
+ onChange={ ( value: ImageSizing ) =>
+ setAttributes( { imageSizing: value } )
+ }
+ >
+ <ToggleGroupControlOption
+ value={ ImageSizing.SINGLE }
+ label={ __( 'Full Size', 'woocommerce' ) }
+ />
+ <ToggleGroupControlOption
+ value={ ImageSizing.THUMBNAIL }
+ label={ __( 'Thumbnail', 'woocommerce' ) }
+ />
+ </ToggleGroupControl>
+ </ToolsPanelItem>
+ </ToolsPanel>
</InspectorControls>
) }
<Block
diff --git a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/title/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/title/edit.tsx
index 3753a3cee6..a7d87d3d56 100644
--- a/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/title/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/atomic/blocks/product-elements/title/edit.tsx
@@ -2,7 +2,6 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
-import { Disabled, PanelBody, ToggleControl } from '@wordpress/components';
import {
InspectorControls,
BlockControls,
@@ -10,6 +9,14 @@ import {
useBlockProps,
} from '@wordpress/block-editor';
import HeadingToolbar from '@woocommerce/editor-components/heading-toolbar';
+import {
+ Disabled,
+ ToggleControl,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanel as ToolsPanel,
+ // eslint-disable-next-line @wordpress/no-unsafe-wp-apis
+ __experimentalToolsPanelItem as ToolsPanelItem,
+} from '@wordpress/components';
/**
* Internal dependencies
@@ -23,6 +30,11 @@ interface Props {
setAttributes: ( attributes: Record< string, unknown > ) => void;
}
+const DEFAULT_ATTRIBUTES = {
+ showProductLink: true,
+ linkTarget: '_self',
+};
+
const TitleEdit = ( { attributes, setAttributes }: Props ): JSX.Element => {
const blockProps = useBlockProps();
const { headingLevel, showProductLink, align, linkTarget } = attributes;
@@ -46,18 +58,52 @@ const TitleEdit = ( { attributes, setAttributes }: Props ): JSX.Element => {
/>
</BlockControls>
<InspectorControls>
- <PanelBody title={ __( 'Link settings', 'woocommerce' ) }>
- <ToggleControl
+ <ToolsPanel
+ label={ __( 'Link settings', 'woocommerce' ) }
+ resetAll={ () =>
+ setAttributes( {
+ showProductLink: DEFAULT_ATTRIBUTES.showProductLink,
+ linkTarget: DEFAULT_ATTRIBUTES.linkTarget,
+ } )
+ }
+ >
+ <ToolsPanelItem
label={ __( 'Make title a link', 'woocommerce' ) }
- checked={ showProductLink }
- onChange={ () =>
+ hasValue={ () =>
+ showProductLink !==
+ DEFAULT_ATTRIBUTES.showProductLink
+ }
+ onDeselect={ () =>
setAttributes( {
- showProductLink: ! showProductLink,
+ showProductLink:
+ DEFAULT_ATTRIBUTES.showProductLink,
} )
}
- />
+ isShownByDefault
+ >
+ <ToggleControl
+ label={ __( 'Make title a link', 'woocommerce' ) }
+ checked={ showProductLink }
+ onChange={ () =>
+ setAttributes( {
+ showProductLink: ! showProductLink,
+ } )
+ }
+ />
+ </ToolsPanelItem>
{ showProductLink && (
- <>
+ <ToolsPanelItem
+ label={ __( 'Open in new tab', 'woocommerce' ) }
+ hasValue={ () =>
+ linkTarget !== DEFAULT_ATTRIBUTES.linkTarget
+ }
+ onDeselect={ () =>
+ setAttributes( {
+ linkTarget: DEFAULT_ATTRIBUTES.linkTarget,
+ } )
+ }
+ isShownByDefault
+ >
<ToggleControl
label={ __( 'Open in new tab', 'woocommerce' ) }
onChange={ ( value ) =>
@@ -67,9 +113,9 @@ const TitleEdit = ( { attributes, setAttributes }: Props ): JSX.Element => {
}
checked={ linkTarget === '_blank' }
/>
- </>
+ </ToolsPanelItem>
) }
- </PanelBody>
+ </ToolsPanel>
</InspectorControls>
<Disabled>
<Block { ...attributes } />