diff --git a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js index 0a73eb53c847..b69b350e99e4 100644 --- a/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/packages/react-native/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -159,6 +159,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { */ color: colorAttributes, fontFamily: true, + fontVariationSettings: true, fontSize: true, fontStyle: true, fontVariant: {process: processFontVariant}, diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index 9ef13a7bd74f..82ba6ecec7cf 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -330,6 +330,7 @@ export interface TextStyleAndroid extends ViewStyle { export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { color?: ColorValue | undefined; fontFamily?: string | undefined; + fontVariationSettings?: string | undefined; fontSize?: number | undefined; fontStyle?: 'normal' | 'italic' | undefined; /** diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js index de54f8235f5e..ce69e28e1244 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js @@ -834,6 +834,7 @@ export type ____TextStyle_InternalCore = $ReadOnly<{ ...$Exact<____ViewStyle_Internal>, color?: ____ColorValue_Internal, fontFamily?: string, + fontVariationSettings?: string, fontSize?: number, fontStyle?: 'normal' | 'italic', fontWeight?: ____FontWeight_Internal, diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 58e73cf5d904..1da8f7b145b1 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -7819,6 +7819,7 @@ export type ____TextStyle_InternalCore = $ReadOnly<{ ...$Exact<____ViewStyle_Internal>, color?: ____ColorValue_Internal, fontFamily?: string, + fontVariationSettings?: string, fontSize?: number, fontStyle?: \\"normal\\" | \\"italic\\", fontWeight?: ____FontWeight_Internal, 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 5b6c2bef0d6d..257a1a60b984 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 @@ -81,6 +81,7 @@ public object ViewProps { public const val FONT_STYLE: String = "fontStyle" public const val FONT_VARIANT: String = "fontVariant" public const val FONT_FAMILY: String = "fontFamily" + public const val FONT_VARIATION_SETTINGS: String = "fontVariationSettings"; public const val LINE_HEIGHT: String = "lineHeight" public const val LETTER_SPACING: String = "letterSpacing" public const val NEEDS_OFFSCREEN_ALPHA_COMPOSITING: String = "needsOffscreenAlphaCompositing" diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java index 6cb16d00028d..3fe093549c0c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java @@ -193,6 +193,7 @@ private static void buildSpannedFromShadowNode( } if (textShadowNode.mFontStyle != ReactConstants.UNSET || textShadowNode.mFontWeight != ReactConstants.UNSET + || textShadowNode.mFontVariationSettings != null || textShadowNode.mFontFamily != null) { ops.add( new SetSpanOperation( @@ -203,6 +204,7 @@ private static void buildSpannedFromShadowNode( textShadowNode.mFontWeight, textShadowNode.mFontFeatureSettings, textShadowNode.mFontFamily, + textShadowNode.mFontVariationSettings, textShadowNode.getThemedContext().getAssets()))); } if (textShadowNode.mIsUnderlineTextDecorationSet) { @@ -348,6 +350,11 @@ protected Spannable spannedFromShadowNode( protected int mFontWeight = ReactConstants.UNSET; + /** + * mFontVariationSettings can be used for variable font features e.g: 'wght' 850 + */ + protected String mFontVariationSettings; + /** * NB: If a font family is used that does not have a style in a certain Android version (ie. * monospace bold pre Android 5.0), that style (ie. bold) will not be inherited by nested Text @@ -525,6 +532,12 @@ public void setFontWeight(@Nullable String fontWeightString) { } } + @ReactProp(name = ViewProps.FONT_VARIATION_SETTINGS) + public void setFontVariationSettings(@Nullable String fontVariationSettings) { + mFontVariationSettings = fontVariationSettings; + markUpdated(); + } + @ReactProp(name = ViewProps.FONT_VARIANT) public void setFontVariant(@Nullable ReadableArray fontVariantArray) { String fontFeatureSettings = ReactTypefaceUtils.parseFontVariant(fontVariantArray); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java index f5dc16e69bd8..1fadf7780cc5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextAttributeProps.java @@ -61,6 +61,8 @@ public class TextAttributeProps { public static final short TA_KEY_LINE_BREAK_STRATEGY = 25; public static final short TA_KEY_ROLE = 26; public static final short TA_KEY_TEXT_TRANSFORM = 27; + public static final short TA_KEY_ALIGNMENT_VERTICAL = 28; + public static final short TA_KEY_FONT_VARIATION_SETTINGS = 29; public static final int UNSET = -1; @@ -135,6 +137,12 @@ public class TextAttributeProps { */ protected @Nullable String mFontFamily = null; + /** + * mFontVariationSettings can be used for variable font features e.g: 'wght' 850 + * This works for Android 8.1 and above. + */ + protected @Nullable String mFontVariationSettings = null; + /** * @see android.graphics.Paint#setFontFeatureSettings */ @@ -225,6 +233,9 @@ public static TextAttributeProps fromMapBuffer(MapBuffer props) { case TA_KEY_TEXT_TRANSFORM: result.setTextTransform(entry.getStringValue()); break; + case TA_KEY_FONT_VARIATION_SETTINGS: + result.setFontVariationSettings(entry.getStringValue()); + break; } } @@ -252,6 +263,7 @@ public static TextAttributeProps fromReadableMap(ReactStylesDiffMap props) { ? props.getInt(ViewProps.BACKGROUND_COLOR, 0) : null); result.setFontFamily(getStringProp(props, ViewProps.FONT_FAMILY)); + result.setFontVariationSettings(getStringProp(props, ViewProps.FONT_VARIATION_SETTINGS)); result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT)); result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE)); result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT)); @@ -465,10 +477,18 @@ public String getFontFamily() { return mFontFamily; } + public String getFontVariationSettings() { + return mFontVariationSettings; + } + private void setFontFamily(@Nullable String fontFamily) { mFontFamily = fontFamily; } + private void setFontVariationSettings(String fontVariationSettings) { + mFontVariationSettings = fontVariationSettings; + } + private void setFontVariant(@Nullable ReadableArray fontVariant) { mFontFeatureSettings = ReactTypefaceUtils.parseFontVariant(fontVariant); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index 2921f84140d1..0f8585a3137f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -249,6 +249,7 @@ private static void buildSpannableFromFragments( new SetSpanOperation(start, end, new ReactAbsoluteSizeSpan(textAttributes.mFontSize))); if (textAttributes.mFontStyle != ReactConstants.UNSET || textAttributes.mFontWeight != ReactConstants.UNSET + || textAttributes.mFontVariationSettings != null || textAttributes.mFontFamily != null) { ops.add( new SetSpanOperation( @@ -259,6 +260,7 @@ private static void buildSpannableFromFragments( textAttributes.mFontWeight, textAttributes.mFontFeatureSettings, textAttributes.mFontFamily, + textAttributes.mFontVariationSettings, context.getAssets()))); } if (textAttributes.mIsUnderlineTextDecorationSet) { 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 81bb303e6a30..738e9ff5bd04 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 @@ -10,6 +10,7 @@ package com.facebook.react.views.text.internal.span import android.content.res.AssetManager import android.graphics.Paint import android.graphics.Typeface +import android.os.Build import android.text.TextPaint import android.text.style.MetricAffectingSpan import com.facebook.react.common.ReactConstants @@ -32,14 +33,15 @@ public class CustomStyleSpan( private val privateWeight: Int, public val fontFeatureSettings: String?, public val fontFamily: String?, + public val fontVariationSettings: String?, private val assetManager: AssetManager ) : MetricAffectingSpan(), ReactSpan { public override fun updateDrawState(ds: TextPaint) { - apply(ds, privateStyle, privateWeight, fontFeatureSettings, fontFamily, assetManager) + apply(ds, privateStyle, privateWeight, fontFeatureSettings, fontFamily, fontVariationSettings, assetManager) } public override fun updateMeasureState(paint: TextPaint) { - apply(paint, privateStyle, privateWeight, fontFeatureSettings, fontFamily, assetManager) + apply(paint, privateStyle, privateWeight, fontFeatureSettings, fontFamily, fontVariationSettings, assetManager) } public val style: Int @@ -59,12 +61,14 @@ public class CustomStyleSpan( } public companion object { + private val TAG = CustomStyleSpan::class.simpleName private fun apply( paint: Paint, style: Int, weight: Int, fontFeatureSettingsParam: String?, family: String?, + fontVariationSettingsParam: String?, assetManager: AssetManager ) { val typeface = @@ -72,6 +76,13 @@ public class CustomStyleSpan( paint.apply { fontFeatureSettings = fontFeatureSettingsParam setTypeface(typeface) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + try { + fontVariationSettings = fontVariationSettingsParam + } catch (e: IllegalArgumentException) { + // Do nothing + } + } isSubpixelText = true } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index 014e0b489dd3..e7da1b969ab1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -39,6 +39,8 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.widget.TextView; + import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatEditText; import androidx.core.util.Predicate; @@ -527,7 +529,7 @@ public void setInputType(int type) { /** * If set forces multiline on input, because of a restriction on Android source that enables * multiline only for inputs of type Text and Multiline on method {@link - * android.widget.TextView#isMultilineInputType(int)}} Source: {@Link TextView.java} */ if (isMultiline()) { @@ -598,6 +600,7 @@ public void maybeUpdateTypeface() { if (mFontStyle != ReactConstants.UNSET || mFontWeight != ReactConstants.UNSET || mFontFamily != null + || getFontVariationSettingsInternal() != null || getFontFeatureSettings() != null) { setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); } else { @@ -771,10 +774,20 @@ private void stripStyleEquivalentSpans(SpannableStringBuilder sb) { return span.getStyle() == mFontStyle && Objects.equals(span.getFontFamily(), mFontFamily) && span.getWeight() == mFontWeight + && Objects.equals(span.getFontVariationSettings(), getFontVariationSettingsInternal()) && Objects.equals(span.getFontFeatureSettings(), getFontFeatureSettings()); }); } + // Font variation settings is only available on API 26+, we return null if not available + private @Nullable String getFontVariationSettingsInternal() { + String fontVariationSettings = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + fontVariationSettings = super.getFontVariationSettings(); + } + return fontVariationSettings; + } + private void stripSpansOfKind( SpannableStringBuilder sb, Class clazz, Predicate shouldStrip) { T[] spans = sb.getSpans(0, sb.length(), clazz); @@ -829,6 +842,7 @@ private void addSpansFromStyleAttributes(SpannableStringBuilder workingText) { if (mFontStyle != ReactConstants.UNSET || mFontWeight != ReactConstants.UNSET || mFontFamily != null + || getFontVariationSettingsInternal() != null || getFontFeatureSettings() != null) { workingText.setSpan( new CustomStyleSpan( @@ -836,6 +850,7 @@ private void addSpansFromStyleAttributes(SpannableStringBuilder workingText) { mFontWeight, getFontFeatureSettings(), mFontFamily, + getFontVariationSettingsInternal(), getContext().getAssets()), 0, workingText.length(), diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 2c225da15548..5e936667580f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -389,6 +389,11 @@ public void setFontFamily(ReactEditText view, String fontFamily) { view.setFontFamily(fontFamily); } + @ReactProp(name = ViewProps.FONT_VARIATION_SETTINGS) + public void setFontVariationSettings(ReactEditText view, String fontVariationSettings) { + view.setFontVariationSettings(fontVariationSettings); + } + @ReactProp(name = ViewProps.MAX_FONT_SIZE_MULTIPLIER, defaultFloat = Float.NaN) public void setMaxFontSizeMultiplier(ReactEditText view, float maxFontSizeMultiplier) { view.setMaxFontSizeMultiplier(maxFontSizeMultiplier); diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index cd32048480f5..3a9c8fdb2632 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -31,6 +31,8 @@ void TextAttributes::apply(TextAttributes textAttributes) { // Font fontFamily = !textAttributes.fontFamily.empty() ? textAttributes.fontFamily : fontFamily; + fontVariationSettings = !textAttributes.fontVariationSettings.empty() ? textAttributes.fontVariationSettings + : fontVariationSettings; fontSize = !std::isnan(textAttributes.fontSize) ? textAttributes.fontSize : fontSize; fontSizeMultiplier = !std::isnan(textAttributes.fontSizeMultiplier) @@ -121,6 +123,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { foregroundColor, backgroundColor, fontFamily, + fontVariationSettings, fontWeight, fontStyle, fontVariant, @@ -145,6 +148,7 @@ bool TextAttributes::operator==(const TextAttributes& rhs) const { rhs.foregroundColor, rhs.backgroundColor, rhs.fontFamily, + rhs.fontVariationSettings, rhs.fontWeight, rhs.fontStyle, rhs.fontVariant, @@ -202,6 +206,7 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { // Font debugStringConvertibleItem("fontFamily", fontFamily), + debugStringConvertibleItem("fontVariationSettings", fontVariationSettings), debugStringConvertibleItem("fontSize", fontSize), debugStringConvertibleItem("fontSizeMultiplier", fontSizeMultiplier), debugStringConvertibleItem("fontWeight", fontWeight), diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h index c8ff0cbd40a4..39b50ec6a979 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/TextAttributes.h @@ -45,6 +45,7 @@ class TextAttributes : public DebugStringConvertible { // Font std::string fontFamily{""}; + std::string fontVariationSettings{""}; Float fontSize{std::numeric_limits::quiet_NaN()}; Float fontSizeMultiplier{std::numeric_limits::quiet_NaN()}; std::optional fontWeight{}; @@ -115,6 +116,7 @@ struct hash { textAttributes.backgroundColor, textAttributes.opacity, textAttributes.fontFamily, + textAttributes.fontVariationSettings, textAttributes.fontSize, textAttributes.fontSizeMultiplier, textAttributes.fontWeight, diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h index a975fe080d9b..8eab9239aa9b 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/conversions.h @@ -856,6 +856,7 @@ constexpr static MapBuffer::Key TA_KEY_LINE_BREAK_STRATEGY = 25; constexpr static MapBuffer::Key TA_KEY_ROLE = 26; constexpr static MapBuffer::Key TA_KEY_TEXT_TRANSFORM = 27; constexpr static MapBuffer::Key TA_KEY_ALIGNMENT_VERTICAL = 28; +constexpr static MapBuffer::Key TA_KEY_FONT_VARIATION_SETTINGS = 29; // constants for ParagraphAttributes serialization constexpr static MapBuffer::Key PA_KEY_MAX_NUMBER_OF_LINES = 0; @@ -929,6 +930,9 @@ inline MapBuffer toMapBuffer(const TextAttributes& textAttributes) { if (!textAttributes.fontFamily.empty()) { builder.putString(TA_KEY_FONT_FAMILY, textAttributes.fontFamily); } + if (!textAttributes.fontVariationSettings.empty()) { + builder.putString(TA_KEY_FONT_VARIATION_SETTINGS, textAttributes.fontVariationSettings); + } if (!std::isnan(textAttributes.fontSize)) { builder.putDouble(TA_KEY_FONT_SIZE, textAttributes.fontSize); } 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 2dfe49020d2e..93fe9c6da7d2 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/text/BaseTextProps.cpp @@ -37,6 +37,12 @@ static TextAttributes convertRawProp( "fontFamily", sourceTextAttributes.fontFamily, defaultTextAttributes.fontFamily); + textAttributes.fontVariationSettings = convertRawProp( + context, + rawProps, + "fontVariationSettings", + sourceTextAttributes.fontVariationSettings, + defaultTextAttributes.fontVariationSettings); textAttributes.fontSize = convertRawProp( context, rawProps, @@ -244,6 +250,8 @@ void BaseTextProps::setProp( defaults, value, textAttributes, foregroundColor, "color"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, fontFamily, "fontFamily"); + REBUILD_FIELD_SWITCH_CASE( + defaults, value, textAttributes, fontVariationSettings, "fontVariationSettings"); REBUILD_FIELD_SWITCH_CASE( defaults, value, textAttributes, fontSize, "fontSize"); REBUILD_FIELD_SWITCH_CASE( 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 6f318ca70956..31e248c27a4c 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 @@ -165,6 +165,8 @@ AndroidTextInputProps::AndroidTextInputProps( convertRawProp(context, rawProps, "fontWeight", sourceProps.fontWeight, {})), fontFamily(CoreFeatures::enablePropIteratorSetter? sourceProps.fontFamily : convertRawProp(context, rawProps, "fontFamily", sourceProps.fontFamily, {})), + fontVariationSettings(CoreFeatures::enablePropIteratorSetter? sourceProps.fontVariationSettings : + convertRawProp(context, rawProps, "fontVariationSettings", sourceProps.fontVariationSettings, {})), // See AndroidTextInputComponentDescriptor for usage // TODO T63008435: can these, and this feature, be removed entirely? hasPadding(CoreFeatures::enablePropIteratorSetter? sourceProps.hasPadding : hasValue(rawProps, sourceProps.hasPadding, "padding")), @@ -246,6 +248,7 @@ void AndroidTextInputProps::setProp( RAW_SET_PROP_SWITCH_CASE_BASIC(includeFontPadding); RAW_SET_PROP_SWITCH_CASE_BASIC(fontWeight); RAW_SET_PROP_SWITCH_CASE_BASIC(fontFamily); + RAW_SET_PROP_SWITCH_CASE_BASIC(fontVariationSettings); case CONSTEXPR_RAW_PROPS_KEY_HASH("value"): { fromRawValue(context, value, this->value, {}); @@ -343,6 +346,7 @@ folly::dynamic AndroidTextInputProps::getDynamic() const { props["includeFontPadding"] = includeFontPadding; props["fontWeight"] = fontWeight; props["fontFamily"] = fontFamily; + props["fontVariationSettings"] = fontVariationSettings; props["cursorColor"] = toAndroidRepr(cursorColor); props["mostRecentEventCount"] = mostRecentEventCount; props["text"] = text; diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h index da41bb4ce251..f8459a91f4a5 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputProps.h @@ -111,6 +111,7 @@ class AndroidTextInputProps final : public BaseTextInputProps { bool includeFontPadding{false}; std::string fontWeight{}; std::string fontFamily{}; + std::string fontVariationSettings{}; /** * Auxiliary information to detect if these props are set or not. diff --git a/packages/rn-tester/android/app/src/main/assets/fonts/MaterialSymbolsSharp.ttf b/packages/rn-tester/android/app/src/main/assets/fonts/MaterialSymbolsSharp.ttf new file mode 100644 index 000000000000..a0ab3cfc537e Binary files /dev/null and b/packages/rn-tester/android/app/src/main/assets/fonts/MaterialSymbolsSharp.ttf differ diff --git a/packages/rn-tester/android/app/src/main/assets/fonts/inter.ttf b/packages/rn-tester/android/app/src/main/assets/fonts/inter.ttf new file mode 100644 index 000000000000..e72470871b8f Binary files /dev/null and b/packages/rn-tester/android/app/src/main/assets/fonts/inter.ttf differ diff --git a/packages/rn-tester/js/examples/Text/TextExample.android.js b/packages/rn-tester/js/examples/Text/TextExample.android.js index c8acafe10e96..76c66799d600 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.android.js +++ b/packages/rn-tester/js/examples/Text/TextExample.android.js @@ -506,6 +506,76 @@ function FontWeightExample(props: {}): React.Node { ); } +function FontVariationSettingsExample(props: {}): React.Node { + const fontSettings = [ + "'wght' 100", + "'wght' 200", + "'wght' 300", + "'wght' 400", + "'wght' 500", + "'wght' 600", + "'wght' 700", + "'wght' 800", + "'wght' 800, 'slnt' -1", + "'wght' 800, 'slnt' -2", + "'wght' 800, 'slnt' -3", + "'wght' 800, 'slnt' -4", + "'wght' 800, 'slnt' -5", + "'wght' 800, 'slnt' -6", + "'wght' 800, 'slnt' -7", + "'wght' 800, 'slnt' -8", + "'wght' 800, 'slnt' -9", + "'wght' 800, 'slnt' -10", + ]; + + return ( + <> + {fontSettings.map((setting, index) => ( + + Inter variable font - {setting} + + ))} + + + + + {'Invalid font variation settings - should fallback to default font'} + + + + + {/* Font Icons with custom axes */} + Material Symbols Sharp - 'wght' 400, 'FILL' 0 + + {String.fromCodePoint(59576)} + + Material Symbols Sharp - 'wght' 100, 'FILL' 1 + + {String.fromCodePoint(59576)} + + + ); +} + function BackgroundColorExample(props: {}): React.Node { return ( <> @@ -1066,6 +1136,13 @@ const examples = [ return ; }, }, + { + title: 'Variable Font Settings', + name: 'fontVariationSettings', + render(): React.Node { + return ; + }, + }, { title: 'Font Style', name: 'fontStyle', diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js index c2c8eb7084a4..6ecbdff70388 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js @@ -522,6 +522,19 @@ const examples: Array = [ return ; }, }, + { + title: 'TextInput with font variation settings', + render: function (): React.Node { + return ( + + ); + }, + }, ]; module.exports = ({