react-native-advanced-text 0.1.22 → 0.1.23

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.
@@ -9,7 +9,7 @@
9
9
 
10
10
  using namespace facebook::react;
11
11
 
12
- @interface AdvancedTextView () <RCTAdvancedTextViewViewProtocol, UIGestureRecognizerDelegate>
12
+ @interface AdvancedTextView () <RCTAdvancedTextViewViewProtocol, UIGestureRecognizerDelegate, UITextViewDelegate>
13
13
 
14
14
  @property (nonatomic, strong) UITextView *textView;
15
15
  @property (nonatomic, strong) NSMutableArray<NSDictionary *> *wordRanges;
@@ -23,21 +23,30 @@ using namespace facebook::react;
23
23
 
24
24
  + (ComponentDescriptorProvider)componentDescriptorProvider
25
25
  {
26
+ NSLog(@"[AdvancedTextView] componentDescriptorProvider called");
26
27
  return concreteComponentDescriptorProvider<AdvancedTextViewComponentDescriptor>();
27
28
  }
28
29
 
29
30
  - (instancetype)initWithFrame:(CGRect)frame
30
31
  {
32
+ NSLog(@"[AdvancedTextView] initWithFrame called");
31
33
  if (self = [super initWithFrame:frame]) {
32
- static const auto defaultProps = std::make_shared<const AdvancedTextViewProps>();
33
- _props = defaultProps;
34
+ @try {
35
+ static const auto defaultProps = std::make_shared<const AdvancedTextViewProps>();
36
+ _props = defaultProps;
34
37
 
35
- _wordRanges = [NSMutableArray array];
36
- _highlightColors = [NSMutableDictionary dictionary];
37
- _indicatorWordIndex = -1;
38
+ _wordRanges = [NSMutableArray array];
39
+ _highlightColors = [NSMutableDictionary dictionary];
40
+ _indicatorWordIndex = -1;
38
41
 
39
- [self setupTextView];
40
- [self setupGestureRecognizers];
42
+ [self setupTextView];
43
+ [self setupGestureRecognizers];
44
+
45
+ NSLog(@"[AdvancedTextView] Initialization successful");
46
+ } @catch (NSException *exception) {
47
+ NSLog(@"[AdvancedTextView] Exception in init: %@", exception);
48
+ @throw;
49
+ }
41
50
  }
42
51
 
43
52
  return self;
@@ -45,330 +54,538 @@ using namespace facebook::react;
45
54
 
46
55
  - (void)setupTextView
47
56
  {
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];
55
-
56
- self.contentView = _textView;
57
+ NSLog(@"[AdvancedTextView] setupTextView called");
58
+ @try {
59
+ _textView = [[UITextView alloc] initWithFrame:self.bounds];
60
+ _textView.editable = NO;
61
+ _textView.selectable = YES; // Allow text selection
62
+ _textView.scrollEnabled = YES;
63
+ _textView.backgroundColor = [UIColor clearColor];
64
+ _textView.textContainerInset = UIEdgeInsetsMake(8, 8, 8, 8);
65
+ _textView.font = [UIFont systemFontOfSize:16];
66
+ _textView.textColor = [UIColor labelColor];
67
+ _textView.delegate = self;
68
+
69
+ self.contentView = _textView;
70
+ NSLog(@"[AdvancedTextView] TextView setup successful");
71
+ } @catch (NSException *exception) {
72
+ NSLog(@"[AdvancedTextView] Exception in setupTextView: %@", exception);
73
+ @throw;
74
+ }
57
75
  }
58
76
 
59
77
  - (void)setupGestureRecognizers
60
78
  {
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];
67
-
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];
79
+ NSLog(@"[AdvancedTextView] setupGestureRecognizers called");
80
+ @try {
81
+ // Single tap for word selection
82
+ UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
83
+ initWithTarget:self
84
+ action:@selector(handleTap:)];
85
+ tapGesture.delegate = self;
86
+ [_textView addGestureRecognizer:tapGesture];
87
+
88
+ NSLog(@"[AdvancedTextView] Gesture recognizers setup successful");
89
+ } @catch (NSException *exception) {
90
+ NSLog(@"[AdvancedTextView] Exception in setupGestureRecognizers: %@", exception);
91
+ @throw;
92
+ }
74
93
  }
75
94
 
76
95
  - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
