From 012d92d0b7e5de2436f186cdbff32ba128e537d5 Mon Sep 17 00:00:00 2001 From: fabriziobertoglio1987 Date: Wed, 23 Mar 2022 09:30:28 +0800 Subject: [PATCH] add errorMessage to ReactTextUpdate and maybeSetErrorMessage allow to display error message on TextInput triggered in a onChangeText callback. Fixes issue explained in: https://github.com/fabriziobertoglio1987/react-native-notes/issues/12#issuecomment-1071989570 Related links: https://github.com/fabriziobertoglio1987/react-native-notes/issues/12#issuecomment-1074827746 https://github.com/fabriziobertoglio1987/react-native/commit/d3d54e10687844ffce6283d07da93d29bbba4cc8 --- .../AndroidTextInputNativeComponent.js | 1 + .../facebook/react/uimanager/ViewProps.java | 2 +- .../react/views/text/ReactTextUpdate.java | 23 +++++++++++++++---- .../react/views/textinput/ReactEditText.java | 14 +++++++++++ .../textinput/ReactTextInputManager.java | 16 +++++++++---- .../textinput/ReactTextInputShadowNode.java | 3 ++- .../TextInput/TextInputSharedExamples.js | 2 +- 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index e896a77f810f16..a335dc62b055c0 100644 --- a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -698,6 +698,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { inlineImageLeft: true, editable: true, fontVariant: true, + android_errorMessage: true, borderBottomRightRadius: true, borderBottomColor: {process: require('../../StyleSheet/processColor')}, borderRadius: true, diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index c020abdde30129..58b88fa02ee1f1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -84,7 +84,7 @@ public class ViewProps { public static final String BACKGROUND_COLOR = "backgroundColor"; public static final String FOREGROUND_COLOR = "foregroundColor"; public static final String COLOR = "color"; - public static final String ERROR_MESSAGE = "errorMessage"; + public static final String ANDROID_ERROR_MESSAGE = "android_errorMessage"; public static final String FONT_SIZE = "fontSize"; public static final String FONT_WEIGHT = "fontWeight"; public static final String FONT_STYLE = "fontStyle"; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java index f1591a5fe35d2b..5e618d3549a28c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java @@ -11,6 +11,7 @@ import android.text.Layout; import android.text.Spannable; +import javax.annotation.Nullable; /** * Class that contains the data needed for a text update. Used by both and @@ -30,6 +31,7 @@ public class ReactTextUpdate { private final int mSelectionStart; private final int mSelectionEnd; private final int mJustificationMode; + private @Nullable String mErrorMessage; public boolean mContainsMultipleFragments; @@ -59,7 +61,8 @@ public ReactTextUpdate( Layout.BREAK_STRATEGY_HIGH_QUALITY, Layout.JUSTIFICATION_MODE_NONE, -1, - -1); + -1, + null); } public ReactTextUpdate( @@ -85,7 +88,8 @@ public ReactTextUpdate( textBreakStrategy, justificationMode, -1, - -1); + -1, + null); } public ReactTextUpdate( @@ -107,7 +111,8 @@ public ReactTextUpdate( textBreakStrategy, justificationMode, -1, - -1); + -1, + null); } public ReactTextUpdate( @@ -122,7 +127,8 @@ public ReactTextUpdate( int textBreakStrategy, int justificationMode, int selectionStart, - int selectionEnd) { + int selectionEnd, + @Nullable String errorMessage) { mText = text; mJsEventCounter = jsEventCounter; mContainsImages = containsImages; @@ -135,6 +141,7 @@ public ReactTextUpdate( mSelectionStart = selectionStart; mSelectionEnd = selectionEnd; mJustificationMode = justificationMode; + mErrorMessage = errorMessage; } public static ReactTextUpdate buildReactTextUpdateFromState( @@ -143,15 +150,21 @@ public static ReactTextUpdate buildReactTextUpdateFromState( int textAlign, int textBreakStrategy, int justificationMode, - boolean containsMultipleFragments) { + boolean containsMultipleFragments, + @Nullable String errorMessage) { ReactTextUpdate reactTextUpdate = new ReactTextUpdate( text, jsEventCounter, false, textAlign, textBreakStrategy, justificationMode); reactTextUpdate.mContainsMultipleFragments = containsMultipleFragments; + reactTextUpdate.mErrorMessage = errorMessage; return reactTextUpdate; } + public @Nullable String getErrorMessage() { + return mErrorMessage; + } + public Spannable getText() { return mText; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 360de688d54849..c8e1b6bd19e6a5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -509,6 +509,20 @@ public void maybeSetTextFromJS(ReactTextUpdate reactTextUpdate) { mIsSettingTextFromJS = false; } + /** + * Attempt to set an error message or fail silently. EventCounter is the same one used as with + * text. + * + * @param eventCounter + * @param errorMessage + */ + public void maybeSetErrorMessage(int eventCounter, String errorMessage) { + if (!canUpdateWithEventCount(eventCounter) || getError() == errorMessage) { + return; + } + setError(errorMessage); + } + public void maybeSetTextFromState(ReactTextUpdate reactTextUpdate) { mIsSettingTextFromState = true; maybeSetText(reactTextUpdate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 3c04d1967cd52b..2e58e038b64dff 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -325,7 +325,7 @@ private ReactTextUpdate getReactTextUpdate( sb.append(TextTransform.apply(text, TextTransform.UNSET)); return new ReactTextUpdate( - sb, mostRecentEventCount, false, 0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0, start, end); + sb, mostRecentEventCount, false, 0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0, start, end, null); } @Override @@ -369,11 +369,12 @@ public void updateExtraData(ReactEditText view, Object extraData) { view.maybeSetTextFromState(update); view.maybeSetSelection(update.getJsEventCounter(), selectionStart, selectionEnd); + view.maybeSetErrorMessage(update.getJsEventCounter(), update.getErrorMessage()); } } - @ReactProp(name = ViewProps.ERROR_MESSAGE) - public void setAndroidErrorMessage(ReactEditText view, String error) { + @ReactProp(name = ViewProps.ANDROID_ERROR_MESSAGE) + public void setErrorMessage(ReactEditText view, String error) { view.setError(error); } @@ -1325,12 +1326,19 @@ public Object updateState( int textBreakStrategy = TextAttributeProps.getTextBreakStrategy(paragraphAttributes.getString("textBreakStrategy")); + @Nullable + String errorMessage = + props.hasKey(ViewProps.ANDROID_ERROR_MESSAGE) + ? props.getString(ViewProps.ANDROID_ERROR_MESSAGE) + : null; + return ReactTextUpdate.buildReactTextUpdateFromState( spanned, state.getInt("mostRecentEventCount"), TextAttributeProps.getTextAlignment(props, TextLayoutManager.isRTL(attributedString)), textBreakStrategy, TextAttributeProps.getJustificationMode(props), - containsMultipleFragments); + containsMultipleFragments, + errorMessage); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index e621e1b585f9be..26e077d523610a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -246,7 +246,8 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { mTextBreakStrategy, mJustificationMode, mSelectionStart, - mSelectionEnd); + mSelectionEnd, + null); uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate); } } diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index e12d9ac9eb40d4..3ba638d1eeac7d 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -483,7 +483,7 @@ function ErrorExample(): React.Node { Type error in the below TextInput to display an error message. setError('onBlur')} onEndEditing={() => setError('onEndEditing')} onChangeText={newText => {