Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/components/advanced-text-control/index.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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 (
Expand All @@ -54,16 +64,16 @@ const AdvancedTextControl = memo( props => {
>
<TextInput
{ ...inputProps }
value={ typeof props.value === 'undefined' ? value : props.value }
onChange={ typeof props.onChange === 'undefined' ? onChange : props.onChange }
value={ internalValue }
onChange={ internalOnChange }
className={ classnames( propsToPass.className, 'ugb-advanced-text-control' ) }
/>
</DynamicContentControl>
<ResetButton
allowReset={ allowReset && ! props.isDynamic }
value={ typeof props.value === 'undefined' ? value : props.value }
value={ internalValue }
default={ props.default }
onChange={ typeof props.onChange === 'undefined' ? onChange : props.onChange }
onChange={ internalOnChange }
hasPanelModifiedIndicator={ props.hasPanelModifiedIndicator }
/>
</AdvancedControl>
Expand Down
15 changes: 12 additions & 3 deletions src/components/image-alt-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<TextareaControl
{ ...props }
value={ internalValue }
onChange={ value => {
setInternalValue( value )
props.onChange( value )
} }
help={
<Fragment>
<>
<ExternalLink href="https://www.w3.org/WAI/tutorials/images/decision-tree">
{ __( 'Describe the purpose of the image', i18n ) }
</ExternalLink>
{ __( 'Leave empty if the image is purely decorative.', i18n ) }
</Fragment>
</>
}
/>
)
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
26 changes: 26 additions & 0 deletions src/hooks/use-internal-value.js
Original file line number Diff line number Diff line change
@@ -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 ]
}
Loading