react-native-advanced-text 0.1.20 → 0.1.22
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.
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// File: AdvancedTextView.kt
|
|
2
1
|
package com.advancedtext
|
|
3
2
|
|
|
4
3
|
import android.content.Context
|
|
@@ -34,7 +33,6 @@ class AdvancedTextView : TextView {
|
|
|
34
33
|
private var currentText: String = ""
|
|
35
34
|
private var textColor: String = "#000000"
|
|
36
35
|
|
|
37
|
-
// Cache for word positions to avoid recalculating
|
|
38
36
|
private var wordPositions: List<WordPosition> = emptyList()
|
|
39
37
|
|
|
40
38
|
constructor(context: Context?) : super(context) { init() }
|
|
@@ -44,11 +42,11 @@ class AdvancedTextView : TextView {
|
|
|
44
42
|
private fun init() {
|
|
45
43
|
Log.d(TAG, "AdvancedTextView initialized")
|
|
46
44
|
|
|
47
|
-
// Set default properties
|
|
48
45
|
textSize = 16f
|
|
49
46
|
setPadding(16, 16, 16, 16)
|
|
50
47
|
movementMethod = LinkMovementMethod.getInstance()
|
|
51
48
|
setTextIsSelectable(true)
|
|
49
|
+
|
|
52
50
|
|
|
53
51
|
customSelectionActionModeCallback = object : ActionMode.Callback {
|
|
54
52
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
|
@@ -156,9 +154,7 @@ class AdvancedTextView : TextView {
|
|
|
156
154
|
|
|
157
155
|
val spannableString = SpannableString(currentText)
|
|
158
156
|
|
|
159
|
-
// Apply spans efficiently
|
|
160
157
|
wordPositions.forEach { wordPos ->
|
|
161
|
-
// Apply highlights
|
|
162
158
|
highlightedWords.find { it.index == wordPos.index }?.let { highlightedWord ->
|
|
163
159
|
val color = parseColor(highlightedWord.highlightColor)
|
|
164
160
|
spannableString.setSpan(
|
|
@@ -169,7 +165,6 @@ class AdvancedTextView : TextView {
|
|
|
169
165
|
)
|
|
170
166
|
}
|
|
171
167
|
|
|
172
|
-
// Apply indicator color
|
|
173
168
|
if (wordPos.index == indicatorWordIndex) {
|
|
174
169
|
spannableString.setSpan(
|
|
175
170
|
ForegroundColorSpan(Color.parseColor(textColor)),
|
|
@@ -179,7 +174,6 @@ class AdvancedTextView : TextView {
|
|
|
179
174
|
)
|
|
180
175
|
}
|
|
181
176
|
|
|
182
|
-
// Make words clickable
|
|
183
177
|
spannableString.setSpan(
|
|
184
178
|
WordClickableSpan(wordPos.index, wordPos.word),
|
|
185
179
|
wordPos.start,
|
|
@@ -188,7 +182,6 @@ class AdvancedTextView : TextView {
|
|
|
188
182
|
)
|
|
189
183
|
}
|
|
190
184
|
|
|
191
|
-
// Use post to ensure UI thread and avoid layout issues
|
|
192
185
|
post {
|
|
193
186
|
setText(spannableString, BufferType.SPANNABLE)
|
|
194
187
|
Log.d(TAG, "Text updated with ${wordPositions.size} spans")
|
|
@@ -225,14 +218,11 @@ class AdvancedTextView : TextView {
|
|
|
225
218
|
) : ClickableSpan() {
|
|
226
219
|
|
|
227
220
|
override fun onClick(widget: View) {
|
|
228
|
-
Log.d(TAG, "
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
Selection.removeSelection(it)
|
|
233
|
-
}
|
|
221
|
+
Log.d(TAG, "WordClickableSpan onClick triggered: '$word' (index=$wordIndex)")
|
|
222
|
+
|
|
223
|
+
widget.post {
|
|
224
|
+
sendWordPressEvent(word, wordIndex)
|
|
234
225
|
}
|
|
235
|
-
sendWordPressEvent(word, wordIndex)
|
|
236
226
|
}
|
|
237
227
|
|
|
238
228
|
override fun updateDrawState(ds: TextPaint) {
|
package/ios/AdvancedTextView.h
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
#ifndef AdvancedTextView_h
|
|
2
|
+
#define AdvancedTextView_h
|
|
3
|
+
|
|
1
4
|
#import <React/RCTViewComponentView.h>
|
|
2
5
|
#import <UIKit/UIKit.h>
|
|
3
6
|
|
|
4
|
-
#ifndef AdvancedTextViewNativeComponent_h
|
|
5
|
-
#define AdvancedTextViewNativeComponent_h
|
|
6
|
-
|
|
7
7
|
NS_ASSUME_NONNULL_BEGIN
|
|
8
8
|
|
|
9
9
|
@interface AdvancedTextView : RCTViewComponentView
|
|
10
|
+
|
|
10
11
|
@end
|
|
11
12
|
|
|
12
13
|
NS_ASSUME_NONNULL_END
|
|
13
14
|
|
|
14
|
-
#endif /*
|
|
15
|
+
#endif /* AdvancedTextView_h */
|
package/ios/AdvancedTextView.mm
CHANGED
|
@@ -9,13 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
using namespace facebook::react;
|
|
11
11
|
|
|
12
|
-
@interface AdvancedTextView () <RCTAdvancedTextViewViewProtocol>
|
|
12
|
+
@interface AdvancedTextView () <RCTAdvancedTextViewViewProtocol, UIGestureRecognizerDelegate>
|
|
13
|
+
|
|
14
|
+
@property (nonatomic, strong) UITextView *textView;
|
|
15
|
+
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *wordRanges;
|
|
16
|
+
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIColor *> *highlightColors;
|
|
17
|
+
@property (nonatomic, strong) NSArray<NSString *> *menuOptions;
|
|
18
|
+
@property (nonatomic, assign) NSInteger indicatorWordIndex;
|
|
13
19
|
|
|
14
20
|
@end
|
|
15
21
|
|
|
16
|
-
@implementation AdvancedTextView
|
|
17
|
-
UIView * _view;
|
|
18
|
-
}
|
|
22
|
+
@implementation AdvancedTextView
|
|
19
23
|
|
|
20
24
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
21
25
|
{
|
|
@@ -24,16 +28,49 @@ using namespace facebook::react;
|
|
|
24
28
|
|
|
25
29
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
26
30
|
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
if (self = [super initWithFrame:frame]) {
|
|
32
|
+
static const auto defaultProps = std::make_shared<const AdvancedTextViewProps>();
|
|
33
|
+
_props = defaultProps;
|
|
34
|
+
|
|
35
|
+
_wordRanges = [NSMutableArray array];
|
|
36
|
+
_highlightColors = [NSMutableDictionary dictionary];
|
|
37
|
+
_indicatorWordIndex = -1;
|
|
38
|
+
|
|
39
|
+
[self setupTextView];
|
|
40
|
+
[self setupGestureRecognizers];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return self;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (void)setupTextView
|
|
47
|
+
{
|
|
48
|
+
_textView = [[UITextView alloc] initWithFrame:self.bounds];
|
|
49
|
+
_textView.editable = NO;
|
|
50
|
+
_textView.scrollEnabled = YES;
|
|
51
|
+
_textView.backgroundColor = [UIColor clearColor];
|
|
52
|
+
_textView.textContainerInset = UIEdgeInsetsMake(8, 8, 8, 8);
|
|
53
|
+
_textView.font = [UIFont systemFontOfSize:16];
|
|
54
|
+
_textView.textColor = [UIColor labelColor];
|
|
30
55
|
|
|
31
|
-
|
|
56
|
+
self.contentView = _textView;
|
|
57
|
+
}
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
- (void)setupGestureRecognizers
|
|
60
|
+
{
|
|
61
|
+
// Single tap for word selection
|
|
62
|
+
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
|
|
63
|
+
initWithTarget:self
|
|
64
|
+
action:@selector(handleTap:)];
|
|
65
|
+
tapGesture.delegate = self;
|
|
66
|
+
[_textView addGestureRecognizer:tapGesture];
|
|
35
67
|
|
|
36
|
-
|
|
68
|
+
// Long press for context menu
|
|
69
|
+
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc]
|
|
70
|
+
initWithTarget:self
|
|
71
|
+
action:@selector(handleLongPress:)];
|
|
72
|
+
longPressGesture.delegate = self;
|
|
73
|
+
[_textView addGestureRecognizer:longPressGesture];
|
|
37
74
|
}
|
|
38
75
|
|
|
39
76
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
@@ -41,26 +78,287 @@ using namespace facebook::react;
|
|
|
41
78
|
const auto &oldViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(_props);
|
|
42
79
|
const auto &newViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(props);
|
|
43
80
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
81
|
+
// Update text
|
|
82
|
+
if (oldViewProps.text != newViewProps.text) {
|
|
83
|
+
NSString *text = [NSString stringWithUTF8String:newViewProps.text.c_str()];
|
|
84
|
+
[self updateTextContent:text];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Update highlighted words
|
|
88
|
+
if (oldViewProps.highlightedWords != newViewProps.highlightedWords) {
|
|
89
|
+
[self updateHighlightedWords:newViewProps.highlightedWords];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Update menu options
|
|
93
|
+
if (oldViewProps.menuOptions != newViewProps.menuOptions) {
|
|
94
|
+
[self updateMenuOptions:newViewProps.menuOptions];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Update indicator word index
|
|
98
|
+
if (oldViewProps.indicatorWordIndex != newViewProps.indicatorWordIndex) {
|
|
99
|
+
_indicatorWordIndex = newViewProps.indicatorWordIndex;
|
|
100
|
+
[self updateTextAppearance];
|
|
47
101
|
}
|
|
48
102
|
|
|
49
103
|
[super updateProps:props oldProps:oldProps];
|
|
50
104
|
}
|
|
51
105
|
|
|
52
|
-
|
|
106
|
+
- (void)updateTextContent:(NSString *)text
|
|
53
107
|
{
|
|
54
|
-
|
|
108
|
+
// Parse text into words and their ranges
|
|
109
|
+
[_wordRanges removeAllObjects];
|
|
110
|
+
|
|
111
|
+
NSRange searchRange = NSMakeRange(0, text.length);
|
|
112
|
+
NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
113
|
+
|
|
114
|
+
NSInteger wordIndex = 0;
|
|
115
|
+
while (searchRange.location < text.length) {
|
|
116
|
+
// Skip whitespace
|
|
117
|
+
while (searchRange.location < text.length &&
|
|
118
|
+
[whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
|
|
119
|
+
searchRange.location++;
|
|
120
|
+
searchRange.length = text.length - searchRange.location;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (searchRange.location >= text.length) break;
|
|
124
|
+
|
|
125
|
+
// Find word end
|
|
126
|
+
NSUInteger wordStart = searchRange.location;
|
|
127
|
+
while (searchRange.location < text.length &&
|
|
128
|
+
![whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
|
|
129
|
+
searchRange.location++;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
NSRange wordRange = NSMakeRange(wordStart, searchRange.location - wordStart);
|
|
133
|
+
NSString *word = [text substringWithRange:wordRange];
|
|
134
|
+
|
|
135
|
+
[_wordRanges addObject:@{
|
|
136
|
+
@"word": word,
|
|
137
|
+
@"range": [NSValue valueWithRange:wordRange],
|
|
138
|
+
@"index": @(wordIndex)
|
|
139
|
+
}];
|
|
140
|
+
|
|
141
|
+
wordIndex++;
|
|
142
|
+
searchRange.length = text.length - searchRange.location;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
[self updateTextAppearance];
|
|
55
146
|
}
|
|
56
147
|
|
|
57
|
-
-
|
|
148
|
+
- (void)updateHighlightedWords:(const std::vector<AdvancedTextViewHighlightedWordsStruct> &)highlightedWords
|
|
58
149
|
{
|
|
150
|
+
[_highlightColors removeAllObjects];
|
|
151
|
+
|
|
152
|
+
for (const auto &hw : highlightedWords) {
|
|
153
|
+
NSInteger index = hw.index;
|
|
154
|
+
NSString *colorString = [NSString stringWithUTF8String:hw.highlightColor.c_str()];
|
|
155
|
+
UIColor *color = [self hexStringToColor:colorString];
|
|
156
|
+
|
|
157
|
+
if (color) {
|
|
158
|
+
_highlightColors[@(index)] = color;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
[self updateTextAppearance];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
- (void)updateMenuOptions:(const std::vector<std::string> &)options
|
|
166
|
+
{
|
|
167
|
+
NSMutableArray *menuArray = [NSMutableArray array];
|
|
168
|
+
for (const auto &option : options) {
|
|
169
|
+
[menuArray addObject:[NSString stringWithUTF8String:option.c_str()]];
|
|
170
|
+
}
|
|
171
|
+
_menuOptions = [menuArray copy];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
- (void)updateTextAppearance
|
|
175
|
+
{
|
|
176
|
+
if (_wordRanges.count == 0) return;
|
|
177
|
+
|
|
178
|
+
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
|
|
179
|
+
initWithString:_textView.text];
|
|
180
|
+
|
|
181
|
+
// Apply default attributes
|
|
182
|
+
[attributedString addAttribute:NSFontAttributeName
|
|
183
|
+
value:[UIFont systemFontOfSize:16]
|
|
184
|
+
range:NSMakeRange(0, attributedString.length)];
|
|
185
|
+
|
|
186
|
+
[attributedString addAttribute:NSForegroundColorAttributeName
|
|
187
|
+
value:[UIColor labelColor]
|
|
188
|
+
range:NSMakeRange(0, attributedString.length)];
|
|
189
|
+
|
|
190
|
+
// Apply highlights
|
|
191
|
+
for (NSDictionary *wordInfo in _wordRanges) {
|
|
192
|
+
NSNumber *index = wordInfo[@"index"];
|
|
193
|
+
NSValue *rangeValue = wordInfo[@"range"];
|
|
194
|
+
NSRange range = [rangeValue rangeValue];
|
|
195
|
+
|
|
196
|
+
UIColor *highlightColor = _highlightColors[index];
|
|
197
|
+
if (highlightColor) {
|
|
198
|
+
[attributedString addAttribute:NSBackgroundColorAttributeName
|
|
199
|
+
value:highlightColor
|
|
200
|
+
range:range];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Add indicator (underline or special formatting) for indicated word
|
|
204
|
+
if (_indicatorWordIndex >= 0 && [index integerValue] == _indicatorWordIndex) {
|
|
205
|
+
[attributedString addAttribute:NSUnderlineStyleAttributeName
|
|
206
|
+
value:@(NSUnderlineStyleSingle)
|
|
207
|
+
range:range];
|
|
208
|
+
[attributedString addAttribute:NSUnderlineColorAttributeName
|
|
209
|
+
value:[UIColor systemBlueColor]
|
|
210
|
+
range:range];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
_textView.attributedText = attributedString;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
- (void)handleTap:(UITapGestureRecognizer *)gesture
|
|
218
|
+
{
|
|
219
|
+
if (gesture.state != UIGestureRecognizerStateEnded) return;
|
|
220
|
+
|
|
221
|
+
CGPoint location = [gesture locationInView:_textView];
|
|
222
|
+
NSInteger wordIndex = [self wordIndexAtPoint:location];
|
|
223
|
+
|
|
224
|
+
if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
|
|
225
|
+
NSDictionary *wordInfo = _wordRanges[wordIndex];
|
|
226
|
+
NSString *word = wordInfo[@"word"];
|
|
227
|
+
|
|
228
|
+
[self emitWordPressEvent:word index:wordIndex];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
|
|
233
|
+
{
|
|
234
|
+
if (gesture.state != UIGestureRecognizerStateBegan) return;
|
|
235
|
+
|
|
236
|
+
CGPoint location = [gesture locationInView:_textView];
|
|
237
|
+
NSInteger wordIndex = [self wordIndexAtPoint:location];
|
|
238
|
+
|
|
239
|
+
if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
|
|
240
|
+
NSDictionary *wordInfo = _wordRanges[wordIndex];
|
|
241
|
+
NSString *word = wordInfo[@"word"];
|
|
242
|
+
|
|
243
|
+
[self showContextMenuForWord:word atIndex:wordIndex location:location];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
- (NSInteger)wordIndexAtPoint:(CGPoint)point
|
|
248
|
+
{
|
|
249
|
+
// Adjust point for text container insets
|
|
250
|
+
point.x -= _textView.textContainerInset.left;
|
|
251
|
+
point.y -= _textView.textContainerInset.top;
|
|
252
|
+
|
|
253
|
+
NSLayoutManager *layoutManager = _textView.layoutManager;
|
|
254
|
+
NSTextContainer *textContainer = _textView.textContainer;
|
|
255
|
+
|
|
256
|
+
NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
|
|
257
|
+
inTextContainer:textContainer
|
|
258
|
+
fractionOfDistanceBetweenInsertionPoints:nil];
|
|
259
|
+
|
|
260
|
+
// Find which word this character belongs to
|
|
261
|
+
for (NSDictionary *wordInfo in _wordRanges) {
|
|
262
|
+
NSValue *rangeValue = wordInfo[@"range"];
|
|
263
|
+
NSRange range = [rangeValue rangeValue];
|
|
264
|
+
|
|
265
|
+
if (NSLocationInRange(characterIndex, range)) {
|
|
266
|
+
return [wordInfo[@"index"] integerValue];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return -1;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
- (void)showContextMenuForWord:(NSString *)word atIndex:(NSInteger)index location:(CGPoint)location
|
|
274
|
+
{
|
|
275
|
+
if (!_menuOptions || _menuOptions.count == 0) return;
|
|
276
|
+
|
|
277
|
+
UIAlertController *alert = [UIAlertController alertControllerWithTitle:word
|
|
278
|
+
message:nil
|
|
279
|
+
preferredStyle:UIAlertControllerStyleActionSheet];
|
|
280
|
+
|
|
281
|
+
for (NSString *option in _menuOptions) {
|
|
282
|
+
UIAlertAction *action = [UIAlertAction actionWithTitle:option
|
|
283
|
+
style:UIAlertActionStyleDefault
|
|
284
|
+
handler:^(UIAlertAction * _Nonnull action) {
|
|
285
|
+
[self emitSelectionEvent:word menuOption:option];
|
|
286
|
+
}];
|
|
287
|
+
[alert addAction:action];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
|
|
291
|
+
style:UIAlertActionStyleCancel
|
|
292
|
+
handler:nil];
|
|
293
|
+
[alert addAction:cancelAction];
|
|
294
|
+
|
|
295
|
+
// Present from the root view controller
|
|
296
|
+
UIViewController *rootVC = [self findViewController];
|
|
297
|
+
if (rootVC) {
|
|
298
|
+
// For iPad, set up popover presentation
|
|
299
|
+
if (alert.popoverPresentationController) {
|
|
300
|
+
alert.popoverPresentationController.sourceView = _textView;
|
|
301
|
+
alert.popoverPresentationController.sourceRect = CGRectMake(location.x, location.y, 1, 1);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
[rootVC presentViewController:alert animated:YES completion:nil];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
- (UIViewController *)findViewController
|
|
309
|
+
{
|
|
310
|
+
UIResponder *responder = self;
|
|
311
|
+
while (responder) {
|
|
312
|
+
if ([responder isKindOfClass:[UIViewController class]]) {
|
|
313
|
+
return (UIViewController *)responder;
|
|
314
|
+
}
|
|
315
|
+
responder = [responder nextResponder];
|
|
316
|
+
}
|
|
317
|
+
return nil;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
- (void)emitWordPressEvent:(NSString *)word index:(NSInteger)index
|
|
321
|
+
{
|
|
322
|
+
if (_eventEmitter) {
|
|
323
|
+
auto emitter = std::static_pointer_cast<const AdvancedTextViewEventEmitter>(_eventEmitter);
|
|
324
|
+
|
|
325
|
+
AdvancedTextViewEventEmitter::OnWordPress event;
|
|
326
|
+
event.word = [word UTF8String];
|
|
327
|
+
event.index = static_cast<int>(index);
|
|
328
|
+
|
|
329
|
+
emitter->onWordPress(event);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
- (void)emitSelectionEvent:(NSString *)selectedText menuOption:(NSString *)option
|
|
334
|
+
{
|
|
335
|
+
if (_eventEmitter) {
|
|
336
|
+
auto emitter = std::static_pointer_cast<const AdvancedTextViewEventEmitter>(_eventEmitter);
|
|
337
|
+
|
|
338
|
+
AdvancedTextViewEventEmitter::OnSelection event;
|
|
339
|
+
event.selectedText = [selectedText UTF8String];
|
|
340
|
+
event.event = [option UTF8String];
|
|
341
|
+
|
|
342
|
+
emitter->onSelection(event);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
- (void)layoutSubviews
|
|
347
|
+
{
|
|
348
|
+
[super layoutSubviews];
|
|
349
|
+
_textView.frame = self.bounds;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
- (UIColor *)hexStringToColor:(NSString *)stringToConvert
|
|
353
|
+
{
|
|
354
|
+
if (!stringToConvert || [stringToConvert length] == 0) return nil;
|
|
355
|
+
|
|
59
356
|
NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
|
|
60
357
|
NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
|
|
61
358
|
|
|
62
359
|
unsigned hex;
|
|
63
360
|
if (![stringScanner scanHexInt:&hex]) return nil;
|
|
361
|
+
|
|
64
362
|
int r = (hex >> 16) & 0xFF;
|
|
65
363
|
int g = (hex >> 8) & 0xFF;
|
|
66
364
|
int b = (hex) & 0xFF;
|
|
@@ -68,4 +366,9 @@ Class<RCTComponentViewProtocol> AdvancedTextViewCls(void)
|
|
|
68
366
|
return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
|
|
69
367
|
}
|
|
70
368
|
|
|
369
|
+
Class<RCTComponentViewProtocol> AdvancedTextViewCls(void)
|
|
370
|
+
{
|
|
371
|
+
return AdvancedTextView.class;
|
|
372
|
+
}
|
|
373
|
+
|
|
71
374
|
@end
|
package/package.json
CHANGED