react-native-highlight-text-view 0.1.25 → 0.1.27

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/README.md CHANGED
@@ -48,6 +48,7 @@ export default function App() {
48
48
  | `verticalAlign` | `'top' \| 'center' \| 'middle' \| 'bottom'` | - | Vertical alignment (iOS only). Alternative to using combined `textAlign` values. **Note:** Android does not support vertical alignment and will use default vertical positioning. |
49
49
  | `fontFamily` | `string` | - | Font family name |
50
50
  | `fontSize` | `string` | `32` | Font size in points |
51
+ | `letterSpacing` | `string` | `0` | Extra space between characters, in layout points (same semantics as React Native's `letterSpacing`). |
51
52
  | `lineHeight` | `string` | `0` | Line height override (0 means use default line height) |
52
53
  | `highlightBorderRadius` | `string` | `0` | Border radius for the highlight background |
53
54
  | `padding` | `string` | `4` | Padding around each character highlight (expands background outward) |
@@ -12,6 +12,7 @@ import android.util.AttributeSet
12
12
  import android.util.TypedValue
13
13
  import android.view.Gravity
14
14
  import androidx.appcompat.widget.AppCompatEditText
15
+ import com.facebook.react.common.assets.ReactFontManager
15
16
 
16
17
  /**
17
18
  * Custom EditText that mimics the iOS implementation by drawing per-character
@@ -46,6 +47,8 @@ class HighlightTextView : AppCompatEditText {
46
47
  private var currentFontFamily: String? = null
47
48
  private var currentFontWeight: String = "normal"
48
49
  private var currentVerticalAlign: String? = null
50
+ // Letter spacing in layout points (same semantics as React Native's letterSpacing prop)
51
+ private var letterSpacingPoints: Float = 0f
49
52
 
50
53
  // Internal flags
51
54
  private var isUpdatingText: Boolean = false
@@ -279,15 +282,20 @@ class HighlightTextView : AppCompatEditText {
279
282
  else -> 400
280
283
  }
281
284
 
282
- // Get base typeface
283
- val baseTypeface = if (currentFontFamily != null) {
284
- when (currentFontFamily?.lowercase()) {
285
+ // Capture currentFontFamily as local variable to avoid smart cast issues
286
+ val fontFamily = currentFontFamily
287
+
288
+ // Get base typeface using ReactFontManager for custom fonts
289
+ val baseTypeface = if (fontFamily != null) {
290
+ when (fontFamily.lowercase()) {
285
291
  "system" -> Typeface.DEFAULT
286
292
  "sans-serif" -> Typeface.SANS_SERIF
287
293
  "serif" -> Typeface.SERIF
288
294
  "monospace" -> Typeface.MONOSPACE
289
295
  else -> try {
290
- Typeface.create(currentFontFamily, Typeface.NORMAL)
296
+ // Use ReactFontManager to load custom fonts from assets
297
+ val style = if (weight >= 600) Typeface.BOLD else Typeface.NORMAL
298
+ ReactFontManager.getInstance().getTypeface(fontFamily, style, context.assets)
291
299
  } catch (e: Exception) {
292
300
  Typeface.DEFAULT
293
301
  }
@@ -354,9 +362,16 @@ class HighlightTextView : AppCompatEditText {
354
362
  invalidate()
355
363
  }
356
364
 
365
+ fun setLetterSpacingProp(points: Float) {
366
+ letterSpacingPoints = points
367
+ applyLetterSpacing()
368
+ invalidate()
369
+ }
370
+
357
371
  override fun setTextSize(unit: Int, size: Float) {
358
372
  super.setTextSize(unit, size)
359
373
  applyLineHeightAndSpacing()
374
+ applyLetterSpacing()
360
375
  }
361
376
 
362
377
  fun setTextProp(newText: String) {
@@ -404,4 +419,17 @@ class HighlightTextView : AppCompatEditText {
404
419
  setLineSpacing(extraSpacing, 1.0f)
405
420
  }
406
421
  }
422
+
423
+ private fun applyLetterSpacing() {
424
+ // React Native's letterSpacing is specified in layout points. Convert that to
425
+ // Android's "em" units: pxSpacing / textSizePx.
426
+ val metrics = resources.displayMetrics
427
+ val pxSpacing = letterSpacingPoints * metrics.scaledDensity
428
+ val textPx = textSize
429
+ if (textPx > 0f) {
430
+ super.setLetterSpacing(pxSpacing / textPx)
431
+ } else {
432
+ super.setLetterSpacing(0f)
433
+ }
434
+ }
407
435
  }
@@ -134,6 +134,13 @@ class HighlightTextViewManager : SimpleViewManager<HighlightTextView>(),
134
134
  }
135
135
  }
136
136
 
137
+ @ReactProp(name = "letterSpacing")
138
+ override fun setLetterSpacing(view: HighlightTextView?, value: String?) {
139
+ value?.toFloatOrNull()?.let { spacing ->
140
+ view?.setLetterSpacingProp(spacing)
141
+ }
142
+ }
143
+
137
144
  @ReactProp(name = "padding")
138
145
  override fun setPadding(view: HighlightTextView?, value: String?) {
139
146
  value?.toFloatOrNull()?.let { padding ->
@@ -90,6 +90,7 @@ using namespace facebook::react;
90
90
  CGFloat _backgroundInsetRight;
91
91
  CGFloat _lineHeight;
92
92
  CGFloat _fontSize;
93
+ CGFloat _letterSpacing; // in layout points, matches React Native's letterSpacing
93
94
  NSString * _fontFamily;
94
95
  NSString * _fontWeight;
95
96
  BOOL _isUpdatingText;
@@ -122,6 +123,7 @@ using namespace facebook::react;
122
123
  _backgroundInsetRight = 0.0;
123
124
  _lineHeight = 0.0; // 0 means use default line height
124
125
  _fontSize = 32.0; // Default font size
126
+ _letterSpacing = 0.0; // Default: no extra spacing
125
127
  _fontFamily = nil;
126
128
  _fontWeight = @"normal";
127
129
  _currentVerticalAlignment = nil;
@@ -296,6 +298,13 @@ using namespace facebook::react;
296
298
  }
297
299
  }
298
300
 
301
+ if (oldViewProps.letterSpacing != newViewProps.letterSpacing) {
302
+ NSString *spacingStr = [[NSString alloc] initWithUTF8String: newViewProps.letterSpacing.c_str()];
303
+ CGFloat spacing = [spacingStr floatValue];
304
+ _letterSpacing = spacing;
305
+ [self applyCharacterBackgrounds]; // Reapply to update glyph layout
306
+ }
307
+
299
308
  if (oldViewProps.highlightBorderRadius != newViewProps.highlightBorderRadius) {
300
309
  NSString *radiusStr = [[NSString alloc] initWithUTF8String: newViewProps.highlightBorderRadius.c_str()];
301
310
  CGFloat radius = [radiusStr floatValue];
@@ -430,6 +439,9 @@ using namespace facebook::react;
430
439
  if (newViewProps.autoFocus && _textView.isEditable) {
431
440
  dispatch_async(dispatch_get_main_queue(), ^{
432
441
  [self->_textView becomeFirstResponder];
442
+ // Move cursor to the end of the text
443
+ NSUInteger textLength = self->_textView.text.length;
444
+ self->_textView.selectedRange = NSMakeRange(textLength, 0);
433
445
  });
434
446
  }
435
447
  }
@@ -537,6 +549,13 @@ Class<RCTComponentViewProtocol> HighlightTextViewCls(void)
537
549
  value:_textView.font
538
550
  range:NSMakeRange(0, text.length)];
539
551
 
552
+ // Apply letter spacing (kern) if specified
553
+ if (_letterSpacing != 0) {
554
+ [attributedString addAttribute:NSKernAttributeName
555
+ value:@(_letterSpacing)
556
+ range:NSMakeRange(0, text.length)];
557
+ }
558
+
540
559
  // Apply text color if available
541
560
  if (_textView.textColor) {
542
561
  [attributedString addAttribute:NSForegroundColorAttributeName
@@ -47,6 +47,8 @@ export interface HighlightTextViewProps extends ViewProps {
47
47
  fontFamily?: string;
48
48
  fontSize?: string;
49
49
  fontWeight?: string;
50
+ /** Additional space between characters, in layout points (matches React Native's letterSpacing). */
51
+ letterSpacing?: string;
50
52
  lineHeight?: string;
51
53
  highlightBorderRadius?: string;
52
54
  padding?: string;
@@ -29,6 +29,8 @@ export interface HighlightTextViewProps extends ViewProps {
29
29
  fontFamily?: string;
30
30
  fontSize?: string;
31
31
  fontWeight?: string;
32
+ /** Additional space between characters, in layout points (matches React Native's letterSpacing). */
33
+ letterSpacing?: string;
32
34
  lineHeight?: string;
33
35
  highlightBorderRadius?: string;
34
36
  padding?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"HighlightTextViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/HighlightTextViewNativeComponent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,SAAS,GACT,YAAY,GACZ,UAAU,GACV,KAAK,GACL,QAAQ,GACR,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAC;AAEnB,MAAM,WAAW,sBAAuB,SAAQ,SAAS;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gFAAgF;IAChF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;CACpD;;AAED,wBAEE"}
1
+ {"version":3,"file":"HighlightTextViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/HighlightTextViewNativeComponent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,SAAS,GACT,YAAY,GACZ,UAAU,GACV,KAAK,GACL,QAAQ,GACR,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAC;AAEnB,MAAM,WAAW,sBAAuB,SAAQ,SAAS;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oGAAoG;IACpG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oFAAoF;IACpF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gFAAgF;IAChF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;CACpD;;AAED,wBAEE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-highlight-text-view",
3
- "version": "0.1.25",
3
+ "version": "0.1.27",
4
4
  "description": "A native text input for React Native that supports inline text highlighting",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -47,6 +47,8 @@ export interface HighlightTextViewProps extends ViewProps {
47
47
  fontFamily?: string;
48
48
  fontSize?: string;
49
49
  fontWeight?: string;
50
+ /** Additional space between characters, in layout points (matches React Native's letterSpacing). */
51
+ letterSpacing?: string;
50
52
  lineHeight?: string;
51
53
  highlightBorderRadius?: string;
52
54
  padding?: string;