react-native-highlight-text-view 0.1.4 → 0.1.6

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.
@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
14
14
  @property (nonatomic, assign) CGFloat paddingTop;
15
15
  @property (nonatomic, assign) CGFloat paddingBottom;
16
16
  @property (nonatomic, assign) CGFloat cornerRadius;
17
+ @property (nonatomic, assign) CGFloat highlightBorderRadius;
17
18
  @end
18
19
 
19
20
  @interface HighlightTextView : RCTViewComponentView
@@ -11,6 +11,8 @@ using namespace facebook::react;
11
11
 
12
12
  @implementation RoundedBackgroundLayoutManager
13
13
 
14
+ @synthesize backgroundColor, padding, paddingLeft, paddingRight, paddingTop, paddingBottom, cornerRadius, highlightBorderRadius;
15
+
14
16
  - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin {
15
17
  NSTextStorage *textStorage = self.textStorage;
16
18
  NSTextContainer *textContainer = self.textContainers.firstObject;
@@ -45,7 +47,9 @@ using namespace facebook::react;
45
47
  boundingRect.size.width += self.paddingLeft + self.paddingRight;
46
48
  boundingRect.size.height += self.paddingTop + self.paddingBottom;
47
49
 
48
- UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:boundingRect cornerRadius:self.cornerRadius];
50
+ // Use highlightBorderRadius if specified, otherwise use cornerRadius
51
+ CGFloat radius = self.highlightBorderRadius > 0 ? self.highlightBorderRadius : self.cornerRadius;
52
+ UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:boundingRect cornerRadius:radius];
49
53
  [self.backgroundColor setFill];
50
54
  [path fill];
51
55
  }
@@ -73,7 +77,11 @@ using namespace facebook::react;
73
77
  CGFloat _paddingTop;
74
78
  CGFloat _paddingBottom;
75
79
  CGFloat _cornerRadius;
80
+ CGFloat _highlightBorderRadius;
81
+ CGFloat _lineHeight;
76
82
  BOOL _isUpdatingText;
83
+ NSString * _currentVerticalAlignment;
84
+ NSTextAlignment _currentHorizontalAlignment;
77
85
  }
78
86
 
79
87
  + (ComponentDescriptorProvider)componentDescriptorProvider
@@ -94,6 +102,10 @@ using namespace facebook::react;
94
102
  _paddingTop = 4.0;
95
103
  _paddingBottom = 4.0;
96
104
  _cornerRadius = 4.0;
105
+ _highlightBorderRadius = 0.0;
106
+ _lineHeight = 0.0; // 0 means use default line height
107
+ _currentVerticalAlignment = nil;
108
+ _currentHorizontalAlignment = NSTextAlignmentCenter;
97
109
 
98
110
  // Create text storage, layout manager, and text container
99
111
  NSTextStorage *textStorage = [[NSTextStorage alloc] init];
@@ -105,6 +117,7 @@ using namespace facebook::react;
105
117
  _layoutManager.paddingTop = _paddingTop;
106
118
  _layoutManager.paddingBottom = _paddingBottom;
107
119
  _layoutManager.cornerRadius = _cornerRadius;
120
+ _layoutManager.highlightBorderRadius = _highlightBorderRadius;
108
121
 
109
122
  [textStorage addLayoutManager:_layoutManager];
110
123
 
@@ -128,6 +141,52 @@ using namespace facebook::react;
128
141
  return self;
129
142
  }
130
143
 
144
+ - (void)layoutSubviews
145
+ {
146
+ [super layoutSubviews];
147
+
148
+ // Recalculate vertical alignment after layout
149
+ if (_currentVerticalAlignment) {
150
+ [self updateVerticalAlignment:_currentVerticalAlignment];
151
+ }
152
+ }
153
+
154
+ - (void)updateVerticalAlignment:(NSString *)verticalAlign
155
+ {
156
+ if ([verticalAlign isEqualToString:@"top"]) {
157
+ _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 0, 10);
158
+ } else if ([verticalAlign isEqualToString:@"bottom"]) {
159
+ // Force layout to get accurate content height
160
+ [_textView.layoutManager ensureLayoutForTextContainer:_textView.textContainer];
161
+
162
+ CGFloat contentHeight = [_textView.layoutManager usedRectForTextContainer:_textView.textContainer].size.height;
163
+ CGFloat viewHeight = _textView.bounds.size.height;
164
+
165
+ // Only apply bottom alignment if we have valid dimensions
166
+ if (viewHeight > 0 && contentHeight > 0) {
167
+ if (contentHeight + 20 <= viewHeight) {
168
+ // Content fits in view - align to bottom with inset
169
+ CGFloat topInset = MAX(10, viewHeight - contentHeight - 10);
170
+ _textView.textContainerInset = UIEdgeInsetsMake(topInset, 10, 10, 10);
171
+ } else {
172
+ // Content exceeds view - use minimal inset and scroll to bottom
173
+ _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
174
+
175
+ // Scroll to bottom to show the latest text
176
+ dispatch_async(dispatch_get_main_queue(), ^{
177
+ CGFloat bottomOffset = self->_textView.contentSize.height - self->_textView.bounds.size.height + self->_textView.contentInset.bottom;
178
+ if (bottomOffset > 0) {
179
+ [self->_textView setContentOffset:CGPointMake(0, bottomOffset) animated:NO];
180
+ }
181
+ });
182
+ }
183
+ }
184
+ } else {
185
+ // Default or center
186
+ _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
187
+ }
188
+ }
189
+
131
190
  - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