77
96
  {
78
- const auto &oldViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(_props);
79
- const auto &newViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(props);
97
+ NSLog(@"[AdvancedTextView] updateProps called");
98
+ @try {
99
+ const auto &oldViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(_props);
100
+ const auto &newViewProps = *std::static_pointer_cast<AdvancedTextViewProps const>(props);
101
+
102
+ BOOL textChanged = NO;
103
+ BOOL highlightsChanged = NO;
104
+ BOOL menuChanged = NO;
105
+ BOOL indicatorChanged = NO;
106
+
107
+ // Check text change
108
+ if (oldViewProps.text != newViewProps.text) {
109
+ textChanged = YES;
110
+ NSLog(@"[AdvancedTextView] Text changed: %s", newViewProps.text.c_str());
111
+ }
80
112
 
81
- // Update text
82
- if (oldViewProps.text != newViewProps.text) {
83
- NSString *text = [NSString stringWithUTF8String:newViewProps.text.c_str()];
84
- [self updateTextContent:text];
85
- }
113
+ // Check highlighted words change
114
+ if (oldViewProps.highlightedWords.size() != newViewProps.highlightedWords.size()) {
115
+ highlightsChanged = YES;
116
+ NSLog(@"[AdvancedTextView] Highlights size changed: %zu -> %zu",
117
+ oldViewProps.highlightedWords.size(), newViewProps.highlightedWords.size());
118
+ } else {
119
+ for (size_t i = 0; i < oldViewProps.highlightedWords.size(); i++) {
120
+ const auto &oldHW = oldViewProps.highlightedWords[i];
121
+ const auto &newHW = newViewProps.highlightedWords[i];
122
+ if (oldHW.index != newHW.index || oldHW.highlightColor != newHW.highlightColor) {
123
+ highlightsChanged = YES;
124
+ NSLog(@"[AdvancedTextView] Highlight changed at index %zu", i);
125
+ break;
126
+ }
127
+ }
128
+ }
86
129
 
87
- // Update highlighted words
88
- if (oldViewProps.highlightedWords != newViewProps.highlightedWords) {
89
- [self updateHighlightedWords:newViewProps.highlightedWords];
90
- }
130
+ // Check menu options change
131
+ if (oldViewProps.menuOptions.size() != newViewProps.menuOptions.size()) {
132
+ menuChanged = YES;
133
+ NSLog(@"[AdvancedTextView] Menu options size changed: %zu -> %zu",
134
+ oldViewProps.menuOptions.size(), newViewProps.menuOptions.size());
135
+ } else {
136
+ for (size_t i = 0; i < oldViewProps.menuOptions.size(); i++) {
137
+ if (oldViewProps.menuOptions[i] != newViewProps.menuOptions[i]) {
138
+ menuChanged = YES;
139
+ NSLog(@"[AdvancedTextView] Menu option changed at index %zu", i);
140
+ break;
141
+ }
142
+ }
143
+ }
91
144
 
92
- // Update menu options
93
- if (oldViewProps.menuOptions != newViewProps.menuOptions) {
94
- [self updateMenuOptions:newViewProps.menuOptions];
95
- }
145
+ // Check indicator change
146
+ if (oldViewProps.indicatorWordIndex != newViewProps.indicatorWordIndex) {
147
+ indicatorChanged = YES;
148
+ NSLog(@"[AdvancedTextView] Indicator changed: %d -> %d",
149
+ oldViewProps.indicatorWordIndex, newViewProps.indicatorWordIndex);
150
+ }
96
151
 
97
- // Update indicator word index
98
- if (oldViewProps.indicatorWordIndex != newViewProps.indicatorWordIndex) {
99
- _indicatorWordIndex = newViewProps.indicatorWordIndex;
100
- [self updateTextAppearance];
101
- }
152
+ // Apply updates
153
+ if (textChanged) {
154
+ NSString *text = [NSString stringWithUTF8String:newViewProps.text.c_str()];
155
+ [self updateTextContent:text];
156
+ }
157
+
158
+ if (highlightsChanged) {
159
+ [self updateHighlightedWords:newViewProps.highlightedWords];
160
+ }
161
+
162
+ if (menuChanged) {
163
+ [self updateMenuOptions:newViewProps.menuOptions];
164
+ }
102
165
 
103
- [super updateProps:props oldProps:oldProps];
166
+ if (indicatorChanged) {
167
+ _indicatorWordIndex = newViewProps.indicatorWordIndex;
168
+ [self updateTextAppearance];
169
+ }
170
+
171
+ [super updateProps:props oldProps:oldProps];
172
+ NSLog(@"[AdvancedTextView] updateProps completed successfully");
173
+ } @catch (NSException *exception) {
174
+ NSLog(@"[AdvancedTextView] Exception in updateProps: %@, reason: %@",
175
+ exception.name, exception.reason);
176
+ @throw;
177
+ }
104
178
  }
