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 && (