diff --git a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index b0cf8dafd2d2..680ff7aa974b 100644 --- a/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/packages/react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -615,6 +615,7 @@ export type AndroidTextInputNativeProps = Readonly<{ includeFontPadding?: ?boolean, fontWeight?: ?string, fontFamily?: ?string, + fontVariationSettings?: ?string, /** * I cannot find where these are defined but JS complains without them. @@ -714,6 +715,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { includeFontPadding: true, fontWeight: true, fontFamily: true, + fontVariationSettings: true, allowFontScaling: true, onSelectionChange: true, mostRecentEventCount: true, diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index bb1e941b57af..68d4fa451f56 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -258,6 +258,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { fontSize: true, fontStyle: true, fontVariant: fontVariantAttribute, + fontVariationSettings: true, fontWeight: true, includeFontPadding: true, letterSpacing: true, diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index 80c004612b10..8e17f07e04fc 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -601,6 +601,12 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { | 'heavy' | 'black' | undefined; + /** + * Specifies OpenType font variation axis values using CSS syntax. An empty + * string resets inherited variation settings. On Android, this requires API + * level 26 or later. + */ + fontVariationSettings?: string | undefined; letterSpacing?: number | undefined; lineHeight?: number | undefined; textAlign?: diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js index c04cfe1c4b20..9df143c6efe1 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js @@ -1011,6 +1011,12 @@ type ____TextStyle_InternalBase = Readonly<{ */ fontWeight?: ____FontWeight_Internal, fontVariant?: ____FontVariantArray_Internal | string, + /** + * Specifies OpenType font variation axis values using CSS syntax. An empty + * string resets inherited variation settings. On Android, this requires API + * level 26 or later. + */ + fontVariationSettings?: string, textShadowOffset?: Readonly<{ width: number, height: number, diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index f69f43bce001..f05157f9262e 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -4543,6 +4543,7 @@ public final class com/facebook/react/uimanager/ViewProps { public static final field FONT_SIZE Ljava/lang/String; public static final field FONT_STYLE Ljava/lang/String; public static final field FONT_VARIANT Ljava/lang/String; + public static final field FONT_VARIATION_SETTINGS Ljava/lang/String; public static final field FONT_WEIGHT Ljava/lang/String; public static final field FOREGROUND_COLOR Ljava/lang/String; public static final field GAP Ljava/lang/String; @@ -6140,6 +6141,7 @@ public final class com/facebook/react/views/text/TextAttributeProps { public static final field TA_KEY_FONT_SIZE_MULTIPLIER I public static final field TA_KEY_FONT_STYLE I public static final field TA_KEY_FONT_VARIANT I + public static final field TA_KEY_FONT_VARIATION_SETTINGS I public static final field TA_KEY_FONT_WEIGHT I public static final field TA_KEY_FOREGROUND_COLOR I public static final field TA_KEY_IS_HIGHLIGHTED I @@ -6170,6 +6172,7 @@ public final class com/facebook/react/views/text/TextAttributeProps { public final fun getFontFeatureSettings ()Ljava/lang/String; public final fun getFontSize ()I public final fun getFontStyle ()I + public final fun getFontVariationSettings ()Ljava/lang/String; public final fun getFontWeight ()I public final fun getLayoutDirection ()I public final fun getLetterSpacing ()F @@ -6358,6 +6361,7 @@ public class com/facebook/react/views/textinput/ReactTextInputManager : com/face public final fun setFontSize (Lcom/facebook/react/views/textinput/ReactEditText;F)V public final fun setFontStyle (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V public final fun setFontVariant (Lcom/facebook/react/views/textinput/ReactEditText;Lcom/facebook/react/bridge/ReadableArray;)V + public final fun setFontVariationSettings (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V public final fun setFontWeight (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V public final fun setImportantForAutofill (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V public final fun setIncludeFontPadding (Lcom/facebook/react/views/textinput/ReactEditText;Z)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt index 23c4b0a97443..07d7e132e7d6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.kt @@ -84,6 +84,7 @@ public object ViewProps { public const val FONT_WEIGHT: String = "fontWeight" public const val FONT_STYLE: String = "fontStyle" public const val FONT_VARIANT: String = "fontVariant" + public const val FONT_VARIATION_SETTINGS: String = "fontVariationSettings" public const val FONT_FAMILY: String = "fontFamily" public const val LINE_HEIGHT: String = "lineHeight" public const val LETTER_SPACING: String = "letterSpacing" diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt index 71dc93dda720..df6eb1dd880f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTypefaceUtils.kt @@ -10,8 +10,11 @@ package com.facebook.react.views.text import android.content.Context import android.content.res.AssetManager import android.content.res.Configuration +import android.graphics.Paint import android.graphics.Typeface +import android.graphics.fonts.FontVariationAxis import android.os.Build +import com.facebook.common.logging.FLog import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.ReactConstants import com.facebook.react.common.assets.ReactFontManager @@ -151,4 +154,44 @@ public object ReactTypefaceUtils { return Typeface.create(baseTypeface, adjustedWeight, italic) } + + internal fun parseFontVariationSettings(fontVariationSettings: String?): String? { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return null + } + + if (fontVariationSettings.isNullOrEmpty()) { + return fontVariationSettings + } + + if (fontVariationSettings.trim().equals("normal", ignoreCase = true)) { + return "" + } + + return try { + FontVariationAxis.fromFontVariationSettings(fontVariationSettings) + fontVariationSettings + } catch (exception: IllegalArgumentException) { + FLog.w(ReactConstants.TAG, "Invalid fontVariationSettings: $fontVariationSettings") + null + } + } + + internal fun applyFontVariationSettings(paint: Paint, fontVariationSettings: String?) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return + } + + try { + paint.setFontVariationSettings(fontVariationSettings) + } catch (exception: IllegalArgumentException) { + // Paint instances are reused, so explicitly clear axes from a previous layout. + paint.setFontVariationSettings(null) + FLog.w( + ReactConstants.TAG, + "Invalid fontVariationSettings: $fontVariationSettings", + exception, + ) + } + } } 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 7ad338167d5e..4ebaa5630c09 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 @@ -25,6 +25,7 @@ import com.facebook.react.uimanager.ReactStylesDiffMap import com.facebook.react.uimanager.ViewProps import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariant +import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariationSettings import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight import kotlin.math.ceil @@ -153,6 +154,10 @@ public class TextAttributeProps private constructor() { public var fontFeatureSettings: String? = null private set + /** @see android.graphics.Paint.setFontVariationSettings */ + public var fontVariationSettings: String? = null + private set + @Deprecated("Use lineHeight instead", ReplaceWith("lineHeight")) public val effectiveLineHeight: Float get() = lineHeight @@ -396,6 +401,7 @@ public class TextAttributeProps private constructor() { public const val TA_KEY_TEXT_TRANSFORM: Int = 27 public const val TA_KEY_MAX_FONT_SIZE_MULTIPLIER: Int = 29 public const val TA_KEY_TEXT_EFFECTS: Int = 30 + public const val TA_KEY_FONT_VARIATION_SETTINGS: Int = 31 private const val TE_KEY_NAME: Int = 0 private const val TE_KEY_PROPS: Int = 1 @@ -433,6 +439,8 @@ public class TextAttributeProps private constructor() { TA_KEY_FONT_WEIGHT -> result.setFontWeight(entry.stringValue) TA_KEY_FONT_STYLE -> result.setFontStyle(entry.stringValue) TA_KEY_FONT_VARIANT -> result.setFontVariant(entry.mapBufferValue) + TA_KEY_FONT_VARIATION_SETTINGS -> + result.fontVariationSettings = parseFontVariationSettings(entry.stringValue) TA_KEY_ALLOW_FONT_SCALING -> result.allowFontScaling = entry.booleanValue TA_KEY_LETTER_SPACING -> result.letterSpacing = entry.doubleValue.toFloat() TA_KEY_LINE_HEIGHT -> result.lineHeight = entry.doubleValue.toFloat() @@ -500,6 +508,8 @@ public class TextAttributeProps private constructor() { result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT)) result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE)) result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT)) + result.fontVariationSettings = + parseFontVariationSettings(getStringProp(props, ViewProps.FONT_VARIATION_SETTINGS)) result.includeFontPadding = getBooleanProp(props, ViewProps.INCLUDE_FONT_PADDING, true) result.setTextDecorationLine(getStringProp(props, ViewProps.TEXT_DECORATION_LINE)) result.textDecorationColor = 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 e64f5de40759..5e0f6575c6dc 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 @@ -313,6 +313,7 @@ internal object TextLayoutManager { if ( textAttributes.fontStyle != ReactConstants.UNSET || textAttributes.fontWeight != ReactConstants.UNSET || + textAttributes.fontVariationSettings != null || textAttributes.fontFamily != null ) { ops.add( @@ -323,6 +324,7 @@ internal object TextLayoutManager { textAttributes.fontStyle, textAttributes.fontWeight, textAttributes.fontFeatureSettings, + textAttributes.fontVariationSettings, textAttributes.fontFamily, assets, fontWeightAdjustment, @@ -547,6 +549,7 @@ internal object TextLayoutManager { if ( fragment.props.fontStyle != ReactConstants.UNSET || fragment.props.fontWeight != ReactConstants.UNSET || + fragment.props.fontVariationSettings != null || fragment.props.fontFamily != null ) { spannable.setSpan( @@ -554,6 +557,7 @@ internal object TextLayoutManager { fragment.props.fontStyle, fragment.props.fontWeight, fragment.props.fontFeatureSettings, + fragment.props.fontVariationSettings, fragment.props.fontFamily, assets, fontWeightAdjustment, @@ -883,6 +887,7 @@ internal object TextLayoutManager { if ( baseTextAttributes.fontStyle != ReactConstants.UNSET || baseTextAttributes.fontWeight != ReactConstants.UNSET || + baseTextAttributes.fontVariationSettings != null || baseTextAttributes.fontFamily != null ) { val typeface = @@ -912,6 +917,8 @@ internal object TextLayoutManager { paint.setTypeface(typeface) } } + + ReactTypefaceUtils.applyFontVariationSettings(paint, baseTextAttributes.fontVariationSettings) } /** diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt index 29eb30f14470..a0607b012be6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/CustomStyleSpan.kt @@ -31,6 +31,7 @@ internal class CustomStyleSpan( private val privateStyle: Int, private val privateWeight: Int, val fontFeatureSettings: String?, + val fontVariationSettings: String?, val fontFamily: String?, private val assetManager: AssetManager, private val fontWeightAdjustment: Int = 0, @@ -41,6 +42,7 @@ internal class CustomStyleSpan( privateStyle, privateWeight, fontFeatureSettings, + fontVariationSettings, fontFamily, assetManager, fontWeightAdjustment, @@ -53,6 +55,7 @@ internal class CustomStyleSpan( privateStyle, privateWeight, fontFeatureSettings, + fontVariationSettings, fontFamily, assetManager, fontWeightAdjustment, @@ -81,6 +84,7 @@ internal class CustomStyleSpan( style: Int, weight: Int, fontFeatureSettingsParam: String?, + fontVariationSettingsParam: String?, family: String?, assetManager: AssetManager, fontWeightAdjustment: Int, @@ -92,6 +96,7 @@ internal class CustomStyleSpan( paint.apply { fontFeatureSettings = fontFeatureSettingsParam setTypeface(adjustedTypeface) + ReactTypefaceUtils.applyFontVariationSettings(this, fontVariationSettingsParam) isSubpixelText = true isLinearText = true } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index 50dea1239a40..9bb938f8b034 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -14,6 +14,7 @@ import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Rect +import android.graphics.Typeface import android.os.Build import android.os.Bundle import android.text.Editable @@ -47,6 +48,7 @@ import androidx.core.view.ViewCompat import com.facebook.common.logging.FLog import com.facebook.react.bridge.ReactSoftExceptionLogger.logSoftException import com.facebook.react.common.ReactConstants +import com.facebook.react.common.assets.ReactFontManager import com.facebook.react.common.build.ReactBuildConfig import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags @@ -73,6 +75,7 @@ import com.facebook.react.views.text.ReactTextUpdate import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles import com.facebook.react.views.text.ReactTypefaceUtils.getFontWeightAdjustment import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle +import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariationSettings import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight import com.facebook.react.views.text.TextAttributes import com.facebook.react.views.text.TextLayoutManager @@ -135,6 +138,9 @@ public open class ReactEditText public constructor(context: Context) : AppCompat private var fontFamily: String? = null private var fontWeight = ReactConstants.UNSET private var fontStyle = ReactConstants.UNSET + internal var parsedFontVariationSettings: String? = null + private set + private var autoFocus = false private var contextMenuHidden = false private var didAttachToWindow = false @@ -646,6 +652,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat } } + internal fun setReactFontVariationSettings(fontVariationSettings: String?) { + val newParsedFontVariationSettings = parseFontVariationSettings(fontVariationSettings) + if (newParsedFontVariationSettings != parsedFontVariationSettings) { + parsedFontVariationSettings = newParsedFontVariationSettings + typefaceDirty = true + } + } + override fun setFontFeatureSettings(fontFeatureSettings: String?) { if (fontFeatureSettings != getFontFeatureSettings()) { super.setFontFeatureSettings(fontFeatureSettings) @@ -662,6 +676,9 @@ public open class ReactEditText public constructor(context: Context) : AppCompat val newTypeface = applyStyles(typeface, fontStyle, fontWeight, fontFamily, context.assets) typeface = newTypeface + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + super.setFontVariationSettings(parsedFontVariationSettings) + } // Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything // nonstandard @@ -669,7 +686,8 @@ public open class ReactEditText public constructor(context: Context) : AppCompat fontStyle != ReactConstants.UNSET || fontWeight != ReactConstants.UNSET || fontFamily != null || - fontFeatureSettings != null + fontFeatureSettings != null || + parsedFontVariationSettings != null paintFlags = if (enableSubpixelText) { paintFlags or Paint.SUBPIXEL_TEXT_FLAG @@ -822,11 +840,16 @@ public open class ReactEditText public constructor(context: Context) : AppCompat span.spacing == textAttributes.effectiveLetterSpacing } + val effectiveFontStyle = if (fontStyle == ReactConstants.UNSET) Typeface.NORMAL else fontStyle + val effectiveFontWeight = + if (fontWeight == ReactConstants.UNSET) ReactFontManager.TypefaceStyle.NORMAL + else fontWeight stripSpansOfKind(sb, CustomStyleSpan::class.java) { span: CustomStyleSpan -> - span.style == fontStyle && + span.style == effectiveFontStyle && span.fontFamily == fontFamily && - span.weight == fontWeight && - span.fontFeatureSettings == fontFeatureSettings + span.weight == effectiveFontWeight && + span.fontFeatureSettings == fontFeatureSettings && + span.fontVariationSettings == parsedFontVariationSettings } } @@ -901,13 +924,15 @@ public open class ReactEditText public constructor(context: Context) : AppCompat fontStyle != ReactConstants.UNSET || fontWeight != ReactConstants.UNSET || fontFamily != null || - fontFeatureSettings != null + fontFeatureSettings != null || + parsedFontVariationSettings != null ) { workingText.setSpan( CustomStyleSpan( fontStyle, fontWeight, fontFeatureSettings, + parsedFontVariationSettings, fontFamily, context.assets, getFontWeightAdjustment(context), diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt index 0d58ffdb5ab7..2336b9ca35eb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt @@ -256,6 +256,11 @@ public open class ReactTextInputManager public constructor() : view.fontFeatureSettings = parseFontVariant(fontVariant) } + @ReactProp(name = ViewProps.FONT_VARIATION_SETTINGS) + public fun setFontVariationSettings(view: ReactEditText, fontVariationSettings: String?) { + view.setReactFontVariationSettings(fontVariationSettings) + } + @ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true) public fun setIncludeFontPadding(view: ReactEditText, includepad: Boolean) { view.includeFontPadding = includepad diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt index 0b63ff69a2a6..81d269ffd167 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextAttributePropsTest.kt @@ -9,12 +9,69 @@ package com.facebook.react.views.text import android.view.Gravity import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.uimanager.DisplayMetricsHolder import com.facebook.react.uimanager.ReactStylesDiffMap import org.assertj.core.api.Assertions.assertThat +import org.junit.After +import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +@RunWith(RobolectricTestRunner::class) class TextAttributePropsTest { + @Before + fun setUp() { + DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(RuntimeEnvironment.getApplication()) + } + + @After + fun tearDown() { + DisplayMetricsHolder.setScreenDisplayMetrics(null) + } + + @Test + fun readableMapSetsFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "'wght' 550")) + ) + + assertThat(textAttributes.fontVariationSettings).isEqualTo("'wght' 550") + } + + @Test + fun readableMapSetsDoubleQuotedFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "\"wght\" 450")) + ) + + assertThat(textAttributes.fontVariationSettings).isEqualTo("\"wght\" 450") + } + + @Test + fun readableMapIgnoresInvalidFontVariationSettings() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "invalid")) + ) + + assertThat(textAttributes.fontVariationSettings).isNull() + } + + @Test + fun readableMapTreatsNormalFontVariationSettingsAsExplicitReset() { + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "NoRmAl")) + ) + + assertThat(textAttributes.fontVariationSettings).isEmpty() + } + @Test fun textAlignStartUsesStartSide() { assertThat(textAlignment("start", isRTL = false)).isEqualTo(Gravity.LEFT) diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt index 3cc6751e6e0b..cfa95850489c 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/text/TextLayoutManagerFontWeightAdjustmentTest.kt @@ -7,19 +7,30 @@ package com.facebook.react.views.text +import android.graphics.Paint +import android.graphics.Typeface +import android.os.Build import android.text.TextPaint +import androidx.annotation.RequiresApi import com.facebook.react.bridge.JavaOnlyMap import com.facebook.react.uimanager.DisplayMetricsHolder import com.facebook.react.uimanager.ReactStylesDiffMap +import com.facebook.react.views.text.internal.span.CustomStyleSpan import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config +@RequiresApi(Build.VERSION_CODES.O) @RunWith(RobolectricTestRunner::class) @Config(sdk = [34]) class TextLayoutManagerFontWeightAdjustmentTest { @@ -64,6 +75,58 @@ class TextLayoutManagerFontWeightAdjustmentTest { assertThat(paint.typeface).isNull() } + @Test + fun `plain text paint ignores invalid font variation settings`() { + val paint = TextPaint(TextPaint.ANTI_ALIAS_FLAG) + val textAttributes = + TextAttributeProps.fromReadableMap( + ReactStylesDiffMap(JavaOnlyMap.of("fontVariationSettings", "invalid")) + ) + + TextLayoutManager.updateTextPaint( + paint, + textAttributes, + RuntimeEnvironment.getApplication().assets, + 0, + ) + + assertThat(paint.fontVariationSettings).isNull() + } + + @Test + fun `custom style applies font variation settings after high level font properties`() { + val paint = mock() + val span = CustomStyleSpan( + Typeface.NORMAL, + 700, + null, + "'wght' 450", + "sans-serif", + RuntimeEnvironment.getApplication().assets, + ) + + span.updateMeasureState(paint) + + inOrder(paint) { + verify(paint).setTypeface(any()) + verify(paint).setFontVariationSettings("'wght' 450") + } + } + + @Test + fun `invalid font variation settings defensively clear a reused paint`() { + val paint = mock() + val invalidSettings = "invalid-reused-paint-test" + whenever(paint.setFontVariationSettings(invalidSettings)).thenThrow(IllegalArgumentException()) + + ReactTypefaceUtils.applyFontVariationSettings(paint, "'wght' 700") + ReactTypefaceUtils.applyFontVariationSettings(paint, invalidSettings) + + verify(paint).setFontVariationSettings("'wght' 700") + verify(paint).setFontVariationSettings(invalidSettings) + verify(paint).setFontVariationSettings(null) + } + private companion object { const val FONT_WEIGHT_ADJUSTMENT_BOLD_TEXT = 300 } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt index f7078a7213e6..a776978e8d63 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt @@ -23,6 +23,7 @@ import android.util.DisplayMetrics import android.view.Gravity import android.view.View import android.view.inputmethod.EditorInfo +import androidx.annotation.RequiresApi import androidx.autofill.HintConstants import androidx.core.content.res.ResourcesCompat.ID_NULL import com.facebook.react.bridge.BridgeReactContext @@ -35,6 +36,7 @@ import com.facebook.react.uimanager.ReactStylesDiffMap import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.views.text.DefaultStyleValuesUtil.getDefaultTextColorHint import com.facebook.react.views.text.ReactTextUpdate +import com.facebook.react.views.text.internal.span.CustomStyleSpan import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test @@ -497,6 +499,98 @@ class ReactTextInputPropertyTest { assertThat(view.filters).isEqualTo(filters) } + @Test + fun testFontVariationSettings() { + manager.updateProperties(view, buildStyles("fontVariationSettings", "'wght' 550")) + assertThat(view.parsedFontVariationSettings).isEqualTo("'wght' 550") + + manager.updateProperties(view, buildStyles("fontVariationSettings", "invalid")) + assertThat(view.parsedFontVariationSettings).isNull() + + manager.updateProperties(view, buildStyles("fontVariationSettings", "normal")) + assertThat(view.parsedFontVariationSettings).isEmpty() + + manager.updateProperties(view, buildStyles("fontVariationSettings", "")) + assertThat(view.parsedFontVariationSettings).isEmpty() + + manager.updateProperties(view, buildStyles("fontVariationSettings", null)) + assertThat(view.parsedFontVariationSettings).isNull() + } + + @Test + fun testFontVariationSettingsOverrideFontWeightRegardlessOfPropOrder() { + manager.updateProperties( + view, + buildStyles( + "fontVariationSettings", + "'wght' 450", + "fontWeight", + "700", + ), + ) + assertThat(view.parsedFontVariationSettings).isEqualTo("'wght' 450") + + manager.updateProperties( + view, + buildStyles( + "fontWeight", + "300", + "fontVariationSettings", + "'wght' 550", + ), + ) + assertThat(view.parsedFontVariationSettings).isEqualTo("'wght' 550") + } + + @RequiresApi(Build.VERSION_CODES.M) + @Test + fun testFontVariationSettingsStripOnlyEquivalentSpans() { + manager.updateProperties( + view, + buildStyles( + "fontFamily", + "sans-serif", + "fontVariationSettings", + "'wght' 550", + ), + ) + val matchingSpan = CustomStyleSpan( + 0, + 400, + view.fontFeatureSettings, + "'wght' 550", + "sans-serif", + themedContext.assets, + ) + val differingSpan = CustomStyleSpan( + 0, + 400, + view.fontFeatureSettings, + "'wght' 700", + "sans-serif", + themedContext.assets, + ) + val textUpdate = + SpannableString("matching different").apply { + setSpan(matchingSpan, 0, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + setSpan(differingSpan, 9, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + } + + view.maybeSetTextFromState( + ReactTextUpdate( + textUpdate, + 0, + view.gravity and Gravity.HORIZONTAL_GRAVITY_MASK, + Layout.BREAK_STRATEGY_HIGH_QUALITY, + 0, + ) + ) + + val remainingSpans = + checkNotNull(view.text).getSpans(0, view.length(), CustomStyleSpan::class.java) + assertThat(remainingSpans).containsExactly(differingSpan) + } + @Test fun testSecureTextDoesNotReplaceSameTextFromJS() { val markerSpan = MarkerSpan() diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index be2e1a2d481b..5851ec21dfff 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -43,6 +43,9 @@ void TextAttributes::apply(TextAttributes textAttributes) { fontVariant = textAttributes.fontVariant.has_value() ? textAttributes.fontVariant : fontVariant; + fontVariationSettings = textAttributes.fontVariationSettings.has_value() + ? textAttributes.fontVariationSettings + : fontVariationSettings; allowFontScaling = textAttributes.allowFontScaling.has_value() ? textAttributes.allowFontScaling : allowFontScaling; @@ -128,6 +131,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { fontWeight, fontStyle, fontVariant, + fontVariationSettings, allowFontScaling, dynamicTypeRamp, alignment, @@ -152,6 +156,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { rhs.fontWeight, rhs.fontStyle, rhs.fontVariant, + rhs.fontVariationSettings, rhs.allowFontScaling, rhs.dynamicTypeRamp, rhs.alignment, @@ -218,6 +223,10 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { "fontStyle", fontStyle, textAttributes.fontStyle), debugStringConvertibleItem( "fontVariant", fontVariant, textAttributes.fontVariant), + debugStringConvertibleItem( + "fontVariationSettings", + fontVariationSettings, + textAttributes.fontVariationSettings), debugStringConvertibleItem( "allowFontScaling", allowFontScaling, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h index c162deee2f73..683c993bf968 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h @@ -58,6 +58,7 @@ class TextAttributes : public DebugStringConvertible { std::optional fontWeight{}; std::optional fontStyle{}; std::optional fontVariant{}; + std::optional fontVariationSettings{}; std::optional allowFontScaling{}; Float maxFontSizeMultiplier{std::numeric_limits::quiet_NaN()}; std::optional dynamicTypeRamp{}; @@ -143,6 +144,7 @@ struct hash { textAttributes.fontWeight, textAttributes.fontStyle, textAttributes.fontVariant, + textAttributes.fontVariationSettings, textAttributes.allowFontScaling, textAttributes.letterSpacing, textAttributes.textTransform, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h index 235e966ae131..beed96737801 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h @@ -1142,6 +1142,7 @@ constexpr static MapBuffer::Key TA_KEY_TEXT_TRANSFORM = 27; constexpr static MapBuffer::Key TA_KEY_ALIGNMENT_VERTICAL = 28; constexpr static MapBuffer::Key TA_KEY_MAX_FONT_SIZE_MULTIPLIER = 29; constexpr static MapBuffer::Key TA_KEY_TEXT_EFFECTS = 30; +constexpr static MapBuffer::Key TA_KEY_FONT_VARIATION_SETTINGS = 31; // Keys within each text effect entry MapBuffer constexpr static MapBuffer::Key TE_KEY_NAME = 0; @@ -1290,6 +1291,9 @@ inline MapBuffer toMapBuffer(const TextAttributes &textAttributes) auto fontVariantMap = toMapBuffer(*textAttributes.fontVariant); builder.putMapBuffer(TA_KEY_FONT_VARIANT, fontVariantMap); } + if (textAttributes.fontVariationSettings.has_value()) { + builder.putString(TA_KEY_FONT_VARIATION_SETTINGS, *textAttributes.fontVariationSettings); + } if (textAttributes.allowFontScaling.has_value()) { builder.putBool(TA_KEY_ALLOW_FONT_SCALING, *textAttributes.allowFontScaling); } diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp index 51fd245e4209..135463aa2d09 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp @@ -67,6 +67,12 @@ static TextAttributes convertRawProp( "fontVariant", sourceTextAttributes.fontVariant, defaultTextAttributes.fontVariant); + textAttributes.fontVariationSettings = convertRawProp( + context, + rawProps, + "fontVariationSettings", + sourceTextAttributes.fontVariationSettings, + defaultTextAttributes.fontVariationSettings); textAttributes.allowFontScaling = convertRawProp( context, rawProps, @@ -261,6 +267,12 @@ void BaseTextProps::setProp( defaults, value, textAttributes, fontStyle, "fontStyle"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, fontVariant, "fontVariant"); + REBUILD_FIELD_SWITCH_CASE( + defaults, + value, + textAttributes, + fontVariationSettings, + "fontVariationSettings"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, allowFontScaling, "allowFontScaling"); REBUILD_FIELD_SWITCH_CASE( @@ -393,6 +405,14 @@ void BaseTextProps::appendTextAttributesProps( : folly::dynamic(nullptr); } + if (textAttributes.fontVariationSettings != + oldProps->textAttributes.fontVariationSettings) { + result["fontVariationSettings"] = + textAttributes.fontVariationSettings.has_value() + ? folly::dynamic(*textAttributes.fontVariationSettings) + : folly::dynamic(nullptr); + } + if (textAttributes.allowFontScaling != oldProps->textAttributes.allowFontScaling) { result["allowFontScaling"] = textAttributes.allowFontScaling.has_value() diff --git a/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp b/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp index 560f2e661e84..0d4ad930c520 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/tests/BaseTextShadowNodeTest.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,43 @@ std::string roundTripTextAlignment(const char* textAlignment) { return toString(result); } +TextAttributes nestedTextAttributes( + const std::shared_ptr& parentProps, + const std::shared_ptr& childProps) { + auto builder = simpleComponentBuilder(); + auto shadowNode = builder.build( + Element().children({ + Element() + .props(parentProps) + .children({ + Element() + .props(childProps) + .children({rawTextElement("Text")}), + }), + })); + + auto baseTextAttributes = TextAttributes::defaultTextAttributes(); + AttributedString output; + BaseTextShadowNode::Attachments attachments; + BaseTextShadowNode::buildAttributedString( + baseTextAttributes, *shadowNode, output, attachments); + + EXPECT_EQ(output.getFragments().size(), 1); + return output.getFragments()[0].textAttributes; +} + +std::shared_ptr textPropsWithRawFontVariationSettings( + const char* fontVariationSettings) { + ContextContainer contextContainer{}; + PropsParserContext parserContext{-1, contextContainer}; + auto rawProps = RawProps( + folly::dynamic::object("fontVariationSettings", fontVariationSettings)); + auto rawPropsParser = RawPropsParser{}; + rawPropsParser.prepare(); + rawProps.parse(rawPropsParser); + return std::make_shared(parserContext, TextProps{}, rawProps); +} + } // namespace TEST(BaseTextShadowNodeTest, textAlignmentStartAndEndRoundTrip) { @@ -107,4 +145,38 @@ TEST(BaseTextShadowNodeTest, rawTextIsMerged) { EXPECT_EQ(output.getFragments().size(), 1); } +TEST(BaseTextShadowNodeTest, childInheritsParentFontVariationSettings) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650"; + auto childProps = std::make_shared(); + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontVariationSettings, "'wght' 650"); +} + +TEST(BaseTextShadowNodeTest, childFontVariationSettingsReplaceParentList) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650, 'wdth' 90"; + auto childProps = textPropsWithRawFontVariationSettings("'wdth' 110"); + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontVariationSettings, "'wdth' 110"); +} + +TEST( + BaseTextShadowNodeTest, + childFontWeightCoexistsWithInheritedFontVariationSettings) { + auto parentProps = std::make_shared(); + parentProps->textAttributes.fontVariationSettings = "'wght' 650"; + auto childProps = std::make_shared(); + childProps->textAttributes.fontWeight = FontWeight::Weight400; + + const auto attributes = nestedTextAttributes(parentProps, childProps); + + EXPECT_EQ(attributes.fontWeight, FontWeight::Weight400); + EXPECT_EQ(attributes.fontVariationSettings, "'wght' 650"); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp index 00cefce0d1fd..4c145e7beeee 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp @@ -323,6 +323,10 @@ folly::dynamic AndroidTextInputProps::getDynamic() const { props["includeFontPadding"] = includeFontPadding; props["fontWeight"] = fontWeight; props["fontFamily"] = fontFamily; + props["fontVariationSettings"] = + textAttributes.fontVariationSettings.has_value() + ? folly::dynamic(*textAttributes.fontVariationSettings) + : folly::dynamic(nullptr); props["cursorColor"] = toAndroidRepr(cursorColor); props["mostRecentEventCount"] = mostRecentEventCount; props["text"] = text; @@ -622,6 +626,14 @@ folly::dynamic AndroidTextInputProps::getDiffProps( result["fontFamily"] = fontFamily; } + if (textAttributes.fontVariationSettings != + oldProps->textAttributes.fontVariationSettings) { + result["fontVariationSettings"] = + textAttributes.fontVariationSettings.has_value() + ? folly::dynamic(*textAttributes.fontVariationSettings) + : folly::dynamic(nullptr); + } + return result; } diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h index f062132f2741..e302e5f7dded 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextMeasureCache.h @@ -125,6 +125,7 @@ inline bool areTextAttributesEquivalentLayoutWise(const TextAttributes &lhs, con lhs.fontWeight, lhs.fontStyle, lhs.fontVariant, + lhs.fontVariationSettings, lhs.allowFontScaling, lhs.dynamicTypeRamp, lhs.alignment) == @@ -133,6 +134,7 @@ inline bool areTextAttributesEquivalentLayoutWise(const TextAttributes &lhs, con rhs.fontWeight, rhs.fontStyle, rhs.fontVariant, + rhs.fontVariationSettings, rhs.allowFontScaling, rhs.dynamicTypeRamp, rhs.alignment) && @@ -152,6 +154,7 @@ inline size_t textAttributesHashLayoutWise(const TextAttributes &textAttributes) textAttributes.fontWeight, textAttributes.fontStyle, textAttributes.fontVariant, + textAttributes.fontVariationSettings, textAttributes.allowFontScaling, textAttributes.maxFontSizeMultiplier, textAttributes.dynamicTypeRamp, diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp index d19545a83f67..3b687657917b 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/tests/TextLayoutManagerTest.cpp @@ -48,6 +48,39 @@ TEST(TextLayoutManagerTest, maxFontSizeMultiplierAffectsLayoutCacheHash) { textAttributesHashLayoutWise(lhs), textAttributesHashLayoutWise(rhs)); } +TEST(TextLayoutManagerTest, fontVariationSettingsAffectLayoutCacheEquality) { + TextAttributes lhs; + TextAttributes rhs; + + lhs.fontVariationSettings = "'wght' 400"; + rhs.fontVariationSettings = "'wght' 700"; + + EXPECT_FALSE(areTextAttributesEquivalentLayoutWise(lhs, rhs)); +} + +TEST(TextLayoutManagerTest, fontVariationSettingsAffectLayoutCacheHash) { + TextAttributes lhs; + TextAttributes rhs; + + lhs.fontVariationSettings = "'wght' 400"; + rhs.fontVariationSettings = "'wght' 700"; + + EXPECT_NE( + textAttributesHashLayoutWise(lhs), textAttributesHashLayoutWise(rhs)); +} + +TEST(TextLayoutManagerTest, emptyFontVariationSettingsClearInheritedSettings) { + TextAttributes parent; + TextAttributes child; + + parent.fontVariationSettings = "'wght' 700"; + child.fontVariationSettings = ""; + parent.apply(child); + + EXPECT_TRUE(parent.fontVariationSettings.has_value()); + EXPECT_TRUE(parent.fontVariationSettings->empty()); +} + // Measurements are rounded to the pixel grid, so a measurement cached at one // pixel scale factor must not satisfy a lookup at another. Keys that differ // only by pointScaleFactor must compare unequal. diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 24f632825a84..b895f37a3ff0 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<> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -744,6 +744,7 @@ declare type ____TextStyle_InternalBase = { readonly fontSize?: number readonly fontStyle?: "italic" | "normal" readonly fontVariant?: ____FontVariantArray_Internal | string + readonly fontVariationSettings?: string readonly fontWeight?: ____FontWeight_Internal readonly includeFontPadding?: boolean readonly letterSpacing?: number @@ -5714,7 +5715,7 @@ export { AlertOptions, // 8a116d2a AlertType, // 5ab91217 AndroidKeyboardEvent, // e03becc8 - Animated, // 50cbe576 + Animated, // 4bf77b70 AppConfig, // 35c0ca70 AppRegistry, // 1e8c5a00 AppState, // 12012be5 @@ -5937,7 +5938,7 @@ export { StatusBarProps, // c2a44d88 StatusBarStyle, // 78f53eea StyleProp, // fa0e9b4a - StyleSheet, // e734acd4 + StyleSheet, // 3c21ec63 SubmitBehavior, // c4ddf490 Switch, // f495bab3 SwitchChangeEvent, // 899635b1 @@ -5947,9 +5948,9 @@ export { TVViewPropsIOS, // 330ce7b5 TargetedEvent, // 16e98910 TaskProvider, // 266dedf2 - Text, // 9ceaff08 + Text, // 09e783b9 TextContentType, // 239b3ecc - TextInput, // ce1e41ff + TextInput, // a2cc82d1 TextInputAndroidProps, // 9ebbc103 TextInputBlurEvent, // b77af40e TextInputChangeEvent, // f55eef98 @@ -5959,13 +5960,13 @@ export { TextInputIOSProps, // fb3c9327 TextInputInstance, // 5a0c0e0d TextInputKeyPressEvent, // 546c5d07 - TextInputProps, // c692f4de + TextInputProps, // dd91ebaa TextInputSelectionChangeEvent, // e58f2abc TextInputSubmitEditingEvent, // 6bcb2aa5 TextInstance, // 05463a96 TextLayoutEvent, // 3f54186f - TextProps, // 93309fac - TextStyle, // b62b8399 + TextProps, // 4a122c2b + TextStyle, // 6ad4307f ToastAndroid, // 88a8969a TouchableHighlight, // 3a6eaed4 TouchableHighlightInstance, // b510c0eb diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index dff12a0398b3..c46ce0ae25dc 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -5011,6 +5012,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index bae821b61ec2..9aaf7be6052a 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -4822,6 +4823,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index beb96517ca4e..2dcd7df641bf 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -523,6 +523,7 @@ static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SI static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_SIZE_MULTIPLIER; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_STYLE; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIANT; +static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_VARIATION_SETTINGS; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FONT_WEIGHT; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_FOREGROUND_COLOR; static constexpr facebook::react::MapBuffer::Key facebook::react::TA_KEY_IS_HIGHLIGHTED; @@ -5002,6 +5003,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index c27595d7f77a..08edbf9b8886 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -7202,6 +7202,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index c8a738e9069d..381fe9367c80 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -7041,6 +7041,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index 3d09b6d29173..fe6bc0e042b4 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -7193,6 +7193,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 0c7d0a5b8a1c..82f34060bfaf 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -3525,6 +3525,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api index 4b6b80e8c2b8..26ed4473aab4 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api @@ -3376,6 +3376,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes); diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index a0e1c10862b6..ec7d627bb4e2 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -3516,6 +3516,7 @@ class facebook::react::TextAttributes : public facebook::react::DebugStringConve public std::optional textDecorationStyle; public std::optional textTransform; public std::optional baseWritingDirection; + public std::optional fontVariationSettings; public std::string fontFamily; public std::vector textEffects; public void apply(facebook::react::TextAttributes textAttributes);