105
179
 
106
180
  - (void)updateTextContent:(NSString *)text
107
181
  {
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;
182
+ NSLog(@"[AdvancedTextView] updateTextContent called with text length: %lu",
183
+ (unsigned long)text.length);
184
+ @try {
185
+ if (!text) {
186
+ NSLog(@"[AdvancedTextView] Text is nil, skipping update");
187
+ return;
121
188
  }
122
189
 
123
- if (searchRange.location >= text.length) break;
190
+ // IMPORTANT: Set the text first!
191
+ _textView.text = text;
192
+ NSLog(@"[AdvancedTextView] Set textView.text with length: %lu", (unsigned long)_textView.text.length);
124
193
 
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
- }
194
+ // Parse text into words and their ranges
195
+ [_wordRanges removeAllObjects];
131
196
 
132
- NSRange wordRange = NSMakeRange(wordStart, searchRange.location - wordStart);
133
- NSString *word = [text substringWithRange:wordRange];
197
+ NSRange searchRange = NSMakeRange(0, text.length);
198
+ NSCharacterSet *whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
134
199
 
135
- [_wordRanges addObject:@{
136
- @"word": word,
137
- @"range": [NSValue valueWithRange:wordRange],
138
- @"index": @(wordIndex)
139
- }];
200
+ NSInteger wordIndex = 0;
201
+ while (searchRange.location < text.length) {
202
+ // Skip whitespace
203
+ while (searchRange.location < text.length &&
204
+ [whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
205
+ searchRange.location++;
206
+ searchRange.length = text.length - searchRange.location;
207
+ }
140
208
 
141
- wordIndex++;
142
- searchRange.length = text.length - searchRange.location;
143
- }
209
+ if (searchRange.location >= text.length) break;
144
210
 
145
- [self updateTextAppearance];
146
- }
211
+ // Find word end
212
+ NSUInteger wordStart = searchRange.location;
213
+ while (searchRange.location < text.length &&
214
+ ![whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
215
+ searchRange.location++;
216
+ }
147
217
 
148
- - (void)updateHighlightedWords:(const std::vector<AdvancedTextViewHighlightedWordsStruct> &)highlightedWords
149
- {
150
- [_highlightColors removeAllObjects];
218
+ NSRange wordRange = NSMakeRange(wordStart, searchRange.location - wordStart);
219
+ NSString *word = [text substringWithRange:wordRange];
151
220
 
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];
221
+ [_wordRanges addObject:@{
222
+ @"word": word,
223
+ @"range": [NSValue valueWithRange:wordRange],
224
+ @"index": @(wordIndex)
225
+ }];
156
226
 
157
- if (color) {
158
- _highlightColors[@(index)] = color;
227
+ wordIndex++;
228
+ searchRange.length = text.length - searchRange.location;
159
229
  }
230
+
231
+ NSLog(@"[AdvancedTextView] Parsed %ld words", (long)_wordRanges.count);
232
+ [self updateTextAppearance];
233
+ } @catch (NSException *exception) {
234
+ NSLog(@"[AdvancedTextView] Exception in updateTextContent: %@", exception);
235
+ @throw;
160
236
  }
237
+ }
238
+
239
+ - (void)updateHighlightedWords:(const std::vector<AdvancedTextViewHighlightedWordsStruct> &)highlightedWords
240
+ {
241
+ NSLog(@"[AdvancedTextView] updateHighlightedWords called with %zu highlights",
242
+ highlightedWords.size());
243
+ @try {
244
+ [_highlightColors removeAllObjects];
245
+
246
+ for (const auto &hw : highlightedWords) {
247
+ NSInteger index = hw.index;
248
+ NSString *colorString = [NSString stringWithUTF8String:hw.highlightColor.c_str()];
249
+ UIColor *color = [self hexStringToColor:colorString];
250
+
251
+ if (color) {
252
+ _highlightColors[@(index)] = color;
253
+ NSLog(@"[AdvancedTextView] Added highlight for word %ld with color %@",
254
+ (long)index, colorString);
255
+ } else {
256
+ NSLog(@"[AdvancedTextView] Failed to parse color: %@", colorString);
257
+ }
258
+ }
161
259
 
162
- [self updateTextAppearance];
260
+ [self updateTextAppearance];
261
+ } @catch (NSException *exception) {
262
+ NSLog(@"[AdvancedTextView] Exception in updateHighlightedWords: %@", exception);
263
+ @throw;
264
+ }
163
265
  }
