99
1010import static com .facebook .react .uimanager .UIManagerHelper .getReactContext ;
1111import static com .facebook .react .views .text .TextAttributeProps .UNSET ;
12+ import static com .facebook .react .config .ReactFeatureFlags .enableComposingSpanRestorationOnSameLength ;
1213
1314import android .content .ClipData ;
1415import android .content .ClipboardManager ;
5051import com .facebook .react .bridge .ReactContext ;
5152import com .facebook .react .bridge .ReactSoftExceptionLogger ;
5253import com .facebook .react .common .build .ReactBuildConfig ;
54+ import com .facebook .react .config .ReactFeatureFlags ;
5355import com .facebook .react .uimanager .FabricViewStateManager ;
5456import com .facebook .react .uimanager .ReactAccessibilityDelegate ;
5557import com .facebook .react .uimanager .UIManagerModule ;
@@ -721,20 +723,20 @@ public void maybeSetText(ReactTextUpdate reactTextUpdate) {
721723 * as long as the text they cover is the same unless they are {@link Spanned#SPAN_COMPOSING}.
722724 * All other spans will remain the same, since they will adapt to the new text, hence why {@link SpannableStringBuilder#replace} never removes
723725 * them.
724- * Keep copy of {@link Spanned#SPAN_COMPOSING} Spans in {@param spannableStringBuilder}, because they are important for
726+ * When {@link ReactFeatureFlags#enableComposingSpanRestorationOnSameLength} is enabled,
727+ * keep copy of {@link Spanned#SPAN_COMPOSING} Spans in {@param spannableStringBuilder}, because they are important for
725728 * keyboard suggestions. Without keeping these Spans, suggestions default to be put after the current selection position,
726729 * possibly resulting in letter duplication (ex. Samsung Keyboard).
727730 */
728731 private void manageSpans (SpannableStringBuilder spannableStringBuilder ) {
729732 Object [] spans = getText ().getSpans (0 , length (), Object .class );
730- boolean shouldKeepComposingSpans = length () == spannableStringBuilder .length ();
733+ boolean shouldKeepComposingSpans = enableComposingSpanRestorationOnSameLength
734+ && length () == spannableStringBuilder .length ();
731735 for (int spanIdx = 0 ; spanIdx < spans .length ; spanIdx ++) {
732736 Object span = spans [spanIdx ];
733737 int spanFlags = getText ().getSpanFlags (span );
734738 boolean isExclusiveExclusive =
735739 (spanFlags & Spanned .SPAN_EXCLUSIVE_EXCLUSIVE ) == Spanned .SPAN_EXCLUSIVE_EXCLUSIVE ;
736- boolean isComposing =
737- (spanFlags & Spanned .SPAN_COMPOSING ) == Spanned .SPAN_COMPOSING ;
738740
739741 // Remove all styling spans we might have previously set
740742 if (span instanceof ReactSpan ) {
@@ -749,10 +751,13 @@ private void manageSpans(SpannableStringBuilder spannableStringBuilder) {
749751 final int spanStart = getText ().getSpanStart (span );
750752 final int spanEnd = getText ().getSpanEnd (span );
751753
752- // We keep a copy of Composing spans
753- if (shouldKeepComposingSpans && isComposing ) {
754- spannableStringBuilder .setSpan (span , spanStart , spanEnd , spanFlags );
755- continue ;
754+ if (shouldKeepComposingSpans ) {
755+ // We keep a copy of Composing spans
756+ boolean isComposing = (spanFlags & Spanned .SPAN_COMPOSING ) == Spanned .SPAN_COMPOSING ;
757+ if (isComposing ) {
758+ spannableStringBuilder .setSpan (span , spanStart , spanEnd , spanFlags );
759+ continue ;
760+ }
756761 }
757762
758763 // Make sure the span is removed from existing text, otherwise the spans we set will be
@@ -883,13 +888,18 @@ private void addSpansFromStyleAttributes(SpannableStringBuilder workingText) {
883888 }
884889
885890 /**
886- * Attaches the {@link Spanned#SPAN_COMPOSING} from {@param spannableStringBuilder} to {@link ReactEditText#getText}
887- * if they are the same length.
891+ * When {@link ReactFeatureFlags#enableComposingSpanRestorationOnSameLength} is enabled, this
892+ * function attaches the {@link Spanned#SPAN_COMPOSING} from {@param spannableStringBuilder} to
893+ * {@link ReactEditText#getText} if they are the same length.
888894 *
889895 * See {@link ReactEditText#manageSpans} for more details.
890- * Also https://github.com/facebook/react-native/issues/11068
896+ * Also this <a href=" https://github.com/facebook/react-native/issues/11068">GitHub issue</a>
891897 */
892898 private void attachCompositeSpansToTextFrom (SpannableStringBuilder spannableStringBuilder ) {
899+ if (!enableComposingSpanRestorationOnSameLength ) {
900+ return ;
901+ }
902+
893903 Editable text = getText ();
894904 if (text == null || text .length () != spannableStringBuilder .length ()) {
895905 return ;
0 commit comments