diff --git a/src/components/advanced-text-control/index.js b/src/components/advanced-text-control/index.js index b679de26d4..83d3e33234 100644 --- a/src/components/advanced-text-control/index.js +++ b/src/components/advanced-text-control/index.js @@ -1,6 +1,7 @@ /** * Internal dependencies */ +import { useInternalValue } from '~stackable/hooks' import AdvancedControl, { extractControlProps } from '../base-control2' import { useControlHandlers } from '../base-control2/hooks' import { ResetButton } from '../base-control2/reset-button' @@ -40,6 +41,15 @@ const AdvancedTextControl = memo( props => { isFormatType, } ) + // Track the value internally, because if not the value will be updated on + // every render and will make the cursor jump to the end. + const [ internalValue, setInternalValue ] = useInternalValue( typeof props.value === 'undefined' ? value : props.value ) + const _onChange = typeof props.onChange === 'undefined' ? onChange : props.onChange + const internalOnChange = value => { + setInternalValue( value ) + _onChange( value ) + } + const TextInput = isMultiline ? TextareaControl : TextControl return ( @@ -54,16 +64,16 @@ const AdvancedTextControl = memo( props => { > diff --git a/src/components/image-alt-control/index.js b/src/components/image-alt-control/index.js index 759853c644..c2cf04d768 100644 --- a/src/components/image-alt-control/index.js +++ b/src/components/image-alt-control/index.js @@ -8,19 +8,28 @@ import { i18n } from 'stackable' */ import { TextareaControl, ExternalLink } from '@wordpress/components' import { __ } from '@wordpress/i18n' -import { Fragment } from '@wordpress/element' +import { useInternalValue } from '~stackable/hooks' const ImageAltControl = props => { + // Keep track of the internal value because we will move the cursor to the + // end of the text when the user types. + const [ internalValue, setInternalValue ] = useInternalValue( props.value ) + return ( { + setInternalValue( value ) + props.onChange( value ) + } } help={ - + <> { __( 'Describe the purpose of the image', i18n ) } { __( 'Leave empty if the image is purely decorative.', i18n ) } - + } /> ) diff --git a/src/hooks/index.js b/src/hooks/index.js index 3f567939a3..0954c6c47c 100644 --- a/src/hooks/index.js +++ b/src/hooks/index.js @@ -9,6 +9,7 @@ export * from './use-saved-default-block-style' export * from './use-font-loader' export * from './use-attribute-edit-handlers' export * from './use-attribute-name' +export * from './use-internal-value' export * from './use-linking' export * from './use-block-hover-state' export * from './use-on-screen' diff --git a/src/hooks/use-internal-value.js b/src/hooks/use-internal-value.js new file mode 100644 index 0000000000..968b80e6ee --- /dev/null +++ b/src/hooks/use-internal-value.js @@ -0,0 +1,26 @@ +// This files is based on +// https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/link-control/use-internal-value.js +// This is a hook that keeps track of the internal value of a component, and +// updates the value only when the value changes. + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element' + +/** + * External dependencies + */ +import fastDeepEqual from 'fast-deep-equal' + +export const useInternalValue = value => { + const [ internalValue, setInternalValue ] = useState( value ) + const [ previousValue, setPreviousValue ] = useState( value ) + + if ( ! fastDeepEqual( value, previousValue ) ) { + setPreviousValue( value ) + setInternalValue( value ) + } + + return [ internalValue, setInternalValue ] +}