react-native-advanced-text 0.1.26 → 0.1.28

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.
@@ -10,7 +10,6 @@
10
10
  using namespace facebook::react;
11
11
 
12
12
 
13
- // Forward declaration
14
13
  @class AdvancedTextView;
15
14
 
16
15
  @interface AdvancedTextView () <RCTAdvancedTextViewViewProtocol, UIGestureRecognizerDelegate, UITextViewDelegate>
@@ -19,14 +18,17 @@ using namespace facebook::react;
19
18
  @property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIColor *> *highlightColors;
20
19
  @property (nonatomic, strong) NSArray<NSString *> *menuOptions;
21
20
  @property (nonatomic, assign) NSInteger indicatorWordIndex;
21
+ @property (nonatomic, assign) CGFloat fontSize;
22
+ @property (nonatomic, strong) NSString *fontWeight;
23
+ @property (nonatomic, strong) UIColor *textColor;
24
+ @property (nonatomic, strong) NSString *textAlign;
25
+ @property (nonatomic, strong) NSString *fontFamily;
22
26
 
23
- // ✅ ADD THIS LINE
24
27
  - (void)handleCustomMenuAction:(UIMenuItem *)sender;
25
28
 
26
29
  @end
27
30
 
28
31
 
29
- // Custom UITextView subclass to override menu behavior
30
32
  @interface CustomTextView : UITextView
31
33
  @property (nonatomic, weak) AdvancedTextView *parentView;
32
34
  @end
@@ -37,22 +39,18 @@ using namespace facebook::react;
37
39
  {
38
40
  NSLog(@"[CustomTextView] canPerformAction: %@", NSStringFromSelector(action));
39
41
 
40
- // Only allow our custom menu actions
41
42
  if (action == @selector(handleCustomMenuAction:)) {
42
43
  NSLog(@"[CustomTextView] ✅ Allowing custom action");
43
44
  return YES;
44
45
  }
45
46
 
46
- // Block ALL system actions
47
47
  NSLog(@"[CustomTextView] ❌ Blocking system action: %@", NSStringFromSelector(action));
48
48
  return NO;
49
49
  }
50
50
 
51
51
  - (void)handleCustomMenuAction:(UIMenuItem *)sender
52
52
  {
53
- // Forward to parent view
54
53
  if (self.parentView) {
55
-
56
54
  [self.parentView handleCustomMenuAction:sender];
57
55
  }
58
56
  }
@@ -86,6 +84,11 @@ using namespace facebook::react;
86
84
  _wordRanges = [NSMutableArray array];
87
85
  _highlightColors = [NSMutableDictionary dictionary];
88
86
  _indicatorWordIndex = -1;
87
+ _fontSize = 16.0;
88
+ _fontWeight = @"normal";
89
+ _textColor = [UIColor labelColor];
90
+ _textAlign = @"left";
91
+ _fontFamily = @"System";
89
92
 
90
93
  [self setupTextView];
91
94
  [self setupGestureRecognizers];