164
266
 
165
267
  - (void)updateMenuOptions:(const std::vector<std::string> &)options
166
268
  {
167
- NSMutableArray *menuArray = [NSMutableArray array];
168
- for (const auto &option : options) {
169
- [menuArray addObject:[NSString stringWithUTF8String:option.c_str()]];
269
+ NSLog(@"[AdvancedTextView] updateMenuOptions called with %zu options", options.size());
270
+ @try {
271
+ NSMutableArray *menuArray = [NSMutableArray array];
272
+ for (const auto &option : options) {
273
+ NSString *optionStr = [NSString stringWithUTF8String:option.c_str()];
274
+ [menuArray addObject:optionStr];
275
+ NSLog(@"[AdvancedTextView] Added menu option: %@", optionStr);
276
+ }
277
+ _menuOptions = [menuArray copy];
278
+ } @catch (NSException *exception) {
279
+ NSLog(@"[AdvancedTextView] Exception in updateMenuOptions: %@", exception);
280
+ @throw;
170
281
  }
171
- _menuOptions = [menuArray copy];
172
282
  }
173
283
 
174
284
  - (void)updateTextAppearance
175
285
  {
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];
286
+ NSLog(@"[AdvancedTextView] updateTextAppearance called");
287
+ @try {
288
+ if (_wordRanges.count == 0) {
289
+ NSLog(@"[AdvancedTextView] No word ranges, skipping appearance update");
290
+ return;
201
291
  }
202
292
 
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];
293
+ if (!_textView.text || _textView.text.length == 0) {
294
+ NSLog(@"[AdvancedTextView] TextView has no text");
295
+ return;
211
296
  }
212
- }
213
297
 
214
- _textView.attributedText = attributedString;
298
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
299
+ initWithString:_textView.text];
300
+
301
+ // Apply default attributes
302
+ [attributedString addAttribute:NSFontAttributeName
303
+ value:[UIFont systemFontOfSize:16]
304
+ range:NSMakeRange(0, attributedString.length)];
305
+
306
+ [attributedString addAttribute:NSForegroundColorAttributeName
307
+ value:[UIColor labelColor]
308
+ range:NSMakeRange(0, attributedString.length)];
309
+
310
+ // Apply highlights
311
+ for (NSDictionary *wordInfo in _wordRanges) {
312
+ NSNumber *index = wordInfo[@"index"];
313
+ NSValue *rangeValue = wordInfo[@"range"];
314
+ NSRange range = [rangeValue rangeValue];
315
+
316
+ // Validate range
317
+ if (range.location + range.length > attributedString.length) {
318
+ NSLog(@"[AdvancedTextView] Invalid range at index %@: {%lu, %lu} for string length %lu",
319
+ index, (unsigned long)range.location, (unsigned long)range.length,
320
+ (unsigned long)attributedString.length);
321
+ continue;
322
+ }
323
+
324
+ UIColor *highlightColor = _highlightColors[index];
325
+ if (highlightColor) {
326
+ [attributedString addAttribute:NSBackgroundColorAttributeName
327
+ value:highlightColor
328
+ range:range];
329
+ }
330
+
331
+ // Add background color indicator for indicated word
332
+ if (_indicatorWordIndex >= 0 && [index integerValue] == _indicatorWordIndex) {
333
+ // Use a semi-transparent blue background for the current word
334
+ UIColor *indicatorColor = [[UIColor systemBlueColor] colorWithAlphaComponent:0.3];
335
+ [attributedString addAttribute:NSBackgroundColorAttributeName
336
+ value:indicatorColor
337
+ range:range];
338
+ }
339
+ }
340
+
341
+ _textView.attributedText = attributedString;
342
+ NSLog(@"[AdvancedTextView] Text appearance updated successfully");
343
+ } @catch (NSException *exception) {
344
+ NSLog(@"[AdvancedTextView] Exception in updateTextAppearance: %@, reason: %@",
345
+ exception.name, exception.reason);
346
+ @throw;
347
+ }
215
348
  }
