@momo-kits/calculator-keyboard 0.150.2-beta.20 → 0.150.2-beta.20-sp.1

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/README.md CHANGED
@@ -10,15 +10,57 @@ npm install react-native-calculator-keyboard
10
10
 
11
11
  ## Usage
12
12
 
13
-
14
13
  ```js
15
- import { CalculatorKeyboardView } from "react-native-calculator-keyboard";
14
+ import InputCalculator from '@momo-kits/calculator-keyboard';
16
15
 
17
16
  // ...
18
17
 
19
- <CalculatorKeyboardView color="tomato" />
18
+ <InputCalculator
19
+ mode="NumDefault"
20
+ customKeyText="Next"
21
+ onCustomKeyEvent={() => console.log('Custom key pressed')}
22
+ />;
23
+ ```
24
+
25
+ ## Requirements
26
+
27
+ **React Native 0.80+** with **Fabric (New Architecture) enabled**.
28
+
29
+ This library is **pure Fabric** implementation with:
30
+
31
+ - ✅ Zero RCTBridge dependencies
32
+ - ✅ Native C++ ComponentView on iOS
33
+ - ✅ Fabric ViewManager with codegen delegates on Android
34
+ - ✅ All Props, Events, Commands auto-generated by codegen
35
+ - ❌ No Paper (old architecture) support
36
+
37
+ ### Android Setup
38
+
39
+ Add to your `gradle.properties`:
40
+
41
+ ```properties
42
+ newArchEnabled=true
43
+ ```
44
+
45
+ Then rebuild:
46
+
47
+ ```bash
48
+ cd android && ./gradlew clean && cd ..
49
+ npx react-native run-android
50
+ ```
51
+
52
+ ### iOS Setup
53
+
54
+ **Required**: Set the environment variable before installing pods:
55
+
56
+ ```bash
57
+ cd ios
58
+ RCT_NEW_ARCH_ENABLED=1 pod install
59
+ cd ..
60
+ npx react-native run-ios
20
61
  ```
21
62
 
63
+ **Note**: This library uses Fabric ComponentView (`.mm` files) and will not work without `RCT_NEW_ARCH_ENABLED=1`.
22
64
 
23
65
  ## Contributing
24
66
 
@@ -12,6 +12,6 @@ class CalculatorKeyboardPackage : ReactPackage {
12
12
  }
13
13
 
14
14
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
- return listOf(RCTInputCalculator())
15
+ return listOf(InputCalculatorManager())
16
16
  }
17
17
  }
@@ -7,7 +7,6 @@ import android.graphics.drawable.GradientDrawable
7
7
  import android.view.Gravity
8
8
  import android.widget.Button
9
9
  import android.widget.ImageButton
10
- import androidx.appcompat.app.AppCompatActivity
11
10
  import androidx.constraintlayout.widget.ConstraintLayout
12
11
  import com.facebook.react.uimanager.ThemedReactContext
13
12
  import org.mariuszgromada.math.mxparser.Expression
