diff --git a/packages/block-library/src/spacer/block.json b/packages/block-library/src/spacer/block.json index ba81cb32911aa3..ed54263b879f19 100644 --- a/packages/block-library/src/spacer/block.json +++ b/packages/block-library/src/spacer/block.json @@ -8,11 +8,11 @@ "textdomain": "default", "attributes": { "height": { - "type": "number", - "default": 100 + "type": "string", + "default": "100px" }, "width": { - "type": "number" + "type": "string" } }, "usesContext": [ "orientation" ], diff --git a/packages/block-library/src/spacer/controls.js b/packages/block-library/src/spacer/controls.js new file mode 100644 index 00000000000000..28ede80b93a231 --- /dev/null +++ b/packages/block-library/src/spacer/controls.js @@ -0,0 +1,108 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { InspectorControls, useSetting } from '@wordpress/block-editor'; +import { + BaseControl, + PanelBody, + __experimentalUseCustomUnits as useCustomUnits, + __experimentalUnitControl as UnitControl, +} from '@wordpress/components'; +import { useInstanceId } from '@wordpress/compose'; +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { MAX_SPACER_SIZE } from './edit'; + +function DimensionInput( { label, onChange, isResizing, value = '' } ) { + const [ temporaryInput, setTemporaryInput ] = useState( null ); + + const inputId = useInstanceId( UnitControl, 'block-spacer-height-input' ); + + // In most contexts the spacer size cannot meaningfully be set to a + // percentage, since this is relative to the parent container. This + // unit is disabled from the UI. + const availableUnitSettings = useSetting( 'spacing.units' ).filter( + ( availableUnit ) => availableUnit !== '%' + ); + + const units = useCustomUnits( { + availableUnits: availableUnitSettings || [ + 'px', + 'em', + 'rem', + 'vw', + 'vh', + ], + defaultValues: { px: '100', em: '10', rem: '10', vw: '10', vh: '25' }, + } ); + + const handleOnChange = ( unprocessedValue ) => { + setTemporaryInput( null ); + onChange( unprocessedValue ); + }; + + const handleOnBlur = () => { + if ( temporaryInput !== null ) { + setTemporaryInput( null ); + } + }; + + const inputValue = temporaryInput !== null ? temporaryInput : value; + + return ( + + + + ); +} + +export default function SpacerControls( { + setAttributes, + orientation, + height, + width, + isResizing, +} ) { + return ( + + + { orientation === 'horizontal' && ( + + setAttributes( { width: nextWidth } ) + } + isResizing={ isResizing } + /> + ) } + { orientation !== 'horizontal' && ( + + setAttributes( { height: nextHeight } ) + } + isResizing={ isResizing } + /> + ) } + + + ); +} diff --git a/packages/block-library/src/spacer/controls.native.js b/packages/block-library/src/spacer/controls.native.js new file mode 100644 index 00000000000000..ecad9fab44860f --- /dev/null +++ b/packages/block-library/src/spacer/controls.native.js @@ -0,0 +1,82 @@ +/** + * WordPress dependencies + */ +import { + PanelBody, + UnitControl, + getValueAndUnit, + __experimentalUseCustomUnits as useCustomUnits, +} from '@wordpress/components'; +import { useCallback } from '@wordpress/element'; +import { useSetting } from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import styles from './style.scss'; + +const DEFAULT_VALUES = { px: '100', em: '10', rem: '10', vw: '10', vh: '25' }; + +function Controls( { attributes, context, setAttributes } ) { + const { orientation } = context; + const label = orientation !== 'horizontal' ? __( 'Height' ) : __( 'Width' ); + + const { height, width } = attributes; + const { valueToConvert, valueUnit: unit } = + getValueAndUnit( orientation !== 'horizontal' ? height : width ) || {}; + const value = Number( valueToConvert ); + + const setNewDimensions = ( nextValue, nextUnit ) => { + const valueWithUnit = `${ nextValue }${ nextUnit }`; + if ( orientation === 'horizontal' ) { + setAttributes( { width: valueWithUnit } ); + } else { + setAttributes( { height: valueWithUnit } ); + } + }; + + const handleChange = useCallback( + ( nextValue ) => { + setNewDimensions( nextValue, unit ); + }, + [ height, width ] + ); + + const handleUnitChange = useCallback( + ( nextUnit ) => { + setNewDimensions( value, nextUnit ); + }, + [ height, width ] + ); + + const units = useCustomUnits( { + availableUnits: useSetting( 'spacing.units' ) || [ + 'px', + 'em', + 'rem', + 'vw', + 'vh', + ], + defaultValues: DEFAULT_VALUES, + } ); + + return ( + <> + + + + + ); +} + +export default Controls; diff --git a/packages/block-library/src/spacer/deprecated.js b/packages/block-library/src/spacer/deprecated.js new file mode 100644 index 00000000000000..79ecc09fe1185e --- /dev/null +++ b/packages/block-library/src/spacer/deprecated.js @@ -0,0 +1,41 @@ +/** + * WordPress dependencies + */ +import { useBlockProps } from '@wordpress/block-editor'; + +const deprecated = [ + { + attributes: { + height: { + type: 'number', + default: 100, + }, + width: { + type: 'number', + }, + }, + migrate( attributes ) { + const { height, width } = attributes; + return { + ...attributes, + width: width !== undefined ? `${ width }px` : undefined, + height: height !== undefined ? `${ height }px` : undefined, + }; + }, + save( { attributes } ) { + return ( +
+ ); + }, + }, +]; + +export default deprecated; diff --git a/packages/block-library/src/spacer/edit.js b/packages/block-library/src/spacer/edit.js index 6c2b2221d18d4b..1e883155e2e681 100644 --- a/packages/block-library/src/spacer/edit.js +++ b/packages/block-library/src/spacer/edit.js @@ -6,23 +6,81 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; import { - InspectorControls, useBlockProps, store as blockEditorStore, } from '@wordpress/block-editor'; -import { PanelBody, ResizableBox, RangeControl } from '@wordpress/components'; +import { ResizableBox } from '@wordpress/components'; import { compose, withInstanceId } from '@wordpress/compose'; import { withDispatch } from '@wordpress/data'; import { useState, useEffect } from '@wordpress/element'; import { View } from '@wordpress/primitives'; -const MIN_SPACER_HEIGHT = 1; -const MAX_SPACER_HEIGHT = 500; +/** + * Internal dependencies + */ +import SpacerControls from './controls'; + +export const MIN_SPACER_SIZE = 1; +export const MAX_SPACER_SIZE = 500; + +const ResizableSpacer = ( { + orientation, + onResizeStart, + onResize, + onResizeStop, + isSelected, + isResizing, + setIsResizing, + ...props +} ) => { + const getCurrentSize = ( elt ) => { + return orientation === 'horizontal' + ? elt.clientWidth + : elt.clientHeight; + }; -const MIN_SPACER_WIDTH = 1; -const MAX_SPACER_WIDTH = 500; + const getNextVal = ( elt ) => { + return `${ getCurrentSize( elt ) }px`; + }; + + return ( + { + const nextVal = getNextVal( elt ); + onResizeStart( nextVal ); + onResize( nextVal ); + } } + onResize={ ( _event, _direction, elt ) => { + onResize( getNextVal( elt ) ); + if ( ! isResizing ) { + setIsResizing( true ); + } + } } + onResizeStop={ ( _event, _direction, elt ) => { + const nextVal = Math.min( + MAX_SPACER_SIZE, + getCurrentSize( elt ) + ); + onResizeStop( `${ nextVal }px` ); + setIsResizing( false ); + } } + __experimentalShowTooltip={ true } + __experimentalTooltipProps={ { + axis: orientation === 'horizontal' ? 'x' : 'y', + position: 'corner', + isVisible: isResizing, + } } + showHandle={ isSelected } + { ...props } + /> + ); +}; const SpacerEdit = ( { attributes, @@ -33,60 +91,41 @@ const SpacerEdit = ( { context, } ) => { const { orientation } = context; - const [ isResizing, setIsResizing ] = useState( false ); const { height, width } = attributes; - const updateHeight = ( value ) => { - setAttributes( { - height: value, - } ); - }; - const updateWidth = ( value ) => { - setAttributes( { - width: value, - } ); - }; - const handleOnResizeStart = ( ...args ) => { - onResizeStart( ...args ); - setIsResizing( true ); - }; + const [ isResizing, setIsResizing ] = useState( false ); + const [ temporaryHeight, setTemporaryHeight ] = useState( null ); + const [ temporaryWidth, setTemporaryWidth ] = useState( null ); - const handleOnVerticalResizeStop = ( event, direction, elt, delta ) => { + const handleOnVerticalResizeStop = ( newHeight ) => { onResizeStop(); - const spacerHeight = Math.min( - parseInt( height + delta.height, 10 ), - MAX_SPACER_HEIGHT - ); - updateHeight( spacerHeight ); - setIsResizing( false ); + + setAttributes( { height: newHeight } ); + setTemporaryHeight( null ); }; - const handleOnHorizontalResizeStop = ( event, direction, elt, delta ) => { + const handleOnHorizontalResizeStop = ( newWidth ) => { onResizeStop(); - const spacerWidth = Math.min( - parseInt( width + delta.width, 10 ), - MAX_SPACER_WIDTH - ); - updateWidth( spacerWidth ); - setIsResizing( false ); + setAttributes( { width: newWidth } ); + setTemporaryWidth( null ); + }; + + const style = { + height: + orientation === 'horizontal' + ? 24 + : temporaryHeight || height || undefined, + width: + orientation === 'horizontal' + ? temporaryWidth || width || undefined + : undefined, }; const resizableBoxWithOrientation = ( blockOrientation ) => { if ( blockOrientation === 'horizontal' ) { return ( - ); } return ( - + <> + + ); }; useEffect( () => { if ( orientation === 'horizontal' && ! width ) { - updateWidth( 72 ); - updateHeight( 0 ); + setAttributes( { + height: '0px', + width: '72px', + } ); } }, [] ); return ( <> - + { resizableBoxWithOrientation( orientation ) } - - - { orientation === 'horizontal' && ( - - ) } - { orientation !== 'horizontal' && ( - - ) } - - + ); }; diff --git a/packages/block-library/src/spacer/edit.native.js b/packages/block-library/src/spacer/edit.native.js new file mode 100644 index 00000000000000..07e650dbc0de78 --- /dev/null +++ b/packages/block-library/src/spacer/edit.native.js @@ -0,0 +1,68 @@ +/** + * External dependencies + */ +import { View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { useConvertUnitToMobile } from '@wordpress/components'; +import { withPreferredColorScheme } from '@wordpress/compose'; +import { InspectorControls } from '@wordpress/block-editor'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Controls from './controls'; +import styles from './editor.native.scss'; + +const Spacer = ( { + attributes, + context, + setAttributes, + isSelected, + getStylesFromColorScheme, +} ) => { + const { height, width } = attributes; + + const { orientation } = context; + const defaultStyle = getStylesFromColorScheme( + styles.staticSpacer, + styles.staticDarkSpacer + ); + + useEffect( () => { + if ( orientation === 'horizontal' && ! width ) { + setAttributes( { + height: '0px', + width: '72px', + } ); + } + }, [] ); + + const convertedHeight = useConvertUnitToMobile( height ); + const convertedWidth = useConvertUnitToMobile( width ); + + return ( + + { isSelected && ( + + + + ) } + + ); +}; + +export default withPreferredColorScheme( Spacer ); diff --git a/packages/block-library/src/spacer/editor.scss b/packages/block-library/src/spacer/editor.scss index 8052e252c785b0..a3cb2fe887e8e6 100644 --- a/packages/block-library/src/spacer/editor.scss +++ b/packages/block-library/src/spacer/editor.scss @@ -28,6 +28,12 @@ .block-library-spacer__resize-container { clear: both; + &:not(.is-resizing) { + // Important is used to have higher specificity than the inline style set by re-resizable library. + height: 100% !important; + width: 100% !important; + } + // Don't show the horizontal indicator. .components-resizable-box__handle::before { content: none; diff --git a/packages/block-library/src/spacer/index.js b/packages/block-library/src/spacer/index.js index b34da523d534a9..4b71001cefad8d 100644 --- a/packages/block-library/src/spacer/index.js +++ b/packages/block-library/src/spacer/index.js @@ -6,6 +6,7 @@ import { resizeCornerNE as icon } from '@wordpress/icons'; /** * Internal dependencies */ +import deprecated from './deprecated'; import edit from './edit'; import metadata from './block.json'; import save from './save'; @@ -18,4 +19,5 @@ export const settings = { icon, edit, save, + deprecated, }; diff --git a/packages/block-library/src/spacer/save.js b/packages/block-library/src/spacer/save.js index 77cf37ff61251f..fe55553c1b9d52 100644 --- a/packages/block-library/src/spacer/save.js +++ b/packages/block-library/src/spacer/save.js @@ -3,11 +3,14 @@ */ import { useBlockProps } from '@wordpress/block-editor'; -export default function save( { attributes } ) { +export default function save( { attributes: { height, width } } ) { return (
diff --git a/packages/components/src/mobile/utils/use-unit-converter-to-mobile.native.js b/packages/components/src/mobile/utils/use-unit-converter-to-mobile.native.js index fda7ff8efc9122..457ab7ae87b0ce 100644 --- a/packages/components/src/mobile/utils/use-unit-converter-to-mobile.native.js +++ b/packages/components/src/mobile/utils/use-unit-converter-to-mobile.native.js @@ -40,6 +40,10 @@ const convertUnitToMobile = ( containerSize, globalStyles, value, unit ) => { const { valueToConvert, valueUnit } = getValueAndUnit( value, unit ) || {}; const { fontSize = 16 } = globalStyles || {}; + if ( valueToConvert === undefined ) { + return undefined; + } + switch ( valueUnit ) { case 'rem': case 'em': @@ -78,7 +82,8 @@ const useConvertUnitToMobile = ( value, unit ) => { }, [] ); return useMemo( () => { - const { valueToConvert, valueUnit } = getValueAndUnit( value, unit ); + const { valueToConvert, valueUnit } = + getValueAndUnit( value, unit ) || {}; return convertUnitToMobile( windowSizes, diff --git a/packages/e2e-tests/specs/editor/blocks/__snapshots__/spacer.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/spacer.test.js.snap index cfd7c9149d512e..d63bd30a0e0618 100644 --- a/packages/e2e-tests/specs/editor/blocks/__snapshots__/spacer.test.js.snap +++ b/packages/e2e-tests/specs/editor/blocks/__snapshots__/spacer.test.js.snap @@ -7,7 +7,7 @@ exports[`Spacer can be created by typing "/spacer" 1`] = ` `; exports[`Spacer can be resized using the drag handle and remains selected after being dragged 1`] = ` -" +"
" `; diff --git a/test/integration/fixtures/blocks/core__spacer.html b/test/integration/fixtures/blocks/core__spacer.html index e7c1e256196de4..f9306b3e30d2ec 100644 --- a/test/integration/fixtures/blocks/core__spacer.html +++ b/test/integration/fixtures/blocks/core__spacer.html @@ -1,3 +1,3 @@ - + diff --git a/test/integration/fixtures/blocks/core__spacer.json b/test/integration/fixtures/blocks/core__spacer.json index 6c05752c1119f9..6e5c0847bcb697 100644 --- a/test/integration/fixtures/blocks/core__spacer.json +++ b/test/integration/fixtures/blocks/core__spacer.json @@ -4,7 +4,7 @@ "name": "core/spacer", "isValid": true, "attributes": { - "height": 100 + "height": "100px" }, "innerBlocks": [], "originalContent": "
" diff --git a/test/integration/fixtures/blocks/core__spacer.parsed.json b/test/integration/fixtures/blocks/core__spacer.parsed.json index 621b9851287ece..babfa095cb0bd9 100644 --- a/test/integration/fixtures/blocks/core__spacer.parsed.json +++ b/test/integration/fixtures/blocks/core__spacer.parsed.json @@ -1,7 +1,9 @@ [ { "blockName": "core/spacer", - "attrs": {}, + "attrs": { + "height": "100px" + }, "innerBlocks": [], "innerHTML": "\n
\n", "innerContent": [ diff --git a/test/integration/fixtures/blocks/core__spacer__deprecated-1.html b/test/integration/fixtures/blocks/core__spacer__deprecated-1.html new file mode 100644 index 00000000000000..b31aafbf5102c0 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__deprecated-1.html @@ -0,0 +1,3 @@ + + + diff --git a/test/integration/fixtures/blocks/core__spacer__deprecated-1.json b/test/integration/fixtures/blocks/core__spacer__deprecated-1.json new file mode 100644 index 00000000000000..6e5c0847bcb697 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__deprecated-1.json @@ -0,0 +1,12 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/spacer", + "isValid": true, + "attributes": { + "height": "100px" + }, + "innerBlocks": [], + "originalContent": "
" + } +] diff --git a/test/integration/fixtures/blocks/core__spacer__deprecated-1.parsed.json b/test/integration/fixtures/blocks/core__spacer__deprecated-1.parsed.json new file mode 100644 index 00000000000000..a05ee06fce7121 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__deprecated-1.parsed.json @@ -0,0 +1,13 @@ +[ + { + "blockName": "core/spacer", + "attrs": { + "height": 100 + }, + "innerBlocks": [], + "innerHTML": "\n
\n", + "innerContent": [ + "\n
\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__spacer__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__spacer__deprecated-1.serialized.html new file mode 100644 index 00000000000000..e7c1e256196de4 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__deprecated-1.serialized.html @@ -0,0 +1,3 @@ + + + diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal.html b/test/integration/fixtures/blocks/core__spacer__horizontal.html index 7381e2582f3114..d8e2dd16f33528 100644 --- a/test/integration/fixtures/blocks/core__spacer__horizontal.html +++ b/test/integration/fixtures/blocks/core__spacer__horizontal.html @@ -1,3 +1,3 @@ - + - \ No newline at end of file + diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal.json b/test/integration/fixtures/blocks/core__spacer__horizontal.json index 1facf7fcaa4910..7e771e0d676133 100644 --- a/test/integration/fixtures/blocks/core__spacer__horizontal.json +++ b/test/integration/fixtures/blocks/core__spacer__horizontal.json @@ -4,8 +4,8 @@ "name": "core/spacer", "isValid": true, "attributes": { - "height": 0, - "width": 72 + "height": "0px", + "width": "72px" }, "innerBlocks": [], "originalContent": "
" diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal.parsed.json b/test/integration/fixtures/blocks/core__spacer__horizontal.parsed.json index 9e88a1c01a0037..6d27497d740996 100644 --- a/test/integration/fixtures/blocks/core__spacer__horizontal.parsed.json +++ b/test/integration/fixtures/blocks/core__spacer__horizontal.parsed.json @@ -2,8 +2,8 @@ { "blockName": "core/spacer", "attrs": { - "height": 0, - "width": 72 + "height": "0px", + "width": "72px" }, "innerBlocks": [], "innerHTML": "\n
\n", diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal.serialized.html b/test/integration/fixtures/blocks/core__spacer__horizontal.serialized.html index 580702a7ee1e42..d8e2dd16f33528 100644 --- a/test/integration/fixtures/blocks/core__spacer__horizontal.serialized.html +++ b/test/integration/fixtures/blocks/core__spacer__horizontal.serialized.html @@ -1,3 +1,3 @@ - - + + diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.html b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.html new file mode 100644 index 00000000000000..7381e2582f3114 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.json b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.json new file mode 100644 index 00000000000000..7e771e0d676133 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.json @@ -0,0 +1,13 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/spacer", + "isValid": true, + "attributes": { + "height": "0px", + "width": "72px" + }, + "innerBlocks": [], + "originalContent": "
" + } +] diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.parsed.json b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.parsed.json new file mode 100644 index 00000000000000..9e88a1c01a0037 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.parsed.json @@ -0,0 +1,14 @@ +[ + { + "blockName": "core/spacer", + "attrs": { + "height": 0, + "width": 72 + }, + "innerBlocks": [], + "innerHTML": "\n
\n", + "innerContent": [ + "\n
\n" + ] + } +] diff --git a/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.serialized.html new file mode 100644 index 00000000000000..d8e2dd16f33528 --- /dev/null +++ b/test/integration/fixtures/blocks/core__spacer__horizontal__deprecated-1.serialized.html @@ -0,0 +1,3 @@ + + +