From ab8a0379bb76bd3ddb3180fb181af89dd0f76aef Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Fri, 13 Aug 2021 15:05:53 +1000 Subject: [PATCH] Initial implementation of SlotFill for DimensionControls This will allow for ad hoc controls to be injected by blocks into the dimensions block support panel. --- packages/block-editor/README.md | 4 + .../components/dimension-controls/README.md | 45 +++++++++++ .../components/dimension-controls/index.js | 18 +++++ packages/block-editor/src/components/index.js | 1 + packages/block-editor/src/hooks/dimensions.js | 74 +++++++++++++------ .../src/tools-panel/tools-panel-item/hook.js | 2 + .../src/tools-panel/tools-panel/hook.js | 10 ++- 7 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 packages/block-editor/src/components/dimension-controls/README.md create mode 100644 packages/block-editor/src/components/dimension-controls/index.js diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 4dc58c54807546..f7f42f685c0c47 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -315,6 +315,10 @@ _Returns_ Undocumented declaration. +### DimensionControls + +Undocumented declaration. + ### FontSizePicker Undocumented declaration. diff --git a/packages/block-editor/src/components/dimension-controls/README.md b/packages/block-editor/src/components/dimension-controls/README.md new file mode 100644 index 00000000000000..e86dfa0b09fd73 --- /dev/null +++ b/packages/block-editor/src/components/dimension-controls/README.md @@ -0,0 +1,45 @@ +# DimensionControls + +Dimension controls appear under the dimensions block support panel in post +settings sidebar when a block is being edited. `DimensionControls` allow for +blocks to group their own dimensions related controls along side those provided +via block supports. + +The dimensions panel is built via the `ToolsPanel` component. Block's can also +add their controls to the `ToolsPanel` menu by wrapping them in a +`ToolsPanelItem` component and providing the required callbacks. + +## Usage + +```js +import { DimensionsControls } from '@wordpress/block-editor'; +import { + TextControl, + __experimentalToolsPanelItem as ToolsPanelItem, +} from '@wordpress/components'; + +function MyBlockEdit( props ) { + const { attributes, setAttributes } = props; + + return ( + + !! attributes.myValue } + label={ __( 'My dimension control' ) } + onDeselect={ () => setAttributes( { myValue: undefined } ) } + resetAllFilter={ ( newAttributes ) => ( { + ...newAttributes, + myValue: undefined, + } ) } + isShownByDefault={ true } + > + setAttributes( { myValue: next } ) ) } + /> + + + ); +} +``` diff --git a/packages/block-editor/src/components/dimension-controls/index.js b/packages/block-editor/src/components/dimension-controls/index.js new file mode 100644 index 00000000000000..108e5d5db03a63 --- /dev/null +++ b/packages/block-editor/src/components/dimension-controls/index.js @@ -0,0 +1,18 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; +/** + * Internal dependencies + */ +import useDisplayBlockControls from '../use-display-block-controls'; + +const { Fill, Slot } = createSlotFill( 'DimensionControls' ); + +function DimensionControls( { children } ) { + return useDisplayBlockControls() ? { children } : null; +} + +DimensionControls.Slot = Slot; + +export default DimensionControls; diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 3cfa70c4b9f408..eaa109be5446c6 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -41,6 +41,7 @@ export { export { default as ColorPalette } from './color-palette'; export { default as ColorPaletteControl } from './color-palette/control'; export { default as ContrastChecker } from './contrast-checker'; +export { default as DimensionControls } from './dimension-controls'; export { default as __experimentalDuotoneControl } from './duotone-control'; export { default as __experimentalFontAppearanceControl } from './font-appearance-control'; export { default as __experimentalFontFamilyControl } from './font-family'; diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js index 697955670b497e..7ea5922acdcab4 100644 --- a/packages/block-editor/src/hooks/dimensions.js +++ b/packages/block-editor/src/hooks/dimensions.js @@ -13,6 +13,7 @@ import { getBlockSupport } from '@wordpress/blocks'; * Internal dependencies */ import InspectorControls from '../components/inspector-controls'; +import DimensionControls from '../components/dimension-controls'; import { MarginEdit, hasMarginSupport, @@ -56,19 +57,33 @@ export function DimensionsPanel( props ) { ] ); // Callback to reset all block support attributes controlled via this panel. - const resetAll = () => { + const resetAll = ( resetFilters = [] ) => { const { style } = props.attributes; - props.setAttributes( { - style: cleanEmptyObject( { + let newAttributes = { + style: { ...style, spacing: { ...style?.spacing, margin: undefined, padding: undefined, }, - } ), + }, + }; + + // Injected controls can register additional functions to further adjust + // the attributes being reset. + resetFilters.forEach( ( resetFilter ) => { + newAttributes = resetFilter( newAttributes ); } ); + + // Enforce a cleaned style object. + newAttributes = { + ...newAttributes, + style: cleanEmptyObject( newAttributes.style ), + }; + + props.setAttributes( newAttributes ); }; return ( @@ -78,26 +93,37 @@ export function DimensionsPanel( props ) { header={ __( 'Dimensions' ) } resetAll={ resetAll } > - { ! isPaddingDisabled && ( - hasPaddingValue( props ) } - label={ __( 'Padding' ) } - onDeselect={ () => resetPadding( props ) } - isShownByDefault={ defaultSpacingControls?.padding } - > - - - ) } - { ! isMarginDisabled && ( - hasMarginValue( props ) } - label={ __( 'Margin' ) } - onDeselect={ () => resetMargin( props ) } - isShownByDefault={ defaultSpacingControls?.margin } - > - - - ) } + + { ( fills ) => ( + <> + { ! isPaddingDisabled && ( + hasPaddingValue( props ) } + label={ __( 'Padding' ) } + onDeselect={ () => resetPadding( props ) } + isShownByDefault={ + defaultSpacingControls?.padding + } + > + + + ) } + { ! isMarginDisabled && ( + hasMarginValue( props ) } + label={ __( 'Margin' ) } + onDeselect={ () => resetMargin( props ) } + isShownByDefault={ + defaultSpacingControls?.margin + } + > + + + ) } + { fills } + + ) } + ); 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 fe9050ab91db91..e18c9f44b9e146 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 @@ -37,6 +38,7 @@ export function useToolsPanelItem( props ) { hasValue, isShownByDefault, label, + resetAllFilter, } ); }, [] ); diff --git a/packages/components/src/tools-panel/tools-panel/hook.js b/packages/components/src/tools-panel/tools-panel/hook.js index 898d1c5e043336..743834605ce8c9 100644 --- a/packages/components/src/tools-panel/tools-panel/hook.js +++ b/packages/components/src/tools-panel/tools-panel/hook.js @@ -23,9 +23,17 @@ export function useToolsPanel( props ) { // Allow panel items to register themselves. const [ panelItems, setPanelItems ] = useState( [] ); + const [ panelResetAllFilters, setPanelResetAllFilters ] = useState( [] ); const registerPanelItem = ( item ) => { setPanelItems( ( items ) => [ ...items, item ] ); + + if ( item.resetAllFilter ) { + setPanelResetAllFilters( ( filters ) => [ + ...filters, + item.resetAllFilter, + ] ); + } }; // Manage and share display state of menu items representing child controls. @@ -54,7 +62,7 @@ export function useToolsPanel( props ) { // Resets display of children and executes resetAll callback if available. const resetAllItems = () => { if ( typeof resetAll === 'function' ) { - resetAll(); + resetAll( panelResetAllFilters ); } // Turn off display of all non-default items.