react-native 0.71.5 → 0.71.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,6 @@
12
12
  exports.version = {
13
13
  major: 0,
14
14
  minor: 71,
15
- patch: 5,
15
+ patch: 7,
16
16
  prerelease: null,
17
17
  };
@@ -23,7 +23,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
23
23
  __rnVersion = @{
24
24
  RCTVersionMajor: @(0),
25
25
  RCTVersionMinor: @(71),
26
- RCTVersionPatch: @(5),
26
+ RCTVersionPatch: @(7),
27
27
  RCTVersionPrerelease: [NSNull null],
28
28
  };
29
29
  });
@@ -1,4 +1,4 @@
1
- VERSION_NAME=0.71.5
1
+ VERSION_NAME=0.71.7
2
2
  GROUP=com.facebook.react
3
3
 
4
4
  # JVM Versions
@@ -17,6 +17,6 @@ public class ReactNativeVersion {
17
17
  public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
18
18
  "major", 0,
19
19
  "minor", 71,
20
- "patch", 5,
20
+ "patch", 7,
21
21
  "prerelease", null);
22
22
  }
@@ -37,6 +37,10 @@ public class CustomLetterSpacingSpan extends MetricAffectingSpan implements Reac
37
37
  apply(paint);
38
38
  }
39
39
 