@@ -127,7 +130,6 @@ using namespace facebook::react;
127
130
  {
128
131
  NSLog(@"[AdvancedTextView] setupGestureRecognizers called");
129
132
  @try {
130
- // Single tap for word selection
131
133
  UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
132
134
  initWithTarget:self
133
135
  action:@selector(handleTap:)];
@@ -152,14 +154,44 @@ using namespace facebook::react;
152
154
  BOOL highlightsChanged = NO;
153
155
  BOOL menuChanged = NO;
154
156
  BOOL indicatorChanged = NO;
157
+ BOOL styleChanged = NO;
158
+
159
+ if (oldViewProps.fontSize != newViewProps.fontSize && newViewProps.fontSize) {
160
+ NSLog(@"[AdvancedTextView] Updating fontSize to: %f", newViewProps.fontSize);
161
+ _fontSize = static_cast<CGFloat>(newViewProps.fontSize);
162
+ styleChanged = YES;
163
+ }
164
+
165
+ if (oldViewProps.textAlign != newViewProps.textAlign && !newViewProps.textAlign.empty()) {
166
+ NSLog(@"[AdvancedTextView] Updating textAlign to: %s", newViewProps.textAlign.c_str());
167
+ _textAlign = [NSString stringWithUTF8String:newViewProps.textAlign.c_str()];
168
+ styleChanged = YES;
169
+ }
170
+
171
+ if (oldViewProps.fontWeight != newViewProps.fontWeight && !newViewProps.fontWeight.empty()) {
172
+ NSLog(@"[AdvancedTextView] Updating fontWeight to: %s", newViewProps.fontWeight.c_str());
173
+ _fontWeight = [NSString stringWithUTF8String:newViewProps.fontWeight.c_str()];
174
+ styleChanged = YES;
175
+ }
176
+
177
+ if (oldViewProps.fontFamily != newViewProps.fontFamily && !newViewProps.fontFamily.empty()) {
178
+ NSLog(@"[AdvancedTextView] Updating fontFamily to: %s", newViewProps.fontFamily.c_str());
179
+ _fontFamily = [NSString stringWithUTF8String:newViewProps.fontFamily.c_str()];
180
+ styleChanged = YES;
181
+ }
182
+
183
+ if (oldViewProps.color != newViewProps.color && !newViewProps.color.empty()) {
184
+ NSLog(@"[AdvancedTextView] Updating color to: %s", newViewProps.color.c_str());
185
+ NSString *colorStr = [NSString stringWithUTF8String:newViewProps.color.c_str()];
186
+ _textColor = [self hexStringToColor:colorStr];
187
+ styleChanged = YES;
188
+ }
155
189
 
156
- // Check text change
157
190
  if (oldViewProps.text != newViewProps.text) {
158
191
  textChanged = YES;
159
192
  NSLog(@"[AdvancedTextView] Text changed");
160
193
  }
161
194
 
162
- // Check highlighted words change
163
195
  if (oldViewProps.highlightedWords.size() != newViewProps.highlightedWords.size()) {
164
196
  highlightsChanged = YES;
165
197
  } else {
@@ -173,7 +205,6 @@ using namespace facebook::react;
173
205
  }
174
206
  }
175
207
 
176
- // Check menu options change
177
208
  if (oldViewProps.menuOptions.size() != newViewProps.menuOptions.size()) {
178
209
  menuChanged = YES;
179
210
  } else {
@@ -185,12 +216,10 @@ using namespace facebook::react;
185
216
  }
186
217
  }
187
218
 
188
- // Check indicator change
189
219
  if (oldViewProps.indicatorWordIndex != newViewProps.indicatorWordIndex) {
190
220
  indicatorChanged = YES;
191
221
  }
192
222
 
193
- // Apply updates
194
223
  if (textChanged) {
195
224
  NSString *text = [NSString stringWithUTF8String:newViewProps.text.c_str()];
196
225
  [self updateTextContent:text];
@@ -209,6 +238,11 @@ using namespace facebook::react;
209
238
  [self updateTextAppearance];
210
239
  }
211
240
 
241
+ if (styleChanged) {
242
+ NSLog(@"[AdvancedTextView] Style properties changed, updating appearance");
243
+ [self updateTextAppearance];
244
+ }
245
+
212
246
  [super updateProps:props oldProps:oldProps];
213
247
  NSLog(@"[AdvancedTextView] updateProps completed successfully");
