Skip to content

Commit

Permalink
Wrap block support slots in ToolsPanel for dimensions support
Browse files Browse the repository at this point in the history
Draft wrapping block support slots in ToolsPanel

Update tests to check resetAll does not trigger onDeselect
  • Loading branch information
aaronrobertshaw committed Aug 20, 2021
1 parent 83bc87e commit 7c23fd8
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 51 deletions.
4 changes: 4 additions & 0 deletions packages/block-editor/src/components/block-inspector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ const BlockInspectorSingleBlock = ( {
</div>
) }
<InspectorControls.Slot bubblesVirtually={ bubblesVirtually } />
<InspectorControls.Slot
__experimentalGroup="dimensions"
bubblesVirtually={ false }
/>
<div>
<AdvancedControls bubblesVirtually={ bubblesVirtually } />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<ToolsPanel
label={ labels[ group ].label }
header={ labels[ group ].header }
resetAll={ resetAll }
>
{ children }
</ToolsPanel>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
11 changes: 11 additions & 0 deletions packages/block-editor/src/components/inspector-controls/slot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -26,5 +29,13 @@ export default function InspectorControlsSlot( {
return null;
}

if ( blockSupportGroups.includes( group ) ) {
return (
<BlockSupportToolsPanel group={ group }>
<Slot { ...props } bubblesVirtually={ bubblesVirtually } />
</BlockSupportToolsPanel>
);
}

return <Slot { ...props } bubblesVirtually={ bubblesVirtually } />;
}
90 changes: 42 additions & 48 deletions packages/block-editor/src/hooks/dimensions.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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' ];
Expand Down Expand Up @@ -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 (
<InspectorControls key="dimensions">
<ToolsPanel
label={ __( 'Dimensions options' ) }
header={ __( 'Dimensions' ) }
resetAll={ resetAll }
>
{ ! isPaddingDisabled && (
<ToolsPanelItem
hasValue={ () => hasPaddingValue( props ) }
label={ __( 'Padding' ) }
onDeselect={ () => resetPadding( props ) }
isShownByDefault={ defaultSpacingControls?.padding }
>
<PaddingEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isMarginDisabled && (
<ToolsPanelItem
hasValue={ () => hasMarginValue( props ) }
label={ __( 'Margin' ) }
onDeselect={ () => resetMargin( props ) }
isShownByDefault={ defaultSpacingControls?.margin }
>
<MarginEdit { ...props } />
</ToolsPanelItem>
) }
</ToolsPanel>
<InspectorControls __experimentalGroup="dimensions">
{ ! isPaddingDisabled && (
<ToolsPanelItem
hasValue={ () => hasPaddingValue( props ) }
label={ __( 'Padding' ) }
onDeselect={ () => resetPadding( props ) }
resetAllFilter={ ( newAttributes ) => ( {
...newAttributes,
style: {
...newAttributes.style,
spacing: {
...newAttributes.style?.spacing,
padding: undefined,
},
},
} ) }
isShownByDefault={ defaultSpacingControls?.padding }
>
<PaddingEdit { ...props } />
</ToolsPanelItem>
) }
{ ! isMarginDisabled && (
<ToolsPanelItem
hasValue={ () => hasMarginValue( props ) }
label={ __( 'Margin' ) }
onDeselect={ () => resetMargin( props ) }
resetAllFilter={ ( newAttributes ) => ( {
...newAttributes,
style: {
...newAttributes.style,
spacing: {
...newAttributes.style?.spacing,
margin: undefined,
},
},
} ) }
isShownByDefault={ defaultSpacingControls?.margin }
>
<MarginEdit { ...props } />
</ToolsPanelItem>
) }
</InspectorControls>
);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/components/src/tools-panel/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
} );
} );

Expand Down
7 changes: 7 additions & 0 deletions packages/components/src/tools-panel/tools-panel-item/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function useToolsPanelItem( props ) {
hasValue,
isShownByDefault,
label,
resetAllFilter,
onDeselect = () => undefined,
onSelect = () => undefined,
...otherProps
Expand All @@ -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
Expand All @@ -41,6 +43,7 @@ export function useToolsPanelItem( props ) {
hasValue,
isShownByDefault,
label,
resetAllFilter,
} );

return () => deregisterPanelItem( label );
Expand All @@ -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();
}
Expand Down
32 changes: 29 additions & 3 deletions packages/components/src/tools-panel/tools-panel/hook.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
import { useEffect, useMemo, useState } from '@wordpress/element';
import { useEffect, useMemo, useRef, useState } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -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( [] );

Expand All @@ -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 = {};
Expand All @@ -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.
Expand All @@ -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,
Expand Down

0 comments on commit 7c23fd8

Please sign in to comment.