@momo-kits/calculator-keyboard 0.150.2-phuc.15 → 0.151.1-beta.2

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.
Files changed (30) hide show
  1. package/README.md +45 -3
  2. package/android/src/main/java/com/calculatorkeyboard/CalculatorKeyboardPackage.kt +1 -1
  3. package/android/src/main/java/com/calculatorkeyboard/CustomKeyboardView.kt +242 -108
  4. package/android/src/main/java/com/calculatorkeyboard/Event.kt +129 -0
  5. package/android/src/main/java/com/calculatorkeyboard/{RCTInputCalculator.kt → InputCalculatorViewManager.kt} +105 -33
  6. package/ios/CalculatorKeyboardView.h +32 -0
  7. package/ios/CalculatorKeyboardView.mm +274 -0
  8. package/ios/NativeInputCalculator.h +11 -0
  9. package/ios/NativeInputCalculator.mm +500 -0
  10. package/ios/Utils.h +10 -0
  11. package/ios/Utils.mm +25 -0
  12. package/package.json +21 -131
  13. package/react-native-calculator-keyboard.podspec +5 -4
  14. package/src/InputCalculatorNativeComponent.ts +71 -0
  15. package/src/index.tsx +93 -43
  16. package/ios/CalculatorKeyboardView.swift +0 -153
  17. package/ios/InputCalculator-Bridging-Header.h +0 -23
  18. package/ios/InputCalculator.m +0 -85
  19. package/ios/InputCalculator.swift +0 -158
  20. package/ios/extension.swift +0 -23
  21. package/lib/commonjs/index.js +0 -72
  22. package/lib/commonjs/index.js.map +0 -1
  23. package/lib/module/index.js +0 -67
  24. package/lib/module/index.js.map +0 -1
  25. package/lib/typescript/commonjs/package.json +0 -1
  26. package/lib/typescript/commonjs/src/index.d.ts +0 -23
  27. package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
  28. package/lib/typescript/module/package.json +0 -1
  29. package/lib/typescript/module/src/index.d.ts +0 -23
  30. package/lib/typescript/module/src/index.d.ts.map +0 -1
