react-native-advanced-text 0.2.10 → 0.2.12
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.
- package/android/build.gradle +1 -0
- package/android/consumer-rules.pro +3 -0
- package/android/src/main/java/com/advancedtext/AdvancedTextPackage.kt +3 -0
- package/android/src/main/java/com/advancedtext/AdvancedTextView.kt +14 -4
- package/android/src/main/java/com/advancedtext/NativeTextMeasurement.kt +17 -1
- package/ios/AdvancedTextView.mm +17 -9
- package/package.json +1 -1
package/android/build.gradle
CHANGED
|
@@ -8,6 +8,9 @@ import java.util.ArrayList
|
|
|
8
8
|
|
|
9
9
|
class AdvancedTextViewPackage : ReactPackage {
|
|
10
10
|
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
11
|
+
// Fabric measures text before any view exists, so hand the app's assets
|
|
12
|
+
// to the measurer as early as possible.
|
|
13
|
+
NativeTextMeasurement.assetManager = reactContext.assets
|
|
11
14
|
val viewManagers: MutableList<ViewManager<*, *>> = ArrayList()
|
|
12
15
|
viewManagers.add(AdvancedTextViewManager())
|
|
13
16
|
return viewManagers
|
|
@@ -19,6 +19,7 @@ import android.view.Menu
|
|
|
19
19
|
import android.view.MenuItem
|
|
20
20
|
import android.view.View
|
|
21
21
|
import android.view.MotionEvent
|
|
22
|
+
import android.view.accessibility.AccessibilityNodeInfo
|
|
22
23
|
import android.widget.TextView
|
|
23
24
|
import com.facebook.react.bridge.Arguments
|
|
24
25
|
import com.facebook.react.bridge.ReactContext
|
|
@@ -173,7 +174,7 @@ class AdvancedTextView : TextView {
|
|
|
173
174
|
fun setAdvancedFontFamily(family: String) {
|
|
174
175
|
if (fontFamily == family) return
|
|
175
176
|
fontFamily = family
|
|
176
|
-
typeface =
|
|
177
|
+
typeface = NativeTextMeasurement.resolveTypeface(family, Typeface.NORMAL)
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
fun setMenuOptions(menuOptions: List<String>) {
|
|
@@ -281,9 +282,9 @@ class AdvancedTextView : TextView {
|
|
|
281
282
|
setTextSize(fontSize)
|
|
282
283
|
|
|
283
284
|
typeface = when (fontWeight) {
|
|
284
|
-
"bold" ->
|
|
285
|
-
"italic" ->
|
|
286
|
-
else ->
|
|
285
|
+
"bold" -> NativeTextMeasurement.resolveTypeface(fontFamily, Typeface.BOLD)
|
|
286
|
+
"italic" -> NativeTextMeasurement.resolveTypeface(fontFamily, Typeface.ITALIC)
|
|
287
|
+
else -> NativeTextMeasurement.resolveTypeface(fontFamily, Typeface.NORMAL)
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
|
|
@@ -310,6 +311,15 @@ class AdvancedTextView : TextView {
|
|
|
310
311
|
Log.d(TAG, "Text updated with ${wordPositions.size} spans")
|
|
311
312
|
}
|
|
312
313
|
|
|
314
|
+
// Every word is a ClickableSpan so a tap can report it, but TalkBack treats
|
|
315
|
+
// each span as a link: it reads the text one word at a time and lists every
|
|
316
|
+
// word under Actions. Plain text keeps it reading as prose; granularity
|
|
317
|
+
// navigation still works since the characters are identical.
|
|
318
|
+
override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo) {
|
|
319
|
+
super.onInitializeAccessibilityNodeInfo(info)
|
|
320
|
+
info.text = text?.toString()
|
|
321
|
+
}
|
|
322
|
+
|
|
313
323
|
override fun onDraw(canvas: Canvas) {
|
|
314
324
|
drawHighlightedWordBackgrounds(canvas)
|
|
315
325
|
super.onDraw(canvas)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
package com.advancedtext
|
|
2
2
|
|
|
3
|
+
import android.content.res.AssetManager
|
|
3
4
|
import android.content.res.Resources
|
|
4
5
|
import android.graphics.Typeface
|
|
5
6
|
import android.text.StaticLayout
|
|
6
7
|
import android.text.TextPaint
|
|
7
8
|
import android.util.TypedValue
|
|
9
|
+
import com.facebook.react.common.assets.ReactFontManager
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* JNI bridge so the Fabric ShadowNode (C++ `measureContent()`) can ask
|
|
@@ -31,6 +33,20 @@ import android.util.TypedValue
|
|
|
31
33
|
*/
|
|
32
34
|
object NativeTextMeasurement {
|
|
33
35
|
|
|
36
|
+
/** App assets, so fonts bundled under `assets/fonts/` resolve here too. */
|
|
37
|
+
@Volatile
|
|
38
|
+
var assetManager: AssetManager? = null
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a font family the way React Native's own <Text> does: fonts
|
|
42
|
+
* registered at runtime (expo-font), then `assets/fonts/<family>.ttf|otf`,
|
|
43
|
+
* then system families. `AdvancedTextView` uses this too, so measuring and
|
|
44
|
+
* rendering always pick the same typeface.
|
|
45
|
+
*/
|
|
46
|
+
@JvmStatic
|
|
47
|
+
fun resolveTypeface(fontFamily: String, style: Int): Typeface =
|
|
48
|
+
ReactFontManager.getInstance().getTypeface(fontFamily, style, assetManager)
|
|
49
|
+
|
|
34
50
|
@JvmStatic
|
|
35
51
|
fun measureHeight(
|
|
36
52
|
text: String,
|
|
@@ -50,7 +66,7 @@ object NativeTextMeasurement {
|
|
|
50
66
|
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, fontSizeSp, displayMetrics)
|
|
51
67
|
|
|
52
68
|
val paint = TextPaint(TextPaint.ANTI_ALIAS_FLAG)
|
|
53
|
-
paint.typeface =
|
|
69
|
+
paint.typeface = resolveTypeface(fontFamily, typefaceStyle)
|
|
54
70
|
paint.textSize = fontSizePx
|
|
55
71
|
// Mirrors AdvancedTextView's own letterSpacing conversion: dp/points
|
|
56
72
|
// prop -> em, scale-invariant so no density conversion is needed.
|
package/ios/AdvancedTextView.mm
CHANGED
|
@@ -9,6 +9,21 @@
|
|
|
9
9
|
|
|
10
10
|
using namespace facebook::react;
|
|
11
11
|
|
|
12
|
+
// Resolves a PostScript name, a family name, or an expo-font alias (expo-font
|
|
13
|
+
// only hooks +fontNamesForFamilyName:, which is also what RN's <Text> uses).
|
|
14
|
+
static UIFont *ATResolveFont(NSString *family, CGFloat size)
|
|
15
|
+
{
|
|
16
|
+
if (family.length == 0) {
|
|
17
|
+
return nil;
|
|
18
|
+
}
|
|
19
|
+
UIFont *font = [UIFont fontWithName:family size:size];
|
|
20
|
+
if (font) {
|
|
21
|
+
return font;
|
|
22
|
+
}
|
|
23
|
+
NSString *fontName = [UIFont fontNamesForFamilyName:family].firstObject;
|
|
24
|
+
return fontName ? [UIFont fontWithName:fontName size:size] : nil;
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
|
|
13
28
|
@class AdvancedTextView;
|
|
14
29
|
|
|
@@ -446,10 +461,7 @@ using namespace facebook::react;
|
|
|
446
461
|
if (_lineHeight > 0) {
|
|
447
462
|
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
|
|
448
463
|
|
|
449
|
-
UIFont *font =
|
|
450
|
-
if (_fontFamily && _fontFamily.length > 0) {
|
|
451
|
-
font = [UIFont fontWithName:_fontFamily size:_fontSize > 0 ? _fontSize : 16.0];
|
|
452
|
-
}
|
|
464
|
+
UIFont *font = ATResolveFont(_fontFamily, _fontSize > 0 ? _fontSize : 16.0);
|
|
453
465
|
if (!font) {
|
|
454
466
|
font = [UIFont systemFontOfSize:_fontSize > 0 ? _fontSize : 16.0];
|
|
455
467
|
}
|
|
@@ -462,11 +474,7 @@ using namespace facebook::react;
|
|
|
462
474
|
range:NSMakeRange(0, attributedString.length)];
|
|
463
475
|
}
|
|
464
476
|
|
|
465
|
-
UIFont *font =
|
|
466
|
-
|
|
467
|
-
if (_fontFamily && _fontFamily.length > 0) {
|
|
468
|
-
font = [UIFont fontWithName:_fontFamily size:_fontSize > 0 ? _fontSize : 16.0];
|
|
469
|
-
}
|
|
477
|
+
UIFont *font = ATResolveFont(_fontFamily, _fontSize > 0 ? _fontSize : 16.0);
|
|
470
478
|
|
|
471
479
|
if (!font) {
|
|
472
480
|
if (_fontWeight && [_fontWeight.lowercaseString isEqualToString:@"bold"]) {
|
package/package.json
CHANGED