216
349
 
217
350
  - (void)handleTap:(UITapGestureRecognizer *)gesture
218
351
  {
219
- if (gesture.state != UIGestureRecognizerStateEnded) return;
352
+ NSLog(@"[AdvancedTextView] handleTap called");
353
+ @try {
354
+ if (gesture.state != UIGestureRecognizerStateEnded) return;
220
355
 
221
- CGPoint location = [gesture locationInView:_textView];
222
- NSInteger wordIndex = [self wordIndexAtPoint:location];
356
+ CGPoint location = [gesture locationInView:_textView];
357
+ NSInteger wordIndex = [self wordIndexAtPoint:location];
223
358
 
224
- if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
225
- NSDictionary *wordInfo = _wordRanges[wordIndex];
226
- NSString *word = wordInfo[@"word"];
359
+ NSLog(@"[AdvancedTextView] Tap at point: {%.2f, %.2f}, word index: %ld",
360
+ location.x, location.y, (long)wordIndex);
227
361
 
228
- [self emitWordPressEvent:word index:wordIndex];
362
+ // Dismiss any existing selection
363
+ _textView.selectedTextRange = nil;
364
+
365
+ if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
366
+ NSDictionary *wordInfo = _wordRanges[wordIndex];
367
+ NSString *word = wordInfo[@"word"];
368
+
369
+ NSLog(@"[AdvancedTextView] Word pressed: %@", word);
370
+ [self emitWordPressEvent:word index:wordIndex];
371
+ }
372
+ } @catch (NSException *exception) {
373
+ NSLog(@"[AdvancedTextView] Exception in handleTap: %@", exception);
229
374
  }
230
375
  }
231
376
 
232
- - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
377
+ #pragma mark - UITextViewDelegate
378
+
379
+ - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction
233
380
  {
234
- if (gesture.state != UIGestureRecognizerStateBegan) return;
381
+ return YES;
382
+ }
235
383
 
236
- CGPoint location = [gesture locationInView:_textView];
237
- NSInteger wordIndex = [self wordIndexAtPoint:location];
384
+ - (void)textViewDidChangeSelection:(UITextView *)textView
385
+ {
386
+ NSLog(@"[AdvancedTextView] Selection changed");
387
+
388
+ // Get selected text
389
+ NSString *selectedText = [textView.text substringWithRange:textView.selectedRange];
238
390
 
239
- if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
240
- NSDictionary *wordInfo = _wordRanges[wordIndex];
241
- NSString *word = wordInfo[@"word"];
391
+ if (selectedText.length > 0) {
392
+ NSLog(@"[AdvancedTextView] Selected text: %@", selectedText);
242
393
 
243
- [self showContextMenuForWord:word atIndex:wordIndex location:location];
394
+ // Add custom menu items
395
+ if (_menuOptions && _menuOptions.count > 0) {
396
+ [self setupCustomMenuItems];
397
+ }
244
398
  }
245
399
  }
246
400
 
247
- - (NSInteger)wordIndexAtPoint:(CGPoint)point
401
+ - (void)setupCustomMenuItems
248
402
  {
249
- // Adjust point for text container insets
250
- point.x -= _textView.textContainerInset.left;
251
- point.y -= _textView.textContainerInset.top;
403
+ NSLog(@"[AdvancedTextView] Setting up custom menu items");
404
+
405
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
406
+ NSMutableArray *customItems = [NSMutableArray array];
407
+
408
+ for (NSString *option in _menuOptions) {
409
+ UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:option
410
+ action:@selector(handleCustomMenuAction:)];
411
+ [customItems addObject:item];
412
+ }
252
413
 
253
- NSLayoutManager *layoutManager = _textView.layoutManager;
254
- NSTextContainer *textContainer = _textView.textContainer;
414
+ menuController.menuItems = customItems;
415
+ }
255
416
 