@@ -0,0 +1,500 @@
1
+ #import "NativeInputCalculator.h"
2
+ #import "CalculatorKeyboardView.h"
3
+
4
+ #import <React/RCTConversions.h>
5
+ #import <React/RCTFabricComponentsPlugins.h>
6
+ #import <react/renderer/components/CalculatorKeyboardSpecs/ComponentDescriptors.h>
7
+ #import <react/renderer/components/CalculatorKeyboardSpecs/EventEmitters.h>
8
+ #import <react/renderer/components/CalculatorKeyboardSpecs/Props.h>
9
+ #import <react/renderer/components/CalculatorKeyboardSpecs/RCTComponentViewHelpers.h>
10
+
11
+ #import "Utils.h"
12
+
13
+ using namespace facebook::react;
14
+
15
+ @interface NativeInputCalculator () <RCTNativeInputCalculatorViewProtocol>
16
+ @end
17
+
18
+ @implementation NativeInputCalculator {
19
+ UITextField *_textField;
20
+ CalculatorKeyboardView *_keyboardView;
21
+ NSString *_lastValue;
22
+ }
23
+
24
+ - (instancetype)initWithFrame:(CGRect)frame
25
+ {
26
+ if (self = [super initWithFrame:frame]) {
27
+ static const auto defaultProps = std::make_shared<const NativeInputCalculatorProps>();
28
+ _props = defaultProps;
29
+
30
+ // Create text field
31
+ _textField = [[UITextField alloc] initWithFrame:self.bounds];
32
+ _textField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
33
+ _textField.delegate = (id<UITextFieldDelegate>)self;
34
+
35
+ // Create keyboard view
36
+ CGFloat bottomInset = [self getBottomInset];
37
+ CGRect keyboardFrame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 240 + bottomInset);
38
+ _keyboardView = [[CalculatorKeyboardView alloc] initWithFrame:keyboardFrame];
39
+ _keyboardView.input = (id)self; // Bridge pattern
40
+
41
+ // Set custom keyboard
42
+ _textField.inputView = _keyboardView;
43
+ [self startObservingFocusNotifications];
44
+
45
+ [self addSubview:_textField];
46
+ }
47
+ return self;
48
+ }
49
+
50
+ - (void)startObservingFocusNotifications
51
+ {
52
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
53
+ [nc addObserver:self selector:@selector(_didBeginEditing:)
54
+ name:UITextFieldTextDidBeginEditingNotification object:_textField];
55
+ [nc addObserver:self selector:@selector(_didEndEditing:)
56
+ name:UITextFieldTextDidEndEditingNotification object:_textField];
57
+ }
58
+
59
+ - (void)_didBeginEditing:(NSNotification *)notification
60
+ {
61
+ [self emitFocus];
62
+ }
63
+
64
+ - (void)_didEndEditing:(NSNotification *)notification
65
+ {
66
+ [self emitBlur];
67
+ }
68
+
69
+ - (void)dealloc
70
+ {
71
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
72
+ }
73
+
74
+ - (CGFloat)getBottomInset
75
+ {
76
+ UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
77
+ CGFloat bottom = window.safeAreaInsets.bottom > 0 ? 21 : 0;
78
+ return bottom;
79
+ }
80
+
81
+ #pragma mark - RCTComponentViewProtocol
82
+
83
+ + (ComponentDescriptorProvider)componentDescriptorProvider
84
+ {
85
+ return concreteComponentDescriptorProvider<NativeInputCalculatorComponentDescriptor>();
86
+ }
87
+
88
+ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
89
+ {
90
+ const auto &oldViewProps = *std::static_pointer_cast<const NativeInputCalculatorProps>(_props);
91
+ const auto &newViewProps = *std::static_pointer_cast<const NativeInputCalculatorProps>(props);
92
+
93
+ if (oldViewProps.value != newViewProps.value) {
94
+ NSString *newValue = RCTNSStringFromString(newViewProps.value);
95
+ if (![_lastValue isEqualToString:newValue]) {
96
+ _textField.text = newValue;
97
+ _lastValue = newValue;
98
+ [self reformatAndKeepSelection];
99
+ [self notifyTextChange];
100
+ }
101
+ }
102
+
103
+ if (oldViewProps.mode != newViewProps.mode) {
104
+ _keyboardView.keyboardMode = RCTNSStringFromString(newViewProps.mode);
105
+ }
106
+
107
+ if (oldViewProps.customKeyText != newViewProps.customKeyText) {
108
+ _keyboardView.customKeyText = RCTNSStringFromString(newViewProps.customKeyText);
109
+ }
110
+
111
+ if (oldViewProps.customKeyBackground != newViewProps.customKeyBackground) {
112
+ _keyboardView.customKeyBackground = RCTNSStringFromString(newViewProps.customKeyBackground);
113
+ }
114
+
115
+ if (oldViewProps.customKeyTextColor != newViewProps.customKeyTextColor) {
116
+ _keyboardView.customKeyTextColor = RCTNSStringFromString(newViewProps.customKeyTextColor);
117
+ }
118
+
119
+ if (oldViewProps.customKeyState != newViewProps.customKeyState) {
120
+ _keyboardView.customKeyState = RCTNSStringFromString(newViewProps.customKeyState);
121
+ }
122
+
123
+ if (oldViewProps.textAttributes.fontSize != newViewProps.textAttributes.fontSize > 0.0f) {
124
+ CGFloat newSize = (CGFloat)newViewProps.textAttributes.fontSize;
125
+ UIFont *current = _textField.font ?: [UIFont systemFontOfSize:UIFont.systemFontSize];
126
+ _textField.font = [current fontWithSize:newSize];
127
+ }
128
+
129
+ if (oldViewProps.textAttributes.fontWeight != newViewProps.textAttributes.fontWeight) {
130
+ UIFontWeight weight = _UIFontWeightFromString(newViewProps.textAttributes.fontWeight);
131
+ CGFloat size = _textField.font ? _textField.font.pointSize : UIFont.systemFontSize;
132
+ _textField.font = [UIFont systemFontOfSize:size weight:weight];
133
+ }
134
+
135
+ if (oldViewProps.textAttributes.placeholder != newViewProps.textAttributes.placeholder
136
+ || oldViewProps.textAttributes.placeholderTextColor != newViewProps.textAttributes.placeholderTextColor) {
137
+ _textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:RCTNSStringFromString(newViewProps.textAttributes.placeholder)
138
+ attributes:@{
139
+ NSForegroundColorAttributeName: [Utils colorFromHex:RCTNSStringFromString(newViewProps.textAttributes.placeholderTextColor)]
140
+ }];
141
+ }
142
+
143
+ [super updateProps:props oldProps:oldProps];
144
+ }
145
+
146
+ static UIFontWeight _UIFontWeightFromString(std::string_view s) {
147
+ std::string v(s);
148
+ for (auto &c : v) c = (char)tolower((unsigned char)c);
149
+
150
+ if (v == "normal" || v == "400") return UIFontWeightRegular;
151
+ if (v == "bold" || v == "700") return UIFontWeightBold;
152
+ if (v == "100") return UIFontWeightUltraLight;
153
+ if (v == "200") return UIFontWeightThin;
154
+ if (v == "300") return UIFontWeightLight;
155
+ if (v == "500") return UIFontWeightMedium;
156
+ if (v == "600") return UIFontWeightSemibold;
157
+ if (v == "800") return UIFontWeightHeavy;
158
+ if (v == "900") return UIFontWeightBlack;
159
+ return UIFontWeightRegular;
160
+ }
161
+
162
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
163
+ {
164
+ RCTNativeInputCalculatorHandleCommand(self, commandName, args);
165
+ }
166
+
167
+ #pragma mark - RCTNativeInputCalculatorViewProtocol
168
+
169
+ - (void)focus
170
+ {
171
+ [_textField becomeFirstResponder];
172
+ }
173
+
174
+ - (void)blur
175
+ {
176
+ [_textField resignFirstResponder];
177
+ }
178
+
179
+ #pragma mark - Keyboard callbacks (called by CalculatorKeyboardView)
180
+
181
+ - (void)keyDidPress:(NSString *)key {
182
+ UITextRange *sel = _textField.selectedTextRange;
183
+ if (!sel) return;
184
+
185
+ NSArray<NSString *> *ops = @[ @" + ", @" - ", @" × ", @" ÷ " ];
186
+ BOOL isOperatorKey = [ops containsObject:key];
187
+
188
+ if (!sel.isEmpty) {
189
+ [_textField replaceRange:sel withText:key];
190
+ } else {
191
+ NSInteger caret = [_textField offsetFromPosition:_textField.beginningOfDocument
192
+ toPosition:sel.start];
193
+ NSString *text = _textField.text ?: @"";
194
+
195
+ if (isOperatorKey && caret >= 3 && caret <= (NSInteger)text.length) {
196
+ NSString *last3 = [text substringWithRange:NSMakeRange(caret - 3, 3)];
197
+ if ([ops containsObject:last3]) {
198
+ UITextPosition *start = [_textField positionFromPosition:_textField.beginningOfDocument
199
+ offset:(caret - 3)];
200
+ UITextPosition *end = [_textField positionFromPosition:_textField.beginningOfDocument
201
+ offset:caret];
202
+ UITextRange *range = [_textField textRangeFromPosition:start toPosition:end];
203
+ [_textField replaceRange:range withText:key];
204
+ } else {
205
+ [_textField insertText:key];
206
+ }
207
+ } else {
208
+ [_textField insertText:key];
209
+ }
210
+ }
211
+
212
+ [self reformatAndKeepSelection];
213
+ [self notifyTextChange];
214
+ }
215
+
216
+ - (void)clearText
217
+ {
218
+ _textField.text = @"";
219
+ [self notifyTextChange];
220
+ }
221
+
222
+ - (NSString *)getText
223
+ {
224
+ return _textField.text;
225
+ }
226
+
227
+ - (void)onBackSpace {
228
+ NSString *formatted = _textField.text ?: @"";
229
+ if (formatted.length == 0) return;
230
+
231
+ UITextRange *selRange = _textField.selectedTextRange;
232
+ NSInteger caretFmt = (NSInteger)[_textField offsetFromPosition:_textField.beginningOfDocument
233
+ toPosition:selRange.start];
234
+
235
+ NSString *rawBefore = [self stripGroupDots:formatted];
236
+ NSInteger caretRaw = [self formattedCaretToRaw:formatted caret:caretFmt];
237
+ if (caretRaw <= 0) return;
238
+
239
+ NSArray<NSString *> *ops = @[ @" + ", @" - ", @" × ", @" ÷ " ];
240
+ NSInteger len = (NSInteger)rawBefore.length;
241
+
242
+ NSInteger delStart = MAX(caretRaw - 1, 0);
243
+ NSInteger delLen = 1;
244
+
245
+ BOOL (^matches)(NSInteger, NSInteger) = ^BOOL(NSInteger start, NSInteger end) {
246
+ if (start < 0 || end > len) return NO;
247
+ if (end - start != 3) return NO;
248
+ NSString *sub = [rawBefore substringWithRange:NSMakeRange(start, 3)];
249
+ for (NSString *op in ops) {
250
+ if ([sub isEqualToString:op]) return YES;
251
+ }
252
+ return NO;
253
+ };
254
+
255
+ if (matches(caretRaw - 3, caretRaw)) {
256
+ delStart = caretRaw - 3;
257
+ delLen = 3;
258
+ }
259
+ else if (matches(caretRaw - 2, caretRaw + 1)) {
260
+ delStart = caretRaw - 2;
261
+ delLen = 3;
262
+ }
263
+ else if (matches(caretRaw - 1, caretRaw + 2)) {
264
+ delStart = caretRaw - 1;
265
+ delLen = 3;
266
+ }
267
+
268
+ NSMutableString *rawAfter = [rawBefore mutableCopy];
269
+ if (delStart >= 0 && delStart + delLen <= (NSInteger)rawAfter.length) {
270
+ [rawAfter deleteCharactersInRange:NSMakeRange(delStart, delLen)];
271
+ }
272
+
273
+ NSString *formattedAfter = [self formatNumberGroups:rawAfter];
274
+ _textField.text = formattedAfter;
275
+
276
+ NSInteger newCaretFmt = [self rawCaretToFormatted:delStart inFormatted:formattedAfter];
277
+ UITextPosition *pos = [_textField positionFromPosition:_textField.beginningOfDocument offset:newCaretFmt];
278
+ if (pos) {
279
+ _textField.selectedTextRange = [_textField textRangeFromPosition:pos toPosition:pos];
280
+ }
281
+
282
+ [self notifyTextChange];
283
+ }
284
+
285
+ - (NSString *)calculate {
286
+ NSString *text = _textField.text ?: @"";
287
+ NSString *invalid = @"invalid";
288
+
289
+ text = [self stripGroupDots:text];
290
+ text = [text stringByReplacingOccurrencesOfString:@"×" withString:@"*"];
291
+ text = [text stringByReplacingOccurrencesOfString:@"÷" withString:@"/"];
292
+
293
+ NSString *pattern = @"^\\s*(-?\\d+(\\.\\d+)?\\s*[-+*/]\\s*)*-?\\d+(\\.\\d+)?\\s*$";
294
+ NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
295
+ if (![regex firstMatchInString:text options:0 range:NSMakeRange(0, text.length)]) {
296
+ NSLog(@"Invalid expression");
297
+ return invalid;
298
+ }
299
+
300
+ @try {
301
+ NSExpression *expr = [NSExpression expressionWithFormat:text];
302
+ id val = [expr expressionValueWithObject:nil context:nil];
303
+ if ([val isKindOfClass:[NSNumber class]]) {
304
+ return [(NSNumber *)val stringValue];
305
+ }
306
+ } @catch (__unused NSException *e) { return invalid; }
307
+ return invalid;
308
+ }
309
+
310
+ - (void)calculateResult {
311
+ NSString *result = [self calculate];
312
+ if ([result isEqual: @"invalid"]) return;
313
+ NSString *formatted = [self formatNumberGroups:result];
314
+ _textField.text = formatted;
315
+
316
+ UITextPosition *end = _textField.endOfDocument;
317
+ _textField.selectedTextRange = [_textField textRangeFromPosition:end toPosition:end];
318
+
319
+ [self notifyTextChange];
320
+ }
321
+
322
+ - (void)emitCustomKey
323
+ {
324
+ if (_eventEmitter) {
325
+ auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
326
+ NativeInputCalculatorEventEmitter::OnCustomKeyEvent event{};
327
+ emitter->onCustomKeyEvent(event);
328
+ }
329
+ }
330
+
331
+ - (void)emitFocus
332
+ {
333
+ printf("emitFocus.");
334
+ if (_eventEmitter) {
335
+ auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
336
+ NativeInputCalculatorEventEmitter::OnFocus event{};
337
+ emitter->onFocus(event);
338
+ }
339
+ }
340
+
341
+ - (void)emitBlur
342
+ {
343
+ printf("emitBlur.");
344
+ if (_eventEmitter) {
345
+ auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
346
+ NativeInputCalculatorEventEmitter::OnBlur event{};
347
+ emitter->onBlur(event);
348
+ }
349
+ }
350
+
351
+ - (void)emitKeyPress:(NSString *)key
352
+ {
353
+ if (_eventEmitter) {
354
+ auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
355
+ NativeInputCalculatorEventEmitter::OnKeyPress event{
356
+ .key = std::string([key UTF8String])
357
+ };
358
+ emitter->onKeyPress(event);
359
+ }
360
+ }
361
+
362
+ - (void)notifyTextChange
363
+ {
364
+ _lastValue = _textField.text;
365
+
366
+ if (_eventEmitter) {
367
+ auto emitter = std::static_pointer_cast<const NativeInputCalculatorEventEmitter>(_eventEmitter);
368
+ NativeInputCalculatorEventEmitter::OnChange event{
369
+ .text = std::string([_textField.text UTF8String])
370
+ };
371
+ emitter->onChange(event);
372
+
373
+ NSString *result = [self calculate];
374
+ NativeInputCalculatorEventEmitter::OnResult event1{
375
+ .result = std::string([result UTF8String])
376
+ };
377
+ emitter->onResult(event1);
378
+
379
+ }
380
+ }
381
+
382
+ #pragma mark - Thousand grouping helpers (strip/format + caret mapping)
383
+
384
+ - (BOOL)isGroupDotAt:(NSInteger)i inString:(NSString *)s {
385
+ if (i < 0 || i >= (NSInteger)s.length) return NO;
386
+ unichar c = [s characterAtIndex:i];
387
+ if (c != '.') return NO;
388
+ BOOL leftIsDigit = (i - 1 >= 0) && [[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[s characterAtIndex:i-1]];
389
+ BOOL rightIsDigit = (i + 1 < (NSInteger)s.length) && [[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[s characterAtIndex:i+1]];
390
+ return leftIsDigit && rightIsDigit;
391
+ }
392
+
393
+ - (NSString *)stripGroupDots:(NSString *)input {
394
+ if (input.length == 0) return input;
395
+ NSMutableString *out = [NSMutableString stringWithCapacity:input.length];
396
+ for (NSInteger i = 0; i < (NSInteger)input.length; i++) {
397
+ unichar c = [input characterAtIndex:i];
398
+ if (c == '.' && [self isGroupDotAt:i inString:input]) {
399
+ // skip
400
+ } else {
401
+ [out appendFormat:@"%C", c];
402
+ }
403
+ }
404
+ return out;
405
+ }
406
+
407
+ - (NSString *)formatNumberGroups:(NSString *)input {
408
+ NSString *noSep = [self stripGroupDots:input];
409
+ if (noSep.length == 0) return noSep;
410
+
411
+ NSError *err = nil;
412
+ NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:@"\\d+" options:0 error:&err];
413
+ if (err) return noSep;
414
+
415
+ NSMutableString *result = [noSep mutableCopy];
416
+ __block NSInteger delta = 0;
417
+ [re enumerateMatchesInString:noSep options:0 range:NSMakeRange(0, noSep.length) usingBlock:^(NSTextCheckingResult * _Nullable match, NSMatchingFlags flags, BOOL * _Nonnull stop) {
418
+ if (!match) return;
419
+ NSRange mr = match.range;
420
+ mr.location += delta;
421
+
422
+ NSString *digits = [result substringWithRange:mr];
423
+
424
+ NSMutableString *rev = [NSMutableString stringWithCapacity:digits.length];
425
+ for (NSInteger i = digits.length - 1; i >= 0; i--) {
426
+ [rev appendFormat:@"%C", [digits characterAtIndex:i]];
427
+ }
428
+
429
+ NSMutableArray<NSString *> *chunks = [NSMutableArray array];
430
+ for (NSInteger i = 0; i < (NSInteger)rev.length; i += 3) {
431
+ NSRange r = NSMakeRange(i, MIN(3, (NSInteger)rev.length - i));
432
+ [chunks addObject:[rev substringWithRange:r]];
433
+ }
434
+ NSString *joined = [chunks componentsJoinedByString:@"."];
435
+
436
+ NSMutableString *final = [NSMutableString stringWithCapacity:joined.length];
437
+ for (NSInteger i = joined.length - 1; i >= 0; i--) {
438
+ [final appendFormat:@"%C", [joined characterAtIndex:i]];
439
+ }
440
+
441
+ [result replaceCharactersInRange:mr withString:final];
442
+ delta += (final.length - mr.length);
443
+ }];
444
+
445
+ return result;
446
+ }
447
+
448
+ - (NSInteger)formattedCaretToRaw:(NSString *)formatted caret:(NSInteger)caretFmt {
449
+ NSInteger rawIdx = 0;
450
+ NSInteger limit = MIN(caretFmt, (NSInteger)formatted.length);
451
+ for (NSInteger i = 0; i < limit; i++) {
452
+ unichar c = [formatted characterAtIndex:i];
453
+ if (!(c == '.' && [self isGroupDotAt:i inString:formatted])) {
454
+ rawIdx++;
455
+ }
456
+ }
457
+ return rawIdx;
458
+ }
459
+
460
+ - (NSInteger)rawCaretToFormatted:(NSInteger)rawCaret inFormatted:(NSString *)formatted {
461
+ NSInteger rawSeen = 0;
462
+ for (NSInteger i = 0; i < (NSInteger)formatted.length; i++) {
463
+ unichar c = [formatted characterAtIndex:i];
464
+ if (!(c == '.' && [self isGroupDotAt:i inString:formatted])) {
465
+ if (rawSeen == rawCaret) return i;
466
+ rawSeen++;
467
+ }
468
+ }
469
+ return (NSInteger)formatted.length;
470
+ }
471
+
472
+ - (void)reformatAndKeepSelection {
473
+ NSString *formattedBefore = _textField.text ?: @"";
474
+
475
+ UITextRange *selRange = _textField.selectedTextRange;
476
+ NSInteger caretFmtBefore = (NSInteger)[_textField offsetFromPosition:_textField.beginningOfDocument
477
+ toPosition:selRange.start];
478
+
479
+ NSInteger caretRaw = [self formattedCaretToRaw:formattedBefore caret:caretFmtBefore];
480
+ NSString *formattedAfter = [self formatNumberGroups:formattedBefore];
481
+
482
+ if (![formattedAfter isEqualToString:formattedBefore]) {
483
+ _textField.text = formattedAfter;
484
+ }
485
+
486
+ NSInteger caretFmtAfter = [self rawCaretToFormatted:caretRaw inFormatted:formattedAfter];
487
+ UITextPosition *pos = [_textField positionFromPosition:_textField.beginningOfDocument offset:caretFmtAfter];
488
+ if (pos) {
489
+ _textField.selectedTextRange = [_textField textRangeFromPosition:pos toPosition:pos];
490
+ }
491
+ }
492
+
493
+
494
+ @end
495
+
496
+ Class<RCTNativeInputCalculatorViewProtocol> NativeInputCalculatorCls(void)
497
+ {
498
+ return NativeInputCalculator.class;
499
+ }
500
+
package/ios/Utils.h ADDED
@@ -0,0 +1,10 @@
1
+ //
2
+ // Utils.h
3
+ // Pods
4
+ //
5
+ // Created by Phuc on 21/10/25.
6
+ //
7
+
8
+ @interface Utils : NSObject
9
+ + (UIColor *)colorFromHex:(NSString *)hexString;
10
+ @end
package/ios/Utils.mm ADDED
@@ -0,0 +1,25 @@
1
+ //
2
+ // Utils.mm
3
+ // Pods
4
+ //
5
+ // Created by Phuc on 21/10/25.
6
+ //
7
+
8
+ #import <UIKit/UIKit.h>
9
+ #import <Utils.h>
10
+
11
+ @implementation Utils
12
+
13
+ + (UIColor *)colorFromHex:(NSString *)hexString
14
+ {
15
+ unsigned rgbValue = 0;
16
+ NSString *cleanHex = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
17
+ NSScanner *scanner = [NSScanner scannerWithString:cleanHex];
18
+ [scanner scanHexInt:&rgbValue];
19
+
20
+ return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
21
+ green:((rgbValue & 0x00FF00) >> 8) / 255.0
22
+ blue:(rgbValue & 0x0000FF) / 255.0
23
+ alpha:1.0];
24
+ }
25
+ @end