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.