diff --git a/packages/react-native/Libraries/Text/TextNativeComponent.js b/packages/react-native/Libraries/Text/TextNativeComponent.js index 50815d71d91f..98ae591a5204 100644 --- a/packages/react-native/Libraries/Text/TextNativeComponent.js +++ b/packages/react-native/Libraries/Text/TextNativeComponent.js @@ -47,6 +47,8 @@ const textViewConfig = { onTextLayout: true, dataDetectorType: true, android_hyphenationFrequency: true, + lineBreak: true, + wordBreak: true, lineBreakStrategyIOS: true, }, directEventTypes: { diff --git a/packages/react-native/Libraries/Text/TextProps.js b/packages/react-native/Libraries/Text/TextProps.js index c8f28ddc4b49..6fb8b163595a 100644 --- a/packages/react-native/Libraries/Text/TextProps.js +++ b/packages/react-native/Libraries/Text/TextProps.js @@ -149,6 +149,31 @@ type TextBaseProps = Readonly<{ */ android_hyphenationFrequency?: ?('normal' | 'none' | 'full'), + /** + * Sets the strictness of the line-breaking rules, such as which characters + * may start or end a line in Chinese and Japanese text (kinsoku), as CSS + * `line-break`. Currently Android only, and ignored below Android 13 (API + * level 33). + * + * @default `'auto'` + * @platform android + */ + lineBreak?: ?('auto' | 'loose' | 'normal' | 'strict'), + + /** + * Sets word-based line breaking, as CSS `word-break`. `'auto-phrase'` breaks + * Japanese text at phrase boundaries instead of between any two characters. + * Currently Android only, and ignored below Android 13 (API level 33). + * + * Support depends on the locale, and text is laid out in the device locale: + * where that locale has no phrase-based breaking, `'auto-phrase'` has no + * effect. + * + * @default `'normal'` + * @platform android + */ + wordBreak?: ?('normal' | 'auto-phrase'), + children?: ?React.Node, /** diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 6c76d3a2197f..ba540f18c54d 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -6042,6 +6042,8 @@ public class com/facebook/react/views/text/ReactTextView : androidx/appcompat/wi public fun setHyphenationFrequency (I)V public fun setIncludeFontPadding (Z)V public fun setLetterSpacing (F)V + public fun setLineBreakStyle (I)V + public fun setLineBreakWordStyle (I)V public fun setLinkifyMask (I)V public fun setMinimumFontScale (F)V public fun setMinimumFontSize (F)V @@ -6088,6 +6090,7 @@ public class com/facebook/react/views/text/ReactTextViewManager : com/facebook/r public final fun setFontSize (Lcom/facebook/react/views/text/ReactTextView;F)V public final fun setIncludeFontPadding (Lcom/facebook/react/views/text/ReactTextView;Z)V public final fun setLetterSpacing (Lcom/facebook/react/views/text/ReactTextView;F)V + public final fun setLineBreak (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/String;)V public final fun setNumberOfLines (Lcom/facebook/react/views/text/ReactTextView;I)V public final fun setOverflow (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/String;)V public synthetic fun setPadding (Landroid/view/View;IIII)V @@ -6096,6 +6099,7 @@ public class com/facebook/react/views/text/ReactTextViewManager : com/facebook/r public final fun setSelectable (Lcom/facebook/react/views/text/ReactTextView;Z)V public final fun setSelectionColor (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/Integer;)V public final fun setTextAlignVertical (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/String;)V + public final fun setWordBreak (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/String;)V public synthetic fun updateExtraData (Landroid/view/View;Ljava/lang/Object;)V public fun updateExtraData (Lcom/facebook/react/views/text/ReactTextView;Ljava/lang/Object;)V public synthetic fun updateState (Landroid/view/View;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;)Ljava/lang/Object; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java index e34ad6521bc9..18321fa94e82 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java @@ -7,9 +7,11 @@ package com.facebook.react.views.text; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; +import android.graphics.text.LineBreakConfig; import android.os.Build; import android.text.Layout; import android.text.Spannable; @@ -26,6 +28,7 @@ import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.appcompat.widget.AppCompatTextView; import androidx.core.view.AccessibilityDelegateCompat; import androidx.core.view.ViewCompat; @@ -199,6 +202,10 @@ private void initView() { setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + setLineBreakStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE); + setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE); + } updateView(); // call after changing ellipsizeLocation in particular } @@ -251,6 +258,8 @@ protected void onDraw(Canvas canvas) { getIncludeFontPadding(), getBreakStrategy(), getHyphenationFrequency(), + getLineBreakStyleCompat(), + getLineBreakWordStyleCompat(), // always passing ALIGN_NORMAL here should be fine, since this method doesn't depend on // how exactly lines are aligned, just their width Layout.Alignment.ALIGN_NORMAL, @@ -599,6 +608,34 @@ public void setHyphenationFrequency(int hyphenationFrequency) { mShouldAdjustSpannableFontSize = true; } + @Override + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void setLineBreakStyle(int lineBreakStyle) { + super.setLineBreakStyle(lineBreakStyle); + mShouldAdjustSpannableFontSize = true; + } + + @Override + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public void setLineBreakWordStyle(int lineBreakWordStyle) { + super.setLineBreakWordStyle(lineBreakWordStyle); + mShouldAdjustSpannableFontSize = true; + } + + @SuppressLint("InlinedApi") + private int getLineBreakStyleCompat() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + ? getLineBreakStyle() + : LineBreakConfig.LINE_BREAK_STYLE_NONE; + } + + @SuppressLint("InlinedApi") + private int getLineBreakWordStyleCompat() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + ? getLineBreakWordStyle() + : LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE; + } + @Override public void setLetterSpacing(float letterSpacing) { if (Float.isNaN(letterSpacing)) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.kt index 8512fccba2f6..ef7c3a33b04e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.kt @@ -343,6 +343,20 @@ public constructor( } } + @ReactProp(name = "lineBreak") + public fun setLineBreak(view: ReactTextView, lineBreak: String?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + view.lineBreakStyle = TextAttributeProps.getLineBreakStyle(lineBreak) + } + } + + @ReactProp(name = "wordBreak") + public fun setWordBreak(view: ReactTextView, wordBreak: String?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + view.lineBreakWordStyle = TextAttributeProps.getLineBreakWordStyle(wordBreak) + } + } + @ReactPropGroup( names = [ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt index ca2d10ece398..24aaea509f52 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.kt @@ -7,6 +7,8 @@ package com.facebook.react.views.text +import android.annotation.SuppressLint +import android.graphics.text.LineBreakConfig import android.os.Build import android.text.Layout import android.text.TextUtils.TruncateAt @@ -612,6 +614,36 @@ public class TextAttributeProps private constructor() { else -> Layout.HYPHENATION_FREQUENCY_FULL } + // The LineBreakConfig constants are inlined at compile time, so reading them is safe below API + // 33. Callers apply the result only on API 33+. + // Maps CSS `line-break` values to LineBreakConfig.LINE_BREAK_STYLE_*. + @SuppressLint("InlinedApi") + internal fun getLineBreakStyle(lineBreak: String?): Int = + when (lineBreak) { + null, + "auto" -> LineBreakConfig.LINE_BREAK_STYLE_NONE + "loose" -> LineBreakConfig.LINE_BREAK_STYLE_LOOSE + "normal" -> LineBreakConfig.LINE_BREAK_STYLE_NORMAL + "strict" -> LineBreakConfig.LINE_BREAK_STYLE_STRICT + else -> { + FLog.w(ReactConstants.TAG, "Invalid lineBreak: $lineBreak") + LineBreakConfig.LINE_BREAK_STYLE_NONE + } + } + + // Maps CSS `word-break` values to LineBreakConfig.LINE_BREAK_WORD_STYLE_*. + @SuppressLint("InlinedApi") + internal fun getLineBreakWordStyle(wordBreak: String?): Int = + when (wordBreak) { + null, + "normal" -> LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE + "auto-phrase" -> LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE + else -> { + FLog.w(ReactConstants.TAG, "Invalid wordBreak: $wordBreak") + LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE + } + } + public fun getEllipsizeMode(ellipsizeMode: String?): TruncateAt? = when (ellipsizeMode) { "head" -> TruncateAt.START diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt index f3bac78200aa..54288339c7d8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt @@ -11,6 +11,7 @@ import android.content.res.AssetManager import android.graphics.Color import android.graphics.RectF import android.graphics.Typeface +import android.graphics.text.LineBreakConfig import android.os.Build import android.text.BoringLayout import android.text.Layout @@ -99,6 +100,8 @@ internal object TextLayoutManager { const val PA_KEY_TEXT_ALIGN_VERTICAL: Int = 8 const val PA_KEY_TEXT_WIDTH_MODE: Int = 9 const val PA_KEY_MINIMUM_FONT_SCALE: Int = 10 + const val PA_KEY_LINE_BREAK: Int = 11 + const val PA_KEY_WORD_BREAK: Int = 12 private val TAG: String = TextLayoutManager::class.java.simpleName @@ -849,6 +852,8 @@ internal object TextLayoutManager { includeFontPadding: Boolean, textBreakStrategy: Int, hyphenationFrequency: Int, + lineBreakStyle: Int, + lineBreakWordStyle: Int, alignment: Layout.Alignment, justificationMode: Int, ellipsizeMode: TextUtils.TruncateAt?, @@ -895,6 +900,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, ellipsizeMode, @@ -913,6 +920,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, ellipsizeMode, @@ -963,6 +972,8 @@ internal object TextLayoutManager { includeFontPadding: Boolean, textBreakStrategy: Int, hyphenationFrequency: Int, + lineBreakStyle: Int, + lineBreakWordStyle: Int, alignment: Layout.Alignment, justificationMode: Int, ellipsizeMode: TextUtils.TruncateAt?, @@ -990,6 +1001,21 @@ internal object TextLayoutManager { builder.setUseLineSpacingFromFallbacks(true) } + // Leave the platform default in place unless a style was requested, so text without these props + // lays out exactly as before. + if ( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && + (lineBreakStyle != LineBreakConfig.LINE_BREAK_STYLE_NONE || + lineBreakWordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE) + ) { + builder.setLineBreakConfig( + LineBreakConfig.Builder() + .setLineBreakStyle(lineBreakStyle) + .setLineBreakWordStyle(lineBreakWordStyle) + .build() + ) + } + // Android shifts negative (left-side) start overhang itself. RTL start overhang is on the // right, so createLayout reserves that space in a second pass while preserving the EXACT Yoga // measurement returned to the caller. @@ -1169,6 +1195,18 @@ internal object TextLayoutManager { TextAttributeProps.getHyphenationFrequency( paragraphAttributes.getString(PA_KEY_HYPHENATION_FREQUENCY), ) + val lineBreakStyle = + TextAttributeProps.getLineBreakStyle( + if (paragraphAttributes.contains(PA_KEY_LINE_BREAK)) + paragraphAttributes.getString(PA_KEY_LINE_BREAK) + else null, + ) + val lineBreakWordStyle = + TextAttributeProps.getLineBreakWordStyle( + if (paragraphAttributes.contains(PA_KEY_WORD_BREAK)) + paragraphAttributes.getString(PA_KEY_WORD_BREAK) + else null, + ) val adjustFontSizeToFit = if (paragraphAttributes.contains(PA_KEY_ADJUST_FONT_SIZE_TO_FIT)) paragraphAttributes.getBoolean(PA_KEY_ADJUST_FONT_SIZE_TO_FIT) @@ -1211,6 +1249,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, paint, @@ -1226,6 +1266,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, ellipsizeMode, @@ -1249,6 +1291,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, ellipsizeMode, @@ -1372,6 +1416,8 @@ internal object TextLayoutManager { includeFontPadding: Boolean, textBreakStrategy: Int, hyphenationFrequency: Int, + lineBreakStyle: Int, + lineBreakWordStyle: Int, alignment: Layout.Alignment, justificationMode: Int, paint: TextPaint, @@ -1436,6 +1482,8 @@ internal object TextLayoutManager { includeFontPadding, textBreakStrategy, hyphenationFrequency, + lineBreakStyle, + lineBreakWordStyle, alignment, justificationMode, null, diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest.kt index 33e00f0af10c..5d2702725743 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest.kt @@ -8,6 +8,7 @@ package com.facebook.react.views.text import android.annotation.SuppressLint +import android.graphics.text.LineBreakConfig import android.text.BoringLayout import android.text.Layout import android.text.SpannableString @@ -104,6 +105,8 @@ class TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest { java.lang.Boolean.TYPE, java.lang.Integer.TYPE, java.lang.Integer.TYPE, + java.lang.Integer.TYPE, + java.lang.Integer.TYPE, Layout.Alignment::class.java, java.lang.Integer.TYPE, TextUtils.TruncateAt::class.java, @@ -121,6 +124,8 @@ class TextLayoutManagerAbsoluteLayoutWithFractionalPixelTest { /* includeFontPadding = */ false, /* textBreakStrategy = */ Layout.BREAK_STRATEGY_HIGH_QUALITY, /* hyphenationFrequency = */ Layout.HYPHENATION_FREQUENCY_NONE, + /* lineBreakStyle = */ LineBreakConfig.LINE_BREAK_STYLE_NONE, + /* lineBreakWordStyle = */ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, Layout.Alignment.ALIGN_NORMAL, /* justificationMode = */ 0, /* ellipsizeMode = */ null, diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerMinimumFontScaleTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerMinimumFontScaleTest.kt index 1fba91156cb6..fe2018802595 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerMinimumFontScaleTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerMinimumFontScaleTest.kt @@ -7,6 +7,7 @@ package com.facebook.react.views.text +import android.graphics.text.LineBreakConfig import android.text.Layout import android.text.SpannableString import android.text.Spanned @@ -123,6 +124,8 @@ class TextLayoutManagerMinimumFontScaleTest { true, Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE, + /* lineBreakStyle = */ LineBreakConfig.LINE_BREAK_STYLE_NONE, + /* lineBreakWordStyle = */ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, Layout.Alignment.ALIGN_NORMAL, 0, newPaint(), @@ -149,6 +152,8 @@ class TextLayoutManagerMinimumFontScaleTest { true, Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE, + /* lineBreakStyle = */ LineBreakConfig.LINE_BREAK_STYLE_NONE, + /* lineBreakWordStyle = */ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, Layout.Alignment.ALIGN_NORMAL, 0, newPaint(), diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerStartOverhangTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerStartOverhangTest.kt index 2f23db9c3047..db1cf120fc0b 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerStartOverhangTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerStartOverhangTest.kt @@ -9,6 +9,7 @@ package com.facebook.react.views.text import android.annotation.SuppressLint import android.graphics.RectF +import android.graphics.text.LineBreakConfig import android.text.BoringLayout import android.text.Layout import android.text.SpannableString @@ -145,6 +146,8 @@ class TextLayoutManagerStartOverhangTest { java.lang.Boolean.TYPE, java.lang.Integer.TYPE, java.lang.Integer.TYPE, + java.lang.Integer.TYPE, + java.lang.Integer.TYPE, Layout.Alignment::class.java, java.lang.Integer.TYPE, TextUtils.TruncateAt::class.java, @@ -162,6 +165,8 @@ class TextLayoutManagerStartOverhangTest { /* includeFontPadding = */ false, /* textBreakStrategy = */ Layout.BREAK_STRATEGY_HIGH_QUALITY, /* hyphenationFrequency = */ Layout.HYPHENATION_FREQUENCY_NONE, + /* lineBreakStyle = */ LineBreakConfig.LINE_BREAK_STYLE_NONE, + /* lineBreakWordStyle = */ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE, Layout.Alignment.ALIGN_NORMAL, /* justificationMode = */ 0, /* ellipsizeMode = */ ellipsizeMode, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp index af4c92f85611..c6bbbf364ce4 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp @@ -23,6 +23,8 @@ bool ParagraphAttributes::operator==(const ParagraphAttributes& rhs) const { adjustsFontSizeToFit, includeFontPadding, android_hyphenationFrequency, + lineBreak, + wordBreak, textAlignVertical) == std::tie( rhs.maximumNumberOfLines, @@ -32,6 +34,8 @@ bool ParagraphAttributes::operator==(const ParagraphAttributes& rhs) const { rhs.adjustsFontSizeToFit, rhs.includeFontPadding, rhs.android_hyphenationFrequency, + rhs.lineBreak, + rhs.wordBreak, rhs.textAlignVertical) && floatEquality(minimumFontSize, rhs.minimumFontSize) && floatEquality(minimumFontScale, rhs.minimumFontScale); @@ -75,6 +79,10 @@ SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const { "android_hyphenationFrequency", android_hyphenationFrequency, paragraphAttributes.android_hyphenationFrequency), + debugStringConvertibleItem( + "lineBreak", lineBreak, paragraphAttributes.lineBreak), + debugStringConvertibleItem( + "wordBreak", wordBreak, paragraphAttributes.wordBreak), debugStringConvertibleItem( "textAlignVertical", textAlignVertical, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h index a944b9e14ff8..7a8d8dba13a1 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h @@ -68,6 +68,18 @@ class ParagraphAttributes : public DebugStringConvertible { */ HyphenationFrequency android_hyphenationFrequency{}; + /* + * Strictness of the line-breaking rules (CSS `line-break`). + * Currently applied on Android only. + */ + LineBreak lineBreak{}; + + /* + * Word-based line breaking (CSS `word-break`). + * Currently applied on Android only. + */ + WordBreak wordBreak{}; + /* * In case of font size adjustment enabled, defines the minimum font size. * Deprecated in favor of minimumFontScale. @@ -112,6 +124,8 @@ struct hash { attributes.minimumFontSize, attributes.includeFontPadding, attributes.android_hyphenationFrequency, + attributes.lineBreak, + attributes.wordBreak, attributes.minimumFontScale, attributes.textAlignVertical); } diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h index 263d53e9b864..61353692b086 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h @@ -1034,6 +1034,88 @@ inline void fromRawValue(const PropsParserContext &context, const RawValue &valu result = HyphenationFrequency::None; } +inline std::string toString(const LineBreak &lineBreak) +{ + switch (lineBreak) { + case LineBreak::Auto: + return "auto"; + case LineBreak::Loose: + return "loose"; + case LineBreak::Normal: + return "normal"; + case LineBreak::Strict: + return "strict"; + } + + LOG(ERROR) << "Unsupported LineBreak value"; + react_native_expect(false); + return "auto"; +} + +inline void fromRawValue(const PropsParserContext &context, const RawValue &value, LineBreak &result) +{ + react_native_expect(value.hasType()); + if (value.hasType()) { + auto string = (std::string)value; + if (string == "auto") { + result = LineBreak::Auto; + } else if (string == "loose") { + result = LineBreak::Loose; + } else if (string == "normal") { + result = LineBreak::Normal; + } else if (string == "strict") { + result = LineBreak::Strict; + } else { + // sane default + LOG(ERROR) << "Unsupported LineBreak value: " << string; + react_native_expect(false); + result = LineBreak::Auto; + } + return; + } + + LOG(ERROR) << "Unsupported LineBreak type"; + react_native_expect(false); + result = LineBreak::Auto; +} + +inline std::string toString(const WordBreak &wordBreak) +{ + switch (wordBreak) { + case WordBreak::Normal: + return "normal"; + case WordBreak::AutoPhrase: + return "auto-phrase"; + } + + LOG(ERROR) << "Unsupported WordBreak value"; + react_native_expect(false); + return "normal"; +} + +inline void fromRawValue(const PropsParserContext &context, const RawValue &value, WordBreak &result) +{ + react_native_expect(value.hasType()); + if (value.hasType()) { + auto string = (std::string)value; + if (string == "normal") { + result = WordBreak::Normal; + } else if (string == "auto-phrase") { + result = WordBreak::AutoPhrase; + } else { + // sane default + LOG(ERROR) << "Unsupported WordBreak value: " << string; + react_native_expect(false); + result = WordBreak::Normal; + } + return; + } + + LOG(ERROR) << "Unsupported WordBreak type"; + react_native_expect(false); + result = WordBreak::Normal; +} + inline ParagraphAttributes convertRawProp( const PropsParserContext &context, const RawProps &rawProps, @@ -1096,6 +1178,10 @@ inline ParagraphAttributes convertRawProp( "android_hyphenationFrequency", sourceParagraphAttributes.android_hyphenationFrequency, defaultParagraphAttributes.android_hyphenationFrequency); + paragraphAttributes.lineBreak = convertRawProp( + context, rawProps, "lineBreak", sourceParagraphAttributes.lineBreak, defaultParagraphAttributes.lineBreak); + paragraphAttributes.wordBreak = convertRawProp( + context, rawProps, "wordBreak", sourceParagraphAttributes.wordBreak, defaultParagraphAttributes.wordBreak); paragraphAttributes.textAlignVertical = convertRawProp( context, rawProps, @@ -1190,6 +1276,8 @@ constexpr static MapBuffer::Key PA_KEY_MINIMUM_FONT_SIZE = 6; constexpr static MapBuffer::Key PA_KEY_TEXT_ALIGN_VERTICAL = 8; constexpr static MapBuffer::Key PA_KEY_TEXT_WIDTH_MODE = 9; constexpr static MapBuffer::Key PA_KEY_MINIMUM_FONT_SCALE = 10; +constexpr static MapBuffer::Key PA_KEY_LINE_BREAK = 11; +constexpr static MapBuffer::Key PA_KEY_WORD_BREAK = 12; inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) { @@ -1201,6 +1289,8 @@ inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) builder.putBool(PA_KEY_ADJUST_FONT_SIZE_TO_FIT, paragraphAttributes.adjustsFontSizeToFit); builder.putBool(PA_KEY_INCLUDE_FONT_PADDING, paragraphAttributes.includeFontPadding); builder.putString(PA_KEY_HYPHENATION_FREQUENCY, toString(paragraphAttributes.android_hyphenationFrequency)); + builder.putString(PA_KEY_LINE_BREAK, toString(paragraphAttributes.lineBreak)); + builder.putString(PA_KEY_WORD_BREAK, toString(paragraphAttributes.wordBreak)); if (paragraphAttributes.textAlignVertical.has_value()) { builder.putString(PA_KEY_TEXT_ALIGN_VERTICAL, toString(*paragraphAttributes.textAlignVertical)); } diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/primitives.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/primitives.h index b96661bd4dd4..265860f687ff 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/primitives.h @@ -163,4 +163,24 @@ enum class HyphenationFrequency { Full // Standard amount of hyphenation. }; +/* + * Strictness of the line-breaking rules, as CSS `line-break`. + * Currently applied on Android only. + */ +enum class LineBreak { + Auto, // The platform's default rules. + Loose, // The least restrictive rules. + Normal, // The most common rules. + Strict // The most restrictive rules. +}; + +/* + * Word-based line breaking, as CSS `word-break`. + * Currently applied on Android only. + */ +enum class WordBreak { + Normal, // No word-based line breaking. + AutoPhrase // Break Japanese text at phrase boundaries. +}; + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/tests/ParagraphAttributesTest.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/tests/ParagraphAttributesTest.cpp index 3478df3f838b..d9b69e53c8e7 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/tests/ParagraphAttributesTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/tests/ParagraphAttributesTest.cpp @@ -93,4 +93,38 @@ TEST(ParagraphAttributesTest, testAutoTextWidthModeSerializesAsAuto) { EXPECT_EQ(toString(TextWidthMode::Auto), "auto"); } +TEST(ParagraphAttributesTest, testOperatorEqualsIncludesLineBreakAndWordBreak) { + ParagraphAttributes defaults{}; + ParagraphAttributes strict{}; + strict.lineBreak = LineBreak::Strict; + ParagraphAttributes phrase{}; + phrase.wordBreak = WordBreak::AutoPhrase; + + EXPECT_FALSE(defaults == strict); + EXPECT_FALSE(defaults == phrase); + EXPECT_NE( + std::hash{}(defaults), + std::hash{}(strict)); +} + +TEST( + ParagraphAttributesTest, + testLineBreakAndWordBreakDefaultToCssInitialValues) { + ParagraphAttributes defaults{}; + + EXPECT_EQ(defaults.lineBreak, LineBreak::Auto); + EXPECT_EQ(defaults.wordBreak, WordBreak::Normal); +} + +// The Android TextLayoutManager parses these strings, so they must match the +// values accepted from JavaScript. +TEST(ParagraphAttributesTest, testLineBreakAndWordBreakSerializeToPropValues) { + EXPECT_EQ(toString(LineBreak::Auto), "auto"); + EXPECT_EQ(toString(LineBreak::Loose), "loose"); + EXPECT_EQ(toString(LineBreak::Normal), "normal"); + EXPECT_EQ(toString(LineBreak::Strict), "strict"); + EXPECT_EQ(toString(WordBreak::Normal), "normal"); + EXPECT_EQ(toString(WordBreak::AutoPhrase), "auto-phrase"); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp index dbe0ba096cbe..6175bf755ea5 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseParagraphProps.cpp @@ -116,6 +116,10 @@ void BaseParagraphProps::setProp( paragraphAttributes, android_hyphenationFrequency, "android_hyphenationFrequency"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, value, paragraphAttributes, lineBreak, "lineBreak"); + REBUILD_FIELD_SWITCH_CASE( + paDefaults, value, paragraphAttributes, wordBreak, "wordBreak"); REBUILD_FIELD_SWITCH_CASE( paDefaults, value, diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/platform/android/react/renderer/components/text/HostPlatformParagraphProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/platform/android/react/renderer/components/text/HostPlatformParagraphProps.cpp index 9cba413645c2..13fc83e55c2f 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/platform/android/react/renderer/components/text/HostPlatformParagraphProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/platform/android/react/renderer/components/text/HostPlatformParagraphProps.cpp @@ -140,6 +140,16 @@ folly::dynamic HostPlatformParagraphProps::getDiffProps( toString(paragraphAttributes.android_hyphenationFrequency); } + if (paragraphAttributes.lineBreak != + oldProps->paragraphAttributes.lineBreak) { + result["lineBreak"] = toString(paragraphAttributes.lineBreak); + } + + if (paragraphAttributes.wordBreak != + oldProps->paragraphAttributes.wordBreak) { + result["wordBreak"] = toString(paragraphAttributes.wordBreak); + } + if (paragraphAttributes.textAlignVertical != oldProps->paragraphAttributes.textAlignVertical) { result["textAlignVertical"] = diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 74c407136ff1..814663cf7006 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<4a9c44fd63e273e2c994c3bf310743df>> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -4867,6 +4867,7 @@ declare type TextBaseProps = { readonly children?: React.ReactNode readonly ellipsizeMode?: "clip" | "head" | "middle" | "tail" readonly id?: string + readonly lineBreak?: "auto" | "loose" | "normal" | "strict" readonly maxFontSizeMultiplier?: number readonly nativeID?: string readonly numberOfLines?: number @@ -4890,6 +4891,7 @@ declare type TextBaseProps = { readonly selectable?: boolean readonly style?: TextStyleProp readonly testID?: string + readonly wordBreak?: "auto-phrase" | "normal" } declare type TextContentType = | "addressCity" @@ -5786,7 +5788,7 @@ export { AlertOptions, // 8a116d2a AlertType, // 5ab91217 AndroidKeyboardEvent, // e03becc8 - Animated, // f6f7758c + Animated, // 33fe7464 AppConfig, // 35c0ca70 AppRegistry, // edec2a30 AppState, // 12012be5 @@ -6020,7 +6022,7 @@ export { TVViewPropsIOS, // 1c612e4e TargetedEvent, // 16e98910 TaskProvider, // 266dedf2 - Text, // 6f8269c1 + Text, // 935ec305 TextContentType, // 239b3ecc TextInput, // cf6467dc TextInputAndroidProps, // 9ebbc103 @@ -6037,7 +6039,7 @@ export { TextInputSubmitEditingEvent, // e811fdbd TextInstance, // 7c7e2069 TextLayoutEvent, // 1a21e24a - TextProps, // ab00c755 + TextProps, // b3707dfc TextStyle, // 898adfd1 ToastAndroid, // 88a8969a TouchableHighlight, // a015710f diff --git a/packages/react-native/types_DEPRECATED/Libraries/Text/Text.d.ts b/packages/react-native/types_DEPRECATED/Libraries/Text/Text.d.ts index 25d8d8abe1ef..e793c03bc6d5 100644 --- a/packages/react-native/types_DEPRECATED/Libraries/Text/Text.d.ts +++ b/packages/react-native/types_DEPRECATED/Libraries/Text/Text.d.ts @@ -88,6 +88,19 @@ export interface TextPropsAndroid { * Hyphenation strategy */ android_hyphenationFrequency?: 'normal' | 'none' | 'full' | undefined; + + /** + * Strictness of the line-breaking rules (CSS `line-break`). + * Currently Android only, and ignored below Android 13 (API level 33). + */ + lineBreak?: 'auto' | 'loose' | 'normal' | 'strict' | undefined; + + /** + * Word-based line breaking (CSS `word-break`). Currently Android only, and + * ignored below Android 13 (API level 33). `'auto-phrase'` has no effect + * where the device locale has no phrase-based breaking. + */ + wordBreak?: 'normal' | 'auto-phrase' | undefined; } // https://reactnative.dev/docs/text#props diff --git a/packages/rn-tester/js/examples/Text/TextExample.android.js b/packages/rn-tester/js/examples/Text/TextExample.android.js index 896cede7ce64..aae2faacf9a0 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.android.js +++ b/packages/rn-tester/js/examples/Text/TextExample.android.js @@ -607,6 +607,38 @@ function HyphenationExample(props: {}): React.Node { ); } +const LINE_BREAK_SAMPLE = + 'キャッシュをチェックしてショートカットからコンピューターのメモリーをクリーンアップします。'; + +function LineBreakExample(props: {}): React.Node { + // Each paragraph has a background so that a mismatch between the measured + // height and the drawn lines is visible. Requires Android 13 (API 33). + return ( + <> + {(['auto', 'loose', 'normal', 'strict'] as const).map(lineBreak => ( + + + lineBreak="{lineBreak}" + + + {LINE_BREAK_SAMPLE} + + + ))} + {(['normal', 'auto-phrase'] as const).map(wordBreak => ( + + + wordBreak="{wordBreak}" + + + {LINE_BREAK_SAMPLE} + + + ))} + + ); +} + function FontWeightExample(props: {}): React.Node { return ( @@ -1459,6 +1491,13 @@ const examples = [ return ; }, }, + { + title: 'Line break (lineBreak, wordBreak)', + name: 'lineBreak', + render(): React.Node { + return ; + }, + }, { title: 'Padding', name: 'padding', @@ -1943,6 +1982,11 @@ const styles = StyleSheet.create({ wrappedText: { maxWidth: 300, }, + lineBreakSample: { + backgroundColor: '#eee', + fontSize: 16, + width: 150, + }, }); module.exports = { diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api index f0ce34575668..9985790cdecd 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidFrameworksCxx.api @@ -411,12 +411,14 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_ADJUST_ static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_ELLIPSIZE_MODE; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_HYPHENATION_FREQUENCY; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_INCLUDE_FONT_PADDING; +static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_LINE_BREAK; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_MAX_NUMBER_OF_LINES; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_MINIMUM_FONT_SCALE; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_MINIMUM_FONT_SIZE; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_TEXT_ALIGN_VERTICAL; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_TEXT_BREAK_STRATEGY; static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_TEXT_WIDTH_MODE; +static constexpr facebook::react::MapBuffer::Key facebook::react::PA_KEY_WORD_BREAK; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_ACCESSIBILITY_ROLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_ALIGNMENT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_ALIGNMENT_VERTICAL; @@ -800,6 +802,7 @@ std::string facebook::react::toString(const facebook::react::ImageResizeMode& va std::string facebook::react::toString(const facebook::react::ImageSource& value); std::string facebook::react::toString(const facebook::react::ImportantForAccessibility& importantForAccessibility); std::string facebook::react::toString(const facebook::react::LayoutDirection& layoutDirection); +std::string facebook::react::toString(const facebook::react::LineBreak& lineBreak); std::string facebook::react::toString(const facebook::react::LineBreakMode& lineBreakMode); std::string facebook::react::toString(const facebook::react::LineBreakStrategy& lineBreakStrategy); std::string facebook::react::toString(const facebook::react::Role& role); @@ -812,6 +815,7 @@ std::string facebook::react::toString(const facebook::react::TextDecorationLineT std::string facebook::react::toString(const facebook::react::TextDecorationStyle& textDecorationStyle); std::string facebook::react::toString(const facebook::react::TextTransform& textTransform); std::string facebook::react::toString(const facebook::react::TextWidthMode& textWidthMode); +std::string facebook::react::toString(const facebook::react::WordBreak& wordBreak); std::string facebook::react::toString(const facebook::react::WritingDirection& writingDirection); std::string facebook::react::toString(double doubleValue, char suffix); std::string facebook::react::toString(facebook::react::AccessibilityLiveRegion accessibilityLiveRegion); @@ -897,6 +901,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::FontWeight& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::HyphenationFrequency& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::ImportantForAccessibility& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreakStrategy& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::OutlineStyle& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::PointerEventsMode& result); @@ -913,6 +918,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TextTransform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::Transform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TransformOrigin& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WordBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WritingDirection& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Align& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Direction& result); @@ -3137,8 +3143,10 @@ class facebook::react::ParagraphAttributes : public facebook::react::DebugString public facebook::react::Float minimumFontScale; public facebook::react::Float minimumFontSize; public facebook::react::HyphenationFrequency android_hyphenationFrequency; + public facebook::react::LineBreak lineBreak; public facebook::react::TextBreakStrategy textBreakStrategy; public facebook::react::TextWidthMode textWidthMode; + public facebook::react::WordBreak wordBreak; public int maximumNumberOfLines; public std::optional textAlignVertical; } @@ -5116,6 +5124,13 @@ enum facebook::react::LayoutDirection { Undefined, } +enum facebook::react::LineBreak { + Auto, + Loose, + Normal, + Strict, +} + enum facebook::react::LineBreakMode : uint8_t { Char, Clip, @@ -5454,6 +5469,11 @@ enum facebook::react::UnitType { Undefined, } +enum facebook::react::WordBreak { + AutoPhrase, + Normal, +} + enum facebook::react::WritingDirection : uint8_t { LeftToRight, Natural, diff --git a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api index f1f68b19e566..229f338933ca 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleFrameworksCxx.api @@ -3575,6 +3575,7 @@ std::string facebook::react::toString(const facebook::react::ImageResizeMode& va std::string facebook::react::toString(const facebook::react::ImageSource& value); std::string facebook::react::toString(const facebook::react::ImportantForAccessibility& importantForAccessibility); std::string facebook::react::toString(const facebook::react::LayoutDirection& layoutDirection); +std::string facebook::react::toString(const facebook::react::LineBreak& lineBreak); std::string facebook::react::toString(const facebook::react::LineBreakMode& lineBreakMode); std::string facebook::react::toString(const facebook::react::LineBreakStrategy& lineBreakStrategy); std::string facebook::react::toString(const facebook::react::Role& role); @@ -3587,6 +3588,7 @@ std::string facebook::react::toString(const facebook::react::TextDecorationLineT std::string facebook::react::toString(const facebook::react::TextDecorationStyle& textDecorationStyle); std::string facebook::react::toString(const facebook::react::TextTransform& textTransform); std::string facebook::react::toString(const facebook::react::TextWidthMode& textWidthMode); +std::string facebook::react::toString(const facebook::react::WordBreak& wordBreak); std::string facebook::react::toString(const facebook::react::WritingDirection& writingDirection); std::string facebook::react::toString(double doubleValue, char suffix); std::string facebook::react::toString(facebook::react::AccessibilityLiveRegion accessibilityLiveRegion); @@ -3672,6 +3674,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::ImportantForAccessibility& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::KeyboardAppearance& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::KeyboardType& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreakStrategy& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::OutlineStyle& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::PointerEventsMode& result); @@ -3690,6 +3693,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TextTransform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::Transform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TransformOrigin& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WordBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WritingDirection& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Align& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Direction& result); @@ -5346,8 +5350,10 @@ class facebook::react::ParagraphAttributes : public facebook::react::DebugString public facebook::react::Float minimumFontScale; public facebook::react::Float minimumFontSize; public facebook::react::HyphenationFrequency android_hyphenationFrequency; + public facebook::react::LineBreak lineBreak; public facebook::react::TextBreakStrategy textBreakStrategy; public facebook::react::TextWidthMode textWidthMode; + public facebook::react::WordBreak wordBreak; public int maximumNumberOfLines; public std::optional textAlignVertical; } @@ -7274,6 +7280,13 @@ enum facebook::react::LayoutDirection { Undefined, } +enum facebook::react::LineBreak { + Auto, + Loose, + Normal, + Strict, +} + enum facebook::react::LineBreakMode : uint8_t { Char, Clip, @@ -7636,6 +7649,11 @@ enum facebook::react::UnitType { Undefined, } +enum facebook::react::WordBreak { + AutoPhrase, + Normal, +} + enum facebook::react::WritingDirection : uint8_t { LeftToRight, Natural, diff --git a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api index 085f78edc124..39b197d6a90f 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonFrameworksCxx.api @@ -375,6 +375,7 @@ std::string facebook::react::toString(const facebook::react::ImageResizeMode& va std::string facebook::react::toString(const facebook::react::ImageSource& value); std::string facebook::react::toString(const facebook::react::ImportantForAccessibility& importantForAccessibility); std::string facebook::react::toString(const facebook::react::LayoutDirection& layoutDirection); +std::string facebook::react::toString(const facebook::react::LineBreak& lineBreak); std::string facebook::react::toString(const facebook::react::LineBreakMode& lineBreakMode); std::string facebook::react::toString(const facebook::react::LineBreakStrategy& lineBreakStrategy); std::string facebook::react::toString(const facebook::react::Role& role); @@ -387,6 +388,7 @@ std::string facebook::react::toString(const facebook::react::TextDecorationLineT std::string facebook::react::toString(const facebook::react::TextDecorationStyle& textDecorationStyle); std::string facebook::react::toString(const facebook::react::TextTransform& textTransform); std::string facebook::react::toString(const facebook::react::TextWidthMode& textWidthMode); +std::string facebook::react::toString(const facebook::react::WordBreak& wordBreak); std::string facebook::react::toString(const facebook::react::WritingDirection& writingDirection); std::string facebook::react::toString(double doubleValue, char suffix); std::string facebook::react::toString(facebook::react::AccessibilityLiveRegion accessibilityLiveRegion); @@ -463,6 +465,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::FontWeight& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::HyphenationFrequency& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::ImportantForAccessibility& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::LineBreakStrategy& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::OutlineStyle& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::PointerEventsMode& result); @@ -479,6 +482,7 @@ void facebook::react::fromRawValue(const facebook::react::PropsParserContext& co void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TextTransform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::Transform& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::TransformOrigin& result); +void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WordBreak& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::react::WritingDirection& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Align& result); void facebook::react::fromRawValue(const facebook::react::PropsParserContext& context, const facebook::react::RawValue& value, facebook::yoga::Direction& result); @@ -1807,8 +1811,10 @@ class facebook::react::ParagraphAttributes : public facebook::react::DebugString public bool operator==(const facebook::react::ParagraphAttributes& rhs) const; public facebook::react::EllipsizeMode ellipsizeMode; public facebook::react::HyphenationFrequency android_hyphenationFrequency; + public facebook::react::LineBreak lineBreak; public facebook::react::TextBreakStrategy textBreakStrategy; public facebook::react::TextWidthMode textWidthMode; + public facebook::react::WordBreak wordBreak; public int maximumNumberOfLines; public std::optional textAlignVertical; } @@ -3513,6 +3519,13 @@ enum facebook::react::LayoutDirection { Undefined, } +enum facebook::react::LineBreak { + Auto, + Loose, + Normal, + Strict, +} + enum facebook::react::LineBreakMode : uint8_t { Char, Clip, @@ -3830,6 +3843,11 @@ enum facebook::react::UnitType { Undefined, } +enum facebook::react::WordBreak { + AutoPhrase, + Normal, +} + enum facebook::react::WritingDirection : uint8_t { LeftToRight, Natural,