132
191
  {
133
192
  const auto &oldViewProps = *std::static_pointer_cast<HighlightTextViewProps const>(_props);
@@ -169,29 +228,26 @@ using namespace facebook::react;
169
228
  // Apply horizontal alignment
170
229
  if (horizontalPart) {
171
230
  if ([horizontalPart isEqualToString:@"center"]) {
172
- _textView.textAlignment = NSTextAlignmentCenter;
231
+ _currentHorizontalAlignment = NSTextAlignmentCenter;
173
232
  } else if ([horizontalPart isEqualToString:@"right"] || [horizontalPart isEqualToString:@"flex-end"]) {
174
- _textView.textAlignment = NSTextAlignmentRight;
233
+ _currentHorizontalAlignment = NSTextAlignmentRight;
175
234
  } else if ([horizontalPart isEqualToString:@"left"] || [horizontalPart isEqualToString:@"flex-start"]) {
176
- _textView.textAlignment = NSTextAlignmentLeft;
235
+ _currentHorizontalAlignment = NSTextAlignmentLeft;
177
236
  } else if ([horizontalPart isEqualToString:@"justify"]) {
178
- _textView.textAlignment = NSTextAlignmentJustified;
237
+ _currentHorizontalAlignment = NSTextAlignmentJustified;
179
238
  } else {
180
- _textView.textAlignment = NSTextAlignmentLeft;
239
+ _currentHorizontalAlignment = NSTextAlignmentLeft;
181
240
  }
241
+ _textView.textAlignment = _currentHorizontalAlignment;
182
242
  }
183
243
 
184
- // Apply vertical alignment via textContainerInset
185
- if ([verticalPart isEqualToString:@"top"]) {
186
- _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 0, 10);
187
- } else if ([verticalPart isEqualToString:@"bottom"]) {
188
- // Calculate bottom alignment by adjusting top inset
189
- CGFloat contentHeight = [_textView.layoutManager usedRectForTextContainer:_textView.textContainer].size.height;
190
- CGFloat viewHeight = _textView.bounds.size.height;
191
- CGFloat topInset = MAX(10, viewHeight - contentHeight - 10);
192
- _textView.textContainerInset = UIEdgeInsetsMake(topInset, 10, 10, 10);
193
- } else if (!verticalPart) {
244
+ // Store and apply vertical alignment
245
+ if (verticalPart) {
246
+ _currentVerticalAlignment = verticalPart;
247
+ [self updateVerticalAlignment:verticalPart];
248
+ } else if (!verticalPart && horizontalPart) {
194
249
  // Default vertical centering for horizontal-only alignments
250
+ _currentVerticalAlignment = nil;
195
251
  _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
196
252
  }
197
253
 
@@ -204,6 +260,26 @@ using namespace facebook::react;
204
260
  if (fontSize > 0) {
205
261
  NSString *fontFamily = _textView.font.familyName;
206
262
  _textView.font = [UIFont fontWithName:fontFamily size:fontSize] ?: [UIFont systemFontOfSize:fontSize];
263
+ [self applyCharacterBackgrounds]; // Reapply to update font
264
+ }
265
+ }
266
+
267
+ if (oldViewProps.lineHeight != newViewProps.lineHeight) {
268
+ NSString *lineHeightStr = [[NSString alloc] initWithUTF8String: newViewProps.lineHeight.c_str()];
269
+ CGFloat lineHeight = [lineHeightStr floatValue];
270
+ if (lineHeight >= 0) {
271
+ _lineHeight = lineHeight;
272
+ [self applyCharacterBackgrounds]; // Reapply to update line height
273
+ }
274
+ }
275
+
276
+ if (oldViewProps.highlightBorderRadius != newViewProps.highlightBorderRadius) {
277
+ NSString *radiusStr = [[NSString alloc] initWithUTF8String: newViewProps.highlightBorderRadius.c_str()];
278
+ CGFloat radius = [radiusStr floatValue];
279
+ if (radius >= 0) {
280
+ _highlightBorderRadius = radius;
281
+ _layoutManager.highlightBorderRadius = _highlightBorderRadius;
282
+ [self applyCharacterBackgrounds]; // Reapply to update highlight border radius
207
283
  }
208
284
  }
209
285
 