256
- NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
257
- inTextContainer:textContainer
258
- fractionOfDistanceBetweenInsertionPoints:nil];
417
+ - (void)handleCustomMenuAction:(UIMenuItem *)sender
418
+ {
419
+ NSLog(@"[AdvancedTextView] Custom menu action: %@", sender.title);
259
420
 
260
- // Find which word this character belongs to
261
- for (NSDictionary *wordInfo in _wordRanges) {
262
- NSValue *rangeValue = wordInfo[@"range"];
263
- NSRange range = [rangeValue rangeValue];
421
+ NSString *selectedText = [_textView.text substringWithRange:_textView.selectedRange];
422
+ [self emitSelectionEvent:selectedText menuOption:sender.title];
264
423
 
265
- if (NSLocationInRange(characterIndex, range)) {
266
- return [wordInfo[@"index"] integerValue];
267
- }
424
+ // Clear selection after action
425
+ _textView.selectedTextRange = nil;
426
+ }
427
+
428
+ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
429
+ {
430
+ // Allow custom menu items
431
+ if (action == @selector(handleCustomMenuAction:)) {
432
+ return YES;
433
+ }
434
+
435
+ // Allow default actions (copy, etc.)
436
+ if (action == @selector(copy:) ||
437
+ action == @selector(selectAll:) ||
438
+ action == @selector(select:)) {
439
+ return [super canPerformAction:action withSender:sender];
268
440
  }
269
441
 
270
- return -1;
442
+ return NO;
271
443
  }
272
444
 
273
- - (void)showContextMenuForWord:(NSString *)word atIndex:(NSInteger)index location:(CGPoint)location
445
+ - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
274
446
  {
275
- if (!_menuOptions || _menuOptions.count == 0) return;
447
+ // Removed - using native iOS text selection menu instead
448
+ }
276
449
 
277
- UIAlertController *alert = [UIAlertController alertControllerWithTitle:word
278
- message:nil
279
- preferredStyle:UIAlertControllerStyleActionSheet];
450
+ - (NSInteger)wordIndexAtPoint:(CGPoint)point
451
+ {
452
+ @try {
453
+ if (!_textView.layoutManager || !_textView.textContainer) {
454
+ NSLog(@"[AdvancedTextView] Layout manager or text container is nil");
455
+ return -1;
456
+ }
280
457
 
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
- }
458
+ // Adjust point for text container insets
459
+ point.x -= _textView.textContainerInset.left;
460
+ point.y -= _textView.textContainerInset.top;
289
461
 
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);
462
+ NSLayoutManager *layoutManager = _textView.layoutManager;
463
+ NSTextContainer *textContainer = _textView.textContainer;
464
+
465
+ NSUInteger characterIndex = [layoutManager characterIndexForPoint:point
466
+ inTextContainer:textContainer
467
+ fractionOfDistanceBetweenInsertionPoints:nil];
468
+
469
+ NSLog(@"[AdvancedTextView] Character index at point: %lu", (unsigned long)characterIndex);
470
+
471
+ // Find which word this character belongs to
472
+ for (NSDictionary *wordInfo in _wordRanges) {
473
+ NSValue *rangeValue = wordInfo[@"range"];
474
+ NSRange range = [rangeValue rangeValue];
475
+
476
+ if (NSLocationInRange(characterIndex, range)) {
477
+ return [wordInfo[@"index"] integerValue];
478
+ }
302
479
  }
303
480
 
304
- [rootVC presentViewController:alert animated:YES completion:nil];
481
+ return -1;
482
+ } @catch (NSException *exception) {
483
+ NSLog(@"[AdvancedTextView] Exception in wordIndexAtPoint: %@", exception);
484
+ return -1;
305
485
  }
306
486
  }
307
487
 
488
+ - (void)showContextMenuForWord:(NSString *)word atIndex:(NSInteger)index location:(CGPoint)location
489
+ {
490
+ // Removed - using native iOS text selection menu instead
491
+ }
492
+
308
493
  - (UIViewController *)findViewController
309
494
  {
310
- UIResponder *responder = self;
311
- while (responder) {
312
- if ([responder isKindOfClass:[UIViewController class]]) {
313
- return (UIViewController *)responder;
314
- }
315
- responder = [responder nextResponder];
316
- }
495
+ // Removed - no longer needed
317
496
  return nil;
318
497
  }
319
498
 
320
499
  - (void)emitWordPressEvent:(NSString *)word index:(NSInteger)index
