diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 0ef6a790d1688..591e47b3b1982 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -129,6 +129,10 @@ const BlockInspectorSingleBlock = ( {
) }
+
diff --git a/packages/block-editor/src/components/inspector-controls/block-support-tools-panel.js b/packages/block-editor/src/components/inspector-controls/block-support-tools-panel.js
new file mode 100644
index 0000000000000..84db563a51acd
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/block-support-tools-panel.js
@@ -0,0 +1,76 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+import { useDispatch, useSelect } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { store as blockEditorStore } from '../../store';
+import { cleanEmptyObject } from '../../hooks/utils';
+
+const labels = {
+ border: {
+ label: __( 'Border options' ),
+ header: __( 'Border' ),
+ },
+ color: {
+ label: __( 'Color options' ),
+ header: __( 'Color' ),
+ },
+ dimensions: {
+ label: __( 'Dimensions options' ),
+ header: __( 'Dimensions' ),
+ },
+ typography: {
+ label: __( 'Typography options' ),
+ header: __( 'Typography' ),
+ },
+};
+
+export default function BlockSupportToolsPanel( { group, children } ) {
+ const { clientId, attributes } = useSelect( ( select ) => {
+ const { getBlockAttributes, getSelectedBlockClientId } = select(
+ blockEditorStore
+ );
+ const selectedBlockClientId = getSelectedBlockClientId();
+
+ return {
+ clientId: selectedBlockClientId,
+ attributes: getBlockAttributes( selectedBlockClientId ),
+ };
+ } );
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
+
+ const resetAll = ( resetFilters = [] ) => {
+ const { style } = attributes;
+ let newAttributes = { style };
+
+ resetFilters.forEach( ( resetFilter ) => {
+ newAttributes = {
+ ...newAttributes,
+ ...resetFilter( newAttributes ),
+ };
+ } );
+
+ // Enforce a cleaned style object.
+ newAttributes = {
+ ...newAttributes,
+ style: cleanEmptyObject( newAttributes.style ),
+ };
+
+ updateBlockAttributes( clientId, newAttributes );
+ };
+
+ return (
+
+ { children }
+
+ );
+}
diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js
index a989132afd4c7..40cf1d929dcfd 100644
--- a/packages/block-editor/src/components/inspector-controls/groups.js
+++ b/packages/block-editor/src/components/inspector-controls/groups.js
@@ -5,10 +5,14 @@ import { createSlotFill } from '@wordpress/components';
const InspectorControlsDefault = createSlotFill( 'InspectorControls' );
const InspectorControlsAdvanced = createSlotFill( 'InspectorAdvancedControls' );
+const InspectorControlsDimensions = createSlotFill(
+ 'InspectorDimensionsControls'
+);
const groups = {
default: InspectorControlsDefault,
advanced: InspectorControlsAdvanced,
+ dimensions: InspectorControlsDimensions,
};
export default groups;
diff --git a/packages/block-editor/src/components/inspector-controls/slot.js b/packages/block-editor/src/components/inspector-controls/slot.js
index f17714cfe41b6..104caf84012c5 100644
--- a/packages/block-editor/src/components/inspector-controls/slot.js
+++ b/packages/block-editor/src/components/inspector-controls/slot.js
@@ -7,8 +7,11 @@ import warning from '@wordpress/warning';
/**
* Internal dependencies
*/
+import BlockSupportToolsPanel from './block-support-tools-panel';
import groups from './groups';
+const blockSupportGroups = [ 'border', 'color', 'dimensions', 'typography' ];
+
export default function InspectorControlsSlot( {
__experimentalGroup: group = 'default',
bubblesVirtually = true,
@@ -26,5 +29,13 @@ export default function InspectorControlsSlot( {
return null;
}
+ if ( blockSupportGroups.includes( group ) ) {
+ return (
+
+
+
+ );
+ }
+
return ;
}
diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js
index 697955670b497..d8a0709c3055f 100644
--- a/packages/block-editor/src/hooks/dimensions.js
+++ b/packages/block-editor/src/hooks/dimensions.js
@@ -1,10 +1,7 @@
/**
* WordPress dependencies
*/
-import {
- __experimentalToolsPanel as ToolsPanel,
- __experimentalToolsPanelItem as ToolsPanelItem,
-} from '@wordpress/components';
+import { __experimentalToolsPanelItem as ToolsPanelItem } from '@wordpress/components';
import { Platform } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { getBlockSupport } from '@wordpress/blocks';
@@ -27,7 +24,6 @@ import {
resetPadding,
useIsPaddingDisabled,
} from './padding';
-import { cleanEmptyObject } from './utils';
export const SPACING_SUPPORT_KEY = 'spacing';
export const ALL_SIDES = [ 'top', 'right', 'bottom', 'left' ];
@@ -55,50 +51,48 @@ export function DimensionsPanel( props ) {
'__experimentalDefaultControls',
] );
- // Callback to reset all block support attributes controlled via this panel.
- const resetAll = () => {
- const { style } = props.attributes;
-
- props.setAttributes( {
- style: cleanEmptyObject( {
- ...style,
- spacing: {
- ...style?.spacing,
- margin: undefined,
- padding: undefined,
- },
- } ),
- } );
- };
-
return (
-
-
- { ! isPaddingDisabled && (
- hasPaddingValue( props ) }
- label={ __( 'Padding' ) }
- onDeselect={ () => resetPadding( props ) }
- isShownByDefault={ defaultSpacingControls?.padding }
- >
-
-
- ) }
- { ! isMarginDisabled && (
- hasMarginValue( props ) }
- label={ __( 'Margin' ) }
- onDeselect={ () => resetMargin( props ) }
- isShownByDefault={ defaultSpacingControls?.margin }
- >
-
-
- ) }
-
+
+ { ! isPaddingDisabled && (
+ hasPaddingValue( props ) }
+ label={ __( 'Padding' ) }
+ onDeselect={ () => resetPadding( props ) }
+ resetAllFilter={ ( newAttributes ) => ( {
+ ...newAttributes,
+ style: {
+ ...newAttributes.style,
+ spacing: {
+ ...newAttributes.style?.spacing,
+ padding: undefined,
+ },
+ },
+ } ) }
+ isShownByDefault={ defaultSpacingControls?.padding }
+ >
+
+
+ ) }
+ { ! isMarginDisabled && (
+ hasMarginValue( props ) }
+ label={ __( 'Margin' ) }
+ onDeselect={ () => resetMargin( props ) }
+ resetAllFilter={ ( newAttributes ) => ( {
+ ...newAttributes,
+ style: {
+ ...newAttributes.style,
+ spacing: {
+ ...newAttributes.style?.spacing,
+ margin: undefined,
+ },
+ },
+ } ) }
+ isShownByDefault={ defaultSpacingControls?.margin }
+ >
+
+
+ ) }
);
}
diff --git a/packages/components/src/tools-panel/test/index.js b/packages/components/src/tools-panel/test/index.js
index d371edabc8be4..d18a95dc26cba 100644
--- a/packages/components/src/tools-panel/test/index.js
+++ b/packages/components/src/tools-panel/test/index.js
@@ -316,6 +316,10 @@ describe( 'ToolsPanel', () => {
await selectMenuItem( 'Reset all' );
expect( resetAll ).toHaveBeenCalledTimes( 1 );
+ expect( controlProps.onSelect ).not.toHaveBeenCalled();
+ expect( controlProps.onDeselect ).not.toHaveBeenCalled();
+ expect( altControlProps.onSelect ).not.toHaveBeenCalled();
+ expect( altControlProps.onDeselect ).not.toHaveBeenCalled();
} );
} );
diff --git a/packages/components/src/tools-panel/tools-panel-item/hook.js b/packages/components/src/tools-panel/tools-panel-item/hook.js
index 1847f172ab790..194e4f6228cbb 100644
--- a/packages/components/src/tools-panel/tools-panel-item/hook.js
+++ b/packages/components/src/tools-panel/tools-panel-item/hook.js
@@ -18,6 +18,7 @@ export function useToolsPanelItem( props ) {
hasValue,
isShownByDefault,
label,
+ resetAllFilter,
onDeselect = () => undefined,
onSelect = () => undefined,
...otherProps
@@ -32,6 +33,7 @@ export function useToolsPanelItem( props ) {
menuItems,
registerPanelItem,
deregisterPanelItem,
+ isResetting,
} = useToolsPanelContext();
// Registering the panel item allows the panel to include it in its
@@ -41,6 +43,7 @@ export function useToolsPanelItem( props ) {
hasValue,
isShownByDefault,
label,
+ resetAllFilter,
} );
return () => deregisterPanelItem( label );
@@ -56,6 +59,10 @@ export function useToolsPanelItem( props ) {
// Determine if the panel item's corresponding menu is being toggled and
// trigger appropriate callback if it is.
useEffect( () => {
+ if ( isResetting ) {
+ return;
+ }
+
if ( isMenuItemChecked && ! isValueSet && ! wasMenuItemChecked ) {
onSelect();
}
diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.js
index f64039bb49253..57b41b6c8cc1f 100644
--- a/packages/components/src/tools-panel/tools-panel/hook.js
+++ b/packages/components/src/tools-panel/tools-panel/hook.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { useEffect, useMemo, useState } from '@wordpress/element';
+import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
/**
* Internal dependencies
@@ -21,6 +21,14 @@ export function useToolsPanel( props ) {
return cx( styles.ToolsPanel, className );
}, [ className ] );
+ const isResetting = useRef( false );
+
+ useEffect( () => {
+ if ( isResetting.current ) {
+ isResetting.current = false;
+ }
+ } );
+
// Allow panel items to register themselves.
const [ panelItems, setPanelItems ] = useState( [] );
@@ -39,6 +47,18 @@ export function useToolsPanel( props ) {
// Manage and share display state of menu items representing child controls.
const [ menuItems, setMenuItems ] = useState( {} );
+ const getResetAllFilters = () => {
+ const filters = [];
+
+ panelItems.forEach( ( item ) => {
+ if ( item.resetAllFilter ) {
+ filters.push( item.resetAllFilter );
+ }
+ } );
+
+ return filters;
+ };
+
// Setup menuItems state as panel items register themselves.
useEffect( () => {
const items = {};
@@ -62,7 +82,8 @@ export function useToolsPanel( props ) {
// Resets display of children and executes resetAll callback if available.
const resetAllItems = () => {
if ( typeof resetAll === 'function' ) {
- resetAll();
+ isResetting.current = true;
+ resetAll( getResetAllFilters() );
}
// Turn off display of all non-default items.
@@ -75,7 +96,12 @@ export function useToolsPanel( props ) {
setMenuItems( resetMenuItems );
};
- const panelContext = { menuItems, registerPanelItem, deregisterPanelItem };
+ const panelContext = {
+ menuItems,
+ registerPanelItem,
+ deregisterPanelItem,
+ isResetting: isResetting.current,
+ };
return {
...otherProps,