214
248
  } @catch (NSException *exception) {
@@ -229,7 +263,6 @@ using namespace facebook::react;
229
263
 
230
264
  _textView.text = text;
231
265
 
232
- // Parse text into words and their ranges
233
266
  [_wordRanges removeAllObjects];
234
267
 
235
268
  NSRange searchRange = NSMakeRange(0, text.length);
@@ -237,7 +270,6 @@ using namespace facebook::react;
237
270
 
238
271
  NSInteger wordIndex = 0;
239
272
  while (searchRange.location < text.length) {
240
- // Skip whitespace
241
273
  while (searchRange.location < text.length &&
242
274
  [whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
243
275
  searchRange.location++;
@@ -246,7 +278,6 @@ using namespace facebook::react;
246
278
 
247
279
  if (searchRange.location >= text.length) break;
248
280
 
249
- // Find word end
250
281
  NSUInteger wordStart = searchRange.location;
251
282
  while (searchRange.location < text.length &&
252
283
  ![whitespaceSet characterIsMember:[text characterAtIndex:searchRange.location]]) {
@@ -318,21 +349,41 @@ using namespace facebook::react;
318
349
  - (void)updateTextAppearance
319
350
  {
320
351
  @try {
321
- if (_wordRanges.count == 0 || !_textView.text || _textView.text.length == 0) {
352
+ if (!_textView.text || _textView.text.length == 0) {
322
353
  return;
323
354
  }
324
355
 
325
356
  NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
326
357
  initWithString:_textView.text];
327
358
 
359
+
360
+ UIFont *font = nil;
361
+
362
+ if (_fontFamily && _fontFamily.length > 0) {
363
+ font = [UIFont fontWithName:_fontFamily size:_fontSize > 0 ? _fontSize : 16.0];
364
+ }
365
+
366
+ if (!font) {
367
+ if (_fontWeight && [_fontWeight.lowercaseString isEqualToString:@"bold"]) {
368
+ font = [UIFont boldSystemFontOfSize:_fontSize > 0 ? _fontSize : 16.0];
369
+ } else if (_fontWeight && [_fontWeight.lowercaseString isEqualToString:@"italic"]) {
370
+ font = [UIFont italicSystemFontOfSize:_fontSize > 0 ? _fontSize : 16.0];
371
+ } else {
372
+ font = [UIFont systemFontOfSize:_fontSize > 0 ? _fontSize : 16.0];
373
+ }
374
+ }
375
+
328
376
  [attributedString addAttribute:NSFontAttributeName
329
- value:[UIFont systemFontOfSize:16]
377
+ value:font
330
378
  range:NSMakeRange(0, attributedString.length)];
331
379
 
380
+
381
+ UIColor *color = _textColor ?: [UIColor labelColor];
332
382
  [attributedString addAttribute:NSForegroundColorAttributeName
333
- value:[UIColor labelColor]
383
+ value:color
334
384
  range:NSMakeRange(0, attributedString.length)];
335
385
 
386
+
336
387
  for (NSDictionary *wordInfo in _wordRanges) {
337
388
  NSNumber *index = wordInfo[@"index"];
338
389
  NSValue *rangeValue = wordInfo[@"range"];
@@ -358,11 +409,25 @@ using namespace facebook::react;
358
409
  }
359
410
 
360
411
  _textView.attributedText = attributedString;
412
+
413
+ if (_textAlign) {
414
+ if ([_textAlign.lowercaseString isEqualToString:@"center"]) {
415
+ _textView.textAlignment = NSTextAlignmentCenter;
416
+ } else if ([_textAlign.lowercaseString isEqualToString:@"right"]) {
417
+ _textView.textAlignment = NSTextAlignmentRight;
418
+ } else {
419
+ _textView.textAlignment = NSTextAlignmentLeft;
420
+ }
421
+ } else {
422
+ _textView.textAlignment = NSTextAlignmentLeft;
423
+ }
424
+
361
425
  } @catch (NSException *exception) {
362
426
  NSLog(@"[AdvancedTextView] Exception in updateTextAppearance: %@", exception.reason);
363
427
  }
364
428
  }
365
429
 
430
+
366
431
  - (void)handleTap:(UITapGestureRecognizer *)gesture
367
432
  {
368
433
  @try {
@@ -371,7 +436,6 @@ using namespace facebook::react;
371
436
  CGPoint location = [gesture locationInView:_textView];
372
437
  NSInteger wordIndex = [self wordIndexAtPoint:location];
373
438
 
374
- // Dismiss any existing selection
375
439
  _textView.selectedTextRange = nil;
376
440
 
377
441
  if (wordIndex >= 0 && wordIndex < _wordRanges.count) {
@@ -464,6 +528,31 @@ using namespace facebook::react;
464
528
  }
465
529
  }
466
530
 
531
+ - (void)setFontSize:(CGFloat)fontSize {
532
+ _fontSize = fontSize;
533
+ [self updateTextAppearance];
534
+ }
535
+
536
+ - (void)setFontWeight:(NSString *)fontWeight {
537
+ _fontWeight = fontWeight;
538
+ [self updateTextAppearance];
539
+ }
540
+
541
+ - (void)setTextColor:(UIColor *)textColor {
542
+ _textColor = textColor;
543
+ [self updateTextAppearance];
544
+ }
545
+
546
+ - (void)setTextAlign:(NSString *)textAlign {
547
+ _textAlign = textAlign;
548
+ [self updateTextAppearance];
549
+ }
550
+
551
+ - (void)setFontFamily:(NSString *)fontFamily {
552
+ _fontFamily = fontFamily;
553
+ [self updateTextAppearance];
554
+ }
555
+
467
556
  - (void)emitWordPressEvent:(NSString *)word index:(NSInteger)index
468
557
  {
469
558
  NSLog(@"[AdvancedTextView] emitWordPressEvent: %@ at index: %ld", word, (long)index);
@@ -1,26 +1,26 @@
1
- /* eslint-disable prettier/prettier */
2
- import type { ViewProps } from 'react-native';
3
- import { codegenNativeComponent } from 'react-native';
4
- // @ts-ignore
5
- import type { DirectEventHandler, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
6
-
7
- interface HighlightedWord {
8
- index: Int32;
9
- highlightColor: string;
10
- }
11
-
12
- export interface NativeProps extends ViewProps {
13
- text: string;
14
- highlightedWords?: ReadonlyArray<HighlightedWord>;
15
- menuOptions?: ReadonlyArray<string>;
16
- onWordPress?: DirectEventHandler<{ word: string; index: Int32 }>;
17
- onSelection?: DirectEventHandler<{ selectedText: string; event: string }>;
18
- indicatorWordIndex?: Int32;
19
- fontSize?: Int32;
20
- fontWeight?: string;
21
- color?: string;
22
- textAlign?: string;
23
- fontFamily?: string;
24
- }
25
-
26
- export default codegenNativeComponent<NativeProps>('AdvancedTextView');
1
+ /* eslint-disable prettier/prettier */
2
+ import type { ViewProps } from 'react-native';
3
+ import { codegenNativeComponent } from 'react-native';
4
+ // @ts-ignore
5
+ import type { DirectEventHandler, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
6
+
7
+ interface HighlightedWord {
8
+ index: Int32;
9
+ highlightColor: string;
10
+ }
11
+
12
+ export interface NativeProps extends ViewProps {
13
+ text: string;
14
+ highlightedWords?: ReadonlyArray<HighlightedWord>;
15
+ menuOptions?: ReadonlyArray<string>;
16
+ onWordPress?: DirectEventHandler<{ word: string; index: Int32 }>;
17
+ onSelection?: DirectEventHandler<{ selectedText: string; event: string }>;
18
+ indicatorWordIndex?: Int32;
19
+ fontSize?: Int32;
20
+ fontWeight?: string;
21
+ color?: string;
22
+ textAlign?: string;
23
+ fontFamily?: string;
24
+ }
25
+
26
+ export default codegenNativeComponent<NativeProps>('AdvancedTextView');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-advanced-text",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
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",
@@ -1,26 +1,26 @@
1
- /* eslint-disable prettier/prettier */
2
- import type { ViewProps } from 'react-native';
3
- import { codegenNativeComponent } from 'react-native';
4
- // @ts-ignore
5
- import type { DirectEventHandler, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
6
-
7
- interface HighlightedWord {
8
- index: Int32;
9
- highlightColor: string;
10
- }
11
-
12
- export interface NativeProps extends ViewProps {
13
- text: string;
14
- highlightedWords?: ReadonlyArray<HighlightedWord>;
15
- menuOptions?: ReadonlyArray<string>;
16
- onWordPress?: DirectEventHandler<{ word: string; index: Int32 }>;
17
- onSelection?: DirectEventHandler<{ selectedText: string; event: string }>;
18
- indicatorWordIndex?: Int32;
19
- fontSize?: Int32;
20
- fontWeight?: string;
21
- color?: string;
22
- textAlign?: string;
23
- fontFamily?: string;
24
- }
25
-
26
- export default codegenNativeComponent<NativeProps>('AdvancedTextView');
1
+ /* eslint-disable prettier/prettier */
2
+ import type { ViewProps } from 'react-native';
3
+ import { codegenNativeComponent } from 'react-native';
4
+ // @ts-ignore
5
+ import type { DirectEventHandler, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
6
+
7
+ interface HighlightedWord {
8
+ index: Int32;
9
+ highlightColor: string;
10
+ }
11
+
12
+ export interface NativeProps extends ViewProps {
13
+ text: string;
14
+ highlightedWords?: ReadonlyArray<HighlightedWord>;
15
+ menuOptions?: ReadonlyArray<string>;
16
+ onWordPress?: DirectEventHandler<{ word: string; index: Int32 }>;
17
+ onSelection?: DirectEventHandler<{ selectedText: string; event: string }>;
18
+ indicatorWordIndex?: Int32;
19
+ fontSize?: Int32;
20
+ fontWeight?: string;
21
+ color?: string;
22
+ textAlign?: string;
23
+ fontFamily?: string;
24
+ }
25
+
26
+ export default codegenNativeComponent<NativeProps>('AdvancedTextView');