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.
- package/ios/HighlightTextView.h +1 -0
- package/ios/HighlightTextView.mm +124 -28
- package/lib/module/HighlightTextViewNativeComponent.ts +2 -0
- package/lib/typescript/src/HighlightTextViewNativeComponent.d.ts +2 -0
- package/lib/typescript/src/HighlightTextViewNativeComponent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/HighlightTextViewNativeComponent.ts +2 -0
package/ios/HighlightTextView.h
CHANGED
|
@@ -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
|
package/ios/HighlightTextView.mm
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
231
|
+
_currentHorizontalAlignment = NSTextAlignmentCenter;
|
|
173
232
|
} else if ([horizontalPart isEqualToString:@"right"] || [horizontalPart isEqualToString:@"flex-end"]) {
|
|
174
|
-
|
|
233
|
+
_currentHorizontalAlignment = NSTextAlignmentRight;
|
|
175
234
|
} else if ([horizontalPart isEqualToString:@"left"] || [horizontalPart isEqualToString:@"flex-start"]) {
|
|
176
|
-
|
|
235
|
+
_currentHorizontalAlignment = NSTextAlignmentLeft;
|
|
177
236
|
} else if ([horizontalPart isEqualToString:@"justify"]) {
|
|
178
|
-
|
|
237
|
+
_currentHorizontalAlignment = NSTextAlignmentJustified;
|
|
179
238
|
} else {
|
|
180
|
-
|
|
239
|
+
_currentHorizontalAlignment = NSTextAlignmentLeft;
|
|
181
240
|
}
|
|
241
|
+
_textView.textAlignment = _currentHorizontalAlignment;
|
|
182
242
|
}
|
|
183
243
|
|
|
184
|
-
//
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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.
|
|
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;
|