react-native-advanced-text 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -25,7 +25,6 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
|
25
25
|
import android.text.Selection
|
|
26
26
|
import android.graphics.Typeface
|
|
27
27
|
import androidx.core.text.getSpans
|
|
28
|
-
import com.facebook.react.common.assets.ReactFontManager
|
|
29
28
|
|
|
30
29
|
class AdvancedTextView : TextView {
|
|
31
30
|
|
|
@@ -164,25 +163,9 @@ class AdvancedTextView : TextView {
|
|
|
164
163
|
fun setAdvancedFontFamily(family: String) {
|
|
165
164
|
if (fontFamily == family) return
|
|
166
165
|
fontFamily = family
|
|
167
|
-
typeface =
|
|
166
|
+
typeface = Typeface.create(family, Typeface.NORMAL)
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
/**
|
|
171
|
-
* `Typeface.create(family, style)` only resolves OS-registered families; it
|
|
172
|
-
* silently substitutes a system font for anything bundled under
|
|
173
|
-
* `assets/fonts/` (the RN/Expo custom-font pipeline) instead of failing.
|
|
174
|
-
* The Fabric ShadowNode measures this component's text via
|
|
175
|
-
* `TextLayoutManager`, which resolves fonts through `ReactFontManager` -
|
|
176
|
-
* so a custom font here rendered with the substituted typeface has
|
|
177
|
-
* different glyph widths than what was measured, wrapping onto a
|
|
178
|
-
* different number of lines and producing extra height for some strings
|
|
179
|
-
* but not others. Going through `ReactFontManager` keeps the rendered
|
|
180
|
-
* typeface identical to the measured one (and is a no-op for system font
|
|
181
|
-
* names, which it falls back to `Typeface.create` for anyway).
|
|
182
|
-
*/
|
|
183
|
-
private fun resolveTypeface(family: String, style: Int): Typeface =
|
|
184
|
-
ReactFontManager.getInstance().getTypeface(family, style, context.assets)
|
|
185
|
-
|
|
186
169
|
fun setMenuOptions(menuOptions: List<String>) {
|
|
187
170
|
if (this.menuOptions == menuOptions) return
|
|
188
171
|
this.menuOptions = menuOptions
|
|
@@ -288,9 +271,9 @@ class AdvancedTextView : TextView {
|
|
|
288
271
|
setTextSize(fontSize)
|
|
289
272
|
|
|
290
273
|
typeface = when (fontWeight) {
|
|
291
|
-
"bold" ->
|
|
292
|
-
"italic" ->
|
|
293
|
-
else ->
|
|
274
|
+
"bold" -> Typeface.create(fontFamily, Typeface.BOLD)
|
|
275
|
+
"italic" -> Typeface.create(fontFamily, Typeface.ITALIC)
|
|
276
|
+
else -> Typeface.create(fontFamily, Typeface.NORMAL)
|
|
294
277
|
}
|
|
295
278
|
|
|
296
279
|
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
|
|
12
12
|
#include <algorithm>
|
|
13
13
|
#include <cctype>
|
|
14
|
-
#include <limits>
|
|
15
14
|
#include <string>
|
|
16
15
|
|
|
17
16
|
#include <react/renderer/attributedstring/AttributedStringBox.h>
|
|
@@ -33,10 +32,6 @@ std::string toLowerAscii(std::string value) {
|
|
|
33
32
|
return value;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
// Fallback only: an approximate ratio of a single line's natural height to
|
|
37
|
-
// its font size, used if a real measurement (Android) isn't available/valid.
|
|
38
|
-
constexpr Float kLineHeightFudgeFactor = 1.2;
|
|
39
|
-
|
|
40
35
|
} // namespace
|
|
41
36
|
|
|
42
37
|
AdvancedTextViewShadowNode::AdvancedTextViewShadowNode(
|
|
@@ -47,47 +42,7 @@ AdvancedTextViewShadowNode::AdvancedTextViewShadowNode(
|
|
|
47
42
|
static_cast<const AdvancedTextViewShadowNode&>(sourceShadowNode)
|
|
48
43
|
.textLayoutManager_) {}
|
|
49
44
|
|
|
50
|
-
|
|
51
|
-
Float AdvancedTextViewShadowNode::measureNaturalSingleLineHeight(
|
|
52
|
-
const LayoutContext& layoutContext,
|
|
53
|
-
const TextAttributes& baseTextAttributes) const {
|
|
54
|
-
// Same font/size/weight/style as the real fragment, but with `lineHeight`
|
|
55
|
-
// cleared so this reports the font's own, unscaled single-line height --
|
|
56
|
-
// exactly what Android's `setLineSpacing(0, multiplier)` multiplies.
|
|
57
|
-
auto probeAttributes = baseTextAttributes;
|
|
58
|
-
probeAttributes.lineHeight = std::numeric_limits<Float>::quiet_NaN();
|
|
59
|
-
|
|
60
|
-
auto probe = AttributedString{};
|
|
61
|
-
probe.appendFragment(AttributedString::Fragment{
|
|
62
|
-
.string = "M",
|
|
63
|
-
.textAttributes = probeAttributes,
|
|
64
|
-
.parentShadowView = ShadowView(*this),
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
auto paragraphAttributes = ParagraphAttributes{};
|
|
68
|
-
|
|
69
|
-
auto textLayoutContext = TextLayoutContext{};
|
|
70
|
-
textLayoutContext.pointScaleFactor = layoutContext.pointScaleFactor;
|
|
71
|
-
textLayoutContext.surfaceId = getSurfaceId();
|
|
72
|
-
|
|
73
|
-
// Unconstrained so a single glyph can never be forced to wrap.
|
|
74
|
-
auto unconstrainedLayoutConstraints = LayoutConstraints{
|
|
75
|
-
{0, 0},
|
|
76
|
-
{std::numeric_limits<Float>::infinity(),
|
|
77
|
-
std::numeric_limits<Float>::infinity()}};
|
|
78
|
-
|
|
79
|
-
auto measurement = textLayoutManager_->measure(
|
|
80
|
-
AttributedStringBox{probe},
|
|
81
|
-
paragraphAttributes,
|
|
82
|
-
textLayoutContext,
|
|
83
|
-
unconstrainedLayoutConstraints);
|
|
84
|
-
|
|
85
|
-
return measurement.size.height;
|
|
86
|
-
}
|
|
87
|
-
#endif
|
|
88
|
-
|
|
89
|
-
AttributedString AdvancedTextViewShadowNode::getAttributedString(
|
|
90
|
-
const LayoutContext& layoutContext) const {
|
|
45
|
+
AttributedString AdvancedTextViewShadowNode::getAttributedString() const {
|
|
91
46
|
const auto& props = getConcreteProps();
|
|
92
47
|
|
|
93
48
|
auto textAttributes = TextAttributes::defaultTextAttributes();
|
|
@@ -113,32 +68,13 @@ AttributedString AdvancedTextViewShadowNode::getAttributedString(
|
|
|
113
68
|
textAttributes.letterSpacing = props.letterSpacing;
|
|
114
69
|
}
|
|
115
70
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// line height, so there is nothing to override in that case (and
|
|
122
|
-
// overriding it with an approximation, as this used to do unconditionally,
|
|
123
|
-
// made even the "no lineHeight override" case measure taller or shorter
|
|
124
|
-
// than the real render).
|
|
125
|
-
if (props.lineHeight > 0 && props.lineHeight != 1.0) {
|
|
126
|
-
#if defined(ANDROID)
|
|
127
|
-
// Android's natural single-line height depends on the resolved
|
|
128
|
-
// font/size/weight and isn't a fixed ratio of fontSize, so a constant
|
|
129
|
-
// approximation drifts from AdvancedTextView.kt's real
|
|
130
|
-
// setLineSpacing()-based layout by an amount that compounds with every
|
|
131
|
-
// wrapped line -- which is why the error scaled with paragraph length.
|
|
132
|
-
// Measure the real natural height for these exact attributes instead.
|
|
133
|
-
auto naturalLineHeight =
|
|
134
|
-
measureNaturalSingleLineHeight(layoutContext, textAttributes);
|
|
135
|
-
textAttributes.lineHeight = naturalLineHeight > 0
|
|
136
|
-
? props.lineHeight * naturalLineHeight
|
|
137
|
-
: props.lineHeight * textAttributes.fontSize * kLineHeightFudgeFactor;
|
|
138
|
-
#else
|
|
71
|
+
if (props.lineHeight > 0) {
|
|
72
|
+
// The component treats `lineHeight` as a multiple of the font size
|
|
73
|
+
// (see AdvancedTextView.mm / AdvancedTextView.kt). `TextAttributes`
|
|
74
|
+
// expects an absolute value; approximate the platform default single
|
|
75
|
+
// line height as 1.2 * fontSize.
|
|
139
76
|
textAttributes.lineHeight =
|
|
140
|
-
props.lineHeight * textAttributes.fontSize *
|
|
141
|
-
#endif
|
|
77
|
+
props.lineHeight * textAttributes.fontSize * 1.2;
|
|
142
78
|
}
|
|
143
79
|
|
|
144
80
|
auto attributedString = AttributedString{};
|
|
@@ -173,7 +109,7 @@ Size AdvancedTextViewShadowNode::measureContent(
|
|
|
173
109
|
textLayoutContext.surfaceId = getSurfaceId();
|
|
174
110
|
|
|
175
111
|
auto measurement = textLayoutManager_->measure(
|
|
176
|
-
AttributedStringBox{getAttributedString(
|
|
112
|
+
AttributedStringBox{getAttributedString()},
|
|
177
113
|
paragraphAttributes,
|
|
178
114
|
textLayoutContext,
|
|
179
115
|
layoutConstraints);
|
|
@@ -86,20 +86,7 @@ class AdvancedTextViewShadowNode final : public ConcreteViewShadowNode<
|
|
|
86
86
|
* Builds a single-fragment `AttributedString` from the component props
|
|
87
87
|
* (text + font attributes), mirroring how the native views render it.
|
|
88
88
|
*/
|
|
89
|
-
AttributedString getAttributedString(
|
|
90
|
-
|
|
91
|
-
#if defined(ANDROID)
|
|
92
|
-
/*
|
|
93
|
-
* Measures the natural (multiplier == 1) height of a single line set in
|
|
94
|
-
* `baseTextAttributes`, by measuring a single glyph with `lineHeight`
|
|
95
|
-
* cleared. Used to turn the component's `lineHeight` multiplier prop into
|
|
96
|
-
* the absolute value `TextAttributes.lineHeight` expects, using this
|
|
97
|
-
* font's *real* metrics instead of an approximation.
|
|
98
|
-
*/
|
|
99
|
-
Float measureNaturalSingleLineHeight(
|
|
100
|
-
const LayoutContext& layoutContext,
|
|
101
|
-
const TextAttributes& baseTextAttributes) const;
|
|
102
|
-
#endif
|
|
89
|
+
AttributedString getAttributedString() const;
|
|
103
90
|
|
|
104
91
|
// Lazily created on first measure, then reused / copied across clones.
|
|
105
92
|
mutable std::shared_ptr<const TextLayoutManager> textLayoutManager_;
|
package/package.json
CHANGED