-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Mobile]: Add Image Caption Styling #14883
Changes from all commits
ab9dab2
b597c6e
b4afb1d
a738017
5d3f86e
ccf785c
e85aa98
4f81ee9
4c4801a
52f62bb
740e9fd
5c442a4
91c3662
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
* External dependencies | ||
*/ | ||
import React from 'react'; | ||
import { View, ImageBackground, TextInput, Text, TouchableWithoutFeedback } from 'react-native'; | ||
import { View, ImageBackground, Text, TouchableWithoutFeedback } from 'react-native'; | ||
import { | ||
subscribeMediaUpload, | ||
requestMediaPickFromMediaLibrary, | ||
|
@@ -63,6 +63,7 @@ class ImageEdit extends React.Component { | |
progress: 0, | ||
isUploadInProgress: false, | ||
isUploadFailed: false, | ||
isCaptionSelected: false, | ||
}; | ||
|
||
this.mediaUpload = this.mediaUpload.bind( this ); | ||
|
@@ -74,6 +75,7 @@ class ImageEdit extends React.Component { | |
this.onSetLinkDestination = this.onSetLinkDestination.bind( this ); | ||
this.onImagePressed = this.onImagePressed.bind( this ); | ||
this.onClearSettings = this.onClearSettings.bind( this ); | ||
this.onFocusCaption = this.onFocusCaption.bind( this ); | ||
} | ||
|
||
componentDidMount() { | ||
|
@@ -101,6 +103,14 @@ class ImageEdit extends React.Component { | |
this.removeMediaUploadListener(); | ||
} | ||
|
||
componentWillReceiveProps( nextProps ) { | ||
// Avoid a UI flicker in the toolbar by insuring that isCaptionSelected | ||
// is updated immediately any time the isSelected prop becomes false | ||
this.setState( ( state ) => ( { | ||
isCaptionSelected: nextProps.isSelected && state.isCaptionSelected, | ||
} ) ); | ||
} | ||
|
||
onImagePressed() { | ||
const { attributes } = this.props; | ||
|
||
|
@@ -109,6 +119,11 @@ class ImageEdit extends React.Component { | |
} else if ( attributes.id && ! isURL( attributes.url ) ) { | ||
requestImageFailedRetryDialog( attributes.id ); | ||
} | ||
|
||
this._caption.blur(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added this so that when an image's caption is selected and the user taps on the image, the caption will lose focus and the toolbar will be updated to only contain the edit image button. |
||
this.setState( { | ||
isCaptionSelected: false, | ||
} ); | ||
} | ||
|
||
mediaUpload( payload ) { | ||
|
@@ -210,6 +225,17 @@ class ImageEdit extends React.Component { | |
]; | ||
} | ||
|
||
onFocusCaption() { | ||
if ( this.props.onFocus ) { | ||
this.props.onFocus(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This
Adding this same logic to the |
||
if ( ! this.state.isCaptionSelected ) { | ||
this.setState( { | ||
isCaptionSelected: true, | ||
} ); | ||
} | ||
} | ||
|
||
render() { | ||
const { attributes, isSelected, setAttributes } = this.props; | ||
const { url, caption, height, width, alt, href } = attributes; | ||
|
@@ -338,9 +364,11 @@ class ImageEdit extends React.Component { | |
> | ||
<View style={ { flex: 1 } }> | ||
{ showSpinner && <Spinner progress={ progress } /> } | ||
<BlockControls> | ||
{ toolbarEditButton } | ||
</BlockControls> | ||
{ ( ! this.state.isCaptionSelected ) && | ||
<BlockControls> | ||
{ toolbarEditButton } | ||
</BlockControls> | ||
} | ||
<InspectorControls> | ||
<ToolbarButton | ||
title={ __( 'Image Settings' ) } | ||
|
@@ -392,19 +420,23 @@ class ImageEdit extends React.Component { | |
} } | ||
</ImageSize> | ||
{ ( ! RichText.isEmpty( caption ) > 0 || isSelected ) && ( | ||
<View | ||
style={ { padding: 12, flex: 1 } } | ||
<View style={ { padding: 12, flex: 1 } } | ||
accessible={ true } | ||
accessibilityLabel={ __( 'Image caption' ) + __( '.' ) + ' ' + ( isEmpty( caption ) ? __( 'Empty' ) : caption ) } | ||
accessibilityRole={ 'button' } | ||
> | ||
<TextInput | ||
style={ { textAlign: 'center' } } | ||
fontFamily={ this.props.fontFamily || ( styles[ 'caption-text' ].fontFamily ) } | ||
underlineColorAndroid="transparent" | ||
value={ caption } | ||
<RichText | ||
setRef={ ( ref ) => { | ||
this._caption = ref; | ||
} } | ||
placeholder={ __( 'Write caption…' ) } | ||
onChangeText={ ( newCaption ) => setAttributes( { caption: newCaption } ) } | ||
value={ caption } | ||
onChange={ ( newCaption ) => setAttributes( { caption: newCaption } ) } | ||
onFocus={ this.onFocusCaption } | ||
onBlur={ this.props.onBlur } // always assign onBlur as props | ||
isSelected={ this.state.isCaptionSelected } | ||
fontSize={ 14 } | ||
underlineColorAndroid="transparent" | ||
/> | ||
</View> | ||
) } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am guarding the
isCaptionSelected
state here with the image block'sisSelected
prop in order to avoid a noticeable flicker in the toolbar buttons when changing to another block with buttons. There seems to be a lag between the image block'sisSelected
prop being updated to false and itsisCaptionSelected
state being updated to false by theonCaptionBlur
function (which is passed as the caption'sonBlur
prop). That lag created a split second where the toolbar buttons for both the caption and the newly-selected block were shown at the same time.My original approach was to just set the caption's
isSelected
prop in the image block's render function asthis.props.isSelected && this.state.isCaptionSelected
. But this did not work when:(1) the caption was selected (so the image's
isCaptionSelected
state was true);(2) the caption had no text; and
(3) another block was selected, causing the image's
isSelected
prop to change to false.When the new block is selected in (3), the caption's
onBlur
prop function (theonCaptionBlur
function) would not be called and update the image block'sisCaptionSelected
state to be false becasuse an empty caption is not even rendered once the image block'sisSelected
prop is false:gutenberg/packages/block-library/src/image/edit.native.js
Lines 420 to 422 in a738017
Because the
isCaptionSelected
state is never updated to false, if the user re-selects the image with the empty caption, the empty caption would appear and immediately be selected even though the user did not tap on the caption (the user couldn't have directly tapped on the caption because empty captions are not shown until the related image is selected). If the caption was not empty, then this bug does not appear because the caption would always render, allowing itsonBlur
prop function to update theisCaptionSelected
state to false.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation!
Maybe for this one it would be worth to add a short comment in code?
So someone else (or future us) that sees it will understand the intention easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I included this info in the commit body, but it makes sense to add a brief explanation here in the code.
I pushed an update addressing this.