diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php
index 2692b316d4db17..a93457347274b2 100644
--- a/lib/block-supports/dimensions.php
+++ b/lib/block-supports/dimensions.php
@@ -26,7 +26,6 @@ function gutenberg_register_dimensions_support( $block_type ) {
}
$has_dimensions_support = gutenberg_block_has_support( $block_type, array( '__experimentalDimensions' ), false );
- // Future block supports such as height & width will be added here.
if ( $has_dimensions_support ) {
$block_type->attributes['style'] = array(
@@ -44,14 +43,35 @@ function gutenberg_register_dimensions_support( $block_type ) {
*
* @return array Block dimensions CSS classes and inline styles.
*/
-function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) {
if ( gutenberg_skip_dimensions_serialization( $block_type ) ) {
return array();
}
$styles = array();
- // Height support to be added in near future.
+ // Height.
+ $has_height_support = gutenberg_block_has_support( $block_type, array( '__experimentalDimensions', 'height' ), false );
+
+ if ( $has_height_support ) {
+ $height_value = _wp_array_get( $block_attributes, array( 'style', 'dimensions', 'height' ), null );
+
+ if ( null !== $height_value ) {
+ $styles[] = sprintf( 'height: %s;', $height_value );
+ }
+ }
+
+ // Minimum height.
+ $has_min_height_support = gutenberg_block_has_support( $block_type, array( '__experimentalDimensions', 'minHeight' ), false );
+
+ if ( $has_min_height_support ) {
+ $min_height_value = _wp_array_get( $block_attributes, array( 'style', 'dimensions', 'minHeight' ), null );
+
+ if ( null !== $min_height_value ) {
+ $styles[] = sprintf( 'min-height: %s;', $min_height_value );
+ }
+ }
+
// Width support to be added in near future.
return empty( $styles ) ? array() : array( 'style' => implode( ' ', $styles ) );
@@ -63,10 +83,11 @@ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) {
*
* @param WP_Block_type $block_type Block type.
*
- * @return boolean Whether to serialize spacing support styles & classes.
+ * @return boolean Whether to serialize dimensions support styles & classes.
*/
function gutenberg_skip_dimensions_serialization( $block_type ) {
$dimensions_support = _wp_array_get( $block_type->supports, array( '__experimentalDimensions' ), false );
+
return is_array( $dimensions_support ) &&
array_key_exists( '__experimentalSkipSerialization', $dimensions_support ) &&
$dimensions_support['__experimentalSkipSerialization'];
diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php
index cf713529b4f70d..285a5133095d6d 100644
--- a/lib/class-wp-theme-json-gutenberg.php
+++ b/lib/class-wp-theme-json-gutenberg.php
@@ -60,6 +60,10 @@ class WP_Theme_JSON_Gutenberg {
'gradient' => null,
'text' => null,
),
+ 'dimensions' => array(
+ 'height' => null,
+ 'minHeight' => null,
+ ),
'spacing' => array(
'margin' => null,
'padding' => null,
@@ -94,6 +98,10 @@ class WP_Theme_JSON_Gutenberg {
'palette' => null,
),
'custom' => null,
+ 'dimensions' => array(
+ 'height' => null,
+ 'minHeight' => null,
+ ),
'layout' => array(
'contentSize' => null,
'wideSize' => null,
@@ -222,6 +230,7 @@ class WP_Theme_JSON_Gutenberg {
'font-size' => array( 'typography', 'fontSize' ),
'font-style' => array( 'typography', 'fontStyle' ),
'font-weight' => array( 'typography', 'fontWeight' ),
+ 'height' => array( 'dimensions', 'height' ),
'letter-spacing' => array( 'typography', 'letterSpacing' ),
'line-height' => array( 'typography', 'lineHeight' ),
'margin' => array( 'spacing', 'margin' ),
@@ -229,6 +238,7 @@ class WP_Theme_JSON_Gutenberg {
'margin-right' => array( 'spacing', 'margin', 'right' ),
'margin-bottom' => array( 'spacing', 'margin', 'bottom' ),
'margin-left' => array( 'spacing', 'margin', 'left' ),
+ 'min-height' => array( 'dimensions', 'minHeight' ),
'padding' => array( 'spacing', 'padding' ),
'padding-top' => array( 'spacing', 'padding', 'top' ),
'padding-right' => array( 'spacing', 'padding', 'right' ),
diff --git a/lib/theme.json b/lib/theme.json
index 6b52969009beed..66c0f238d0ee2f 100644
--- a/lib/theme.json
+++ b/lib/theme.json
@@ -210,6 +210,10 @@
}
]
},
+ "dimensions": {
+ "height": false,
+ "minHeight": false
+ },
"spacing": {
"customMargin": false,
"customPadding": false,
diff --git a/package-lock.json b/package-lock.json
index 77a1fa1c1c7115..5e6609560bfb52 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16487,9 +16487,9 @@
}
},
"@types/hammerjs": {
- "version": "2.0.39",
- "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.39.tgz",
- "integrity": "sha512-lYR2Y/tV2ujpk/WyUc7S0VLI0a9hrtVIN9EwnrNo5oSEJI2cK2/XrgwOQmXLL3eTulOESvh9qP6si9+DWM9cOA=="
+ "version": "2.0.40",
+ "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.40.tgz",
+ "integrity": "sha512-VbjwR1fhsn2h2KXAY4oy1fm7dCxaKy0D+deTb8Ilc3Eo3rc5+5eA4rfYmZaHgNJKxVyI0f6WIXzO2zLkVmQPHA=="
},
"@types/hast": {
"version": "2.3.1",
@@ -18930,7 +18930,7 @@
"jsdom-jscore-rn": "git+https://github.com/iamcco/jsdom-jscore-rn.git#a562f3d57c27c13e5bfc8cf82d496e69a3ba2800",
"node-fetch": "^2.6.0",
"react-native": "0.64.0",
- "react-native-gesture-handler": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#1.10.1-wp",
+ "react-native-gesture-handler": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#1.10.1-wp-2",
"react-native-get-random-values": "git+https://github.com/wordpress-mobile/react-native-get-random-values.git#v1.4.0-wp",
"react-native-hr": "git+https://github.com/Riglerr/react-native-hr.git#2d01a5cf77212d100e8b99e0310cce5234f977b3",
"react-native-hsv-color-picker": "git+https://github.com/wordpress-mobile/react-native-hsv-color-picker.git#v1.0.1-wp",
@@ -30662,12 +30662,27 @@
}
},
"color": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
- "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"requires": {
- "color-convert": "^1.9.1",
- "color-string": "^1.5.4"
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ },
+ "dependencies": {
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ }
}
},
"color-convert": {
@@ -30684,9 +30699,9 @@
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
},
"color-string": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz",
- "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz",
+ "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
@@ -32278,7 +32293,6 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
- "dev": true,
"requires": {
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
@@ -32287,8 +32301,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
@@ -46283,8 +46296,7 @@
"mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
- "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
- "dev": true
+ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
},
"mdurl": {
"version": "1.0.1",
@@ -47938,9 +47950,9 @@
"optional": true
},
"nanoid": {
- "version": "3.1.23",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
- "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
+ "version": "3.1.25",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
+ "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q=="
},
"nanomatch": {
"version": "1.2.13",
@@ -53383,8 +53395,8 @@
}
},
"react-native-gesture-handler": {
- "version": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#5282a8f3b5f4ef8439c9c60f90c99629658c4cc3",
- "from": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#1.10.1-wp",
+ "version": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#0b284c3d26c2af4b99f9b631b9888df7e11502d0",
+ "from": "git+https://github.com/wordpress-mobile/react-native-gesture-handler.git#1.10.1-wp-2",
"requires": {
"@egjs/hammerjs": "^2.0.17",
"fbjs": "^3.0.0",
@@ -53523,15 +53535,6 @@
"nth-check": "^1.0.2"
}
},
- "css-tree": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
- "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
- "requires": {
- "mdn-data": "2.0.14",
- "source-map": "^0.6.1"
- }
- },
"css-what": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
@@ -53546,11 +53549,6 @@
"domelementtype": "1"
}
},
- "mdn-data": {
- "version": "2.0.14",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
- "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
- },
"nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -53558,11 +53556,6 @@
"requires": {
"boolbase": "~1.0.0"
}
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
diff --git a/packages/block-editor/src/hooks/dimensions.js b/packages/block-editor/src/hooks/dimensions.js
index 697955670b497e..10639e65c3397a 100644
--- a/packages/block-editor/src/hooks/dimensions.js
+++ b/packages/block-editor/src/hooks/dimensions.js
@@ -13,6 +13,20 @@ import { getBlockSupport } from '@wordpress/blocks';
* Internal dependencies
*/
import InspectorControls from '../components/inspector-controls';
+import {
+ HeightEdit,
+ hasHeightSupport,
+ hasHeightValue,
+ resetHeight,
+ useIsHeightDisabled,
+} from './height';
+import {
+ MinHeightEdit,
+ hasMinHeightSupport,
+ hasMinHeightValue,
+ resetMinHeight,
+ useIsMinHeightDisabled,
+} from './min-height';
import {
MarginEdit,
hasMarginSupport,
@@ -29,6 +43,7 @@ import {
} from './padding';
import { cleanEmptyObject } from './utils';
+export const DIMENSIONS_SUPPORT_KEY = '__experimentalDimensions';
export const SPACING_SUPPORT_KEY = 'spacing';
export const ALL_SIDES = [ 'top', 'right', 'bottom', 'left' ];
export const AXIAL_SIDES = [ 'vertical', 'horizontal' ];
@@ -37,12 +52,13 @@ export const AXIAL_SIDES = [ 'vertical', 'horizontal' ];
* Inspector controls for dimensions support.
*
* @param {Object} props Block props.
- *
- * @return {WPElement} Inspector controls for spacing support features.
+ * @return {WPElement} Inspector controls for dimensions support features.
*/
export function DimensionsPanel( props ) {
const isPaddingDisabled = useIsPaddingDisabled( props );
const isMarginDisabled = useIsMarginDisabled( props );
+ const isHeightDisabled = useIsHeightDisabled( props );
+ const isMinHeightDisabled = useIsMinHeightDisabled( props );
const isDisabled = useIsDimensionsDisabled( props );
const isSupported = hasDimensionsSupport( props.name );
@@ -50,6 +66,11 @@ export function DimensionsPanel( props ) {
return null;
}
+ const defaultDimensionsControls = getBlockSupport( props.name, [
+ DIMENSIONS_SUPPORT_KEY,
+ '__experimentalDefaultControls',
+ ] );
+
const defaultSpacingControls = getBlockSupport( props.name, [
SPACING_SUPPORT_KEY,
'__experimentalDefaultControls',
@@ -62,6 +83,11 @@ export function DimensionsPanel( props ) {
props.setAttributes( {
style: cleanEmptyObject( {
...style,
+ dimensions: {
+ ...style?.dimensions,
+ height: undefined,
+ minHeight: undefined,
+ },
spacing: {
...style?.spacing,
margin: undefined,
@@ -78,6 +104,30 @@ export function DimensionsPanel( props ) {
header={ __( 'Dimensions' ) }
resetAll={ resetAll }
>
+ { ! isHeightDisabled && (
+ hasHeightValue( props ) }
+ label={ __( 'Height' ) }
+ onDeselect={ () => resetHeight( props ) }
+ isShownByDefault={ defaultDimensionsControls?.height }
+ >
+
+
+ ) }
+ { ! isMinHeightDisabled && (
+ hasMinHeightValue( props ) }
+ label={ __( 'Minimum height' ) }
+ onDeselect={ () => resetMinHeight( props ) }
+ isShownByDefault={
+ defaultDimensionsControls?.minHeight
+ }
+ >
+
+
+ ) }
{ ! isPaddingDisabled && (
hasPaddingValue( props ) }
@@ -115,21 +165,29 @@ export function hasDimensionsSupport( blockName ) {
return false;
}
- return hasPaddingSupport( blockName ) || hasMarginSupport( blockName );
+ return (
+ hasHeightSupport( blockName ) ||
+ hasMinHeightSupport( blockName ) ||
+ hasPaddingSupport( blockName ) ||
+ hasMarginSupport( blockName )
+ );
}
/**
* Determines whether dimensions support has been disabled.
*
* @param {Object} props Block properties.
- *
- * @return {boolean} If spacing support is completely disabled.
+ * @return {boolean} If dimensions support is completely disabled.
*/
const useIsDimensionsDisabled = ( props = {} ) => {
+ const heightDisabled = useIsHeightDisabled( props );
+ const minHeightDisabled = useIsMinHeightDisabled( props );
const paddingDisabled = useIsPaddingDisabled( props );
const marginDisabled = useIsMarginDisabled( props );
- return paddingDisabled && marginDisabled;
+ return (
+ heightDisabled && minHeightDisabled && paddingDisabled && marginDisabled
+ );
};
/**
diff --git a/packages/block-editor/src/hooks/height.js b/packages/block-editor/src/hooks/height.js
new file mode 100644
index 00000000000000..a2c80bc4eea9b9
--- /dev/null
+++ b/packages/block-editor/src/hooks/height.js
@@ -0,0 +1,121 @@
+/**
+ * WordPress dependencies
+ */
+import { getBlockSupport } from '@wordpress/blocks';
+import {
+ __experimentalUseCustomUnits as useCustomUnits,
+ __experimentalUnitControl as UnitControl,
+} from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import useSetting from '../components/use-setting';
+import { DIMENSIONS_SUPPORT_KEY } from './dimensions';
+import { cleanEmptyObject } from './utils';
+
+/**
+ * Determines if there is height support.
+ *
+ * @param {string|Object} blockType Block name or Block Type object.
+ * @return {boolean} Whether there is support.
+ */
+export function hasHeightSupport( blockType ) {
+ const support = getBlockSupport( blockType, DIMENSIONS_SUPPORT_KEY );
+ return !! ( true === support || support?.height );
+}
+
+/**
+ * Checks if there is a current value in the height block support attributes.
+ *
+ * @param {Object} props Block props.
+ * @return {boolean} Whether or not the block has a height value set.
+ */
+export function hasHeightValue( props ) {
+ return props.attributes.style?.dimensions?.height !== undefined;
+}
+
+/**
+ * Resets the height block support attributes. This can be used when
+ * disabling the height support controls for a block via a progressive
+ * discovery panel.
+ *
+ * @param {Object} props Block props.
+ * @param {Object} props.attributes Block's attributes.
+ * @param {Object} props.setAttributes Function to set block's attributes.
+ */
+export function resetHeight( { attributes = {}, setAttributes } ) {
+ const { style } = attributes;
+
+ setAttributes( {
+ style: cleanEmptyObject( {
+ ...style,
+ dimensions: {
+ ...style?.dimensions,
+ height: undefined,
+ },
+ } ),
+ } );
+}
+
+/**
+ * Custom hook that checks if height controls have been disabled.
+ *
+ * @param {string} name The name of the block.
+ * @return {boolean} Whether height control is disabled.
+ */
+export function useIsHeightDisabled( { name: blockName } = {} ) {
+ const isDisabled = ! useSetting( 'dimensions.height' );
+ return ! hasHeightSupport( blockName ) || isDisabled;
+}
+
+/**
+ * Inspector control panel containing the height related configuration.
+ *
+ * @param {Object} props Block props.
+ * @return {WPElement} Edit component for height.
+ */
+export function HeightEdit( props ) {
+ const {
+ attributes: { style },
+ setAttributes,
+ } = props;
+
+ const units = useCustomUnits( {
+ availableUnits: useSetting( 'dimensions.units' ) || [
+ '%',
+ 'px',
+ 'em',
+ 'rem',
+ 'vh',
+ 'vw',
+ ],
+ } );
+
+ if ( useIsHeightDisabled( props ) ) {
+ return null;
+ }
+
+ const onChange = ( next ) => {
+ const newStyle = {
+ ...style,
+ dimensions: {
+ ...style?.dimensions,
+ height: next,
+ },
+ };
+
+ setAttributes( { style: cleanEmptyObject( newStyle ) } );
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/hooks/min-height.js b/packages/block-editor/src/hooks/min-height.js
new file mode 100644
index 00000000000000..6e57e23eb94d90
--- /dev/null
+++ b/packages/block-editor/src/hooks/min-height.js
@@ -0,0 +1,122 @@
+/**
+ * WordPress dependencies
+ */
+import { getBlockSupport } from '@wordpress/blocks';
+import {
+ __experimentalUseCustomUnits as useCustomUnits,
+ __experimentalUnitControl as UnitControl,
+} from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import useSetting from '../components/use-setting';
+import { DIMENSIONS_SUPPORT_KEY } from './dimensions';
+import { cleanEmptyObject } from './utils';
+
+/**
+ * Determines if there is min-height support.
+ *
+ * @param {string|Object} blockType Block name or Block Type object.
+ * @return {boolean} Whether there is support.
+ */
+export function hasMinHeightSupport( blockType ) {
+ const support = getBlockSupport( blockType, DIMENSIONS_SUPPORT_KEY );
+ return !! ( true === support || support?.minHeight );
+}
+
+/**
+ * Checks if there is a current value in the min-height block support attributes.
+ *
+ * @param {Object} props Block props.
+ * @return {boolean} Whether or not the block has a min-height value set.
+ */
+export function hasMinHeightValue( props ) {
+ return props.attributes.style?.dimensions?.minHeight !== undefined;
+}
+
+/**
+ * Resets the min-height block support attributes. This can be used when
+ * disabling the min-height support controls for a block via a progressive
+ * discovery panel.
+ *
+ * @param {Object} props Block props.
+ * @param {Object} props.attributes Block's attributes.
+ * @param {Object} props.setAttributes Function to set block's attributes.
+ */
+export function resetMinHeight( { attributes = {}, setAttributes } ) {
+ const { style } = attributes;
+
+ setAttributes( {
+ style: cleanEmptyObject( {
+ ...style,
+ dimensions: {
+ ...style?.dimensions,
+ minHeight: undefined,
+ },
+ } ),
+ } );
+}
+
+/**
+ * Custom hook that checks if min-height controls have been disabled.
+ *
+ * @param {Object} props Block props.
+ * @param {string} props.name The name of the block.
+ * @return {boolean} Whether min-height control is disabled.
+ */
+export function useIsMinHeightDisabled( { name: blockName } = {} ) {
+ const isDisabled = ! useSetting( 'dimensions.minHeight' );
+ return ! hasMinHeightSupport( blockName ) || isDisabled;
+}
+
+/**
+ * Inspector control panel containing the min-height related configuration.
+ *
+ * @param {Object} props Block props.
+ * @return {WPElement} Edit component for min-height.
+ */
+export function MinHeightEdit( props ) {
+ const {
+ attributes: { style },
+ setAttributes,
+ } = props;
+
+ const units = useCustomUnits( {
+ availableUnits: useSetting( 'dimensions.units' ) || [
+ '%',
+ 'px',
+ 'em',
+ 'rem',
+ 'vh',
+ 'vw',
+ ],
+ } );
+
+ if ( useIsMinHeightDisabled( props ) ) {
+ return null;
+ }
+
+ const onChange = ( next ) => {
+ const newStyle = {
+ ...style,
+ dimensions: {
+ ...style?.dimensions,
+ minHeight: next,
+ },
+ };
+
+ setAttributes( { style: cleanEmptyObject( newStyle ) } );
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js
index 87bf4685d50d42..2c3fff303ec402 100644
--- a/packages/block-editor/src/hooks/style.js
+++ b/packages/block-editor/src/hooks/style.js
@@ -37,13 +37,18 @@ import {
TYPOGRAPHY_SUPPORT_KEY,
TYPOGRAPHY_SUPPORT_KEYS,
} from './typography';
-import { SPACING_SUPPORT_KEY, DimensionsPanel } from './dimensions';
+import {
+ DIMENSIONS_SUPPORT_KEY,
+ SPACING_SUPPORT_KEY,
+ DimensionsPanel,
+} from './dimensions';
import useDisplayBlockControls from '../components/use-display-block-controls';
const styleSupportKeys = [
...TYPOGRAPHY_SUPPORT_KEYS,
BORDER_SUPPORT_KEY,
COLOR_SUPPORT_KEY,
+ DIMENSIONS_SUPPORT_KEY,
SPACING_SUPPORT_KEY,
];
@@ -152,8 +157,11 @@ const skipSerializationPaths = {
[ `${ TYPOGRAPHY_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
TYPOGRAPHY_SUPPORT_KEY,
],
+ [ `${ DIMENSIONS_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
+ DIMENSIONS_SUPPORT_KEY,
+ ],
[ `${ SPACING_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
- 'spacing',
+ SPACING_SUPPORT_KEY,
],
};
diff --git a/packages/block-editor/src/hooks/test/style.js b/packages/block-editor/src/hooks/test/style.js
index 706d9a93ed0ba4..70f6e0c271e5b0 100644
--- a/packages/block-editor/src/hooks/test/style.js
+++ b/packages/block-editor/src/hooks/test/style.js
@@ -23,6 +23,10 @@ describe( 'getInlineStyles', () => {
style: 'dotted',
color: '#21759b',
},
+ dimensions: {
+ height: '500px',
+ minHeight: '200px',
+ },
spacing: {
padding: { top: '10px' },
margin: { bottom: '15px' },
@@ -37,6 +41,8 @@ describe( 'getInlineStyles', () => {
color: 'red',
lineHeight: 1.5,
fontSize: 10,
+ height: '500px',
+ minHeight: '200px',
marginBottom: '15px',
paddingTop: '10px',
} );
diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js
index 18342aa9162565..5459558e804955 100644
--- a/packages/blocks/src/api/constants.js
+++ b/packages/blocks/src/api/constants.js
@@ -72,6 +72,10 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
value: [ 'typography', 'fontWeight' ],
support: [ 'typography', '__experimentalFontWeight' ],
},
+ height: {
+ value: [ 'dimensions', 'height' ],
+ support: [ '__experimentalDimensions', 'height' ],
+ },
lineHeight: {
value: [ 'typography', 'lineHeight' ],
support: [ 'typography', 'lineHeight' ],
@@ -86,6 +90,10 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
marginLeft: 'left',
},
},
+ minHeight: {
+ value: [ 'dimensions', 'minHeight' ],
+ support: [ '__experimentalDimensions', 'minHeight' ],
+ },
padding: {
value: [ 'spacing', 'padding' ],
support: [ 'spacing', 'padding' ],
diff --git a/packages/edit-site/src/components/editor/global-styles-renderer.js b/packages/edit-site/src/components/editor/global-styles-renderer.js
index fdec33c3fc0230..1c68b413955dfe 100644
--- a/packages/edit-site/src/components/editor/global-styles-renderer.js
+++ b/packages/edit-site/src/components/editor/global-styles-renderer.js
@@ -192,7 +192,13 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => {
const pickStyleKeys = ( treeToPickFrom ) =>
pickBy( treeToPickFrom, ( value, key ) =>
- [ 'border', 'color', 'spacing', 'typography' ].includes( key )
+ [
+ 'border',
+ 'color',
+ 'dimensions',
+ 'spacing',
+ 'typography',
+ ].includes( key )
);
// Top-level.
diff --git a/packages/edit-site/src/components/sidebar/dimensions-panel.js b/packages/edit-site/src/components/sidebar/dimensions-panel.js
index 05b4aadd2d5bf0..387cc379b6690a 100644
--- a/packages/edit-site/src/components/sidebar/dimensions-panel.js
+++ b/packages/edit-site/src/components/sidebar/dimensions-panel.js
@@ -7,6 +7,7 @@ import {
__experimentalToolsPanelItem as ToolsPanelItem,
__experimentalBoxControl as BoxControl,
__experimentalUseCustomUnits as useCustomUnits,
+ __experimentalUnitControl as UnitControl,
} from '@wordpress/components';
import { __experimentalUseCustomSides as useCustomSides } from '@wordpress/block-editor';
@@ -18,10 +19,24 @@ import { useSetting } from '../editor/utils';
const AXIAL_SIDES = [ 'horizontal', 'vertical' ];
export function useHasDimensionsPanel( context ) {
+ const hasHeight = useHasHeight( context );
+ const hasMinHeight = useHasMinHeight( context );
const hasPadding = useHasPadding( context );
const hasMargin = useHasMargin( context );
- return hasPadding || hasMargin;
+ return hasHeight || hasMinHeight || hasPadding || hasMargin;
+}
+
+function useHasHeight( { name, supports } ) {
+ const settings = useSetting( 'dimensions.height', name );
+
+ return settings && supports.includes( 'height' );
+}
+
+function useHasMinHeight( { name, supports } ) {
+ const settings = useSetting( 'dimensions.minHeight', name );
+
+ return settings && supports.includes( 'minHeight' );
}
function useHasPadding( { name, supports } ) {
@@ -76,6 +91,8 @@ function splitStyleValue( value ) {
export default function DimensionsPanel( { context, getStyle, setStyle } ) {
const { name } = context;
+ const showHeightControl = useHasHeight( context );
+ const showMinHeightControl = useHasMinHeight( context );
const showPaddingControl = useHasPadding( context );
const showMarginControl = useHasMargin( context );
const units = useCustomUnits( {
@@ -88,6 +105,19 @@ export default function DimensionsPanel( { context, getStyle, setStyle } ) {
],
} );
+ // Height.
+ const heightValue = getStyle( name, 'height' );
+ const setHeightValue = ( next ) => setStyle( name, 'height', next );
+ const resetHeightValue = () => setHeightValue( undefined );
+ const hasHeightValue = () => !! heightValue;
+
+ // Min height.
+ const minHeightValue = getStyle( name, 'minHeight' );
+ const setMinHeightValue = ( next ) => setStyle( name, 'minHeight', next );
+ const resetMinHeightValue = () => setMinHeightValue( undefined );
+ const hasMinHeightValue = () => !! minHeightValue;
+
+ // Padding.
const paddingValues = splitStyleValue( getStyle( name, 'padding' ) );
const paddingSides = useCustomSides( name, 'padding' );
const isAxialPadding =
@@ -102,6 +132,7 @@ export default function DimensionsPanel( { context, getStyle, setStyle } ) {
const hasPaddingValue = () =>
paddingValues && Object.keys( paddingValues ).length;
+ // Margin.
const marginValues = splitStyleValue( getStyle( name, 'margin' ) );
const marginSides = useCustomSides( name, 'margin' );
const isAxialMargin =
@@ -117,6 +148,8 @@ export default function DimensionsPanel( { context, getStyle, setStyle } ) {
marginValues && Object.keys( marginValues ).length;
const resetAll = () => {
+ resetHeightValue();
+ resetMinHeightValue();
resetPaddingValue();
resetMarginValue();
};
@@ -127,6 +160,40 @@ export default function DimensionsPanel( { context, getStyle, setStyle } ) {
header={ __( 'Dimensions' ) }
resetAll={ resetAll }
>
+ { showHeightControl && (
+
+
+
+ ) }
+ { showMinHeightControl && (
+
+
+
+ ) }
{ showPaddingControl && (
array(
'core/group' => array(
- 'border' => array(
+ 'border' => array(
'radius' => '10px',
),
- 'elements' => array(
+ 'elements' => array(
'link' => array(
'color' => array(
'text' => '#111',
),
),
),
- 'spacing' => array(
+ 'dimensions' => array(
+ 'height' => '200px',
+ 'minHeight' => '100px',
+ ),
+ 'spacing' => array(
'padding' => '24px',
),
),
@@ -352,11 +356,11 @@ function test_get_stylesheet() {
);
$this->assertEquals(
- 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}body{color: var(--wp--preset--color--grey);}.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}',
+ 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}body{color: var(--wp--preset--color--grey);}.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;height: 200px;min-height: 100px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}',
$theme_json->get_stylesheet()
);
$this->assertEquals(
- 'body{color: var(--wp--preset--color--grey);}.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}',
+ 'body{color: var(--wp--preset--color--grey);}.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); margin-bottom: 0; }a{background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;height: 200px;min-height: 100px;padding: 24px;}.wp-block-group a{color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a{background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}',
$theme_json->get_stylesheet( 'block_styles' )
);
$this->assertEquals(