321
500
  {
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);
501
+ NSLog(@"[AdvancedTextView] emitWordPressEvent: %@ at index: %ld", word, (long)index);
502
+ @try {
503
+ if (_eventEmitter) {
504
+ auto emitter = std::static_pointer_cast<const AdvancedTextViewEventEmitter>(_eventEmitter);
505
+
506
+ AdvancedTextViewEventEmitter::OnWordPress event;
507
+ event.word = [word UTF8String];
508
+ event.index = static_cast<int>(index);
509
+
510
+ emitter->onWordPress(event);
511
+ NSLog(@"[AdvancedTextView] Word press event emitted successfully");
512
+ } else {
513
+ NSLog(@"[AdvancedTextView] Event emitter is null");
514
+ }
515
+ } @catch (NSException *exception) {
516
+ NSLog(@"[AdvancedTextView] Exception in emitWordPressEvent: %@", exception);
330
517
  }
331
518
  }
332
519
 
333
520
  - (void)emitSelectionEvent:(NSString *)selectedText menuOption:(NSString *)option
334
521
  {
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);
522
+ NSLog(@"[AdvancedTextView] emitSelectionEvent: %@ with option: %@", selectedText, option);
523
+ @try {
524
+ if (_eventEmitter) {
525
+ auto emitter = std::static_pointer_cast<const AdvancedTextViewEventEmitter>(_eventEmitter);
526
+
527
+ AdvancedTextViewEventEmitter::OnSelection event;
528
+ event.selectedText = [selectedText UTF8String];
529
+ event.event = [option UTF8String];
530
+
531
+ emitter->onSelection(event);
532
+ NSLog(@"[AdvancedTextView] Selection event emitted successfully");
533
+ } else {
534
+ NSLog(@"[AdvancedTextView] Event emitter is null");
535
+ }
536
+ } @catch (NSException *exception) {
537
+ NSLog(@"[AdvancedTextView] Exception in emitSelectionEvent: %@", exception);
343
538
  }
344
539
  }
345
540
 
346
541
  - (void)layoutSubviews
347
542
  {
348
- [super layoutSubviews];
349
- _textView.frame = self.bounds;
543
+ NSLog(@"[AdvancedTextView] layoutSubviews called");
544
+ @try {
545
+ [super layoutSubviews];
546
+ _textView.frame = self.bounds;
547
+ } @catch (NSException *exception) {
548
+ NSLog(@"[AdvancedTextView] Exception in layoutSubviews: %@", exception);
549
+ }
350
550
  }
351
551
 
352
552
  - (UIColor *)hexStringToColor:(NSString *)stringToConvert
353
553
  {
354
- if (!stringToConvert || [stringToConvert length] == 0) return nil;
554
+ @try {
555
+ if (!stringToConvert || [stringToConvert length] == 0) {
556
+ NSLog(@"[AdvancedTextView] Empty color string");
557
+ return nil;
558
+ }
355
559
 
356
- NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
357
- NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
560
+ NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
561
+ NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
358
562
 
359
- unsigned hex;
360
- if (![stringScanner scanHexInt:&hex]) return nil;
563
+ unsigned hex;
564
+ if (![stringScanner scanHexInt:&hex]) {
565
+ NSLog(@"[AdvancedTextView] Failed to parse hex color: %@", stringToConvert);
566
+ return nil;
567
+ }
361
568
 
362
- int r = (hex >> 16) & 0xFF;
363
- int g = (hex >> 8) & 0xFF;
364
- int b = (hex) & 0xFF;
569
+ int r = (hex >> 16) & 0xFF;
570
+ int g = (hex >> 8) & 0xFF;
571
+ int b = (hex) & 0xFF;
365
572
 
366
- return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
573
+ return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
574
+ } @catch (NSException *exception) {
575
+ NSLog(@"[AdvancedTextView] Exception in hexStringToColor: %@", exception);
576
+ return nil;
577
+ }
367
578
  }
368
579
 
369
580
  Class<RCTComponentViewProtocol> AdvancedTextViewCls(void)
370
581
  {
582
+ NSLog(@"[AdvancedTextView] AdvancedTextViewCls called");
371
583
  return AdvancedTextView.class;
372
584
  }
373
585
 
586
+ - (void)dealloc
587
+ {
588
+ NSLog(@"[AdvancedTextView] dealloc called");
589
+ }
590
+
374
591
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-advanced-text",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": " Advanced text component for React Native with custom select options.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",