40
+ public float getSpacing() {
41
+ return mLetterSpacing;
42
+ }
43
+
40
44
  private void apply(TextPaint paint) {
41
45
  if (!Float.isNaN(mLetterSpacing)) {
42
46
  paint.setLetterSpacing(mLetterSpacing);
@@ -71,6 +71,10 @@ public class CustomStyleSpan extends MetricAffectingSpan implements ReactSpan {
71
71
  return mFontFamily;
72
72
  }
73
73
 
74
+ public @Nullable String getFontFeatureSettings() {
75
+ return mFeatureSettings;
76
+ }
77
+
74
78
  private static void apply(
75
79
  Paint paint,
76
80
  int style,
@@ -31,8 +31,6 @@ public class ReactTextUpdate {
31
31
  private final int mSelectionEnd;
32
32
  private final int mJustificationMode;
33
33
 
34
- public boolean mContainsMultipleFragments;
35
-
36
34
  /**
37
35
  * @deprecated Use a non-deprecated constructor for ReactTextUpdate instead. This one remains
38
36
  * because it's being used by a unit test that isn't currently open source.
@@ -142,13 +140,11 @@ public class ReactTextUpdate {
142
140
  int jsEventCounter,
143
141
  int textAlign,
144
142
  int textBreakStrategy,
145
- int justificationMode,
146
- boolean containsMultipleFragments) {
143
+ int justificationMode) {
147
144
 
148
145
  ReactTextUpdate reactTextUpdate =
149
146
  new ReactTextUpdate(
150
147
  text, jsEventCounter, false, textAlign, textBreakStrategy, justificationMode);
151
- reactTextUpdate.mContainsMultipleFragments = containsMultipleFragments;
152
148
  return reactTextUpdate;
153
149
  }
154
150
 
@@ -54,7 +54,6 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
54
54
  private boolean mContainsImages;
55
55
  private final int mDefaultGravityHorizontal;
56
56
  private final int mDefaultGravityVertical;
57
- private int mTextAlign;
58
57
  private int mNumberOfLines;
59
58
  private TextUtils.TruncateAt mEllipsizeLocation;
60
59
  private boolean mAdjustsFontSizeToFit;
@@ -69,8 +68,7 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
69
68
  super(context);
70
69
 
71
70
  // Get these defaults only during the constructor - these should never be set otherwise
72
- mDefaultGravityHorizontal =
73
- getGravity() & (Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK);
71
+ mDefaultGravityHorizontal = getGravityHorizontal();
74
72
  mDefaultGravityVertical = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
75
73
 
76
74
  initView();
@@ -89,10 +87,10 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
89
87
 
90
88
  mReactBackgroundManager = new ReactViewBackgroundManager(this);
91
89
 
92
- mTextAlign = Gravity.NO_GRAVITY;
93
90
  mNumberOfLines = ViewDefaults.NUMBER_OF_LINES;
94
91
  mAdjustsFontSizeToFit = false;
95
92
  mLinkifyMaskType = 0;
93
+ mNotifyOnInlineViewLayout = false;
96
94
  mTextIsSelectable = false;
97
95
  mEllipsizeLocation = TextUtils.TruncateAt.END;
98
96
 
@@ -392,10 +390,9 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
392
390
  }
393
391
 
394
392
  int nextTextAlign = update.getTextAlign();
395
- if (mTextAlign != nextTextAlign) {
396
- mTextAlign = nextTextAlign;
393
+ if (nextTextAlign != getGravityHorizontal()) {
394
+ setGravityHorizontal(nextTextAlign);
397
395
  }
398
- setGravityHorizontal(mTextAlign);
399
396
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
400
397
  if (getBreakStrategy() != update.getTextBreakStrategy()) {
401
398
  setBreakStrategy(update.getTextBreakStrategy());
@@ -552,6 +549,11 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
552
549
  return false;
553
550
  }
554
551
 
552
+ /* package */ int getGravityHorizontal() {
553
+ return getGravity()
554
+ & (Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK);
555
+ }
556
+
555
557
  /* package */ void setGravityHorizontal(int gravityHorizontal) {
556
558
  if (gravityHorizontal == 0) {
557
559
  gravityHorizontal = mDefaultGravityHorizontal;
@@ -8,6 +8,7 @@
8
8
  package com.facebook.react.views.text;
9
9
 
10
10
  import android.content.Context;
11
+ import android.os.Build;
11
12
  import android.text.Spannable;
12
13
  import androidx.annotation.NonNull;
13
14
  import androidx.annotation.Nullable;
@@ -23,6 +24,7 @@ import com.facebook.react.uimanager.ReactAccessibilityDelegate;
23
24
  import com.facebook.react.uimanager.ReactStylesDiffMap;
24
25
  import com.facebook.react.uimanager.StateWrapper;
25
26
  import com.facebook.react.uimanager.ThemedReactContext;
27
+ import com.facebook.react.uimanager.ViewProps;
26
28
  import com.facebook.yoga.YogaMeasureMode;
27
29
  import java.util.HashMap;
28
30
  import java.util.Map;
@@ -148,15 +150,19 @@ public class ReactTextViewManager
148
150
  view.setSpanned(spanned);
149
151
 
150
152
  int textBreakStrategy =
151
- TextAttributeProps.getTextBreakStrategy(paragraphAttributes.getString("textBreakStrategy"));
153
+ TextAttributeProps.getTextBreakStrategy(
154
+ paragraphAttributes.getString(ViewProps.TEXT_BREAK_STRATEGY));
155
+ int currentJustificationMode =
156
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode();
152
157
 
153
158
  return new ReactTextUpdate(
154
159
  spanned,
155
160
  state.hasKey("mostRecentEventCount") ? state.getInt("mostRecentEventCount") : -1,
156
161
  false, // TODO add this into local Data
157
- TextAttributeProps.getTextAlignment(props, TextLayoutManager.isRTL(attributedString)),
162
+ TextAttributeProps.getTextAlignment(
163
+ props, TextLayoutManager.isRTL(attributedString), view.getGravityHorizontal()),
158
164
  textBreakStrategy,
159
- TextAttributeProps.getJustificationMode(props));
165
+ TextAttributeProps.getJustificationMode(props, currentJustificationMode));
160
166
  }
161
167
 
162
168
  private Object getReactTextUpdate(ReactTextView view, ReactStylesDiffMap props, MapBuffer state) {
@@ -171,15 +177,17 @@ public class ReactTextViewManager
171
177
  int textBreakStrategy =
172
178
  TextAttributeProps.getTextBreakStrategy(
173
179
  paragraphAttributes.getString(TextLayoutManagerMapBuffer.PA_KEY_TEXT_BREAK_STRATEGY));
180
+ int currentJustificationMode =
181
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode();
174
182
 
175
183
  return new ReactTextUpdate(
176
184
  spanned,
177
185
  -1, // UNUSED FOR TEXT
178
186
  false, // TODO add this into local Data
179
187
  TextAttributeProps.getTextAlignment(
180
- props, TextLayoutManagerMapBuffer.isRTL(attributedString)),
188
+ props, TextLayoutManagerMapBuffer.isRTL(attributedString), view.getGravityHorizontal()),
181
189
  textBreakStrategy,
182
- TextAttributeProps.getJustificationMode(props));
190
+ TextAttributeProps.getJustificationMode(props, currentJustificationMode));
183
191
  }
184
192
 
185
193
  @Override
@@ -249,35 +249,35 @@ public class TextAttributeProps {
249
249
  return result;
250
250
  }
251
251
 
252
- public static int getTextAlignment(ReactStylesDiffMap props, boolean isRTL) {
253
- @Nullable
254
- String textAlignPropValue =
255
- props.hasKey(ViewProps.TEXT_ALIGN) ? props.getString(ViewProps.TEXT_ALIGN) : null;
256
- int textAlignment;
252
+ public static int getTextAlignment(ReactStylesDiffMap props, boolean isRTL, int defaultValue) {
253
+ if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
254
+ return defaultValue;
255
+ }
257
256
 
257
+ String textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN);
258
258
  if ("justify".equals(textAlignPropValue)) {
259
- textAlignment = Gravity.LEFT;
259
+ return Gravity.LEFT;
260
260
  } else {
261
261
  if (textAlignPropValue == null || "auto".equals(textAlignPropValue)) {
262
- textAlignment = Gravity.NO_GRAVITY;
262
+ return Gravity.NO_GRAVITY;
263
263
  } else if ("left".equals(textAlignPropValue)) {
264
- textAlignment = isRTL ? Gravity.RIGHT : Gravity.LEFT;
264
+ return isRTL ? Gravity.RIGHT : Gravity.LEFT;
265
265
  } else if ("right".equals(textAlignPropValue)) {
266
- textAlignment = isRTL ? Gravity.LEFT : Gravity.RIGHT;
266
+ return isRTL ? Gravity.LEFT : Gravity.RIGHT;
267
267
  } else if ("center".equals(textAlignPropValue)) {
268
- textAlignment = Gravity.CENTER_HORIZONTAL;
268
+ return Gravity.CENTER_HORIZONTAL;
269
269
  } else {
270
270
  throw new JSApplicationIllegalArgumentException("Invalid textAlign: " + textAlignPropValue);
271
271
  }
272
272
  }
273
- return textAlignment;
274
273
  }
275
274
 
276
- public static int getJustificationMode(ReactStylesDiffMap props) {
277
- @Nullable
278
- String textAlignPropValue =
279
- props.hasKey(ViewProps.TEXT_ALIGN) ? props.getString(ViewProps.TEXT_ALIGN) : null;
275
+ public static int getJustificationMode(ReactStylesDiffMap props, int defaultValue) {
276
+ if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
277
+ return defaultValue;
278
+ }
280
279
 
280
+ String textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN);
281
281
  if ("justify".equals(textAlignPropValue) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
282
282
  return Layout.JUSTIFICATION_MODE_INTER_WORD;
283
283
  }
@@ -11,6 +11,8 @@ import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;
11
11
  import static com.facebook.react.views.text.TextAttributeProps.UNSET;
12
12
 
13
13
  import android.content.Context;
14
+ import android.graphics.Color;
15
+ import android.graphics.Paint;
14
16
  import android.graphics.Rect;
15
17
  import android.graphics.Typeface;
16
18
  import android.graphics.drawable.Drawable;
@@ -50,15 +52,19 @@ import com.facebook.react.views.text.CustomLetterSpacingSpan;
50
52
  import com.facebook.react.views.text.CustomLineHeightSpan;
51
53
  import com.facebook.react.views.text.CustomStyleSpan;
52
54
  import com.facebook.react.views.text.ReactAbsoluteSizeSpan;
55
+ import com.facebook.react.views.text.ReactBackgroundColorSpan;
56
+ import com.facebook.react.views.text.ReactForegroundColorSpan;
53
57
  import com.facebook.react.views.text.ReactSpan;
58
+ import com.facebook.react.views.text.ReactStrikethroughSpan;
54
59
  import com.facebook.react.views.text.ReactTextUpdate;
55
60
  import com.facebook.react.views.text.ReactTypefaceUtils;
61
+ import com.facebook.react.views.text.ReactUnderlineSpan;
56
62
  import com.facebook.react.views.text.TextAttributes;
57
63
  import com.facebook.react.views.text.TextInlineImageSpan;
58
64
  import com.facebook.react.views.text.TextLayoutManager;
59
65
  import com.facebook.react.views.view.ReactViewBackgroundManager;
60
66
  import java.util.ArrayList;
61
- import java.util.List;
67
+ import java.util.Objects;
62
68
 
63
69
  /**
64
70
  * A wrapper around the EditText that lets us better control what happens when an EditText gets
@@ -82,7 +88,6 @@ public class ReactEditText extends AppCompatEditText
82
88
  // *TextChanged events should be triggered. This is less expensive than removing the text
83
89
  // listeners and adding them back again after the text change is completed.
84
90
  protected boolean mIsSettingTextFromJS;
85
- protected boolean mIsSettingTextFromCacheUpdate = false;
86
91
  private int mDefaultGravityHorizontal;
87
92
  private int mDefaultGravityVertical;
88
93
 
@@ -362,7 +367,7 @@ public class ReactEditText extends AppCompatEditText
362
367
  }
363
368
 
364
369
  super.onSelectionChanged(selStart, selEnd);
365
- if (!mIsSettingTextFromCacheUpdate && mSelectionWatcher != null && hasFocus()) {
370
+ if (mSelectionWatcher != null && hasFocus()) {
366
371
  mSelectionWatcher.onSelectionChanged(selStart, selEnd);
367
372
  }
368
373
  }
@@ -512,6 +517,14 @@ public class ReactEditText extends AppCompatEditText
512
517
  }
513
518
  }
514
519
 
520
+ @Override
521
+ public void setFontFeatureSettings(String fontFeatureSettings) {
522
+ if (!Objects.equals(fontFeatureSettings, getFontFeatureSettings())) {
523
+ super.setFontFeatureSettings(fontFeatureSettings);
524
+ mTypefaceDirty = true;
525
+ }
526
+ }
527
+
515
528
  public void maybeUpdateTypeface() {
516
529
  if (!mTypefaceDirty) {
517
530
  return;
@@ -523,6 +536,17 @@ public class ReactEditText extends AppCompatEditText
523
536
  ReactTypefaceUtils.applyStyles(
524
537
  getTypeface(), mFontStyle, mFontWeight, mFontFamily, getContext().getAssets());
525
538
  setTypeface(newTypeface);
539
+
540
+ // Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything
541
+ // nonstandard
542
+ if (mFontStyle != UNSET
543
+ || mFontWeight != UNSET
544
+ || mFontFamily != null
545
+ || getFontFeatureSettings() != null) {
546
+ setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
547
+ } else {
548
+ setPaintFlags(getPaintFlags() & (~Paint.SUBPIXEL_TEXT_FLAG));
549
+ }
526
550
  }
527
551
 
528
552
  // VisibleForTesting from {@link TextInputEventsTestCase}.
@@ -584,10 +608,8 @@ public class ReactEditText extends AppCompatEditText
584
608
  SpannableStringBuilder spannableStringBuilder =
585
609
  new SpannableStringBuilder(reactTextUpdate.getText());
586
610
 
587
- manageSpans(spannableStringBuilder, reactTextUpdate.mContainsMultipleFragments);
588
-
589
- // Mitigation for https://github.com/facebook/react-native/issues/35936 (S318090)
590
- stripAbsoluteSizeSpans(spannableStringBuilder);
611
+ manageSpans(spannableStringBuilder);
612
+ stripStyleEquivalentSpans(spannableStringBuilder);
591
613
 
592
614
  mContainsImages = reactTextUpdate.containsImages();
593
615
 
@@ -615,7 +637,7 @@ public class ReactEditText extends AppCompatEditText
615
637
  }
616
638
 
617
639
  // Update cached spans (in Fabric only).
618
- updateCachedSpannable(false);
640
+ updateCachedSpannable();
619
641
  }
620
642
 
621
643
  /**
@@ -624,8 +646,7 @@ public class ReactEditText extends AppCompatEditText
624
646
  * will adapt to the new text, hence why {@link SpannableStringBuilder#replace} never removes
625
647
  * them.
626
648
  */
627
- private void manageSpans(
628
- SpannableStringBuilder spannableStringBuilder, boolean skipAddSpansForMeasurements) {
649
+ private void manageSpans(SpannableStringBuilder spannableStringBuilder) {
629
650
  Object[] spans = getText().getSpans(0, length(), Object.class);
630
651
  for (int spanIdx = 0; spanIdx < spans.length; spanIdx++) {
631
652
  Object span = spans[spanIdx];
@@ -653,33 +674,170 @@ public class ReactEditText extends AppCompatEditText
653
674
  spannableStringBuilder.setSpan(span, spanStart, spanEnd, spanFlags);
654
675
  }
655
676
  }
677
+ }
678
+
679
+ // TODO: Replace with Predicate<T> and lambdas once Java 8 builds in OSS
680
+ interface SpanPredicate<T> {
681
+ boolean test(T span);
682
+ }
683
+
684
+ /**
685
+ * Remove spans from the SpannableStringBuilder which can be represented by TextAppearance
686
+ * attributes on the underlying EditText. This works around instability on Samsung devices with
687
+ * the presence of spans https://github.com/facebook/react-native/issues/35936 (S318090)
688
+ */
689
+ private void stripStyleEquivalentSpans(SpannableStringBuilder sb) {
690
+ stripSpansOfKind(
691
+ sb,
692
+ ReactAbsoluteSizeSpan.class,
693
+ new SpanPredicate<ReactAbsoluteSizeSpan>() {
694
+ @Override
695
+ public boolean test(ReactAbsoluteSizeSpan span) {
696
+ return span.getSize() == mTextAttributes.getEffectiveFontSize();
697
+ }
698
+ });
699
+
700
+ stripSpansOfKind(
701
+ sb,
702
+ ReactBackgroundColorSpan.class,
703
+ new SpanPredicate<ReactBackgroundColorSpan>() {
704
+ @Override
705
+ public boolean test(ReactBackgroundColorSpan span) {
706
+ return span.getBackgroundColor() == mReactBackgroundManager.getBackgroundColor();
707
+ }
708
+ });
656
709
 
657
- // In Fabric only, apply necessary styles to entire span
658
- // If the Spannable was constructed from multiple fragments, we don't apply any spans that could
659
- // impact the whole Spannable, because that would override "local" styles per-fragment
660
- if (!skipAddSpansForMeasurements) {
661
- addSpansForMeasurement(getText());
710
+ stripSpansOfKind(
711
+ sb,
712
+ ReactForegroundColorSpan.class,
713
+ new SpanPredicate<ReactForegroundColorSpan>() {
714
+ @Override
715
+ public boolean test(ReactForegroundColorSpan span) {
716
+ return span.getForegroundColor() == getCurrentTextColor();
717
+ }
718
+ });
719
+
720
+ stripSpansOfKind(
721
+ sb,
722
+ ReactStrikethroughSpan.class,
723
+ new SpanPredicate<ReactStrikethroughSpan>() {
724
+ @Override
725
+ public boolean test(ReactStrikethroughSpan span) {
726
+ return (getPaintFlags() & Paint.STRIKE_THRU_TEXT_FLAG) != 0;
727
+ }
728
+ });
729
+
730
+ stripSpansOfKind(
731
+ sb,
732
+ ReactUnderlineSpan.class,
733
+ new SpanPredicate<ReactUnderlineSpan>() {
734
+ @Override
735
+ public boolean test(ReactUnderlineSpan span) {
736
+ return (getPaintFlags() & Paint.UNDERLINE_TEXT_FLAG) != 0;
737
+ }
738
+ });
739
+
740
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
741
+ stripSpansOfKind(
742
+ sb,
743
+ CustomLetterSpacingSpan.class,
744
+ new SpanPredicate<CustomLetterSpacingSpan>() {
745
+ @Override
746
+ public boolean test(CustomLetterSpacingSpan span) {
747
+ return span.getSpacing() == mTextAttributes.getEffectiveLetterSpacing();
748
+ }
749
+ });
662
750
  }
751
+
752
+ stripSpansOfKind(
753
+ sb,
754
+ CustomStyleSpan.class,
755
+ new SpanPredicate<CustomStyleSpan>() {
756
+ @Override
757
+ public boolean test(CustomStyleSpan span) {
758
+ return span.getStyle() == mFontStyle
759
+ && Objects.equals(span.getFontFamily(), mFontFamily)
760
+ && span.getWeight() == mFontWeight
761
+ && Objects.equals(span.getFontFeatureSettings(), getFontFeatureSettings());
762
+ }
763
+ });
663
764
  }
664
765
 
665
- private void stripAbsoluteSizeSpans(SpannableStringBuilder sb) {
666
- // We have already set a font size on the EditText itself. We can safely remove sizing spans
667
- // which are the same as the set font size, and not otherwise overlapped.
668
- final int effectiveFontSize = mTextAttributes.getEffectiveFontSize();
669
- ReactAbsoluteSizeSpan[] spans = sb.getSpans(0, sb.length(), ReactAbsoluteSizeSpan.class);
766
+ private <T> void stripSpansOfKind(
767
+ SpannableStringBuilder sb, Class<T> clazz, SpanPredicate<T> shouldStrip) {
768
+ T[] spans = sb.getSpans(0, sb.length(), clazz);
670
769
 
671
- outerLoop:
672
- for (ReactAbsoluteSizeSpan span : spans) {
673
- ReactAbsoluteSizeSpan[] overlappingSpans =
674
- sb.getSpans(sb.getSpanStart(span), sb.getSpanEnd(span), ReactAbsoluteSizeSpan.class);
770
+ for (T span : spans) {
771
+ if (shouldStrip.test(span)) {
772
+ sb.removeSpan(span);
773
+ }
774
+ }
775
+ }
675
776
 
676
- for (ReactAbsoluteSizeSpan overlappingSpan : overlappingSpans) {
677
- if (span.getSize() != effectiveFontSize) {
678
- continue outerLoop;
679
- }
777
+ /**
778
+ * Copy styles represented as attributes to the underlying span, for later measurement or other
779
+ * usage outside the ReactEditText.
780
+ */
781
+ private void addSpansFromStyleAttributes(SpannableStringBuilder workingText) {
782
+ int spanFlags = Spannable.SPAN_INCLUSIVE_INCLUSIVE;
783
+
784
+ // Set all bits for SPAN_PRIORITY so that this span has the highest possible priority
785
+ // (least precedence). This ensures the span is behind any overlapping spans.
786
+ spanFlags |= Spannable.SPAN_PRIORITY;
787
+
788
+ workingText.setSpan(
789
+ new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
790
+ 0,
791
+ workingText.length(),
792
+ spanFlags);
793
+
794
+ workingText.setSpan(
795
+ new ReactForegroundColorSpan(getCurrentTextColor()), 0, workingText.length(), spanFlags);
796
+
797
+ int backgroundColor = mReactBackgroundManager.getBackgroundColor();
798
+ if (backgroundColor != Color.TRANSPARENT) {
799
+ workingText.setSpan(
800
+ new ReactBackgroundColorSpan(backgroundColor), 0, workingText.length(), spanFlags);
801
+ }
802
+
803
+ if ((getPaintFlags() & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
804
+ workingText.setSpan(new ReactStrikethroughSpan(), 0, workingText.length(), spanFlags);
805
+ }
806
+
807
+ if ((getPaintFlags() & Paint.UNDERLINE_TEXT_FLAG) != 0) {
808
+ workingText.setSpan(new ReactUnderlineSpan(), 0, workingText.length(), spanFlags);
809
+ }
810
+
811
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
812
+ float effectiveLetterSpacing = mTextAttributes.getEffectiveLetterSpacing();
813
+ if (!Float.isNaN(effectiveLetterSpacing)) {
814
+ workingText.setSpan(
815
+ new CustomLetterSpacingSpan(effectiveLetterSpacing),
816
+ 0,
817
+ workingText.length(),
818
+ spanFlags);
680
819
  }
820
+ }
681
821
 
682
- sb.removeSpan(span);
822
+ if (mFontStyle != UNSET
823
+ || mFontWeight != UNSET
824
+ || mFontFamily != null
825
+ || getFontFeatureSettings() != null) {
826
+ workingText.setSpan(
827
+ new CustomStyleSpan(
828
+ mFontStyle,
829
+ mFontWeight,
830
+ getFontFeatureSettings(),
831
+ mFontFamily,
832
+ getContext().getAssets()),
833
+ 0,
834
+ workingText.length(),
835
+ spanFlags);
836
+ }
837
+
838
+ float lineHeight = mTextAttributes.getEffectiveLineHeight();
839
+ if (!Float.isNaN(lineHeight)) {
840
+ workingText.setSpan(new CustomLineHeightSpan(lineHeight), 0, workingText.length(), spanFlags);
683
841
  }
684
842
  }
685
843
 
@@ -699,73 +857,6 @@ public class ReactEditText extends AppCompatEditText
699
857
  return true;
700
858
  }
701
859
 
702
- // This is hacked in for Fabric. When we delete non-Fabric code, we might be able to simplify or
703
- // clean this up a bit.
704
- private void addSpansForMeasurement(Spannable spannable) {
705
- if (!mFabricViewStateManager.hasStateWrapper()) {
706
- return;
707
- }
708
-
709
- boolean originalDisableTextDiffing = mDisableTextDiffing;
710
- mDisableTextDiffing = true;
711
-
712
- int start = 0;
713
- int end = spannable.length();
714
-
715
- // Remove duplicate spans we might add here
716
- Object[] spans = spannable.getSpans(0, length(), Object.class);
717
- for (Object span : spans) {
718
- int spanFlags = spannable.getSpanFlags(span);
719
- boolean isInclusive =
720
- (spanFlags & Spanned.SPAN_INCLUSIVE_INCLUSIVE) == Spanned.SPAN_INCLUSIVE_INCLUSIVE
721
- || (spanFlags & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) == Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
722
- if (isInclusive
723
- && span instanceof ReactSpan
724
- && spannable.getSpanStart(span) == start
725
- && spannable.getSpanEnd(span) == end) {
726
- spannable.removeSpan(span);
727
- }
728
- }
729
-
730
- List<TextLayoutManager.SetSpanOperation> ops = new ArrayList<>();
731
-
732
- if (!Float.isNaN(mTextAttributes.getLetterSpacing())) {
733
- ops.add(
734
- new TextLayoutManager.SetSpanOperation(
735
- start, end, new CustomLetterSpacingSpan(mTextAttributes.getLetterSpacing())));
736
- }
737
- ops.add(
738
- new TextLayoutManager.SetSpanOperation(
739
- start, end, new ReactAbsoluteSizeSpan((int) mTextAttributes.getEffectiveFontSize())));
740
- if (mFontStyle != UNSET || mFontWeight != UNSET || mFontFamily != null) {
741
- ops.add(
742
- new TextLayoutManager.SetSpanOperation(
743
- start,
744
- end,
745
- new CustomStyleSpan(
746
- mFontStyle,
747
- mFontWeight,
748
- null, // TODO: do we need to support FontFeatureSettings / fontVariant?
749
- mFontFamily,
750
- getReactContext(ReactEditText.this).getAssets())));
751
- }
752
- if (!Float.isNaN(mTextAttributes.getEffectiveLineHeight())) {
753
- ops.add(
754
- new TextLayoutManager.SetSpanOperation(
755
- start, end, new CustomLineHeightSpan(mTextAttributes.getEffectiveLineHeight())));
756
- }
757
-
758
- int priority = 0;
759
- for (TextLayoutManager.SetSpanOperation op : ops) {
760
- // Actual order of calling {@code execute} does NOT matter,
761
- // but the {@code priority} DOES matter.
762
- op.execute(spannable, priority);
763
- priority++;
764
- }
765
-
766
- mDisableTextDiffing = originalDisableTextDiffing;
767
- }
768
-
769
860
  protected boolean showSoftKeyboard() {
770
861
  return mInputMethodManager.showSoftInput(this, 0);
771
862
  }
@@ -820,6 +911,11 @@ public class ReactEditText extends AppCompatEditText
820
911
  }
821
912
  }
822
913
 
914
+ /* package */ int getGravityHorizontal() {
915
+ return getGravity()
916
+ & (Gravity.HORIZONTAL_GRAVITY_MASK | Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK);
917
+ }
918
+
823
919
  /* package */ void setGravityHorizontal(int gravityHorizontal) {
824
920
  if (gravityHorizontal == 0) {
825
921
  gravityHorizontal = mDefaultGravityHorizontal;
@@ -1030,7 +1126,9 @@ public class ReactEditText extends AppCompatEditText
1030
1126
 
1031
1127
  float effectiveLetterSpacing = mTextAttributes.getEffectiveLetterSpacing();
1032
1128
  if (!Float.isNaN(effectiveLetterSpacing)) {
1033
- setLetterSpacing(effectiveLetterSpacing);
1129
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
1130
+ setLetterSpacing(effectiveLetterSpacing);
1131
+ }
1034
1132
  }
1035
1133
  }
1036
1134
 
@@ -1045,7 +1143,7 @@ public class ReactEditText extends AppCompatEditText
1045
1143
  * TextLayoutManager.java with some very minor modifications. There's some duplication between
1046
1144
  * here and TextLayoutManager, so there might be an opportunity for refactor.
1047
1145
  */
1048
- private void updateCachedSpannable(boolean resetStyles) {
1146
+ private void updateCachedSpannable() {
1049
1147
  // Noops in non-Fabric
1050
1148
  if (mFabricViewStateManager == null || !mFabricViewStateManager.hasStateWrapper()) {
1051
1149
  return;
@@ -1055,12 +1153,6 @@ public class ReactEditText extends AppCompatEditText
1055
1153
  return;
1056
1154
  }
1057
1155
 
1058
- if (resetStyles) {
1059
- mIsSettingTextFromCacheUpdate = true;
1060
- addSpansForMeasurement(getText());
1061
- mIsSettingTextFromCacheUpdate = false;
1062
- }
1063
-
1064
1156
  Editable currentText = getText();
1065
1157
  boolean haveText = currentText != null && currentText.length() > 0;
1066
1158
 
@@ -1118,11 +1210,9 @@ public class ReactEditText extends AppCompatEditText
1118
1210
  // Measure something so we have correct height, even if there's no string.
1119
1211
  sb.append("I");
1120
1212
  }
1121
-
1122
- // Make sure that all text styles are applied when we're measurable the hint or "blank" text
1123
- addSpansForMeasurement(sb);
1124
1213
  }
1125
1214
 
1215
+ addSpansFromStyleAttributes(sb);
1126
1216
  TextLayoutManager.setCachedSpannabledForTag(getId(), sb);
1127
1217
  }