@@ -269,6 +345,12 @@ using namespace facebook::react;
269
345
  _isUpdatingText = YES;
270
346
  _textView.text = text;
271
347
  [self applyCharacterBackgrounds];
348
+
349
+ // Recalculate vertical alignment when text changes
350
+ if (_currentVerticalAlignment) {
351
+ [self updateVerticalAlignment:_currentVerticalAlignment];
352
+ }
353
+
272
354
  _isUpdatingText = NO;
273
355
  }
274
356
  }
@@ -279,18 +361,8 @@ using namespace facebook::react;
279
361
 
280
362
  if (oldViewProps.verticalAlign != newViewProps.verticalAlign) {
281
363
  NSString *verticalAlign = [[NSString alloc] initWithUTF8String: newViewProps.verticalAlign.c_str()];
282
-
283
- if ([verticalAlign isEqualToString:@"top"]) {
284
- _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 0, 10);
285
- } else if ([verticalAlign isEqualToString:@"bottom"]) {
286
- CGFloat contentHeight = [_textView.layoutManager usedRectForTextContainer:_textView.textContainer].size.height;
287
- CGFloat viewHeight = _textView.bounds.size.height;
288
- CGFloat topInset = MAX(10, viewHeight - contentHeight - 10);
289
- _textView.textContainerInset = UIEdgeInsetsMake(topInset, 10, 10, 10);
290
- } else if ([verticalAlign isEqualToString:@"center"] || [verticalAlign isEqualToString:@"middle"]) {
291
- _textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10);
292
- }
293
-
364
+ _currentVerticalAlignment = verticalAlign;
365
+ [self updateVerticalAlignment:verticalAlign];
294
366
  [self applyCharacterBackgrounds];
295
367
  }
296
368
 
@@ -305,6 +377,12 @@ Class<RCTComponentViewProtocol> HighlightTextViewCls(void)
305
377
  - (void)textViewDidChange:(UITextView *)textView
306
378
  {
307
379
  [self applyCharacterBackgrounds];
380
+
381
+ // Recalculate vertical alignment when text changes
382
+ if (_currentVerticalAlignment) {
383
+ [self updateVerticalAlignment:_currentVerticalAlignment];
384
+ }
385
+
308
386
  if (!_isUpdatingText) {
309
387
  if (_eventEmitter != nullptr) {
310
388
  std::dynamic_pointer_cast<const HighlightTextViewEventEmitter>(_eventEmitter)
@@ -339,6 +417,24 @@ Class<RCTComponentViewProtocol> HighlightTextViewCls(void)
339
417
 
340
418
  NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
341
419
  paragraphStyle.alignment = _textView.textAlignment;
420
+
421
+ // Apply line height if specified
422
+ if (_lineHeight > 0) {
423
+ CGFloat fontSize = _textView.font.pointSize;
424
+
425
+ // If lineHeight is smaller than fontSize, use lineHeightMultiple for better centering
426
+ if (_lineHeight < fontSize) {
427
+ paragraphStyle.lineHeightMultiple = _lineHeight / fontSize;
428
+ paragraphStyle.minimumLineHeight = 0;
429
+ paragraphStyle.maximumLineHeight = 0;
430
+ } else {
431
+ // For larger line heights, use absolute values
432
+ paragraphStyle.minimumLineHeight = _lineHeight;
433
+ paragraphStyle.maximumLineHeight = _lineHeight;
434
+ paragraphStyle.lineHeightMultiple = 0;
435
+ }
436
+ }
437
+
342
438
  [attributedString addAttribute:NSParagraphStyleAttributeName
343
439
  value:paragraphStyle
344
440
  range:NSMakeRange(0, text.length)];
@@ -46,6 +46,8 @@ export interface HighlightTextViewProps extends ViewProps {
46
46
  verticalAlign?: string;
47
47
  fontFamily?: string;
48
48
  fontSize?: string;
49
+ lineHeight?: string;
50
+ highlightBorderRadius?: string;
49
51
  padding?: string;
50
52
  paddingLeft?: string;
51
53
  paddingRight?: string;
@@ -28,6 +28,8 @@ export interface HighlightTextViewProps extends ViewProps {
28
28
  verticalAlign?: string;
29
29
  fontFamily?: string;
30
30
  fontSize?: string;
31
+ lineHeight?: string;
32
+ highlightBorderRadius?: string;
31
33
  padding?: string;
32
34
  paddingLeft?: string;
33
35
  paddingRight?: 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,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,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,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,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,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,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.4",
3
+ "version": "0.1.6",
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",
@@ -46,6 +46,8 @@ export interface HighlightTextViewProps extends ViewProps {
46
46
  verticalAlign?: string;
47
47
  fontFamily?: string;
48
48
  fontSize?: string;
49
+ lineHeight?: string;
50
+ highlightBorderRadius?: string;
49
51
  padding?: string;
50
52
  paddingLeft?: string;
51
53
  paddingRight?: string;