@@ -21,53 +20,57 @@ class CustomKeyboardView(
21
20
  context: ThemedReactContext,
22
21
  private val editText: CalculatorEditText
23
22
  ) : ConstraintLayout(context) {
24
- private val keys = listOf(
23
+ private val numWithCTAKeys = listOf(
25
24
  listOf("1", "2", "3", "÷", "back"),
26
25
  listOf("4", "5", "6", "×", "="),
27
- listOf("7", "8", "9", "-", "Xong"),
26
+ listOf("7", "8", "9", "-", "Tiếp"),
28
27
  listOf("000", "0", "+")
29
28
  )
30
- private val specialKeys = listOf("=", "-", "×", "÷", "back", "+")
29
+ private val defaultKeys = listOf(
30
+ listOf("1", "2", "3", "÷", "AC"),
31
+ listOf("4", "5", "6", "×", "back"),
32
+ listOf("7", "8", "9", "-", "="),
33
+ listOf("000", "0", "+")
34
+ )
35
+ private val specialKeys = listOf("=", "-", "×", "÷", "back", "+", "AC")
31
36
  private val separatorWidth = 8f
32
37
  private var specialButtonColor: Int = "#D8D8D8".toColorInt()
33
38
 
39
+ private var keyboardMode: String = "NumDefault"
40
+
34
41
  private var customKeyButton: Button? = null
35
42
  private var customKeyButtonBackground: Int = "#D8D8D8".toColorInt()
36
43
  private var customKeyButtonTextColor: Int = Color.BLACK
37
44
  private var customKeyButtonState: String = "default"
38
45
 
39
46
  init {
40
- val activity = context.currentActivity as? AppCompatActivity
41
- if (activity != null) {
42
- val displayMetrics = resources.displayMetrics
43
- val widthButton = (displayMetrics.widthPixels - separatorWidth * 2 - 4 * separatorWidth) / 5f
44
- val heightButton = (calculatorHeight - separatorWidth * 2 - 3 * separatorWidth) / 4
45
-
46
47
  isClickable = false
47
48
  isFocusable = false
48
49
  isFocusableInTouchMode = false
49
50
  clipToPadding = false
50
51
  clipChildren = false
51
-
52
- renderUI(widthButton, heightButton)
53
- }
54
-
55
52
  }
56
53
 
57
- private fun renderUI(buttonWidth: Float, buttonHeight: Float) {
54
+ private fun renderUI() {
55
+ val displayMetrics = resources.displayMetrics
56
+ val buttonWidth = (displayMetrics.widthPixels - separatorWidth * 2 - 4 * separatorWidth) / 5f
57
+ val buttonHeight = (calculatorHeight - separatorWidth * 2 - 3 * separatorWidth) / 4
58
+
58
59
  var yOffset = separatorWidth
60
+ val keys = if (keyboardMode == "NumWithCTA") numWithCTAKeys else defaultKeys
59
61
  for ((rowIndex, row) in keys.withIndex()) {
60
62
  var xOffset = separatorWidth
61
63
  for ((colIndex, key) in row.withIndex()) {
62
- val isCustomKey = rowIndex == 2 && colIndex == 4
64
+ val isMainKey = rowIndex == 2 && colIndex == 4
65
+ val isMainCTAKey = isMainKey && keyboardMode == "NumWithCTA"
63
66
  val width = if (key == "000") buttonWidth * 2 + separatorWidth else buttonWidth
64
- val height = if (isCustomKey) buttonHeight * 2 + separatorWidth else buttonHeight
67
+ val height = if (isMainKey) buttonHeight * 2 + separatorWidth else buttonHeight
65
68
 
66
69
  val button = if (key == "back") {
67
70
  createImageButton(key, xOffset, yOffset, buttonWidth.toInt(), buttonHeight.toInt())
68
71
  } else {
69
- createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isCustomKey).also { b ->
70
- if (isCustomKey) customKeyButton = b
72
+ createButton(key, xOffset, yOffset, width.toInt(), height.toInt(), isMainKey, isMainCTAKey).also { b ->
73
+ if (isMainCTAKey) customKeyButton = b
71
74
  }
72
75
  }
73
76
 
@@ -85,7 +88,8 @@ class CustomKeyboardView(
85
88
  yOffset: Float,
86
89
  buttonWidth: Int,
87
90
  buttonHeight: Int,
88
- isCustomKey: Boolean
91
+ isMainKey: Boolean,
92
+ isMainCTAKey: Boolean
89
93
  ): Button {
90
94
  return Button(context).apply {
91
95
  val shapeInit = GradientDrawable().apply {
@@ -98,7 +102,7 @@ class CustomKeyboardView(
98
102
  background = shapeInit
99
103
  text = key
100
104
  setTypeface(typeface)
101
- textSize = (if (isCustomKey) 18 else 24).toFloat()
105
+ textSize = (if (isMainCTAKey) 18 else 24).toFloat()
102
106
  setTextColor(Color.BLACK)
103
107
  stateListAnimator = null
104
108
  maxLines = 1
@@ -110,7 +114,7 @@ class CustomKeyboardView(
110
114
  constrainedWidth = false
111
115
  }
112
116
 
113
- if (specialKeys.contains(key)) {
117
+ if (specialKeys.contains(key) || isMainKey) {
114
118
  background = GradientDrawable().apply {
115
119
  shape = GradientDrawable.RECTANGLE
116
120
  cornerRadius = 24f
@@ -125,7 +129,7 @@ class CustomKeyboardView(
125
129
 
126
130
  translationX = xOffset.toInt().toFloat()
127
131
  translationY = yOffset.toInt().toFloat()
128
- setOnClickListener { onKeyPress(key, isCustomKey) }
132
+ setOnClickListener { onKeyPress(key, isMainCTAKey) }
129
133
  }
130
134
  }
131
135
 
@@ -195,14 +199,15 @@ class CustomKeyboardView(
195
199
  }
196
200
  }
197
201
 
198
- private fun onKeyPress(key: String, isCustomKey: Boolean) {
199
- if (isCustomKey) {
202
+ private fun onKeyPress(key: String, isMainCTAKey: Boolean) {
203
+ if (isMainCTAKey) {
200
204
  emitCustomKey()
201
205
  return
202
206
  }
203
207
 
204
208
  emitKeyPress(key)
205
209
  when (key) {
210
+ "AC" -> clearText()
206
211
  "back" -> onBackSpace()
207
212
  "=" -> calculateResult()
208
213
  "×", "+", "-", "÷" -> keyDidPress(" $key ")
@@ -215,6 +220,10 @@ class CustomKeyboardView(
215
220
  editText.text?.replace(editText.selectionStart, editText.selectionEnd, key)
216
221
  }
217
222
 
223
+ private fun clearText() {
224
+ editText.text?.clear()
225
+ }
226
+
218
227
  private fun onBackSpace() {
219
228
  val start = editText.selectionStart
220
229
  val end = editText.selectionEnd
@@ -270,25 +279,29 @@ class CustomKeyboardView(
270
279
  customKeyButton?.text = text
271
280
  }
272
281
 
282
+ fun setMode(mode: String) {
283
+ keyboardMode = mode
284
+ renderUI()
285
+ }
286
+
273
287
  fun setCustomKeyBackground(background: Int) {
274
288
  customKeyButtonBackground = background
275
- updateCustomKeyUI(background, customKeyButtonTextColor, customKeyButtonState)
289
+ updateCustomKeyUI(background, customKeyButtonTextColor)
276
290
  }
277
291
 
278
292
  fun setCustomKeyTextColor(textColor: Int) {
279
293
  customKeyButtonTextColor = textColor
280
- updateCustomKeyUI(customKeyButtonBackground, textColor, customKeyButtonState)
294
+ updateCustomKeyUI(customKeyButtonBackground, textColor)
281
295
  }
282
296
 
283
297
 
284
298
  fun setCustomKeyState(state: String) {
285
299
  customKeyButtonState = state
286
300
  customKeyButton?.isEnabled = state != "disable"
287
- updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor, state)
301
+ updateCustomKeyUI(customKeyButtonBackground, customKeyButtonTextColor)
288
302
  }
289
303
 
290
- private fun updateCustomKeyUI(background: Int, textColor: Int, state: String){
291
-
304
+ private fun updateCustomKeyUI(background: Int, textColor: Int){
292
305
  customKeyButton?.background = GradientDrawable().apply {
293
306
  shape = GradientDrawable.RECTANGLE
294
307
  cornerRadius = 24f
@@ -297,5 +310,4 @@ class CustomKeyboardView(
297
310
  customKeyButton?.setTextColor(textColor)
298
311
  }
299
312
 
300
-
301
313
  }
@@ -8,15 +8,20 @@ import android.view.inputmethod.InputMethodManager
8
8
  import androidx.core.graphics.toColorInt
9
9
  import androidx.core.view.ViewCompat
10
10
  import androidx.core.view.WindowInsetsCompat
11
- import com.facebook.react.bridge.ReadableArray
12
11
  import com.facebook.react.bridge.UiThreadUtil
13
12
  import com.facebook.react.uimanager.PixelUtil.dpToPx
14
13
  import com.facebook.react.uimanager.ThemedReactContext
15
- import com.facebook.react.uimanager.annotations.ReactProp
16
14
  import com.facebook.react.views.textinput.ReactEditText
17
15
  import com.facebook.react.views.textinput.ReactTextInputManager
16
+ import com.facebook.react.viewmanagers.NativeInputCalculatorManagerDelegate
17
+ import com.facebook.react.viewmanagers.NativeInputCalculatorManagerInterface
18
+ import com.facebook.react.uimanager.ViewManagerDelegate
19
+ import androidx.annotation.Nullable
18
20
 
19
- class RCTInputCalculator : ReactTextInputManager() {
21
+ // Fabric-only manager with codegen name `NativeInputCalculator`
22
+ class InputCalculatorManager : ReactTextInputManager(), NativeInputCalculatorManagerInterface<ReactEditText> {
23
+
24
+ private val mDelegate: ViewManagerDelegate<ReactEditText> = NativeInputCalculatorManagerDelegate(this)
20
25
 
21
26
  private var keyboardView: CustomKeyboardView? = null
22
27
  private lateinit var editText: CalculatorEditText
@@ -30,12 +35,11 @@ class RCTInputCalculator : ReactTextInputManager() {
30
35
  override fun getName() = REACT_CLASS
31
36
 
32
37
  companion object {
33
- const val REACT_CLASS = "RCTInputCalculator"
38
+ const val REACT_CLASS = "NativeInputCalculator"
34
39
  val calculatorHeight: Int = 240.dpToPx().toInt()
35
40
  }
36
41
 
37
- @ReactProp(name = "value")
38
- fun setValue(view: ReactEditText, value: String?) {
42
+ override fun setValue(view: ReactEditText, @Nullable value: String?) {
39
43
  UiThreadUtil.runOnUiThread {
40
44
  val e = view.editableText ?: run { view.setText(value ?: ""); return@runOnUiThread }
41
45
  val newText = value ?: ""
@@ -48,29 +52,28 @@ class RCTInputCalculator : ReactTextInputManager() {
48
52
  }
49
53
  }
50
54
 
51
- @ReactProp(name = "customKeyText")
52
- fun setCustomKeyText(view: ReactEditText, text: String?) {
53
- keyboardView?.setCustomKeyText(text ?: "Xong")
55
+ override fun setMode(view: ReactEditText, @Nullable mode: String?) {
56
+ keyboardView?.setMode(mode ?: "NumDefault")
57
+ }
58
+
59
+ override fun setCustomKeyText(view: ReactEditText, @Nullable text: String?) {
60
+ keyboardView?.setCustomKeyText(text ?: "Tiếp")
54
61
  }
55
62
 
56
- @ReactProp(name = "customKeyBackground")
57
- fun setCustomKeyBackground(view: ReactEditText, background: String?) {
63
+ override fun setCustomKeyBackground(view: ReactEditText, @Nullable background: String?) {
58
64
  keyboardView?.setCustomKeyBackground((background ?: "#d8d8d8").toColorInt())
59
65
  }
60
66
 
61
- @ReactProp(name = "customKeyTextColor")
62
- fun setCustomKeyTextColor(view: ReactEditText, textColor: String?) {
67
+ override fun setCustomKeyTextColor(view: ReactEditText, @Nullable textColor: String?) {
63
68
  keyboardView?.setCustomKeyTextColor(textColor?.toColorInt() ?: Color.BLACK)
64
69
  }
65
70
 
66
- @ReactProp(name = "customKeyState")
67
- fun setCustomKeyState(view: ReactEditText, state: String?) {
71
+ override fun setCustomKeyState(view: ReactEditText, @Nullable state: String?) {
68
72
  keyboardView?.setCustomKeyState(state ?: "default")
69
73
  }
70
74
 
71
- @ReactProp(name = "keyboardColor")
72
- fun setKeyboardColor(view: ReactEditText, color: String) {
73
- keyboardView?.updateButtonColors(color.toColorInt())
75
+ override fun setKeyboardColor(view: ReactEditText, @Nullable color: Int?) {
76
+ color?.let { keyboardView?.updateButtonColors(it) }
74
77
  }
75
78
 
76
79
  @SuppressLint("ClickableViewAccessibility")
@@ -165,26 +168,17 @@ class RCTInputCalculator : ReactTextInputManager() {
165
168
  v.showSoftInputOnFocus = true
166
169
  }
167
170
 
168
- override fun getCommandsMap(): Map<String, Int> = mapOf("blur" to 1, "focus" to 2)
171
+ override fun getDelegate(): ViewManagerDelegate<ReactEditText> = mDelegate
169
172
 
170
- override fun receiveCommand(reactEditText: ReactEditText, commandId: Int, args: ReadableArray?) {
171
- when (commandId) {
172
- 1 -> blur()
173
- 2 -> focus()
174
- }
173
+ override fun focus(view: ReactEditText) {
174
+ UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
175
175
  }
176
176
 
177
- override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
178
- val base = super.getExportedCustomBubblingEventTypeConstants().toMutableMap()
179
- base["onKeyPress"] = mapOf("phasedRegistrationNames" to mapOf("bubbled" to "onKeyPress"))
180
- return base
177
+ override fun blur(view: ReactEditText) {
178
+ UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
181
179
  }
182
180
 
183
- override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
184
- val base = super.getExportedCustomDirectEventTypeConstants().toMutableMap()
185
- base["onCustomKeyEvent"] = mapOf("registrationName" to "onCustomKeyEvent")
186
- return base
187
- }
181
+ // Events are emitted from CustomKeyboardView using RCTEventEmitter.
188
182
 
189
183
  private fun focus() {
190
184
  UiThreadUtil.runOnUiThread { if (!editText.isFocused) editText.requestFocus() }
@@ -194,4 +188,3 @@ class RCTInputCalculator : ReactTextInputManager() {
194
188
  UiThreadUtil.runOnUiThread { if (editText.isFocused) editText.clearFocus() }
195
189
  }
196
190
  }
197
-
@@ -0,0 +1,30 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @protocol CalculatorKeyboardInput <NSObject>
6
+
7
+ - (void)keyDidPress:(NSString *)key;
8
+ - (void)clearText;
9
+ - (void)onBackSpace;
10
+ - (void)calculateResult;
11
+ - (void)emitCustomKey;
12
+ - (void)emitKeyPress:(NSString *)key;
13
+
14
+ @end
15
+
16
+ @interface CalculatorKeyboardView : UIView
17
+
18
+ @property (nonatomic, weak, nullable) id<CalculatorKeyboardInput> input;
19
+ @property (nonatomic, strong, nullable) NSString *keyboardMode;
20
+ @property (nonatomic, strong, nullable) NSString *customKeyText;
21
+ @property (nonatomic, strong, nullable) NSString *customKeyBackground;
22
+ @property (nonatomic, strong, nullable) NSString *customKeyTextColor;
23
+ @property (nonatomic, strong, nullable) NSString *customKeyState;
24
+
25
+ - (void)setKeyboardColor:(UIColor *)color;
26
+
27
+ @end
28
+
29
+ NS_ASSUME_NONNULL_END
30
+
@@ -0,0 +1,231 @@
1
+ #import "CalculatorKeyboardView.h"
2
+
3
+ @interface CalculatorKeyboardView ()
4
+ @property (nonatomic, strong) NSArray<NSArray<NSString *> *> *numWithCTAKeys;
5
+ @property (nonatomic, strong) NSArray<NSArray<NSString *> *> *defaultKeys;
6
+ @property (nonatomic, strong) NSSet<NSString *> *specialKeys;
7
+ @property (nonatomic, weak) UIButton *customKeyButton;
8
+ @end
9
+
10
+ @implementation CalculatorKeyboardView {
11
+ CGFloat _separatorWidth;
12
+ }
13
+
14
+ - (instancetype)initWithFrame:(CGRect)frame
15
+ {
16
+ if (self = [super initWithFrame:frame]) {
17
+ _separatorWidth = 4.0;
18
+
19
+ _numWithCTAKeys = @[
20
+ @[@"1", @"2", @"3", @"÷", @"back"],
21
+ @[@"4", @"5", @"6", @"×", @"="],
22
+ @[@"7", @"8", @"9", @"-", @"Tiếp"],
23
+ @[@"000", @"0", @"+"]
24
+ ];
25
+
26
+ _defaultKeys = @[
27
+ @[@"1", @"2", @"3", @"÷", @"AC"],
28
+ @[@"4", @"5", @"6", @"×", @"back"],
29
+ @[@"7", @"8", @"9", @"-", @"="],
30
+ @[@"000", @"0", @"+"]
31
+ ];
32
+
33
+ _specialKeys = [NSSet setWithArray:@[@"=", @"-", @"×", @"÷", @"back", @"+", @"AC"]];
34
+
35
+ [self setup];
36
+ }
37
+ return self;
38
+ }
39
+
40
+ - (void)setKeyboardMode:(NSString *)keyboardMode
41
+ {
42
+ if ([_keyboardMode isEqualToString:keyboardMode]) {
43
+ return;
44
+ }
45
+ _keyboardMode = keyboardMode;
46
+ [self setup];
47
+ }
48
+
49
+ - (void)setCustomKeyText:(NSString *)customKeyText
50
+ {
51
+ _customKeyText = customKeyText;
52
+ [self updateCustomKeyTitle];
53
+ }
54
+
55
+ - (void)setCustomKeyBackground:(NSString *)customKeyBackground
56
+ {
57
+ _customKeyBackground = customKeyBackground;
58
+ [self updateCustomKeyBackground];
59
+ }
60
+
61
+ - (void)setCustomKeyTextColor:(NSString *)customKeyTextColor
62
+ {
63
+ _customKeyTextColor = customKeyTextColor;
64
+ [self updateCustomKeyBackground];
65
+ }
66
+
67
+ - (void)setCustomKeyState:(NSString *)customKeyState
68
+ {
69
+ _customKeyState = customKeyState;
70
+ [self updateCustomKeyBackground];
71
+ }
72
+
73
+ - (void)setKeyboardColor:(UIColor *)color
74
+ {
75
+ [self setup];
76
+ }
77
+
78
+ - (void)setup
79
+ {
80
+ // Remove all subviews
81
+ for (UIView *subview in self.subviews) {
82
+ [subview removeFromSuperview];
83
+ }
84
+
85
+ self.backgroundColor = [self colorFromHex:@"#f2f2f6"];
86
+
87
+ CGFloat buttonWidth = (UIScreen.mainScreen.bounds.size.width - _separatorWidth * 2 - 4 * _separatorWidth) / 5;
88
+ CGFloat buttonHeight = (240 - _separatorWidth * 2 - 3 * _separatorWidth) / 4;
89
+
90
+ // Create content view
91
+ UIView *contentView = [[UIView alloc] init];
92
+ contentView.translatesAutoresizingMaskIntoConstraints = NO;
93
+ [self addSubview:contentView];
94
+
95
+ // Set contentView constraints
96
+ [NSLayoutConstraint activateConstraints:@[
97
+ [contentView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_separatorWidth],
98
+ [contentView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_separatorWidth],
99
+ [contentView.topAnchor constraintEqualToAnchor:self.topAnchor constant:_separatorWidth],
100
+ [contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-_separatorWidth]
101
+ ]];
102
+
103
+ CGFloat yOffset = 0;
104
+ NSArray<NSArray<NSString *> *> *keys = [_keyboardMode isEqualToString:@"NumDefault"] ? _defaultKeys : _numWithCTAKeys;
105
+
106
+ for (NSInteger rowIndex = 0; rowIndex < keys.count; rowIndex++) {
107
+ NSArray<NSString *> *row = keys[rowIndex];
108
+ CGFloat xOffset = 0;
109
+
110
+ for (NSInteger colIndex = 0; colIndex < row.count; colIndex++) {
111
+ NSString *key = row[colIndex];
112
+ BOOL isMainKey = (colIndex == 4 && rowIndex == 2);
113
+ BOOL isMainCTAKey = isMainKey && [_keyboardMode isEqualToString:@"NumWithCTA"];
114
+
115
+ UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
116
+ button.backgroundColor = UIColor.whiteColor;
117
+ button.layer.cornerRadius = 8;
118
+
119
+ NSString *title = isMainCTAKey ? (_customKeyText ?: key) : key;
120
+ [button setTitle:title forState:UIControlStateNormal];
121
+ [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
122
+ button.titleLabel.font = [UIFont systemFontOfSize:isMainCTAKey ? 18 : 24 weight:UIFontWeightMedium];
123
+ button.accessibilityIdentifier = key;
124
+ button.tag = isMainCTAKey ? 1 : 0;
125
+
126
+ CGRect buttonFrame = CGRectMake(xOffset, yOffset, buttonWidth, buttonHeight);
127
+ if (isMainKey) {
128
+ buttonFrame.size.height = buttonHeight * 2 + _separatorWidth;
129
+ }
130
+ if ([key isEqualToString:@"000"]) {
131
+ buttonFrame.size.width = buttonWidth * 2 + _separatorWidth;
132
+ }
133
+
134
+ button.frame = buttonFrame;
135
+
136
+ if ([key isEqualToString:@"back"]) {
137
+ [button setTitle:@"" forState:UIControlStateNormal];
138
+ UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightBold];
139
+ UIImage *image = [UIImage systemImageNamed:@"delete.backward" withConfiguration:config];
140
+ [button setImage:image forState:UIControlStateNormal];
141
+ button.tintColor = UIColor.blackColor;
142
+ }
143
+
144
+ if ([_specialKeys containsObject:key] || isMainKey) {
145
+ [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
146
+ button.backgroundColor = [self colorFromHex:@"#d8d8d8"];
147
+ }
148
+
149
+ if (isMainKey) {
150
+ self.customKeyButton = button;
151
+ }
152
+
153
+ [button addTarget:self action:@selector(keyPressed:) forControlEvents:UIControlEventTouchUpInside];
154
+ [contentView addSubview:button];
155
+
156
+ xOffset += buttonFrame.size.width + _separatorWidth;
157
+ }
158
+
159
+ yOffset += buttonHeight + _separatorWidth;
160
+ }
161
+ }
162
+
163
+ - (void)updateCustomKeyTitle
164
+ {
165
+ if (!self.customKeyButton || !_customKeyText) {
166
+ return;
167
+ }
168
+ [self.customKeyButton setTitle:_customKeyText forState:UIControlStateNormal];
169
+ [self.customKeyButton setImage:nil forState:UIControlStateNormal];
170
+ }
171
+
172
+ - (void)updateCustomKeyBackground
173
+ {
174
+ if (!self.customKeyButton || !_keyboardMode || !_customKeyBackground || !_customKeyTextColor || !_customKeyState) {
175
+ return;
176
+ }
177
+
178
+ if ([_keyboardMode isEqualToString:@"numWithCTA"]) {
179
+ self.customKeyButton.enabled = ![_customKeyState isEqualToString:@"disable"];
180
+ } else {
181
+ self.customKeyButton.enabled = YES;
182
+ }
183
+
184
+ self.customKeyButton.backgroundColor = [self colorFromHex:_customKeyBackground];
185
+ [self.customKeyButton setTitleColor:[self colorFromHex:_customKeyTextColor] forState:UIControlStateNormal];
186
+ }
187
+
188
+ - (void)keyPressed:(UIButton *)sender
189
+ {
190
+ NSString *key = sender.accessibilityIdentifier;
191
+ if (!key) {
192
+ return;
193
+ }
194
+
195
+ BOOL isCustomKeyCTA = (sender.tag == 1);
196
+ if (isCustomKeyCTA) {
197
+ [self.input emitCustomKey];
198
+ return;
199
+ }
200
+
201
+ [self.input emitKeyPress:key];
202
+
203
+ if ([key isEqualToString:@"AC"]) {
204
+ [self.input clearText];
205
+ } else if ([key isEqualToString:@"back"]) {
206
+ [self.input onBackSpace];
207
+ } else if ([key isEqualToString:@"="]) {
208
+ [self.input calculateResult];
209
+ } else if ([key isEqualToString:@"+"] || [key isEqualToString:@"-"] ||
210
+ [key isEqualToString:@"÷"] || [key isEqualToString:@"×"]) {
211
+ [self.input keyDidPress:[NSString stringWithFormat:@" %@ ", key]];
212
+ } else {
213
+ [self.input keyDidPress:key];
214
+ }
215
+ }
216
+
217
+ - (UIColor *)colorFromHex:(NSString *)hexString
218
+ {
219
+ unsigned rgbValue = 0;
220
+ NSString *cleanHex = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
221
+ NSScanner *scanner = [NSScanner scannerWithString:cleanHex];
222
+ [scanner scanHexInt:&rgbValue];
223
+
224
+ return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
225
+ green:((rgbValue & 0x00FF00) >> 8) / 255.0
226
+ blue:(rgbValue & 0x0000FF) / 255.0
227
+ alpha:1.0];
228
+ }
229
+
230
+ @end
231
+
@@ -0,0 +1,11 @@
1
+ #import <React/RCTViewComponentView.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface NativeInputCalculator : RCTViewComponentView
7
+
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
11
+