From 11363573e67bffdf0ff98a2a58cabb830c20c25b Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Mon, 24 May 2021 13:27:26 -0700 Subject: [PATCH 1/6] Refactor Button to functional component --- .../src/button/controls.native.js | 107 +++ .../block-library/src/button/edit.native.js | 632 ++++++++---------- 2 files changed, 372 insertions(+), 367 deletions(-) create mode 100644 packages/block-library/src/button/controls.native.js 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..637bf38b274fe0 --- /dev/null +++ b/packages/block-library/src/button/controls.native.js @@ -0,0 +1,107 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { InspectorControls, BlockControls } from '@wordpress/block-editor'; +import { + PanelBody, + RangeControl, + ToolbarGroup, + ToolbarButton, + BottomSheetSelectControl, +} from '@wordpress/components'; +import { link } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import ColorEdit from './color-edit'; + +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 ( + + + + ); +} + +export default function Controls ( { + attributes, + setAttributes, + clientId, + borderRadiusValue, + getLinkSettings, + onShowLinkSettings, + onChangeBorderRadius, +} ) { + const { url, width } = attributes; + + return ( + <> + + + + + + { getLinkSettings( false ) } + + + + + + + + { getLinkSettings( true ) } + + + + ); +}; diff --git a/packages/block-library/src/button/edit.native.js b/packages/block-library/src/button/edit.native.js index 923ed47282efb8..9f7ff6729131ad 100644 --- a/packages/block-library/src/button/edit.native.js +++ b/packages/block-library/src/button/edit.native.js @@ -9,25 +9,15 @@ import { withInstanceId, compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { RichText, - InspectorControls, - BlockControls, withGradient, store as blockEditorStore, getColorObjectByAttributeValues, getGradientValueBySlug, __experimentalGetColorClassesAndStyles as getColorClassesAndStyles, } from '@wordpress/block-editor'; -import { - PanelBody, - RangeControl, - ToolbarGroup, - ToolbarButton, - LinkSettingsNavigation, - BottomSheetSelectControl, -} from '@wordpress/components'; -import { Component } from '@wordpress/element'; +import { LinkSettingsNavigation } from '@wordpress/components'; import { withSelect, withDispatch } from '@wordpress/data'; -import { link } from '@wordpress/icons'; +import { useEffect, useState, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -35,9 +25,8 @@ import { link } from '@wordpress/icons'; import richTextStyle from './rich-text.scss'; import styles from './editor.scss'; import ColorBackground from './color-background'; +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. @@ -48,145 +37,142 @@ 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 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'; - } +const usePrevious = ( value ) => { + const ref = useRef(); - 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, - }; + useEffect( () => { + ref.current = value; + }, [ value ] ); - 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' ), - }, - }; + return ref.current; +}; - this.noFocusLinkSettingOptions = { - ...this.linkSettingsOptions, - url: { - ...this.linkSettingsOptions.url, - autoFocus: false, - }, - }; - } +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 onClearSettings = () => { + setAttributes( { + url: '', + rel: '', + linkTarget: '', + } ); - componentDidMount() { - this.onSetMaxWidth(); - } + onHideLinkSettings(); + }; - componentDidUpdate( prevProps, prevState ) { - const { isSelected, editorSidebarOpened, parentWidth } = this.props; - const { isLinkSheetVisible, isButtonFocused } = this.state; + const linkSettingsActions = [ + { + label: __( 'Remove link' ), + onPress: onClearSettings, + }, + ]; - 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.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, style } = this.props; - const { backgroundColor, gradient } = attributes; - + }, [ + isSelected, + editorSidebarOpened, + parentWidth, + isLinkSheetVisible, + isButtonFocused, + wasSelected, + wasEditorSidebarOpened, + wasLinkSheetVisible, + ] ); + + const getBackgroundColor = () => { // Return named gradient value if available. const gradientValue = getGradientValueBySlug( gradients, gradient ); @@ -200,7 +186,7 @@ class ButtonEdit extends Component { // do not load their color stylesheets in the editor. const colorObject = getColorObjectByAttributeValues( colors, - backgroundColor + attributes.backgroundColor ); return ( @@ -210,10 +196,9 @@ class ButtonEdit extends Component { style?.backgroundColor || styles.defaultButton.backgroundColor ); - } + }; - getTextColor() { - const { attributes, colors, style } = this.props; + const getTextColor = () => { const colorProps = getColorClassesAndStyles( attributes ); // Retrieve named color object to force inline styles for themes that @@ -229,303 +214,216 @@ class ButtonEdit extends Component { style?.color || styles.defaultButton.color ); - } + }; - onChangeText( value ) { - const { setAttributes } = this.props; + const onChangeText = ( value ) => { setAttributes( { text: value } ); - } + }; - onChangeBorderRadius( newRadius ) { - const { setAttributes, attributes } = this.props; - const { style } = attributes; - const newStyle = { - ...style, - border: { - ...style?.border, - radius: newRadius, - }, - }; - - setAttributes( { style: newStyle } ); - } + const onChangeBorderRadius = ( value ) => { + setAttributes( { + borderRadius: value, + } ); + }; - onShowLinkSettings() { - this.setState( { isLinkSheetVisible: true } ); - } + const onShowLinkSettings = () => { + setIsLinkSheetVisible( true ); + }; - onHideLinkSettings() { - this.setState( { isLinkSheetVisible: false } ); - } + const onHideLinkSettings = () => { + setIsLinkSheetVisible( false ); + }; - onToggleButtonFocus( value ) { - if ( value !== this.state.isButtonFocused ) { - this.setState( { isButtonFocused: value } ); + const onToggleButtonFocus = ( value ) => { + if ( value !== isButtonFocused ) { + setIsButtonFocused( value ); } - } - - onClearSettings() { - const { setAttributes } = this.props; - - setAttributes( { - url: '', - rel: '', - linkTarget: '', - } ); + }; - this.onHideLinkSettings(); - } - - onLayout( { nativeEvent } ) { - const { width } = nativeEvent.layout; - this.onSetMaxWidth( width ); - } + 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 ) ); } - } + }; - render() { - const { - attributes, - isSelected, - clientId, - onReplace, - mergeBlocks, - parentWidth, - setAttributes, - style, - } = this.props; - const { - placeholder, - text, - style: buttonStyle, - url, - align = 'center', - width, - } = attributes; - const { maxWidth, isButtonFocused, placeholderTextWidth } = this.state; - const { paddingTop: spacing, borderWidth } = styles.defaultButton; - - if ( parentWidth === 0 ) { - return null; - } + const { paddingTop: spacing, borderWidth } = styles.defaultButton; - const borderRadius = buttonStyle?.border?.radius; - - 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; + if ( parentWidth === 0 ) { + return null; + } - return ( - - { this.getPlaceholderWidth( placeholderText ) } - - { isSelected && ( - - ) } - - this.onToggleButtonFocus( true ) - } - __unstableMobileNoFocusOnMount={ ! isSelected } - selectionColor={ textColor } - onBlur={ () => { - this.onSetMaxWidth(); - } } - onReplace={ onReplace } - onRemove={ this.onRemove } - onMerge={ mergeBlocks } - /> - + 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, From 4d93ddd535c21c5edf011e00410984c668b80941 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Wed, 12 May 2021 13:43:08 -0700 Subject: [PATCH 2/6] Add a utility for getting the spacing inline styles --- packages/block-editor/src/hooks/index.js | 1 + .../src/hooks/use-spacing-props.js | 27 +++++++++++++++++++ packages/block-editor/src/index.js | 1 + 3 files changed, 29 insertions(+) create mode 100644 packages/block-editor/src/hooks/use-spacing-props.js diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 3308b98d281696..ce5b677a64f615 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 { useSpacingProps } 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..305efda5903d24 --- /dev/null +++ b/packages/block-editor/src/hooks/use-spacing-props.js @@ -0,0 +1,27 @@ +/** + * 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. + +/** + * Determines the spacing related props for a block derived from its spacing block + * support attributes. + * + * @param {Object} attributes Block attributes. + * @return {Object} ClassName & style props from spacing block support. + */ +export function useSpacingProps( 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 1e567a9c295af4..8c2d114da18299 100644 --- a/packages/block-editor/src/index.js +++ b/packages/block-editor/src/index.js @@ -8,6 +8,7 @@ export { getColorClassesAndStyles as __experimentalGetColorClassesAndStyles, useColorProps as __experimentalUseColorProps, useCustomSides as __experimentalUseCustomSides, + useSpacingProps as __experimentalUseSpacingProps, } from './hooks'; export * from './components'; export * from './utils'; From 0fa155651af4e8c286b4f352d4f042477241bff1 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Wed, 12 May 2021 13:50:21 -0700 Subject: [PATCH 3/6] Add padding support to the Button block --- packages/block-library/src/button/block.json | 4 ++++ packages/block-library/src/button/edit.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index f2e4a52debd81a..d954cc3c40e991 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -66,6 +66,10 @@ "__experimentalFontFamily": true }, "reusable": false, + "spacing": { + "__experimentalSkipSerialization": true, + "padding": true + }, "__experimentalBorder": { "radius": true, "__experimentalSkipSerialization": true diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 079185d8e2e39e..a0cf9ce515a483 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -25,6 +25,7 @@ import { useBlockProps, __experimentalUseBorderProps as useBorderProps, __experimentalUseColorProps as useColorProps, + __experimentalUseSpacingProps as useSpacingProps, __experimentalLinkControl as LinkControl, } from '@wordpress/block-editor'; import { rawShortcut, displayShortcut } from '@wordpress/keycodes'; @@ -199,6 +200,7 @@ function ButtonEdit( props ) { const borderProps = useBorderProps( attributes ); const colorProps = useColorProps( attributes ); + const spacingProps = useSpacingProps( attributes ); const ref = useRef(); const blockProps = useBlockProps( { ref } ); @@ -231,6 +233,7 @@ function ButtonEdit( props ) { style={ { ...borderProps.style, ...colorProps.style, + ...spacingProps.style, } } onSplit={ ( value ) => createBlock( 'core/button', { From 0c298fc2fcadf55c6d7b638b89ba8cefa3642232 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Wed, 12 May 2021 16:21:06 -0700 Subject: [PATCH 4/6] Reflect style selection on frontend --- packages/block-editor/src/hooks/index.js | 2 +- packages/block-editor/src/hooks/use-spacing-props.js | 9 +++++---- packages/block-editor/src/index.js | 2 +- packages/block-library/src/button/edit.js | 2 +- packages/block-library/src/button/save.js | 3 +++ 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index ce5b677a64f615..c0e5c1b5f8bb85 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -15,4 +15,4 @@ import './layout'; export { useCustomSides } from './spacing'; export { getBorderClassesAndStyles, useBorderProps } from './use-border-props'; export { getColorClassesAndStyles, useColorProps } from './use-color-props'; -export { useSpacingProps } from './use-spacing-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 index 305efda5903d24..35fe87c1e5ec40 100644 --- a/packages/block-editor/src/hooks/use-spacing-props.js +++ b/packages/block-editor/src/hooks/use-spacing-props.js @@ -8,13 +8,14 @@ import { getInlineStyles } from './style'; // styles still need to be generated so they can be applied to inner elements. /** - * Determines the spacing related props for a block derived from its spacing block - * support attributes. + * Provides the CSS class names and inline styles for a block's spacing support + * attributes. * * @param {Object} attributes Block attributes. - * @return {Object} ClassName & style props from spacing block support. + * + * @return {Object} Spacing block support derived CSS classes & styles. */ -export function useSpacingProps( attributes ) { +export function getSpacingClassesAndStyles( attributes ) { const { style } = attributes; // Collect inline styles for spacing. diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js index 8c2d114da18299..2720c2cd4c9588 100644 --- a/packages/block-editor/src/index.js +++ b/packages/block-editor/src/index.js @@ -8,7 +8,7 @@ export { getColorClassesAndStyles as __experimentalGetColorClassesAndStyles, useColorProps as __experimentalUseColorProps, useCustomSides as __experimentalUseCustomSides, - useSpacingProps as __experimentalUseSpacingProps, + getSpacingClassesAndStyles as __experimentalGetSpacingClassesAndStyles, } from './hooks'; export * from './components'; export * from './utils'; diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index a0cf9ce515a483..c0f80bc40ae0d2 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -25,7 +25,7 @@ import { useBlockProps, __experimentalUseBorderProps as useBorderProps, __experimentalUseColorProps as useColorProps, - __experimentalUseSpacingProps as useSpacingProps, + __experimentalGetSpacingClassesAndStyles as useSpacingProps, __experimentalLinkControl as LinkControl, } from '@wordpress/block-editor'; import { rawShortcut, displayShortcut } from '@wordpress/keycodes'; diff --git a/packages/block-library/src/button/save.js b/packages/block-library/src/button/save.js index d462cf52e6dd7b..1910044f9529a5 100644 --- a/packages/block-library/src/button/save.js +++ b/packages/block-library/src/button/save.js @@ -11,6 +11,7 @@ import { useBlockProps, __experimentalGetBorderClassesAndStyles as getBorderClassesAndStyles, __experimentalGetColorClassesAndStyles as getColorClassesAndStyles, + __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles, } from '@wordpress/block-editor'; export default function save( { attributes, className } ) { @@ -31,6 +32,7 @@ export default function save( { attributes, className } ) { const borderProps = getBorderClassesAndStyles( attributes ); const colorProps = getColorClassesAndStyles( attributes ); + const spacingProps = getSpacingClassesAndStyles( attributes ); const buttonClasses = classnames( 'wp-block-button__link', colorProps.className, @@ -44,6 +46,7 @@ export default function save( { attributes, className } ) { const buttonStyle = { ...borderProps.style, ...colorProps.style, + ...spacingProps.style, }; // The use of a `title` attribute here is soft-deprecated, but still applied From 1286e6b70b73d074f838aa2d1eeedb87576cc568 Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Thu, 20 May 2021 15:39:19 -0700 Subject: [PATCH 5/6] Fix error on mobile from missing export --- packages/block-editor/src/hooks/index.native.js | 1 + 1 file changed, 1 insertion(+) 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'; From ef6fb3a577eb1e2fe4195b26edcba71eb91d6afa Mon Sep 17 00:00:00 2001 From: Staci Cooper Date: Tue, 13 Jul 2021 10:45:01 -0700 Subject: [PATCH 6/6] Revert "Refactor Button to functional component" This reverts commit 7235697fd43925338b911cbbdc7399f59d05c84a --- .../src/button/controls.native.js | 107 --- .../block-library/src/button/edit.native.js | 632 ++++++++++-------- 2 files changed, 367 insertions(+), 372 deletions(-) delete mode 100644 packages/block-library/src/button/controls.native.js diff --git a/packages/block-library/src/button/controls.native.js b/packages/block-library/src/button/controls.native.js deleted file mode 100644 index 637bf38b274fe0..00000000000000 --- a/packages/block-library/src/button/controls.native.js +++ /dev/null @@ -1,107 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { InspectorControls, BlockControls } from '@wordpress/block-editor'; -import { - PanelBody, - RangeControl, - ToolbarGroup, - ToolbarButton, - BottomSheetSelectControl, -} from '@wordpress/components'; -import { link } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import ColorEdit from './color-edit'; - -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 ( - - - - ); -} - -export default function Controls ( { - attributes, - setAttributes, - clientId, - borderRadiusValue, - getLinkSettings, - onShowLinkSettings, - onChangeBorderRadius, -} ) { - const { url, width } = attributes; - - return ( - <> - - - - - - { getLinkSettings( false ) } - - - - - - - - { getLinkSettings( true ) } - - - - ); -}; diff --git a/packages/block-library/src/button/edit.native.js b/packages/block-library/src/button/edit.native.js index 9f7ff6729131ad..923ed47282efb8 100644 --- a/packages/block-library/src/button/edit.native.js +++ b/packages/block-library/src/button/edit.native.js @@ -9,15 +9,25 @@ import { withInstanceId, compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { RichText, + InspectorControls, + BlockControls, withGradient, store as blockEditorStore, getColorObjectByAttributeValues, getGradientValueBySlug, __experimentalGetColorClassesAndStyles as getColorClassesAndStyles, } from '@wordpress/block-editor'; -import { LinkSettingsNavigation } from '@wordpress/components'; +import { + PanelBody, + RangeControl, + ToolbarGroup, + ToolbarButton, + LinkSettingsNavigation, + BottomSheetSelectControl, +} from '@wordpress/components'; +import { Component } from '@wordpress/element'; import { withSelect, withDispatch } from '@wordpress/data'; -import { useEffect, useState, useRef } from '@wordpress/element'; +import { link } from '@wordpress/icons'; /** * Internal dependencies @@ -25,8 +35,9 @@ import { useEffect, useState, useRef } from '@wordpress/element'; import richTextStyle from './rich-text.scss'; import styles from './editor.scss'; import ColorBackground from './color-background'; -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. @@ -37,142 +48,145 @@ const MIN_WIDTH_MARGINS = { 25: styles.button25?.marginLeft, }; -const usePrevious = ( value ) => { - const ref = useRef(); +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 } ); + } - useEffect( () => { - ref.current = value; - }, [ value ] ); + const options = [ + { value: 'auto', label: __( 'Auto' ) }, + { value: 25, label: '25%' }, + { value: 50, label: '50%' }, + { value: 75, label: '75%' }, + { value: 100, label: '100%' }, + ]; - return ref.current; -}; + if ( ! selectedWidth ) { + selectedWidth = 'auto'; + } -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 onClearSettings = () => { - setAttributes( { - url: '', - rel: '', - linkTarget: '', - } ); + 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, + }; - onHideLinkSettings(); - }; + 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' ), + }, + }; - const linkSettingsActions = [ - { - label: __( 'Remove link' ), - onPress: onClearSettings, - }, - ]; + 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; - 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 ( isSelected && ! prevProps.isSelected ) { + this.onToggleButtonFocus( true ); } - if ( prevParentWidth !== parentWidth ) { - onSetMaxWidth( null, true ); + if ( prevProps.parentWidth !== parentWidth ) { + this.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 ( - ( ! wasEditorSidebarOpened && editorSidebarOpened ) || - ( ! wasLinkSheetVisible && isLinkSheetVisible ) + ( ! prevProps.editorSidebarOpened && editorSidebarOpened ) || + ( ! prevState.isLinkSheetVisible && isLinkSheetVisible ) ) { - if ( Platform.OS === 'android' && richTextRef.current ) { - richTextRef.current.blur(); - onToggleButtonFocus( false ); + if ( Platform.OS === 'android' && this.richTextRef ) { + this.richTextRef.blur(); + this.onToggleButtonFocus( false ); } } - if ( richTextRef.current ) { + if ( this.richTextRef ) { if ( ! isSelected && isButtonFocused ) { - onToggleButtonFocus( false ); + this.onToggleButtonFocus( false ); } if ( isSelected && ! isButtonFocused ) { AccessibilityInfo.isScreenReaderEnabled().then( ( enabled ) => { if ( enabled ) { - onToggleButtonFocus( true ); - richTextRef.current.focus(); + this.onToggleButtonFocus( true ); + this.richTextRef.focus(); } } ); } } - }, [ - isSelected, - editorSidebarOpened, - parentWidth, - isLinkSheetVisible, - isButtonFocused, - wasSelected, - wasEditorSidebarOpened, - wasLinkSheetVisible, - ] ); - - const getBackgroundColor = () => { + } + + getBackgroundColor() { + const { attributes, colors, gradients, style } = this.props; + const { backgroundColor, gradient } = attributes; + // Return named gradient value if available. const gradientValue = getGradientValueBySlug( gradients, gradient ); @@ -186,7 +200,7 @@ const ButtonEdit = ( { // do not load their color stylesheets in the editor. const colorObject = getColorObjectByAttributeValues( colors, - attributes.backgroundColor + backgroundColor ); return ( @@ -196,9 +210,10 @@ const ButtonEdit = ( { style?.backgroundColor || styles.defaultButton.backgroundColor ); - }; + } - const getTextColor = () => { + getTextColor() { + const { attributes, colors, style } = this.props; const colorProps = getColorClassesAndStyles( attributes ); // Retrieve named color object to force inline styles for themes that @@ -214,216 +229,303 @@ const ButtonEdit = ( { style?.color || styles.defaultButton.color ); - }; + } - const onChangeText = ( value ) => { + onChangeText( value ) { + const { setAttributes } = this.props; setAttributes( { text: value } ); - }; + } - const onChangeBorderRadius = ( value ) => { - setAttributes( { - borderRadius: value, - } ); - }; + onChangeBorderRadius( newRadius ) { + const { setAttributes, attributes } = this.props; + const { style } = attributes; + const newStyle = { + ...style, + border: { + ...style?.border, + radius: newRadius, + }, + }; + + setAttributes( { style: newStyle } ); + } - const onShowLinkSettings = () => { - setIsLinkSheetVisible( true ); - }; + onShowLinkSettings() { + this.setState( { isLinkSheetVisible: true } ); + } - const onHideLinkSettings = () => { - setIsLinkSheetVisible( false ); - }; + onHideLinkSettings() { + this.setState( { isLinkSheetVisible: false } ); + } - const onToggleButtonFocus = ( value ) => { - if ( value !== isButtonFocused ) { - setIsButtonFocused( value ); + onToggleButtonFocus( value ) { + if ( value !== this.state.isButtonFocused ) { + this.setState( { isButtonFocused: value } ); } - }; + } + + onClearSettings() { + const { setAttributes } = this.props; + + setAttributes( { + url: '', + rel: '', + linkTarget: '', + } ); - const onLayout = ( { nativeEvent } ) => { - const { layoutWidth } = nativeEvent.layout; - onSetMaxWidth( layoutWidth ); - }; + this.onHideLinkSettings(); + } + + onLayout( { nativeEvent } ) { + const { width } = nativeEvent.layout; + this.onSetMaxWidth( width ); + } - const onSetMaxWidth = ( newWidth, isParentWidthDidChange = false ) => { + onSetMaxWidth( width, isParentWidthDidChange = false ) { + const { maxWidth } = this.state; + const { parentWidth } = this.props; const { marginRight: spacing } = styles.defaultButton; const isParentWidthChanged = isParentWidthDidChange ? isParentWidthDidChange : maxWidth !== parentWidth; - const isWidthChanged = maxWidth !== newWidth; - - if ( parentWidth && ! newWidth && isParentWidthChanged ) { - setMaxWidth( parentWidth - spacing ); - } else if ( ! parentWidth && newWidth && isWidthChanged ) { - setMaxWidth( newWidth - spacing ); + const isWidthChanged = maxWidth !== width; + + if ( parentWidth && ! width && isParentWidthChanged ) { + this.setState( { + maxWidth: parentWidth - spacing, + } ); + } else if ( ! parentWidth && width && isWidthChanged ) { + this.setState( { maxWidth: width - spacing } ); } - }; + } + + onRemove() { + const { numOfButtons, onDeleteBlock, onReplace } = this.props; - const onRemove = () => { if ( numOfButtons === 1 ) { onDeleteBlock(); } else { onReplace( [] ); } - }; + } - const dismissSheet = () => { - onHideLinkSettings(); - closeSettingsBottomSheet(); - }; + dismissSheet() { + this.onHideLinkSettings(); + this.props.closeSettingsBottomSheet(); + } - const getLinkSettings = ( isCompatibleWithSettings ) => { + getLinkSettings( isCompatibleWithSettings ) { + const { isLinkSheetVisible } = this.state; + const { attributes, setAttributes } = this.props; 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` - const getPlaceholderWidth = ( placeholderText ) => { + getPlaceholderWidth( placeholderText ) { return ( { placeholderText } ); - }; + } - const onPlaceholderTextWidth = ( { nativeEvent } ) => { + onPlaceholderTextWidth( { nativeEvent } ) { + const { maxWidth, placeholderTextWidth } = this.state; const textWidth = nativeEvent.lines[ 0 ] && nativeEvent.lines[ 0 ].width; if ( textWidth && textWidth !== placeholderTextWidth ) { - setPlaceholderTextWidth( Math.min( textWidth, maxWidth ) ); + this.setState( { + placeholderTextWidth: Math.min( textWidth, maxWidth ), + } ); } - }; + } - const { paddingTop: spacing, borderWidth } = styles.defaultButton; + render() { + const { + attributes, + isSelected, + clientId, + onReplace, + mergeBlocks, + parentWidth, + setAttributes, + style, + } = this.props; + const { + placeholder, + text, + style: buttonStyle, + url, + align = 'center', + width, + } = attributes; + const { maxWidth, isButtonFocused, placeholderTextWidth } = this.state; + const { paddingTop: spacing, borderWidth } = styles.defaultButton; + + if ( parentWidth === 0 ) { + return null; + } - if ( parentWidth === 0 ) { - return null; - } + const borderRadius = buttonStyle?.border?.radius; + + 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; - 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 ( + + { this.getPlaceholderWidth( placeholderText ) } + + { isSelected && ( + + ) } + + this.onToggleButtonFocus( true ) + } + __unstableMobileNoFocusOnMount={ ! isSelected } + selectionColor={ textColor } + onBlur={ () => { + this.onSetMaxWidth(); + } } + onReplace={ onReplace } + onRemove={ this.onRemove } + onMerge={ mergeBlocks } + /> + - 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,