1128
1218
 
@@ -1137,7 +1227,7 @@ public class ReactEditText extends AppCompatEditText
1137
1227
  private class TextWatcherDelegator implements TextWatcher {
1138
1228
  @Override
1139
1229
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {
1140
- if (!mIsSettingTextFromCacheUpdate && !mIsSettingTextFromJS && mListeners != null) {
1230
+ if (!mIsSettingTextFromJS && mListeners != null) {
1141
1231
  for (TextWatcher listener : mListeners) {
1142
1232
  listener.beforeTextChanged(s, start, count, after);
1143
1233
  }
@@ -1151,23 +1241,20 @@ public class ReactEditText extends AppCompatEditText
1151
1241
  TAG, "onTextChanged[" + getId() + "]: " + s + " " + start + " " + before + " " + count);
1152
1242
  }
1153
1243
 
1154
- if (!mIsSettingTextFromCacheUpdate) {
1155
- if (!mIsSettingTextFromJS && mListeners != null) {
1156
- for (TextWatcher listener : mListeners) {
1157
- listener.onTextChanged(s, start, before, count);
1158
- }
1244
+ if (!mIsSettingTextFromJS && mListeners != null) {
1245
+ for (TextWatcher listener : mListeners) {
1246
+ listener.onTextChanged(s, start, before, count);
1159
1247
  }
1160
-
1161
- updateCachedSpannable(
1162
- !mIsSettingTextFromJS && !mIsSettingTextFromState && start == 0 && before == 0);
1163
1248
  }
1164
1249
 
1250
+ updateCachedSpannable();
1251
+
1165
1252
  onContentSizeChange();
1166
1253
  }
1167
1254
 
1168
1255
  @Override
1169
1256
  public void afterTextChanged(Editable s) {
1170
- if (!mIsSettingTextFromCacheUpdate && !mIsSettingTextFromJS && mListeners != null) {
1257
+ if (!mIsSettingTextFromJS && mListeners != null) {
1171
1258
  for (TextWatcher listener : mListeners) {
1172
1259
  listener.afterTextChanged(s);
1173
1260
  }
@@ -13,6 +13,7 @@ import android.content.Context;
13
13
  import android.content.res.ColorStateList;
14
14
  import android.graphics.BlendMode;
15
15
  import android.graphics.BlendModeColorFilter;
16
+ import android.graphics.Paint;
16
17
  import android.graphics.PorterDuff;
17
18
  import android.graphics.drawable.Drawable;
18
19
  import android.os.Build;
@@ -67,6 +68,7 @@ import com.facebook.react.views.text.DefaultStyleValuesUtil;
67
68
  import com.facebook.react.views.text.ReactBaseTextShadowNode;
68
69
  import com.facebook.react.views.text.ReactTextUpdate;
69
70
  import com.facebook.react.views.text.ReactTextViewManagerCallback;
71
+ import com.facebook.react.views.text.ReactTypefaceUtils;
70
72
  import com.facebook.react.views.text.TextAttributeProps;
71
73
  import com.facebook.react.views.text.TextInlineImageSpan;
72
74
  import com.facebook.react.views.text.TextLayoutManager;
@@ -404,6 +406,11 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
404
406
  view.setFontStyle(fontStyle);
405
407
  }
406
408
 
409
+ @ReactProp(name = ViewProps.FONT_VARIANT)
410
+ public void setFontVariant(ReactEditText view, @Nullable ReadableArray fontVariant) {
411
+ view.setFontFeatureSettings(ReactTypefaceUtils.parseFontVariant(fontVariant));
412
+ }
413
+
407
414
  @ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
408
415
  public void setIncludeFontPadding(ReactEditText view, boolean includepad) {
409
416
  view.setIncludeFontPadding(includepad);
@@ -925,6 +932,20 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
925
932
  view.setAutoFocus(autoFocus);
926
933
  }
927
934
 
935
+ @ReactProp(name = ViewProps.TEXT_DECORATION_LINE)
936
+ public void setTextDecorationLine(ReactEditText view, @Nullable String textDecorationLineString) {
937
+ view.setPaintFlags(
938
+ view.getPaintFlags() & ~(Paint.STRIKE_THRU_TEXT_FLAG | Paint.UNDERLINE_TEXT_FLAG));
939
+
940
+ for (String token : textDecorationLineString.split(" ")) {
941
+ if (token.equals("underline")) {
942
+ view.setPaintFlags(view.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
943
+ } else if (token.equals("line-through")) {
944
+ view.setPaintFlags(view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
945
+ }
946
+ }
947
+ }
948
+
928
949
  @ReactPropGroup(
929
950
  names = {
930
951
  ViewProps.BORDER_WIDTH,
@@ -1305,10 +1326,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
1305
1326
  }
1306
1327
 
1307
1328
  ReadableNativeMap state = stateWrapper.getStateData();
1308
- if (state == null) {
1309
- return null;
1310
- }
1311
- if (!state.hasKey("attributedString")) {
1329
+ if (state == null || !state.hasKey("attributedString")) {
1312
1330
  return null;
1313
1331
  }
1314
1332
 
@@ -1322,19 +1340,19 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
1322
1340
  TextLayoutManager.getOrCreateSpannableForText(
1323
1341
  view.getContext(), attributedString, mReactTextViewManagerCallback);
1324
1342
 
1325
- boolean containsMultipleFragments =
1326
- attributedString.getArray("fragments").toArrayList().size() > 1;
1327
-
1328
1343
  int textBreakStrategy =
1329
- TextAttributeProps.getTextBreakStrategy(paragraphAttributes.getString("textBreakStrategy"));
1344
+ TextAttributeProps.getTextBreakStrategy(
1345
+ paragraphAttributes.getString(ViewProps.TEXT_BREAK_STRATEGY));
1346
+ int currentJustificationMode =
1347
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode();
1330
1348
 
1331
1349
  return ReactTextUpdate.buildReactTextUpdateFromState(
1332
1350
  spanned,
1333
1351
  state.getInt("mostRecentEventCount"),
1334
- TextAttributeProps.getTextAlignment(props, TextLayoutManager.isRTL(attributedString)),
1352
+ TextAttributeProps.getTextAlignment(
1353
+ props, TextLayoutManager.isRTL(attributedString), view.getGravityHorizontal()),
1335
1354
  textBreakStrategy,
1336
- TextAttributeProps.getJustificationMode(props),
1337
- containsMultipleFragments);
1355
+ TextAttributeProps.getJustificationMode(props, currentJustificationMode));
1338
1356
  }
1339
1357
 
1340
1358
  public Object getReactTextUpdate(ReactEditText view, ReactStylesDiffMap props, MapBuffer state) {
@@ -1355,20 +1373,18 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
1355
1373
  TextLayoutManagerMapBuffer.getOrCreateSpannableForText(
1356
1374
  view.getContext(), attributedString, mReactTextViewManagerCallback);
1357
1375
 
1358
- boolean containsMultipleFragments =
1359
- attributedString.getMapBuffer(TextLayoutManagerMapBuffer.AS_KEY_FRAGMENTS).getCount() > 1;
1360
-
1361
1376
  int textBreakStrategy =
1362
1377
  TextAttributeProps.getTextBreakStrategy(
1363
1378
  paragraphAttributes.getString(TextLayoutManagerMapBuffer.PA_KEY_TEXT_BREAK_STRATEGY));
1379
+ int currentJustificationMode =
1380
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode();
1364
1381
 
1365
1382
  return ReactTextUpdate.buildReactTextUpdateFromState(
1366
1383
  spanned,
1367
1384
  state.getInt(TX_STATE_KEY_MOST_RECENT_EVENT_COUNT),
1368
1385
  TextAttributeProps.getTextAlignment(
1369
- props, TextLayoutManagerMapBuffer.isRTL(attributedString)),
1386
+ props, TextLayoutManagerMapBuffer.isRTL(attributedString), view.getGravityHorizontal()),
1370
1387
  textBreakStrategy,
1371
- TextAttributeProps.getJustificationMode(props),
1372
- containsMultipleFragments);
1388
+ TextAttributeProps.getJustificationMode(props, currentJustificationMode));
1373
1389
  }
1374
1390
  }
@@ -19,6 +19,7 @@ public class ReactViewBackgroundManager {
19
19
 
20
20
  private @Nullable ReactViewBackgroundDrawable mReactBackgroundDrawable;
21
21
  private View mView;
22
+ private int mColor = Color.TRANSPARENT;
22
23
 
23
24
  public ReactViewBackgroundManager(View view) {
24
25
  this.mView = view;
@@ -56,6 +57,10 @@ public class ReactViewBackgroundManager {
56
57
  }
57
58
  }
58
59
 
60
+ public int getBackgroundColor() {
61
+ return mColor;
62
+ }
63
+
59
64
  public void setBorderWidth(int position, float width) {
60
65
  getOrCreateReactViewBackground().setBorderWidth(position, width);
61
66
  }
@@ -17,7 +17,7 @@ namespace facebook::react {
17
17
  constexpr struct {
18
18
  int32_t Major = 0;
19
19
  int32_t Minor = 71;
20
- int32_t Patch = 5;
20
+ int32_t Patch = 7;
21
21
  std::string_view Prerelease = "";
22
22
  } ReactNativeVersion;
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native",
3
- "version": "0.71.5",
3
+ "version": "0.71.7",
4
4
  "bin": "./cli.js",
5
5
  "description": "A framework for building native apps using React",
6
6
  "license": "MIT",
@@ -85,7 +85,7 @@ class CodegenUtils
85
85
  'source' => { :git => '' },
86
86
  'header_mappings_dir' => './',
87
87
  'platforms' => {
88
- 'ios' => '11.0',
88
+ 'ios' => min_ios_version_supported,
89
89
  },
90
90
  'source_files' => "**/*.{h,mm,cpp}",
91
91
  'pod_target_xcconfig' => { "HEADER_SEARCH_PATHS" =>
Binary file
Binary file
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "react": "18.2.0",
14
- "react-native": "0.71.5"
14
+ "react-native": "0.71.7"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@babel/core": "^7.20.0",