diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js
index 3308b98d281696..c0e5c1b5f8bb85 100644
--- a/packages/block-editor/src/hooks/index.js
+++ b/packages/block-editor/src/hooks/index.js
@@ -15,3 +15,4 @@ import './layout';
export { useCustomSides } from './spacing';
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
+export { getSpacingClassesAndStyles } from './use-spacing-props';
diff --git a/packages/block-editor/src/hooks/index.native.js b/packages/block-editor/src/hooks/index.native.js
index 11dbe0a30e4c9a..b0aac50354da6b 100644
--- a/packages/block-editor/src/hooks/index.native.js
+++ b/packages/block-editor/src/hooks/index.native.js
@@ -11,3 +11,4 @@ import './font-size';
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
+export { getSpacingClassesAndStyles } from './use-spacing-props';
diff --git a/packages/block-editor/src/hooks/use-spacing-props.js b/packages/block-editor/src/hooks/use-spacing-props.js
new file mode 100644
index 00000000000000..35fe87c1e5ec40
--- /dev/null
+++ b/packages/block-editor/src/hooks/use-spacing-props.js
@@ -0,0 +1,28 @@
+/**
+ * Internal dependencies
+ */
+import { getInlineStyles } from './style';
+
+// This utility is intended to assist where the serialization of the spacing
+// block support is being skipped for a block but the spacing related CSS
+// styles still need to be generated so they can be applied to inner elements.
+
+/**
+ * Provides the CSS class names and inline styles for a block's spacing support
+ * attributes.
+ *
+ * @param {Object} attributes Block attributes.
+ *
+ * @return {Object} Spacing block support derived CSS classes & styles.
+ */
+export function getSpacingClassesAndStyles( attributes ) {
+ const { style } = attributes;
+
+ // Collect inline styles for spacing.
+ const spacingStyles = style?.spacing || {};
+ const styleProp = getInlineStyles( { spacing: spacingStyles } );
+
+ return {
+ style: styleProp,
+ };
+}
diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js
index 27af4c4be666b8..aba0be6926a21c 100644
--- a/packages/block-editor/src/index.js
+++ b/packages/block-editor/src/index.js
@@ -13,6 +13,7 @@ export {
getColorClassesAndStyles as __experimentalGetColorClassesAndStyles,
useColorProps as __experimentalUseColorProps,
useCustomSides as __experimentalUseCustomSides,
+ getSpacingClassesAndStyles as __experimentalGetSpacingClassesAndStyles,
} from './hooks';
export * from './components';
export * from './utils';
diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json
index 3cb59a7fd653eb..72fd2dbccef724 100644
--- a/packages/block-library/src/button/block.json
+++ b/packages/block-library/src/button/block.json
@@ -63,6 +63,10 @@
},
"fontSize": true,
"reusable": false,
+ "spacing": {
+ "__experimentalSkipSerialization": true,
+ "padding": true
+ },
"__experimentalBorder": {
"radius": true,
"__experimentalSkipSerialization": true
diff --git a/packages/block-library/src/button/controls.native.js b/packages/block-library/src/button/controls.native.js
new file mode 100644
index 00000000000000..3a11da889d8663
--- /dev/null
+++ b/packages/block-library/src/button/controls.native.js
@@ -0,0 +1,274 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ InspectorControls,
+ BlockControls,
+ useSetting,
+} from '@wordpress/block-editor';
+import {
+ PanelBody,
+ RangeControl,
+ ToolbarGroup,
+ ToolbarButton,
+ BottomSheetSelectControl,
+ UnitControl,
+ getValueAndUnit,
+ __experimentalUseCustomUnits as useCustomUnits,
+} from '@wordpress/components';
+
+import { link } from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import ColorEdit from './color-edit';
+import styles from './editor.scss';
+import { cleanEmptyObject } from '../../../block-editor/src/hooks/utils';
+
+const MIN_BORDER_RADIUS_VALUE = 0;
+const MAX_BORDER_RADIUS_VALUE = 50;
+
+function WidthPanel( { selectedWidth, setAttributes } ) {
+ function handleChange( newWidth ) {
+ // Check if we are toggling the width off
+ let width = selectedWidth === newWidth ? undefined : newWidth;
+ if ( newWidth === 'auto' ) {
+ width = undefined;
+ }
+ // Update attributes
+ setAttributes( { width } );
+ }
+
+ const options = [
+ { value: 'auto', label: __( 'Auto' ) },
+ { value: 25, label: '25%' },
+ { value: 50, label: '50%' },
+ { value: 75, label: '75%' },
+ { value: 100, label: '100%' },
+ ];
+
+ if ( ! selectedWidth ) {
+ selectedWidth = 'auto';
+ }
+
+ return (
+
+
+
+ );
+}
+
+const PaddingInputs = ( props ) => {
+ const {
+ values,
+ units,
+ sides,
+ onChange,
+ onChangeUnits,
+ unitOptions,
+ } = props;
+
+ const LABELS = {
+ top: __( 'Top' ),
+ bottom: __( 'Bottom' ),
+ left: __( 'Left' ),
+ right: __( 'Right' ),
+ };
+
+ const handleOnChange = ( nextValues ) => {
+ onChange( nextValues );
+ };
+
+ const handleOnChangeUnits = ( nextUnits ) => {
+ onChangeUnits( nextUnits );
+ };
+
+ const createHandleOnChange = ( side ) => ( next ) => {
+ const nextValues = { ...values };
+ nextValues[ side ] = next;
+ handleOnChange( nextValues );
+ };
+
+ const createHandleOnUnitChange = ( side ) => ( next ) => {
+ const nextUnits = { ...units };
+ nextUnits[ side ] = next;
+ handleOnChangeUnits( nextUnits );
+ };
+
+ return (
+ <>
+ { sides.map( ( side ) => (
+
+ ) ) }
+ >
+ );
+};
+
+const PaddingPanel = ( props ) => {
+ const {
+ attributes: { style },
+ setAttributes,
+ defaultPadding,
+ } = props;
+
+ const customPaddingSelections = style?.spacing?.padding || {};
+
+ const sides = [ 'top', 'bottom', 'left', 'right' ];
+ const values = {};
+ const units = {};
+
+ sides.forEach( ( side ) => {
+ // Get custom padding selection from the style attribute, falling back to default.
+ const paddingForSide = customPaddingSelections[ side ]
+ ? customPaddingSelections[ side ]
+ : defaultPadding[ side ];
+
+ // Break out into value and unit, as UnitControl for native requires setting unit and value separately.
+ const { valueToConvert, valueUnit } =
+ getValueAndUnit( paddingForSide ) || {};
+ values[ side ] = valueToConvert;
+ units[ side ] = valueUnit;
+ } );
+
+ const unitOptions = useCustomUnits( {
+ availableUnits: useSetting( 'spacing.units' ) || [
+ 'px',
+ 'em',
+ 'rem',
+ 'vw',
+ 'vh',
+ ],
+ defaultValues: { px: '430', em: '20', rem: '20', vw: '20', vh: '50' },
+ } );
+
+ // Update the style object with new padding selections.
+ const updatePadding = ( nextValues, nextUnits ) => {
+ const updatedPaddingValues = getValuesWithUnits(
+ nextValues,
+ nextUnits
+ );
+ const newStyle = {
+ ...style,
+ spacing: {
+ ...style?.spacing,
+ padding: {
+ ...updatedPaddingValues,
+ },
+ },
+ };
+ setAttributes( {
+ style: cleanEmptyObject( newStyle ),
+ } );
+ };
+
+ // Get the values with units, for updating the style.
+ const getValuesWithUnits = ( nextValues, nextUnits ) => {
+ const valuesWithUnits = {};
+ sides.forEach( ( side ) => {
+ valuesWithUnits[
+ side
+ ] = `${ nextValues[ side ] }${ nextUnits[ side ] }`;
+ } );
+
+ return valuesWithUnits;
+ };
+
+ // Update when a value was changed.
+ const handleChange = ( nextValues ) => {
+ updatePadding( nextValues, units );
+ };
+
+ // Update when a unit was changed.
+ const handleUnitsChange = ( nextUnits ) => {
+ updatePadding( values, nextUnits );
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default function Controls( {
+ attributes,
+ setAttributes,
+ clientId,
+ borderRadiusValue,
+ getLinkSettings,
+ onShowLinkSettings,
+ onChangeBorderRadius,
+ defaultPadding,
+} ) {
+ const { url, width } = attributes;
+
+ return (
+ <>
+
+
+
+
+
+ { getLinkSettings( false ) }
+
+
+
+
+
+
+
+
+ { getLinkSettings( true ) }
+
+
+ >
+ );
+}
diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js
index 70ce701138999b..c9d795890d65b4 100644
--- a/packages/block-library/src/button/edit.js
+++ b/packages/block-library/src/button/edit.js
@@ -24,6 +24,7 @@ import {
RichText,
useBlockProps,
__experimentalUseColorProps as useColorProps,
+ __experimentalGetSpacingClassesAndStyles as useSpacingProps,
__experimentalLinkControl as LinkControl,
} from '@wordpress/block-editor';
import { rawShortcut, displayShortcut } from '@wordpress/keycodes';
@@ -198,6 +199,7 @@ function ButtonEdit( props ) {
const borderRadius = style?.border?.radius;
const colorProps = useColorProps( attributes );
+ const spacingProps = useSpacingProps( attributes );
const ref = useRef();
const blockProps = useBlockProps( { ref } );
@@ -229,6 +231,7 @@ function ButtonEdit( props ) {
? borderRadius + 'px'
: undefined,
...colorProps.style,
+ ...spacingProps.style,
} }
onSplit={ ( value ) =>
createBlock( 'core/button', {
diff --git a/packages/block-library/src/button/edit.native.js b/packages/block-library/src/button/edit.native.js
index 7818d3e37d197a..db18e60af68a2f 100644
--- a/packages/block-library/src/button/edit.native.js
+++ b/packages/block-library/src/button/edit.native.js
@@ -2,32 +2,28 @@
* External dependencies
*/
import { View, AccessibilityInfo, Platform, Text } from 'react-native';
+import { get } from 'lodash';
+
/**
* WordPress dependencies
*/
-import { withInstanceId, compose } from '@wordpress/compose';
+import { withInstanceId, compose, usePrevious } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import {
RichText,
- InspectorControls,
- BlockControls,
withGradient,
store as blockEditorStore,
getColorObjectByAttributeValues,
getGradientValueBySlug,
__experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
+ __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles,
} from '@wordpress/block-editor';
import {
- PanelBody,
- RangeControl,
- ToolbarGroup,
- ToolbarButton,
LinkSettingsNavigation,
- BottomSheetSelectControl,
+ useConvertUnitToMobile,
} from '@wordpress/components';
-import { Component } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
-import { link } from '@wordpress/icons';
+import { useEffect, useState, useRef } from '@wordpress/element';
/**
* Internal dependencies
@@ -35,10 +31,8 @@ import { link } from '@wordpress/icons';
import richTextStyle from './rich-text.scss';
import styles from './editor.scss';
import ColorBackground from './color-background';
-import ColorEdit from './color-edit';
+import Controls from './controls';
-const MIN_BORDER_RADIUS_VALUE = 0;
-const MAX_BORDER_RADIUS_VALUE = 50;
const INITIAL_MAX_WIDTH = 108;
const MIN_WIDTH = 40;
// Map of the percentage width to pixel subtraction that make the buttons fit nicely into columns.
@@ -49,145 +43,138 @@ const MIN_WIDTH_MARGINS = {
25: styles.button25?.marginLeft,
};
-function WidthPanel( { selectedWidth, setAttributes } ) {
- function handleChange( newWidth ) {
- // Check if we are toggling the width off
- let width = selectedWidth === newWidth ? undefined : newWidth;
- if ( newWidth === 'auto' ) {
- width = undefined;
- }
- // Update attributes
- setAttributes( { width } );
- }
+const DEFAULT_PADDING = {
+ top: '0px',
+ bottom: '0px',
+ left: richTextStyle.richText.paddingLeft + 'px',
+ right: richTextStyle.richText.paddingRight + 'px',
+};
- const options = [
- { value: 'auto', label: __( 'Auto' ) },
- { value: 25, label: '25%' },
- { value: 50, label: '50%' },
- { value: 75, label: '75%' },
- { value: 100, label: '100%' },
+const ButtonEdit = ( {
+ attributes,
+ colors,
+ gradients,
+ isSelected,
+ clientId,
+ onReplace,
+ mergeBlocks,
+ parentWidth,
+ setAttributes,
+ editorSidebarOpened,
+ numOfButtons,
+ onDeleteBlock,
+ closeSettingsBottomSheet,
+} ) => {
+ const {
+ placeholder,
+ text,
+ borderRadius,
+ align = 'center',
+ width,
+ gradient,
+ } = attributes;
+ const [ maxWidth, setMaxWidth ] = useState( INITIAL_MAX_WIDTH );
+ const [ isLinkSheetVisible, setIsLinkSheetVisible ] = useState( false );
+ const [ isButtonFocused, setIsButtonFocused ] = useState( true );
+ const [ placeholderTextWidth, setPlaceholderTextWidth ] = useState( 0 );
+ const richTextRef = useRef( null );
+
+ const prevParentWidth = usePrevious( parentWidth );
+ const wasSelected = usePrevious( isSelected );
+ const wasEditorSidebarOpened = usePrevious( editorSidebarOpened );
+ const wasLinkSheetVisible = usePrevious( isLinkSheetVisible );
+
+ const linkSettingsActions = [
+ {
+ label: __( 'Remove link' ),
+ onPress: onClearSettings,
+ },
];
- if ( ! selectedWidth ) {
- selectedWidth = 'auto';
- }
-
- return (
-
-
-
- );
-}
-
-class ButtonEdit extends Component {
- constructor( props ) {
- super( props );
- this.onChangeText = this.onChangeText.bind( this );
- this.onChangeBorderRadius = this.onChangeBorderRadius.bind( this );
- this.onClearSettings = this.onClearSettings.bind( this );
- this.onLayout = this.onLayout.bind( this );
- this.onSetMaxWidth = this.onSetMaxWidth.bind( this );
- this.dismissSheet = this.dismissSheet.bind( this );
- this.onShowLinkSettings = this.onShowLinkSettings.bind( this );
- this.onHideLinkSettings = this.onHideLinkSettings.bind( this );
- this.onToggleButtonFocus = this.onToggleButtonFocus.bind( this );
- this.onPlaceholderTextWidth = this.onPlaceholderTextWidth.bind( this );
- this.setRef = this.setRef.bind( this );
- this.onRemove = this.onRemove.bind( this );
- this.getPlaceholderWidth = this.getPlaceholderWidth.bind( this );
-
- this.state = {
- maxWidth: INITIAL_MAX_WIDTH,
- isLinkSheetVisible: false,
- isButtonFocused: true,
- placeholderTextWidth: 0,
- };
-
- this.linkSettingsActions = [
- {
- label: __( 'Remove link' ),
- onPress: this.onClearSettings,
- },
- ];
-
- this.linkSettingsOptions = {
- url: {
- label: __( 'Button Link URL' ),
- placeholder: __( 'Add URL' ),
- autoFocus: true,
- autoFill: true,
- },
- openInNewTab: {
- label: __( 'Open in new tab' ),
- },
- linkRel: {
- label: __( 'Link Rel' ),
- placeholder: __( 'None' ),
- },
- };
-
- this.noFocusLinkSettingOptions = {
- ...this.linkSettingsOptions,
- url: {
- ...this.linkSettingsOptions.url,
- autoFocus: false,
- },
- };
- }
-
- componentDidMount() {
- this.onSetMaxWidth();
- }
-
- componentDidUpdate( prevProps, prevState ) {
- const { isSelected, editorSidebarOpened, parentWidth } = this.props;
- const { isLinkSheetVisible, isButtonFocused } = this.state;
-
- if ( isSelected && ! prevProps.isSelected ) {
- this.onToggleButtonFocus( true );
+ const linkSettingsOptions = {
+ url: {
+ label: __( 'Button Link URL' ),
+ placeholder: __( 'Add URL' ),
+ autoFocus: true,
+ autoFill: true,
+ },
+ openInNewTab: {
+ label: __( 'Open in new tab' ),
+ },
+ linkRel: {
+ label: __( 'Link Rel' ),
+ placeholder: __( 'None' ),
+ },
+ };
+
+ const noFocusLinkSettingOptions = {
+ ...linkSettingsOptions,
+ url: {
+ ...linkSettingsOptions.url,
+ autoFocus: false,
+ },
+ };
+
+ useEffect( () => {
+ onSetMaxWidth();
+ }, [] );
+
+ useEffect( () => {
+ if ( isSelected && ! wasSelected ) {
+ onToggleButtonFocus( true );
}
- if ( prevProps.parentWidth !== parentWidth ) {
- this.onSetMaxWidth( null, true );
+ if ( prevParentWidth !== parentWidth ) {
+ onSetMaxWidth( null, true );
}
// Blur `RichText` on Android when link settings sheet or button settings sheet is opened,
// to avoid flashing caret after closing one of them
if (
- ( ! prevProps.editorSidebarOpened && editorSidebarOpened ) ||
- ( ! prevState.isLinkSheetVisible && isLinkSheetVisible )
+ ( ! wasEditorSidebarOpened && editorSidebarOpened ) ||
+ ( ! wasLinkSheetVisible && isLinkSheetVisible )
) {
- if ( Platform.OS === 'android' && this.richTextRef ) {
- this.richTextRef.blur();
- this.onToggleButtonFocus( false );
+ if (
+ Platform.OS === 'android' &&
+ richTextRef &&
+ richTextRef.current
+ ) {
+ richTextRef.current.blur();
+ onToggleButtonFocus( false );
}
}
- if ( this.richTextRef ) {
+ if ( richTextRef.current ) {
if ( ! isSelected && isButtonFocused ) {
- this.onToggleButtonFocus( false );
+ onToggleButtonFocus( false );
}
if ( isSelected && ! isButtonFocused ) {
AccessibilityInfo.isScreenReaderEnabled().then( ( enabled ) => {
if ( enabled ) {
- this.onToggleButtonFocus( true );
- this.richTextRef.focus();
+ onToggleButtonFocus( true );
+ richTextRef.current.focus();
}
} );
}
}
- }
-
- getBackgroundColor() {
- const { attributes, colors, gradients } = this.props;
- const { backgroundColor, gradient } = attributes;
-
+ }, [
+ isSelected,
+ editorSidebarOpened,
+ parentWidth,
+ isLinkSheetVisible,
+ isButtonFocused,
+ wasSelected,
+ wasEditorSidebarOpened,
+ wasLinkSheetVisible,
+ richTextRef.current,
+ ] );
+
+ const setRef = ( nodeRef ) => {
+ richTextRef.current = nodeRef;
+ };
+
+ const getBackgroundColor = () => {
// Return named gradient value if available.
const gradientValue = getGradientValueBySlug( gradients, gradient );
@@ -201,7 +188,7 @@ class ButtonEdit extends Component {
// do not load their color stylesheets in the editor.
const colorObject = getColorObjectByAttributeValues(
colors,
- backgroundColor
+ attributes.backgroundColor
);
return (
@@ -210,10 +197,9 @@ class ButtonEdit extends Component {
colorProps.style?.background ||
styles.defaultButton.backgroundColor
);
- }
+ };
- getTextColor() {
- const { attributes, colors } = this.props;
+ const getTextColor = () => {
const colorProps = getColorClassesAndStyles( attributes );
// Retrieve named color object to force inline styles for themes that
@@ -228,294 +214,240 @@ class ButtonEdit extends Component {
colorProps.style?.color ||
styles.defaultButton.color
);
- }
+ };
- onChangeText( value ) {
- const { setAttributes } = this.props;
+ const onChangeText = ( value ) => {
setAttributes( { text: value } );
- }
+ };
- onChangeBorderRadius( value ) {
- const { setAttributes } = this.props;
+ const onChangeBorderRadius = ( value ) => {
setAttributes( {
borderRadius: value,
} );
- }
+ };
- onShowLinkSettings() {
- this.setState( { isLinkSheetVisible: true } );
- }
+ const onShowLinkSettings = () => {
+ setIsLinkSheetVisible( true );
+ };
- onHideLinkSettings() {
- this.setState( { isLinkSheetVisible: false } );
- }
-
- onToggleButtonFocus( value ) {
- if ( value !== this.state.isButtonFocused ) {
- this.setState( { isButtonFocused: value } );
- }
- }
-
- onClearSettings() {
- const { setAttributes } = this.props;
+ const onHideLinkSettings = () => {
+ setIsLinkSheetVisible( false );
+ };
+ const onClearSettings = () => {
setAttributes( {
url: '',
rel: '',
linkTarget: '',
} );
- this.onHideLinkSettings();
- }
+ onHideLinkSettings();
+ };
- onLayout( { nativeEvent } ) {
- const { width } = nativeEvent.layout;
- this.onSetMaxWidth( width );
- }
+ const onToggleButtonFocus = ( value ) => {
+ if ( value !== isButtonFocused ) {
+ setIsButtonFocused( value );
+ }
+ };
+
+ const onLayout = ( { nativeEvent } ) => {
+ const { layoutWidth } = nativeEvent.layout;
+ onSetMaxWidth( layoutWidth );
+ };
- onSetMaxWidth( width, isParentWidthDidChange = false ) {
- const { maxWidth } = this.state;
- const { parentWidth } = this.props;
+ const onSetMaxWidth = ( newWidth, isParentWidthDidChange = false ) => {
const { marginRight: spacing } = styles.defaultButton;
const isParentWidthChanged = isParentWidthDidChange
? isParentWidthDidChange
: maxWidth !== parentWidth;
- const isWidthChanged = maxWidth !== width;
-
- if ( parentWidth && ! width && isParentWidthChanged ) {
- this.setState( {
- maxWidth: parentWidth - spacing,
- } );
- } else if ( ! parentWidth && width && isWidthChanged ) {
- this.setState( { maxWidth: width - spacing } );
- }
- }
+ const isWidthChanged = maxWidth !== newWidth;
- onRemove() {
- const { numOfButtons, onDeleteBlock, onReplace } = this.props;
+ if ( parentWidth && ! newWidth && isParentWidthChanged ) {
+ setMaxWidth( parentWidth - spacing );
+ } else if ( ! parentWidth && newWidth && isWidthChanged ) {
+ setMaxWidth( newWidth - spacing );
+ }
+ };
+ const onRemove = () => {
if ( numOfButtons === 1 ) {
onDeleteBlock();
} else {
onReplace( [] );
}
- }
+ };
- dismissSheet() {
- this.onHideLinkSettings();
- this.props.closeSettingsBottomSheet();
- }
+ const dismissSheet = () => {
+ onHideLinkSettings();
+ closeSettingsBottomSheet();
+ };
- getLinkSettings( isCompatibleWithSettings ) {
- const { isLinkSheetVisible } = this.state;
- const { attributes, setAttributes } = this.props;
+ const getLinkSettings = ( isCompatibleWithSettings ) => {
return (
);
- }
-
- setRef( richText ) {
- this.richTextRef = richText;
- }
+ };
// Render `Text` with `placeholderText` styled as a placeholder
// to calculate its width which then is set as a `minWidth`
- getPlaceholderWidth( placeholderText ) {
+ const getPlaceholderWidth = ( placeholderText ) => {
return (
{ placeholderText }
);
- }
+ };
- onPlaceholderTextWidth( { nativeEvent } ) {
- const { maxWidth, placeholderTextWidth } = this.state;
+ const onPlaceholderTextWidth = ( { nativeEvent } ) => {
const textWidth =
nativeEvent.lines[ 0 ] && nativeEvent.lines[ 0 ].width;
if ( textWidth && textWidth !== placeholderTextWidth ) {
- this.setState( {
- placeholderTextWidth: Math.min( textWidth, maxWidth ),
- } );
+ setPlaceholderTextWidth( Math.min( textWidth, maxWidth ) );
}
+ };
+
+ const paddingStyles = getSpacingClassesAndStyles( attributes ).style;
+
+ // Convert units for mobile.
+ const convertedPadding = {
+ paddingTop: useConvertUnitToMobile(
+ get( paddingStyles, 'paddingTop', DEFAULT_PADDING.top )
+ ),
+ paddingBottom: useConvertUnitToMobile(
+ get( paddingStyles, 'paddingBottom', DEFAULT_PADDING.bottom )
+ ),
+ paddingLeft: useConvertUnitToMobile(
+ get( paddingStyles, 'paddingLeft', DEFAULT_PADDING.left )
+ ),
+ paddingRight: useConvertUnitToMobile(
+ get( paddingStyles, 'paddingRight', DEFAULT_PADDING.right )
+ ),
+ };
+
+ if ( parentWidth === 0 ) {
+ return null;
}
- render() {
- const {
- attributes,
- isSelected,
- clientId,
- onReplace,
- mergeBlocks,
- parentWidth,
- setAttributes,
- } = this.props;
- const {
- placeholder,
- text,
- borderRadius,
- url,
- align = 'center',
- width,
- } = attributes;
- const { maxWidth, isButtonFocused, placeholderTextWidth } = this.state;
- const { paddingTop: spacing, borderWidth } = styles.defaultButton;
-
- if ( parentWidth === 0 ) {
- return null;
- }
-
- const borderRadiusValue = Number.isInteger( borderRadius )
- ? borderRadius
- : styles.defaultButton.borderRadius;
- const outlineBorderRadius =
- borderRadiusValue > 0
- ? borderRadiusValue + spacing + borderWidth
- : 0;
-
- // To achieve proper expanding and shrinking `RichText` on iOS, there is a need to set a `minWidth`
- // value at least on 1 when `RichText` is focused or when is not focused, but `RichText` value is
- // different than empty string.
- let minWidth =
- isButtonFocused || ( ! isButtonFocused && text && text !== '' )
- ? MIN_WIDTH
- : placeholderTextWidth;
- if ( width ) {
- // Set the width of the button.
- minWidth = Math.floor(
- maxWidth * ( width / 100 ) - MIN_WIDTH_MARGINS[ width ]
- );
- }
- // To achieve proper expanding and shrinking `RichText` on Android, there is a need to set
- // a `placeholder` as an empty string when `RichText` is focused,
- // because `AztecView` is calculating a `minWidth` based on placeholder text.
- const placeholderText =
- isButtonFocused || ( ! isButtonFocused && text && text !== '' )
- ? ''
- : placeholder || __( 'Add text…' );
-
- const backgroundColor = this.getBackgroundColor();
- const textColor = this.getTextColor();
- const isFixedWidth = !! width;
-
- return (
-
- { this.getPlaceholderWidth( placeholderText ) }
-
- { isSelected && (
-
- ) }
-
- this.onToggleButtonFocus( true )
- }
- __unstableMobileNoFocusOnMount={ ! isSelected }
- selectionColor={ textColor }
- onBlur={ () => {
- this.onSetMaxWidth();
- } }
- onReplace={ onReplace }
- onRemove={ this.onRemove }
- onMerge={ mergeBlocks }
- />
-
+ const { paddingTop: spacing, borderWidth } = styles.defaultButton;
+
+ const borderRadiusValue = Number.isInteger( borderRadius )
+ ? borderRadius
+ : styles.defaultButton.borderRadius;
+ const outlineBorderRadius =
+ borderRadiusValue > 0 ? borderRadiusValue + spacing + borderWidth : 0;
+
+ // To achieve proper expanding and shrinking `RichText` on iOS, there is a need to set a `minWidth`
+ // value at least on 1 when `RichText` is focused or when is not focused, but `RichText` value is
+ // different than empty string.
+ let minWidth =
+ isButtonFocused || ( ! isButtonFocused && text && text !== '' )
+ ? MIN_WIDTH
+ : placeholderTextWidth;
+ if ( width ) {
+ // Set the width of the button.
+ minWidth = Math.floor(
+ maxWidth * ( width / 100 ) - MIN_WIDTH_MARGINS[ width ]
+ );
+ }
+ // To achieve proper expanding and shrinking `RichText` on Android, there is a need to set
+ // a `placeholder` as an empty string when `RichText` is focused,
+ // because `AztecView` is calculating a `minWidth` based on placeholder text.
+ const placeholderText =
+ isButtonFocused || ( ! isButtonFocused && text && text !== '' )
+ ? ''
+ : placeholder || __( 'Add text…' );
+
+ const backgroundColor = getBackgroundColor();
+ const textColor = getTextColor();
+ const isFixedWidth = !! width;
+ return (
+
+ { getPlaceholderWidth( placeholderText ) }
+
{ isSelected && (
- <>
-
-
-
-
-
- { this.getLinkSettings( false ) }
-
-
-
-
-
-
-
- { this.getLinkSettings( true ) }
-
-
- >
+
) }
-
- );
- }
-}
+ onToggleButtonFocus( true ) }
+ __unstableMobileNoFocusOnMount={ ! isSelected }
+ selectionColor={ textColor }
+ onBlur={ () => {
+ onSetMaxWidth();
+ } }
+ onReplace={ onReplace }
+ onRemove={ onRemove }
+ onMerge={ mergeBlocks }
+ />
+
+
+ { isSelected && (
+
+ ) }
+
+ );
+};
export default compose( [
withInstanceId,
diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js
index 695e27e07b5b40..a09d35a6447c15 100644
--- a/packages/block-library/src/button/save.js
+++ b/packages/block-library/src/button/save.js
@@ -10,6 +10,7 @@ import {
RichText,
useBlockProps,
__experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
+ __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles,
} from '@wordpress/block-editor';
export default function save( { attributes, className } ) {
@@ -30,6 +31,7 @@ export default function save( { attributes, className } ) {
const borderRadius = style?.border?.radius;
const colorProps = getColorClassesAndStyles( attributes );
+ const spacingProps = getSpacingClassesAndStyles( attributes );
const buttonClasses = classnames(
'wp-block-button__link',
colorProps.className,
@@ -40,6 +42,7 @@ export default function save( { attributes, className } ) {
const buttonStyle = {
borderRadius: borderRadius ? borderRadius + 'px' : undefined,
...colorProps.style,
+ ...spacingProps.style,
};
// The use of a `title` attribute here is soft-deprecated, but still applied