diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 0ef6a790d1688..0b15ae17665ee 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -129,6 +129,11 @@ 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..450a8351de8e3
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/block-support-tools-panel.js
@@ -0,0 +1,58 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
+import { useDispatch, useSelect } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { store as blockEditorStore } from '../../store';
+import { cleanEmptyObject } from '../../hooks/utils';
+
+export default function BlockSupportToolsPanel( { children, label, header } ) {
+ 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..4b039d35f2916 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(
+ 'InspectorControlsDimensions'
+);
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..d9dfba0af06b9 100644
--- a/packages/block-editor/src/components/inspector-controls/slot.js
+++ b/packages/block-editor/src/components/inspector-controls/slot.js
@@ -7,11 +7,13 @@ import warning from '@wordpress/warning';
/**
* Internal dependencies
*/
+import BlockSupportToolsPanel from './block-support-tools-panel';
import groups from './groups';
export default function InspectorControlsSlot( {
__experimentalGroup: group = 'default',
bubblesVirtually = true,
+ label,
...props
} ) {
const Slot = groups[ group ]?.Slot;
@@ -26,5 +28,13 @@ export default function InspectorControlsSlot( {
return null;
}
+ if ( label ) {
+ return (
+
+
+
+ );
+ }
+
return ;
}
diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js
index d85ce67104b39..9e38b6c6f0cab 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';
@@ -34,7 +31,6 @@ import {
resetPadding,
useIsPaddingDisabled,
} from './padding';
-import { cleanEmptyObject } from './utils';
export const SPACING_SUPPORT_KEY = 'spacing';
export const ALL_SIDES = [ 'top', 'right', 'bottom', 'left' ];
@@ -63,62 +59,56 @@ 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,
- blockGap: undefined,
- margin: undefined,
- padding: undefined,
- },
- } ),
- } );
- };
+ const createResetAllFilter = ( attribute ) => ( newAttributes ) => ( {
+ ...newAttributes,
+ style: {
+ ...newAttributes.style,
+ spacing: {
+ ...newAttributes.style?.spacing,
+ [ attribute ]: undefined,
+ },
+ },
+ } );
return (
-
-
- { ! isPaddingDisabled && (
- hasPaddingValue( props ) }
- label={ __( 'Padding' ) }
- onDeselect={ () => resetPadding( props ) }
- isShownByDefault={ defaultSpacingControls?.padding }
- >
-
-
- ) }
- { ! isMarginDisabled && (
- hasMarginValue( props ) }
- label={ __( 'Margin' ) }
- onDeselect={ () => resetMargin( props ) }
- isShownByDefault={ defaultSpacingControls?.margin }
- >
-
-
- ) }
- { ! isGapDisabled && (
- hasGapValue( props ) }
- label={ __( 'Block gap' ) }
- onDeselect={ () => resetGap( props ) }
- isShownByDefault={ defaultSpacingControls?.blockGap }
- >
-
-
- ) }
-
+
+ { ! isPaddingDisabled && (
+ hasPaddingValue( props ) }
+ label={ __( 'Padding' ) }
+ onDeselect={ () => resetPadding( props ) }
+ resetAllFilter={ createResetAllFilter( 'padding' ) }
+ isShownByDefault={ defaultSpacingControls?.padding }
+ panelId={ props.clientId }
+ >
+
+
+ ) }
+ { ! isMarginDisabled && (
+ hasMarginValue( props ) }
+ label={ __( 'Margin' ) }
+ onDeselect={ () => resetMargin( props ) }
+ resetAllFilter={ createResetAllFilter( 'margin' ) }
+ isShownByDefault={ defaultSpacingControls?.margin }
+ panelId={ props.clientId }
+ >
+
+
+ ) }
+ { ! isGapDisabled && (
+ hasGapValue( props ) }
+ label={ __( 'Block gap' ) }
+ onDeselect={ () => resetGap( props ) }
+ resetAllFilter={ createResetAllFilter( 'blockGap' ) }
+ isShownByDefault={ defaultSpacingControls?.blockGap }
+ panelId={ props.clientId }
+ >
+
+
+ ) }
);
}
diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.js
index 13adb434e4276..02e0d23f3f4a5 100644
--- a/packages/components/src/tools-panel/tools-panel/hook.js
+++ b/packages/components/src/tools-panel/tools-panel/hook.js
@@ -22,6 +22,17 @@ export function useToolsPanel( props ) {
}, [ className ] );
const isResetting = useRef( false );
+ const wasResetting = isResetting.current;
+
+ // `isResetting` is cleared via this hook to effectively batch together
+ // the resetAll task. Without this, the flag is cleared after the first
+ // control updates and forces a rerender with subsequent controls then
+ // believing they need to reset, unfortunately using stale data.
+ useEffect( () => {
+ if ( wasResetting ) {
+ isResetting.current = false;
+ }
+ }, [ wasResetting ] );
// Allow panel items to register themselves.
const [ panelItems, setPanelItems ] = useState( [] );
@@ -104,12 +115,6 @@ export function useToolsPanel( props ) {
isResetting: isResetting.current,
};
- // Clean up isResetting after advising panel context we were resetting
- // all controls. This lets panel items know to skip onDeselect callbacks.
- if ( isResetting.current ) {
- isResetting.current = false;
- }
-
return {
...otherProps,
panelContext,
diff --git a/packages/edit-site/src/components/sidebar/dimensions-panel.js b/packages/edit-site/src/components/sidebar/dimensions-panel.js
index 72059768b3018..23dc23599af5d 100644
--- a/packages/edit-site/src/components/sidebar/dimensions-panel.js
+++ b/packages/edit-site/src/components/sidebar/dimensions-panel.js
@@ -140,11 +140,7 @@ export default function DimensionsPanel( { context, getStyle, setStyle } ) {
};
return (
-
+
{ showPaddingControl && (